Giter Club home page Giter Club logo

Comments (12)

bskimball avatar bskimball commented on May 28, 2024 12

@adam-lynch I ended up not using the blog-module, because I wanted to customize the templates and use vuex to store info about the posts. I did use the blog module as a base for what I was trying to do. I also used this article https://www.vuejsradar.com/static-vue-cms-part-3/ as well as look at the source code for nuxtent. I also use the markdownit module. I have been meaning to upload to github as an example for others.

Here is a basic summary:

nuxt.config.js

/**
 *  use node fs and slugify to generate the routes based off of the files in the top-level blog directory
 *  you can name the directory anything
 **/
...
  generate: {
    routes: function () {
      return require('fs').readdirSync('blog').map(function (file) {
        return '/blog/' + require('slugify')(file.replace(/\.md$/, ''))
      })
    }
  }
...

docs on generate can be found here --> https://nuxtjs.org/api/configuration-generate

Then in my vuex store, I do something similar with node on build so I can have access to the posts in my global store.

store/index.js

/**
 * the key here is to use if (process.server)
 * I'm also using front-matter to grab metadata from the markdown files
 **/
...
    actions: {
      nuxtServerInit () {
        if (process.server) {
          const fs = require('fs')
          const files = fs.readdirSync('blog')
          const posts = files.map((file) => {
            let post = fm(fs.readFileSync(`blog/${file}`, 'utf8'))
            post.filename = file
            post.created = new Date(fs.statSync(`blog/${file}`).ctime)
            post.slug = slugify(file.replace(/\.md$/, ''), {lower: true})
            post.url = `/blog/${post.slug}`
            return post
          })
          this.dispatch('loadPosts', posts)
        }
      },
      loadPosts ({commit}, posts) {
        const sorted = posts.sort((a, b) => {
          if (a === b) {
            return 0
          }
          return (a.created < b.created) ? 1 : -1
        })
        commit('updatePosts', sorted)
      },
      loadPost ({commit}, slug) {
        const post = this.state.posts.find((post) => {
          return post.slug === slug
        })
        commit('updatePost', post)
      }
    }
...

Because of the store and template integration it made more since to not use blog-module

finally, I have a template for the posts

pages/blog/_post.vue

<template>
    <el-row style="padding: 0 15%">
        <el-col>
            <base-page-title>{{post.attributes.title}}</base-page-title>
            <br>
            <small><i class="el-icon-date"></i> {{createdAt}}</small>
            <div v-html="postFile"></div>
        </el-col>
    </el-row>
</template>

<script>
    import {Col, Row} from 'element-ui'
    import {format} from 'date-fns'
    import BasePageTitle from '~/components/BasePageTitle'

    export default {
      components: {
        'el-row': Row,
        'el-col': Col,
        'base-page-title': BasePageTitle
      },
      fetch ({store, params}) {
        store.dispatch('loadPost', params.post)
      },
      head () {
        return {
          title: this.postTitle
        }
      },
      computed: {
        post () {
          return this.$store.getters.getPost
        },
        postFile () {
          if (this.post.filename) {
            return require(`~/blog/${this.post.filename}`)
          } else {
            return require('~/blog/not-found.md')
          }
        },
        createdAt () {
          return format(new Date(this.post.created), 'MMMM Do[,] YYYY')
        },
        postTitle () {
          return `Blog :: ${this.post.attributes.title}`
        }
      }
    }
</script>

I may have missed some parts but you should be able to get it figured out.

from blog-module.

bskimball avatar bskimball commented on May 28, 2024 2

@tcurdt I currently do not. I can try to put one up at some point.

I have changed my process a little bit, where I extracted the function that reads the markdown files from the directory called "content"

Right now my in my Vuex store I have

// store/index.js

function sortByPublished(a, b) {
  if (a === b) {
    return 0;
  }
  return a.attributes.published < b.attributes.published ? 1 : -1;
}

export const state = () => ({
  posts: [],
  post: {}
});

export const getters = {
  getPost: state => {
    return state.post;
  },
  allPosts: state => {
    const posts = state.posts.filter(post => post.slug !== "not-found");
    return posts.sort((a, b) => sortByPublished(a, b));
  }
};

export const mutations = {
  updatePosts(state, posts) {
    state.posts = posts;
  },
  updatePost(state, post) {
    state.post = post;
  }
};

export const actions = {
  nuxtServerInit() {
    if (process.server) {
      const markdownFromDirectory = require("../utils/markdownFromDirectory");
      this.dispatch("loadPosts", markdownFromDirectory("blog"));
    }
  },
  loadPosts({ commit }, posts) {
    commit("updatePosts", posts);
  },
  loadPost({ commit, state }, slug) {
    const { posts } = state;
    commit("updatePost", posts.find(post => post.slug === slug));
  }
};

Then the function that reads from the content directory

// utils/markdownFromDirectory.js

const slugify = require("slugify");
const fs = require("fs");
const fm = require("front-matter");

