├── postcss.config.js ├── public └── images │ └── logo.png ├── modules ├── @apostrophecms │ ├── rich-text-widget │ │ └── ui │ │ │ └── src │ │ │ └── index.scss │ ├── express │ │ └── index.js │ ├── asset │ │ └── index.js │ ├── page │ │ ├── views │ │ │ └── notFound.html │ │ └── index.js │ ├── settings │ │ └── index.js │ └── home-page │ │ ├── index.js │ │ └── views │ │ └── page.html ├── asset │ ├── ui │ │ └── src │ │ │ ├── scss │ │ │ ├── _widgets.scss │ │ │ ├── _settings.scss │ │ │ ├── _layout.scss │ │ │ ├── _type.scss │ │ │ └── _welcome.scss │ │ │ ├── index.js │ │ │ └── index.scss │ └── index.js └── default-page │ ├── views │ └── page.html │ └── index.js ├── lib └── area.js ├── eslint.config.js ├── deployment ├── README ├── settings.staging ├── migrate ├── rsync_exclude.txt ├── stop ├── settings ├── dependencies └── start ├── .gitignore ├── LICENSE ├── app.js ├── scripts ├── sync-down └── sync-up ├── package.json ├── views └── layout.html └── README.md /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apostrophecms/starter-kit-essentials/main/public/images/logo.png -------------------------------------------------------------------------------- /modules/@apostrophecms/rich-text-widget/ui/src/index.scss: -------------------------------------------------------------------------------- 1 | .bp-rich-text img { 2 | width: 100%; 3 | margin: auto; 4 | } 5 | -------------------------------------------------------------------------------- /modules/asset/ui/src/scss/_widgets.scss: -------------------------------------------------------------------------------- 1 | .bp-video-widget { 2 | width: 100%; 3 | } 4 | 5 | .bp-image-widget { 6 | max-width: 100%; 7 | } -------------------------------------------------------------------------------- /modules/asset/ui/src/scss/_settings.scss: -------------------------------------------------------------------------------- 1 | $color-purple: #6236ff; 2 | $color-purple-light: #8264f1; 3 | $color-pink: #fe5599; 4 | $color-green: #0c8; 5 | $color-gold: #f7b500; -------------------------------------------------------------------------------- /lib/area.js: -------------------------------------------------------------------------------- 1 | export default { 2 | '@apostrophecms/image': {}, 3 | '@apostrophecms/video': {}, 4 | '@apostrophecms/html': {}, 5 | '@apostrophecms/rich-text': {} 6 | }; 7 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import apostrophe from 'eslint-config-apostrophe'; 2 | import { defineConfig } from 'eslint/config'; 3 | 4 | export default defineConfig([ 5 | apostrophe 6 | ]); 7 | -------------------------------------------------------------------------------- /modules/asset/ui/src/index.js: -------------------------------------------------------------------------------- 1 | export default () => { 2 | // Your own project level JS may go here 3 | // eslint-disable-next-line no-console 4 | console.log('Hello World'); 5 | }; 6 | -------------------------------------------------------------------------------- /modules/@apostrophecms/express/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | options: { 3 | session: { 4 | // If this still says `undefined`, set a real secret! 5 | secret: undefined 6 | } 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /deployment/README: -------------------------------------------------------------------------------- 1 | This is a deployment folder for use with Stagecoach. 2 | 3 | You don't have to use Stagecoach. 4 | 5 | It's just a neat solution for deploying node apps. 6 | 7 | See: 8 | 9 | http://github.com/apostrophecms/stagecoach 10 | -------------------------------------------------------------------------------- /modules/asset/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | handlers(self) { 3 | return { 4 | '@apostrophecms/page:beforeSend': { 5 | webpack(req) { 6 | req.data.isDev = (process.env.NODE_ENV !== 'production'); 7 | } 8 | } 9 | }; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /deployment/settings.staging: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Settings specific to the 'master' deployment target. 4 | # USER is the ssh user, SERVER is the ssh host. USER should 5 | # match the USER setting in /opt/stagecoach/settings on 6 | # the server 7 | 8 | USER=nodeapps 9 | SERVER=staging.apos.dev 10 | -------------------------------------------------------------------------------- /modules/asset/ui/src/index.scss: -------------------------------------------------------------------------------- 1 | @import url('normalize.css'); 2 | // NOTE: We're using a `.bp-` namespace to indicate these are the boilerplate 3 | // styles. 4 | @import './scss/_settings'; 5 | @import './scss/_type'; 6 | @import './scss/_layout'; 7 | @import './scss/_welcome'; 8 | @import './scss/_widgets'; 9 | -------------------------------------------------------------------------------- /modules/@apostrophecms/asset/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // When not in production, refresh the page on restart 3 | options: { 4 | // Change to `apos` for admin UI HMR 5 | // `public` is the default and provides HMR for project UI code 6 | hmr: 'public', 7 | refreshOnRestart: true 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /deployment/migrate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export NODE_ENV=production 4 | 5 | # Run any necessary database migration tasks that should happen while the 6 | # site is paused here. 7 | # 8 | # We don't have any, 3.x policy is safe migrations only. -Tom 9 | 10 | # node app @apostrophecms/migration:migrate 11 | # 12 | #echo "Site migrated" 13 | -------------------------------------------------------------------------------- /modules/@apostrophecms/page/views/notFound.html: -------------------------------------------------------------------------------- 1 | {# 2 | Use this template to build out your 404 error pages. Like page templates, 3 | it inherits a global layout. 4 | #} 5 | 6 | {% extends "layout.html" %} 7 | 8 | {% block title %}404 - Page not found{% endblock %} 9 | 10 | {% block main %} 11 | We're sorry. We couldn't find the page you're looking for. 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /modules/@apostrophecms/page/index.js: -------------------------------------------------------------------------------- 1 | // This configures the @apostrophecms/page module to add a "home" page type to the 2 | // pages menu 3 | 4 | export default { 5 | options: { 6 | types: [ 7 | { 8 | name: 'default-page', 9 | label: 'Default' 10 | }, 11 | { 12 | name: '@apostrophecms/home-page', 13 | label: 'Home' 14 | } 15 | ] 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /modules/default-page/views/page.html: -------------------------------------------------------------------------------- 1 | {# 2 | This is an example home page template. It inherits and extends a layout template 3 | that lives in the top-level views/ folder for convenience 4 | #} 5 | 6 | {% extends "layout.html" %} 7 | 8 | {% block main %} 9 |
10 |

