├── .gitignore ├── LICENSE ├── README.md ├── blog ├── .env.development ├── .gitignore ├── .netlify │ └── state.json ├── .prettierrc ├── LICENSE ├── README.md ├── gatsby-browser.js ├── gatsby-config.js ├── gatsby-node.js ├── gatsby-ssr.js ├── netlify.toml ├── package-lock.json ├── package.json └── src │ ├── components │ ├── header.js │ ├── image.js │ ├── layout.css │ ├── layout.js │ └── seo.js │ ├── images │ ├── gatsby-astronaut.png │ └── gatsby-icon.png │ ├── pages │ ├── 404.js │ ├── index.js │ └── page-2.js │ ├── styles │ └── global.css │ └── templates │ ├── article.js │ └── author.js ├── cms ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── README.md ├── api │ ├── .gitkeep │ └── article │ │ ├── config │ │ └── routes.json │ │ ├── controllers │ │ └── Article.js │ │ ├── models │ │ ├── Article.js │ │ └── Article.settings.json │ │ └── services │ │ └── Article.js ├── config │ ├── application.json │ ├── custom.json │ ├── environments │ │ ├── development │ │ │ ├── custom.json │ │ │ ├── database.json │ │ │ ├── request.json │ │ │ ├── response.json │ │ │ ├── security.json │ │ │ └── server.json │ │ ├── production │ │ │ ├── custom.json │ │ │ ├── database.json │ │ │ ├── request.json │ │ │ ├── response.json │ │ │ ├── security.json │ │ │ └── server.json │ │ └── staging │ │ │ ├── custom.json │ │ │ ├── database.json │ │ │ ├── request.json │ │ │ ├── response.json │ │ │ ├── security.json │ │ │ └── server.json │ ├── functions │ │ ├── bootstrap.js │ │ ├── cron.js │ │ └── responses │ │ │ └── 404.js │ ├── hook.json │ ├── language.json │ ├── locales │ │ ├── de_de.json │ │ ├── en_us.json │ │ ├── es_es.json │ │ ├── fr_fr.json │ │ ├── it_it.json │ │ ├── ja_jp.json │ │ ├── ru_ru.json │ │ └── tr_tr.json │ └── middleware.json ├── extensions │ ├── .gitkeep │ └── users-permissions │ │ ├── config │ │ └── jwt.json │ │ └── models │ │ └── User.settings.json ├── favicon.ico ├── package.json ├── public │ ├── index.html │ ├── robots.txt │ └── uploads │ │ └── .gitkeep └── yarn.lock └── content-master ├── Markdown-mark.png ├── bed-and-breakfast-content.jpg ├── bed-and-breakfasts-give-travel-a-personal-touch.jpg ├── content-for-tutorial.txt ├── creative-gift-giving-easier-than-you-think.jpg ├── fall-in-love-content.jpg ├── fall-in-love-with-greater-fort-lauderdale.jpg ├── gatsby-logo.png ├── markdown-cheatsheet.md ├── real-talk-content.jpg ├── real-talk-when-was-the-last-time-you-enjoyed-your-business-trip.jpeg ├── strapi-logo.png ├── stylish-carrying-case-corrals-handbag-essentials-in-style.jpg └── the-big-appeal-of-small-city-vacations.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | ############################ 64 | # OS X 65 | ############################ 66 | 67 | .DS_Store 68 | .AppleDouble 69 | .LSOverride 70 | Icon 71 | .Spotlight-V100 72 | .Trashes 73 | ._* 74 | 75 | 76 | ############################ 77 | # Linux 78 | ############################ 79 | 80 | *~ 81 | 82 | 83 | ############################ 84 | # Windows 85 | ############################ 86 | 87 | Thumbs.db 88 | ehthumbs.db 89 | Desktop.ini 90 | $RECYCLE.BIN/ 91 | *.cab 92 | *.msi 93 | *.msm 94 | *.msp 95 | 96 | 97 | ############################ 98 | # Packages 99 | ############################ 100 | 101 | *.7z 102 | *.csv 103 | *.dat 104 | *.dmg 105 | *.gz 106 | *.iso 107 | *.jar 108 | *.rar 109 | *.tar 110 | *.zip 111 | *.com 112 | *.class 113 | *.dll 114 | *.exe 115 | *.o 116 | *.seed 117 | *.so 118 | *.swo 119 | *.swp 120 | *.swn 121 | *.swm 122 | *.out 123 | *.pid 124 | 125 | 126 | ############################ 127 | # Logs and databases 128 | ############################ 129 | 130 | .tmp 131 | *.log 132 | *.sql 133 | *.sqlite 134 | *.sqlite3 135 | 136 | 137 | ############################ 138 | # Misc. 139 | ############################ 140 | 141 | *# 142 | ssl 143 | .idea 144 | nbproject 145 | public/uploads/* 146 | !public/uploads/.gitkeep 147 | 148 | ############################ 149 | # Node.js 150 | ############################ 151 | 152 | lib-cov 153 | lcov.info 154 | pids 155 | logs 156 | results 157 | node_modules 158 | .node_history 159 | 160 | 161 | ############################ 162 | # Tests 163 | ############################ 164 | 165 | testApp 166 | coverage 167 | 168 | # Logs 169 | logs 170 | *.log 171 | npm-debug.log* 172 | yarn-debug.log* 173 | yarn-error.log* 174 | 175 | # Runtime data 176 | pids 177 | *.pid 178 | *.seed 179 | *.pid.lock 180 | 181 | # Directory for instrumented libs generated by jscoverage/JSCover 182 | lib-cov 183 | 184 | # Coverage directory used by tools like istanbul 185 | coverage 186 | 187 | # nyc test coverage 188 | .nyc_output 189 | 190 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 191 | .grunt 192 | 193 | # Bower dependency directory (https://bower.io/) 194 | bower_components 195 | 196 | # node-waf configuration 197 | .lock-wscript 198 | 199 | # Compiled binary addons (http://nodejs.org/api/addons.html) 200 | build/Release 201 | 202 | # Dependency directories 203 | node_modules/ 204 | jspm_packages/ 205 | 206 | # Typescript v1 declaration files 207 | typings/ 208 | 209 | # Optional npm cache directory 210 | .npm 211 | 212 | # Optional eslint cache 213 | .eslintcache 214 | 215 | # Optional REPL history 216 | .node_repl_history 217 | 218 | # Output of 'npm pack' 219 | *.tgz 220 | 221 | # dotenv environment variables file 222 | .env 223 | 224 | # gatsby files 225 | .cache/ 226 | public 227 | 228 | # Mac files 229 | .DS_Store 230 | 231 | # Yarn 232 | yarn-error.log 233 | .pnp/ 234 | .pnp.js 235 | # Yarn Integrity file 236 | .yarn-integrity 237 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 David Kartuzinski aka Kai Dawei 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Strapi with Gatsby Video Tutorial Series 2 | 3 | This REPO contains the latest example code from the [Gatsby / Strapi Video Tutorial Series](https://youtu.be/It4PRFJJaF0). You can review the code directly, within the following directories. 4 | 5 | **NOTE:** This is the **BETA** version of Strapi, **ALPHA** is not being maintained. 6 | 7 | - Code examples for the folder "cms". `Path: ./tutorial/cms` <- **Strapi Project** 8 | 9 | - Code examples for the folder "blog". `Path: ./tutorial/blog`. <- **Gatsby Project** 10 | 11 | ## Instructions for cloning and using this repo locally 12 | 13 | Create a folder, e.g. `./my-project` and `git clone` this repo. 14 | 15 | ```bash 16 | cd my-project 17 | git clone https://github.com/strapi/strapi-heroku-cms-demo.git 18 | ``` 19 | 20 | ### Install this Strapi & Gatsby Project locally 21 | 22 | From your command line, issue the following commands in order to install **_this Strapi and Gatsby project_**: 23 | 24 | Path: `./my-project/` 25 | 26 | ### Install the Strapi part of the Project 27 | 28 | ``` 29 | git clone git@github.com:strapi/strapi-heroku-cms-demo.git 30 | cd strapi-heroku-cms-demo 31 | cd cms 32 | npm install 33 | strapi build 34 | ``` 35 | 36 | Once installed, you will need to do a few steps to replicate the final production environment (this steps are done also when you first upload and install to Heroku or other production environment): 37 | 38 | - Create a User: Under CONTENT TYPES -> **Users** - add a user. 39 | - Set WYIWYG to Visible: Under PLUGINS -> **Content Manager** -> Article -> [Tab] Edit View(Settings) -> Click on `content` -> Scroll down and toggle **Display as WYSIWYG** to `ON`. 40 | - Allow API Access: Under PLUGINS -> **Roles & Permissions** -> Public -> Article (check **find** and **findone**), User (check **find** and **findone**) 41 | - Enter your Cloudinary Credentials: Under PLUGINS -> **FILES UPLOAD - COGWHEEL** 42 | - Add Content: Under CONTENT TYPES -> **Articles** -> add content. 43 | 44 | Test you [local API routes](http://localhost:1337/articles) 45 | 46 | #### Upload to Heroku 47 | 48 | You will need to have a Heroku account, and the Heroku CLI installed. [Heroku install instructions](https://strapi.io/documentation/3.0.0-beta.x/guides/deployment.html#heroku) 49 | 50 | Do these steps to upload your Strapi project to Heroku: 51 | 52 | - Login to Heroku: `heroku login` 53 | - Initilize Git: 54 | 55 | ``` 56 | git init 57 | git add . 58 | git commit -am "Initial Commit" 59 | ``` 60 | 61 | - Create a Heroku project (**with a unique name for the URL**) 62 | 63 | ``` 64 | heroku create my-uniquely-named-strapi-project 65 | ``` 66 | 67 | - setup database configuration (**DO NOT CUT AND PASTE - USE OWN SETTINGS**) 68 | 69 | ``` 70 | heroku addons:create heroku-postgresql:hobby-dev 71 | heroku config 72 | heroku config:set DATABASE_USERNAME=example 73 | heroku config:set DATABASE_PASSWORD=example 74 | heroku config:set DATABASE_HOST=example.compute-2.amazonaws.com 75 | heroku config:set DATABASE_PORT=5432 76 | heroku config:set DATABASE_NAME=example 77 | ``` 78 | 79 | - Push project to Heroku. 80 | 81 | ``` 82 | git push heroku master 83 | ``` 84 | 85 | - Open your app project, and redo these steps to match your **Development Environment**: 86 | 87 | - Create a User: Under CONTENT TYPES -> **Users** - add a user. 88 | - Set WYIWYG to Visible: Under PLUGINS -> **Content Manager** -> Article -> [Tab] Edit View(Settings) -> Click on `content` -> Scroll down and toggle **Display as WYSIWYG** to `ON`. 89 | - Allow API Access: Under PLUGINS -> **Roles & Permissions** -> Public -> Article (check **find** and **findone**), User (check **find** and **findone**) 90 | - Enter your Cloudinary Credentials: Under PLUGINS -> **FILES UPLOAD - COGWHEEL** 91 | - Add Content: Under CONTENT TYPES -> **Articles** -> add content. 92 | 93 | After you add content, you can go ahead and follow the next steps to create the Gatsby part of the project. 94 | 95 | ### Install the Gatsby part of the Project 96 | 97 | Open a new tab in your command line, and navigate to `./strapi-heroku-cms-demo/blog/`: 98 | 99 | `Path: ./strapi-heroku-cms-demo/blog` 100 | 101 | ``` 102 | npm install 103 | gatsby develop 104 | ``` 105 | 106 | You can now check to see if Gatsby is running [http://localhost:8000](http://localhost:8000). 107 | 108 | #### Push the Gatsby Project to a separate GitHub repo 109 | 110 | You will need to create a separate repo to push just the Gatsby part of the project and which will link to Netlify. 111 | 112 | ``` 113 | git init 114 | git add . 115 | git commit -m "first commit" 116 | git remote add origin git@github.com:YOUR-NAME/YOUR-NEW-EMPTY-REPO.git 117 | git push -u origin master 118 | ``` 119 | 120 | #### Modify the Gatsby-Config file 121 | 122 | Locate this code and replace the URL to match the URL from your Heroku install: 123 | 124 | `Path: ./blog/gatsby-config.js` 125 | 126 | ``` 127 | { 128 | resolve: `gatsby-source-strapi`, 129 | options: { 130 | apiURL: process.env.DEPLOY_URL 131 | ? "https://YOUR-APP-URL.herokuapp.com" 132 | : "http://localhost:1337", 133 | contentTypes: [`article`, `user`], 134 | queryLimit: 1000, 135 | }, 136 | }, 137 | ``` 138 | 139 | #### Configure Netlfiy 140 | 141 | - Login to Netlify with `netlify login`. 142 | 143 | You will need to link netlify to this repo. Use the **netlify init** to do so. 144 | 145 | ``` 146 | netlify init 147 | ``` 148 | 149 | After configuring Netlify (see tutorial), you need to commit all the changes: 150 | 151 | Commit these changes: 152 | 153 | ``` 154 | git add . 155 | git commit -m "git commit -m "netlify config settings files" 156 | git push 157 | netlify open 158 | ``` 159 | 160 | #### Set-up the Netlify WebHook URL 161 | 162 | The last step is to set-up the Netlify Webhook URL so it updates: 163 | 164 | - From your App, go to: Settings -> Build & deploy -> Continuous deployment -> Build hooks 165 | 166 | - Click Add build hook 167 | - Give your app a build hook name, e.g. strapiUpdate 168 | - Save it and then copy the issued URL to the clipboard 169 | 170 | - Change the **staticWebsiteBuildURL** variable found in `custom.json`. 171 | 172 | These changes occur on your **Strapi Project**. 173 | 174 | `Path: ./cms/config/environments/production/custom.json` 175 | 176 | Replace the link with your link for the **staticWebsiteBuildURL** 177 | 178 | Commit these changes: 179 | 180 | ``` 181 | git add . 182 | git commit -m "Add webhook support" 183 | git push heroku master 184 | ``` 185 | 186 | You are now ready to test and play with this installation. You can build or change this. 187 | 188 | **NOTE:** You have NOT created a Repo for the Strapi part of the project, but this is highly recommended. 189 | -------------------------------------------------------------------------------- /blog/.env.development: -------------------------------------------------------------------------------- 1 | IMAGE_BASE_URL=http://localhost:1337 -------------------------------------------------------------------------------- /blog/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | package-lock.json -------------------------------------------------------------------------------- /blog/.netlify/state.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /blog/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /blog/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 gatsbyjs 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 all 13 | 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 THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /blog/README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | Gatsby 5 | 6 |