module.exports = function(directory) {
  return fs.readdirSync(`./content/${directory}`).map(file => {
    return {
      ...fm(fs.readFileSync(`./content/${directory}/${file}`, "utf8")),
      filename: file,
      get created() {
        return new Date(
          fs.statSync(`./content/${directory}/${file}`, "utf8").ctime
        );
      },
      get slug() {
        return slugify(file.replace(/\.md$/, ""), { lower: true });
      },
      get href() {
        return `/${directory}/${this.slug}`;
      }
    };
  });
};

Then the Post template

// pages/blog/_post.vue

<template>
  <div class="post mb-6">
    <h1 class="text-blue-darker">{{ post.attributes.title }}</h1>
    <div class="flex -mx-2 mbitems-center text-grey-darker text-sm">
      <div>{{ createdAt }}</div>
    </div>
    <div class="flex -mx-2 mb-4 items-center text-grey-darker text-sm">
      <div>{{ post.attributes.author }}</div>
    </div>
    <div class="mb-2">
      <img
        v-lazy="post.attributes.featuredImage"
        :alt="`${post.title} featured image`"
      />
    </div>
    <div v-html="postFile"></div>
  </div>
</template>

<script>
export default {
  layout: "post",
  fetch({ store, params }) {
    store.dispatch("loadPost", params.post);
  },
  head() {
    return {
      title: this.postTitle
    };
  },
  computed: {
    post() {
      return this.$store.getters.getPost;
    },
    postFile() {
      if (this.post.filename) {
        return require(`~/content/blog/${this.post.filename}`);
      } else {
        return require("~/content/blog/not-found.md");
      }
    },
    createdAt() {
      return format(new Date(this.post.created), "MMMM Do[,] YYYY");
    },
    postTitle() {
      return `Blog :: ${this.post.attributes.title}`;
    }
  }
};
</script>

If I find time I will upload a nuxt blog example to github

from blog-module.

adam-lynch avatar adam-lynch commented on May 28, 2024

how I can customize the HTML outputted for each post preview, for example.

@bskimball maybe you can shed some light on this? (Since you mentioned changing the templates in #2)

from blog-module.

znck avatar znck commented on May 28, 2024

I'll spend some time on the repository next month. I'll improve documentation then.

from blog-module.

adam-lynch avatar adam-lynch commented on May 28, 2024

@bskimball

I ended up not using the blog-module... I did use the blog module as a base for what I was trying to do.

I was thinking I'd probably do the same actually.

I also use the markdownit module

FYI there's a vue-markdown which uses markdown-it under the hood.


Thanks a lot for that! I'll go for something similar for sure. I might not use Vuex to begin with because I don't think I need it yet. Thanks again.

from blog-module.

bskimball avatar bskimball commented on May 28, 2024

@adam-lynch yeah, I'm aware of vue-markdown. I'm using nuxtjs/markdownit which is here --> https://github.com/nuxt-community/modules/tree/master/packages/markdownit

with the following options plus front-matter

  markdownit: {
    preset: 'default',
    linkify: true,
    breaks: true,
    use: [
      'markdown-it-container',
      'markdown-it-attrs',
      'markdown-it-meta'
    ]
  }

The main reason I chose to use Vuex is so I could list recent blog posts in the sidebar on any page.

from blog-module.

adam-lynch avatar adam-lynch commented on May 28, 2024

Nice, thanks

from blog-module.

tcurdt avatar tcurdt commented on May 28, 2024

@bskimball You don't have the full site on github by any chance? Seems like the blog plugin was abandoned so I am still researching my options.

from blog-module.

tcurdt avatar tcurdt commented on May 28, 2024

@bskimball So IIUC you are using dynamic routes to create the posts and feed the store manually on startup.

I also want co-located post assets. So my content structure is:

content/
  posts/
    slug1/
      index.md
      someimage.jpg

I don't think that's possible to do with your approach, is it?

from blog-module.

bskimball avatar bskimball commented on May 28, 2024

With your structure, you would have to adjust the markdownFromDirectory function. My setup in this scenario is:

content/
    posts/
        my-first-post.md
        my-second-post.md
static/
    images/
        someImage.jpg

In your markdown file you would reference your image as /images/someImage.jpg. In your store in the nuxtServerInit would look like this

  nuxtServerInit() {
    if (process.server) {
      const markdownFromDirectory = require("../utils/markdownFromDirectory");
      this.dispatch("loadPosts", markdownFromDirectory("posts"));
    }
  },

The markdownFromDirectory function assumes the directory is directly under the content folder, and that the file name matches the slug. Also, with images in nuxt, I always put them in the static folder so they can be referenced relative to the url

from blog-module.

tcurdt avatar tcurdt commented on May 28, 2024

Yes, adjusting the markdownFromDirectory is no problem - but having co-located images is the tricky part. I don't want to shove them all into the static folder but keep them with the posts.

from blog-module.

bskimball avatar bskimball commented on May 28, 2024

Only way I would know to do that inside nuxt, is hook into the builder and move them to a directory on render https://nuxtjs.org/api/internals-renderer or maybe some kind of custom built middleware. I just chose the path of least resistance and put them in the static directory

Another option would be to build your own api (using express, feathers, adonis etc.) that reads the markdown files and presents them as json, along with a path to the image and serve the image from your api. Of course there are also a ton of other options.

from blog-module.

Related Issues (13)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.