npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

dimer-vue

v3.0.3

Published

Components and helpers to build user documentation websites using Dimer and Vue

Downloads

4

Readme

Dimer vue

Components and helpers to build user interfaces using Dimer

| file | size | gzip size | |------------------------|----------|-----------| | CJS | 26 KB | 5.83 KB | | UMD | 28.3 KB | 6.02 KB | | UMD MIN | 9.63 KB | 2.98 KB |

The goal of the project is to make it easier to create custom designs for your documentation, without re-creating the core elements or components.

Table of contents

Prerequisites

Before getting started, make sure you know how to connect to the Dimer API server.

  1. If you are testing it on your local server, then it will be accessible as http://localhost:5000
  2. If you have published it on Dimer cloud, then it will be https://api.dimerapp.com/YOUR_DOMAIN.

Installation

Install the package from npm registry as follows:

npm i dimer-vue

# yarn
yarn add dimer-vue

Nuxt usage

The documentation covers this module usage with Nuxt. However, any Vue project using Vue router and Vuex store can leverage the API.

Nuxt has almost zero boilerplate to create full blow SPA in Vue.js. So give it a try.

Before getting started, you have to install handful of dependencies and register them as nuxt modules inside nuxt.config.js file.

npm i nuxt-env @nuxtjs/axios @nuxtjs/router
  • The nuxt-env is required, so that we can define environment variable for the Dimer API base url. The environment variables gives us the freedom to point to a different API endpoints in production and development respectively.
  • The @nuxtjs/axios is required for making API calls.
  • The @nuxtjs/router is required to register custom routes exposed by this module. The route is an optional dependency, however it makes the process of registering custom routes so simple.

Setup nuxt.config.js file

Next step is to setup the nuxt.config.js file with following code.

export default {
  modules: [
    '@nuxtjs/router',
    '@nuxtjs/axios',
    ['nuxt-env', {
      keys: [{
        key: 'DIMER_BASE_URL',
        default: 'http://localhost:5000'
      }]
    }]
  ],
  plugins: ['~plugins/dimer.js']
}

We will create ~plugins/dimer.js now, with following contents.

import Vue from 'vue'
import { Dimer, DimerTree } from 'dimer-vue'

export default async function (ctx, inject) {
  Dimer.use(DimerTree)
  
  /**
   * Injects handful of utility methods and loads the vuex
   * store with `dimer` module.
   */
  await Dimer.loadStore(ctx, inject)
  
  Vue.use(Dimer)
}

The dimer plugin is straight forward. We pre-load some stuff from the API to the Vuex store and also inject some helper functions.

Feel free to add custom renderers and Dimer plugins inside this file.

Registering routes

Now, we need to register couple of routes, which are handled by Dimer. This is done, so that Dimer can offload the task of making API calls, validating routes to have correct zone and version etc.

We will leverage the router module and define following routes inside router.js file.

import Vue from 'vue'
import Router from 'vue-router'
import { routes } from 'dimer-vue'

import LayoutComponent from '~/components/Layout'
import DocComponent from '~/components/Doc'

Vue.use(Router)

export function createRouter() {
  return new Router({
    mode: 'history',
    routes: routes(LayoutComponent, DocComponent)
  })
}

The routes function exported by Dimer will register following routes

  • :/zone/:version
  • :/zone/:version/:permalink

Also, if you have noticed, the routes function accepts two Vue components. These components are rendered when Dimer will receive request on the registered routes.

Layout component

Define the complete page layout and documentation navigation (usually a sidebar) in this file.

<template>
  <section>    
    <main>
      <aside>
        <ul v-for="node in tree">
          <h2> {{ node.category }} </h2>
          <li v-for="doc in node.docs">
            <nuxt-link :to="doc.permalink">
              {{ doc.title }} 
            </nuxt-link>
          </li>
        </ul>
      </aside>
      
      <article>
        <nuxt-child />
      </article>
    </main>
  </section>
</template>

<script>
 export default {
   props: ['tree']
 }
</script>

<style>
  .main {
    display: flex;
  }

  .aside {
    width: 300px;
    padding-right: 40px;
  }
</style>

Doc component

The Doc component is meant to render a single doc.

<template>
  <div>
    <h1> {{ doc.title }} </h1>
    <dimer-tree :node="doc.content" />
  </div>
</template>

<script>
 export default {
   props: ['doc']
 }
</script>

That's all. Now you have a fully working Nuxt app consuming the Dimer API and rendering docs. From here

  • You are free to design and structure the layout as per your needs.
  • Use any Dimer plugins to enhance the documentation.
  • Don't worry about someone entering the wrong URL, as Dimer custom routes will handle everything for you.

Vuex store

The Dimer.loadStore method registers a module named dimer and makes the API calls to the Dimer API and add following values to the store.

{
  websiteOptions: {},
  zones: []
}
  1. The websiteOptions is loaded from /config.json endpoint.
  2. The zones are loaded from /zones.json endpoint.

You are free to read values from the store from any custom component. For example: Rendering the main menu from the available zones and so on.

Dimer plugins