7 |

8 | Gatsby's default starter 9 |

10 | 11 | Kick off your project with this default boilerplate. This starter ships with the main Gatsby configuration files you might need to get up and running blazing fast with the blazing fast app generator for React. 12 | 13 | _Have another more specific idea? You may want to check out our vibrant collection of [official and community-created starters](https://www.gatsbyjs.org/docs/gatsby-starters/)._ 14 | 15 | ## 🚀 Quick start 16 | 17 | 1. **Create a Gatsby site.** 18 | 19 | Use the Gatsby CLI to create a new site, specifying the default starter. 20 | 21 | ```sh 22 | # create a new Gatsby site using the default starter 23 | gatsby new my-default-starter https://github.com/gatsbyjs/gatsby-starter-default 24 | ``` 25 | 26 | 1. **Start developing.** 27 | 28 | Navigate into your new site’s directory and start it up. 29 | 30 | ```sh 31 | cd my-default-starter/ 32 | gatsby develop 33 | ``` 34 | 35 | 1. **Open the source code and start editing!** 36 | 37 | Your site is now running at `http://localhost:8000`! 38 | 39 | _Note: You'll also see a second link: _`http://localhost:8000/___graphql`_. This is a tool you can use to experiment with querying your data. Learn more about using this tool in the [Gatsby tutorial](https://www.gatsbyjs.org/tutorial/part-five/#introducing-graphiql)._ 40 | 41 | Open the `my-default-starter` directory in your code editor of choice and edit `src/pages/index.js`. Save your changes and the browser will update in real time! 42 | 43 | ## 🧐 What's inside? 44 | 45 | A quick look at the top-level files and directories you'll see in a Gatsby project. 46 | 47 | . 48 | ├── node_modules 49 | ├── src 50 | ├── .gitignore 51 | ├── .prettierrc 52 | ├── gatsby-browser.js 53 | ├── gatsby-config.js 54 | ├── gatsby-node.js 55 | ├── gatsby-ssr.js 56 | ├── LICENSE 57 | ├── package-lock.json 58 | ├── package.json 59 | └── README.md 60 | 61 | 1. **`/node_modules`**: This directory contains all of the modules of code that your project depends on (npm packages) are automatically installed. 62 | 63 | 2. **`/src`**: This directory will contain all of the code related to what you will see on the front-end of your site (what you see in the browser) such as your site header or a page template. `src` is a convention for “source code”. 64 | 65 | 3. **`.gitignore`**: This file tells git which files it should not track / not maintain a version history for. 66 | 67 | 4. **`.prettierrc`**: This is a configuration file for [Prettier](https://prettier.io/). Prettier is a tool to help keep the formatting of your code consistent. 68 | 69 | 5. **`gatsby-browser.js`**: This file is where Gatsby expects to find any usage of the [Gatsby browser APIs](https://www.gatsbyjs.org/docs/browser-apis/) (if any). These allow customization/extension of default Gatsby settings affecting the browser. 70 | 71 | 6. **`gatsby-config.js`**: This is the main configuration file for a Gatsby site. This is where you can specify information about your site (metadata) like the site title and description, which Gatsby plugins you’d like to include, etc. (Check out the [config docs](https://www.gatsbyjs.org/docs/gatsby-config/) for more detail). 72 | 73 | 7. **`gatsby-node.js`**: This file is where Gatsby expects to find any usage of the [Gatsby Node APIs](https://www.gatsbyjs.org/docs/node-apis/) (if any). These allow customization/extension of default Gatsby settings affecting pieces of the site build process. 74 | 75 | 8. **`gatsby-ssr.js`**: This file is where Gatsby expects to find any usage of the [Gatsby server-side rendering APIs](https://www.gatsbyjs.org/docs/ssr-apis/) (if any). These allow customization of default Gatsby settings affecting server-side rendering. 76 | 77 | 9. **`LICENSE`**: Gatsby is licensed under the MIT license. 78 | 79 | 10. **`package-lock.json`** (See `package.json` below, first). This is an automatically generated file based on the exact versions of your npm dependencies that were installed for your project. **(You won’t change this file directly).** 80 | 81 | 11. **`package.json`**: A manifest file for Node.js projects, which includes things like metadata (the project’s name, author, etc). This manifest is how npm knows which packages to install for your project. 82 | 83 | 12. **`README.md`**: A text file containing useful reference information about your project. 84 | 85 | ## 🎓 Learning Gatsby 86 | 87 | Looking for more guidance? Full documentation for Gatsby lives [on the website](https://www.gatsbyjs.org/). Here are some places to start: 88 | 89 | - **For most developers, we recommend starting with our [in-depth tutorial for creating a site with Gatsby](https://www.gatsbyjs.org/tutorial/).** It starts with zero assumptions about your level of ability and walks through every step of the process. 90 | 91 | - **To dive straight into code samples, head [to our documentation](https://www.gatsbyjs.org/docs/).** In particular, check out the _Guides_, _API Reference_, and _Advanced Tutorials_ sections in the sidebar. 92 | 93 | ## 💫 Deploy 94 | 95 | [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/gatsbyjs/gatsby-starter-default) 96 | 97 | 98 | -------------------------------------------------------------------------------- /blog/gatsby-browser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Browser APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/browser-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /blog/gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: "My super blog", 4 | description: "Gatsby blog with Strapi", 5 | author: "Strapi team", 6 | }, 7 | plugins: [ 8 | "gatsby-plugin-react-helmet", 9 | { 10 | resolve: `gatsby-source-filesystem`, 11 | options: { 12 | name: `images`, 13 | path: `${__dirname}/src/images`, 14 | }, 15 | }, 16 | { 17 | resolve: "gatsby-source-strapi", 18 | options: { 19 | apiURL: process.env.DEPLOY_URL 20 | ? "https://YOUR-UNIQUE-HEROKU-URL.herokuapp.com" 21 | : "http://localhost:1337", 22 | contentTypes: [ 23 | // List of the Content Types you want to be able to request from Gatsby. 24 | "article", 25 | "user", 26 | ], 27 | queryLimit: 1000, 28 | }, 29 | }, 30 | "gatsby-transformer-sharp", 31 | "gatsby-plugin-sharp", 32 | { 33 | resolve: `gatsby-plugin-manifest`, 34 | options: { 35 | name: "gatsby-starter-default", 36 | short_name: "starter", 37 | start_url: "/", 38 | background_color: "#663399", 39 | theme_color: "#663399", 40 | display: "minimal-ui", 41 | icon: "src/images/gatsby-icon.png", // This path is relative to the root of the site. 42 | }, 43 | }, 44 | "gatsby-plugin-offline", 45 | ], 46 | } 47 | -------------------------------------------------------------------------------- /blog/gatsby-node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Node APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/node-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | 9 | const path = require(`path`) 10 | 11 | const makeRequest = (graphql, request) => 12 | new Promise((resolve, reject) => { 13 | // Query for article nodes to use in creating pages. 14 | resolve( 15 | graphql(request).then(result => { 16 | if (result.errors) { 17 | reject(result.errors) 18 | } 19 | 20 | return result 21 | }) 22 | ) 23 | }) 24 | 25 | // Implement the Gatsby API “createPages”. This is called once the 26 | // data layer is bootstrapped to let plugins create pages from data. 27 | exports.createPages = ({ actions, graphql }) => { 28 | const { createPage } = actions 29 | 30 | const getArticles = makeRequest( 31 | graphql, 32 | ` 33 | { 34 | allStrapiArticle { 35 | edges { 36 | node { 37 | id 38 | } 39 | } 40 | } 41 | } 42 | ` 43 | ).then(result => { 44 | // Create pages for each article. 45 | result.data.allStrapiArticle.edges.forEach(({ node }) => { 46 | createPage({ 47 | path: `/${node.id}`, 48 | component: path.resolve(`src/templates/article.js`), 49 | context: { 50 | id: node.id, 51 | }, 52 | }) 53 | }) 54 | }) 55 | 56 | const getAuthors = makeRequest( 57 | graphql, 58 | ` 59 | { 60 | allStrapiUser { 61 | edges { 62 | node { 63 | id 64 | } 65 | } 66 | } 67 | } 68 | ` 69 | ).then(result => { 70 | // Create pages for each user. 71 | result.data.allStrapiUser.edges.forEach(({ node }) => { 72 | createPage({ 73 | path: `/authors/${node.id}`, 74 | component: path.resolve(`src/templates/author.js`), 75 | context: { 76 | id: node.id, 77 | }, 78 | }) 79 | }) 80 | }) 81 | 82 | // Queries for articles and authors nodes to use in creating pages. 83 | return Promise.all([getArticles, getAuthors]) 84 | } 85 | -------------------------------------------------------------------------------- /blog/gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/ssr-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /blog/netlify.toml: -------------------------------------------------------------------------------- 1 | # example netlify.toml 2 | [build] 3 | command = "gatsby build" 4 | functions = "functions" 5 | publish = "public" 6 | 7 | ## Uncomment to use this redirect for Single Page Applications like create-react-app. 8 | ## Not needed for static site generators. 9 | #[[redirects]] 10 | # from = "/*" 11 | # to = "/index.html" 12 | # status = 200 13 | 14 | ## (optional) Settings for Netlify Dev 15 | ## https://github.com/netlify/netlify-dev-plugin#project-detection 16 | #[dev] 17 | # command = "yarn start" # Command to start your dev server 18 | # port = 3000 # Port that the dev server will be listening on 19 | # publish = "dist" # Folder with the static content for _redirect file 20 | 21 | ## more info on configuring this file: https://www.netlify.com/docs/netlify-toml-reference/ 22 | -------------------------------------------------------------------------------- /blog/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-starter-default", 3 | "private": true, 4 | "description": "A simple starter to get up and developing quickly with Gatsby", 5 | "version": "0.1.0", 6 | "author": "Kyle Mathews ", 7 | "dependencies": { 8 | "gatsby": "^2.11.7", 9 | "gatsby-image": "^2.2.3", 10 | "gatsby-plugin-manifest": "^2.2.0", 11 | "gatsby-plugin-offline": "^2.2.0", 12 | "gatsby-plugin-react-helmet": "^3.1.0", 13 | "gatsby-plugin-sharp": "^2.2.1", 14 | "gatsby-source-filesystem": "^2.1.1", 15 | "gatsby-source-strapi": "0.0.8", 16 | "gatsby-transformer-sharp": "^2.2.0", 17 | "prop-types": "^15.7.2", 18 | "react": "^16.8.6", 19 | "react-dom": "^16.8.6", 20 | "react-helmet": "^5.2.1", 21 | "react-markdown": "^4.1.0" 22 | }, 23 | "devDependencies": { 24 | "prettier": "^1.18.2" 25 | }, 26 | "keywords": [ 27 | "gatsby" 28 | ], 29 | "license": "MIT", 30 | "scripts": { 31 | "build": "gatsby build", 32 | "develop": "gatsby develop", 33 | "format": "prettier --write src/**/*.{js,jsx}", 34 | "start": "npm run develop", 35 | "serve": "gatsby serve", 36 | "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\"" 37 | }, 38 | "repository": { 39 | "type": "git", 40 | "url": "https://github.com/gatsbyjs/gatsby-starter-default" 41 | }, 42 | "bugs": { 43 | "url": "https://github.com/gatsbyjs/gatsby/issues" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /blog/src/components/header.js: -------------------------------------------------------------------------------- 1 | import { Link } from "gatsby" 2 | import PropTypes from "prop-types" 3 | import React from "react" 4 | 5 | const Header = ({ siteTitle }) => ( 6 |
12 |
19 |

20 | 27 | {siteTitle} 28 | 29 |

30 |
31 |
32 | ) 33 | 34 | Header.propTypes = { 35 | siteTitle: PropTypes.string, 36 | } 37 | 38 | Header.defaultProps = { 39 | siteTitle: ``, 40 | } 41 | 42 | export default Header 43 | -------------------------------------------------------------------------------- /blog/src/components/image.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { useStaticQuery, graphql } from "gatsby" 3 | import Img from "gatsby-image" 4 | 5 | /* 6 | * This component is built using `gatsby-image` to automatically serve optimized 7 | * images with lazy loading and reduced file sizes. The image is loaded using a 8 | * `useStaticQuery`, which allows us to load the image from directly within this 9 | * component, rather than having to pass the image data down from pages. 10 | * 11 | * For more information, see the docs: 12 | * - `gatsby-image`: https://gatsby.dev/gatsby-image 13 | * - `useStaticQuery`: https://www.gatsbyjs.org/docs/use-static-query/ 14 | */ 15 | 16 | const Image = () => { 17 | const data = useStaticQuery(graphql` 18 | query { 19 | placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) { 20 | childImageSharp { 21 | fluid(maxWidth: 300) { 22 | ...GatsbyImageSharpFluid 23 | } 24 | } 25 | } 26 | } 27 | `) 28 | 29 | return 30 | } 31 | 32 | export default Image 33 | -------------------------------------------------------------------------------- /blog/src/components/layout.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-family: sans-serif; 3 | -ms-text-size-adjust: 100%; 4 | -webkit-text-size-adjust: 100%; 5 | } 6 | body { 7 | margin: 0; 8 | -webkit-font-smoothing: antialiased; 9 | -moz-osx-font-smoothing: grayscale; 10 | } 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | main, 19 | menu, 20 | nav, 21 | section, 22 | summary { 23 | display: block; 24 | } 25 | audio, 26 | canvas, 27 | progress, 28 | video { 29 | display: inline-block; 30 | } 31 | audio:not([controls]) { 32 | display: none; 33 | height: 0; 34 | } 35 | progress { 36 | vertical-align: baseline; 37 | } 38 | [hidden], 39 | template { 40 | display: none; 41 | } 42 | a { 43 | background-color: transparent; 44 | -webkit-text-decoration-skip: objects; 45 | } 46 | a:active, 47 | a:hover { 48 | outline-width: 0; 49 | } 50 | abbr[title] { 51 | border-bottom: none; 52 | text-decoration: underline; 53 | text-decoration: underline dotted; 54 | } 55 | b, 56 | strong { 57 | font-weight: inherit; 58 | font-weight: bolder; 59 | } 60 | dfn { 61 | font-style: italic; 62 | } 63 | h1 { 64 | font-size: 2em; 65 | margin: 0.67em 0; 66 | } 67 | mark { 68 | background-color: #ff0; 69 | color: #000; 70 | } 71 | small { 72 | font-size: 80%; 73 | } 74 | sub, 75 | sup { 76 | font-size: 75%; 77 | line-height: 0; 78 | position: relative; 79 | vertical-align: baseline; 80 | } 81 | sub { 82 | bottom: -0.25em; 83 | } 84 | sup { 85 | top: -0.5em; 86 | } 87 | img { 88 | border-style: none; 89 | } 90 | svg:not(:root) { 91 | overflow: hidden; 92 | } 93 | code, 94 | kbd, 95 | pre, 96 | samp { 97 | font-family: monospace, monospace; 98 | font-size: 1em; 99 | } 100 | figure { 101 | margin: 1em 40px; 102 | } 103 | hr { 104 | box-sizing: content-box; 105 | height: 0; 106 | overflow: visible; 107 | } 108 | button, 109 | input, 110 | optgroup, 111 | select, 112 | textarea { 113 | font: inherit; 114 | margin: 0; 115 | } 116 | optgroup { 117 | font-weight: 700; 118 | } 119 | button, 120 | input { 121 | overflow: visible; 122 | } 123 | button, 124 | select { 125 | text-transform: none; 126 | } 127 | [type="reset"], 128 | [type="submit"], 129 | button, 130 | html [type="button"] { 131 | -webkit-appearance: button; 132 | } 133 | [type="button"]::-moz-focus-inner, 134 | [type="reset"]::-moz-focus-inner, 135 | [type="submit"]::-moz-focus-inner, 136 | button::-moz-focus-inner { 137 | border-style: none; 138 | padding: 0; 139 | } 140 | [type="button"]:-moz-focusring, 141 | [type="reset"]:-moz-focusring, 142 | [type="submit"]:-moz-focusring, 143 | button:-moz-focusring { 144 | outline: 1px dotted ButtonText; 145 | } 146 | fieldset { 147 | border: 1px solid silver; 148 | margin: 0 2px; 149 | padding: 0.35em 0.625em 0.75em; 150 | } 151 | legend { 152 | box-sizing: border-box; 153 | color: inherit; 154 | display: table; 155 | max-width: 100%; 156 | padding: 0; 157 | white-space: normal; 158 | } 159 | textarea { 160 | overflow: auto; 161 | } 162 | [type="checkbox"], 163 | [type="radio"] { 164 | box-sizing: border-box; 165 | padding: 0; 166 | } 167 | [type="number"]::-webkit-inner-spin-button, 168 | [type="number"]::-webkit-outer-spin-button { 169 | height: auto; 170 | } 171 | [type="search"] { 172 | -webkit-appearance: textfield; 173 | outline-offset: -2px; 174 | } 175 | [type="search"]::-webkit-search-cancel-button, 176 | [type="search"]::-webkit-search-decoration { 177 | -webkit-appearance: none; 178 | } 179 | ::-webkit-input-placeholder { 180 | color: inherit; 181 | opacity: 0.54; 182 | } 183 | ::-webkit-file-upload-button { 184 | -webkit-appearance: button; 185 | font: inherit; 186 | } 187 | html { 188 | font: 112.5%/1.45em georgia, serif; 189 | box-sizing: border-box; 190 | overflow-y: scroll; 191 | } 192 | * { 193 | box-sizing: inherit; 194 | } 195 | *:before { 196 | box-sizing: inherit; 197 | } 198 | *:after { 199 | box-sizing: inherit; 200 | } 201 | body { 202 | color: hsla(0, 0%, 0%, 0.8); 203 | font-family: georgia, serif; 204 | font-weight: normal; 205 | word-wrap: break-word; 206 | font-kerning: normal; 207 | -moz-font-feature-settings: "kern", "liga", "clig", "calt"; 208 | -ms-font-feature-settings: "kern", "liga", "clig", "calt"; 209 | -webkit-font-feature-settings: "kern", "liga", "clig", "calt"; 210 | font-feature-settings: "kern", "liga", "clig", "calt"; 211 | } 212 | img { 213 | max-width: 100%; 214 | margin-left: 0; 215 | margin-right: 0; 216 | margin-top: 0; 217 | padding-bottom: 0; 218 | padding-left: 0; 219 | padding-right: 0; 220 | padding-top: 0; 221 | margin-bottom: 1.45rem; 222 | } 223 | h1 { 224 | margin-left: 0; 225 | margin-right: 0; 226 | margin-top: 0; 227 | padding-bottom: 0; 228 | padding-left: 0; 229 | padding-right: 0; 230 | padding-top: 0; 231 | margin-bottom: 1.45rem; 232 | color: inherit; 233 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 234 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 235 | font-weight: bold; 236 | text-rendering: optimizeLegibility; 237 | font-size: 2.25rem; 238 | line-height: 1.1; 239 | } 240 | h2 { 241 | margin-left: 0; 242 | margin-right: 0; 243 | margin-top: 0; 244 | padding-bottom: 0; 245 | padding-left: 0; 246 | padding-right: 0; 247 | padding-top: 0; 248 | margin-bottom: 1.45rem; 249 | color: inherit; 250 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 251 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 252 | font-weight: bold; 253 | text-rendering: optimizeLegibility; 254 | font-size: 1.62671rem; 255 | line-height: 1.1; 256 | } 257 | h3 { 258 | margin-left: 0; 259 | margin-right: 0; 260 | margin-top: 0; 261 | padding-bottom: 0; 262 | padding-left: 0; 263 | padding-right: 0; 264 | padding-top: 0; 265 | margin-bottom: 1.45rem; 266 | color: inherit; 267 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 268 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 269 | font-weight: bold; 270 | text-rendering: optimizeLegibility; 271 | font-size: 1.38316rem; 272 | line-height: 1.1; 273 | } 274 | h4 { 275 | margin-left: 0; 276 | margin-right: 0; 277 | margin-top: 0; 278 | padding-bottom: 0; 279 | padding-left: 0; 280 | padding-right: 0; 281 | padding-top: 0; 282 | margin-bottom: 1.45rem; 283 | color: inherit; 284 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 285 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 286 | font-weight: bold; 287 | text-rendering: optimizeLegibility; 288 | font-size: 1rem; 289 | line-height: 1.1; 290 | } 291 | h5 { 292 | margin-left: 0; 293 | margin-right: 0; 294 | margin-top: 0; 295 | padding-bottom: 0; 296 | padding-left: 0; 297 | padding-right: 0; 298 | padding-top: 0; 299 | margin-bottom: 1.45rem; 300 | color: inherit; 301 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 302 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 303 | font-weight: bold; 304 | text-rendering: optimizeLegibility; 305 | font-size: 0.85028rem; 306 | line-height: 1.1; 307 | } 308 | h6 { 309 | margin-left: 0; 310 | margin-right: 0; 311 | margin-top: 0; 312 | padding-bottom: 0; 313 | padding-left: 0; 314 | padding-right: 0; 315 | padding-top: 0; 316 | margin-bottom: 1.45rem; 317 | color: inherit; 318 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 319 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 320 | font-weight: bold; 321 | text-rendering: optimizeLegibility; 322 | font-size: 0.78405rem; 323 | line-height: 1.1; 324 | } 325 | hgroup { 326 | margin-left: 0; 327 | margin-right: 0; 328 | margin-top: 0; 329 | padding-bottom: 0; 330 | padding-left: 0; 331 | padding-right: 0; 332 | padding-top: 0; 333 | margin-bottom: 1.45rem; 334 | } 335 | ul { 336 | margin-left: 1.45rem; 337 | margin-right: 0; 338 | margin-top: 0; 339 | padding-bottom: 0; 340 | padding-left: 0; 341 | padding-right: 0; 342 | padding-top: 0; 343 | margin-bottom: 1.45rem; 344 | list-style-position: outside; 345 | list-style-image: none; 346 | } 347 | ol { 348 | margin-left: 1.45rem; 349 | margin-right: 0; 350 | margin-top: 0; 351 | padding-bottom: 0; 352 | padding-left: 0; 353 | padding-right: 0; 354 | padding-top: 0; 355 | margin-bottom: 1.45rem; 356 | list-style-position: outside; 357 | list-style-image: none; 358 | } 359 | dl { 360 | margin-left: 0; 361 | margin-right: 0; 362 | margin-top: 0; 363 | padding-bottom: 0; 364 | padding-left: 0; 365 | padding-right: 0; 366 | padding-top: 0; 367 | margin-bottom: 1.45rem; 368 | } 369 | dd { 370 | margin-left: 0; 371 | margin-right: 0; 372 | margin-top: 0; 373 | padding-bottom: 0; 374 | padding-left: 0; 375 | padding-right: 0; 376 | padding-top: 0; 377 | margin-bottom: 1.45rem; 378 | } 379 | p { 380 | margin-left: 0; 381 | margin-right: 0; 382 | margin-top: 0; 383 | padding-bottom: 0; 384 | padding-left: 0; 385 | padding-right: 0; 386 | padding-top: 0; 387 | margin-bottom: 1.45rem; 388 | } 389 | figure { 390 | margin-left: 0; 391 | margin-right: 0; 392 | margin-top: 0; 393 | padding-bottom: 0; 394 | padding-left: 0; 395 | padding-right: 0; 396 | padding-top: 0; 397 | margin-bottom: 1.45rem; 398 | } 399 | pre { 400 | margin-left: 0; 401 | margin-right: 0; 402 | margin-top: 0; 403 | margin-bottom: 1.45rem; 404 | font-size: 0.85rem; 405 | line-height: 1.42; 406 | background: hsla(0, 0%, 0%, 0.04); 407 | border-radius: 3px; 408 | overflow: auto; 409 | word-wrap: normal; 410 | padding: 1.45rem; 411 | } 412 | table { 413 | margin-left: 0; 414 | margin-right: 0; 415 | margin-top: 0; 416 | padding-bottom: 0; 417 | padding-left: 0; 418 | padding-right: 0; 419 | padding-top: 0; 420 | margin-bottom: 1.45rem; 421 | font-size: 1rem; 422 | line-height: 1.45rem; 423 | border-collapse: collapse; 424 | width: 100%; 425 | } 426 | fieldset { 427 | margin-left: 0; 428 | margin-right: 0; 429 | margin-top: 0; 430 | padding-bottom: 0; 431 | padding-left: 0; 432 | padding-right: 0; 433 | padding-top: 0; 434 | margin-bottom: 1.45rem; 435 | } 436 | blockquote { 437 | margin-left: 1.45rem; 438 | margin-right: 1.45rem; 439 | margin-top: 0; 440 | padding-bottom: 0; 441 | padding-left: 0; 442 | padding-right: 0; 443 | padding-top: 0; 444 | margin-bottom: 1.45rem; 445 | } 446 | form { 447 | margin-left: 0; 448 | margin-right: 0; 449 | margin-top: 0; 450 | padding-bottom: 0; 451 | padding-left: 0; 452 | padding-right: 0; 453 | padding-top: 0; 454 | margin-bottom: 1.45rem; 455 | } 456 | noscript { 457 | margin-left: 0; 458 | margin-right: 0; 459 | margin-top: 0; 460 | padding-bottom: 0; 461 | padding-left: 0; 462 | padding-right: 0; 463 | padding-top: 0; 464 | margin-bottom: 1.45rem; 465 | } 466 | iframe { 467 | margin-left: 0; 468 | margin-right: 0; 469 | margin-top: 0; 470 | padding-bottom: 0; 471 | padding-left: 0; 472 | padding-right: 0; 473 | padding-top: 0; 474 | margin-bottom: 1.45rem; 475 | } 476 | hr { 477 | margin-left: 0; 478 | margin-right: 0; 479 | margin-top: 0; 480 | padding-bottom: 0; 481 | padding-left: 0; 482 | padding-right: 0; 483 | padding-top: 0; 484 | margin-bottom: calc(1.45rem - 1px); 485 | background: hsla(0, 0%, 0%, 0.2); 486 | border: none; 487 | height: 1px; 488 | } 489 | address { 490 | margin-left: 0; 491 | margin-right: 0; 492 | margin-top: 0; 493 | padding-bottom: 0; 494 | padding-left: 0; 495 | padding-right: 0; 496 | padding-top: 0; 497 | margin-bottom: 1.45rem; 498 | } 499 | b { 500 | font-weight: bold; 501 | } 502 | strong { 503 | font-weight: bold; 504 | } 505 | dt { 506 | font-weight: bold; 507 | } 508 | th { 509 | font-weight: bold; 510 | } 511 | li { 512 | margin-bottom: calc(1.45rem / 2); 513 | } 514 | ol li { 515 | padding-left: 0; 516 | } 517 | ul li { 518 | padding-left: 0; 519 | } 520 | li > ol { 521 | margin-left: 1.45rem; 522 | margin-bottom: calc(1.45rem / 2); 523 | margin-top: calc(1.45rem / 2); 524 | } 525 | li > ul { 526 | margin-left: 1.45rem; 527 | margin-bottom: calc(1.45rem / 2); 528 | margin-top: calc(1.45rem / 2); 529 | } 530 | blockquote *:last-child { 531 | margin-bottom: 0; 532 | } 533 | li *:last-child { 534 | margin-bottom: 0; 535 | } 536 | p *:last-child { 537 | margin-bottom: 0; 538 | } 539 | li > p { 540 | margin-bottom: calc(1.45rem / 2); 541 | } 542 | code { 543 | font-size: 0.85rem; 544 | line-height: 1.45rem; 545 | } 546 | kbd { 547 | font-size: 0.85rem; 548 | line-height: 1.45rem; 549 | } 550 | samp { 551 | font-size: 0.85rem; 552 | line-height: 1.45rem; 553 | } 554 | abbr { 555 | border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); 556 | cursor: help; 557 | } 558 | acronym { 559 | border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); 560 | cursor: help; 561 | } 562 | abbr[title] { 563 | border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); 564 | cursor: help; 565 | text-decoration: none; 566 | } 567 | thead { 568 | text-align: left; 569 | } 570 | td, 571 | th { 572 | text-align: left; 573 | border-bottom: 1px solid hsla(0, 0%, 0%, 0.12); 574 | font-feature-settings: "tnum"; 575 | -moz-font-feature-settings: "tnum"; 576 | -ms-font-feature-settings: "tnum"; 577 | -webkit-font-feature-settings: "tnum"; 578 | padding-left: 0.96667rem; 579 | padding-right: 0.96667rem; 580 | padding-top: 0.725rem; 581 | padding-bottom: calc(0.725rem - 1px); 582 | } 583 | th:first-child, 584 | td:first-child { 585 | padding-left: 0; 586 | } 587 | th:last-child, 588 | td:last-child { 589 | padding-right: 0; 590 | } 591 | tt, 592 | code { 593 | background-color: hsla(0, 0%, 0%, 0.04); 594 | border-radius: 3px; 595 | font-family: "SFMono-Regular", Consolas, "Roboto Mono", "Droid Sans Mono", 596 | "Liberation Mono", Menlo, Courier, monospace; 597 | padding: 0; 598 | padding-top: 0.2em; 599 | padding-bottom: 0.2em; 600 | } 601 | pre code { 602 | background: none; 603 | line-height: 1.42; 604 | } 605 | code:before, 606 | code:after, 607 | tt:before, 608 | tt:after { 609 | letter-spacing: -0.2em; 610 | content: " "; 611 | } 612 | pre code:before, 613 | pre code:after, 614 | pre tt:before, 615 | pre tt:after { 616 | content: ""; 617 | } 618 | @media only screen and (max-width: 480px) { 619 | html { 620 | font-size: 100%; 621 | } 622 | } 623 | -------------------------------------------------------------------------------- /blog/src/components/layout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Layout component that queries for data 3 | * with Gatsby's useStaticQuery component 4 | * 5 | * See: https://www.gatsbyjs.org/docs/use-static-query/ 6 | */ 7 | 8 | import React from "react" 9 | import PropTypes from "prop-types" 10 | import { useStaticQuery, graphql } from "gatsby" 11 | 12 | import Header from "./header" 13 | import "./layout.css" 14 | 15 | const Layout = ({ children }) => { 16 | const data = useStaticQuery(graphql` 17 | query SiteTitleQuery { 18 | site { 19 | siteMetadata { 20 | title 21 | } 22 | } 23 | } 24 | `) 25 | 26 | return ( 27 | <> 28 |
29 |
37 |
{children}
38 |
39 | © {new Date().getFullYear()}, Built with 40 | {` `} 41 | Gatsby and{" "} 42 | Strapi 43 |
44 |
45 | 46 | ) 47 | } 48 | 49 | Layout.propTypes = { 50 | children: PropTypes.node.isRequired, 51 | } 52 | 53 | export default Layout 54 | -------------------------------------------------------------------------------- /blog/src/components/seo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SEO component that queries for data with 3 | * Gatsby's useStaticQuery React hook 4 | * 5 | * See: https://www.gatsbyjs.org/docs/use-static-query/ 6 | */ 7 | 8 | import React from "react" 9 | import PropTypes from "prop-types" 10 | import Helmet from "react-helmet" 11 | import { useStaticQuery, graphql } from "gatsby" 12 | 13 | function SEO({ description, lang, meta, title }) { 14 | const { site } = useStaticQuery( 15 | graphql` 16 | query { 17 | site { 18 | siteMetadata { 19 | title 20 | description 21 | author 22 | } 23 | } 24 | } 25 | ` 26 | ) 27 | 28 | const metaDescription = description || site.siteMetadata.description 29 | 30 | return ( 31 | 72 | ) 73 | } 74 | 75 | SEO.defaultProps = { 76 | lang: `en`, 77 | meta: [], 78 | description: ``, 79 | } 80 | 81 | SEO.propTypes = { 82 | description: PropTypes.string, 83 | lang: PropTypes.string, 84 | meta: PropTypes.arrayOf(PropTypes.object), 85 | title: PropTypes.string.isRequired, 86 | } 87 | 88 | export default SEO 89 | -------------------------------------------------------------------------------- /blog/src/images/gatsby-astronaut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/blog/src/images/gatsby-astronaut.png -------------------------------------------------------------------------------- /blog/src/images/gatsby-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/blog/src/images/gatsby-icon.png -------------------------------------------------------------------------------- /blog/src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | import Layout from "../components/layout" 4 | import SEO from "../components/seo" 5 | 6 | const NotFoundPage = () => ( 7 | 8 | 9 |

