├── .babelrc ├── .editorconfig ├── .env.example ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .nvmrc ├── .postcssrc.js ├── .tern-project ├── README.md ├── _redirects ├── app.json ├── bucket.json ├── build ├── build.js ├── check-versions.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js └── prod.env.js ├── index.html ├── netlify.toml ├── package-lock.json ├── package.json ├── server.js ├── src ├── App.vue ├── assets │ ├── ApplicationHomePage.png │ ├── add-bucket.png │ ├── credentials.png │ ├── deploy-button.svg │ ├── env.png │ ├── install_app.png │ ├── redeploy.png │ ├── search_apps.png │ └── vue-snip.svg ├── components │ ├── Blog.vue │ ├── BlogFeed.vue │ ├── BlogFooter.vue │ ├── BlogNav.vue │ ├── BlogPost.vue │ ├── BlogTitle.vue │ └── index.js ├── config │ └── index.js ├── helpers.js ├── main.js ├── plugins │ ├── device-queries │ │ ├── index.js │ │ └── match-media.js │ └── resource │ │ ├── cache.js │ │ └── index.js ├── resources │ ├── Blog.js │ ├── BlogFeed.js │ ├── BlogPost.js │ └── index.js ├── router │ └── index.js ├── sass │ ├── _app.scss │ ├── _tools.scss │ ├── base │ │ ├── _body.scss │ │ ├── _reset.scss │ │ └── _text.scss │ ├── blocks │ │ ├── _blog.scss │ │ ├── _footer.scss │ │ ├── _nav.scss │ │ ├── _pace.scss │ │ ├── _post.scss │ │ ├── _preview.scss │ │ ├── _rte.scss │ │ └── _v-transitions.scss │ └── tools │ │ ├── _colors.scss │ │ ├── _easings.scss │ │ ├── _functions.scss │ │ ├── _mediaqueries.scss │ │ └── _mixins.scss └── startup.js └── static ├── .gitkeep ├── api ├── blog.json ├── feed.json └── post │ ├── consequat-ut-nulla.json │ ├── curabitur-gravida-nisi.json │ ├── dolor-quis.json │ ├── lacinia-eget-tincidunt.json │ ├── neque-libero-convallis-eget.json │ ├── nunc-commodo-placerat.json │ ├── posuere-cubilia.json │ ├── potenti-cras-in-purus.json │ ├── pretium-nisl.json │ ├── sapien-ut-nunc.json │ ├── sit-amet-diam-in.json │ ├── sit-amet-erat.json │ ├── ultrices-mattis-odio.json │ ├── ut-massa-quis-augue.json │ └── vivamus-tortor-duis-mattis.json └── icons ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── browserconfig.xml ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── manifest.json ├── mstile-150x150.png └── safari-pinned-tab.svg /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-runtime"], 12 | "env": { 13 | "test": { 14 | "presets": ["env", "stage-2"], 15 | "plugins": ["istanbul"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | COSMIC_BUCKET= 2 | COSMIC_READ_KEY= 3 | COSMIC_WRITE_KEY= -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // http://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 13 | extends: 'standard', 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html' 17 | ], 18 | // add your custom rules here 19 | 'rules': { 20 | // allow paren-less arrow functions 21 | 'arrow-parens': 0, 22 | // allow async-await 23 | 'generator-star-spacing': 0, 24 | // allow debugger during development 25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 26 | // custom 27 | 'space-before-function-paren': 0, 28 | 'object-property-newline': 0, 29 | 'new-cap': 0, 30 | 'no-eval': 0, 31 | 'semi': 0 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | .env 8 | 9 | # Editor directories and files 10 | .idea 11 | .vscode 12 | .tern-project 13 | *.suo 14 | *.ntvs* 15 | *.njsproj 16 | *.sln 17 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v8.11.3 2 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-custom-media": {}, 6 | // to edit target browsers: use "browserlist" field in package.json 7 | "autoprefixer": {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.tern-project: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaVersion": 6, 3 | "libs": [ 4 | "browser" 5 | ], 6 | "loadEagerly": [], 7 | "dontLoad": [ 8 | "node_modules/**" 9 | ], 10 | "plugins": { 11 | "doc_comment": true, 12 | "complete_strings": { 13 | "maxLength": 15 14 | }, 15 | "node_resolve": {}, 16 | "modules": { 17 | "dontLoad": "", 18 | "load": "", 19 | "modules": "" 20 | }, 21 | "es_modules": {} 22 | } 23 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue.js Blog Template Powered by Cosmic 2 | 3 | A simple Vue.js template for creating a fast, beautiful blog on Netlify powerd by the [Cosmic Headless CMS](https://cosmicjs.com) for content editing. 4 | 5 | This template provides blog, blog posts, authors and elegant modern design ready to deploy on [Netlify](http://netlify.com/) in one click! 6 | 7 | ![Vue.js Blog Template Powered by Cosmic](https://cosmic-s3.imgix.net/c3e70670-9bdf-11e8-8928-b51c5e4c8149-vue-blog.png?w=2000 "Vue.js Blog Template Powered by Cosmic ") 8 | 9 | ### [View live demo](https://cosmicjs.com/apps/simple-vue-blog) 10 | 11 | ## Getting Started 12 | 13 | Below are steps to deploy your application to Netlify and integrate with Cosmic for content editing. 14 | 15 | ### 1. Deploy to Netlify 16 | 17 | Click the button below to deploy this application to Netlify. By default, it will be connected to a Bucket with demo content. 18 | 19 | [![Deploy to Netlify](src/assets/deploy-button.svg "Deploy this application to Netlify")](https://app.netlify.com/start/deploy?repository=https://github.com/cosmicjs/vue-blog-netlify-template) 20 | 21 | ### 2. Create Cosmic Bucket 22 | 23 | [Install the Simple Vue Blog](https://cosmicjs.com/apps/simple-vue-blog) by clicking `Install Free` on the app page. 24 | 25 | ![Install App](src/assets/install_app.png) 26 | 27 | ### 3. Generate Credentials 28 | 29 | Click on `Settings` and then `Basic Settings` in your Bucket dashboard. There you can generate `API Read Access Key` & `API Write Access Key` and save them. This step is optional but recommended for security purposes. 30 | 31 | ![Generate Credentials](src/assets/credentials.png) 32 | 33 | ### 4. Add Environment Variable - Netlify 34 | 35 | Now go to Netlify Site Settings and then go to the `Build and Deploy` page. Scroll down and you will see `Build environment variables` section where you will enter Cosmic Bucket credentials. 36 | 37 | ```javascript 38 | { 39 | COSMIC_BUCKET: "", /* Default: 'simple-vue-blog' */ 40 | COSMIC_READ_KEY: "", /* Default: ' */ 41 | COSMIC_WRITE_KEY: "", /* Default: '' */ 42 | BLOG_TITLE: "", /* Default: 'Vue Blog Cosmic' */ 43 | } 44 | ``` 45 | 46 | ![Add Environment Variables](src/assets/env.png) 47 | 48 | ### 5. Redeploy 49 | 50 | At last, go to Netlify `Deploys` page and Trigger Deploy. Congratulation, your application is deployed and connected to Cosmic Bucket. 51 | 52 | ![Add Environment Variables](src/assets/redeploy.png) 53 | -------------------------------------------------------------------------------- /_redirects: -------------------------------------------------------------------------------- 1 | # Netlify redirect rules - https://www.netlify.com/docs/redirects/ 2 | # SPA setup - redirect all to index 3 | /* /index.html 200 4 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Vue Blog", 3 | "description": "A Vue Blog app using Cosmic JS", 4 | "repository": "https://github.com/cosmicjs/vue-blog-cosmicjs", 5 | "logo": "https://cosmicjs.com/images/logo.svg", 6 | "keywords": ["vue", "blog"] 7 | } 8 | -------------------------------------------------------------------------------- /bucket.json: -------------------------------------------------------------------------------- 1 | { 2 | "bucket": { 3 | "_id": "5a3cf965339183383f00013a", 4 | "slug": "vue-blog-cosmicjs", 5 | "title": "Vue Blog", 6 | "object_types": [ 7 | { 8 | "title": "Authors", 9 | "slug": "authors", 10 | "singular": "Author", 11 | "metafields": [], 12 | "options": { 13 | "slug_field": 1, 14 | "content_editor": 0 15 | }, 16 | "preview_link": "", 17 | "priority_locale": null 18 | }, 19 | { 20 | "title": "Posts", 21 | "slug": "posts", 22 | "singular": "Post", 23 | "metafields": [ 24 | { 25 | "required": true, 26 | "value": "", 27 | "key": "image", 28 | "title": "Image", 29 | "type": "file", 30 | "children": null 31 | }, 32 | { 33 | "required": true, 34 | "value": "", 35 | "key": "description", 36 | "title": "Description", 37 | "type": "text", 38 | "children": null 39 | }, 40 | { 41 | "object_type": "authors", 42 | "value": "", 43 | "key": "author", 44 | "title": "Author", 45 | "type": "object", 46 | "children": null 47 | } 48 | ], 49 | "options": { 50 | "slug_field": 1, 51 | "content_editor": 1 52 | }, 53 | "preview_link": "", 54 | "priority_locale": null, 55 | "localization": false, 56 | "locales": null 57 | } 58 | ], 59 | "objects": [ 60 | { 61 | "_id": "5a3cfa0d339183383f000156", 62 | "order": 0, 63 | "slug": "waqas-arshad", 64 | "title": "Waqas Arshad", 65 | "content": "", 66 | "metafields": [], 67 | "bucket": "5a3cf965339183383f00013a", 68 | "type_slug": "authors", 69 | "created_at": "2017-12-22T12:26:53.371Z", 70 | "created_by": "597f4130c4102a386100055c", 71 | "created": "2017-12-22T12:26:53.371Z", 72 | "user_id": "597f4130c4102a386100055c", 73 | "options": { 74 | "content_editor": 0, 75 | "slug_field": 0 76 | }, 77 | "status": "published" 78 | }, 79 | { 80 | "_id": "5a44e616016e2aed0200017a", 81 | "order": 0, 82 | "slug": "15-brilliant-ways-to-advertise-new-year", 83 | "title": "15 Brilliant Ways To Advertise New Year.", 84 | "content": "

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean in nulla nunc. Duis augue est, rutrum at cursus id, scelerisque nec est. Suspendisse potenti. Vestibulum porttitor erat porttitor libero lacinia rhoncus. Integer fermentum pulvinar ex a ultrices. Cras gravida a velit at blandit. Proin euismod vel nisl sit amet tincidunt. Fusce vitae neque tincidunt, posuere erat rhoncus, mattis sapien. Proin sollicitudin ut mi a efficitur. Phasellus fermentum aliquam ex. Fusce ultricies, odio vel interdum efficitur, neque mi dictum eros, eget elementum nibh mauris eget tellus. Vestibulum interdum felis nec bibendum rutrum. Morbi interdum urna sem, et porttitor sem ullamcorper non.

Donec ac sem mi. Cras viverra est magna, feugiat euismod nibh hendrerit ac. Sed in tempus nunc, sed sodales libero. Morbi aliquet nibh eget nisi pulvinar, eu malesuada urna pulvinar. Quisque laoreet hendrerit libero, vel imperdiet erat rhoncus non. Nullam arcu tortor, pulvinar non lacus eu, molestie faucibus metus. Aliquam tempus felis et enim faucibus, in posuere velit dignissim. Aliquam id tempus justo. Vestibulum fermentum massa vel felis dignissim, vel dignissim sem convallis. Phasellus rhoncus nisi sit amet tristique faucibus. Aenean a arcu quam. Pellentesque sed nunc laoreet, molestie orci dapibus, vehicula mauris. Aliquam nec efficitur lorem, vel varius quam. Aenean risus diam, egestas a luctus ac, rutrum vel elit. Praesent consequat urna augue. Vestibulum euismod, velit id elementum molestie, massa risus semper felis, in lobortis massa eros interdum eros.

Donec vitae pretium nibh, elementum aliquam metus. Suspendisse quis elit volutpat, pulvinar ligula et, posuere lacus. Nullam sit amet risus ac mi varius consectetur. Aliquam lectus mi, semper nec dui ac, semper lacinia velit. Aliquam elementum vestibulum vulputate. Nullam iaculis ipsum et urna iaculis, sed efficitur sapien condimentum. Pellentesque suscipit accumsan arcu, non pretium libero placerat at. Proin non tortor quis sapien sagittis consectetur. Duis nec pellentesque nisl. Aenean mi eros, fermentum sit amet ultrices non, rhoncus sed justo. Proin eu ornare odio. Cras rhoncus sapien ac vulputate imperdiet. Suspendisse interdum purus magna. Praesent euismod quam id massa scelerisque aliquam. Vivamus id libero at tortor porta tincidunt id et risus.

Ut vehicula accumsan erat, ut condimentum libero vulputate nec. Sed id lacus dolor. Vivamus eu lacus vel tortor lobortis euismod. Aenean in venenatis orci. Nunc in nisi et metus gravida porta auctor id nisi. Vestibulum lobortis efficitur enim vel pharetra. Aenean arcu nibh, maximus a elit quis, posuere convallis mi. Donec sed ornare lectus. Etiam porta consectetur congue.

", 85 | "metafields": [ 86 | { 87 | "required": true, 88 | "value": "26220930-ebcc-11e7-9942-d12ac3348247-pexels-photo-714703.jpeg", 89 | "key": "image", 90 | "title": "Image", 91 | "type": "file", 92 | "children": null 93 | }, 94 | { 95 | "required": true, 96 | "value": "Apathy is the glove into which evil slips its hand.", 97 | "key": "description", 98 | "title": "Description", 99 | "type": "text", 100 | "children": null 101 | }, 102 | { 103 | "object_type": "authors", 104 | "value": "5a3cf9fb339183383f000147", 105 | "key": "author", 106 | "title": "Author", 107 | "type": "object", 108 | "children": null 109 | } 110 | ], 111 | "bucket": "5a3cf965339183383f00013a", 112 | "type_slug": "posts", 113 | "created_at": "2017-12-28T12:39:50.867Z", 114 | "created_by": "597f4130c4102a386100055c", 115 | "created": "2017-12-28T12:39:50.867Z", 116 | "user_id": "597f4130c4102a386100055c", 117 | "options": { 118 | "content_editor": 1, 119 | "slug_field": 1 120 | }, 121 | "status": "published" 122 | }, 123 | { 124 | "_id": "5a3cf9fb339183383f000147", 125 | "order": 1, 126 | "slug": "jazib-sawar", 127 | "title": "Jazib Sawar", 128 | "content": "", 129 | "metafields": [], 130 | "bucket": "5a3cf965339183383f00013a", 131 | "type_slug": "authors", 132 | "created_at": "2017-12-22T12:26:35.402Z", 133 | "created_by": "597f4130c4102a386100055c", 134 | "created": "2017-12-22T12:26:35.402Z", 135 | "user_id": "597f4130c4102a386100055c", 136 | "options": { 137 | "content_editor": 0, 138 | "slug_field": 0 139 | }, 140 | "status": "published" 141 | }, 142 | { 143 | "_id": "5a44e5b8016e2aed02000175", 144 | "order": 1, 145 | "slug": "the-ultimate-revelation-of-success", 146 | "title": "The Ultimate Revelation Of Success.", 147 | "content": "

