Resources

Making templates for articles, desks, authors, & tags

Introduction

😮
resources refers to pages generated from data from articles, desks, tags, and authors.
  • Pages for all of your resources live in the /templates/resources folder.
  • Karbon uses file based routing, meaning your file routes will form the URL of your publication. Be aware of this when optimizing your Karbon publication for SEO.
  • Using these defined routes, Karbon will generate your pages by pulling data from Storipress and/or other third party sources.
 

 

Folder Structure

😮
All pages in Karbon are completely optional. If you do not need these pages, simply delete the page files or modify the config settings.

Your resources files are all placed in the resources folder

---| node_modules/
---| nuxt.config.js
---| package.json
---| templates/
------| resources/
---------| article.vue
---------| author.vue
---------| desk.vue
---------| tag.vue

Usage

Create a page

In the .vue pages under /templates/resources, you can use setupPage to get data needed for your page.

# /templates/resources/article.vue

<script lang="ts" setup>
	const article = setupPage({ type: 'article' })
</script>

<template>
	<div>
    <div class="text-sky-900">Article data</div>
    <ul>
			<li>id: {{ article.id }}</li>
      <li>title: {{ article.title }}</li>
    </ul>
  </div>
</template>

Configure your URL

Karbon comes with a default resource configuration. This configuration can be overwritten in the nuxt.config.js file.