{{ data.page.title }}

11 | {% area data.page, 'main' %} 12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /modules/@apostrophecms/settings/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | options: { 3 | subforms: { 4 | title: { 5 | fields: [ 'title' ], 6 | protection: true, 7 | reload: true 8 | }, 9 | changePassword: { 10 | fields: [ 'password' ] 11 | } 12 | }, 13 | 14 | groups: { 15 | account: { 16 | label: 'Account', 17 | subforms: [ 'title', 'changePassword' ] 18 | } 19 | } 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | /locales 3 | npm-debug.log 4 | /data 5 | /public/uploads 6 | /public/apos-minified 7 | /data/temp/uploadfs 8 | node_modules 9 | # This folder is created on the fly and contains symlinks updated at startup (we'll come up with a Windows solution that actually copies things) 10 | /public/modules 11 | # Don't commit build files 12 | /apos-build 13 | /public/apos-frontend 14 | /modules/asset/ui/public/site.js 15 | # Don't commit masters generated on the fly at startup, these import all the rest 16 | /public/css/master-*.less 17 | .jshintrc 18 | .DS_Store 19 | 20 | -------------------------------------------------------------------------------- /modules/@apostrophecms/home-page/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | options: { 3 | label: 'Home Page' 4 | }, 5 | fields: { 6 | add: { 7 | main: { 8 | type: 'area', 9 | options: { 10 | widgets: { 11 | '@apostrophecms/rich-text': {}, 12 | '@apostrophecms/image': {}, 13 | '@apostrophecms/video': {} 14 | } 15 | } 16 | } 17 | }, 18 | group: { 19 | basics: { 20 | label: 'Basics', 21 | fields: [ 22 | 'title', 23 | 'main' 24 | ] 25 | } 26 | } 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /deployment/rsync_exclude.txt: -------------------------------------------------------------------------------- 1 | # List files and folders that shouldn't be deployed (such as data folders and runtime status files) here. 2 | # In our projects .git and .gitignore are good candidates, also 'data' which contains persistent files 3 | # that are *not* part of deployment. A good place for things like data/port, data/pid, and any 4 | # sqlite databases or static web content you may need 5 | data 6 | temp 7 | public/uploads 8 | public/apos-frontend 9 | .git 10 | .gitignore 11 | # We don't deploy these anymore, instead we always 'npm install' to ensure 12 | # that any compiled C++ modules are built for the right architecture 13 | node_modules 14 | -------------------------------------------------------------------------------- /modules/default-page/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | extend: '@apostrophecms/page-type', 3 | options: { 4 | label: 'Default Page' 5 | }, 6 | fields: { 7 | add: { 8 | main: { 9 | type: 'area', 10 | options: { 11 | widgets: { 12 | '@apostrophecms/rich-text': {}, 13 | '@apostrophecms/image': {}, 14 | '@apostrophecms/video': {} 15 | } 16 | } 17 | } 18 | }, 19 | group: { 20 | basics: { 21 | label: 'Basics', 22 | fields: [ 23 | 'title', 24 | 'main' 25 | ] 26 | } 27 | } 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /deployment/stop: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export NODE_ENV=production 4 | 5 | # Shut the site down, for instance by tweaking a .htaccess file to display 6 | # a 'please wait' notice, or stopping a node server 7 | 8 | if [ ! -f "app.js" ]; then 9 | echo "I don't see app.js in the current directory." 10 | exit 1 11 | fi 12 | 13 | # Stop the node app via 'forever'. You'll get a harmless warning if the app 14 | # was not already running. Use `pwd` to make sure we have a full path, 15 | # forever is otherwise easily confused and will stop every server with 16 | # the same filename 17 | forever stop `pwd`/app.js && echo "Site stopped" 18 | 19 | # Stop the app without 'forever'. We recommend using 'forever' for node apps, 20 | # but this may be your best bet for non-node apps 21 | # 22 | # if [ -f "data/pid" ]; then 23 | # kill `cat data/pid` 24 | # rm data/pid 25 | # echo "Site stopped" 26 | # else 27 | # echo "Site was not running" 28 | # fi 29 | 30 | -------------------------------------------------------------------------------- /deployment/settings: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Settings shared by all targets (staging, production, etc). Usually the 4 | # shortname of the project (which is also the hostname for the frontend 5 | # proxy server used for staging sites) and the directory name. For our 6 | # web apps that use sc-proxy we make sure each is a subdirectory 7 | # of /opt/stagecoach/apps 8 | 9 | # Should match the repo name = short name = everything name! 10 | PROJECT=a3-boilerplate 11 | 12 | DIR=/opt/stagecoach/apps/$PROJECT 13 | 14 | # Adjust the PATH environment variable on the remote host. Here's an example 15 | # for deploying to MacPorts 16 | #ADJUST_PATH='export PATH=/opt/local/bin:$PATH' 17 | 18 | # ... But you probably won't need to on real servers. I just find it handy for 19 | # testing parts of stagecoach locally on a Mac. : is an acceptable "no-op" (do-nothing) statement 20 | ADJUST_PATH=':' 21 | 22 | # ssh port. Sensible people leave this set to 22 but it's common to do the 23 | # "security by obscurity" thing alas 24 | SSH_PORT=22 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Apostrophe Technologies 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | import apostrophe from 'apostrophe'; 2 | 3 | apostrophe({ 4 | root: import.meta, 5 | shortName: 'a4-boilerplate', 6 | modules: { 7 | // Apostrophe module configuration 8 | // ******************************* 9 | // 10 | // NOTE: most configuration occurs in the respective modules' directories. 11 | // See modules/@apostrophecms/page/index.js for an example. 12 | // 13 | // Any modules that are not present by default in Apostrophe must at least 14 | // have a minimal configuration here to turn them on: `moduleName: {}` 15 | // *********************************************************************** 16 | // `className` options set custom CSS classes for Apostrophe core widgets. 17 | '@apostrophecms/rich-text-widget': { 18 | options: { 19 | className: 'bp-rich-text' 20 | } 21 | }, 22 | '@apostrophecms/image-widget': { 23 | options: { 24 | className: 'bp-image-widget' 25 | } 26 | }, 27 | '@apostrophecms/video-widget': { 28 | options: { 29 | className: 'bp-video-widget' 30 | } 31 | }, 32 | // `asset` supports the project's build for client-side assets. 33 | asset: {}, 34 | // use vite for asset bundling and hot module reloading 35 | '@apostrophecms/vite': {}, 36 | // The project's first custom page type. 37 | 'default-page': {} 38 | } 39 | }); 40 | -------------------------------------------------------------------------------- /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/asset/ui/src/scss/_layout.scss: -------------------------------------------------------------------------------- 1 | // Use flex to keep the footer at the bottom. 2 | body, 3 | [data-apos-refreshable], 4 | .bp-wrapper { 5 | display: flex; 6 | flex-direction: column; 7 | } 8 | 9 | [data-apos-refreshable], 10 | .bp-wrapper, 11 | main { 12 | flex-grow: 1; 13 | } 14 | 15 | body { 16 | min-height: 100vh; 17 | // Nice system fonts. 18 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 19 | } 20 | 21 | .bp-header, 22 | main, 23 | .bp-footer { 24 | width: 100%; 25 | max-width: 800px; 26 | margin-left: auto; 27 | margin-right: auto; 28 | } 29 | 30 | .bp-header { 31 | display: flex; 32 | align-items: center; 33 | justify-content: space-between; 34 | flex-wrap: wrap; 35 | margin-bottom: 10px; 36 | padding: 40px 0; 37 | } 38 | 39 | .bp-footer { 40 | padding: 40px 0; 41 | } 42 | 43 | .bp-footer__links { 44 | padding-left: 0px; 45 | list-style: none; 46 | text-align: center; 47 | 48 | li { 49 | display: inline-block; 50 | margin-right: 20px; 51 | } 52 | li:last-child { margin-right: 0; } 53 | } 54 | 55 | .bp-header__logo { 56 | display: block; 57 | width: 190px; 58 | max-width: 100%; 59 | object-fit: contain; 60 | } 61 | 62 | .bp-header__login { 63 | 64 | &:visited { 65 | color: white; 66 | } 67 | } 68 | 69 | .bp-content { 70 | max-width: 600px; 71 | margin-left: auto; 72 | margin-right: auto; 73 | } 74 | -------------------------------------------------------------------------------- /modules/asset/ui/src/scss/_type.scss: -------------------------------------------------------------------------------- 1 | h1, 2 | h2, 3 | h3 { 4 | text-align: center; 5 | } 6 | 7 | h1 { 8 | font-size: 4em; 9 | font-weight: 200; 10 | } 11 | 12 | a { 13 | color: $color-purple; 14 | text-decoration: none; 15 | 16 | &:hover, 17 | &:focus { 18 | text-decoration: underline; 19 | } 20 | 21 | &:visited { 22 | color: $color-purple-light; 23 | } 24 | } 25 | 26 | ::selection { 27 | background-color: $color-gold; 28 | } 29 | 30 | code { 31 | white-space: normal; 32 | } 33 | 34 | pre { 35 | display: flex; 36 | position: relative; 37 | font-family: Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace; 38 | color: white; 39 | font-size: 14px; 40 | text-align: left; 41 | white-space: pre; 42 | word-spacing: normal; 43 | word-break: normal; 44 | word-wrap: normal; 45 | line-height: 1.8; 46 | tab-size: 4; 47 | hyphens: none; 48 | border-radius: 6px; 49 | margin-bottom: 1.5rem; 50 | padding: 1.5rem; 51 | overflow: auto; 52 | background: #2b2b2b; 53 | max-width: 600px; 54 | margin: 0 auto; 55 | } 56 | 57 | .bp-button { 58 | display: inline-block; 59 | padding: 12px 24px 10px 24px; 60 | text-decoration: none; 61 | font-size: 14px; 62 | border-radius: 30px; 63 | line-height: 1; 64 | font-weight: 500; 65 | background: $color-purple; 66 | color: white; 67 | &:visited, &:hover, &:active { 68 | color: white; 69 | } 70 | } 71 | 72 | .bp-button--cta { 73 | font-size: 16px; 74 | font-weight: 400; 75 | padding: 20px 30px; 76 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "starter-kit-essentials", 3 | "version": "1.0.0", 4 | "description": "ApostropheCMS Essential Starter Kit Site", 5 | "main": "app.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node app", 9 | "dev": "nodemon", 10 | "build": "cross-env NODE_ENV=production node app @apostrophecms/asset:build", 11 | "serve": "cross-env NODE_ENV=production node app", 12 | "release": "npm install && npm run build && node app @apostrophecms/migration:migrate" 13 | }, 14 | "nodemonConfig": { 15 | "delay": 1000, 16 | "verbose": true, 17 | "watch": [ 18 | "./app.js", 19 | "./modules/**/*", 20 | "./lib/**/*.js", 21 | "./views/**/*.html" 22 | ], 23 | "ignoreRoot": [ 24 | ".git" 25 | ], 26 | "ignore": [ 27 | "**/ui/", 28 | "locales/*.json", 29 | "public/uploads/", 30 | "public/apos-frontend/*.js", 31 | "data/" 32 | ], 33 | "ext": "json, js, cjs, html" 34 | }, 35 | "repository": { 36 | "type": "git", 37 | "url": "https://github.com/apostrophecms/starter-kit-essentials" 38 | }, 39 | "author": "Apostrophe Technologies, Inc.", 40 | "license": "MIT", 41 | "dependencies": { 42 | "@apostrophecms/vite": "^1.0.0", 43 | "apostrophe": "^4.23.0", 44 | "cross-env": "^10.1.0", 45 | "normalize.css": "^8.0.1" 46 | }, 47 | "devDependencies": { 48 | "autoprefixer": "^10.4.20", 49 | "eslint-config-apostrophe": "^6.0.1", 50 | "nodemon": "^3.0.1" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /views/layout.html: -------------------------------------------------------------------------------- 1 | {# Automatically extends the right outer layout and also handles AJAX siutations #} 2 | {% extends data.outerLayout %} 3 | 4 | {% set title = data.piece.title or data.page.title %} 5 | {% block title %} 6 | {{ title }} 7 | {% if not title %} 8 | {{ apos.log('Looks like you forgot to override the title block in a template that does not have access to an Apostrophe page or piece.') }} 9 | {% endif %} 10 | {% endblock %} 11 | 12 | {% block beforeMain %} 13 |
14 |
15 | 16 | 17 | {% if not data.user %} 18 | 19 | {% endif %} 20 |
21 |
22 | {% endblock %} 23 | 24 | {% block main %} 25 | {# 26 | Usually, your page templates in the @apostrophecms/pages module will override 27 | this block. It is safe to assume this is where your page-specific content 28 | should go. 29 | #} 30 | {% endblock %} 31 | 32 | {% block afterMain %} 33 |
34 | 43 |
{# Close .bp-wrapper #} 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /scripts/sync-up: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TARGET="$1" 4 | if [ -z "$TARGET" ]; then 5 | echo "Usage: ./scripts/sync-up production" 6 | echo "(or as appropriate)" 7 | echo 8 | echo "THIS WILL CLOBBER EVERYTHING ON THE" 9 | echo "TARGET SITE. MAKE SURE THAT IS WHAT" 10 | echo "YOU WANT!" 11 | exit 1 12 | fi 13 | 14 | read -p "THIS WILL CRUSH THE SITE'S CONTENT ON $TARGET. Are you sure? " -n 1 -r 15 | echo 16 | if [[ ! $REPLY =~ ^[Yy]$ ]] 17 | then 18 | exit 1 19 | fi 20 | 21 | source deployment/settings || exit 1 22 | source "deployment/settings.$TARGET" || exit 1 23 | 24 | #Enter the Mongo DB name (should be same locally and remotely). 25 | dbName=$PROJECT 26 | 27 | #Enter the Project name (should be what you called it for stagecoach). 28 | projectName=$PROJECT 29 | 30 | #Enter the SSH username/url for the remote server. 31 | remoteSSH="-p $SSH_PORT $USER@$SERVER" 32 | rsyncTransport="ssh -p $SSH_PORT" 33 | rsyncDestination="$USER@$SERVER" 34 | 35 | echo "Syncing MongoDB" 36 | mongodump -d $dbName -o /tmp/mongodump.$dbName && 37 | echo rsync -av -e "$rsyncTransport" /tmp/mongodump.$dbName/ $rsyncDestination:/tmp/mongodump.$dbName && 38 | rsync -av -e "$rsyncTransport" /tmp/mongodump.$dbName/ $rsyncDestination:/tmp/mongodump.$dbName && 39 | rm -rf /tmp/mongodump.$dbName && 40 | # noIndexRestore increases compatibility between 3.x and 2.x, 41 | # and Apostrophe will recreate the indexes correctly at startup 42 | ssh $remoteSSH mongorestore --noIndexRestore --drop -d $dbName /tmp/mongodump.$dbName/$dbName && 43 | echo "Syncing Files" && 44 | rsync -av --delete -e "$rsyncTransport" ./public/uploads/ $rsyncDestination:/opt/stagecoach/apps/$projectName/uploads && 45 | echo "Synced up to $TARGET" 46 | echo "YOU MUST RESTART THE SITE ON $TARGET TO REBUILD THE MONGODB INDEXES." 47 | -------------------------------------------------------------------------------- /deployment/dependencies: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export NODE_ENV=production 4 | 5 | # Also a good place to ensure any data folders 6 | # that are *not* supposed to be replaced on every deployment exist 7 | # and create a symlink to them from the latest deployment directory. 8 | 9 | # The real 'data' folder is shared. It lives two levels up and one over 10 | # (we're in a deployment dir, which is a subdir of 'deployments', which 11 | # is a subdir of the project's main dir) 12 | 13 | HERE=`pwd` 14 | mkdir -p ../../data 15 | ln -s ../../data $HERE/data 16 | 17 | # We also have a shared uploads folder which is convenient to keep 18 | # in a separate place so we don't have to have two express.static calls 19 | 20 | mkdir -p ../../uploads 21 | ln -s ../../../uploads $HERE/public/uploads 22 | 23 | # Install any dependencies that can't just be rsynced over with 24 | # the deployment. Example: node apps have npm modules in a 25 | # node_modules folder. These may contain compiled C++ code that 26 | # won't work portably from one server to another. 27 | 28 | # This script runs after the rsync, but before the 'stop' script, 29 | # so your app is not down during the npm installation. 30 | 31 | # Make sure node_modules exists so npm doesn't go searching 32 | # up the filesystem tree 33 | mkdir -p node_modules 34 | 35 | # If there is no package.json file then we don't need npm install 36 | if [ -f './package.json' ]; then 37 | # Install npm modules 38 | # Use a suitable version of Python 39 | # export PYTHON=/usr/bin/python26 40 | npm install 41 | if [ $? -ne 0 ]; then 42 | echo "Error during npm install!" 43 | exit 1 44 | fi 45 | fi 46 | 47 | node app @apostrophecms/migration:migrate 48 | # Generate new static asset files for this 49 | # deployment of the app without shutting down 50 | # (TODO: for 3.0 this is actually disruptive because 51 | # we don't have a generation identifier yet) 52 | npm run build 53 | -------------------------------------------------------------------------------- /modules/@apostrophecms/home-page/views/page.html: -------------------------------------------------------------------------------- 1 | {# 2 | This is an example home page template. It inherits and extends a layout template 3 | that lives in the top-level views/ folder for convenience 4 | #} 5 | 6 | {% extends "layout.html" %} 7 | 8 | {% block main %} 9 |
10 |

11 | Welcome to ApostropheCMS 12 |

13 | {% if not data.user %} 14 | {# Message only for logged out users. #} 15 |

First time spinning up the ApostropheCMS 3 demo?

16 |

17 | Use the credentials created during setup with the CLI tool or create a new user with the CLI command: 18 |

19 |
20 |         Command Line
21 |         
22 |           node app @apostrophecms/user:add myUsername admin
23 |         
24 |       
25 |

26 | Then log in here 27 |

28 | {% endif %} 29 |

30 | For a guide on how to configure and customize this project, please check out the Apostrophe 3 documentation. 31 |

32 |
33 | {% if data.user %} 34 | {# Message only for logged in users. #} 35 | {% if not data.query['apos-edit'] %} 36 |

37 | Enter Edit mode from the admin bar 👆 to begin. 38 |

39 | {% else %} 40 |

41 | Add and edit content below in the content area. 👇 42 |

43 | {% endif %} 44 | {% endif %} 45 | {% area data.page, 'main' %} 46 |
47 |
48 | {% endblock %} 49 | -------------------------------------------------------------------------------- /modules/asset/ui/src/scss/_welcome.scss: -------------------------------------------------------------------------------- 1 | .bp-welcome { 2 | max-width: 800px; 3 | margin-left: auto; 4 | margin-right: auto; 5 | 6 | } 7 | 8 | .bp-welcome__area { 9 | margin-top: 40px; 10 | } 11 | 12 | .bp-welcome__headline { 13 | position: relative; 14 | margin: 0 0 50px; 15 | } 16 | 17 | .bp-welcome__verson-wrapper { 18 | display: flex; 19 | justify-content: center; 20 | } 21 | 22 | .bp-welcome__version { 23 | position: relative; 24 | background-color: #a992ff; 25 | padding: 4px 5px; 26 | border-radius: 2px; 27 | display: inline-block; 28 | color: #300ab7; 29 | font-size: 12px; 30 | box-shadow: 0 25px 50px rgba(64,70,104,.1); 31 | font-weight: 500; 32 | letter-spacing: 2px; 33 | text-transform: uppercase; 34 | } 35 | 36 | .bp-welcome__help { 37 | font-weight: 600; 38 | font-size: 22px; 39 | margin-bottom: 24px; 40 | } 41 | 42 | .bp-welcome p { 43 | max-width: 500px; 44 | margin: 20px auto; 45 | line-height: 1.5; 46 | font-size: 1.1rem; 47 | } 48 | 49 | .bp-welcome__code__context { 50 | position: absolute; 51 | display: inline-block; 52 | bottom: auto; 53 | left: auto; 54 | right: 0; 55 | top: 0; 56 | width: auto; 57 | height: auto; 58 | text-transform: uppercase; 59 | font-size: 11px; 60 | font-family: code-saver,sans-serif; 61 | letter-spacing: .025em; 62 | padding: 5px 10px; 63 | -webkit-user-select: none; 64 | -moz-user-select: none; 65 | -ms-user-select: none; 66 | user-select: none; 67 | border-top-right-radius: 2px; 68 | background: #ffffff20; 69 | color: #ffffff96; 70 | letter-spacing: 1px; 71 | } 72 | 73 | .bp-welcome__code { 74 | margin: 40px auto; 75 | } 76 | 77 | p.bp-welcome__cta { 78 | text-align: center; 79 | margin-bottom: 40px; 80 | } 81 | 82 | .bp-mode { 83 | display: inline-block; 84 | padding: 5px 5px; 85 | font-size: 12px; 86 | font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; 87 | line-height: 10px; 88 | color: black; 89 | vertical-align: middle; 90 | background-color: white; 91 | border-bottom-color: black; 92 | border: 1px solid black; 93 | border-radius: 6px; 94 | box-shadow: inset 0 -1px 0 black; 95 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ApostropheCMS essentials starter kit 2 | 3 | ## Getting started 4 | 5 | This Starter Kit, also known as a boilerplate project, serves as a template for initiating new projects and is intended for use in two main ways: 6 | 7 | 1. **Using Our CLI Tool**: Run our [CLI tool](https://github.com/apostrophecms/cli) to clone this template locally, install its dependencies, and set up an initial admin user. You accomplish this using: 8 | 9 | `apos create ` 10 | 11 | 2. **Manual Setup**: Manually `git clone` this repository and install its dependencies using `npm install`. Add an initial admin user with `node app @apostrophecms/user:add admin admin`. 12 | 13 | For those who need to create multiple projects with additional base modules, consider [forking this repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/about-forks) into your organizational or personal GitHub account. Customize it to fit your needs. To use your customized template, run the following CLI command: 14 | 15 | `apos create --starter=` 16 | 17 | Here, `` should be the URL of your forked repository, excluding the `https://github.com/` part. 18 | 19 | **Note: This template is NOT designed to be installed into an existing project.** 20 | 21 | ## Running the project 22 | 23 | Run `npm run dev` to build the Apostrophe UI and start the site up. Remember, this is during alpha development, so we're all in "dev mode." The `dev` script will watch for saves in client-side CSS and Javascript and trigger a build and page refresh if they are detected. It will also restart the app when server-side code is saved. 24 | 25 | ## Making it your own 26 | 27 | This boilerplate is designed so you can install and start running it right away. If you are starting a project that will go into production one day, there are a few things you should be sure to check: 28 | 29 | - [ ] **Update the shortname.** You don't need to perform this step if you created your project using the CLI tool. The `shortname` option in `app.js` is used for the database name (unless another is given in the `@apostrophecms/db` module). You should change this to an appropriate project name before you start adding any users or content you would like to keep. 30 | - [ ] **Update the Express.js session secret.** The secret is set to `undefined` initially in the `modules/@apostrophecms/express/index.js` file. You should update this to a unique string. 31 | - [ ] **Decide if you want hot reloading on.** This boilerplate uses nodemon to restart the app when files are changed. In `modules/@apostrophecms/asset/index.js` there is an option enabled to refresh the browser on restart. If you like this, do nothing. If you don't, remove the option or set it to `false`. The option has no effect when the app is in production. 32 | - [ ] **Update the `className` options in `app.js`.** This option is set for core widget types to provide CSS styling hooks. It is namespaced with `bp-` for "boilerplate." You will likely want to update that to match your general CSS class naming practices. 33 | 34 | ## You really want the docs 35 | 36 | Right now, [all the juicy info is in the ApostropheCMS docs](https://docs.apostrophecms.org), so head over there and start reading! This boilerplate project is a fun introduction to the UI, but you'll want to know more to really try it out. 37 | 38 | --------------------------------------------------------------------------------