commit
b297d33675
@ -0,0 +1,6 @@ |
||||
*.log |
||||
.cache |
||||
.DS_Store |
||||
src/.temp |
||||
node_modules |
||||
dist |
@ -0,0 +1,21 @@ |
||||
MIT License |
||||
|
||||
Copyright (c) 2019 Yashu Mittal |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -0,0 +1,15 @@ |
||||
 |
||||
|
||||
This starter is a [casper](https://demo.ghost.io/) based theme built using [Gridsome](https://gridsome.org/). |
||||
|
||||
## Deploy |
||||
|
||||
To deploy the website, click the deploy button. |
||||
|
||||
[](https://app.netlify.com/start/deploy?repository=https://gitlab.com/mittalyashu/gridsome-starter-casper) |
||||
|
||||
## Donate |
||||
|
||||
I've put a lot of time and effort into making **Gridsome Starter Casper** project. If you love it, you can Become a Patron. I promise it will be a good investment ๐. |
||||
|
||||
[](https://www.patreon.com/bePatron?u=8494594) |
@ -0,0 +1,31 @@ |
||||
--- |
||||
title: Welcome to Gridsome |
||||
date: 2018-12-08 20:08:08 -0700 |
||||
slug: welcome |
||||
image: '/images/welcome-to-gridsome.jpg' |
||||
tags: getting-started |
||||
author: ['mittalyashu'] |
||||
--- |
||||
|
||||
|
||||
|
||||
๐ Welcome, it's great to have you here. |
||||
|
||||
We know that first impressions are important, so we've populated your new site with some initial **getting started** posts that will help you get familiar with everything in no time. This is the first one! |
||||
|
||||
**A few things you should know upfront**: |
||||
|
||||
1. Ghost is designed for ambitious, professional publishers who want to actively build a business around their content. That's who it works best for. |
||||
2. The entire platform can be modified and customised to suit your needs. It's very powerful, but does require some knowledge of code. Ghost is not necessarily a good platform for beginners or people who just want a simple personal blog. |
||||
3. For the best experience we recommend downloading the Ghost Desktop App for your computer, which is the best way to access your Ghost site on a desktop device. |
||||
|
||||
Ghost is made by an independent non-profit organisation called the Ghost Foundation. We are 100% self funded by revenue from our Ghost(Pro) service, and every penny we make is re-invested into funding further development of free, open source technology for modern publishing. |
||||
|
||||
The version of Ghost you are looking at right now would not have been made possible without generous contributions from the open source [community](https://github.com/TryGhost). |
||||
|
||||
## Next up, the editor |
||||
|
||||
The main thing you'll want to read about next is probably: [the Ghost editor](/the-editor). This is where the good stuff happens. |
||||
|
||||
> By the way, once you're done reading, you can simply delete the default **Ghost** user from your team to remove all of these introductory posts! |
||||
|
@ -0,0 +1,12 @@ |
||||
--- |
||||
title: Publishing options |
||||
date: 2018-12-10 20:08:08 -0700 |
||||
slug: publishing-options |
||||
image: '' |
||||
tags: publish |
||||
author: ['mittalyashu', 'john'] |
||||
--- |
||||
|
||||
Customise your social media sharing cards for Facebook and Twitter, enabling you to add custom images, titles and descriptions for social media. |
||||
|
||||
Thereโs no need to hard code your meta data. You can set your meta title and description using the post settings tool, which has a handy character guide and SERP preview. |
@ -0,0 +1,11 @@ |
||||
--- |
||||
title: Managing admin settings |
||||
date: 2018-12-11 20:08:08 -0700 |
||||
slug: admin-settings |
||||
image: '/images/admin-settings.jpg' |
||||
tags: getting-started |
||||
author: ['gridsome'] |
||||
--- |
||||
|
||||
Make your site private |
||||
If you've got a publication that you don't want the world to see yet because it's not ready to launch, you can hide your Ghost site behind a basic shared pass-phrase. |
@ -0,0 +1,23 @@ |
||||
site: |
||||
title: Gridsome Casper |
||||
cover_image: '/images/blog-cover.jpg' |
||||
logo: '/images/gridsome-logo.png' |
||||
url: '/' |
||||
description: 'The professional publishing platform' |
||||
subscribers: true |
||||
navigation: true |
||||
|
||||
social_media: |
||||
facebook: 'gridsome' |
||||
twitter: 'gridsome' |
||||
patreon: 'mittalyashu' |
||||
|
||||
nav_home: |
||||
- title: Home |
||||
link: / |
||||
- title: About |
||||
link: /about |
||||
- title: Getting Started |
||||
link: /tag/getting-started/ |
||||
- title: Try Gridsome |
||||
link: https://www.gridsome.org/ |
@ -0,0 +1,10 @@ |
||||
--- |
||||
id: gridsome |
||||
name: Gridsome |
||||
image: /images/gridsome-logo.png |
||||
tagline: 'Static Site Generator' |
||||
bio: "We are a SSG a.k.a. Static site generator which use Vue.js at it's core." |
||||
location: World |
||||
website: https://gridsome.org/ |
||||
twitter: gridsome |
||||
--- |
@ -0,0 +1,8 @@ |
||||
--- |
||||
id: john |
||||
name: John O' Nolan |
||||
bio: 'I am the founder of Ghost foundation and we are doing a great job.' |
||||
location: Earth |
||||
twitter: john |
||||
facebook: john |
||||
--- |
@ -0,0 +1,10 @@ |
||||
--- |
||||
id: mittalyashu |
||||
name: Yashu Mittal |
||||
image: /images/mittalyashu.jpg |
||||
tagline: 'Open Source Developer' |
||||
bio: 'I am the Founder and CEO at CodeCarrot and open source developer.' |
||||
location: India |
||||
website: https://mittalyashu.now.sh/ |
||||
twitter: mittalyashu77 |
||||
--- |
@ -0,0 +1,40 @@ |
||||
module.exports = { |
||||
siteName: 'Gridsome Casper', |
||||
siteUrl: 'https://www.gridsome.org', |
||||
siteDescription: 'The professional publishing platform', |
||||
titleTemplate: `%s - Gridsome`, |
||||
|
||||
plugins: [ |
||||
{ |
||||
use: '@gridsome/plugin-google-analytics', |
||||
options: { |
||||
id: 'UA-XXXXXXXXX-X' |
||||
} |
||||
}, |
||||
{ |
||||
use: '@gridsome/source-filesystem', |
||||
options: { |
||||
path: 'blog/*.md', |
||||
typeName: 'Post', |
||||
route: '/:slug', |
||||
refs: { |
||||
author: 'Author', |
||||
tags: { |
||||
typeName: 'Tag', |
||||
route: '/tag/:title', |
||||
create: true |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
use: '@gridsome/source-filesystem', |
||||
options: { |
||||
// TODO Use yaml file as data source
|
||||
path: 'data/author/*.md', |
||||
typeName: 'Author', |
||||
route: '/author/:id' |
||||
} |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,3 @@ |
||||
[build] |
||||
publish = "dist" |
||||
command = "gridsome build" |
@ -0,0 +1,18 @@ |
||||
{ |
||||
"name": "snipette-gridsome", |
||||
"private": true, |
||||
"scripts": { |
||||
"build": "gridsome build", |
||||
"develop": "gridsome develop", |
||||
"explore": "gridsome explore" |
||||
}, |
||||
"dependencies": { |
||||
"@gridsome/plugin-google-analytics": "^0.1.0", |
||||
"@gridsome/source-filesystem": "^0.3.0", |
||||
"@gridsome/transformer-remark": "^0.2.0", |
||||
"gridsome": "^0.5.0", |
||||
"node-sass": "^4.11.0", |
||||
"sass-loader": "^7.1.0", |
||||
"vue-moment": "^4.0.0" |
||||
} |
||||
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,69 @@ |
||||
<template> |
||||
<article :class="articleClass"> |
||||
<a v-if="cardData.image" class="post-card-image-link" :href="cardData.path"> |
||||
<!-- FIXME Background size cover --> |
||||
<div class="post-card-image" :style="'background-image: url(' + cardData.image + ')'"></div> |
||||
</a> |
||||
<div class="post-card-content"> |
||||
<a class="post-card-content-link" :href="cardData.path"> |
||||
<header class="post-card-header"> |
||||
<span |
||||
v-if="cardData.tags" |
||||
class="post-card-tags" |
||||
>{{ cardData.tags.title.replace('-', ' ') }}</span> |
||||
<h2 class="post-card-title">{{ cardData.title }}</h2> |
||||
</header> |
||||
<section class="post-card-excerpt"> |
||||
<p>{{ cardData.content | stripHTML | truncate(190, '...') }}</p> |
||||
</section> |
||||
</a> |
||||
<footer class="post-card-meta"> |
||||
<ul class="author-list"> |
||||
<li v-for="author in cardData.author" class="author-list-item" :key="author.name"> |
||||
<div class="author-name-tooltip">{{ author.name }}</div> |
||||
<a v-if="author.image" :href="'/author/' + author.id" class="static-avatar"> |
||||
<img class="author-profile-image" :src="author.image" :alt="author.name" /> |
||||
</a> |
||||
<a v-else :href="'/author/' + author.id" class="static-avatar author-profile-image"> |
||||
<Avatar/> |
||||
</a> |
||||
</li> |
||||
</ul> |
||||
|
||||
<span class="reading-time">{{ cardData.timeToRead }} MIN READ</span> |
||||
</footer> |
||||
</div> |
||||
</article> |
||||
</template> |
||||
|
||||
<script> |
||||
import Avatar from "./icons/Avatar"; |
||||
|
||||
export default { |
||||
components: { |
||||
Avatar |
||||
}, |
||||
props: { |
||||
cardData: Object |
||||
}, |
||||
computed: { |
||||
articleClass() { |
||||
let classes = ["post-card", "post"]; |
||||
if (this.cardData.fields === null) { |
||||
classes.push("no-image"); |
||||
} |
||||
const cardTagClass = "post-" + this.cardData.tags; |
||||
classes.push(cardTagClass); |
||||
return classes; |
||||
} |
||||
}, |
||||
filters: { |
||||
truncate: (text, length, suffix) => { |
||||
return text.substring(0, length) + suffix; |
||||
}, |
||||
stripHTML: text => { |
||||
return text.replace(/<[^>]+>/g, '') |
||||
} |
||||
} |
||||
}; |
||||
</script> |
@ -0,0 +1,48 @@ |
||||
<template> |
||||
<div class="floating-header"> |
||||
<div class="floating-header-logo"> |
||||
<a href="/"> |
||||
<img v-if="Admin.site.logo" :src="Admin.site.logo" :alt="Admin.site.title + ' icon'" /> |
||||
<span>{{ Admin.site.title }}</span> |
||||
</a> |
||||
</div> |
||||
<span class="floating-header-divider">—</span> |
||||
<div class="floating-header-title">{{ title }}</div> |
||||
<div class="floating-header-share"> |
||||
<div class="floating-header-share-label">Share this <PointerIcon/></div> |
||||
<!-- TODO Add Twitter share link --> |
||||
<a class="floating-header-share-tw"> |
||||
<TwitterIcon/> |
||||
</a> |
||||
<!-- TODO Add Facebook share link --> |
||||
<a class="floating-header-share-fb"> |
||||
<FacebookIcon/> |
||||
</a> |
||||
</div> |
||||
<progress id="reading-progress" class="progress" value="0"> |
||||
<div class="progress-container"> |
||||
<span class="progress-bar"></span> |
||||
</div> |
||||
</progress> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import Admin from "../../data/admin.yml" |
||||
import PointerIcon from './icons/Pointer'; |
||||
import FacebookIcon from './icons/Facebook' |
||||
import TwitterIcon from './icons/Twitter' |
||||
|
||||
export default { |
||||
components: { |
||||
PointerIcon, |
||||
FacebookIcon, |
||||
TwitterIcon |
||||
}, |
||||
comments: { |
||||
Admin() { |
||||
return Admin |
||||
} |
||||
} |
||||
} |
||||
</script> |
@ -0,0 +1,29 @@ |
||||
<template> |
||||
<!-- The footer at the very bottom of the screen --> |
||||
<footer class="site-footer outer"> |
||||
<div class="site-footer-content inner"> |
||||
<section class="copyright"> |
||||
<a href="/">{{ Admin.site.title }}</a> © {{ new Date().getFullYear() }} |
||||
</section> |
||||
<nav class="site-footer-nav"> |
||||
<g-link to="/">Latest Posts</g-link> |
||||
<a v-if="Admin.social_media.facebook" :href="'https://facebook.com/' + Admin.social_media.facebook" target="_blank" rel="noopener">Facebook</a> |
||||
<a v-if="Admin.social_media.twitter" :href="'https://twitter.com/' + Admin.social_media.twitter" target="_blank" rel="noopener">Twitter</a> |
||||
<a v-if="Admin.social_media.patreon" :href="'https://www.patreon.com/' + Admin.social_media.patreon" target="_blank" rel="noopener">Become My Patron</a> |
||||
<a href="https://gridsome.org" target="_blank" rel="noopener">Gridsome</a> |
||||
</nav> |
||||
</div> |
||||
</footer> |
||||
</template> |
||||
|
||||
<script> |
||||
import Admin from '../../data/admin.yml' |
||||
|
||||
export default { |
||||
computed: { |
||||
Admin() { |
||||
return Admin |
||||
} |
||||
} |
||||
} |
||||
</script> |
@ -0,0 +1,90 @@ |
||||
<template> |
||||
<nav class="site-nav"> |
||||
<div class="site-nav-left"> |
||||
<div v-if="logo"> |
||||
<a v-if="Admin.site.logo" class="site-nav-logo" :href="Admin.site.url"> |
||||
<img :src="Admin.site.logo" :alt="Admin.site.title"> |
||||
</a> |
||||
<a v-else class="site-nav-logo" :href="Admin.site.url">{{ Admin.site.title }}</a> |
||||
</div> |
||||
<Navigation v-if="Admin.site.navigation"/> |
||||
</div> |
||||
<div class="site-nav-right"> |
||||
<div class="social-links"> |
||||
<a |
||||
v-if="Admin.social_media.patreon" |
||||
class="social-link social-link-p" |
||||
:href="'https://www.patreon.com/' + Admin.social_media.patreon" |
||||
title="Become My Patron" |
||||
target="_blank" |
||||
rel="noopener" |
||||
> |
||||
<Patreon/> |
||||
</a> |
||||
|
||||
<a |
||||
v-if="Admin.social_media.facebook" |
||||
class="social-link social-link-fb" |
||||
:href="'https://facebook.com/' + Admin.social_media.facebook" |
||||
title="Facebook" |
||||
target="_blank" |
||||
rel="noopener" |
||||
> |
||||
<Facebook/> |
||||
</a> |
||||
|
||||
<a |
||||
v-if="Admin.social_media.twitter" |
||||
class="social-link social-link-tw" |
||||
:href="'https://twitter.com/' + Admin.social_media.twitter" |
||||
title="Twitter" |
||||
target="_blank" |
||||
rel="noopener" |
||||
> |
||||
<Twitter/> |
||||
</a> |
||||
</div> |
||||
<a v-if="Admin.site.subscribers" class="subscribe-button" href="#subscribe">Subscribe</a> |
||||
<a v-else class="rss-button" href="/feed.xml" title="RSS" target="_blank" rel="noopener"> |
||||
<RSS/> |
||||
</a> |
||||
</div> |
||||
</nav> |
||||
</template> |
||||
|
||||
<script> |
||||
import Admin from "../../data/admin.yml"; |
||||
import Navigation from "./Navigation"; |
||||
|
||||
// Icons |
||||
import Facebook from "./icons/Facebook"; |
||||
import Twitter from "./icons/Twitter"; |
||||
import Patreon from "./icons/Patreon"; |
||||
import RSS from "./icons/RSS"; |
||||
|
||||
export default { |
||||
props: { |
||||
logo: { |
||||
type: Boolean, |
||||
default: false |
||||
} |
||||
}, |
||||
components: { |
||||
Navigation, |
||||
Patreon, |
||||
Facebook, |
||||
Twitter, |
||||
RSS |
||||
}, |
||||
computed: { |
||||
Admin() { |
||||
return Admin; |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="sass"> |
||||
.social-link > svg |
||||
width: 1.8rem |
||||
</style> |
@ -0,0 +1,19 @@ |
||||
<template> |
||||
<ul class="nav" role="menu"> |
||||
<li v-for="item in Admin.nav_home" :key="item.title" role="menuitem"> |
||||
<a :href="item.link">{{ item.title }}</a> |
||||
</li> |
||||
</ul> |
||||
</template> |
||||
|
||||
<script> |
||||
import Admin from '../../data/admin.yml' |
||||
|
||||
export default { |
||||
computed: { |
||||
Admin() { |
||||
return Admin |
||||
} |
||||
} |
||||
} |
||||
</script> |
@ -0,0 +1,126 @@ |
||||
<template> |
||||
<!-- Links to Previous/Next posts --> |
||||
<aside class="read-next outer"> |
||||
<div class="inner"> |
||||
<div class="read-next-feed"> |
||||
<article |
||||
class="read-next-card" |
||||
:style="'background-image: url(' + Admin.site.cover_image + ')'" |
||||
> |
||||
<header class="read-next-card-header"> |
||||
<small class="read-next-card-header-sitetitle">— {{ Admin.site.title }} —</small> |
||||
<h3 class="read-next-card-header-title"> |
||||
<a :href="'/tag/' + tag">{{ tag.replace('-', ' ') | capitalizeFilter }}</a> |
||||
</h3> |
||||
</header> |
||||
<div class="read-next-divider"> |
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> |
||||
<path |
||||
d="M13 14.5s2 3 5 3 5.5-2.463 5.5-5.5S21 6.5 18 6.5c-5 0-7 11-12 11C2.962 17.5.5 15.037.5 12S3 6.5 6 6.5s4.5 3.5 4.5 3.5" |
||||
></path> |
||||
</svg> |
||||
</div> |
||||
<div class="read-next-card-content"> |
||||
<ul> |
||||
<li v-for="post in posts" :key="post.node.id"> |
||||
<a :href="post.node.path">{{ post.node.title }}</a> |
||||
</li> |
||||
</ul> |
||||
</div> |
||||
<footer class="read-next-card-footer"> |
||||
<a :href="'/tag/' + this.tag">See all {{ posts.length }} posts โ</a> |
||||
</footer> |
||||
</article> |
||||
<Card |
||||
v-for="PreviousNexts in this.PreviousNexts" |
||||
:key="PreviousNexts.id" |
||||
:cardData="PreviousNexts" |
||||
/> |
||||
</div> |
||||
</div> |
||||
</aside> |
||||
</template> |
||||
|
||||
<script> |
||||
import Card from "./Card"; |
||||
import Admin from "../../data/admin.yml"; |
||||
import capitalizeFilter from "../filters/capitalize"; |
||||
|
||||
export default { |
||||
data() { |
||||
return { |
||||
currentPostId: this.id, |
||||
PreviousNexts: [] |
||||
}; |
||||
}, |
||||
props: { |
||||
id: { |
||||
type: String |
||||
}, |
||||
tag: { |
||||
type: String |
||||
}, |
||||
posts: { |
||||
type: Array |
||||
} |
||||
}, |
||||
components: { |
||||
Card |
||||
}, |
||||
filters: { |
||||
capitalizeFilter |
||||
}, |
||||
mounted() { |
||||
this.getPreviousNext(); |
||||
}, |
||||
computed: { |
||||
Admin() { |
||||
return Admin; |
||||
}, |
||||
tagPosts() { |
||||
const allTagPosts = this.$static.allTag.edges; |
||||
console.log(allTagPosts); |
||||
} |
||||
}, |
||||
methods: { |
||||
getPreviousNext() { |
||||
const allBlogs = this.$static.allPost.edges; |
||||
for (let i = 0; i < allBlogs.length; i++) { |
||||
if (allBlogs[i].node.id === this.currentPostId) { |
||||
if (i > 0) { |
||||
this.PreviousNexts.push(allBlogs[i - 1].node); |
||||
} |
||||
if (allBlogs.length > i) { |
||||
this.PreviousNexts.push(allBlogs[i + 1].node); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<static-query> |
||||
query Blog { |
||||
allPost(order: ASC) { |
||||
edges { |
||||
node { |
||||
id |
||||
title |
||||
path |
||||
tags { |
||||
title |
||||
} |
||||
image |
||||
author { |
||||
id |
||||
name |
||||
image |
||||
} |
||||
content |
||||
timeToRead |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</static-query> |
@ -0,0 +1,89 @@ |
||||
<template> |
||||
<footer class="post-full-footer"> |
||||
<section class="post-full-authors"> |
||||
<div class="post-full-authors-content"> |
||||
<p>This post was a collaboration between</p> |
||||
<p> |
||||
<!-- FIXME Add comma after first author --> |
||||
<a |
||||
v-for="author in author" |
||||
:key="author.name" |
||||
:href="'/author/' + author.id" |
||||
>{{ author.name }}</a> |
||||
</p> |
||||
</div> |
||||
|
||||
<ul class="author-list" v-on:mouseleave="hideAuthorCard"> |
||||
<!-- FIXME Appear only single card on hover --> |
||||
<li |
||||
v-on:mouseover="authorCardHovered = authorUsername" |
||||
v-for="author in author" |
||||
:key="author.name" |
||||
class="author-list-item" |
||||
> |
||||
<div :class="{'author-card': true, hovered: authorCardHovered === authorUsername }"> |
||||
<div class="basic-info"> |
||||
<img |
||||
v-if="author.image" |
||||
class="author-profile-image" |
||||
:src="author.image" |
||||
:alt="author.name" |
||||
> |
||||
<div v-else class="author-profile-image"> |
||||
<Avatar/> |
||||
</div> |
||||
|
||||
<h2>{{ author.name }}</h2> |
||||
</div> |
||||
|
||||
<div class="bio"> |
||||
<div v-if="author.bio"> |
||||
<p>{{ author.bio }}</p> |
||||
<p> |
||||
<a :href="'/author/' + author.id">More posts</a> |
||||
by {{ author.name }}. |
||||
</p> |
||||
</div> |
||||
<p v-else> |
||||
Read |
||||
<a :href="'/author/' + author.id">more posts</a> by this author. |
||||
</p> |
||||
</div> |
||||
</div> |
||||
|
||||
<a v-if="author.image" :href="'/author/' + author.id" class="moving-avatar"> |
||||
<img class="author-profile-image" :src="author.image" :alt="author.name"> |
||||
</a> |
||||
<a v-else :href="'/author/' + author.id" class="moving-avatar author-profile-image"> |
||||
<Avatar/> |
||||
</a> |
||||
</li> |
||||
</ul> |
||||
</section> |
||||
</footer> |
||||
</template> |
||||
|
||||
<script> |
||||
import Avatar from "./icons/Avatar"; |
||||
|
||||
export default { |
||||
data: () => { |
||||
return { |
||||
authorCardHovered: "" |
||||
}; |
||||
}, |
||||
props: { |
||||
author: Array |
||||
}, |
||||
components: { |
||||
Avatar |
||||
}, |
||||
methods: { |
||||
hideAuthorCard() { |
||||
setTimeout(() => { |
||||
this.authorCardHovered = ""; |
||||
}, 800); |
||||
} |
||||
} |
||||
}; |
||||
</script> |
@ -0,0 +1,41 @@ |
||||
<template> |
||||
<footer class="post-full-footer"> |
||||
<section class="author-card"> |
||||
<g-image v-if="authorData.image" class="author-profile-image" :src="authorData.image" :alt="authorData.name" /> |
||||
<span v-else class="avatar-wrapper"> |
||||
<Avatar /> |
||||
</span> |
||||
|
||||
<section class="author-card-content"> |
||||
<h4 class="author-card-name"> |
||||
<a :href="'/author/' + authorData.id"> |
||||
{{ authorData.name }} |
||||
</a> |
||||
</h4> |
||||
<p v-if="authorData.tagline">{{ authorData.tagline }}</p> |
||||
<p v-else>Read <a :href="'/author/' + authorData.id">more posts</a> by this author.</p> |
||||
</section> |
||||
</section> |
||||
<div class="post-full-footer-right"> |
||||
<a class="author-card-button" :href="'/author/' + authorData.id">Read More</a> |
||||
</div> |
||||
</footer> |
||||
</template> |
||||
|
||||
<script> |
||||
import Avatar from './icons/Avatar'; |
||||
|
||||
export default { |
||||
props: { |
||||
author: Array |
||||
}, |
||||
components: { |
||||
Avatar |
||||
}, |
||||
computed: { |
||||
authorData() { |
||||
return this.author[0] |
||||
} |
||||
} |
||||
} |
||||
</script> |
@ -0,0 +1,3 @@ |
||||
<template> |
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M3.513 18.998C4.749 15.504 8.082 13 12 13s7.251 2.504 8.487 5.998C18.47 21.442 15.417 23 12 23s-6.47-1.558-8.487-4.002zM12 12c2.21 0 4-2.79 4-5s-1.79-4-4-4-4 1.79-4 4 1.79 5 4 5z" fill="#FFF"/></g></svg> |
||||
</template> |
@ -0,0 +1,3 @@ |
||||
<template> |
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M19 6h5V0h-5c-3.86 0-7 3.14-7 7v3H8v6h4v16h6V16h5l1-6h-6V7c0-.542.458-1 1-1z"/></svg> |
||||
</template> |
@ -0,0 +1,3 @@ |
||||
<template> |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="96" viewBox="0 0 100 96"> <g fill-rule="evenodd"> <path d="M64.1102,0.1004 C44.259,0.1004 28.1086,16.2486 28.1086,36.0986 C28.1086,55.8884 44.259,71.989 64.1102,71.989 C83.9,71.989 100,55.8884 100,36.0986 C100,16.2486 83.9,0.1004 64.1102,0.1004"/> <polygon points=".012 95.988 17.59 95.988 17.59 .1 .012 .1"/> </g> </svg> |
||||
</template> |
@ -0,0 +1,3 @@ |
||||
<template> |
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M7.5 15.5V4a1.5 1.5 0 1 1 3 0v4.5h2a1 1 0 0 1 1 1h2a1 1 0 0 1 1 1H18a1.5 1.5 0 0 1 1.5 1.5v3.099c0 .929-.13 1.854-.385 2.748L17.5 23.5h-9c-1.5-2-5.417-8.673-5.417-8.673a1.2 1.2 0 0 1 1.76-1.605L7.5 15.5zm6-6v2m-3-3.5v3.5m6-1v2"/> </svg> |
||||
</template> |
@ -0,0 +1,3 @@ |
||||
<template> |
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="6.18" cy="17.82" r="2.18"/><path d="M4 4.44v2.83c7.03 0 12.73 5.7 12.73 12.73h2.83c0-8.59-6.97-15.56-15.56-15.56zm0 5.66v2.83c3.9 0 7.07 3.17 7.07 7.07h2.83c0-5.47-4.43-9.9-9.9-9.9z"/></svg> |
||||
</template> |
@ -0,0 +1,3 @@ |
||||
<template> |
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"/></svg> |
||||
</template> |
@ -0,0 +1,3 @@ |
||||
<template> |
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M23.5 11.957c0 6.375-5.163 11.544-11.532 11.544C5.599 23.5.5 18.125.5 11.75.5 5.542 5.37.758 11.505.511l.5-.011C18.374.5 23.5 5.582 23.5 11.957zM11.505.511c-6 6.5-6 14.98 0 22.98m1-22.98c6 6.5 6 14.977 0 22.977M2 17.479h20.063m-19.657-12h19.062m-20.968 6h22.938" stroke="#000" stroke-linejoin="round" stroke-miterlimit="10" fill="none"/></svg> |
||||
</template> |
@ -0,0 +1,22 @@ |
||||
<template> |
||||
<form method="post" action="/subscribe/" id="" class=""> |
||||
<div class="form-group"> |
||||
<input class="subscribe-email" type="email" name="email" :placeholder=placeholder> |
||||
</div> |
||||
|
||||
<button id="" class="" type="submit"> |
||||
<span>Subscribe</span> |
||||
</button> |
||||
</form> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
props: { |
||||
placeholder: { |
||||
type: String, |
||||
default: "youremail@example.com" |
||||
} |
||||
} |
||||
} |
||||
</script> |
After Width: | Height: | Size: 60 KiB |
@ -0,0 +1,4 @@ |
||||
export default value => { |
||||
console.log(value); |
||||
return value.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase()); |
||||
} |
@ -0,0 +1,8 @@ |
||||
export default string => { |
||||
let array = string.split(' ') |
||||
let capitalizeString = ''; |
||||
array.map(value => { |
||||
capitalizeString += value[0].toUpperCase() + value.substr(1) + ' ' |
||||
}) |
||||
return capitalizeString.trim(); |
||||
} |
@ -0,0 +1,41 @@ |
||||
<template> |
||||
<div class="site-wrapper"> |
||||
<!-- All the main content gets inserted here, index.vue, blogPost.vue, etc --> |
||||
<slot/> |
||||
|
||||
<!-- The footer at the very bottom of the screen --> |
||||
<Footer/> |
||||
|
||||
<!-- TODO Showing upon clicking the button --> |
||||
<!-- The big email subscribe modal content --> |
||||
<div v-if="Admin.site.subscribers" id="subscribe" class="subscribe-overlay"> |
||||
<a class="subscribe-overlay-close" href="#"></a> |
||||
<div class="subscribe-overlay-content"> |
||||
<img v-if="!Admin.site.logo" class="subscribe-overlay-logo" :src="Admin.site.logo" :alt="Admin.site.title" /> |
||||
<h1 class="subscribe-overlay-title">Subscribe to {{ Admin.site.title }}</h1> |
||||
<p class="subscribe-overlay-description">Stay up to date! Get all the latest & greatest posts delivered straight to your inbox</p> |
||||
<subscribeForm placeholder="youremail@example.com" /> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- TODO Add pagination --> |
||||
<!-- <script v-if="Admin.site.pagination" src=""></script> --> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import Footer from '../components/Footer'; |
||||
import Admin from '../../data/admin.yml'; |
||||
import subscribeForm from '../components/subscribeForm' |
||||
|
||||
export default { |
||||
components: { |
||||
Footer, subscribeForm |
||||
}, |
||||
computed: { |
||||
Admin() { |
||||
return Admin |
||||
} |
||||
} |
||||
} |
||||
</script> |
@ -0,0 +1,32 @@ |
||||
<template> |
||||
<Layout> |
||||
<header class="site-header outer"> |
||||
<div class="inner"> |
||||
<Navbar :logo="true"/> |
||||
</div> |
||||
</header> |
||||
<main id="site-main" class="site-main outer"> |
||||
<div class="inner"> |
||||
<slot/> |
||||
</div> |
||||
</main> |
||||
</Layout> |
||||
</template> |
||||
|
||||
<script> |
||||
import Navbar from "../components/Navbar"; |
||||
|
||||
export default { |
||||
metaInfo() { |
||||
return { |
||||
bodyAttrs: { |
||||
class: `page-template` |
||||
} |
||||
}; |
||||
}, |
||||
components: { |
||||
Navbar |
||||
} |
||||
}; |
||||
</script> |
||||
|
@ -0,0 +1,8 @@ |
||||
import '~/assets/css/style.scss' |
||||
import DefaultLayout from '~/layouts/Default.vue' |
||||
import moment from "vue-moment" |
||||
|
||||
export default Vue => { |
||||
Vue.component('Layout', DefaultLayout) |
||||
Vue.use(moment) |
||||
} |
@ -0,0 +1,51 @@ |
||||
<template> |
||||
<Page> |
||||
<article class="post-full post page" :class="pageClass"> |
||||
|
||||
<header class="post-full-header"> |
||||
<h1 class="post-full-title">About us</h1> |
||||
</header> |
||||
|
||||
<figure v-if="image" class="post-full-image"> |
||||
<g-image v-bind="image" src="" alt="" /> |
||||
</figure> |
||||
|
||||
<section class="post-full-content"> |
||||
<div class="post-content"> |
||||
<p>This is a Gridsome starter casper theme cloned from <a target="_blank" href="https://demo.ghost.io/">Casper</a>. I've put a lot of time and effort into making <strong>Gridsome Starter Casper</strong> project. If you love it, you can <a target="_blank" href="https://www.patreon.com/bePatron?u=8494594">Become a Patron</a>. I promise it will be a good investment ๐.</p> |
||||
</div> |
||||
</section> |
||||
|
||||
</article> |
||||
</Page> |
||||
</template> |
||||
|
||||
<script> |
||||
import Page from "../layouts/Page"; |
||||
|
||||
export default { |
||||
metaInfo() { |
||||
return { |
||||
title: 'About', |
||||
bodyAttrs: { |
||||
class: `page-about` |
||||
} |
||||
}; |
||||
}, |
||||
data() { |
||||
return { |
||||
image: '' |
||||
} |
||||
}, |
||||
computed: { |
||||
pageClass() { |
||||
if (this.image === '') { |
||||
return 'no-image' |
||||
} |
||||
} |
||||
}, |
||||
components: { |
||||
Page |
||||
} |
||||
}; |
||||
</script> |
@ -0,0 +1,88 @@ |
||||
<template> |
||||
<Layout> |
||||
<header :class=HeroBgClass :style=HeroBgImage> |
||||
<div class="inner"> |
||||
<div class="site-header-content"> |
||||
<h1 class="site-title"> |
||||
<img v-if="Admin.site.logo != ''" class="site-logo" :src="Admin.site.logo" :alt="Admin.site.title" /> |
||||
<p v-if="Admin.site.logo === ''"> |
||||
{{ Admin.site.title }} |
||||
</p> |
||||
</h1> |
||||
<h2 class="site-description">{{ Admin.site.description}}</h2> |
||||
</div> |
||||
<Navbar :logo=false /> |
||||
</div> |
||||
</header> |
||||
|
||||
<!-- The main content area --> |
||||
<main id="site-main" class="site-main outer"> |
||||
<div class="inner"> |
||||
<div class="post-feed"> |
||||
<Card v-for="{ node } in $page.allPost.edges" :key="node.id" :cardData="node" /> |
||||
</div> |
||||
</div> |
||||
</main> |
||||
</Layout> |
||||
</template> |
||||
|
||||
<script> |
||||
import Admin from '../../data/admin.yml'; |
||||
import Navbar from '../components/Navbar' |
||||
import Card from '../components/Card'; |
||||
|
||||
export default { |
||||
metaInfo: { |
||||
bodyAttrs: { |
||||
class: 'home-template' |
||||
} |
||||
}, |
||||
components: { |
||||
Navbar, Card |
||||
}, |
||||
computed: { |
||||
Admin() { |
||||
return Admin |
||||
}, |
||||
HeroBgImage() { |
||||
if (Admin.site.cover_image) { |
||||
return { |
||||
backgroundImage: 'url(' + Admin.site.cover_image + ')' |
||||
} |
||||
} |
||||
}, |
||||
HeroBgClass() { |
||||
if (Admin.site.cover_image) { |
||||
return 'site-header outer' |
||||
} else { |
||||
return 'site-header outer no-cover' |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<page-query> |
||||
query Home ($page: Int) { |
||||
allPost (page: $page, order: ASC) { |
||||
edges { |
||||
node { |
||||
id |
||||
title |
||||
path |
||||
tags { |
||||
title |
||||
} |
||||
image |
||||
content |
||||
author { |
||||
id |
||||
name |
||||
image |
||||
} |
||||
timeToRead |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</page-query> |
@ -0,0 +1,135 @@ |
||||
<template> |
||||
<Layout> |
||||
<header class="site-header outer no-image"> |
||||
<div class="inner"> |
||||
<Navbar :logo=true /> |
||||
<div class="site-header-content"> |
||||
<img v-if="$page.author.image" class="author-profile-image" :src="$page.author.image" :alt="$page.author.name" /> |
||||
<h1 class="site-title"> {{ $page.author.name }} </h1> |
||||
<h2 v-if="bio = true" class="author-bio">{{ $page.author.bio }}</h2> |
||||
<div class="author-meta"> |
||||
|
||||
<div v-if="location = true" class="author-location">{{ $page.author.location }} |
||||
<span class="bull">•</span> |
||||
</div> |
||||
|
||||
<div class="author-stats"> |
||||
{{ numberofPosts }} |
||||
<span class="bull">•</span> |
||||
</div> |
||||
|
||||
<a v-if="$page.author.website" class="social-link social-link-wb" :href="$page.author.website" target="_blank" rel="noopener"> |
||||
<WebsiteIcon /> |
||||
</a> |
||||
|
||||
<a v-if="$page.author.twitter" class="social-link social-link-tw" :href="'https://www.twitter.com/' + $page.author.twitter" target="_blank" rel="noopener"> |
||||
<TwitterIcon /> |
||||
</a> |
||||
|
||||
<a v-if="$page.author.facebook" class="social-link social-link-fb" :href="'https://www.facebook.com/' + $page.author.facebook" target="_blank" rel="noopener"> |
||||
<FacebookIcon /> |
||||
</a> |
||||
|
||||
<!-- NOTE Gridsome doesn't support RSS feed yet --> |
||||
<!-- <a class="social-link social-link-rss" href="" target="_blank" rel="noopener"> |
||||
<RSSIcon /> |
||||
</a> --> |
||||
|
||||
</div> |
||||
</div> |
||||
</div> |
||||
</header> |
||||
|
||||
<!-- The main content area --> |
||||
<main id="site-main" class="site-main outer"> |
||||
<div class="inner"> |
||||
|
||||
<div class="post-feed"> |
||||
<Card v-for="{ node } in $page.author.belongsTo.edges" :key="node.id" :cardData="node" /> |
||||
</div> |
||||
|
||||
</div> |
||||
</main> |
||||
|
||||
</Layout> |
||||
</template> |
||||
|
||||
<script> |
||||
// Components |
||||
import Navbar from '../components/Navbar'; |
||||
import Card from '../components/Card'; |
||||
|
||||
// Icons |
||||
import WebsiteIcon from '../components/icons/Website'; |
||||
import TwitterIcon from '../components/icons/Twitter'; |
||||
import FacebookIcon from '../components/icons/Facebook'; |
||||
import RSSIcon from '../components/icons/RSS'; |
||||
|
||||
import { Pager } from 'gridsome' |
||||
|
||||
export default { |
||||
metaInfo() { |
||||
return { |
||||
title: this.$page.author.name, |
||||
bodyAttrs: { |
||||
class: `author-template` |
||||
} |
||||
} |
||||
}, |
||||
components: { |
||||
// Components |
||||
Navbar, Card, |
||||
// Icons |
||||
WebsiteIcon, TwitterIcon, FacebookIcon, RSSIcon, Pager |
||||
}, |
||||
computed: { |
||||
numberofPosts() { |
||||
let count = this.$page.author.belongsTo.edges.length |
||||
if (count == 1) { |
||||
return `${count} post` |
||||
} else if (count >= 2) { |
||||
return `${count} posts` |
||||
} else { |
||||
return 'No posts' |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="css" scoped> |
||||
|
||||
</style> |
||||
|
||||
<page-query> |
||||
query Author ($id: String!) { |
||||
author (id: $id) { |
||||
name |
||||
image |
||||
bio |
||||
location |
||||
website |
||||
twitter |
||||
facebook |
||||
belongsTo { |
||||
edges { |
||||
node { |
||||
...on Post { |
||||
id |
||||
title |
||||
author { |
||||
id |
||||
name |
||||
image |
||||
} |
||||
path |
||||
image |
||||
content |
||||
timeToRead |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</page-query> |
@ -0,0 +1,128 @@ |
||||
<template> |
||||
<Layout> |
||||
<header class="site-header outer"> |
||||
<div class="inner"> |
||||
<Navbar :logo="true"/> |
||||
</div> |
||||
</header> |
||||
|
||||
<!-- <FloatingHeader/> --> |
||||
|
||||
<main id="site-main" class="site-main outer"> |
||||
<div class="inner"> |
||||
<article :class="postClass"> |
||||
<header class="post-full-header"> |
||||
<section class="post-full-meta"> |
||||
<time class="post-full-meta-date" :datetime="$page.post.date | moment('d, MMMM YYYY')">{{ $page.post.date | moment("d, MMMM YYYY") }}</time> |
||||
<span class="date-divider">/</span> |
||||
<a |
||||
:href="'/tag/' + $page.post.tags.title" |
||||
>{{ $page.post.tags.title.replace('-', ' ') }}</a> |
||||
</section> |
||||
<h1 class="post-full-title">{{ $page.post.title }}</h1> |
||||
</header> |
||||
|
||||
<figure v-if="$page.post.image" class="post-full-image"> |
||||
<g-image :src="$page.post.image" :alt="$page.post.title"/> |
||||
</figure> |
||||
|
||||
<section class="post-full-content"> |
||||
<div class="post-content" v-html="$page.post.content"></div> |
||||
</section> |
||||
|
||||
<!-- Email subscribe form at the bottom of the page --> |
||||
<section v-if="Admin.site.subscribers" class="subscribe-form"> |
||||
<h3 class="subscribe-form-title">Subscribe to {{ Admin.site.title }}</h3> |
||||
<p>Get the latest posts delivered right to your inbox</p> |
||||
<subscribeForm placeholder="youremail@example.com"/> |
||||
</section> |
||||
|
||||
<bylineMultiple :author="$page.post.author" v-if="$page.post.author.length > 1"/> |
||||
<bylineSingle :author="$page.post.author" v-else/> |
||||
|
||||
<!-- NOTE Comment section --> |
||||
<!-- <section class="post-full-comments"> |
||||
If you want to embed comments, this is a good place to do it! |
||||
</section>--> |
||||
</article> |
||||
</div> |
||||
</main> |
||||
|
||||
<PreviousNext :id="$page.post.id" :tag="$page.post.tags.title" :posts="$page.post.tags.belongsTo.edges"/> |
||||
</Layout> |
||||
</template> |
||||
|
||||
<script> |
||||
import Admin from "../../data/admin.yml"; |
||||
import Navbar from "../components/Navbar"; |
||||
import FloatingHeader from "../components/FloatingHeader"; |
||||
import subscribeForm from "../components/subscribeForm"; |
||||
import bylineMultiple from "../components/bylineMultiple"; |
||||
import bylineSingle from "../components/bylineSingle"; |
||||
import PreviousNext from "../components/PreviousNext"; |
||||
|
||||
export default { |
||||
metaInfo() { |
||||
return { |
||||
title: this.$page.post.title, |
||||
bodyAttrs: { |
||||
class: `post-template tag-${this.$page.post.tags.title}` |
||||
} |
||||
}; |
||||
}, |
||||
components: { |
||||
Navbar, |
||||
FloatingHeader, |
||||
subscribeForm, |
||||
bylineMultiple, |
||||
bylineSingle, |
||||
PreviousNext |
||||
}, |
||||
computed: { |
||||
Admin() { |
||||
return Admin; |
||||
}, |
||||
postClass() { |
||||
let classes = ["post-full", "post"]; |
||||
if (!this.$page.post.image) { |
||||
classes.push("no-image"); |
||||
} |
||||
const postTagClass = "tag-" + this.$page.post.tags.title; |
||||
classes.push(postTagClass); |
||||
return classes; |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
<page-query> |
||||
query BlogPost ($path: String!) { |
||||
post (path: $path) { |
||||
id |
||||
title |
||||
date |
||||
tags { |
||||
title |
||||
belongsTo { |
||||
edges { |
||||
node { |
||||
... on Post { |
||||
id |
||||
title |
||||
path |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
image |
||||
author { |
||||
id |
||||
name |
||||
image |
||||
tagline |
||||
bio |
||||
} |
||||
content |
||||
} |
||||
} |
||||
</page-query> |
@ -0,0 +1,88 @@ |
||||
<template> |
||||
<Layout> |
||||
<header class="site-header outer no-image"> |
||||
<div class="inner"> |
||||
<Navbar :logo="true"/> |
||||
<div class="site-header-content"> |
||||
<h1 class="site-title">{{ capitalize }}</h1> |
||||
<h2 class="site-description">A collection of {{ $page.tag.belongsTo.edges.length }} posts</h2> |
||||
</div> |
||||
</div> |
||||
</header> |
||||