export default defineNuxtConfig({
	...,
	karbon: {
		resources: {
	    article: 
 
 

Using these helper functions

You can use these helper functions that are specific to certain resources: createArticleRoute, createTagRoute, createTagCollectionRoute, createDeskRoute, createAuthorRoute.

They allow you to define your desired route type more easily.

 

createArticleRoute

Use this function to generate routes for article resources

  • url: URL structure, will explain the syntax in URL Syntax
 

createTagRoute

Use this function to generate routes for tag resources

  • url: URL structure, will explain the syntax in URL Syntax
 

createTagCollectionRoute

Use this function to generate routes for tag collection resources

  • url: URL structure, will explain the syntax in URL Syntax
  • groupKey: string
    • Setting the tag group key will find the tags under that group and automatically generate the related page. Please reference Tag Groups for more details

      ⚠️
      Setting an invalid value will cause unexpected errors in Karbon
 

createDeskRoute

Use this function to generate routes for desk resources

  • url: URL structure, will explain the syntax in URL Syntax
 

createAuthorRoute

Use this function to generate routes for author resources

  • url: URL structure, will explain the syntax in URL Syntax

Example

resources: {
	article: createArticleRoute('/posts/{id}'),
  desk: createDeskRoute('/desks/{id}'),
  author: createAuthorRoute('/author/{id}'),
  tag: createTagRoute('/tags/{id}'),
  collection: createTagCollectionRoute('/collection/{slug}', 'taggroup'),
}

Using the createResourceRoute helper

The createResourceRoute helper is the underlying version of other helpers.

You probably don't need to use it.

import { createResourceRoute } from '@storipress/karbon'

type Resources = 'article' | 'desk' | 'tag' | 'author'

interface ResourceRouteOption {
  url: string
  resource: Resources
  groupKey?: string
}

function createResourceRoute(opt: ResourceRouteOption): ResourcePage<BaseMeta, RouteOptionsContext>

createResourceRoute

  • url: URL structure, will explain the syntax in URL Syntax
  • resource: Resources
    • type of resource

      type Resources = 'article' | 'desk' | 'tag' | 'author'
 
  • groupKey: string
    • Setting the tag group key will find the tags under that group and automatically generate the related page. Please reference Tag Groups for more details

      ⚠️
      Setting an invalid value will cause unexpected errors in Karbon
      resources: {
        collection: createResourceRoute({
      		resource: 'tag',
      		groupKey: 'example_group',
      		url: '/collection/{slug}',
      	})
      }
 

Deleting resources

To delete resources, simply delete any pages in the resources folder.

 

URL Syntax

URL syntax is look like: /posts/{slug} , the dynamic parameters will be surround by {} . With /posts/{slug}, Karbon will fetch your articles and fill article’s slug into the {slug} part and generate your page like /posts/example-slug

 

Resource Identity

💡
You must use either id , sid or slug in your URL

In Storipress, resource will be identity by either id, sid or slug, For example, these identity could point to the same article:

 
  • id: 1 An id is a sequence number
  • sid: abcdefg A sid is a short string version of id
  • slug: example-slug A slug is an human readable string, which is safe for URL and it’s configuable for articles in Storipress
 

Karbon will combine the resource option and the identitiable parameters (i.e. id, sid, slug) to find your resource. Thus, it’s important to use one if the identitable parameters.

 

For example:

 

✅ These are valid URL config

/posts/{slug}
/{slug}/view
/{root_desk.slug}/{sid}
 

🔴 These are invalid because of missing identifiable parameters

/article # No identifiable parameter
/{root_desk.slug} # Only containing desk's slug is not valid
 

Optional parameter

💡
Prefix a ? like {?param} will make a dynamic parameter optional

In Storipress, article could live under a sub desk, but this is not enforce. Which mean your article may or may not live under a sub desk. What if you want to make your URL like:

  • /parent-desk/sub-desk/slug for article that is under subdesk
  • /desk-without-subdesk/slug for article that is not under subdesk

Here comes the optional parameter. You only need to configure your URL like

  • /{root_desk.slug}/{?sub_desk.slug}/{slug}

Please notice the ? before the sub_desk.slug which will make the parameter optional. If the article is not belong to a subdesk. Karbon will simply ignore the {sub_desk.slug} part and also remove the following / for you

Article parameters

We know the article is the most important part of your site. Thus, we provide a lot of additional parameters for your articles.

 

But before getting start, let me introduce you how to understand the document of parameters

 

Here is the simpliest form

  • parameter_name: description for parameter_name

For example:

  • year: Published year for the article in YYYY format, e.g. 2023

And you can use {year} in your URL

 

Here comes the nested parameter

  • parent_param : description for parent_param
    • child_param: descriotion for child_param

For example:

  • root_desk: The toplevel desk for the article
    • slug: The slug for the toplevel desk of the article

And you MUST use it like {root_desk.slug} in your URL. Or it will result an error

 

Let’s start

 
  • year: Published year for the article in YYYY format, e.g. 2023
  • month: Published month for the article in MM format, e.g. 01
  • day: Published day for the article in dd format, e.g. 02
  • root_desk: The toplevel desk for the article
    • id: The id for the toplevel desk of the article
    • sid: The sid for the toplevel desk of the article
    • slug: The slug for the toplevel desk of the article
  • sub_desk: The sub desk for the article, which can be optional
    • id: The id for the sub desk of the article
    • sid: The sid for the sub desk of the article
    • slug: The slug for the sub desk of the article

Examples


This will generate the following URL /posts/<parent-desk>/<sub-desk>/<slug> for your articles.
import { createResourceRoute } from '@storipress/karbon'

export default defineNuxtConfig({
	...,
	storipress: {
		resources: {
	    article: createResourceRoute({
				resource: 'article',
				url: '/posts/{root_desk.slug}/{?sub_desk.slug}/{slug}',
			})
		}
	}
})
 

Customise Resource Page

If the createResourceRoute helper doesn't meet your requirements, you can also define your own ResourcePage object in the karbon.resources of your nuxt.config.ts to configure it.

 

Type

type BaseID<Type extends 'article' | 'desk' | 'tag' | 'author'> =
  | {
      type: Type
      id: string
    }
  | {
      type: Type
      slug: string
    }
type ArticleID =
  | BaseID<'article'>
  | {
      type: 'article'
      sid: string
    }
type DeskID = BaseID<'desk'>
type AuthorID = BaseID<'author'>
type TagID = BaseID<'tag'>

type ResourceID = ArticleID | DeskID | AuthorID | TagID

interface Identifiable {
  id: string
  slug?: string
  sid?: string
}

interface ResourcePage<Meta extends Identifiable> {
  enable: boolean
  route: string
  getIdentity(params: Record<string, string>): ResourceID
  toURL(resource: Meta): string
  isValid(params: Record<string, string>, resource: Meta): boolean
  groupKey?: string
}
 

Params

⚠️
The functions getIdentity, toURL, and isValid must be pure and not use any external variables or functions. This is because Karbon will serialize them as strings and pass them into the client context.
  • enable : boolean
    • Whether to enable this routing configuration.

  • route : string
    • Use a string to set the URL, it has same syntax with vue-router. You can use : as a prefix after / to indicate that the value is passed as a URL params to getIdentity, isValid, toURL for subsequent logic judgment.

  • getIdentity : (params: Record<string, string>): ResourceID
    • Define a handler function that will receive the params parameter defined through route.

      It needs to return a ResourceID so that Karbon can find the correct Resource.

  • toURL : (resource: Meta): string
    • Define a handler function to set the logic for building the URL, which will pass in the complete meta data of Resource as parameters.

      It needs to return a set of actual URL strings used to set the URL.

  • isValid : (params: Record<string, string>, resource: Meta, _context: Ctx): boolean
    • Define a handler function to validate whether the current URL connection is valid. It will receive the params parameter defined through route, the complete meta data of Resource, and ResourcePageContext.

      It needs to return a boolean result to confirm that this URL provides access.

      Common checks include verifying that a Resource can be properly matched.

  • groupKey : string
 

Example

export default defineNuxtConfig({
  karbon: {
    resources: {
      article: {
				enable: true,
				route: '/posts/:desk/:articleId',
				getIdentity: ({ articleId }) => ({ type: 'article', id: articleId }),
				toURL: ({ id, desk }) => `/posts/${desk.slug}/${id}`,
				isValid: ({ desk }, { desk: {slug} }) => desk === slug,
      },
    },
  },
})

Last updated on February 3, 2023