lumen-cms
v0.0.2
Published
Module for a cms based on Nuxt and GraphQl
Downloads
5
Readme
nuxtjs/lumen-cms
Module for a cms based on Nuxt and GraphQl
Lumen CMS
NodeJS | Vue 2.x | NuxtJs | Vuetify | GraphQl - graph.cool
Motivation
This project aims to combine very popular open-source projects and a solid managed backend service of graph.cool. It is API-Driven and extendable with graphql schema definition. Due to the nature of NuxtJs and the powerful modularization concept it extends your NuxtJs project with a fully-featured CMS. As a component framework Vuetify is included and brings Google Material Design specification out of the box. It offers best practices for SEO combined with a lot of performance optimization for the website render process.
Features
- Content management system
- Google Analytics integration
- Sitemap generator
- 301 Redirects
- SEO optimized
- SSR-rendered SPA feel of static website
- Imageproxy (CDN + scale/crop)
- Lazy-loading
- Responsive images
- Fontloader
- In-Page-Editing
- Multi-Language
- Multi-Domain
- Configurable
- 95%+ on GooglePageSpeed
Technology stack
- NodeJS (https://nodejs.org)
- Vue 2.x (https://vuejs.org/)
- NuxtJs (https://nuxtjs.org/)
- Vuetify (https://vuetifyjs.com)
- GraphQL managed backend by graph.cool (https://graph.cool/)
- Apollo (https://www.apollographql.com/client/, https://github.com/Akryum/vue-apollo)
- Vue-i18n (https://kazupon.github.io/vue-i18n/en/)
- Fast deplyoment with zeit.co/now (https://zeit.co/now)
Requirement
- NodeJS v >=8 (check out https://nuxtjs.org dependencies)
- NPM/Yarn
- GraphQL endpoint (https://graph.cool) You need a graph.cool endpoint and backend. Head over to lumen-graphcool to install and deploy your backend.
Installation
New project
Make use of the vue-cli starter-template
$ vue init lumen-cms/starter-template my-project
$ cd my-project
# install dependencies
$ npm install # Or yarn install
# open localhost:3000/admin to proceed with login
Existing project
- Add
nuxtjs/lumen-cms
dependency using yarn or npm to your project - Add
lumen-cms
tomodules
section ofnuxt.config.js
npm i lumen-cms --save
// nuxt.config.js
export default = {
// check out https://github.com/lumen-cms/lumen-graphcool to set it up
env:{
GRAPHQL_PROJECT_ID: '[Project ID]',
GRAPHQL_SUBSCRIPTION: '[SUBSCRIPTION]'
},
modules: [
'lumen-cms' // add lumen-cms module
],
// customize settings
'lumen-cms':{
// here comes your configuration
}
First Start
- Visit http://localhost:3000/admin and register a user
- Visit your graphcool backend and add
Moderator/Admin
role to the user - Now you can log in and start a very basic installation (http://localhost:3000/installation)
* your installation respects the languages array and create for each locale one default root page
- keep in mind: every language starts with the "/[locale]" slug
- you can configure canonical tags or any custom behaviour for multi-language websites => After successful installation will be redirected to the root of your website and you can start adding content
Pages
Lumen CMS provides admin interfaces and render entry points for your top-level article/page schema. Below is the list and routePath of all pre-configured routes. Make sure that these paths does not collide with any of your NuxtJs pages setup. All of the pages are accessible through the Admin-Bar
Root - Index.vue (routePath "/any/path")
Catches all requests and renders the schema Article
based on the slug. The slug can be any slug as
- /simple-slug
- /directory/slug/deep/nested
- On Error / Not found
- try to find a 301 => redirect
- render 404 if no article found
- render 500 if any error occurs
Important: make sure you don't provide any index.vue file inside your
pages
folder otherwise the CMS won't be able to render the content.
Admin (routePath: '/admin')
Login/Sign Up for the website administration. After successful login you get forwarded to the root of your website. In case of sign up a new user: you have to enable a permission role (Admin|Moderator) to the user in your graph.cool console interface.
Install (routePath: '/admin/install')
Creates the root page/entry point for each locale you provide in your configuration:
'lumen-cms':{
cms:{
languages:['en','de','it','fr'] // => install would create all 4 articles with a basic content element as a starter
}
}
Article-Admin (routePath: '/admin/article-admin'
Datatable lists all articles and you can view/edit it. The Footer shows a language switch to change the locale for your listing.
Article-Edit (routePath: '/admin/article-edit/:id?')
Creates/updates the article schema. You can either click on the edit inside of the Admin-Bar
or inside of the Article Admin
to reach the edit page.
Page-Templates (routePath: '/admin/page-templates')
Overview over all page templates. Page templates is vue-rendered
content you can specify inside of footer/header/sidebars/toolbars. Basically it holds generic content which should be displayed in static parts of the layout.
Redirects (routePath: '/admin/redirects')
Datatable lists all redirects in case you moved pages/paths to a different location
Article/Blog list (routePath: '/blog|articles')
Configurable alias path to render an article list.
'lumen-cms':{
cms:{
routes: {
// map locale to each routes.path
listMapLocale: {
articles: 'en',
blog: 'de'
},
// all available path alias for the article list
list: ['articles', 'blog']
}
}
}
Admin-Bar
On logged in you will see on the bottom left corner a floating speed-dial button this action menu buttons:
- Logout
- Media Gallery (only visible if content edit mode is ON)
- Redirects
- Blog admin list
- Page templates
- Content-Edit-Mode toggle
- Add new article
- Edit article
Use Admin-Bar
You can include the LcAdminBar
into your own template. You can enable add
or edit
action and the toggle for content-edit
:
<lc-admin-bar v-if="$store.getters.canEdit"
:edit-route="{name: 'articleEdit', params: {id: $store.state.lc.pageProps.articleId}}"
:add-route="{name:'articleEdit'}"
:content-edit-toggle="true"/>
Customize Admin-Bar
Add links into the Admin-Bar panel
'lumen-cms':{
// overwrite the entire widget
component:{
edit:{
LcAdminBar: '~/component/yourCustomAdminBar.vue'
}
},
cms:{
// add some link(s) to the admin bar
adminBarLinks:[{
title: 'Some custom page',
to: {name: 'customPageRouteName'},
color: 'yellow darken-2', // any color variant
icon: 'code' //material icon name
}]
}
}
Configuration
You can customize your website bundle in several ways:
lumen-cms
configuration options from the nuxt.config.js fileWebpack alias
to provide a custom file and replace the default
Options
[disableCSS] - Boolean (default: false)
Disable the CSS import and manualy add it with stylus
'lumen-cms':{
disableCSS: true
}
css: [
{src: '~assets/style/app.styl', lang: 'styl'}
]
@import '~lumen-cms/lib/templates/assets/style/vuetify-imports.styl'
$themeprimary = #ff6f00
$themeaccent = #ffc400
$themesecondary = $grey.darken-3
$themeinfo = $light-blue.darken-1
$themewarning = $orange.darken-1
$themeerror = $red.darken-1
$themesuccess = $light-green.darken-1
@import '~lumen-cms/lib/templates/assets/style/imports.styl'
[fonts] - Object (default: roboto)
Modify fonts of Google to get loading with fontloader API
fonts:{montserrat: 'Montserrat:thin,extra-light,light,100,200,300,400,500,600,700,800'}
h1, h2, h3 {
font-family: 'Montserrat'
}
[components] - Object (default: empty)
Overwrite build-in components by provide a custom component path. All components are prefixed with Lc
ComponentName. Components are loaded as asynchronous and are devided in four sections: core|layout|view|edit
.
[pages] - Object (default: empty)
Overwrite built-in pages by provide a custom page path. Following pages are provided. Provide a pages
object with the exact name and custom path to overwrite the default:
pages:{
admin: resolve(__dirname, './templates/pages/admin.vue'),
install: resolve(__dirname, './templates/pages/install.vue'),
articleAdmin: resolve(__dirname, './templates/pages/articleAdmin.vue'),
articleEdit: resolve(__dirname, './templates/pages/articleEdit.vue'),
pageTemplates: resolve(__dirname, './templates/pages/pageTemplates.vue'),
redirects: resolve(__dirname, './templates/pages/redirects.vue',
articleList: resolve(__dirname, './templates/pages/articleList.vue'),
index: resolve(__dirname, './templates/pages/index.vue')
}
// in case you want to overwrite articleList page
pages:{
articleList: '~/pages/customArticleList.vue'
}
[cms] - Object
The cms
config object is getting injected into the context of your app (https://nuxtjs.org/guide/plugins#inject-in-root-amp-context).
Vuex
- actions asthis.app.$cms
- Vue Components as
this.$cms
- Check out all options
cms:{
pageToolbarExtension: false,
Head:{
site_name: 'Your domain',
}
}
Data Schema
The backend is configured to fit most website usecases. The main top-level schema is called Article, its the main schema for all pages/articles. The difference between a page and article is marginal - you can change it with a switch and its made to differenciate inside of the content list widget.
Article - View
- holds the top level schema
- can hold many content elements
- Taxonomy with
ArticleCategory
- Add a media image to show a picture in
ListWidget
-lists languageKey
is important to represent the locale of the contentslug
has to be unique * locale is always the root of a landing page (en
for english,de
for german) * you can pass in directivesparent/my/subpage
- every string will get slugified
* no leading slashes - no
.html
endings needed (they will get redirected automatically) * there is no locale directive as/en/any-page
|/de/german-page
needed due to uniqness of the slug
- every string will get slugified
* no leading slashes - no
ArticleCategory - View
- categorization/taxonomy/tagging for each article
Author - View
- basic author schema
Content - View
- holds the content element schema for any content element
- extandable through
- properties JSON
- styles JSON
File - View
- graph.cool internal file schema
FileReference - View
- holds the reference to each file via media browser
FileTag - View
- categorization/taxonomy/tagging for each file
Media - View
- media image for preview images of articles
PageTemplate - View
- holds generic content for different and global layout positions
- toolbars
- navigation drawer
- footer
- configurable
UrlAlias (301 redirects) - View
- 301 in case of renamed paths/slugs
User - View
- graph.cool internal user schema for authentication
Content Elements
All content elments can be added/edited for each article. Lumen CMS ships 5 content elements while each of them is
customizable through stylesheets and properties. The most common element is LcTextImage
which has many configuration option and fit many usecases. You can overwrite either the content element with providing a custom path or create custom elements and add them to your project read more.
Text with image (LcTextImage
)
- Header (h1 - h6)
- Text (enabled richt text editor from QuillJs)
- Image(s) as gallery or single
- Parallax/Jumbotron/Fixed-Background effect
- Flexible arrangement
- Highly customizable through styles
- "Component-Pre-Set" as a collection of class names can be defined or added to the defaults
Divider (LcDivider
)
- Recognizes google material icons
- Different sizing
- Colorization
- Border widths
Layout (LcLayout
)
- Tabs
- Columns - Parralax/Jumbotron/Fixed-Background images
- Slider
- Expansion-panel => holds as many content elmements inside each row/column
List Widget (LcListWidget
)
- List of articles
- Different list styles
- Filter based on taxonomy
Read more accordion (LcReadMore
)
- Teaser text (richt text)
- Body text (rich text)
Customize content elements and layout
There are two ways of customizing your website render. Either you overwrite an existing component or you want to create a new custom content element or you extend the current content elements
Overwrite components
Overwrite existing components with keeping the exact name and pass a new path. Keep the same group and componentName and webpack will bundle your customized file instead of the default file.
components: {
layout: {
LcLanguageSwitch: '~/components/overwrites/LanguageSwitch.vue',
LcMainFooter: '~/components/overwrites/MainFooter.vue'
},
view: {
LcArticleList: '~/components/overwrites/ArticleList.vue',
LcListWidget: '~/components/overwrites/ListWidget.js'
}
}
Extend content elements
Every content element needs a unique component name. It should be UpperCamelCase and inside the componentMapping it takes the prefix LC
. Example: LcCustomComponentName
. To extend the default elements two options needs to get passed: a new componentMapping declaration and the edit and view component files.
'lumen-cms':{
components:{
view:{
LcCustomComponent: '~/component/MyCustomComponent.vue' // must match componentMapping view
},
edit:{
LcCustomComponentEdit: '~/component/MyCustomComponentEdit.vue' // must match componentMapping name
}
},
cms:{
componentMapping:{
'CustomComponent':{
name: 'lc-custom-component-edit', // component to render the edit dialog
icon: 'material-icon', // shows the icon in the bottom bar
text: 'My custom component', // readable component title
view: 'lc-custom-component' // component to render the view
}
}
}
}
Custom Webpack Alias
To extend/overwrite the default behaviour there are following paths to overwrite the default functionality. Following is a complete example to extend your Webpack config with all available path alias.
- Pass file with predefinedStyles
- Customize GQL main schema files to fits your needs
- Three hooks are available to customize the output of your render:
- initialAsync Data
Returns
locale
,host
andslug
to process further website render - getCanonical In case you want to render a canonical tag
- getMeta Default meta data as robots or google-site-verification in case you have multi-domain setup.
// nuxt.config.js
build:{
extend(config){
// extend pre-defined content element options
config.resolve.alias['~predefinedStyles'] = '~/customPath/predefinedStyles.js' // array of pre-defined custom layout
// gql schema and mutation files for top level schemas
config.resolve.alias['~updateArticle'] = '~/customPath/updateArticle.gql' // in case you customized article
config.resolve.alias['~createArticle'] = '~/customPath/createArticle.gql' // in case you customized article
config.resolve.alias['~extendedArticleFragment'] = '~/customPath/extendedArticleFragment.gql' // in case you customized article
config.resolve.alias['~createMedia'] = '~/customPath/createMedia.gql' // in case you need to add media in some other schemas
// hooks for initial data render
config.resolve.alias['~initialAsyncData'] = '~/customPath/initialAsyncData.js' // initial render of asyncData
config.resolve.alias['~getCanonical'] = '~/customPath/getCanonical.js' // receive canonical tag
config.resolve.alias['~getMeta'] = '~/customPath/getMeta.js' // get default head meta
}
}
Deploy
With https://zeit.now the deploy of your Lumen CMS is as simple as typing:
$ npm i now -g
$ cd pathOfProject
$ now
To connect the now deployment with your custom domain head over to the documentation Sidenote: you need at least a premium account due to the size of the website bundle.
Websites built with Lumen CMS
- https://planet.training
- https://www.studentsgoabroad.com | https://www.studentsgoabroad.org
Contribute
- Clone this repository
- Install dependencies using
yarn install
ornpm install
- Start development server using
npm run dev
License
Copyright (c) Dominic Garms [email protected]