Donec ac sem mi. Cras viverra est magna, feugiat euismod nibh hendrerit ac. Sed in tempus nunc, sed sodales libero. Morbi aliquet nibh eget nisi pulvinar, eu malesuada urna pulvinar. Quisque laoreet hendrerit libero, vel imperdiet erat rhoncus non. Nullam arcu tortor, pulvinar non lacus eu, molestie faucibus metus. Aliquam tempus felis et enim faucibus, in posuere velit dignissim. Aliquam id tempus justo. Vestibulum fermentum massa vel felis dignissim, vel dignissim sem convallis. Phasellus rhoncus nisi sit amet tristique faucibus. Aenean a arcu quam. Pellentesque sed nunc laoreet, molestie orci dapibus, vehicula mauris. Aliquam nec efficitur lorem, vel varius quam. Aenean risus diam, egestas a luctus ac, rutrum vel elit. Praesent consequat urna augue. Vestibulum euismod, velit id elementum molestie, massa risus semper felis, in lobortis massa eros interdum eros.

Donec vitae pretium nibh, elementum aliquam metus. Suspendisse quis elit volutpat, pulvinar ligula et, posuere lacus. Nullam sit amet risus ac mi varius consectetur. Aliquam lectus mi, semper nec dui ac, semper lacinia velit. Aliquam elementum vestibulum vulputate. Nullam iaculis ipsum et urna iaculis, sed efficitur sapien condimentum. Pellentesque suscipit accumsan arcu, non pretium libero placerat at. Proin non tortor quis sapien sagittis consectetur. Duis nec pellentesque nisl. Aenean mi eros, fermentum sit amet ultrices non, rhoncus sed justo. Proin eu ornare odio. Cras rhoncus sapien ac vulputate imperdiet. Suspendisse interdum purus magna. Praesent euismod quam id massa scelerisque aliquam. Vivamus id libero at tortor porta tincidunt id et risus.

Ut vehicula accumsan erat, ut condimentum libero vulputate nec. Sed id lacus dolor. Vivamus eu lacus vel tortor lobortis euismod. Aenean in venenatis orci. Nunc in nisi et metus gravida porta auctor id nisi. Vestibulum lobortis efficitur enim vel pharetra. Aenean arcu nibh, maximus a elit quis, posuere convallis mi. Donec sed ornare lectus. Etiam porta consectetur congue.

", 148 | "metafields": [ 149 | { 150 | "required": true, 151 | "value": "f1597670-ebcb-11e7-9942-d12ac3348247-pexels-photo-747079.jpeg", 152 | "key": "image", 153 | "title": "Image", 154 | "type": "file", 155 | "children": null 156 | }, 157 | { 158 | "required": true, 159 | "value": "Men are so constituted that every one undertakes what he sees another successful in, whether he has aptitude for it or not.", 160 | "key": "description", 161 | "title": "Description", 162 | "type": "text", 163 | "children": null 164 | }, 165 | { 166 | "object_type": "authors", 167 | "value": "5a3cf9fb339183383f000147", 168 | "key": "author", 169 | "title": "Author", 170 | "type": "object", 171 | "children": null 172 | } 173 | ], 174 | "bucket": "5a3cf965339183383f00013a", 175 | "type_slug": "posts", 176 | "created_at": "2017-12-28T12:38:16.540Z", 177 | "created_by": "597f4130c4102a386100055c", 178 | "created": "2017-12-28T12:38:16.540Z", 179 | "user_id": "597f4130c4102a386100055c", 180 | "options": { 181 | "content_editor": 1, 182 | "slug_field": 1 183 | }, 184 | "status": "published" 185 | }, 186 | { 187 | "_id": "5a44e57000d6d07e020000f8", 188 | "order": 2, 189 | "slug": "this-is-why-nature-is-so-famous", 190 | "title": "This Is Why Nature Is So Famous!", 191 | "content": "

Donec ac sem mi. Cras viverra est magna, feugiat euismod nibh hendrerit ac. Sed in tempus nunc, sed sodales libero. Morbi aliquet nibh eget nisi pulvinar, eu malesuada urna pulvinar. Quisque laoreet hendrerit libero, vel imperdiet erat rhoncus non. Nullam arcu tortor, pulvinar non lacus eu, molestie faucibus metus. Aliquam tempus felis et enim faucibus, in posuere velit dignissim. Aliquam id tempus justo. Vestibulum fermentum massa vel felis dignissim, vel dignissim sem convallis. Phasellus rhoncus nisi sit amet tristique faucibus. Aenean a arcu quam. Pellentesque sed nunc laoreet, molestie orci dapibus, vehicula mauris. Aliquam nec efficitur lorem, vel varius quam. Aenean risus diam, egestas a luctus ac, rutrum vel elit. Praesent consequat urna augue. Vestibulum euismod, velit id elementum molestie, massa risus semper felis, in lobortis massa eros interdum eros.

Donec vitae pretium nibh, elementum aliquam metus. Suspendisse quis elit volutpat, pulvinar ligula et, posuere lacus. Nullam sit amet risus ac mi varius consectetur. Aliquam lectus mi, semper nec dui ac, semper lacinia velit. Aliquam elementum vestibulum vulputate. Nullam iaculis ipsum et urna iaculis, sed efficitur sapien condimentum. Pellentesque suscipit accumsan arcu, non pretium libero placerat at. Proin non tortor quis sapien sagittis consectetur. Duis nec pellentesque nisl. Aenean mi eros, fermentum sit amet ultrices non, rhoncus sed justo. Proin eu ornare odio. Cras rhoncus sapien ac vulputate imperdiet. Suspendisse interdum purus magna. Praesent euismod quam id massa scelerisque aliquam. Vivamus id libero at tortor porta tincidunt id et risus.

", 192 | "metafields": [ 193 | { 194 | "required": true, 195 | "value": "c660ca90-ebcb-11e7-a759-f9eda9745d97-pexels-photo-747964.jpeg", 196 | "key": "image", 197 | "title": "Image", 198 | "type": "file", 199 | "children": null 200 | }, 201 | { 202 | "required": true, 203 | "value": "That which we do not believe, we cannot adequately say; even though we may repeat the words ever so often.", 204 | "key": "description", 205 | "title": "Description", 206 | "type": "text", 207 | "children": null 208 | }, 209 | { 210 | "object_type": "authors", 211 | "value": "5a3cf9fb339183383f000147", 212 | "key": "author", 213 | "title": "Author", 214 | "type": "object", 215 | "children": null 216 | } 217 | ], 218 | "bucket": "5a3cf965339183383f00013a", 219 | "type_slug": "posts", 220 | "created_at": "2017-12-28T12:37:04.704Z", 221 | "created_by": "597f4130c4102a386100055c", 222 | "created": "2017-12-28T12:37:04.705Z", 223 | "user_id": "597f4130c4102a386100055c", 224 | "options": { 225 | "content_editor": 1, 226 | "slug_field": 1 227 | }, 228 | "status": "published" 229 | }, 230 | { 231 | "_id": "5a44e501016e2aed02000170", 232 | "order": 3, 233 | "slug": "cool-working-environment", 234 | "title": "Cool Working Environment", 235 | "content": "

Donec vitae pretium nibh, elementum aliquam metus. Suspendisse quis elit volutpat, pulvinar ligula et, posuere lacus. Nullam sit amet risus ac mi varius consectetur. Aliquam lectus mi, semper nec dui ac, semper lacinia velit. Aliquam elementum vestibulum vulputate. Nullam iaculis ipsum et urna iaculis, sed efficitur sapien condimentum. Pellentesque suscipit accumsan arcu, non pretium libero placerat at. Proin non tortor quis sapien sagittis consectetur. Duis nec pellentesque nisl. Aenean mi eros, fermentum sit amet ultrices non, rhoncus sed justo. Proin eu ornare odio. Cras rhoncus sapien ac vulputate imperdiet. Suspendisse interdum purus magna. Praesent euismod quam id massa scelerisque aliquam. Vivamus id libero at tortor porta tincidunt id et risus.

Ut vehicula accumsan erat, ut condimentum libero vulputate nec. Sed id lacus dolor. Vivamus eu lacus vel tortor lobortis euismod. Aenean in venenatis orci. Nunc in nisi et metus gravida porta auctor id nisi. Vestibulum lobortis efficitur enim vel pharetra. Aenean arcu nibh, maximus a elit quis, posuere convallis mi. Donec sed ornare lectus. Etiam porta consectetur congue.

Aliquam hendrerit nisl non blandit pulvinar. Sed gravida finibus viverra. Aliquam dolor tortor, condimentum sed egestas sit amet, gravida at dui. Cras laoreet ex justo, interdum porta nibh vulputate sit amet. Cras gravida mauris vel vestibulum ultrices. Nulla facilisi. Proin lobortis est bibendum sapien malesuada, in commodo mauris dictum. Curabitur efficitur turpis nunc, semper semper nisl pellentesque in. Mauris ut lorem sed libero tristique elementum varius id urna. Mauris varius viverra suscipit. Suspendisse dictum lorem eget ante tempus lacinia. Nam facilisis fringilla hendrerit. Etiam in ex magna. Quisque eget urna dictum, bibendum metus in, gravida sem.

", 236 | "metafields": [ 237 | { 238 | "required": true, 239 | "value": "7f787a60-ebcb-11e7-a759-f9eda9745d97-pexels-photo-748777.jpeg", 240 | "key": "image", 241 | "title": "Image", 242 | "type": "file", 243 | "children": null 244 | }, 245 | { 246 | "required": true, 247 | "value": "The critics who love are the severe ones ... we know our relationship must be based on honesty.", 248 | "key": "description", 249 | "title": "Description", 250 | "type": "text", 251 | "children": null 252 | }, 253 | { 254 | "object_type": "authors", 255 | "value": "5a3cfa0d339183383f000156", 256 | "key": "author", 257 | "title": "Author", 258 | "type": "object", 259 | "children": null 260 | } 261 | ], 262 | "bucket": "5a3cf965339183383f00013a", 263 | "type_slug": "posts", 264 | "created_at": "2017-12-28T12:35:13.090Z", 265 | "created_by": "597f4130c4102a386100055c", 266 | "created": "2017-12-28T12:35:13.090Z", 267 | "user_id": "597f4130c4102a386100055c", 268 | "options": { 269 | "content_editor": 1, 270 | "slug_field": 1 271 | }, 272 | "status": "published", 273 | "modified_at": "2017-12-28T12:52:10.742Z", 274 | "modified_by": "597f4130c4102a386100055c", 275 | "publish_at": null 276 | }, 277 | { 278 | "_id": "5a44dd5b00d6d07e020000e2", 279 | "order": 4, 280 | "slug": "heres-what-people-are-saying-about-coding", 281 | "title": "Here's What People Are Saying About Coding", 282 | "content": "

Donec vitae pretium nibh, elementum aliquam metus. Suspendisse quis elit volutpat, pulvinar ligula et, posuere lacus. Nullam sit amet risus ac mi varius consectetur. Aliquam lectus mi, semper nec dui ac, semper lacinia velit. Aliquam elementum vestibulum vulputate. Nullam iaculis ipsum et urna iaculis, sed efficitur sapien condimentum. Pellentesque suscipit accumsan arcu, non pretium libero placerat at. Proin non tortor quis sapien sagittis consectetur. Duis nec pellentesque nisl. Aenean mi eros, fermentum sit amet ultrices non, rhoncus sed justo. Proin eu ornare odio. Cras rhoncus sapien ac vulputate imperdiet. Suspendisse interdum purus magna. Praesent euismod quam id massa scelerisque aliquam. Vivamus id libero at tortor porta tincidunt id et risus.

Ut vehicula accumsan erat, ut condimentum libero vulputate nec. Sed id lacus dolor. Vivamus eu lacus vel tortor lobortis euismod. Aenean in venenatis orci. Nunc in nisi et metus gravida porta auctor id nisi. Vestibulum lobortis efficitur enim vel pharetra. Aenean arcu nibh, maximus a elit quis, posuere convallis mi. Donec sed ornare lectus. Etiam porta consectetur congue.

Aliquam hendrerit nisl non blandit pulvinar. Sed gravida finibus viverra. Aliquam dolor tortor, condimentum sed egestas sit amet, gravida at dui. Cras laoreet ex justo, interdum porta nibh vulputate sit amet. Cras gravida mauris vel vestibulum ultrices. Nulla facilisi. Proin lobortis est bibendum sapien malesuada, in commodo mauris dictum. Curabitur efficitur turpis nunc, semper semper nisl pellentesque in. Mauris ut lorem sed libero tristique elementum varius id urna. Mauris varius viverra suscipit. Suspendisse dictum lorem eget ante tempus lacinia. Nam facilisis fringilla hendrerit. Etiam in ex magna. Quisque eget urna dictum, bibendum metus in, gravida sem.