NOT FOUND

10 |

You just hit a route that doesn't exist... the sadness.

11 |
12 | ) 13 | 14 | export default NotFoundPage 15 | -------------------------------------------------------------------------------- /blog/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link, graphql } from "gatsby" 3 | import Img from "gatsby-image" 4 | import Layout from "../components/layout" 5 | import ReactMarkdown from "react-markdown" 6 | 7 | import "../styles/global.css" 8 | 9 | const IndexPage = ({ data }) => ( 10 | 11 |

Hi people

12 |

Welcome to your new Gatsby site.

13 |

Now go build something great.

14 |
    15 | {data.allStrapiArticle.edges.map(document => ( 16 |
  • 17 |

    18 | {document.node.title} 19 |

    20 | 21 | 24 | uri.startsWith("http") 25 | ? uri 26 | : `${process.env.IMAGE_BASE_URL}${uri}` 27 | } 28 | className="indexArticle" 29 | escapeHtml={false} 30 | /> 31 | 32 | Read more 33 |
  • 34 | ))} 35 |
36 | Go to page 2 37 |
38 | ) 39 | 40 | export default IndexPage 41 | 42 | export const pageQuery = graphql` 43 | query IndexQuery { 44 | allStrapiArticle { 45 | edges { 46 | node { 47 | id 48 | image { 49 | childImageSharp { 50 | fixed(width: 200, height: 125) { 51 | ...GatsbyImageSharpFixed 52 | } 53 | } 54 | } 55 | title 56 | content 57 | } 58 | } 59 | } 60 | } 61 | ` 62 | -------------------------------------------------------------------------------- /blog/src/pages/page-2.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "gatsby" 3 | 4 | import Layout from "../components/layout" 5 | import SEO from "../components/seo" 6 | 7 | const SecondPage = () => ( 8 | 9 | 10 |

Hi from the second page

11 |

Welcome to page 2

12 | Go back to the homepage 13 |
14 | ) 15 | 16 | export default SecondPage 17 | -------------------------------------------------------------------------------- /blog/src/styles/global.css: -------------------------------------------------------------------------------- 1 | .indexArticle { 2 | max-height: 250px; 3 | overflow: hidden; 4 | } 5 | 6 | .indexArticle img { 7 | display: none; 8 | } 9 | 10 | .articleContent img { 11 | display: block; 12 | margin: 0 auto; 13 | width: 400px; 14 | } 15 | 16 | .articleContent .small { 17 | width: 100%; 18 | max-width: 250px; 19 | } 20 | 21 | .articleContent .large { 22 | width: 100%; 23 | max-width: 600px; 24 | } 25 | -------------------------------------------------------------------------------- /blog/src/templates/article.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link, graphql } from "gatsby" 3 | import Img from "gatsby-image" 4 | import Layout from "../components/layout" 5 | import ReactMarkdown from "react-markdown" 6 | 7 | import "../styles/global.css" 8 | 9 | const ArticleTemplate = ({ data }) => ( 10 | 11 |

{data.strapiArticle.title}

12 |

13 | by{" "} 14 | 15 | {data.strapiArticle.author.username} 16 | 17 |

18 | 19 | 22 | uri.startsWith("http") ? uri : `${process.env.IMAGE_BASE_URL}${uri}` 23 | } 24 | className="articleContent" 25 | escapeHtml={false} 26 | /> 27 |
28 | ) 29 | 30 | export default ArticleTemplate 31 | 32 | export const query = graphql` 33 | query ArticleTemplate($id: String!) { 34 | strapiArticle(id: { eq: $id }) { 35 | title 36 | content 37 | image { 38 | childImageSharp { 39 | fluid(maxWidth: 960) { 40 | ...GatsbyImageSharpFluid 41 | } 42 | } 43 | } 44 | author { 45 | id 46 | username 47 | } 48 | } 49 | } 50 | ` 51 | -------------------------------------------------------------------------------- /blog/src/templates/author.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link, graphql } from "gatsby" 3 | import Layout from "../components/layout" 4 | import ReactMarkdown from "react-markdown" 5 | 6 | import "../styles/global.css" 7 | 8 | const UserTemplate = ({ data }) => ( 9 | 10 |

{data.strapiUser.username}

11 |
    12 | {data.strapiUser.articles.map(article => ( 13 |
  • 14 |

    15 | {article.title} 16 |

    17 | 18 | 21 | uri.startsWith("http") 22 | ? uri 23 | : `${process.env.IMAGE_BASE_URL}${uri}` 24 | } 25 | className="indexArticle" 26 | escapeHtml={false} 27 | /> 28 | 29 | Read more 30 |
  • 31 | ))} 32 |
