• Stars
    star
    390
  • Rank 106,713 (Top 3 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created about 3 years ago
  • Updated 12 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

๐Ÿ™ Turn your github issues into a CMS for your blog.

Github Blog

Turn your github issues into a CMS for your blog.

yarn add @rena.to/github-blog

API Only

This repository is just about the API.

Note:

If you're looking for something more 'high level', like a full-featured blog application, I'm working on a starter template using Next.js, TypeScript and Tailwindcss. Follow me on twitter to follow up and receive updates.

Concept

The main idea is simple: each issue is a blog post entity.

Taxonomy is managed by labels and have <key>:<value> structure. Like type:post, tag:javascript, etc. Labels can be used to filter posts on querying, but is also available on post too. So you can use to add any kind of flags to your post.

The built-in label keys are: type, state, tag, flag and slug.

  • Use type labels to differentiate post from article, for example.
  • Use state labels to handle published and draft.
  • Use tag labels to add tags to your posts, like typescript.
  • Use flag labels to add any kind of flag to your post, like outdated to mark post as outdated.
  • Use slug label to define an slug to your post. Read about slug problem.

You can also add any k:v labels to your post, like foo:bar.

Table of Contents

Getting Started

Let's create your first blog post.
You will need: 1) a repository, 2) an issue with some labels

Repository

First, you will need to create a repository to publish your posts.

It can be private, but I recommend you to create a public since it will allow people comment and react to your posts.
Random people will be able to create issues but they can't add labels. So you can control what posts will be shown using some label like type:post for example. It will prevent random people to post on your blog. Also, by core github-blog only fetches by opened issues. You can close any random issue opened by others to keep posts organized.

image

Issue

Create a issue with your content and add the labels state:published, type:post.
Also add an label to your slug like slug:my-first-post.

Tip: Your issue content can have frontmatter data

image

Fetch

Here comes github-blog. First install

yarn add @rena.to/github-blog
# npm install @rena.to/github-blog

Now create a new blog instance passing your repo and your github token.
Create your token here โŸถ.

import { GithubBlog } from "@rena.to/github-blog";

const blog = new GithubBlog({
  repo: "<user>/<repo>", // e.g.: "renatorib/posts"
  token: "<token>",
});

Fetch your post using getPost:

const post = await blog.getPost({
  query: { slug: "my-first-post" },
});

Fetch post comments using getComments:

const comments = await blog.getComments({
  query: { slug: "my-first-post" },
  pager: { first: 100 },
});

Fetch all your posts using getPosts:

const posts = await blog.getPosts({
  query: { type: "post", state: "published" },
  pager: { limit: 10, offset: 0 },
});

That's all.

Guides

Querying

All query works by AND logic. You can't query by OR because of the nature and limitations of github search.
But you can exclude results using prefix not (notType, notState, etc.)
E.g: If you want to query posts with type post but it can't have a flag outdated, you can use:

const posts = await blog.getPosts({
  query: { type: "post", notFlag: "outdated" },
  pager: { limit: 10, offset: 0 },
});

You can also pass an array to most of query params:

const posts = await blog.getPosts({
  query: { type: ["post", "article"], tag: ["javascript", "react"] },
  pager: { limit: 10, offset: 0 },
});

Searching

You can also search for post that contain terms using query.search param:

const posts = await blog.getPosts({
  query: { type: "post", state: "published", search: "compiler" },
  pager: { limit: 10, offset: 0 },
});

Sorting

You can sort results by interactions, reactions, author-date, created, updated.
All of them are desc by default but you can suffix with -asc. See all in docs

const posts = await blog.getPosts({
  query: { type: "post", sort: "interactions" },
  pager: { limit: 10, offset: 0 },
});

Pagination

You can paginate using pager.limit and pager.offset as you saw before, but you can also paginate using cursors with the pager params after, before, first and last.

// first 10 posts
const posts = await blog.getPosts({
  query: { type: "post" },
  pager: { first: 10 },
});

// more 10 posts
const morePosts = await blog.getPosts({
  query: { type: "post" },
  pager: { first: 10, after: posts.pageInfo.endCursor },
});

NOTE: limit and offset uses first and after under the hood.
So if you pass both limit and first or offset and after, limit and offset will be ignored.

Defaults

You can set some defaults for querying right in your blog instance, if you want to avoid some query repetition:

const blog = new GithubBlog({
  repo: "renatorib/posts",
  token: process.env.GITHUB_TOKEN,
  queryDefaults: {
    state: "published",
    type: "post",
  },
});

const posts = await blog.getPosts({
  pager: { first: 10, offset: 0 },
});

Comments

You can fetch all post comments using getComments method

// first 10 comments
const comments = await blog.getComments({
  query: { slug: "my-first-post" },
  pager: { first: 10 },
});