", 283 | "metafields": [ 284 | { 285 | "required": true, 286 | "value": "f456a320-ebc6-11e7-84a7-7367c605d42b-pexels-photo-577585.jpeg", 287 | "key": "image", 288 | "title": "Image", 289 | "type": "file", 290 | "children": null 291 | }, 292 | { 293 | "required": true, 294 | "value": "The essence of Government is power; and power, lodged as it must be in human hands, will ever be liable to abuse", 295 | "key": "description", 296 | "title": "Description", 297 | "type": "text", 298 | "children": null 299 | }, 300 | { 301 | "object_type": "authors", 302 | "value": "5a3cfa0d339183383f000156", 303 | "key": "author", 304 | "title": "Author", 305 | "type": "object", 306 | "children": null 307 | } 308 | ], 309 | "bucket": "5a3cf965339183383f00013a", 310 | "type_slug": "posts", 311 | "created_at": "2017-12-28T12:02:35.262Z", 312 | "created_by": "597f4130c4102a386100055c", 313 | "created": "2017-12-28T12:02:35.262Z", 314 | "user_id": "597f4130c4102a386100055c", 315 | "options": { 316 | "content_editor": 1, 317 | "slug_field": 1 318 | }, 319 | "status": "published", 320 | "modified_at": "2017-12-28T12:52:05.616Z", 321 | "modified_by": "597f4130c4102a386100055c", 322 | "publish_at": null 323 | }, 324 | { 325 | "_id": "5a44dcf453d863d87f000116", 326 | "order": 5, 327 | "slug": "this-year-will-be-the-year-of-creativity", 328 | "title": "This Year Will Be The Year of Creativity.", 329 | "content": "

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean in nulla nunc. Duis augue est, rutrum at cursus id, scelerisque nec est. Suspendisse potenti. Vestibulum porttitor erat porttitor libero lacinia rhoncus. Integer fermentum pulvinar ex a ultrices. Cras gravida a velit at blandit. Proin euismod vel nisl sit amet tincidunt. Fusce vitae neque tincidunt, posuere erat rhoncus, mattis sapien. Proin sollicitudin ut mi a efficitur. Phasellus fermentum aliquam ex. Fusce ultricies, odio vel interdum efficitur, neque mi dictum eros, eget elementum nibh mauris eget tellus. Vestibulum interdum felis nec bibendum rutrum. Morbi interdum urna sem, et porttitor sem ullamcorper non.

Donec ac sem mi. Cras viverra est magna, feugiat euismod nibh hendrerit ac. Sed in tempus nunc, sed sodales libero. Morbi aliquet nibh eget nisi pulvinar, eu malesuada urna pulvinar. Quisque laoreet hendrerit libero, vel imperdiet erat rhoncus non. Nullam arcu tortor, pulvinar non lacus eu, molestie faucibus metus. Aliquam tempus felis et enim faucibus, in posuere velit dignissim. Aliquam id tempus justo. Vestibulum fermentum massa vel felis dignissim, vel dignissim sem convallis. Phasellus rhoncus nisi sit amet tristique faucibus. Aenean a arcu quam. Pellentesque sed nunc laoreet, molestie orci dapibus, vehicula mauris. Aliquam nec efficitur lorem, vel varius quam. Aenean risus diam, egestas a luctus ac, rutrum vel elit. Praesent consequat urna augue. Vestibulum euismod, velit id elementum molestie, massa risus semper felis, in lobortis massa eros interdum eros.

Donec vitae pretium nibh, elementum aliquam metus. Suspendisse quis elit volutpat, pulvinar ligula et, posuere lacus. Nullam sit amet risus ac mi varius consectetur. Aliquam lectus mi, semper nec dui ac, semper lacinia velit. Aliquam elementum vestibulum vulputate. Nullam iaculis ipsum et urna iaculis, sed efficitur sapien condimentum. Pellentesque suscipit accumsan arcu, non pretium libero placerat at. Proin non tortor quis sapien sagittis consectetur. Duis nec pellentesque nisl. Aenean mi eros, fermentum sit amet ultrices non, rhoncus sed justo. Proin eu ornare odio. Cras rhoncus sapien ac vulputate imperdiet. Suspendisse interdum purus magna. Praesent euismod quam id massa scelerisque aliquam. Vivamus id libero at tortor porta tincidunt id et risus.