The Dimer plugins are mainly focused on the Rendering layer of Vue. As you know that Dimer API returns the markdown content as JSON AST and available plugins can ease the process of rendering and handling certain nodes differently.

Dimer tree

The DimerTree is the bare minimum you need to render the JSON AST as it is.

import { DimerTree, Dimer } from 'dimer'
Dimer.use(DimerTree)

and then use the component as follows:

<template>
  <dimer-tree :node="doc.content" />
</template>

The DimerTree component also accepts one or more renderer functions. These functions will receive all the AST nodes and can handle them any way.

Let's say we want to add target="_blank" to all external links. We can define a renderer for that.

import { DimerTree, Dimer, utils } from 'dimer'
Dimer.use(DimerTree)

Dimer.addRenderer(function (node, rerender, createElement) {
  if (node.tag === 'a' && /^http(s)?/.test(node.url)) {
    node.props.target = '_blank'

    const attrs = utils.propsToAttrs(node.props)
    const children = node.children.map(rerender)

    return createElement('a', { attrs }, children)
  }
})

The possibilities with custom renderers are endless

Component renderers

The renderers added via Dimer.addRenderer are global and will always be used by dimer-tree component. However, you can use customRenderers prop to define custom renderers.

<template>
  <dimer-tree :node="doc.content" />
</template>

<script>
  function myCustomRenderer (node, rerender, createElement) {
  }

  export default {
    methods: {
      customRenderers (globalRenderers) {
        return globalRenderers.concat(myCustomRenderer)
      }
    }
  }
</script>

Dimer tabs

The DimerTabs component is registered to ease the process showing multiple codeblocks inside a tab. They are defined using the [codeblock] macro in Markdown.

This is a renderless component, that you need to wrap in order to define your own markup for tabs.

The first step is to define a Dimer renderer, that returns a custom component for the tabs node.

import { Dimer, DimerTabs } from 'dimer-vue'
Dimer.use(DimerTabs)

import Tabs from '~/components/Tabs'

Dimer.addRenderer(function (node, rerender, createElement) {
  if (node.props.className && node.props.className.indexOf('tabs') > -1) {
    return createElement(Tabs, { props: { node } })
  }
})

Next step is to create the ~components/Tabs component. This component will make use DimerTabs and defines the markup for the tabs.

<template>
  <dimer-tabs :node="node">
    <template slot-scope="tabs">
      <div class="tabsHead">
        <a
          v-for="(link, index) in tabs.links" @click.prevent="activeTab(index)"
        >
          {{ link }}
        </a>
      </div>

      <div class="tabBody">
        <div
          v-for="(pane, index) in tabs.panes"
          v-show="index === activeIndex"
        >
          <dimer-tree :node="pane" />
        </div>
      </div>
    </template>
  </dimer-tabs>
</template>

<script>
  export default {
    data () {
      return {
        activeIndex: 0
      }
    },

    methods: {
      activeTab (index) {
        this.activeIndex = index
      }
    },

    props: ['node']
  }
</script>

Dimer collapse

The DimerCollapse component is similar to the DimerTabs component, but to define the custom markup and behavior for the [collapse] macro.

import { Dimer, DimerCollapse } from 'dimer-vue'
Dimer.use(DimerCollapse)

import Collapse from '~/components/Collapse'

Dimer.addRenderer(function (node, rerender, createElement) {
  if (node.props.className && node.props.className.indexOf('collapsible') > -1) {
    return createElement(Collapse, { props: { node } })
  }
})

Next step is to create the ~/components/Collapse component.

<template>
  <dimer-collapse :node="node">
    <template slot-scope="collapse">
      <details>
        <summary>{{ collapse.title }}</summary>
        <dimer-tree :node="collapse.body" />
      </details>
    </template>
  </dimer-collapse>
</template>

<script>
  export default {
    props: ['node']
  }
</script>

Dimer search

Dimer has inbuilt search for documentation and instead of building the entire Typeahead search from hand, we recommend using the renderless DimerSearch component.

import { Dimer, DimerSearch } from 'dimer-vue'
Dimer.use(DimerSearch)
<template>
  <dimer-search :model="model">
    <template slot-scope="searchScope">  
      <input
        type="search"
        v-model="model.query"
        @keyup="searchScope.triggerSearch"
      />
      
      <div>
       <div v-for="item in model.data">
         <p> Results for {{ item.zone }} </p>
         <li v-for="row in item.results">
           <h2>
             <component :is="searchScope.renderMark(row.title.marks)" />
            </h2>
            <p v-if="row.body.length">
              <component :is="searchScope.renderMark(row.body[0].marks)" />
            </p>
         </li>
        </div>
      </div>
    </template>
  </dimer-search>
</template>

<script>
  export default {
    data () {
      return {
        model: {
          query: '',
          data: [
            {
              zone: 'faqs',
              version: 'master',
              results: [],
            }
          ]
        }
      }
    }
  }
</script>

Events

You can define listeners for following events.

<dimer-search
  :model="model"
  @onArrowUp="customHandler"
  @onArrowDown="customHandler"
  @onEnter="customHandler"
  @onEscape="customHandler"
>
</dimer-search>