// more 10 posts
const moreComments = await blog.getComments({
  query: { slug: "my-first-post" },
  pager: { first: 10, after: comments.pageInfo.endCursor },
});

NOTE: Comment pagination by limit and offset is still not possible while I figure out on how generate v2 cursors based on offset.
Read more about this issue here, maybe you can help.

Problems

Github issues and Github API of course isn't designed to this kind of usage. So I ended up bumping into some limitations during the design and construction of the project. Here I list some of them and try to describe the problem and how I tried to get around.

Slug Problem

One of my biggest disappointments. It's impossible to create a safe and unique slug for your posts.

My first attempt was to use issue title to slug, and define the actual post title into issue's frontmatter.
But it does not worked because:

Github only let you query for an exact repo/issue using the number of it, and I don't want to put id/number into my urls.

query {
  repository(owner: "renatorib", name: "posts") {
    issue(number: 1) { // get issue at https://github.com/renatorib/posts/issue/1
      title
    }
  }
}

Github repository issues only allow you to filter using labels, states (closed/open), assignee, dates, etc. Nothing that let me use the title.

query {
  repository(owner: "renatorib", name: "posts") {
    issues(...filters) {  // some specific filters, nothing useful
      title
    }
  }
}

So I was forced to use the query search that I find more powerful and I could filter by repo:owner/name Now I can find the issue using title this way:

query {
  search(type: ISSUE, first: 1, query: "repo:renatorib/posts slug-name") {
    nodes {
      ... on Issue {
        title
      }
    }
  }
}

But it isn't reliable. I can't search for an exact title with query search and it could return an issue with title of slug-name-foo instead of the slug-name depending on the sort rules.

I gave up and ended using labels for that. Now I can query by exact slug:

query {
  search(type: ISSUE, first: 1, query: "repo:renatorib/posts label:slug:slug-name") {
    nodes {
      ... on Issue {
        title
      }
    }
  }
}

It works. But the problem is that it isn't the ideal. Each post is a new label, it don't scale well.

Pagination by limit/offset problem

TODO

API Reference

See at /docs (auto-generated from typescript types)

More Repositories

1

react-powerplug

๐Ÿ”Œ [Unmaintained] Renderless Containers
JavaScript
2,686
star
2

react-sizes

โ†”๏ธ Hoc to easily map window sizes to props.
JavaScript
724
star
3

bjson

ABANDONED! Bind Json: Reactive way to read/write json files.
JavaScript
72
star
4

janimate

jQuery Animate: jQuery animations with animate.css
JavaScript
69
star
5

react-bps

๐Ÿ”ฑ Create breakpoints to your component props
JavaScript
64
star
6

styn

๐Ÿ’Ž A small, zero-dependency, extensible, object to css generator
TypeScript
41
star
7

styleshape

๐Ÿ”ถ Because inline style can also be cool! [180 bytes only!]
JavaScript
41
star
8

lo-jsondb

Small database based on local .json files
JavaScript
40
star
9

next-jph

๐Ÿ“ JsonPlaceholder sample app made with Next.js
JavaScript
34
star
10

cartola-api

Implementaรงรฃo da API do CartolaFC em PHP
PHP
22
star
11

tibia-outfitter

New Tibia Outfitter.php
PHP
19
star
12

otinfo

Open Tibia Server Info Parser (otinfo). Catch information like players online, owner, motd, map weight, monsters, npcs, etc. passing IP and PORT.
PHP
18
star
13

otcts

Open Tibia Client in TS. Still WIP.
TypeScript
17
star
14

slaq

๐Ÿงฑ A lib to build Slack Apps, modular.
JavaScript
16
star
15

tibia-node-crawler

Tibia Crawler in nodejs
JavaScript
16
star
16

renatorib.github.io

My personal website
JavaScript
6
star
17

caixinha

Simple bundler for study
TypeScript
6
star
18

geo

TypeScript
6
star
19

covid19databr

For studying purposes.
JavaScript
4
star
20

slack-ui

Build slack Block Kit ui with JSX
3
star
21

curriculum-vitae

Renato Ribeiro, Frontend Engineer.
CSS
3
star
22

dot-notation

Node package to help you working with dot notation in objects
JavaScript
3
star
23

posts

rena.to posts source repo
2
star
24

caixa

TypeScript
2
star
25

cvb

Covid Vaccine Br
TypeScript
2
star
26

2048.js

fp 2048 lib
JavaScript
1
star
27

tibia-tasks

Build some automated tasks in tibia.com =)
HTML
1
star
28

2048-term

Play 2048 game in terminal
JavaScript
1
star
29

spinein

Spine like a shell spinner
JavaScript
1
star
30

renatorib

1
star
31

github-blog-tests

1
star
32

cra-material-ui

JavaScript
1
star
33

souls

Souls is a collection of CSS Animations that can also be handled by JavaScript.
1
star
34

typed-ms

Typed MS
TypeScript
1
star