33 |
34 | ) 35 | 36 | export default UserTemplate 37 | 38 | export const query = graphql` 39 | query UserTemplate($id: String!) { 40 | strapiUser(id: { eq: $id }) { 41 | id 42 | username 43 | articles { 44 | id 45 | title 46 | content 47 | } 48 | } 49 | } 50 | ` 51 | -------------------------------------------------------------------------------- /cms/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [{package.json,*.yml}] 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /cms/.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/** 2 | -------------------------------------------------------------------------------- /cms/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "eslint:recommended", 4 | "env": { 5 | "commonjs": true, 6 | "es6": true, 7 | "node": true, 8 | "browser": false 9 | }, 10 | "parserOptions": { 11 | "ecmaFeatures": { 12 | "experimentalObjectRestSpread": true, 13 | "jsx": false 14 | }, 15 | "sourceType": "module" 16 | }, 17 | "globals": { 18 | "strapi": true 19 | }, 20 | "rules": { 21 | "indent": ["error", 2, { "SwitchCase": 1 }], 22 | "linebreak-style": ["error", "unix"], 23 | "no-console": 0, 24 | "quotes": ["error", "single"], 25 | "semi": ["error", "always"] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /cms/.gitignore: -------------------------------------------------------------------------------- 1 | ############################ 2 | # OS X 3 | ############################ 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | Icon 9 | .Spotlight-V100 10 | .Trashes 11 | ._* 12 | 13 | 14 | ############################ 15 | # Linux 16 | ############################ 17 | 18 | *~ 19 | 20 | 21 | ############################ 22 | # Windows 23 | ############################ 24 | 25 | Thumbs.db 26 | ehthumbs.db 27 | Desktop.ini 28 | $RECYCLE.BIN/ 29 | *.cab 30 | *.msi 31 | *.msm 32 | *.msp 33 | 34 | 35 | ############################ 36 | # Packages 37 | ############################ 38 | 39 | *.7z 40 | *.csv 41 | *.dat 42 | *.dmg 43 | *.gz 44 | *.iso 45 | *.jar 46 | *.rar 47 | *.tar 48 | *.zip 49 | *.com 50 | *.class 51 | *.dll 52 | *.exe 53 | *.o 54 | *.seed 55 | *.so 56 | *.swo 57 | *.swp 58 | *.swn 59 | *.swm 60 | *.out 61 | *.pid 62 | 63 | 64 | ############################ 65 | # Logs and databases 66 | ############################ 67 | 68 | .tmp 69 | *.log 70 | *.sql 71 | *.sqlite 72 | *.sqlite3 73 | 74 | 75 | ############################ 76 | # Misc. 77 | ############################ 78 | 79 | *# 80 | ssl 81 | .idea 82 | nbproject 83 | public/uploads/* 84 | !public/uploads/.gitkeep 85 | 86 | ############################ 87 | # Node.js 88 | ############################ 89 | 90 | lib-cov 91 | lcov.info 92 | pids 93 | logs 94 | results 95 | node_modules 96 | .node_history 97 | 98 | 99 | ############################ 100 | # Tests 101 | ############################ 102 | 103 | testApp 104 | coverage 105 | 106 | ############################ 107 | # Strapi 108 | ############################ 109 | 110 | exports 111 | .cache 112 | build 113 | 114 | ############################ 115 | # Strapi Heroku 116 | ############################ 117 | 118 | package-lock.json -------------------------------------------------------------------------------- /cms/README.md: -------------------------------------------------------------------------------- 1 | # cms 2 | 3 | A quick description of cms. 4 | -------------------------------------------------------------------------------- /cms/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/cms/api/.gitkeep -------------------------------------------------------------------------------- /cms/api/article/config/routes.json: -------------------------------------------------------------------------------- 1 | { 2 | "routes": [ 3 | { 4 | "method": "GET", 5 | "path": "/articles", 6 | "handler": "Article.find", 7 | "config": { 8 | "policies": [] 9 | } 10 | }, 11 | { 12 | "method": "GET", 13 | "path": "/articles/count", 14 | "handler": "Article.count", 15 | "config": { 16 | "policies": [] 17 | } 18 | }, 19 | { 20 | "method": "GET", 21 | "path": "/articles/:id", 22 | "handler": "Article.findOne", 23 | "config": { 24 | "policies": [] 25 | } 26 | }, 27 | { 28 | "method": "POST", 29 | "path": "/articles", 30 | "handler": "Article.create", 31 | "config": { 32 | "policies": [] 33 | } 34 | }, 35 | { 36 | "method": "PUT", 37 | "path": "/articles/:id", 38 | "handler": "Article.update", 39 | "config": { 40 | "policies": [] 41 | } 42 | }, 43 | { 44 | "method": "DELETE", 45 | "path": "/articles/:id", 46 | "handler": "Article.delete", 47 | "config": { 48 | "policies": [] 49 | } 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /cms/api/article/controllers/Article.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Read the documentation (https://strapi.io/documentation/3.0.0-beta.x/guides/controllers.html#core-controllers) 5 | * to customize this controller 6 | */ 7 | 8 | module.exports = {}; 9 | -------------------------------------------------------------------------------- /cms/api/article/models/Article.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const axios = require('axios'); 4 | 5 | /** 6 | * Lifecycle callbacks for the `Article` model. 7 | */ 8 | 9 | module.exports = { 10 | // Before saving a value. 11 | // Fired before an `insert` or `update` query. 12 | // beforeSave: async (model, attrs, options) => {}, 13 | 14 | // After saving a value. 15 | // Fired after an `insert` or `update` query. 16 | // afterSave: async (model, response, options) => {}, 17 | 18 | // Before fetching a value. 19 | // Fired before a `fetch` operation. 20 | // beforeFetch: async (model, columns, options) => {}, 21 | 22 | // After fetching a value. 23 | // Fired after a `fetch` operation. 24 | // afterFetch: async (model, response, options) => {}, 25 | 26 | // Before fetching all values. 27 | // Fired before a `fetchAll` operation. 28 | // beforeFetchAll: async (model, columns, options) => {}, 29 | 30 | // After fetching all values. 31 | // Fired after a `fetchAll` operation. 32 | // afterFetchAll: async (model, response, options) => {}, 33 | 34 | // Before creating a value. 35 | // Fired before an `insert` query. 36 | // beforeCreate: async (model, attrs, options) => {}, 37 | 38 | // After creating a value. 39 | // Fired after an `insert` query. 40 | // afterCreate: async (model, attrs, options) => { 41 | afterCreate: async entry => { 42 | axios 43 | .post(strapi.config.currentEnvironment.staticWebsiteBuildURL, entry) 44 | .catch(() => { 45 | // Ignore 46 | }); 47 | }, 48 | 49 | // Before updating a value. 50 | // Fired before an `update` query. 51 | // beforeUpdate: async (model, attrs, options) => {}, 52 | 53 | // After updating a value. 54 | // Fired after an `update` query. 55 | // afterUpdate: async (model, attrs, options) => { 56 | afterUpdate: async entry => { 57 | axios 58 | .post(strapi.config.currentEnvironment.staticWebsiteBuildURL, entry) 59 | .catch(() => { 60 | // Ignore 61 | }); 62 | }, 63 | 64 | // Before destroying a value. 65 | // Fired before a `delete` query. 66 | // beforeDestroy: async (model, attrs, options) => {}, 67 | 68 | // After destroying a value. 69 | // Fired after a `delete` query. 70 | // afterDestroy: async (model, attrs, options) => { 71 | afterDestroy: async entry => { 72 | axios 73 | .post(strapi.config.currentEnvironment.staticWebsiteBuildURL, entry) 74 | .catch(() => { 75 | // Ignore 76 | }); 77 | }, 78 | }; -------------------------------------------------------------------------------- /cms/api/article/models/Article.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "connection": "default", 3 | "collectionName": "articles", 4 | "info": { 5 | "name": "article", 6 | "description": "Travel Articles" 7 | }, 8 | "options": { 9 | "increments": true, 10 | "timestamps": true, 11 | "comment": "" 12 | }, 13 | "attributes": { 14 | "title": { 15 | "minLength": 10, 16 | "required": true, 17 | "unique": true, 18 | "type": "string" 19 | }, 20 | "content": { 21 | "type": "text" 22 | }, 23 | "image": { 24 | "model": "file", 25 | "via": "related", 26 | "plugin": "upload" 27 | }, 28 | "author": { 29 | "model": "user", 30 | "via": "articles", 31 | "plugin": "users-permissions" 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /cms/api/article/services/Article.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Read the documentation (https://strapi.io/documentation/3.0.0-beta.x/guides/services.html#core-services) 5 | * to customize this service 6 | */ 7 | 8 | module.exports = {}; 9 | -------------------------------------------------------------------------------- /cms/config/application.json: -------------------------------------------------------------------------------- 1 | { 2 | "favicon": { 3 | "path": "favicon.ico", 4 | "maxAge": 86400000 5 | }, 6 | "public": { 7 | "path": "./public", 8 | "maxAge": 60000 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /cms/config/custom.json: -------------------------------------------------------------------------------- 1 | { 2 | "myCustomConfiguration": "This configuration is accessible through strapi.config.myCustomConfiguration" 3 | } 4 | -------------------------------------------------------------------------------- /cms/config/environments/development/custom.json: -------------------------------------------------------------------------------- 1 | { 2 | "myCustomConfiguration": "This configuration is accessible through strapi.config.environments.development.myCustomConfiguration" 3 | } 4 | -------------------------------------------------------------------------------- /cms/config/environments/development/database.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultConnection": "default", 3 | "connections": { 4 | "default": { 5 | "connector": "strapi-hook-bookshelf", 6 | "settings": { 7 | "client": "sqlite", 8 | "filename": ".tmp/data.db" 9 | }, 10 | "options": { 11 | "useNullAsDefault": true 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /cms/config/environments/development/request.json: -------------------------------------------------------------------------------- 1 | { 2 | "session": { 3 | "enabled": true, 4 | "client": "cookie", 5 | "key": "strapi.sid", 6 | "prefix": "strapi:sess:", 7 | "secretKeys": ["mySecretKey1", "mySecretKey2"], 8 | "httpOnly": true, 9 | "maxAge": 86400000, 10 | "overwrite": true, 11 | "signed": false, 12 | "rolling": false 13 | }, 14 | "logger": { 15 | "level": "debug", 16 | "exposeInContext": true, 17 | "requests": true 18 | }, 19 | "parser": { 20 | "enabled": true, 21 | "multipart": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cms/config/environments/development/response.json: -------------------------------------------------------------------------------- 1 | { 2 | "gzip": { 3 | "enabled": false 4 | }, 5 | "responseTime": { 6 | "enabled": false 7 | }, 8 | "poweredBy": { 9 | "enabled": true, 10 | "value": "Strapi " 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /cms/config/environments/development/security.json: -------------------------------------------------------------------------------- 1 | { 2 | "csrf": { 3 | "enabled": false, 4 | "key": "_csrf", 5 | "secret": "_csrfSecret" 6 | }, 7 | "csp": { 8 | "enabled": false, 9 | "policy": { 10 | "default-src": "'self'" 11 | } 12 | }, 13 | "p3p": { 14 | "enabled": false, 15 | "value": "" 16 | }, 17 | "hsts": { 18 | "enabled": false, 19 | "maxAge": 31536000, 20 | "includeSubDomains": true 21 | }, 22 | "xframe": { 23 | "enabled": false, 24 | "value": "SAMEORIGIN" 25 | }, 26 | "xss": { 27 | "enabled": false, 28 | "mode": "block" 29 | }, 30 | "cors": { 31 | "enabled": true, 32 | "origin": "*", 33 | "expose": [ 34 | "WWW-Authenticate", 35 | "Server-Authorization" 36 | ], 37 | "maxAge": 31536000, 38 | "credentials": true, 39 | "methods": [ 40 | "GET", 41 | "POST", 42 | "PUT", 43 | "PATCH", 44 | "DELETE", 45 | "OPTIONS", 46 | "HEAD" 47 | ], 48 | "headers": [ 49 | "Content-Type", 50 | "Authorization", 51 | "X-Frame-Options", 52 | "Origin" 53 | ] 54 | }, 55 | "ip": { 56 | "enabled": false, 57 | "whiteList": [], 58 | "blackList": [] 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /cms/config/environments/development/server.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "localhost", 3 | "port": 1337, 4 | "proxy": { 5 | "enabled": false 6 | }, 7 | "cron": { 8 | "enabled": false 9 | }, 10 | "admin": { 11 | "autoOpen": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /cms/config/environments/production/custom.json: -------------------------------------------------------------------------------- 1 | { 2 | "myCustomConfiguration": "This configuration is accessible through strapi.config.environments.production.myCustomConfiguration", 3 | "staticWebsiteBuildURL": "https://api.netlify.com/build_hooks/YOUR-UNIQUE-NETLIFY-URL" 4 | } 5 | -------------------------------------------------------------------------------- /cms/config/environments/production/database.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultConnection": "default", 3 | "connections": { 4 | "default": { 5 | "connector": "strapi-hook-bookshelf", 6 | "settings": { 7 | "client": "postgres", 8 | "host": "${process.env.DATABASE_HOST}", 9 | "port": "${process.env.DATABASE_PORT}", 10 | "database": "${process.env.DATABASE_NAME}", 11 | "username": "${process.env.DATABASE_USERNAME}", 12 | "password": "${process.env.DATABASE_PASSWORD}", 13 | "ssl": true 14 | }, 15 | "options": {} 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /cms/config/environments/production/request.json: -------------------------------------------------------------------------------- 1 | { 2 | "session": { 3 | "enabled": true, 4 | "client": "cookie", 5 | "key": "strapi.sid", 6 | "prefix": "strapi:sess:", 7 | "secretKeys": ["mySecretKey1", "mySecretKey2"], 8 | "httpOnly": true, 9 | "maxAge": 86400000, 10 | "overwrite": true, 11 | "signed": false, 12 | "rolling": false 13 | }, 14 | "logger": { 15 | "level": "info", 16 | "exposeInContext": true, 17 | "requests": false 18 | }, 19 | "parser": { 20 | "enabled": true, 21 | "multipart": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cms/config/environments/production/response.json: -------------------------------------------------------------------------------- 1 | { 2 | "gzip": { 3 | "enabled": true 4 | }, 5 | "responseTime": { 6 | "enabled": false 7 | }, 8 | "poweredBy": { 9 | "enabled": true, 10 | "value": "Strapi " 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /cms/config/environments/production/security.json: -------------------------------------------------------------------------------- 1 | { 2 | "csrf": { 3 | "enabled": false, 4 | "key": "_csrf", 5 | "secret": "_csrfSecret" 6 | }, 7 | "csp": { 8 | "enabled": true, 9 | "policy": [{ 10 | "img-src": "'self' http:" 11 | }, 12 | "block-all-mixed-content" 13 | ] 14 | }, 15 | "p3p": { 16 | "enabled": true, 17 | "value": "" 18 | }, 19 | "hsts": { 20 | "enabled": true, 21 | "maxAge": 31536000, 22 | "includeSubDomains": true 23 | }, 24 | "xframe": { 25 | "enabled": true, 26 | "value": "SAMEORIGIN" 27 | }, 28 | "xss": { 29 | "enabled": true, 30 | "mode": "block" 31 | }, 32 | "cors": { 33 | "enabled": true, 34 | "origin": "*", 35 | "expose": [ 36 | "WWW-Authenticate", 37 | "Server-Authorization" 38 | ], 39 | "maxAge": 31536000, 40 | "credentials": true, 41 | "methods": [ 42 | "GET", 43 | "POST", 44 | "PUT", 45 | "PATCH", 46 | "DELETE", 47 | "OPTIONS", 48 | "HEAD" 49 | ], 50 | "headers": [ 51 | "Content-Type", 52 | "Authorization", 53 | "X-Frame-Options", 54 | "Origin" 55 | ] 56 | }, 57 | "ip": { 58 | "enabled": false, 59 | "whiteList": [], 60 | "blackList": [] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /cms/config/environments/production/server.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "localhost", 3 | "port": "${process.env.PORT || 1337}", 4 | "production": true, 5 | "proxy": { 6 | "enabled": false 7 | }, 8 | "cron": { 9 | "enabled": false 10 | }, 11 | "admin": { 12 | "autoOpen": false 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /cms/config/environments/staging/custom.json: -------------------------------------------------------------------------------- 1 | { 2 | "myCustomConfiguration": "This configuration is accessible through strapi.config.environments.staging.myCustomConfiguration" 3 | } 4 | -------------------------------------------------------------------------------- /cms/config/environments/staging/database.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultConnection": "default", 3 | "connections": { 4 | "default": { 5 | "connector": "strapi-hook-bookshelf", 6 | "settings": { 7 | "client": "sqlite", 8 | "host": "${process.env.DATABASE_HOST || '127.0.0.1'}", 9 | "port": "${process.env.DATABASE_PORT || 27017}", 10 | "database": "${process.env.DATABASE_NAME || 'strapi'}", 11 | "username": "${process.env.DATABASE_USERNAME || ''}", 12 | "password": "${process.env.DATABASE_PASSWORD || ''}" 13 | }, 14 | "options": {} 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /cms/config/environments/staging/request.json: -------------------------------------------------------------------------------- 1 | { 2 | "session": { 3 | "enabled": true, 4 | "client": "cookie", 5 | "key": "strapi.sid", 6 | "prefix": "strapi:sess:", 7 | "secretKeys": ["mySecretKey1", "mySecretKey2"], 8 | "httpOnly": true, 9 | "maxAge": 86400000, 10 | "overwrite": true, 11 | "signed": false, 12 | "rolling": false 13 | }, 14 | "logger": { 15 | "level": "info", 16 | "exposeInContext": true, 17 | "requests": false 18 | }, 19 | "parser": { 20 | "enabled": true, 21 | "multipart": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cms/config/environments/staging/response.json: -------------------------------------------------------------------------------- 1 | { 2 | "gzip": { 3 | "enabled": true 4 | }, 5 | "responseTime": { 6 | "enabled": false 7 | }, 8 | "poweredBy": { 9 | "enabled": true, 10 | "value": "Strapi " 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /cms/config/environments/staging/security.json: -------------------------------------------------------------------------------- 1 | { 2 | "csrf": { 3 | "enabled": false, 4 | "key": "_csrf", 5 | "secret": "_csrfSecret" 6 | }, 7 | "csp": { 8 | "enabled": true, 9 | "policy": [{ 10 | "img-src": "'self' http:" 11 | }, 12 | "block-all-mixed-content" 13 | ] 14 | }, 15 | "p3p": { 16 | "enabled": true, 17 | "value": "" 18 | }, 19 | "hsts": { 20 | "enabled": true, 21 | "maxAge": 31536000, 22 | "includeSubDomains": true 23 | }, 24 | "xframe": { 25 | "enabled": true, 26 | "value": "SAMEORIGIN" 27 | }, 28 | "xss": { 29 | "enabled": true, 30 | "mode": "block" 31 | }, 32 | "cors": { 33 | "enabled": true, 34 | "origin": "*", 35 | "expose": [ 36 | "WWW-Authenticate", 37 | "Server-Authorization" 38 | ], 39 | "maxAge": 31536000, 40 | "credentials": true, 41 | "methods": [ 42 | "GET", 43 | "POST", 44 | "PUT", 45 | "PATCH", 46 | "DELETE", 47 | "OPTIONS", 48 | "HEAD" 49 | ], 50 | "headers": [ 51 | "Content-Type", 52 | "Authorization", 53 | "X-Frame-Options", 54 | "Origin" 55 | ] 56 | }, 57 | "ip": { 58 | "enabled": false, 59 | "whiteList": [], 60 | "blackList": [] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /cms/config/environments/staging/server.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "localhost", 3 | "port": "${process.env.PORT || 1337}", 4 | "production": true, 5 | "proxy": { 6 | "enabled": false 7 | }, 8 | "cron": { 9 | "enabled": false 10 | }, 11 | "admin": { 12 | "autoOpen": false 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /cms/config/functions/bootstrap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * An asynchronous bootstrap function that runs before 5 | * your application gets started. 6 | * 7 | * This gives you an opportunity to set up your data model, 8 | * run jobs, or perform some special logic. 9 | */ 10 | 11 | module.exports = cb => { 12 | cb(); 13 | }; 14 | -------------------------------------------------------------------------------- /cms/config/functions/cron.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Cron config that gives you an opportunity 5 | * to run scheduled jobs. 6 | * 7 | * The cron format consists of: 8 | * [MINUTE] [HOUR] [DAY OF MONTH] [MONTH OF YEAR] [DAY OF WEEK] [YEAR (optional)] 9 | */ 10 | 11 | module.exports = { 12 | 13 | /** 14 | * Simple example. 15 | * Every monday at 1am. 16 | */ 17 | 18 | // '0 1 * * 1': () => { 19 | // 20 | // } 21 | }; 22 | -------------------------------------------------------------------------------- /cms/config/functions/responses/404.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = async (/* ctx */) => { 4 | // return ctx.notFound('My custom message 404'); 5 | }; 6 | -------------------------------------------------------------------------------- /cms/config/hook.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeout": 3000, 3 | "load": { 4 | "before": [], 5 | "order": [ 6 | "Define the hooks' load order by putting their names in this array in the right order" 7 | ], 8 | "after": [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /cms/config/language.json: -------------------------------------------------------------------------------- 1 | { 2 | "enabled": true, 3 | "defaultLocale": "en_us", 4 | "modes": [ 5 | "query", 6 | "subdomain", 7 | "cookie", 8 | "header", 9 | "url", 10 | "tld" 11 | ], 12 | "cookieName": "locale" 13 | } 14 | -------------------------------------------------------------------------------- /cms/config/locales/de_de.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "Willkommen" 3 | } 4 | -------------------------------------------------------------------------------- /cms/config/locales/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "Welcome" 3 | } 4 | -------------------------------------------------------------------------------- /cms/config/locales/es_es.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "Bienvenido" 3 | } 4 | -------------------------------------------------------------------------------- /cms/config/locales/fr_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "Bienvenue" 3 | } 4 | -------------------------------------------------------------------------------- /cms/config/locales/it_it.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "Benvenuto" 3 | } 4 | -------------------------------------------------------------------------------- /cms/config/locales/ja_jp.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "ようこそ" 3 | } 4 | -------------------------------------------------------------------------------- /cms/config/locales/ru_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "Добро пожаловать" 3 | } 4 | -------------------------------------------------------------------------------- /cms/config/locales/tr_tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "Hoşgeldin" 3 | } 4 | -------------------------------------------------------------------------------- /cms/config/middleware.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeout": 100, 3 | "load": { 4 | "before": [ 5 | "responseTime", 6 | "logger", 7 | "cors", 8 | "responses", 9 | "gzip" 10 | ], 11 | "order": [ 12 | "Define the middlewares' load order by putting their name in this array is the right order" 13 | ], 14 | "after": [ 15 | "parser", 16 | "router" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cms/extensions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/cms/extensions/.gitkeep -------------------------------------------------------------------------------- /cms/extensions/users-permissions/config/jwt.json: -------------------------------------------------------------------------------- 1 | { 2 | "jwtSecret": "7e995e9d-bea5-4c36-91d1-c5ba945eedf3" 3 | } -------------------------------------------------------------------------------- /cms/extensions/users-permissions/models/User.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "collectionName": "users-permissions_user", 3 | "connection": "default", 4 | "info": { 5 | "name": "user", 6 | "description": "" 7 | }, 8 | "options": { 9 | "timestamps": [ 10 | "created_at", 11 | "updated_at" 12 | ] 13 | }, 14 | "attributes": { 15 | "username": { 16 | "type": "string", 17 | "minLength": 3, 18 | "unique": true, 19 | "configurable": false, 20 | "required": true 21 | }, 22 | "email": { 23 | "type": "email", 24 | "minLength": 6, 25 | "configurable": false, 26 | "required": true 27 | }, 28 | "provider": { 29 | "type": "string", 30 | "configurable": false 31 | }, 32 | "password": { 33 | "type": "password", 34 | "minLength": 6, 35 | "configurable": false, 36 | "private": true 37 | }, 38 | "resetPasswordToken": { 39 | "type": "string", 40 | "configurable": false, 41 | "private": true 42 | }, 43 | "confirmed": { 44 | "type": "boolean", 45 | "default": false, 46 | "configurable": false 47 | }, 48 | "blocked": { 49 | "type": "boolean", 50 | "default": false, 51 | "configurable": false 52 | }, 53 | "role": { 54 | "model": "role", 55 | "via": "users", 56 | "plugin": "users-permissions", 57 | "configurable": false 58 | }, 59 | "articles": { 60 | "collection": "article", 61 | "via": "author" 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /cms/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/cms/favicon.ico -------------------------------------------------------------------------------- /cms/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cms", 3 | "private": true, 4 | "version": "0.1.0", 5 | "description": "A Strapi application.", 6 | "scripts": { 7 | "develop": "strapi develop", 8 | "start": "strapi start", 9 | "build": "strapi build", 10 | "strapi": "strapi", 11 | "lint": "eslint api/**/*.js config/**/*.js plugins/**/*.js" 12 | }, 13 | "devDependencies": { 14 | "babel-eslint": "^7.1.1", 15 | "eslint": "^4.19.1", 16 | "eslint-config-airbnb": "^13.0.0", 17 | "eslint-plugin-import": "^2.11.0", 18 | "eslint-plugin-react": "^7.7.0" 19 | }, 20 | "dependencies": { 21 | "axios": "^0.19.0", 22 | "knex": "latest", 23 | "lodash": "^4.17.5", 24 | "pg": "^7.11.0", 25 | "sqlite3": "latest", 26 | "strapi": "3.0.0-beta.7", 27 | "strapi-admin": "3.0.0-beta.7", 28 | "strapi-hook-bookshelf": "3.0.0-beta.7", 29 | "strapi-hook-knex": "3.0.0-beta.7", 30 | "strapi-plugin-content-manager": "3.0.0-beta.7", 31 | "strapi-plugin-content-type-builder": "3.0.0-beta.7", 32 | "strapi-plugin-email": "3.0.0-beta.7", 33 | "strapi-plugin-settings-manager": "3.0.0-beta.7", 34 | "strapi-plugin-upload": "3.0.0-beta.7", 35 | "strapi-plugin-users-permissions": "3.0.0-beta.7", 36 | "strapi-provider-upload-cloudinary": "^3.0.0-alpha.15", 37 | "strapi-utils": "3.0.0-beta.7" 38 | }, 39 | "author": { 40 | "name": "david", 41 | "email": "", 42 | "url": "" 43 | }, 44 | "maintainers": [ 45 | { 46 | "name": "david", 47 | "email": "", 48 | "url": "" 49 | } 50 | ], 51 | "strapi": { 52 | "uuid": "5828e072-011a-429b-b328-8c0920770796" 53 | }, 54 | "engines": { 55 | "node": "10.x", 56 | "npm": ">= 6.0.0" 57 | }, 58 | "license": "MIT" 59 | } 60 | -------------------------------------------------------------------------------- /cms/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Welcome to your Strapi app 8 | 9 | 141 | 142 | 143 |
144 |
145 |

Welcome.

146 |

You successfully created your Strapi application.

147 |

You are looking at: ./public/index.html.

148 |

Your built-in admin panel is available at /admin. 149 |

Create your first API

150 |

Easily generate a complete API with controllers, models and routes using:

151 |
$ strapi generate:api <apiName>
152 |

Resources

153 |

You'll probably also want to learn how to customize your application, set up security and configure your data sources.

154 |

For more help getting started, check out: 155 |

161 |

162 |
163 |
164 | 165 | 166 | -------------------------------------------------------------------------------- /cms/public/robots.txt: -------------------------------------------------------------------------------- 1 | # To prevent search engines from seeing the site altogether, uncomment the next two lines: 2 | # User-Agent: * 3 | # Disallow: / 4 | -------------------------------------------------------------------------------- /cms/public/uploads/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/cms/public/uploads/.gitkeep -------------------------------------------------------------------------------- /content-master/Markdown-mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/Markdown-mark.png -------------------------------------------------------------------------------- /content-master/bed-and-breakfast-content.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/bed-and-breakfast-content.jpg -------------------------------------------------------------------------------- /content-master/bed-and-breakfasts-give-travel-a-personal-touch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/bed-and-breakfasts-give-travel-a-personal-touch.jpg -------------------------------------------------------------------------------- /content-master/content-for-tutorial.txt: -------------------------------------------------------------------------------- 1 | Articles are from http://www.copyrightfreecontent.com 2 | 3 | Article 1: 4 | 5 | Title: 6 | 7 | Bed and Breakfasts Give Travel a Personal Touch 8 | 9 | Content: 10 | 11 | === 12 | 13 | Photo by: [Elora Allen](https://unsplash.com/photos/Wikeo8KZUhA?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 14 | 15 | ## Personal 16 | 17 | Travelers seeking a personal touch and insider stories would do well to consider staying at a local bed and breakfast (B&B). B&Bs _"are more intimate, with much more personal attention,"_ says Sharon Scruggs, who operates the Fife and Drum Inn with her husband, Billy. Both are lifetime residents of Williamsburg, Virginia, and provide a unique and in-depth perspective on the history of the area for their guests. The bed-and-breakfast experience offers many other benefits beyond what travelers find in a chain- hotel setting. 18 | 19 | ## Location 20 | 21 | Many bed and breakfasts are historic properties, often located in the center of scenic areas.The Fife and Drum Inn has been part of Sharon’s family for generations. The building was constructed in 1933 by her grandfather as a combination of stores with apartments above, and is a short walk to the sights and sounds of Colonial Williamsburg, including the holiday Grand Illumination fireworks display.- Character. 22 | 23 | Part of the charm of a bed and breakfast is the uniqueness: 24 | 25 | - art, 26 | - décor, 27 | - and food are integrated to create a complete experience. 28 | 29 | For example, the Fife and Drum retains the colonial feel of the area in all its guest rooms. 30 | 31 | Special features include: 32 | 33 | 1. antique furnishings, 34 | 2. elegant four poster beds in some guest rooms, as well as 35 | 3. folk art and artifacts (from the restoration period of the historic area available for guests to enjoy). 36 | 37 | ## Food 38 | 39 | Bed and breakfasts don’t shirk the breakfast half of the equation, and the best of them reflect the local cuisine. The Fife and Drum features daily breakfast casseroles based on family recipes to reflect the southern cooking of the area; other items include fresh biscuits, Virginia ham, fruit, and a unique blend of granola to fuel a day of sightseeing. 40 | 41 | ## Customization 42 | 43 | Not only do visitors to a bed and breakfast get a unique perspective on the place they are visiting, they have options for special packages not available in other hotel settings. 44 | 45 | Bed and breakfasts can partner easily with local businesses for a smoothly organized and highly personalized vacation experience.The Fife and Drum Inn offers options such as the Historic Triangle Package that includes three nights at the Inn, breakfasts, and admissions to historic Williamsburg, Jamestown, and Yorktown. Bed and breakfasts also lend themselves to romance. Helpful hosts can design guest packages built around proposals, anniversaries, or just a special getaway. 46 | 47 | Visit [fifeanddruminn.com](fifeanddruminn.com) for more details about how a bed and breakfast makes for a memorable travel experience. 48 | 49 | === 50 | HEADER: 51 | Image: bed-and-breakfasts-give-travel-a-personal-touch.jpg 52 | 53 | Photo by [Elora Allen](https://unsplash.com/photos/Wikeo8KZUhA?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 54 | 55 | CONTENT: 56 | 57 | bed-and-breakfasts-content.jpg 58 | 59 | Photo by: [Freestocks.org](https://unsplash.com/search/photos/breakfast-in-bed?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 60 | 61 | https://unsplash.com 62 | Unsplash 63 | 64 | ======================= 65 | 66 | Article 2: 67 | 68 | Title: 69 | 70 | Real Talk — When Was The Last Time You Enjoyed Your Business Trip? 71 | 72 | Content: 73 | 74 | === 75 | 76 | Photo by: [Lance Asper](https://unsplash.com/photos/eJx43ng-fTU?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 77 | 78 | ## Hard to Believe 79 | 80 | It’s hard to believe that 2017 is more than halfway over and that fall is in the air. With that, life starts to speed up as kids head back to school, holidays loom just around the corner, and you may find yourself traveling for work a bit more in the coming months as companies try to wrap up end-of-the-year projects. 81 | 82 | ### Welcome to real travel 83 | 84 | What does that mean exactly? While we would all like to plan trips to exotic locations for weeks at a time, the truth is that people travel for life reasons, such as visiting relatives, meeting with clients, and for children’s sports. Just because these types of trips are practical does not mean they can’t also be enjoyable. And one travel blogger has some ideas on how to inject some fun into your real life trips. 85 | 86 | Danielle Smith, wife, mother, and creator of the Pretty Extraordinary website, _"A place where you can ditch perfection, embrace the juggle and come away celebrating the small victories,"_ believes there are some simple ways to get the best out of real travel. 87 | 88 | ## Make Practical Trips Fun and Fun Trips Practical 89 | 90 | Whether you are obligated to visit a family member or simply travel for business, seek out a few opportunities to enjoy the time away. Find a new restaurant that serves your favorite type of food, take in a show or visit a local treasure. Alternatively, if you have the opportunity to steal away for vacation, take the time to do a college tour with your kids: even if they aren’t looking yet, you never know what doors you may open. 91 | 92 | ## Seek the Perks 93 | 94 | For any type of travel, always look for hotels that offer the amenities that will make your stay both more comfortable and affordable. When traveling for business, chances are you’re visiting clients in various cities, so it’s important to find a hotel brand that consistently offers what you need. Hampton by Hilton, for instance, has more than 2,240 properties around the world and offers free amenities to make your stay more pleasurable. To help fuel up for those long days on the road or endless meetings, the hotel provides On the Run breakfast bags as a perk. Need to stay up late working into the evening? There’s free Wi-Fi for that. 95 | 96 | ## Plan for Disruption 97 | 98 | We all know that real travel involves real life moments: 99 | 100 | - lost luggage, 101 | - delayed flights, and 102 | - rainstorms when you were planning on a sunny day. 103 | 104 | So take the time to monitor the weather before you head to your destination, and keep a few extra items in your carry-on or purse (such as a rain hat, sweater or umbrella).While travel can be stressful, if you are prepared and plan ahead, it doesn’t have to be. You may even be able to enjoy a few moments. 105 | 106 | So don’t forget to book your next getaway at [Hampton.com](hampton.com), where Hilton Honors members get a guaranteed discount. 107 | 108 | === 109 | HEADER: 110 | Image: 111 | 112 | real-talk-when-was-the-last-time-you-enjoyed-your-business-trip.jpeg 113 | 114 | Photo by [Lance Asper](https://unsplash.com/photos/eJx43ng-fTU?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 115 | 116 | CONTENT: 117 | 118 | real-talk-content.jpg 119 | 120 | Photo by: [Mantas Hesthaven](https://unsplash.com/search/photos/business-trip?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 121 | 122 | on 123 | 124 | https://unsplash.com 125 | Unsplash 126 | 127 | ======================= 128 | 129 | Article 3: 130 | 131 | Title: 132 | 133 | Fall in Love with Greater Fort Lauderdale 134 | 135 | Content: 136 | 137 | === 138 | 139 | Photo by: [Lance Asper](https://unsplash.com/photos/eJx43ng-fTU?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 140 | 141 | Travelers may think of summer and beach activities when they think of Florida, but Greater Fort Lauderdale takes its relaxing vibe into the fall season.With options for off-season savings, visitors can enjoy a VIP experience for less and make the most of a fall visit to the destination, including deals on fine dining, outdoor activities, and indulgent spa experiences, just before heading into winter. 142 | 143 | - Food: Greater Fort Lauderdale Restaurant Month is back by popular demand with a new name and improved dining deals. 144 | 145 | _"Crave GFL,"_ Greater Fort Lauderdale Restaurant Month, is back by popular demand with a new name and improved dining deals. _"Crave GFL,"_ which runs through the month of September with many restaurants extending until October 15, celebrates the distinctive fusion of flavors that Greater Fort Lauderdale has to offer. 146 | 147 | The promotion includes a series of tasting events, and more than 45 area restaurants offer specially created three course meals priced at \$37. celebrates the area’s distinctive fusion of flavors that Greater Fort Lauderdale has to offer. 148 | 149 | The promotion includes a series of tasting events, and more than 45 area restaurants offer specially- created three-course meals priced at \$37." 150 | 151 | The natural beauty of our seaside community inspires chefs to create meals that are fresh and palate-pleasing," says Stacy Ritter, president of the Greater Fort Lauderdale Convention & Visitors Bureau."Our restaurants and cafes are taking their rightful place not only on the global-cuisine stage, but also among our abundance of visitor attractions," she adds. 152 | 153 | For more information, visit [sunny.org/cravegfl](sunny.org/cravegfl) for more details. 154 | 155 | - Fun: The Vacation Like A VIP program, offering packages at a number of upscale hotels through October 15, allows visitors to Greater Fort Lauderdale to enjoy a buy-one-get-one free deal on activities, including Everglades airboat rides, visits to Sawgrass Recreation Park and Everglades Holiday Park, scuba diving, snorkeling, and surfing the FlowRider at Margaritaville Hollywood Beach Resort, along with other water-sport activities and water-taxi tours. 156 | 157 | Visit [sunny.org/vip](sunny.org/vip) for additional information. 158 | 159 | - Feeling good: Greater Fort Lauderdale’s popular spa promotion is back through October 15. 160 | 161 | During "Spatember," the promotion includes specialty services for \$99 at select spas in the area, with many extending to October 15. Treatments range from organic facials and eye treatments to therapeutic manicures and pedicures, as well as unique hot stone massage sessions. The Spatember deals may be a welcome opportunity "to find some much deserved ‘me time’ to restore the mind, body, and soul without breaking the bank," Ms. Ritter says. 162 | 163 | Visit [sunny.org/spatember](sunny.org/spatember) for more information. 164 | 165 | === 166 | 167 | Image: 168 | 169 | HEADER: 170 | fall-in-love-with-greater-fort-lauderdale.jpg 171 | 172 | Photo by [Lance Asper](https://unsplash.com/photos/eJx43ng-fTU?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 173 | 174 | CONTENT: 175 | 176 | fall-in-love-content.jpg 177 | 178 | Photo by [Lance Asper](https://unsplash.com/search/photos/fort-lauderdale?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 179 | 180 | on 181 | 182 | https://unsplash.com 183 | Unsplash 184 | 185 | ======================= 186 | 187 | Article 4: 188 | 189 | Title: 190 | 191 | The Big Appeal of Small City Vacations 192 | 193 | Content: 194 | 195 | # The Big Appeal of Small City Vacations 196 | 197 | If you live or work in a big city, you may be reluctant to travel across the ocean to another bustling metropolis. There’s only one Paris but getting from the Louvre to Notre-Dame to the Arc de Triomphe via the Paris Metro doesn’t feel a whole lot like a vacation if your typical day includes the New York City subway, for example.The good news is that there are many places outside of major cities for great culture and cuisine, but with a more laid-back feel.Blue-Roads, a world leader in small group touring, specializes in taking you to these more intimate destinations where you get the best of both worlds. 198 | 199 | Here are a few ideas for authentic experiences coupled with a relaxed pace that allow you to truly decompress and better enjoy your travels: 200 | 201 | ## Bilbao, Spain. 202 | 203 | Millions of tourists flock annually to Catalonia’s capital, Barcelona, for its world-class art museums, its imposing gothic architecture and Northern Spanish delights such as paella. In Bilbao, you’ll find equally appealing character and ambiance. In this rugged coastal city, steep yourself in Basque culture, history and cuisine. It’s renowned for its fresh seafood and Basque foodways, its world-class Guggenheim Museum, and it’s amazing indoor food market and contemporary architecture. On Blue-Roads’ Highlights of Northern Spain tour, you’ll explore the iconic Frank Gehry-designed Guggenheim and dine at a Michelin-starred restaurant. 204 | 205 | ## Granada, Spain. 206 | 207 | Madrid may be famous for its great European masterworks and breathtaking architecture, notably the Royal Palace and Plaza Mayor, but Granada is a jewel in its own right. You’ll marvel at Granada’s equally breathtaking Moorish architecture, a distinctive mix of Islamic and Arabic influences. No visit to Granada is complete without seeing the splendor of the Alhambra’s palace and gardens from its plateau in the Sierra Nevada Mountains, with a sweeping vista overlooking the city. Included in the Iberian Inspiration tour is an exploration of this famed place, considered one of the finest masterpieces in Islamic architecture. 208 | 209 | ## York, England. 210 | 211 | While few cities can match the lure of London, it is a very crowded destination. About three and a half hours north is York, one of the best-preserved ancient walled cities in the world. It dates back to Roman times. It’s also one of the most picturesque places in England. The Heart of Britain tour brings you into the heart of Old Town York. Steps built in the middle ages bring you to the top of the city wall where you can take in dazzling views before sitting down to enjoy a pint or a meal. 212 | 213 | ## Galway, Ireland. 214 | 215 | Ireland is famous for its rugged coastline, majestic castles and emerald green hills. Be sure not to limit yourself to Dublin or Belfast, though. Don’t miss Galway, considered Ireland’s cultural heart and designated the European Cultural Capital 2020. Known for its traditional Irish music, Galway is rich in medieval history, street art and is the birthplace of the traditional Claddagh ring. On Blue-Roads’ Emerald Isle tour, you’ll soak in the vibrant energy of this eclectic city, including a walking tour of the harbor city of Galway, where fisherman have lived and worked for centuries.Who says you can’t have it all? When you visit one of these less-traveled cities featured in Blue-Roads Tours, you’ll replace the day-to-day with a getaway to remember. 216 | 217 | Image: 218 | 219 | the-big-appeal-of-small-city-vacations.jpg 220 | 221 | Photo by Chang Duong 222 | https://unsplash.com/photos/3D57xfaWekY?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText 223 | 224 | on 225 | 226 | https://unsplash.com 227 | Unsplash 228 | 229 | ======================= 230 | 231 | Article 5: 232 | 233 | Title: 234 | 235 | Stylish Carrying Case Corrals Handbag Essentials in Style 236 | 237 | Content: 238 | 239 | Despite their best efforts, most women have had the experience of frantically digging into the bottom of a large purse or handbag for an essential item such as eyeglasses, cellphone, keys, or passport. A separate case to corral these important possessions makes sense, especially if it combines fashion with function.Being able to protect, carry, and access these items in a reliable, convenient, safe way makes women’s lives easier and better, according to the creator of TravelEyez, a unique, stylish accessory that holds not only eyeglasses, but other essentials including phones and keys. 240 | 241 | The **TravelEyez** products are double-sided and designed to zip around the strap or handle of any purse, handbag, or backpack.This stylish accessory is available in black mesh with six different-colored zipper options, as well as black leather and caramel leather for a dressier look, and are sold in sets of two cases that may be zipped together or used separately. 242 | 243 | ## Identical designs 244 | 245 | The designs are identical regardless of color, so they can mix and match, or stay consistent."Each TravelEyez case can hold a pair of glasses or car keys, money, credit cards, jewelry or a smart phone. You can zip cases together to connect as many as you need, and attach them to your purse or bag handle to keep your personal items organized and close at hand for easy access," says Yvonne Graber, creator of TravelEyez. 246 | 247 | TravelEyez also gives women peace of mind. The case cancels the need to keep valuables such as a phone or keys in a pants or jacket pocket where they might fall out. 248 | 249 | Some of the most popular uses include: 250 | 251 | - Travel. Whether you’re traveling for business or pleasure, the case provides a secure way to monitor a phone, wallet, credit cards and passport. Try it on a suitcase, travel tote, or carry-on bag. 252 | - Shopping. As mundane as it may sound, don’t underestimate the value of a handy way to easily access your phone and wallet when shopping, especially for moms toting small children along. 253 | - On the go. This is an ideal accessory for students, fitness fanatics, or those on the go. The cases attach easily to bike bars, gym bags, and backpack straps. With the holidays just around the corner, TravelEyez also makes a great gift or stocking stuffer. 254 | 255 | The patent on the TravelEyez design is pending. 256 | 257 | For more information, visit [traveleyez.com](traveleyez.com). 258 | 259 | Image: 260 | 261 | stylish-carrying-case-corrals-handbag-essentials-in-style.jpg 262 | 263 | Photo by SOCIAL . CUT 264 | https://unsplash.com/photos/bHCeSytrid4?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText 265 | 266 | on 267 | 268 | https://unsplash.com 269 | Unsplash 270 | 271 | ======================= 272 | 273 | Article 6: 274 | 275 | Title: 276 | 277 | Creative Gift Giving Is Easier Than You Think 278 | 279 | Content: 280 | 281 | It’s no secret that shopping for holiday gifts can be overwhelming.The answer to alleviating the stress of thoughtful gift giving comes in a cardboard box.Seriously.Subscription box services are popular options for a "gift that keeps on giving," providing a personalized experience delivered safely every month. 282 | 283 | In fact, in a survey conducted by the Paper and Packaging Board from August 2015 to November 2016, 82 percent of those surveyed agreed that they could rely on corrugated cardboard boxes to get their merchandise shipped and delivered safely. And 60 percent feel that products that come in paper-packaging tend to feel more premium.Innovations in box and packaging design allow these boxes to delight well past delivery with extended use and upcycling options. 284 | 285 | Find the perfect gift for your loved one this season with one of these favorites: 286 | 287 | ## KiwiCo (Kiwico.com): 288 | 289 | For the Kid Who Is Going to Run the World. KiwiCo develops monthly STEAM educational hands-on projects and activities to spark curiosity and creativity in kids aged 0-16+. Each eco-friendly corrugated box is filled with interactive projects to fit a child’s respective age group. As your child or loved one grows, so do the boxes! 290 | 291 | ## Loot Crate (LootCrate.com): 292 | 293 | For the Pop-Culture Obsessed. Loot Crate is a pop culture- themed subscription box featuring a changing monthly theme that covers all fandoms.These corrugated boxes hit every interest from video games to television and movies. Loot Crate offers an additional perk – the box is part of the monthly theme itself, which is to say, the box transforms into a "bonus" gift with some simple cuts and folds. You have to see it to believe it. 294 | 295 | ## Graze (Graze.com): 296 | 297 | For the Foodie. Graze is a subscription box that uses high-quality, nutritionist- approved ingredients to provide wholesome snacks. Graze uses responsibly resourced paper-based packaging to ensure that its products are safe and fresh for consumption. Foodies can subscribe for weekly, bi-weekly or monthly deliveries of personalized Graze boxes based on their custom-snack profile. 298 | 299 | ## KitNipBox (KitNipBox.com): 300 | 301 | For the Cat Lover. KitNipBox is uniquely themed so cats (and their humans!) have something fresh, fun and new to look forward to each month. The design of the box, which can be recycled, is specifically made to fit 95 percent of cats, so they can play with the box and fit inside of it.Additionally, KitNipBox uses specially designed crinkling tissue paper in the boxes, so that the unwrapping experience is even more special for cats and their owners. 302 | 303 | ## Cratejoy (Cratejoy.com): 304 | 305 | For Everyone. Cratejoy is the world’s premier subscription box website, providing a global marketplace of products. Cratejoy offers a vast selection of uniquely crafted corrugated boxes suited to virtually any hobby, interest or taste.Gifting a subscription box service is an easy yet thoughtful option for anyone on your shopping list! Unbox an experience that will last long past this holiday season. 306 | 307 | Find out more by visiting [HowLifeUnfolds.com](HowLifeUnfolds.com) 308 | 309 | Image: 310 | 311 | creative-gift-giving-easier-than-you-think.jpg 312 | 313 | Photo by FreeStocks.org 314 | https://unsplash.com/photos/spP6LqxN0-g?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText 315 | 316 | on 317 | 318 | https://unsplash.com 319 | Unsplash -------------------------------------------------------------------------------- /content-master/creative-gift-giving-easier-than-you-think.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/creative-gift-giving-easier-than-you-think.jpg -------------------------------------------------------------------------------- /content-master/fall-in-love-content.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/fall-in-love-content.jpg -------------------------------------------------------------------------------- /content-master/fall-in-love-with-greater-fort-lauderdale.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/fall-in-love-with-greater-fort-lauderdale.jpg -------------------------------------------------------------------------------- /content-master/gatsby-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/gatsby-logo.png -------------------------------------------------------------------------------- /content-master/markdown-cheatsheet.md: -------------------------------------------------------------------------------- 1 | # Markdown Cheatsheet for Strapi with Gatsby 2 | 3 | (Taken from [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)) 4 | 5 | This cheatsheet shows you the markdown that is supported when using Strapi with Gatsby. 6 | 7 | ![Strapi Logo](https://res.cloudinary.com/dunjfeiit/image/upload/v1556888660/f9l8shax7l4ichpv8qze.png) 8 | 9 | ### Headers 10 | 11 | ``` 12 | # H1 13 | ## H2 14 | ### H3 15 | #### H4 16 | ##### H5 17 | ###### H6 18 | 19 | ``` 20 | 21 | # H1 22 | 23 | ## H2 24 | 25 | ### H3 26 | 27 | #### H4 28 | 29 | ##### H5 30 | 31 | ###### H6 32 | 33 | ### Emphasis 34 | 35 | ``` 36 | Emphasis, aka italics, with *asterisks*. 37 | 38 | Strong emphasis, aka bold, with **asterisks**. 39 | 40 | Combined emphasis with **asterisks and *single asteriks***. 41 | 42 | Strikethrough uses two tildes. ~~Scratch this.~~ 43 | 44 | ``` 45 | 46 | Emphasis, aka italics, with _asterisks_. 47 | 48 | Strong emphasis, aka bold, with **asterisks**. 49 | 50 | Combined emphasis with **asterisks and _single asteriks_**. 51 | 52 | Strikethrough uses two tildes. ~~Scratch this.~~ 53 | 54 | ### Lists 55 | 56 | ``` 57 | 1. First ordered list item 58 | 2. Another item 59 | - Unordered sub-list. 60 | 1. Actual numbers don't matter, just that it's a number 61 | 1. Ordered sub-list 62 | 4. And another item. 63 | 64 | * Unordered list can use asterisks 65 | - Or minuses 66 | + Or pluses 67 | ``` 68 | 69 | 1. First ordered list item 70 | 2. Another item 71 | - Unordered sub-list. 72 | 3. Actual numbers don't matter, just that it's a number 73 | 1. Ordered sub-list 74 | 4. And another item. 75 | 76 | - Unordered list can use asterisks 77 | 78 | * Or minuses 79 | 80 | - Or pluses 81 | 82 | ### Links 83 | 84 | This is how to create links: 85 | 86 | ``` 87 | [I'm an inline-style link](https://www.google.com) 88 | 89 | [I'm an inline-style link with title](https://www.google.com "Google's Homepage") 90 | 91 | 92 | [I'm a reference-style link][Arbitrary case-insensitive reference text] 93 | 94 | [I'm a relative reference to a repository file](../Article_1) 95 | 96 | [You can use numbers for reference-style link definitions][1] 97 | 98 | Or leave it empty and use the [link text itself]. 99 | 100 | URLs and URLs in angle brackets will automatically get turned into links. 101 | http://www.example.com or but not 102 | example.com. 103 | 104 | Some text to show that the reference links can follow later (see above). 105 | 106 | [arbitrary case-insensitive reference text]: https://www.mozilla.org 107 | [1]: http://slashdot.org 108 | [link text itself]: http://www.reddit.com 109 | 110 | ``` 111 | 112 | [I'm an inline-style link](https://www.google.com) 113 | 114 | [I'm an inline-style link with title](https://www.google.com "Google's Homepage") 115 | 116 | [I'm a reference-style link][arbitrary case-insensitive reference text] 117 | 118 | [I'm a relative reference to a repository file](../Article_1) 119 | 120 | [You can use numbers for reference-style link definitions][1] 121 | 122 | Or leave it empty and use the [link text itself]. 123 | 124 | URLs and URLs in angle brackets will automatically get turned into links. 125 | http://www.example.com or but not 126 | example.com. 127 | 128 | Some text to show that the reference links can follow later. 129 | 130 | [arbitrary case-insensitive reference text]: https://www.mozilla.org 131 | [1]: http://slashdot.org 132 | [link text itself]: http://www.reddit.com 133 | 134 | ### Images 135 | 136 | Here's our logo (hover to see the title text): 137 | 138 | Inline-style: 139 | 140 | ![Strapi Logo](https://res.cloudinary.com/dunjfeiit/image/upload/v1556888660/f9l8shax7l4ichpv8qze.png 'Strapi Logo') 141 | 142 | Reference-style: 143 | 144 | Small Gatsby Logo 145 | 146 | Default Gatsby Logo 147 | 148 | ![text](https://res.cloudinary.com/dunjfeiit/image/upload/v1556888704/s0mji46npwzj4rpfvkbc.png 'Gatsby Logo') 149 | 150 | LargeGatsby Logo 151 | 152 | ### Code 153 | 154 | Code blocks are part of the Markdown spec. 155 | 156 | ``` 157 | Inline `code` has `back-ticks around` it. 158 | ``` 159 | 160 | Inline `code` has `back-ticks around` it. 161 | 162 | Blocks of code are either fenced by lines with three back-ticks ```, or are indented with four spaces. I recommend only using the fenced code blocks -- they're easier. 163 | 164 | ```` 165 | 166 | ``` 167 | But let's throw in a tag. 168 | ``` 169 | 170 | ```` 171 | 172 | ``` 173 | But let's throw in a tag. 174 | ``` 175 | -------------------------------------------------------------------------------- /content-master/real-talk-content.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/real-talk-content.jpg -------------------------------------------------------------------------------- /content-master/real-talk-when-was-the-last-time-you-enjoyed-your-business-trip.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/real-talk-when-was-the-last-time-you-enjoyed-your-business-trip.jpeg -------------------------------------------------------------------------------- /content-master/strapi-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/strapi-logo.png -------------------------------------------------------------------------------- /content-master/stylish-carrying-case-corrals-handbag-essentials-in-style.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/stylish-carrying-case-corrals-handbag-essentials-in-style.jpg -------------------------------------------------------------------------------- /content-master/the-big-appeal-of-small-city-vacations.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/strapi-heroku-cms-demo/5644e20a3d9fa12ce99793a593873f91e104cf92/content-master/the-big-appeal-of-small-city-vacations.jpg --------------------------------------------------------------------------------