A blog theme for VuePress by Ktquez π€π€
Vuepress does not yet have native support for blogs, but this theme has some practices and customizations to turn into a blog.
I know the theme configuration seems like a lot of work though, I've created a boilerplate with the settings and structure of folders organized, just clone the repository and change the information for your blog, modify the images and start using.
https://github.com/ktquez/vuepress-theme-ktquez-starter
npm install -S vuepress-theme-ktquez
The theme customization is done through the .vuepress/config.js
For your reference, you can see the config.js of my blog.
module.exports = {
theme: 'ktquez',
...
locales: { // Example with multiple locales, but usually works only with a single locale
'/': {
lang: 'en'
},
'/pt/': {
lang: 'pt-br'
},
'/es/': {
lang: 'es'
}
},
themeConfig: // example below
configureWebpack () {
return {
resolve: {
alias: {
'@public': path.join(__dirname, './public')
}
}
}
}
}
themeConfig: {
locales: {
'/': {
languages: { // Used in the drop down of languages
label: 'English',
shortname: 'EN'
},
translation: {}, // Look for the "translations section" below
logo: {
name: 'MY_LOGO_FILENAME',
ext: 'png',
alt: 'My description about logo'
},
share: {
facebookCaption: 'MY_CAPTION_FB_SHARE',
twitterVia: 'MY_TWITTER_NICKNAME'
},
newsletter: {
provider: 'mailchimp', // Currently supports mailchimp
action: 'link_form_action_mailchimp'
},
copy: '2018 Β© Ktquez play - <a href="https://vuepress.vuejs.org/" rel="noopener" target="_blank"> MADE WITH VUEPRESS </a>',
footer: {
nav1: {
title: 'NAVIGATION 1',
items: [
{
label: 'ABOUT',
path: '/about/' // Use "link" for external links and "path" for internal links
},
...
]
},
nav2: {
title: 'NAVIGATION 2',
items: [
{
label: 'Slack Group',
link: 'https://my_group.slack.com/' // Use "link" for external links and "path" for internal links
},
...
]
}
},
social: [
{
name: 'twitter', // Look for the "social icon section" below
link: 'https://www.twitter.com/ktquez'
},
...
]
},
'/pt/': {
languages: { // Used in the drop down of languages
label: 'Portuguese',
shortname: 'PT'
},
... // the rest of the properties of this locale are the same as the example above, but with information for that language
},
'/es/': ...
},
disqus: 'MY_DISQUS_SHORTNAME',
url: 'https://my_doamin.com',
cdn: '', // If there is a CDN, put the bucket link here.
blackWhite: true, // Active toggle for Nocturne mode
topNavigation: true, // Turn on the navigation menu above the header
searchMaxSuggestions: 7, // Maximum result per search
responsive: {
active: true, // Turn on responsive images on the cover of the post
ext: 'png',
breakpoints: [320, 427, 524, 680] // Breakpoints used for picture media tag
},
share: {
facebook: { appId: '', version: 'v3.1' }
},
elevator: { duration: 4000, mainAudio: '/music/elevator.mp3', endAudio: '/music/ding.mp3' }
},
The texts that are in the theme are translated and currently the theme has included the translations for EN
andPT
, any other language you will use, just add the key: value
in the translation property that the theme will do rest for you.
themeConfig: {
locales: {
'/es/': {
languages: { label: 'Spanish', shortname: 'ES' },
translation: {
back: 'AtrΓ‘s',
home: 'Home',
author: 'Autor',
...
}
},
'/fr/': {
languages: { label: 'French', shortname: 'FR' },
translation: {
back: 'arrière',
home: 'Page d\'accueil',
author: 'auteur',
...
}
}
}
}
For you to see all the key: value
used in the theme, just access this example
To make the newsletter form appear, simply add the action of your newsletter.
themeConfig: {
locales: {
...
'/': {
...
newsletter: {
provider: 'mailchimp',
action: 'MY_ACTION_FOR_ENGLISH_USERS'
},
},
'/pt/': {
...
newsletter: {
provider: 'mailchimp',
action: '' // Does not display the form if you leave an empty string
}
}
}
...
}
To improve UX and performance, the blog supports responsive images through breakpoints.
themeConfig: {
...
responsive: {
active: true, // Turn on responsive images on the cover of the post
ext: 'png',
breakpoints: [320, 427, 524, 680] // Breakpoints used for picture media tag
},
...
}
With the example above, you need to insert the images with the final ,w_XXX
, for example:
If your post is: /posts/my-first-post.md
Your images should be in public/images/posts/__YEAR__/__MONTH__/
and with the following sizes:
public/images/posts/2018/8/my-first-post,w_320.png
public/images/posts/2018/8/my-first-post,w_427.png
public/images/posts/2018/8/my-first-post,w_524.png
public/images/posts/2018/8/my-first-post,w_680.png
public/images/posts/2018/8/my-first-post.png
If you don't want to use responsive images, simply disable and to use public/images/posts/2018/8/my-first-post.png
βββ .vuepress
βββ index.md
βββ about/
| βββ README.md
βββ contact/
| βββ README.md
βββ categories/
| βββ README.md
| βββ category1.md
| βββ category2.md
βββ posts/
| βββ README.md
| βββ my-first-post.md
βββ pt/
| βββ index.md
| βββ sobre/
| | βββ README.md
| βββ contato/
| | βββ README.md
| βββ categorias
| | βββ README.md
| | βββ categoria1.md
| | βββ categoria2.md
| βββ posts/
| | βββ README.md
| | βββ meu-primeiro-post.md
βββ es/
...
There are key: value
in translations of routes, if you do not have your language or want to rename, just add in translation translation
---
view: home
title: my title
description: my description
meta:
- property: og:image
content: https://my_domain.com/share/my-site-image-share.png
- name: twitter:image
content: https://my_domain.com/share/my-site-image-share.png
---
---
view: post
layout: post
lang: pt-br # Lang by locale of post (required)
author: ktquez # Nickname author
title: My First post
description:
excerpt:
cover: true # If true it displays the cover image of the post, if it has no image, leave it as false
coverExt: # If you want to specify the image extension, PNG is the default
coverAlt: # cover alt text
demo: # If you have demo link, insert here, to display the demo demo button in post
categories:
- vuejs # slug of category
- javascript
tags:
- tag1 # You may feel free to create tags, it will be used on the category page
- tag2
- tag3
created_at: 2018-08-22 11:00
updated_at: 2018-08-22 11:00
meta:
- property: og:image
content: https://my_domain.com/images/posts/my-first-post.png
- name: twitter:image
content: https://my_domain/images/posts/my-first-post.png
---
For more examples, just see the posts of Ktquez play
---
view: category
lang: pt-br # Lang by locale of post (required)
order: 1 # Order of display in list categories
top: true # Include category in navigation Top
title: Vue.js
description:
excerpt:
slug: vuejs # Used in post yaml for the array of categories
---
---
view: author
lang: pt-br # Lang by locale of post (required)
title: Articles by Alan Ktquez
description:
name: Alan Ktquez
nickname: ktquez # Used in post yaml to indicate the author
role: Web developer
avatar: /authors/avatar_author.png
created_at: 2018-08-22
social:
- name: twitter
url: https://twitter.com/author
- name: github
url: https://github.com/author
- name: site
url: https://author_site.com
meta:
- property: og:image
content: https://my_domain.com/authors/avatar_author.png
- name: twitter:image
content: https://my_domain.com/authors/avatar_author.png
---
---
view: page
title:
description:
excerpt:
ctaContact: true # Show call-to-action to contact page. If there is no contact page, set it to false
---
To overwrite the theme variables to customize colors and etc, simply create a file in .vuepress/override.styl
, por exemplo:
$primaryColor = #AE4967
$accentColor = #35495E
$color1 = #41b883
$colorImageFallback = $accentColor
$firstFooterColor = #35495E
$secondFooterColor = #263647
To see all the variables, access this link
The theme uses some plugins from the Vue A11y project
In addition to good practices such as:
It is possible to delay media loading using the global component
In any markdown files you can to use this component, for example load a Youtube video
<lazy-load tag="iframe" :data="{ src: 'https://www.youtube.com/watch?v=lIv1ItUzktc' }" />
Or for images:
<lazy-load tag="img" :data="{ src: 'https://octodex.github.com/images/stormtroopocat.jpg', alt: 'The Stormtroopocat' }" />
This component uses the IntersectionObserver API to display the elements. You can check this link for support of this API
If you want to use and support older browsers, you can use this polyfill
All posts sharing icons links are included in analytics campaign parameters.
?utm_source=SOCIALNAMECLICKED&utm_medium=share&utm_campaign=single-post
With this you can analyze the interaction and shares of your posts.
The theme have as fonts:
To overwrite the fonts, simply use the
.vuepress/style.styl
. Ver doc vuepress
This theme adopts the strategy to load Web fonts using FontFaceObserver
You can copy some assets from the public folder of the theme, they server for you to configure some images as well as files to turn your blog into a PWA (for example the file manifest.json).
You can also insert ads in the blog, which are displayed in the sidebar of the home page and the right side of the post. Ads are built through an array of objects that we can insert into each themeConfig locale, example taken from my personal blog
For example:
themeConfig: {
locales: {
...
'/': {
...
ads: [
{
text: 'Did you know that Udemy has more than 300 web development courses for only R $ 21.99?',
link: 'http://bit.ly/web-development-udemy',
image: {
src: '/web-development-english.png',
alt: 'Illustration of a user studying online'
},
by: {
text: 'udemy.com',
link: 'http://bit.ly/all-courses-udemy'
}
}
],
},
'/pt/': {
...
ads: [
{
text: 'VocΓͺ sabia que a Udemy tem mais de 300 cursos de desenvolvimento web por apenas R$ 21,99?',
link: 'http://bit.ly/desenvolvimento-web-em-portugues-udemy',
image: {
src: '/web-development-portugues.png',
alt: 'Ilustração de um usuÑrio estudando online'
},
by: {
text: 'udemy.com',
link: 'http://bit.ly/all-courses-udemy'
}
}
]
}
}
...
}
Note, avoid placing words that indicate that it is an ad, to avoid blocking Adblock
Tools that can help you:
If you want a faster communication, find me on @ktquez
Thank you