", 330 | "metafields": [ 331 | { 332 | "required": true, 333 | "value": "8457d490-ebc6-11e7-a759-f9eda9745d97-pexels-photo-262297.jpeg", 334 | "key": "image", 335 | "title": "Image", 336 | "type": "file", 337 | "children": null 338 | }, 339 | { 340 | "required": true, 341 | "value": "Fortunate indeed, is the man who takes exactely the right measure of himself, and holds a just balance between what he can acquire and what he can use.", 342 | "key": "description", 343 | "title": "Description", 344 | "type": "text", 345 | "children": null 346 | }, 347 | { 348 | "object_type": "authors", 349 | "value": "5a3cf9fb339183383f000147", 350 | "key": "author", 351 | "title": "Author", 352 | "type": "object", 353 | "children": null 354 | } 355 | ], 356 | "bucket": "5a3cf965339183383f00013a", 357 | "type_slug": "posts", 358 | "created_at": "2017-12-28T12:00:52.936Z", 359 | "created_by": "597f4130c4102a386100055c", 360 | "created": "2017-12-28T12:00:52.936Z", 361 | "user_id": "597f4130c4102a386100055c", 362 | "options": { 363 | "content_editor": 1, 364 | "slug_field": 1 365 | }, 366 | "status": "published" 367 | } 368 | ], 369 | "media": [ 370 | { 371 | "_id": "5a3cfa57339183383f00015a", 372 | "name": "90625dd0-e713-11e7-b3b1-5f98a6272afd-mona-eendra.jpg", 373 | "original_name": "mona-eendra.jpg", 374 | "size": 170326, 375 | "type": "image/jpeg", 376 | "bucket": "5a3cf965339183383f00013a", 377 | "created": "2017-12-22T12:28:07.281Z", 378 | "location": "https://s3-us-west-2.amazonaws.com/cosmicjs", 379 | "folder": null 380 | }, 381 | { 382 | "_id": "5a44e602016e2aed02000178", 383 | "name": "26220930-ebcc-11e7-9942-d12ac3348247-pexels-photo-714703.jpeg", 384 | "original_name": "pexels-photo-714703.jpeg", 385 | "size": 613936, 386 | "type": "image/jpeg", 387 | "bucket": "5a3cf965339183383f00013a", 388 | "created": "2017-12-28T12:39:30.465Z", 389 | "location": "https://s3-us-west-2.amazonaws.com/cosmicjs", 390 | "folder": null 391 | }, 392 | { 393 | "_id": "5a44e5aa016e2aed02000174", 394 | "name": "f1597670-ebcb-11e7-9942-d12ac3348247-pexels-photo-747079.jpeg", 395 | "original_name": "pexels-photo-747079.jpeg", 396 | "size": 1093366, 397 | "type": "image/jpeg", 398 | "bucket": "5a3cf965339183383f00013a", 399 | "created": "2017-12-28T12:38:02.100Z", 400 | "location": "https://s3-us-west-2.amazonaws.com/cosmicjs", 401 | "folder": null 402 | }, 403 | { 404 | "_id": "5a44e56100d6d07e020000f7", 405 | "name": "c660ca90-ebcb-11e7-a759-f9eda9745d97-pexels-photo-747964.jpeg", 406 | "original_name": "pexels-photo-747964.jpeg", 407 | "size": 1840090, 408 | "type": "image/jpeg", 409 | "bucket": "5a3cf965339183383f00013a", 410 | "created": "2017-12-28T12:36:49.936Z", 411 | "location": "https://s3-us-west-2.amazonaws.com/cosmicjs", 412 | "folder": null 413 | }, 414 | { 415 | "_id": "5a44e4eb00d6d07e020000f6", 416 | "name": "7f787a60-ebcb-11e7-a759-f9eda9745d97-pexels-photo-748777.jpeg", 417 | "original_name": "pexels-photo-748777.jpeg", 418 | "size": 1906525, 419 | "type": "image/jpeg", 420 | "bucket": "5a3cf965339183383f00013a", 421 | "created": "2017-12-28T12:34:51.340Z", 422 | "location": "https://s3-us-west-2.amazonaws.com/cosmicjs", 423 | "folder": null 424 | }, 425 | { 426 | "_id": "5a44dd4b53d863d87f000117", 427 | "name": "f456a320-ebc6-11e7-84a7-7367c605d42b-pexels-photo-577585.jpeg", 428 | "original_name": "pexels-photo-577585.jpeg", 429 | "size": 541610, 430 | "type": "image/jpeg", 431 | "bucket": "5a3cf965339183383f00013a", 432 | "created": "2017-12-28T12:02:19.533Z", 433 | "location": "https://s3-us-west-2.amazonaws.com/cosmicjs", 434 | "folder": null 435 | }, 436 | { 437 | "_id": "5a44dc8f00d6d07e020000e0", 438 | "name": "8457d490-ebc6-11e7-a759-f9eda9745d97-pexels-photo-262297.jpeg", 439 | "original_name": "pexels-photo-262297.jpeg", 440 | "size": 395558, 441 | "type": "image/jpeg", 442 | "bucket": "5a3cf965339183383f00013a", 443 | "created": "2017-12-28T11:59:11.578Z", 444 | "location": "https://s3-us-west-2.amazonaws.com/cosmicjs", 445 | "folder": null 446 | }, 447 | { 448 | "_id": "5a4e25829019dd07240000e2", 449 | "name": "4a1044a0-f14f-11e7-be6f-e3df94a9edf5-1.docx", 450 | "original_name": "1.docx", 451 | "size": 12132, 452 | "type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", 453 | "bucket": "5a3cf965339183383f00013a", 454 | "created": "2018-01-04T13:00:50.675Z", 455 | "location": "https://s3-us-west-2.amazonaws.com/cosmicjs", 456 | "folder": null 457 | } 458 | ] 459 | } 460 | } -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const shell = require('shelljs') 11 | const webpack = require('webpack') 12 | const config = require('../config') 13 | const copyFiles = config.build.copyFiles 14 | const assetsRoot = config.build.assetsRoot 15 | const webpackConfig = require('./webpack.prod.conf') 16 | 17 | const spinner = ora('building for production...') 18 | spinner.start() 19 | 20 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 21 | if (err) throw err 22 | webpack(webpackConfig, function (err, stats) { 23 | spinner.stop() 24 | if (err) throw err 25 | process.stdout.write(stats.toString({ 26 | colors: true, 27 | modules: false, 28 | children: false, 29 | chunks: false, 30 | chunkModules: false 31 | }) + '\n\n') 32 | 33 | if (stats.hasErrors()) { 34 | console.log(chalk.red(' Build failed with errors.\n')) 35 | process.exit(1) 36 | } 37 | 38 | shell.config.silent = true 39 | 40 | Object.keys(copyFiles) 41 | .forEach(src => shell.cp( 42 | path.resolve(__dirname, src), 43 | path.resolve(assetsRoot, copyFiles[src]) 44 | )) 45 | 46 | shell.config.silent = false 47 | 48 | console.log(chalk.cyan(' Build complete.\n')) 49 | console.log(chalk.yellow( 50 | ' Tip: built files are meant to be served over an HTTP server.\n' + 51 | ' Opening index.html over file:// won\'t work.\n' 52 | )) 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | function exec (cmd) { 7 | return require('child_process').execSync(cmd).toString().trim() 8 | } 9 | 10 | const versionRequirements = [ 11 | { 12 | name: 'node', 13 | currentVersion: semver.clean(process.version), 14 | versionRequirement: packageConfig.engines.node 15 | } 16 | ] 17 | 18 | if (shell.which('npm')) { 19 | versionRequirements.push({ 20 | name: 'npm', 21 | currentVersion: exec('npm --version'), 22 | versionRequirement: packageConfig.engines.npm 23 | }) 24 | } 25 | 26 | module.exports = function () { 27 | const warnings = [] 28 | for (let i = 0; i < versionRequirements.length; i++) { 29 | const mod = versionRequirements[i] 30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 31 | warnings.push(mod.name + ': ' + 32 | chalk.red(mod.currentVersion) + ' should be ' + 33 | chalk.green(mod.versionRequirement) 34 | ) 35 | } 36 | } 37 | 38 | if (warnings.length) { 39 | console.log('') 40 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 41 | console.log() 42 | for (let i = 0; i < warnings.length; i++) { 43 | const warning = warnings[i] 44 | console.log(' ' + warning) 45 | } 46 | console.log() 47 | process.exit(1) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 'use strict' 3 | require('eventsource-polyfill') 4 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 5 | 6 | hotClient.subscribe(function (event) { 7 | if (event.action === 'reload') { 8 | window.location.reload() 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /build/dev-server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | const config = require('../config') 5 | if (!process.env.NODE_ENV) { 6 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 7 | } 8 | 9 | const opn = require('opn') 10 | const path = require('path') 11 | const express = require('express') 12 | const webpack = require('webpack') 13 | const proxyMiddleware = require('http-proxy-middleware') 14 | const webpackConfig = require('./webpack.dev.conf') 15 | 16 | // default port where dev server listens for incoming traffic 17 | const port = process.env.PORT || config.dev.port 18 | // automatically open browser, if not set will be false 19 | const autoOpenBrowser = !!config.dev.autoOpenBrowser 20 | // Define HTTP proxies to your custom API backend 21 | // https://github.com/chimurai/http-proxy-middleware 22 | const proxyTable = config.dev.proxyTable 23 | 24 | const app = express() 25 | const compiler = webpack(webpackConfig) 26 | 27 | const devMiddleware = require('webpack-dev-middleware')(compiler, { 28 | publicPath: webpackConfig.output.publicPath, 29 | quiet: true 30 | }) 31 | 32 | const hotMiddleware = require('webpack-hot-middleware')(compiler, { 33 | log: false, 34 | heartbeat: 2000 35 | }) 36 | // force page reload when html-webpack-plugin template changes 37 | // currently disabled until this is resolved: 38 | // https://github.com/jantimon/html-webpack-plugin/issues/680 39 | // compiler.plugin('compilation', function (compilation) { 40 | // compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 41 | // hotMiddleware.publish({ action: 'reload' }) 42 | // cb() 43 | // }) 44 | // }) 45 | 46 | // enable hot-reload and state-preserving 47 | // compilation error display 48 | app.use(hotMiddleware) 49 | 50 | // proxy api requests 51 | Object.keys(proxyTable).forEach(function (context) { 52 | let options = proxyTable[context] 53 | if (typeof options === 'string') { 54 | options = { target: options } 55 | } 56 | app.use(proxyMiddleware(options.filter || context, options)) 57 | }) 58 | 59 | // handle fallback for HTML5 history API 60 | app.use(require('connect-history-api-fallback')()) 61 | 62 | // serve webpack bundle output 63 | app.use(devMiddleware) 64 | 65 | // serve pure static assets 66 | const staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 67 | app.use(staticPath, express.static('./static')) 68 | 69 | const uri = 'http://localhost:' + port 70 | 71 | var _resolve 72 | var _reject 73 | var readyPromise = new Promise((resolve, reject) => { 74 | _resolve = resolve 75 | _reject = reject 76 | }) 77 | 78 | var server 79 | var portfinder = require('portfinder') 80 | portfinder.basePort = port 81 | 82 | console.log('> Starting dev server...') 83 | devMiddleware.waitUntilValid(() => { 84 | portfinder.getPort((err, port) => { 85 | if (err) { 86 | _reject(err) 87 | } 88 | process.env.PORT = port 89 | var uri = 'http://localhost:' + port 90 | console.log('> Listening at ' + uri + '\n') 91 | // when env is testing, don't need open it 92 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { 93 | opn(uri) 94 | } 95 | server = app.listen(port) 96 | _resolve() 97 | }) 98 | }) 99 | 100 | module.exports = { 101 | ready: readyPromise, 102 | close: () => { 103 | server.close() 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | 6 | exports.assetsPath = function (_path) { 7 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 8 | ? config.build.assetsSubDirectory 9 | : config.dev.assetsSubDirectory 10 | return path.posix.join(assetsSubDirectory, _path) 11 | } 12 | 13 | exports.cssLoaders = function (options) { 14 | options = options || {} 15 | 16 | const cssLoader = { 17 | loader: 'css-loader', 18 | options: { 19 | minimize: process.env.NODE_ENV === 'production', 20 | sourceMap: options.sourceMap 21 | } 22 | } 23 | 24 | // generate loader string to be used with extract text plugin 25 | function generateLoaders (loader, loaderOptions) { 26 | const loaders = [cssLoader] 27 | if (loader) { 28 | loaders.push({ 29 | loader: loader + '-loader', 30 | options: Object.assign({}, loaderOptions, { 31 | sourceMap: options.sourceMap 32 | }) 33 | }) 34 | } 35 | 36 | // Extract CSS when that option is specified 37 | // (which is the case during production build) 38 | if (options.extract) { 39 | return ExtractTextPlugin.extract({ 40 | use: loaders, 41 | fallback: 'vue-style-loader' 42 | }) 43 | } else { 44 | return ['vue-style-loader'].concat(loaders) 45 | } 46 | } 47 | 48 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 49 | return { 50 | css: generateLoaders(), 51 | postcss: generateLoaders(), 52 | less: generateLoaders('less'), 53 | sass: generateLoaders('sass', { indentedSyntax: true }), 54 | scss: generateLoaders('sass'), 55 | stylus: generateLoaders('stylus'), 56 | styl: generateLoaders('stylus') 57 | } 58 | } 59 | 60 | // Generate loaders for standalone style files (outside of .vue) 61 | exports.styleLoaders = function (options) { 62 | const output = [] 63 | const loaders = exports.cssLoaders(options) 64 | for (const extension in loaders) { 65 | const loader = loaders[extension] 66 | output.push({ 67 | test: new RegExp('\\.' + extension + '$'), 68 | use: loader 69 | }) 70 | } 71 | return output 72 | } 73 | -------------------------------------------------------------------------------- /build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | 6 | module.exports = { 7 | loaders: utils.cssLoaders({ 8 | sourceMap: isProduction 9 | ? config.build.productionSourceMap 10 | : config.dev.cssSourceMap, 11 | extract: isProduction 12 | }), 13 | transformToRequire: { 14 | video: 'src', 15 | source: 'src', 16 | img: 'src', 17 | image: 'xlink:href' 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | module.exports = { 12 | entry: { 13 | app: './src/main.js' 14 | }, 15 | output: { 16 | path: config.build.assetsRoot, 17 | filename: '[name].js', 18 | publicPath: process.env.NODE_ENV === 'production' 19 | ? config.build.assetsPublicPath 20 | : config.dev.assetsPublicPath 21 | }, 22 | resolve: { 23 | extensions: ['.js', '.vue', '.json'], 24 | alias: { 25 | 'vue$': 'vue/dist/vue.esm.js', 26 | '@': resolve('src'), 27 | } 28 | }, 29 | module: { 30 | rules: [ 31 | { 32 | test: /\.(js|vue)$/, 33 | loader: 'eslint-loader', 34 | enforce: 'pre', 35 | include: [resolve('src'), resolve('test')], 36 | options: { 37 | formatter: require('eslint-friendly-formatter') 38 | } 39 | }, 40 | { 41 | test: /\.vue$/, 42 | loader: 'vue-loader', 43 | options: vueLoaderConfig 44 | }, 45 | { 46 | test: /\.js$/, 47 | loader: 'babel-loader', 48 | include: [resolve('src'), resolve('test')] 49 | }, 50 | { 51 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 52 | loader: 'url-loader', 53 | options: { 54 | limit: 10000, 55 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 56 | } 57 | }, 58 | { 59 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 60 | loader: 'url-loader', 61 | options: { 62 | limit: 10000, 63 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 64 | } 65 | }, 66 | { 67 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 68 | loader: 'url-loader', 69 | options: { 70 | limit: 10000, 71 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 72 | } 73 | } 74 | ] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const baseWebpackConfig = require('./webpack.base.conf') 7 | const HtmlWebpackPlugin = require('html-webpack-plugin') 8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 9 | 10 | // add hot-reload related code to entry chunks 11 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 12 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 13 | }) 14 | 15 | module.exports = merge(baseWebpackConfig, { 16 | module: { 17 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 18 | }, 19 | // cheap-module-eval-source-map is faster for development 20 | devtool: '#cheap-module-eval-source-map', 21 | plugins: [ 22 | new webpack.DefinePlugin({ 23 | 'process.env': config.dev.env 24 | }), 25 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 26 | new webpack.HotModuleReplacementPlugin(), 27 | new webpack.NoEmitOnErrorsPlugin(), 28 | // https://github.com/ampedandwired/html-webpack-plugin 29 | new HtmlWebpackPlugin({ 30 | filename: 'index.html', 31 | template: 'index.html', 32 | inject: true 33 | }), 34 | new FriendlyErrorsPlugin() 35 | ] 36 | }) 37 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const webpack = require('webpack') 5 | const config = require('../config') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 12 | 13 | const env = config.build.env 14 | 15 | const webpackConfig = merge(baseWebpackConfig, { 16 | module: { 17 | rules: utils.styleLoaders({ 18 | sourceMap: config.build.productionSourceMap, 19 | extract: true 20 | }) 21 | }, 22 | devtool: config.build.productionSourceMap ? '#source-map' : false, 23 | output: { 24 | path: config.build.assetsRoot, 25 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 26 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 27 | }, 28 | plugins: [ 29 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 30 | new webpack.DefinePlugin({ 31 | 'process.env': env 32 | }), 33 | // UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify 34 | new webpack.optimize.UglifyJsPlugin({ 35 | compress: { 36 | warnings: false 37 | }, 38 | sourceMap: true 39 | }), 40 | // extract css into its own file 41 | new ExtractTextPlugin({ 42 | filename: utils.assetsPath('css/[name].[contenthash].css') 43 | }), 44 | // Compress extracted CSS. We are using this plugin so that possible 45 | // duplicated CSS from different components can be deduped. 46 | new OptimizeCSSPlugin({ 47 | cssProcessorOptions: { 48 | safe: true 49 | } 50 | }), 51 | // generate dist index.html with correct asset hash for caching. 52 | // you can customize output by editing /index.html 53 | // see https://github.com/ampedandwired/html-webpack-plugin 54 | new HtmlWebpackPlugin({ 55 | filename: config.build.index, 56 | template: 'index.html', 57 | inject: true, 58 | minify: { 59 | removeComments: true, 60 | collapseWhitespace: true, 61 | removeAttributeQuotes: true 62 | // more options: 63 | // https://github.com/kangax/html-minifier#options-quick-reference 64 | }, 65 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 66 | chunksSortMode: 'dependency' 67 | }), 68 | // keep module.id stable when vender modules does not change 69 | new webpack.HashedModuleIdsPlugin(), 70 | // split vendor js into its own file 71 | new webpack.optimize.CommonsChunkPlugin({ 72 | name: 'vendor', 73 | minChunks: function (module) { 74 | // any required modules inside node_modules are extracted to vendor 75 | return ( 76 | module.resource && 77 | /\.js$/.test(module.resource) && 78 | module.resource.indexOf( 79 | path.join(__dirname, '../node_modules') 80 | ) === 0 81 | ) 82 | } 83 | }), 84 | // extract webpack runtime and module manifest to its own file in order to 85 | // prevent vendor hash from being updated whenever app bundle is updated 86 | new webpack.optimize.CommonsChunkPlugin({ 87 | name: 'manifest', 88 | chunks: ['vendor'] 89 | }), 90 | // copy custom static assets 91 | new CopyWebpackPlugin([ 92 | { 93 | from: path.resolve(__dirname, '../static'), 94 | to: config.build.assetsSubDirectory, 95 | ignore: ['.*'] 96 | } 97 | ]) 98 | ] 99 | }) 100 | 101 | if (config.build.productionGzip) { 102 | const CompressionWebpackPlugin = require('compression-webpack-plugin') 103 | 104 | webpackConfig.plugins.push( 105 | new CompressionWebpackPlugin({ 106 | asset: '[path].gz[query]', 107 | algorithm: 'gzip', 108 | test: new RegExp( 109 | '\\.(' + 110 | config.build.productionGzipExtensions.join('|') + 111 | ')$' 112 | ), 113 | threshold: 10240, 114 | minRatio: 0.8 115 | }) 116 | ) 117 | } 118 | 119 | if (config.build.bundleAnalyzerReport) { 120 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 121 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 122 | } 123 | 124 | module.exports = webpackConfig 125 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict' 3 | // Template version: 1.1.3 4 | // see http://vuejs-templates.github.io/webpack for documentation. 5 | 6 | const path = require('path') 7 | require('dotenv').config() 8 | 9 | module.exports = { 10 | build: { 11 | env: require('./prod.env'), 12 | index: path.resolve(__dirname, '../dist/index.html'), 13 | assetsRoot: path.resolve(__dirname, '../dist'), 14 | assetsSubDirectory: 'static', 15 | assetsPublicPath: '/', 16 | productionSourceMap: true, 17 | copyFiles: { '../_redirects': './' }, 18 | // Gzip off by default as many popular static hosts such as 19 | // Surge or Netlify already gzip all static assets for you. 20 | // Before setting to `true`, make sure to: 21 | // npm install --save-dev compression-webpack-plugin 22 | productionGzip: false, 23 | productionGzipExtensions: ['js', 'css'], 24 | // Run the build command with an extra argument to 25 | // View the bundle analyzer report after build finishes: 26 | // `npm run build --report` 27 | // Set to `true` or `false` to always turn it on or off 28 | bundleAnalyzerReport: process.env.npm_config_report 29 | }, 30 | dev: { 31 | env: require('./dev.env'), 32 | port: process.env.PORT || 8080, 33 | autoOpenBrowser: true, 34 | assetsSubDirectory: 'static', 35 | assetsPublicPath: '/', 36 | proxyTable: {}, 37 | // CSS Sourcemaps off by default because relative paths are "buggy" 38 | // with this option, according to the CSS-Loader README 39 | // (https://github.com/webpack/css-loader#sourcemaps) 40 | // In our experience, they generally work as expected, 41 | // just be aware of this issue when enabling this option. 42 | cssSourceMap: false 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"', 4 | COSMIC_BUCKET: `"${process.env.COSMIC_BUCKET || 'simple-vue-blog'}"`, 5 | COSMIC_READ_KEY: `"${process.env.COSMIC_READ_KEY}"`, 6 | COSMIC_WRITE_KEY: `"${process.env.COSMIC_WRITE_KEY}"`, 7 | BLOG_TITLE: `"${process.env.BLOG_TITLE || 'Vue Blog Cosmic JS'}"`, 8 | } 9 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vue Blog Cosmic JS 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "npm run build" 3 | publish = "dist" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-blog-cosmicjs", 3 | "version": "1.0.1", 4 | "description": "A simple blog app built using Vue & Vuex. It connects to the Cosmic JS CMS via API. You can manage your content from your Cosmic JS Dashboard.", 5 | "author": "Jazib Sawar ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "start": "node server.js", 10 | "build": "node build/build.js", 11 | "heroku-postbuild": "npm run build", 12 | "lint": "eslint --ext .js,.vue src" 13 | }, 14 | "dependencies": { 15 | "capitalize": "^1.0.0", 16 | "connect-history-api-fallback": "^1.5.0", 17 | "express": "^4.16.2", 18 | "lodash.map": "^4.6.0", 19 | "lodash.merge": "^4.6.0", 20 | "scrollto-with-animation": "^4.5.2", 21 | "vue": "^2.5.2", 22 | "vue-disqus": "^2.0.3", 23 | "vue-router": "^3.0.1", 24 | "autoprefixer": "^7.1.2", 25 | "babel-core": "^6.22.1", 26 | "babel-eslint": "^7.1.1", 27 | "babel-loader": "^7.1.1", 28 | "babel-plugin-transform-runtime": "^6.22.0", 29 | "babel-polyfill": "^6.23.0", 30 | "babel-preset-env": "^1.3.2", 31 | "babel-preset-stage-2": "^6.22.0", 32 | "babel-register": "^6.22.0", 33 | "chalk": "^2.0.1", 34 | "copy-webpack-plugin": "^4.0.1", 35 | "css-loader": "^0.28.0", 36 | "dotenv": "^4.0.0", 37 | "eslint": "^3.19.0", 38 | "eslint-config-standard": "^10.2.1", 39 | "eslint-friendly-formatter": "^3.0.0", 40 | "eslint-loader": "^1.7.1", 41 | "eslint-plugin-html": "^3.0.0", 42 | "eslint-plugin-import": "^2.7.0", 43 | "eslint-plugin-node": "^5.2.0", 44 | "eslint-plugin-promise": "^3.4.0", 45 | "eslint-plugin-standard": "^3.0.1", 46 | "eventsource-polyfill": "^0.9.6", 47 | "extract-text-webpack-plugin": "^3.0.0", 48 | "file-loader": "^1.1.4", 49 | "friendly-errors-webpack-plugin": "^1.6.1", 50 | "html-webpack-plugin": "^2.30.1", 51 | "http-proxy-middleware": "^0.17.3", 52 | "node-sass": "4.9.0", 53 | "opn": "^5.1.0", 54 | "optimize-css-assets-webpack-plugin": "^3.2.0", 55 | "ora": "^1.2.0", 56 | "pace": "0.0.4", 57 | "pace-progress": "^1.0.2", 58 | "portfinder": "^1.0.13", 59 | "postcss-custom-media": "^6.0.0", 60 | "rimraf": "^2.6.0", 61 | "sass-loader": "^6.0.6", 62 | "semver": "^5.3.0", 63 | "shelljs": "^0.7.6", 64 | "url-loader": "^0.5.8", 65 | "vue-loader": "^13.3.0", 66 | "vue-style-loader": "^3.0.1", 67 | "vue-template-compiler": "^2.5.2", 68 | "webpack": "^3.6.0", 69 | "webpack-bundle-analyzer": "^2.9.0", 70 | "webpack-dev-middleware": "^1.12.0", 71 | "webpack-hot-middleware": "^2.18.2", 72 | "webpack-merge": "^4.1.0" 73 | }, 74 | "engines": { 75 | "node": ">= 8.11.3", 76 | "npm": ">= 5.0.0" 77 | }, 78 | "browserslist": [ 79 | "last 2 versions", 80 | "not ie <= 9" 81 | ] 82 | } 83 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path'); 3 | const serveStatic = require('serve-static'); 4 | const history = require('connect-history-api-fallback'); 5 | 6 | app = express(); 7 | app.use(history()); 8 | app.use(serveStatic(__dirname + "/dist")); 9 | 10 | const port = process.env.PORT || 5000; 11 | 12 | app.listen(port); 13 | 14 | console.log(`Server started on port ${port}`); 15 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /src/assets/ApplicationHomePage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/src/assets/ApplicationHomePage.png -------------------------------------------------------------------------------- /src/assets/add-bucket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/src/assets/add-bucket.png -------------------------------------------------------------------------------- /src/assets/credentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/src/assets/credentials.png -------------------------------------------------------------------------------- /src/assets/deploy-button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/assets/env.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/src/assets/env.png -------------------------------------------------------------------------------- /src/assets/install_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/src/assets/install_app.png -------------------------------------------------------------------------------- /src/assets/redeploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/src/assets/redeploy.png -------------------------------------------------------------------------------- /src/assets/search_apps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/src/assets/search_apps.png -------------------------------------------------------------------------------- /src/assets/vue-snip.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Blog.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 63 | -------------------------------------------------------------------------------- /src/components/BlogFeed.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 109 | -------------------------------------------------------------------------------- /src/components/BlogFooter.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /src/components/BlogNav.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 43 | -------------------------------------------------------------------------------- /src/components/BlogPost.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 74 | -------------------------------------------------------------------------------- /src/components/BlogTitle.vue: -------------------------------------------------------------------------------- 1 | 52 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Blog' 2 | -------------------------------------------------------------------------------- /src/config/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | COSMIC_BUCKET: process.env.COSMIC_BUCKET, 3 | COSMIC_READ_KEY: process.env.COSMIC_READ_KEY, 4 | COSMIC_WRITE_KEY: process.env.COSMIC_WRITE_KEY, 5 | BLOG_TITLE: process.env.BLOG_TITLE 6 | } 7 | -------------------------------------------------------------------------------- /src/helpers.js: -------------------------------------------------------------------------------- 1 | import animateScroll from 'scrollto-with-animation' 2 | import capitalize from 'capitalize' 3 | 4 | export const scrollTo = (pos, duration = 600, delay = 0) => new Promise(resolve => { 5 | setTimeout(() => { 6 | animateScroll(document.documentElement, 'scrollTop', pos, duration, 'easeInOutSine', resolve) 7 | }, delay) 8 | }) 9 | 10 | export const kebabify = (words) => 11 | words 12 | .toLowerCase() 13 | .replace(' ', '-') 14 | 15 | export const unkebabify = (str) => capitalize.words(str.replace(/-/g, ' ')) 16 | 17 | export const prettyDate = (date) => 18 | new Date(date) 19 | .toString() 20 | .split(' ') 21 | .slice(0, 4) 22 | .join(' ') 23 | .replace(/( \d+)$/, ',$1') 24 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import './startup' 2 | 3 | import Vue from 'vue' 4 | import App from './App' 5 | import router from './router' 6 | import * as resources from './resources' 7 | import resource from './plugins/resource' 8 | import deviceQueries from './plugins/device-queries' 9 | import config from './config' 10 | 11 | Vue.config.productionTip = false 12 | 13 | Vue.use(resource, { 14 | resources, 15 | endpoint: 'https://api.cosmicjs.com/v1/' + config.COSMIC_BUCKET 16 | }) 17 | 18 | Vue.use(deviceQueries, { 19 | phone: 'max-width: 567px', 20 | tablet: 'min-width: 568px', 21 | mobile: 'max-width: 1024px', 22 | laptop: 'min-width: 1025px', 23 | desktop: 'min-width: 1280px', 24 | monitor: 'min-width: 1448px' 25 | }) 26 | 27 | new Vue({ 28 | router, 29 | render: h => h(App) 30 | }).$mount('#app') 31 | -------------------------------------------------------------------------------- /src/plugins/device-queries/index.js: -------------------------------------------------------------------------------- 1 | import matchMedia from './match-media' 2 | 3 | export default { 4 | install(Vue, queries) { 5 | const DeviceVM = new Vue({ 6 | data() { 7 | return { 8 | devices: {} 9 | } 10 | }, 11 | 12 | methods: { 13 | addDevice(name, active) { 14 | this.$set(this.devices, name, active) 15 | 16 | return ({ matches }) => { 17 | this.devices[name] = matches 18 | } 19 | } 20 | } 21 | }) 22 | 23 | Object.keys(queries).forEach(name => { 24 | let query = matchMedia(`(${queries[name]})`) 25 | let update = DeviceVM.addDevice(name, query.matches) 26 | query.addListener(update) 27 | }) 28 | 29 | Vue.prototype.$device = DeviceVM.devices 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/plugins/device-queries/match-media.js: -------------------------------------------------------------------------------- 1 | const matchMediaFallback = () => { 2 | let listeners = [] 3 | let idle = true 4 | 5 | const device = (() => { 6 | let node = document.createElement('div') 7 | let style = document.createElement('style') 8 | 9 | node.id = 'match-media-node' 10 | style.innerHTML = `#match-media-node { 11 | width: 100%; 12 | height: 100%; 13 | position: absolute; 14 | bottom: 100%; 15 | overflow: scroll; 16 | }` 17 | 18 | document.head.appendChild(style) 19 | document.body.insertBefore(node, document.body.children[0]) 20 | 21 | return { 22 | get width() { 23 | return node.clientWidth 24 | }, 25 | get height() { 26 | return node.clientHeight 27 | }, 28 | get orientation() { 29 | return (node.clientHeight > node.clientWidth) 30 | ? 'portrait' 31 | : 'landscape' 32 | }, 33 | get fontSize() { 34 | return window 35 | .getComputedStyle(document.documentElement) 36 | .getPropertyValue('font-size') 37 | } 38 | } 39 | })() 40 | 41 | const createHandler = (feature, value) => { 42 | if (feature === 'orientation') { 43 | return () => value === device.orientation 44 | } 45 | 46 | let [prop, limit] = feature 47 | .split('-') 48 | .reverse() 49 | 50 | const operand = (!limit) ? '==' 51 | : (limit === 'min') ? '<' 52 | : '>' 53 | 54 | const parseValue = (() => { 55 | return (~value.indexOf('em')) 56 | ? () => parseFloat(value) * device.fontSize 57 | : () => parseFloat(value) 58 | })() 59 | 60 | const handlers = { 61 | 'width': () => eval(parseValue() + operand + device.width), 62 | 'height': () => eval(parseValue() + operand + device.height) 63 | } 64 | 65 | return handlers[prop] 66 | } 67 | 68 | const parseQuery = (queryString) => { 69 | let [feature, value] = queryString.replace(/[()\s]/g, '').split(':') 70 | return createHandler(feature, value) 71 | } 72 | 73 | window.addEventListener('resize', () => { 74 | if (!idle) return; 75 | idle = false 76 | 77 | let width = device.width 78 | let height = device.height 79 | 80 | let timer = setInterval(() => { 81 | if (width !== device.width || height !== device.height) { 82 | width = device.width 83 | height = device.height 84 | } else { 85 | clearTimeout(timer) 86 | listeners.forEach(handler => handler()) 87 | idle = true 88 | } 89 | }, 100) 90 | }) 91 | 92 | return (queryString) => { 93 | const query = parseQuery(queryString) 94 | const matcher = { 95 | get matches() { 96 | return query() 97 | } 98 | } 99 | 100 | return { 101 | ...matcher, 102 | addListener(cb) { 103 | const handler = () => cb(matcher) 104 | listeners.push(handler) 105 | } 106 | } 107 | } 108 | } 109 | 110 | const matchMedia = window.matchMedia || matchMediaFallback() 111 | 112 | export { matchMedia as default } 113 | -------------------------------------------------------------------------------- /src/plugins/resource/cache.js: -------------------------------------------------------------------------------- 1 | export default (() => { 2 | let store = {} 3 | 4 | return { 5 | has: uri => !!store[uri], 6 | get: uri => JSON.parse(store[uri]), 7 | set: (uri, data) => { 8 | store[uri] = JSON.stringify(data) 9 | return Promise.resolve(data) 10 | } 11 | } 12 | })() 13 | -------------------------------------------------------------------------------- /src/plugins/resource/index.js: -------------------------------------------------------------------------------- 1 | import cache from './cache' 2 | import _merge from 'lodash.merge' 3 | import config from '../../config' 4 | 5 | // install $resource as a Vue plugin 6 | export default { 7 | install(Vue, { endpoint = '', resources = {} }) { 8 | Vue.prototype.$getResource = function(method, options) { 9 | let name = this.$options.resource 10 | if (!name || !resources[name] || !resources[name][method]) return; 11 | 12 | // get fetch path and response resolver/mapper 13 | let { path, resolve } = resources[name][method](options) 14 | let uri = ''; 15 | if (method === 'blog') { 16 | uri = '/static/api' + path 17 | } else { 18 | uri = endpoint + path + '?hide_metafields=true&read_key=' + config.COSMIC_READ_KEY 19 | } 20 | 21 | // methods return promise to allow chaining 22 | const mappers = { 23 | // only return promise without modifying instance $data 24 | pipe: dataSet => Promise.resolve(dataSet), 25 | 26 | // deep merge object with instance $data 27 | merge: dataSet => { 28 | _merge(this.$data, dataSet) 29 | return Promise.resolve(dataSet) 30 | }, 31 | 32 | // set individual props on instance $data 33 | set: dataSet => { 34 | Object.keys(dataSet).forEach(prop => { 35 | this.$set(this.$data, prop, dataSet[prop]) 36 | }) 37 | 38 | return Promise.resolve(dataSet) 39 | } 40 | } 41 | 42 | // check to see if the resource has been cached already 43 | if (cache.has(uri)) return resolve(cache.get(uri), mappers) 44 | 45 | // fetch, parse and cache resource then pass to resolver 46 | return fetch(uri) 47 | .then(response => response.json()) 48 | .then(response => cache.set(uri, response)) 49 | .then(response => resolve(response, mappers)) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/resources/Blog.js: -------------------------------------------------------------------------------- 1 | import config from '../config' 2 | 3 | export default { 4 | blog() { 5 | return { 6 | path: '/blog.json', 7 | resolve: (response, mappers) => { 8 | let blog = response.results[0] 9 | return mappers.merge({ 10 | title: config.BLOG_TITLE || blog.title, 11 | labels: { 12 | post: blog.post_label, 13 | author: blog.author_label 14 | } 15 | }) 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/resources/BlogFeed.js: -------------------------------------------------------------------------------- 1 | import _map from 'lodash.map' 2 | 3 | export default { 4 | feed() { 5 | return { 6 | path: '/object-type/posts', 7 | resolve: (response, mappers) => { 8 | let _posts = _map(response.objects, function(i) { 9 | let temp = { 10 | title: i.title, 11 | image: i.metadata.image.imgix_url, 12 | published: i.created_at, 13 | author: i.metadata.author.title, 14 | id: i.slug 15 | }; 16 | return temp; 17 | }) 18 | return mappers.pipe(_posts) 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/resources/BlogPost.js: -------------------------------------------------------------------------------- 1 | export default { 2 | post(id) { 3 | return { 4 | path: `/object/${id}`, 5 | resolve: (response, mappers) => { 6 | let { title, content, created_at, metadata } = response.object 7 | let meta = { 8 | description: metadata.description, 9 | published: created_at, 10 | author: metadata.author.title 11 | } 12 | return mappers.merge({ title, content, ...meta }) 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/resources/index.js: -------------------------------------------------------------------------------- 1 | export { default as Blog } from './Blog' 2 | export { default as BlogFeed } from './BlogFeed' 3 | export { default as BlogPost } from './BlogPost' 4 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Blog from '../components' 4 | 5 | Vue.use(Router) 6 | 7 | export default new Router({ 8 | mode: 'history', 9 | linkActiveClass: 'active', 10 | routes: [{ 11 | path: '/', 12 | name: 'feed', 13 | component: Blog 14 | }, { 15 | path: '/by/:author', 16 | name: 'author', 17 | props: true, 18 | component: Blog 19 | }, { 20 | path: '/read/:post', 21 | name: 'post', 22 | props: true, 23 | component: Blog 24 | }] 25 | }) 26 | -------------------------------------------------------------------------------- /src/sass/_app.scss: -------------------------------------------------------------------------------- 1 | @import 2 | // tools */ 3 | './tools', 4 | './tools/mediaqueries', 5 | // base */ 6 | './base/reset', 7 | './base/text', 8 | './base/body', 9 | // blocks */ 10 | './blocks/pace', 11 | './blocks/rte', 12 | './blocks/nav', 13 | './blocks/blog', 14 | './blocks/preview', 15 | './blocks/post', 16 | './blocks/footer', 17 | './blocks/v-transitions' 18 | -------------------------------------------------------------------------------- /src/sass/_tools.scss: -------------------------------------------------------------------------------- 1 | // tools */ 2 | @import 3 | './tools/mixins', 4 | './tools/colors', 5 | './tools/easings', 6 | './tools/functions' 7 | -------------------------------------------------------------------------------- /src/sass/base/_body.scss: -------------------------------------------------------------------------------- 1 | body { 2 | @extend %txt--body; 3 | position: relative; 4 | color: cc(txt); 5 | background-color: cc(bg); 6 | 7 | ::selection { 8 | background-color: cc(selection); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/sass/base/_reset.scss: -------------------------------------------------------------------------------- 1 | /* reset */ 2 | * { 3 | box-sizing: inherit; 4 | margin: 0; 5 | padding: 0; 6 | border-radius: 0; 7 | border: none; 8 | outline: none; 9 | background: none; 10 | -webkit-margin-before: 0; 11 | -webkit-margin-after: 0; 12 | -webkit-margin-start: 0; 13 | -webkit-margin-end: 0; 14 | -webkit-padding-before: 0; 15 | -webkit-padding-start: 0; 16 | -webkit-padding-end: 0; 17 | -webkit-padding-after: 0; 18 | } 19 | 20 | *::before, 21 | *::after { 22 | box-sizing: inherit; 23 | } 24 | 25 | *:active, 26 | *:hover { 27 | outline: 0; 28 | } 29 | 30 | html { 31 | box-sizing: border-box; 32 | font-size: 100%; 33 | height: 100%; 34 | } 35 | 36 | body { 37 | position: relative; 38 | line-height: 1; 39 | -webkit-font-smoothing: antialiased; 40 | -moz-osx-font-smoothing: grayscale; 41 | } 42 | 43 | b, i, em, strong, 44 | h1, h2, h3, h4, h5, h6, 45 | th, td, pre, ins, del, address, 46 | input, select, button, textarea { 47 | text-transform: inherit; 48 | font-family: inherit; 49 | font-size: inherit; 50 | font-weight: inherit; 51 | font-style: normal; 52 | letter-spacing: inherit; 53 | } 54 | 55 | textarea, 56 | input { 57 | appearance: none; 58 | background-clip: padding-box; 59 | } 60 | 61 | a, ins, del, button { 62 | color: inherit; 63 | text-decoration: none; 64 | } 65 | 66 | ul, ol, 67 | menu { 68 | list-style: none; 69 | } 70 | 71 | table { 72 | width: 100%; 73 | border-collapse: separate; 74 | border-spacing: 0; 75 | } 76 | 77 | pre, 78 | textarea { 79 | overflow: auto; 80 | max-width: 100%; 81 | } 82 | 83 | img { 84 | display: block; 85 | width: 100%; 86 | height: auto; 87 | } 88 | 89 | svg:not(:root) { 90 | overflow: hidden; 91 | } 92 | 93 | form { 94 | width: 100%; 95 | } 96 | 97 | button { 98 | cursor: pointer; 99 | overflow: visible; 100 | } 101 | 102 | textarea { 103 | resize: none; 104 | } 105 | 106 | ::moz-focus-inner { 107 | padding: 0; 108 | border: none; 109 | } 110 | -------------------------------------------------------------------------------- /src/sass/base/_text.scss: -------------------------------------------------------------------------------- 1 | // font stack 2 | @mixin font-stack($ff, $weight: normal) { 3 | font-family: #{$ff}, Helvetica, Arial, sans-serif; 4 | font-weight: $weight; 5 | } 6 | 7 | // font families 8 | %ff--200 { @include font-stack('Prompt', 200) } 9 | %ff--300 { @include font-stack('Prompt', 300) } 10 | %ff--500 { @include font-stack('Prompt', 500) } 11 | %ff--700 { @include font-stack('Prompt', 700) } 12 | 13 | // extend placeholders 14 | %txt--body { 15 | @extend %ff--300; 16 | font-size: 1rem; 17 | } 18 | 19 | %txt--rte { 20 | @extend %txt--body; 21 | line-height: 1.5; 22 | } 23 | 24 | %txt--banner { 25 | @extend %ff--700; 26 | line-height: 1; 27 | font-size: 2.4rem; 28 | letter-spacing: -.005em; 29 | 30 | @media (--tablet) { 31 | font-size: 2.6rem; 32 | } 33 | } 34 | 35 | %txt--preview { 36 | @extend %ff--500; 37 | font-size: 3rem; 38 | text-transform: capitalize; 39 | 40 | @media (--laptop) { 41 | font-size: 2.7rem; 42 | } 43 | 44 | @media (--desktop) { 45 | font-size: 3.2rem; 46 | } 47 | } 48 | 49 | %txt--title { 50 | @extend %ff--200; 51 | font-size: 3rem; 52 | line-height: 1.2; 53 | text-transform: capitalize; 54 | 55 | @media (--laptop) { 56 | font-size: 3.2rem; 57 | } 58 | } 59 | 60 | %txt--subtitle { 61 | @extend %ff--500; 62 | font-size: 1.25rem; 63 | line-height: 1.5; 64 | } 65 | 66 | %txt--heading { 67 | @extend %ff--700; 68 | font-size: 1.15rem; 69 | line-height: 1.5; 70 | } 71 | -------------------------------------------------------------------------------- /src/sass/blocks/_blog.scss: -------------------------------------------------------------------------------- 1 | .blog { 2 | position: relative; 3 | min-height: 100vh; 4 | max-width: 90rem; 5 | margin: 0 auto; 6 | padding-top: 6.25rem; 7 | overflow-x: hidden; 8 | 9 | @media (--tablet) { 10 | padding: 7.5rem 0; 11 | } 12 | 13 | @media (--desktop) { 14 | padding: 7.5rem 2.5rem 6.5vw; 15 | 16 | &--reading { 17 | padding-bottom: 0; 18 | } 19 | } 20 | 21 | @media (--monitor) { 22 | padding: 7.5rem 0 6.5vw; 23 | 24 | &--reading { 25 | padding-bottom: 0; 26 | } 27 | } 28 | 29 | &__feed { 30 | position: relative; 31 | padding: 0 .625rem; 32 | 33 | @media (--tablet) { 34 | display: flex; 35 | align-items: flex-start; 36 | flex-wrap: wrap; 37 | padding: 0 1.25rem; 38 | } 39 | 40 | @media (--monitor) { 41 | padding: 0; 42 | } 43 | } 44 | 45 | &__footer { 46 | width: 100%; 47 | height: 5rem; 48 | display: flex; 49 | justify-content: center; 50 | align-items: center; 51 | padding: 0 2.5rem; 52 | 53 | @media (--tablet) { 54 | position: absolute; 55 | bottom: 0; 56 | left: 0; 57 | } 58 | 59 | @media (--laptop) { 60 | justify-content: flex-start; 61 | } 62 | 63 | @media (--desktop) { 64 | padding: 0 6.25rem; 65 | } 66 | 67 | @media (--monitor) { 68 | padding: 0 2.5rem; 69 | } 70 | 71 | .signature { 72 | display: inline-block; 73 | width: 15rem; 74 | text-align: center; 75 | 76 | @media (--tablet) { 77 | width: 18rem; 78 | } 79 | } 80 | .cosmicjs { 81 | color: #ADB6C0; 82 | text-transform: capitalize; 83 | a { 84 | color: #2A3744; 85 | font-weight: 400; 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/sass/blocks/_footer.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/src/sass/blocks/_footer.scss -------------------------------------------------------------------------------- /src/sass/blocks/_nav.scss: -------------------------------------------------------------------------------- 1 | .nav { 2 | position: fixed; 3 | top: 0; 4 | left: 50%; 5 | width: calc(100% - 2.5rem); 6 | max-width: 90rem; 7 | padding: 1.25rem .625rem .625rem; 8 | border-bottom: 1px solid cc(border); 9 | background-color: cc(bg, .975); 10 | box-shadow: 0 -50vw 0 50vw cc(bg, .975); 11 | display: flex; 12 | justify-content: space-between; 13 | align-items: flex-end; 14 | transform: translate(-50%); 15 | z-index: 1; 16 | 17 | @media (--tablet) { 18 | padding: 1.75rem 1.25rem 1.25rem; 19 | } 20 | 21 | @media (--desktop) { 22 | width: calc(100% - 10rem); 23 | } 24 | 25 | @media (--monitor) { 26 | padding: 1.75rem 2.5rem 1.25rem; 27 | } 28 | 29 | &__title { 30 | @extend %txt--banner; 31 | color: cc(txt, alt); 32 | } 33 | 34 | &__menu { 35 | position: relative; 36 | 37 | @media (--phone) { 38 | height: 1.75rem; 39 | } 40 | } 41 | 42 | &__item { 43 | cursor: pointer; 44 | display: inline-block; 45 | position: relative; 46 | margin-left: .75rem; 47 | padding-left: .25rem; 48 | user-select: none; 49 | white-space: nowrap; 50 | z-index: 0; 51 | transition: all 250ms cb() 300ms; 52 | 53 | @media (--phone) { 54 | width: 1.75rem; 55 | height: 1.75rem; 56 | } 57 | 58 | &-enter, 59 | &-leave-to { 60 | opacity: 0; 61 | transition-delay: 0ms; 62 | transform: translate3d(-2.5rem, 0, 0); 63 | } 64 | 65 | &-leave-active { 66 | position: absolute; 67 | bottom: 0; 68 | right: 0; 69 | } 70 | 71 | &--icon { 72 | display: block; 73 | position: absolute; 74 | top: 50%; 75 | right: 100%; 76 | transform: translate3d(-25%, -50%, 0); 77 | font-size: 1.25rem; 78 | width: 1em; 79 | height: 1em; 80 | box-shadow: inset 0 0 0 0 cc(primary); 81 | border-radius: 100%; 82 | overflow: hidden; 83 | transition: box-shadow 175ms cb() 25ms; 84 | 85 | &::before, 86 | &::after { 87 | content: ''; 88 | position: absolute; 89 | top: 50%; 90 | left: 50%; 91 | width: 10%; 92 | height: 70%; 93 | background-color: cc(bg); 94 | transition: transform 225ms cb(); 95 | } 96 | 97 | &::before { transform: translate3d(-50%, -50%, 0) rotate(-45deg) scaleY(0) } 98 | &::after { transform: translate3d(-50%, -50%, 0) rotate(45deg) scaleY(0) } 99 | 100 | @media (--phone) { 101 | right: 0; 102 | box-shadow: none; 103 | background-color: cc(primary); 104 | 105 | &::before, 106 | &::after { 107 | height: 35%; 108 | } 109 | 110 | &::before { 111 | transform: translate3d(0, -50%, 0) rotate(-45deg) scaleY(1); 112 | transform-origin: 100% 100%; 113 | } 114 | 115 | &::after { 116 | transform: translate3d(0, -50%, 0) rotate(45deg) scaleY(1); 117 | transform-origin: 100% 0%; 118 | } 119 | } 120 | } 121 | 122 | &:hover &--icon { 123 | box-shadow: inset 0 0 0 1.1em cc(primary); 124 | &::before { transform: translate3d(-50%, -50%, 0) rotate(-45deg) scaleY(1) } 125 | &::after { transform: translate3d(-50%, -50%, 0) rotate(45deg) scaleY(1) } 126 | } 127 | 128 | &--label { 129 | @media (--phone) { 130 | display: none; 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/sass/blocks/_pace.scss: -------------------------------------------------------------------------------- 1 | .pace { 2 | pointer-events: none; 3 | user-select: none; 4 | 5 | &-inactive { 6 | display: none; 7 | } 8 | 9 | .pace-progress { 10 | background: cc(primary); 11 | position: fixed; 12 | z-index: 2000; 13 | top: 0; 14 | right: 100%; 15 | width: 100%; 16 | height: 3px; 17 | } 18 | } 19 | 20 | .pace-inactive { 21 | display: none; 22 | } 23 | -------------------------------------------------------------------------------- /src/sass/blocks/_post.scss: -------------------------------------------------------------------------------- 1 | .post { 2 | padding: 0 1.25rem 0; 3 | background-color: cc(bg); 4 | transform: translate3d(0, 0, 0); 5 | 6 | &-enter-active { transition: all 375ms cb(out) 225ms } 7 | &-leave-active { transition: all 300ms cb(in) } 8 | 9 | &-enter, 10 | &-leave-to { 11 | opacity: 0; 12 | transform: translate3d(100%, 0, 0); 13 | } 14 | 15 | @media (--laptop) { 16 | position: fixed; 17 | top: 0; 18 | left: calc(100% / 3 + 3.25rem); 19 | width: calc(100% / 1.5 - 3.25rem); 20 | height: 100%; 21 | padding: 10rem 5rem 5rem 0; 22 | overflow-y: scroll; 23 | 24 | &-enter-active { transition: all 525ms cb(out) 225ms } 25 | &-leave-active { transition: all 350ms cb(in) } 26 | 27 | &-enter, 28 | &-leave-to { 29 | opacity: 0; 30 | transform: translate3d(100%, 0, 0); 31 | } 32 | } 33 | 34 | @media (--monitor) { 35 | width: 62rem; 36 | left: calc(50% - 12rem); 37 | } 38 | 39 | &__header { 40 | @media (--tablet) { 41 | position: absolute; 42 | bottom: 100%; 43 | right: 0; 44 | width: 50vw; 45 | height: calc(70vw - 2.5rem); 46 | display: flex; 47 | flex-direction: column; 48 | padding-right: 2.5rem; 49 | padding-bottom: 2.5rem; 50 | } 51 | 52 | @media (--laptop) { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | display: block; 57 | margin-bottom: 1.25rem; 58 | padding-bottom: 0; 59 | } 60 | } 61 | 62 | &__title { 63 | @extend %txt--title; 64 | display: none; 65 | 66 | @media (--tablet) { 67 | display: block; 68 | color: cc(txt, alt); 69 | margin-bottom: .75rem; 70 | padding-left: 1.25rem; 71 | } 72 | } 73 | 74 | &__meta { 75 | display: none; 76 | 77 | @media (--tablet) { 78 | display: block; 79 | margin-bottom: 1.25rem; 80 | padding-left: 1.25rem; 81 | padding-bottom: 1.25rem; 82 | } 83 | 84 | @media (--laptop) { 85 | border-bottom: 1px solid cc(border); 86 | } 87 | } 88 | 89 | &__author { 90 | @extend %ff--500; 91 | text-decoration: underline; 92 | } 93 | 94 | &__sep { 95 | display: block; 96 | height: .625rem; 97 | 98 | @media (--laptop) { 99 | display: inline-block; 100 | margin: 0 .5rem; 101 | 102 | &::before { 103 | content: '—'; 104 | } 105 | } 106 | } 107 | 108 | &__subtitle { 109 | @extend %txt--subtitle; 110 | flex-grow: 1; 111 | display: flex; 112 | flex-direction: column; 113 | justify-content: center; 114 | padding: 0 2.5rem 1.25rem 2.5rem; 115 | 116 | @media (--tablet) { 117 | padding-top: 1.25rem; 118 | } 119 | 120 | @media (--laptop) { 121 | padding-right: 7.5rem; 122 | } 123 | } 124 | 125 | &__body { 126 | padding: 1.25rem 1.25rem 3.75rem; 127 | border-bottom: 1px solid cc(border); 128 | 129 | @media (--laptop) { 130 | padding: 0 1.25rem 2.5rem; 131 | } 132 | } 133 | 134 | &__footer { 135 | margin-top: 3.75rem; 136 | padding: 0 1.25rem; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/sass/blocks/_preview.scss: -------------------------------------------------------------------------------- 1 | .preview { 2 | position: relative; 3 | margin: 1.25rem 1.25rem 5rem; 4 | z-index: 0; 5 | @include imagePlaceholder; 6 | 7 | @media (--tablet) { 8 | width: calc(50% - 2.5rem); 9 | margin: 1.25rem 1.25rem 2.5rem; 10 | } 11 | 12 | @media (--laptop) { 13 | width: calc(100% / 3 - 2.5rem); 14 | } 15 | 16 | @media (--desktop) { 17 | width: calc(100% / 3 - 5rem); 18 | margin: 1rem; 19 | } 20 | 21 | &-move { transition: all 550ms cb() } 22 | &-enter-active { transition: all 325ms cb(out) 175ms } 23 | &-appear-enter-active { transition: all 275ms cb(out) 200ms } 24 | 25 | &-leave-active { 26 | transition: all 225ms cb(in); 27 | position: absolute; 28 | z-index: -1; 29 | } 30 | 31 | &-enter, 32 | &-leave-to, 33 | &-appear-enter { 34 | opacity: 0; 35 | transform: translate3d(0, -2.5rem, 0); 36 | } 37 | 38 | &__figure { 39 | position: relative; 40 | padding-top: 140%; 41 | transition: padding-top 275ms cb(out); 42 | @include bgCover; 43 | 44 | &::before { 45 | content: ''; 46 | position: absolute; 47 | top: 0; 48 | left: 0; 49 | width: 100%; 50 | height: 33%; 51 | background-image: linear-gradient(to bottom, cc(shadow, .33), transparent); 52 | } 53 | 54 | &--mobile { 55 | padding-top: 90%; 56 | } 57 | } 58 | 59 | &__details { 60 | position: absolute; 61 | top: 0; 62 | left: 0; 63 | width: 100%; 64 | height: 100%; 65 | } 66 | 67 | &__title { 68 | @extend %txt--preview; 69 | display: block; 70 | height: 100%; 71 | padding: .75rem; 72 | color: cc(txt, inv); 73 | background-color: cc(shadow, 0); 74 | transition: background-color 225ms cb(); 75 | 76 | .preview__figure--mobile &, 77 | &:hover { 78 | background-color: cc(shadow, .65); 79 | } 80 | 81 | @media (--monitor) { 82 | padding-right: 1.5rem; 83 | } 84 | } 85 | 86 | &__meta { 87 | position: absolute; 88 | top: 100%; 89 | left: 0; 90 | padding: .5rem 0; 91 | font-size: .9rem; 92 | 93 | @media (--tablet) { 94 | white-space: nowrap; 95 | } 96 | } 97 | 98 | &__published::after { 99 | content: 'by'; 100 | padding: 0 .25rem; 101 | } 102 | 103 | &__author { 104 | @extend %ff--500; 105 | text-decoration: underline; 106 | white-space: nowrap; 107 | font-size: .9rem; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/sass/blocks/_rte.scss: -------------------------------------------------------------------------------- 1 | .rte { 2 | @extend %txt--rte; 3 | 4 | p + p { 5 | margin-top: 1em; 6 | } 7 | 8 | a:hover, 9 | a:hover * { 10 | text-decoration: underline; 11 | } 12 | 13 | h3, 14 | h4 { 15 | margin: 1.25em 0 .75em; 16 | } 17 | 18 | em { 19 | font-style: italic; 20 | } 21 | 22 | strong { 23 | @extend %ff--500; 24 | } 25 | 26 | em strong, 27 | strong em { 28 | @extend %ff--500; 29 | font-style: italic; 30 | } 31 | 32 | ul { 33 | margin-top: 1.5em; 34 | margin-bottom: .75em; 35 | 36 | li { 37 | position: relative; 38 | padding-left: 1.5em; 39 | 40 | &::before { 41 | content: ''; 42 | display: inline-block; 43 | position: absolute; 44 | top: .4em; 45 | left: 0; 46 | width: .2em; 47 | height: .2em; 48 | border-radius: 100%; 49 | bacground-color: cc(accent); 50 | } 51 | 52 | & + li { 53 | margin-top: .5em; 54 | } 55 | } 56 | } 57 | 58 | figure { 59 | text-align: center; 60 | margin: 2.25em 0; 61 | } 62 | 63 | figcaption { 64 | font-size: 14px; 65 | text-align: center; 66 | font-style: italic; 67 | } 68 | 69 | img { 70 | display: inline-block; 71 | max-width: 100%; 72 | } 73 | 74 | iframe { 75 | max-width: 100%; 76 | } 77 | 78 | address { 79 | display: inline-block; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/sass/blocks/_v-transitions.scss: -------------------------------------------------------------------------------- 1 | .v { 2 | &--fade { 3 | &-enter-active, 4 | &-leave-active { transition: all 275ms cb() } 5 | 6 | &-enter, 7 | &-leave-to { opacity: 0 } 8 | 9 | &-leave, 10 | &-enter-to { opacity: 1 } 11 | } 12 | 13 | &--mask { 14 | &-enter-active, 15 | &-leave-active { transition: all 150ms cb() 500ms } 16 | 17 | &-enter, 18 | &-leave-to { opacity: 0 } 19 | 20 | &-leave, 21 | &-enter-to { opacity: 1 } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/sass/tools/_colors.scss: -------------------------------------------------------------------------------- 1 | // colors 2 | $ghost-white: #fcfdff; 3 | $mystic: #dae4eb; 4 | $gunmetal: #2a3744; 5 | $smoky-black: #0a0908; 6 | 7 | // cc map 8 | $colors:( 9 | default:( 10 | bg: $ghost-white, 11 | txt: $smoky-black, 12 | primary: $gunmetal, 13 | border: $mystic, 14 | shadow: $smoky-black, 15 | overlay: $gunmetal, 16 | selection: rgba($gunmetal, .33) 17 | ), 18 | 19 | alt:( 20 | txt: $gunmetal, 21 | bg: $mystic, 22 | border: $gunmetal 23 | ), 24 | 25 | inv:( 26 | txt: $ghost-white 27 | ) 28 | ); 29 | -------------------------------------------------------------------------------- /src/sass/tools/_easings.scss: -------------------------------------------------------------------------------- 1 | $easings:( 2 | default: cubic-bezier(.4, .25, .3, 1), 3 | in: cubic-bezier(.6, .1, .8, .7), 4 | out: cubic-bezier(.2, .3, .4, .9), 5 | in-out: cubic-bezier(.5, .15, .4, 1), 6 | bounce: cubic-bezier(.4, .25, .3, 1.4) 7 | ); 8 | -------------------------------------------------------------------------------- /src/sass/tools/_functions.scss: -------------------------------------------------------------------------------- 1 | // cubic-bezier 2 | @function cb($fn: default) { 3 | @return map-get($easings, $fn); 4 | } 5 | 6 | // em 7 | @function em($pixels, $context: 16) { 8 | @return #{$pixels/$context}em; 9 | } 10 | 11 | // color-control 12 | @function cc($color, $option: false, $alpha: false) { 13 | $opacity: null; 14 | $palette: null; 15 | 16 | @if ($alpha) {$opacity: $alpha;} 17 | @else {$opacity: if(type-of($option) == 'number', $option, false);} 18 | 19 | @if ($option) {$palette: if(type-of($option) == 'number', default, $option);} 20 | @else {$palette: default;} 21 | 22 | $getPalette: map-get($colors, $palette); 23 | 24 | @return if($opacity, rgba(map-get($getPalette, $color), $opacity), map-get($getPalette, $color)); 25 | } 26 | -------------------------------------------------------------------------------- /src/sass/tools/_mediaqueries.scss: -------------------------------------------------------------------------------- 1 | @custom-media --phone only screen and (max-width: #{em(567)}); 2 | @custom-media --tablet only screen and (min-width: #{em(568)}); 3 | @custom-media --mobile only screen and (max-width: #{em(1024)}); 4 | @custom-media --laptop only screen and (min-width: #{em(1025)}); 5 | @custom-media --desktop only screen and (min-width: #{em(1280)}); 6 | @custom-media --monitor only screen and (min-width: #{em(1448)}); 7 | -------------------------------------------------------------------------------- /src/sass/tools/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin imagePlaceholder() { 2 | background-image: linear-gradient( 3 | to bottom, 4 | rgba(#162229, .75), 5 | rgba(#064362, .75), 6 | rgba(#6f868c, .75), 7 | rgba(#673c28, .75) 8 | ); 9 | } 10 | 11 | @mixin bgCover($_pos:center) { 12 | background-size: cover; 13 | background-repeat: no-repeat; 14 | background-position: $_pos; 15 | } 16 | -------------------------------------------------------------------------------- /src/startup.js: -------------------------------------------------------------------------------- 1 | import Pace from 'pace-progress' 2 | 3 | // pace progress bar 4 | Pace.start() 5 | 6 | // use pace hook to know when rendering is ready 7 | Pace.once('hide', () => { 8 | window.prerenderReady = true 9 | }) 10 | 11 | // Spektrum Media console message 12 | console.info('%c', 'line-height:48px;padding:18px 150px;background:url(\'https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/vue-snip.svg\') center / contain no-repeat;') 13 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/static/.gitkeep -------------------------------------------------------------------------------- /static/api/blog.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "title": "Vue Blog Cosmic JS", 4 | "post_label": "Exit reading mode", 5 | "author_label": "View all Posts" 6 | }] 7 | } 8 | -------------------------------------------------------------------------------- /static/api/feed.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "title": "neque libero convallis eget", 4 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/karl-magnuson.jpg", 5 | "published": "2017-09-14T18:17:00Z", 6 | "author": "Michelle Blackford", 7 | "id": "neque-libero-convallis-eget" 8 | }, { 9 | "title": "sit amet erat", 10 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/etienne-bosiger.jpg", 11 | "published": "2017-09-09T22:11:56Z", 12 | "author": "Nathan Greave", 13 | "id": "sit-amet-erat" 14 | }, { 15 | "title": "posuere cubilia", 16 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/saksham-gangwar.jpg", 17 | "published": "2017-09-05T00:55:44Z", 18 | "author": "Hugo Curness", 19 | "id": "posuere-cubilia" 20 | }, { 21 | "title": "consequat ut nulla", 22 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/mona-eendra.jpg", 23 | "published": "2017-07-28T18:31:01Z", 24 | "author": "Derrik Yerrington", 25 | "id": "consequat-ut-nulla" 26 | }, { 27 | "title": "curabitur gravida nisi", 28 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/adam-krowitz.jpg", 29 | "published": "2017-06-12T10:01:51Z", 30 | "author": "Michelle Blackford", 31 | "id": "curabitur-gravida-nisi" 32 | }, { 33 | "title": "pretium nisl", 34 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/steven-pahel.jpg", 35 | "published": "2017-06-02T03:22:11Z", 36 | "author": "Nathan Greave", 37 | "id": "pretium-nisl" 38 | }, { 39 | "title": "vivamus tortor duis mattis", 40 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/simone-hutsch.jpg", 41 | "published": "2017-05-27T00:05:26Z", 42 | "author": "Tommi Filipson", 43 | "id": "vivamus-tortor-duis-mattis" 44 | }, { 45 | "title": "potenti cras in purus", 46 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/casey-horner.jpg", 47 | "published": "2017-05-25T13:12:39Z", 48 | "author": "Nathan Greave", 49 | "id": "potenti-cras-in-purus" 50 | }, { 51 | "title": "ultrices mattis odio", 52 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/nate-rayfield.jpg", 53 | "published": "2017-05-10T13:57:35Z", 54 | "author": "Nathan Greave", 55 | "id": "ultrices-mattis-odio" 56 | }, { 57 | "title": "nunc commodo placerat", 58 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/kimon-maritz.jpg", 59 | "published": "2017-04-12T09:43:53Z", 60 | "author": "Nathan Greave", 61 | "id": "nunc-commodo-placerat" 62 | }, { 63 | "title": "sit amet diam in", 64 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/shalom-mwenesi.jpg", 65 | "published": "2017-04-03T22:21:22Z", 66 | "author": "Derrik Yerrington", 67 | "id": "sit-amet-diam-in" 68 | }, { 69 | "title": "sapien ut nunc", 70 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/robson-hatsukami-morgan.jpg", 71 | "published": "2017-03-10T21:11:06Z", 72 | "author": "Derrik Yerrington", 73 | "id": "sapien-ut-nunc" 74 | }, { 75 | "title": "ut massa quis augue", 76 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/tom-barrett.jpg", 77 | "published": "2016-12-15T23:29:56Z", 78 | "author": "Nathan Greave", 79 | "id": "ut-massa-quis-augue" 80 | }, { 81 | "title": "lacinia eget tincidunt", 82 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/joshua-hibbert.jpg", 83 | "published": "2016-11-02T02:21:18Z", 84 | "author": "Martha Bonde", 85 | "id": "lacinia-eget-tincidunt" 86 | }, { 87 | "title": "dolor quis", 88 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/maarten-van-den-heuvel.jpg", 89 | "published": "2016-10-27T09:42:32Z", 90 | "author": "Tommi Filipson", 91 | "id": "dolor-quis" 92 | }] 93 | } 94 | -------------------------------------------------------------------------------- /static/api/post/consequat-ut-nulla.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "consequat-ut-nulla", 4 | "title": "consequat ut nulla", 5 | "content": "Etiam vel augue. Vestibulum rutrum rutrum neque. Aenean auctor gravida sem.\n\nPraesent id massa id nisl venenatis lacinia. Aenean sit amet justo. Morbi ut odio.\n\nCras mi pede, malesuada in, imperdiet et, commodo vulputate, justo. In blandit ultrices enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n\nProin interdum mauris non ligula pellentesque ultrices. Phasellus id sapien in sapien iaculis congue. Vivamus metus arcu, adipiscing molestie, hendrerit at, vulputate vitae, nisl.\n\nAenean lectus. Pellentesque eget nunc. Donec quis orci eget orci vehicula condimentum.\n\nCurabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/mona-eendra.jpg", 7 | "meta": { 8 | "description": "Fusce posuere felis sed lacus. Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.", 9 | "published": "2017-07-28T18:31:01Z", 10 | "author": "Derrik Yerrington" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/curabitur-gravida-nisi.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "curabitur-gravida-nisi", 4 | "title": "curabitur gravida nisi", 5 | "content": "Sed ante. Vivamus tortor. Duis mattis egestas metus.\n\nAenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.\n\nQuisque id justo sit amet sapien dignissim vestibulum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est. Donec odio justo, sollicitudin ut, suscipit a, feugiat et, eros.\n\nVestibulum ac est lacinia nisi venenatis tristique. Fusce congue, diam id ornare imperdiet, sapien urna pretium nisl, ut volutpat sapien arcu sed augue. Aliquam erat volutpat.\n\nIn congue. Etiam justo. Etiam pretium iaculis justo.\n\nIn hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/adam-krowitz.jpg", 7 | "meta": { 8 | "description": "Proin at turpis a pede posuere nonummy. Integer non velit. Donec diam neque, vestibulum eget, vulputate ut, ultrices vel, augue.", 9 | "published": "2017-06-12T10:01:51Z", 10 | "author": "Michelle Blackford" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/dolor-quis.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "dolor-quis", 4 | "title": "dolor quis", 5 | "content": "Morbi porttitor lorem id ligula. Suspendisse ornare consequat lectus. In est risus, auctor sed, tristique in, tempus sit amet, sem.\n\nFusce consequat. Nulla nisl. Nunc nisl.\n\nDuis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus. Duis at velit eu est congue elementum.\n\nIn hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/kimon-maritz.jpg", 7 | "meta": { 8 | "description": "Nunc nisl. Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus.", 9 | "published": "2017-04-12T09:43:53Z", 10 | "author": "Nathan Greave" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/lacinia-eget-tincidunt.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "lacinia-eget-tincidunt", 4 | "title": "lacinia eget tincidunt", 5 | "content": "Aliquam quis turpis eget elit sodales scelerisque. Mauris sit amet eros. Suspendisse accumsan tortor quis turpis.\n\nSed ante. Vivamus tortor. Duis mattis egestas metus.\n\nAenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.\n\nQuisque id justo sit amet sapien dignissim vestibulum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est. Donec odio justo, sollicitudin ut, suscipit a, feugiat et, eros.\n\nVestibulum ac est lacinia nisi venenatis tristique. Fusce congue, diam id ornare imperdiet, sapien urna pretium nisl, ut volutpat sapien arcu sed augue. Aliquam erat volutpat.\n\nIn congue. Etiam justo. Etiam pretium iaculis justo.\n\nIn hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.\n\nNulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/joshua-hibbert.jpg", 7 | "meta": { 8 | "description": "Nam dui. Proin leo odio, porttitor id, consequat in, consequat ut, nulla.", 9 | "published": "2016-11-02T02:21:18Z", 10 | "author": "Martha Bonde" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/neque-libero-convallis-eget.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "neque-libero-convallis-eget", 4 | "title": "neque libero convallis eget", 5 | "content": "In hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo.\n\nAliquam quis turpis eget elit sodales scelerisque. Mauris sit amet eros. Suspendisse accumsan tortor quis turpis.\n\nSed ante. Vivamus tortor. Duis mattis egestas metus.\n\nAenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/karl-magnuson.jpg", 7 | "meta": { 8 | "description": "Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.", 9 | "published": "2017-09-14T18:17:00Z", 10 | "author": "Michelle Blackford" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/nunc-commodo-placerat.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "nunc-commodo-placerat", 4 | "title": "nunc commodo placerat", 5 | "content": "In sagittis dui vel nisl. Duis ac nibh. Fusce lacus purus, aliquet at, feugiat non, pretium quis, lectus.\n\nSuspendisse potenti. In eleifend quam a odio. In hac habitasse platea dictumst.\n\nMaecenas ut massa quis augue luctus tincidunt. Nulla mollis molestie lorem. Quisque ut erat.\n\nCurabitur gravida nisi at nibh. In hac habitasse platea dictumst. Aliquam augue quam, sollicitudin vitae, consectetuer eget, rutrum at, lorem.\n\nInteger tincidunt ante vel ipsum. Praesent blandit lacinia erat. Vestibulum sed magna at nunc commodo placerat.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/robson-hatsukami-morgan.jpg", 7 | "meta": { 8 | "description": "Morbi non quam nec dui luctus rutrum. Nulla tellus. In sagittis dui vel nisl.", 9 | "published": "2017-03-10T21:11:06Z", 10 | "author": "Derrik Yerrington" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/posuere-cubilia.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "posuere-cubilia", 4 | "title": "posuere cubilia", 5 | "content": "Sed sagittis. Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci. Nullam molestie nibh in lectus.\n\nPellentesque at nulla. Suspendisse potenti. Cras in purus eu magna vulputate luctus.\n\nCum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus vestibulum sagittis sapien. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.\n\nEtiam vel augue. Vestibulum rutrum rutrum neque. Aenean auctor gravida sem.\n\nPraesent id massa id nisl venenatis lacinia. Aenean sit amet justo. Morbi ut odio.\n\nCras mi pede, malesuada in, imperdiet et, commodo vulputate, justo. In blandit ultrices enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/saksham-gangwar.jpg", 7 | "meta": { 8 | "description": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin risus.", 9 | "published": "2017-09-05T00:55:44Z", 10 | "author": "Hugo Curness" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/potenti-cras-in-purus.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "potenti-cras-in-purus", 4 | "title": "potenti cras in purus", 5 | "content": "Sed ante. Vivamus tortor. Duis mattis egestas metus.\n\nAenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.\n\nQuisque id justo sit amet sapien dignissim vestibulum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est. Donec odio justo, sollicitudin ut, suscipit a, feugiat et, eros.\n\nVestibulum ac est lacinia nisi venenatis tristique. Fusce congue, diam id ornare imperdiet, sapien urna pretium nisl, ut volutpat sapien arcu sed augue. Aliquam erat volutpat.\n\nIn congue. Etiam justo. Etiam pretium iaculis justo.\n\nIn hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.\n\nNulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/casey-horner.jpg", 7 | "meta": { 8 | "description": "Proin interdum mauris non ligula pellentesque ultrices. Phasellus id sapien in sapien iaculis congue.", 9 | "published": "2017-05-25T13:12:39Z", 10 | "author": "Nathan Greave" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/pretium-nisl.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "pretium-nisl", 4 | "title": "pretium nisl", 5 | "content": "Nulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi.\n\nCras non velit nec nisi vulputate nonummy. Maecenas tincidunt lacus at velit. Vivamus vel nulla eget eros elementum pellentesque.\n\nQuisque porta volutpat erat. Quisque erat eros, viverra eget, congue eget, semper rutrum, nulla. Nunc purus.\n\nPhasellus in felis. Donec semper sapien a libero. Nam dui.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/steven-pahel.jpg", 7 | "meta": { 8 | "description": "Nullam varius. Nulla facilisi. Cras non velit nec nisi vulputate nonummy.", 9 | "published": "2017-06-02T03:22:11Z", 10 | "author": "Nathan Greave" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/sapien-ut-nunc.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "sapien-ut-nunc", 4 | "title": "sapien ut nunc", 5 | "content": "Proin interdum mauris non ligula pellentesque ultrices. Phasellus id sapien in sapien iaculis congue. Vivamus metus arcu, adipiscing molestie, hendrerit at, vulputate vitae, nisl.\n\nAenean lectus. Pellentesque eget nunc. Donec quis orci eget orci vehicula condimentum.\n\nCurabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.\n\nPhasellus sit amet erat. Nulla tempus. Vivamus in felis eu sapien cursus vestibulum.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/maarten-van-den-heuvel.jpg", 7 | "meta": { 8 | "description": "Morbi vel lectus in quam fringilla rhoncus. Mauris enim leo, rhoncus sed, vestibulum sit amet, cursus id, turpis. Integer aliquet, massa id lobortis convallis.", 9 | "published": "2016-10-27T09:42:32Z", 10 | "author": "Tommi Filipson" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/sit-amet-diam-in.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "sit-amet-diam-in", 4 | "title": "sit amet diam in", 5 | "content": "Nullam porttitor lacus at turpis. Donec posuere metus vitae ipsum. Aliquam non mauris.\n\nMorbi non lectus. Aliquam sit amet diam in magna bibendum imperdiet. Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis.\n\nFusce posuere felis sed lacus. Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.\n\nSed sagittis. Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci. Nullam molestie nibh in lectus.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/shalom-mwenesi.jpg", 7 | "meta": { 8 | "description": "Praesent id massa id nisl venenatis lacinia. Aenean sit amet justo. Morbi ut odio.", 9 | "published": "2017-04-03T22:21:22Z", 10 | "author": "Derrik Yerrington" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/sit-amet-erat.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "sit-amet-erat", 4 | "title": "sit amet erat", 5 | "content": "Maecenas tristique, est et tempus semper, est quam pharetra magna, ac consequat metus sapien ut nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris viverra diam vitae quam. Suspendisse potenti.\n\nNullam porttitor lacus at turpis. Donec posuere metus vitae ipsum. Aliquam non mauris.\n\nMorbi non lectus. Aliquam sit amet diam in magna bibendum imperdiet. Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis.\n\nFusce posuere felis sed lacus. Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.\n\nSed sagittis. Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci. Nullam molestie nibh in lectus.\n\nPellentesque at nulla. Suspendisse potenti. Cras in purus eu magna vulputate luctus.\n\nCum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus vestibulum sagittis sapien. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/etienne-bosiger.jpg", 7 | "meta": { 8 | "description": "Nulla facilisi. Cras non velit nec nisi vulputate nonummy. Maecenas tincidunt lacus at velit.", 9 | "published": "2017-09-09T22:11:56Z", 10 | "author": "Nathan Greave" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/ultrices-mattis-odio.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "ultrices-mattis-odio", 4 | "title": "ultrices mattis odio", 5 | "content": "Aenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.\n\nQuisque id justo sit amet sapien dignissim vestibulum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est. Donec odio justo, sollicitudin ut, suscipit a, feugiat et, eros.\n\nVestibulum ac est lacinia nisi venenatis tristique. Fusce congue, diam id ornare imperdiet, sapien urna pretium nisl, ut volutpat sapien arcu sed augue. Aliquam erat volutpat.\n\nIn congue. Etiam justo. Etiam pretium iaculis justo.\n\nIn hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/nate-rayfield.jpg", 7 | "meta": { 8 | "description": "Proin at turpis a pede posuere nonummy. Integer non velit.", 9 | "published": "2017-05-10T13:57:35Z", 10 | "author": "Nathan Greave" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/ut-massa-quis-augue.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "ut-massa-quis-augue", 4 | "title": "ut massa quis augue", 5 | "content": "Praesent id massa id nisl venenatis lacinia. Aenean sit amet justo. Morbi ut odio.\n\nCras mi pede, malesuada in, imperdiet et, commodo vulputate, justo. In blandit ultrices enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n\nProin interdum mauris non ligula pellentesque ultrices. Phasellus id sapien in sapien iaculis congue. Vivamus metus arcu, adipiscing molestie, hendrerit at, vulputate vitae, nisl.\n\nAenean lectus. Pellentesque eget nunc. Donec quis orci eget orci vehicula condimentum.\n\nCurabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.\n\nPhasellus sit amet erat. Nulla tempus. Vivamus in felis eu sapien cursus vestibulum.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/tom-barrett.jpg", 7 | "meta": { 8 | "description": "Praesent blandit lacinia erat. Vestibulum sed magna at nunc commodo placerat. Praesent blandit.", 9 | "published": "2016-12-15T23:29:56Z", 10 | "author": "Nathan Greave" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/api/post/vivamus-tortor-duis-mattis.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "id": "vivamus-tortor-duis-mattis", 4 | "title": "vivamus tortor duis mattis", 5 | "content": "Sed ante. Vivamus tortor. Duis mattis egestas metus.\n\nAenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.\n\nQuisque id justo sit amet sapien dignissim vestibulum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est. Donec odio justo, sollicitudin ut, suscipit a, feugiat et, eros.\n\nVestibulum ac est lacinia nisi venenatis tristique. Fusce congue, diam id ornare imperdiet, sapien urna pretium nisl, ut volutpat sapien arcu sed augue. Aliquam erat volutpat.\n\nIn congue. Etiam justo. Etiam pretium iaculis justo.\n\nIn hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.\n\nNulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi.", 6 | "image": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/450744/simone-hutsch.jpg", 7 | "meta": { 8 | "description": "Vivamus vestibulum sagittis sapien. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", 9 | "published": "2017-05-27T00:05:26Z", 10 | "author": "Tommi Filipson" 11 | } 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /static/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/static/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /static/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/static/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /static/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/static/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /static/icons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #408c71 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/static/icons/favicon-16x16.png -------------------------------------------------------------------------------- /static/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/static/icons/favicon-32x32.png -------------------------------------------------------------------------------- /static/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/static/icons/favicon.ico -------------------------------------------------------------------------------- /static/icons/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Vue Proto", 3 | "icons": [ 4 | { 5 | "src": "/static/icons/android-chrome-192x192.png", 6 | "sizes": "192x192", 7 | "type": "image/png" 8 | }, 9 | { 10 | "src": "/static/icons/android-chrome-512x512.png", 11 | "sizes": "512x512", 12 | "type": "image/png" 13 | } 14 | ], 15 | "theme_color": "#408c71", 16 | "background_color": "#408c71", 17 | "display": "standalone" 18 | } -------------------------------------------------------------------------------- /static/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/vue-blog-netlify-template/ac6baef822974cfe2f88e54b16e7b653077965d3/static/icons/mstile-150x150.png -------------------------------------------------------------------------------- /static/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 82 | 83 | 84 | --------------------------------------------------------------------------------