diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..3465227
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,25 @@
+{
+ "presets": [
+ "next/babel"
+ ],
+ "plugins": [
+ [
+ "prismjs",
+ {
+ "languages": [
+ "javascript",
+ "js",
+ "json",
+ "bash",
+ "http"
+ ],
+ "plugins": [
+ "line-numbers",
+ "show-language"
+ ],
+ "theme": "okaidia",
+ "css": true
+ }
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 0f6be16..5095bed 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ This app can easily be deployed to multiple targets including Vercel, Netlify or
- Vercel
- [jambonz.vercel.com](https://jambonz.vercel.app)
- AWS+circleci
- - Could easily be implemented as in this repo [here](https://github.com/kitajchuk/punxy#aws--circleci).
+ - Could easily be implemented similar to this Next.js repo [here](https://github.com/kitajchuk/uncle-toms-letters#aws--circleci).
## Dev start
@@ -37,4 +37,6 @@ We are using static data with [yamljs](https://www.npmjs.com/package/yamljs) and
## Jambonz developer docs
-The project is using [Nextra.js](https://nextra.vercel.app) which provides a stylized developer docs theme for Next.js. We are loading theme CSS styles with the `styles/_nextra.scss` partial. It is being used to hide the frontend page links from the Nextra sidebar nav as there is currently no way to do this using pure nextra config. There is a [Github issue here](https://github.com/shuding/nextra/issues/59) referring to "Page exclusion from docs".
+The project is generating developer docs from markdown files using static file JS utilities alongside Next.js static paths/props system. We are leveraging their [catch-all](https://nextjs.org/docs/routing/dynamic-routes#optional-catch-all-routes) dynamic routes logic located at `pages/docs/[[...slug]].js`. The markdown files are in the `docs` directory. The docs structure is controlled in the docs page YAML data located in `data/docs.yaml`. You can create docs markdown files at will in the `docs` directory but they will not render in the sidebar nav until they are also added to the nav structure in this file.
+
+We are using [remark](https://github.com/remarkjs/remark) & [remark-html](https://github.com/remarkjs/remark-html) as well as [gray-matter](https://github.com/jonschlinkert/gray-matter) for parsing the docs markdown files. Code syntax highlighting is done with [prismjs](https://prismjs.com) and the associative babel config is in the `.babelrc` file. It's important to leave the preset in this file that merges our config with `next/babel` so Next.js works properly.
diff --git a/components/footer.js b/components/footer.js
index d12b65e..384e0ac 100644
--- a/components/footer.js
+++ b/components/footer.js
@@ -1,7 +1,9 @@
+import { nanoid } from 'nanoid';
+
import Link from 'next/link';
+
import { Button } from './jambonz-ui';
import { homeObj } from '../lib/vars';
-import { nanoid } from 'nanoid';
function FooterItem({ obj }) {
return (
diff --git a/components/jambonz-ui.js b/components/jambonz-ui.js
index aa3a62e..38a02ad 100644
--- a/components/jambonz-ui.js
+++ b/components/jambonz-ui.js
@@ -1,10 +1,13 @@
-import Link from 'next/link';
import classNames from 'classnames';
import * as Icons from 'react-feather';
import { nanoid } from 'nanoid';
-import { mobileMedia } from '../lib/vars';
import { useState, useEffect } from 'react';
+import Link from 'next/link';
+
+import { mobileMedia } from '../lib/vars';
+
+
// Normalize how we work with the subtext as an array[]
export function normalizeSubtext(subtext) {
if (!Array.isArray(subtext)) {
@@ -93,7 +96,7 @@ export function Hero({ data, subStyle }) {
}
return (
-
+
);
}
diff --git a/components/layout.js b/components/layout.js
index 8ab7038..22de6c9 100644
--- a/components/layout.js
+++ b/components/layout.js
@@ -1,4 +1,5 @@
import Head from 'next/head';
+
import Navi from './navi';
import Footer from './footer';
diff --git a/components/navi.js b/components/navi.js
index 8d83a8a..d8ca098 100644
--- a/components/navi.js
+++ b/components/navi.js
@@ -1,16 +1,18 @@
-import { useState, useEffect } from 'react';
+import { useState } from 'react';
+import { nanoid } from 'nanoid';
+import classNames from 'classnames';
+
import Link from 'next/link';
import { useRouter } from 'next/router';
-import classNames from 'classnames';
+
import { Button, Icon, useMobileMedia } from './jambonz-ui';
import { homeObj } from '../lib/vars';
-import { nanoid } from 'nanoid';
function NaviItem({obj}) {
const router = useRouter();
const classes = {
navi__link: true,
- active: (router.route === obj.link),
+ active: (router.route.replace('/[[...slug]]', '') === obj.link),
};
return (
diff --git a/data/docs.yml b/data/docs.yml
new file mode 100644
index 0000000..7a1eec6
--- /dev/null
+++ b/data/docs.yml
@@ -0,0 +1,44 @@
+navi:
+ -
+ path: getting-started
+ title: Getting Started
+ pages:
+ -
+ path: add-carrier
+ title: Add a Carrier
+ -
+ path: add-speech
+ title: Add Speech Credentials
+ -
+ path: add-application
+ title: Add an Application
+ -
+ path: add-phone-numbers
+ title: Add Phone Numbers
+ -
+ path: register-sip-client
+ title: Register SIP clients
+ -
+ path: api
+ title: API Reference
+ pages:
+ -
+ path: webhooks
+ title: Webhooks
+ -
+ path: rest
+ title: REST APIs
+ -
+ path: tutorials
+ title: Tutorials
+ pages:
+ -
+ path: overview
+ title: Overview
+ -
+ path: open-source
+ title: Open Source
+ pages:
+ -
+ path: overview
+ title: Overview
\ No newline at end of file
diff --git a/pages/docs/advanced/code-highlighting.mdx b/docs/api/rest.md
similarity index 100%
rename from pages/docs/advanced/code-highlighting.mdx
rename to docs/api/rest.md
diff --git a/docs/api/webhooks.md b/docs/api/webhooks.md
new file mode 100644
index 0000000..ac597c1
--- /dev/null
+++ b/docs/api/webhooks.md
@@ -0,0 +1 @@
+# Webhooks
diff --git a/docs/getting-started/add-application.md b/docs/getting-started/add-application.md
new file mode 100644
index 0000000..f77ab14
--- /dev/null
+++ b/docs/getting-started/add-application.md
@@ -0,0 +1,3 @@
+# Add an Application
+
+TODO
\ No newline at end of file
diff --git a/docs/getting-started/add-carrier.md b/docs/getting-started/add-carrier.md
new file mode 100644
index 0000000..0f48404
--- /dev/null
+++ b/docs/getting-started/add-carrier.md
@@ -0,0 +1,3 @@
+# Add a Carrier
+
+TODO
\ No newline at end of file
diff --git a/docs/getting-started/add-phone-numbers.md b/docs/getting-started/add-phone-numbers.md
new file mode 100644
index 0000000..fdc02db
--- /dev/null
+++ b/docs/getting-started/add-phone-numbers.md
@@ -0,0 +1,3 @@
+# Add Phone Numbers
+
+TODO
\ No newline at end of file
diff --git a/docs/getting-started/add-speech.md b/docs/getting-started/add-speech.md
new file mode 100644
index 0000000..2aa5bb7
--- /dev/null
+++ b/docs/getting-started/add-speech.md
@@ -0,0 +1,3 @@
+# Add Speech Credentials
+
+TODO
\ No newline at end of file
diff --git a/docs/getting-started/register-sip-client.md b/docs/getting-started/register-sip-client.md
new file mode 100644
index 0000000..c3a1546
--- /dev/null
+++ b/docs/getting-started/register-sip-client.md
@@ -0,0 +1,3 @@
+# Register sip clients
+
+TODO
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..a39b810
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,13 @@
+# jambonz
+
+jambonz is a CPaaS that is designed for communications service providers. As an API-driven platform, you will primarily interface with it using [Webhooks]() and [REST APIs]().
+
+jambonz is available for use both as cloud APIs, or as an open source platform that you can run on your own infrastructure. Either way, your applications are written in the same fashion, so you can start off by using the cloud APIs and later migrate to running your own platform if you like.
+
+jambonz is also a "Bring Your Own Everything" (BYOE) CPaaS, meaning that you will [plug in your own SIP trunking providers](), and [use your own AWS or Google credentials]() for speech processing.
+
+Follow the [Getting Started]() pages that follow to get yourself up and running on the cloud platform, or dive into the [API Reference]() or examine [client SDKs]() and [sample applications]() for inspiration.
+
+```javascript
+const foo = "bar";
+```
\ No newline at end of file
diff --git a/docs/open-source/overview.md b/docs/open-source/overview.md
new file mode 100644
index 0000000..07dd0c5
--- /dev/null
+++ b/docs/open-source/overview.md
@@ -0,0 +1 @@
+# Overview
diff --git a/docs/tutorials/overview.md b/docs/tutorials/overview.md
new file mode 100644
index 0000000..07dd0c5
--- /dev/null
+++ b/docs/tutorials/overview.md
@@ -0,0 +1 @@
+# Overview
diff --git a/lib/data.js b/lib/data.js
index 29f020e..c04d56d 100644
--- a/lib/data.js
+++ b/lib/data.js
@@ -1,17 +1,146 @@
const fs = require('fs');
const path = require('path');
const yamljs = require('yamljs');
+const matter = require('gray-matter');
+const remark = require('remark');
+const remarkHtml = require('remark-html');
const dataDir = path.join(process.cwd(), 'data');
+const docsDir = path.join(process.cwd(), 'docs');
+/******************************************************************************
+ * Static page data
+*******************************************************************************/
function _getData(key) {
const fullPath = path.join(dataDir, `${key}.yml`);
const fileContents = fs.readFileSync(fullPath, 'utf8');
return yamljs.parse(fileContents);
}
+// Load YAML data to generate the static props for Next.js page components
export function getData(key) {
return {
[key]: _getData(key),
site: _getData('site'),
};
+}
+
+/******************************************************************************
+ * Static developer docs data
+*******************************************************************************/
+function _getCleanSlug(slug) {
+ return slug
+ .replace(docsDir, '')
+ .replace(/^\/+|\/+$/, '')
+ .split('/');
+}
+
+// Load Markdown and YAML front-matter to generate the static props for Next.js docs component
+async function _getDocs(filePath) {
+ const fileContents = fs.readFileSync(filePath, 'utf8');
+ const fileMatter = matter(fileContents);
+ const frontMatter = fileMatter.data;
+
+ // Use remark to convert markdown into HTML string
+ const processedContent = await remark()
+ .use(remarkHtml)
+ .process(fileMatter.content);
+ const contentHtml = processedContent.toString();
+
+ // Combine the data with the slug and contentHtml
+ return {
+ contentHtml,
+ frontMatter,
+ }
+}
+
+// Walk the pages/docs file tree to generate the static paths for Next.js docs pages
+function _getDocsPaths(dirPath, arrayOfFiles = [{params:{slug:[]}}]) {
+ const files = fs.readdirSync(dirPath);
+
+ files.forEach((file) => {
+ const filePath = `${dirPath}/${file}`;
+ const isDirectory = fs.statSync(filePath).isDirectory();
+ const isMarkdown = /\.md$/.test(file);
+ let slug;
+
+ if (isDirectory) {
+ const indexFile = path.join(filePath, 'index.md');
+ const isIndexFile = fs.existsSync(indexFile);
+
+ if (isIndexFile) {
+ slug = _getCleanSlug(path.join(
+ __dirname,
+ dirPath,
+ '/',
+ file
+ ));
+
+ arrayOfFiles.push({
+ params: {
+ slug,
+ },
+ });
+ }
+
+ arrayOfFiles = _getDocsPaths(filePath, arrayOfFiles);
+
+ } else if (isMarkdown) {
+ slug = _getCleanSlug(path.join(
+ __dirname,
+ dirPath,
+ '/',
+ file.replace(/\.md$/, '')
+ ));
+
+ arrayOfFiles.push({
+ params: {
+ slug,
+ },
+ });
+ }
+ });
+
+ return arrayOfFiles;
+}
+
+// Public proxy for _getDocs() to return static props for Next.js docs component
+export async function getDocs(slug) {
+ let filePath = slug ? path.join(
+ docsDir,
+ slug.join('/')
+ ) : path.join(
+ docsDir,
+ 'index.md'
+ );
+ const isDirectory = (fs.existsSync(filePath) && fs.statSync(filePath).isDirectory());
+ let isMarkdown = /\.md$/.test(filePath);
+
+ if (isDirectory) {
+ filePath = path.join(
+ docsDir,
+ slug.join('/'),
+ 'index.md'
+ );
+ isMarkdown = true;
+
+ } else if (!isMarkdown) {
+ filePath = path.join(
+ docsDir,
+ `${slug.join('/')}.md`
+ );
+ isMarkdown = true;
+ }
+
+ if (isMarkdown && fs.existsSync(filePath)) {
+ return _getDocs(filePath);
+ }
+
+ return null;
+}
+
+// Public proxy for _getDocsPaths() to return static paths for Next.js docs pages
+export function getDocsPaths() {
+ const paths = _getDocsPaths(docsDir);
+
+ return paths;
}
\ No newline at end of file
diff --git a/lib/vars.js b/lib/vars.js
index 9cdf269..06cde60 100644
--- a/lib/vars.js
+++ b/lib/vars.js
@@ -5,7 +5,13 @@ const homeObj = {
label: 'Home',
};
+const docsObj = {
+ link: '/docs',
+ label: 'For Developers',
+};
+
export {
homeObj,
+ docsObj,
mobileMedia,
}
\ No newline at end of file
diff --git a/next.config.js b/next.config.js
index 851af14..5f4f78d 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,2 +1,3 @@
-const withNextra = require('nextra')('nextra-theme-docs', './theme.config.js')
-module.exports = withNextra()
+module.exports = {
+ trailingSlash: true,
+};
\ No newline at end of file
diff --git a/package.json b/package.json
index 7219c59..797d0bf 100644
--- a/package.json
+++ b/package.json
@@ -13,19 +13,22 @@
"license": "MIT",
"dependencies": {
"classnames": "^2.2.6",
- "env-cmd": "^10.1.0",
"nanoid": "^3.1.22",
"next": "^10.0.8-canary.9",
- "nextra": "^0.4.1",
- "nextra-theme-docs": "^1.1.2",
+ "prismjs": "^1.23.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
- "react-feather": "^2.0.9",
- "sass": "^1.32.8",
- "yamljs": "^0.3.0"
+ "react-feather": "^2.0.9"
},
"devDependencies": {
- "prettier": "^2.0.5"
+ "babel-plugin-prismjs": "^2.0.1",
+ "prettier": "^2.0.5",
+ "gray-matter": "^4.0.2",
+ "env-cmd": "^10.1.0",
+ "remark": "^13.0.0",
+ "remark-html": "^13.0.1",
+ "sass": "^1.32.8",
+ "yamljs": "^0.3.0"
},
"prettier": {
"semi": false,
diff --git a/pages/_app.js b/pages/_app.js
index c04bd99..2d2abc7 100644
--- a/pages/_app.js
+++ b/pages/_app.js
@@ -1,4 +1,3 @@
-import 'nextra-theme-docs/style.css';
import '../styles/global.scss';
export default function App({Component, pageProps}) {
diff --git a/pages/docs/[[...slug]].js b/pages/docs/[[...slug]].js
new file mode 100644
index 0000000..ea39c01
--- /dev/null
+++ b/pages/docs/[[...slug]].js
@@ -0,0 +1,120 @@
+import { useEffect, useState } from 'react';
+import { nanoid } from 'nanoid';
+import classNames from 'classnames';
+import Prism from 'prismjs';
+
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+
+import Layout from '../../components/layout';
+import { Icon } from '../../components/jambonz-ui';
+import { getData, getDocs, getDocsPaths } from '../../lib/data';
+import { docsObj } from '../../lib/vars';
+
+function Sidebar({data}) {
+ const router = useRouter();
+ const [active, setActive] = useState({
+ [data.navi[0].path]: true,
+ });
+
+ const handleToggle = (slug) => {
+ setActive((oldActive) => {
+ const newActive = {};
+
+ for (let i in oldActive) {
+ newActive[i] = oldActive[i];
+ }
+
+ newActive[slug] = newActive[slug] ? false : true;
+
+ return newActive;
+ });
+ };
+
+ return (
+
+ );
+}
+
+export default function Docs({ data, docs }) {
+ useEffect(() => {
+ setTimeout(() => Prism.highlightAll(), 0);
+ });
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export async function getStaticPaths() {
+ const paths = getDocsPaths();
+
+ return {
+ paths,
+ fallback: false,
+ };
+}
+
+export async function getStaticProps({ params }) {
+ const data = getData('docs');
+ const docs = await getDocs(params.slug);
+
+ return {
+ props: {
+ data,
+ docs,
+ },
+ };
+}
diff --git a/pages/docs/advanced/meta.json b/pages/docs/advanced/meta.json
deleted file mode 100644
index b3382bd..0000000
--- a/pages/docs/advanced/meta.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "code-highlighting": "Code Highlighting"
-}
\ No newline at end of file
diff --git a/pages/docs/anchors.md b/pages/docs/anchors.md
deleted file mode 100644
index 7f8337c..0000000
--- a/pages/docs/anchors.md
+++ /dev/null
@@ -1,57 +0,0 @@
-# Anchor Links
-
-`h2` tags will become anchors in the sidebar automatically.
-
-## When You Are Old
-
-When you are old and grey and full of sleep,
-And nodding by the fire, take down this book,
-And slowly read, and dream of the soft look
-Your eyes had once, and of their shadows deep;
-
-How many loved your moments of glad grace,
-And loved your beauty with love false or true,
-But one man loved the pilgrim soul in you,
-And loved the sorrows of your changing face;
-
-And bending down beside the glowing bars,
-Murmur, a little sadly, how Love fled
-And paced upon the mountains overhead
-And hid his face amid a crowd of stars.
-
-## The Young Man's Song
-
-I whispered, "I am too young,"
-And then, "I am old enough";
-Wherefore I threw a penny
-To find out if I might love.
-"Go and love, go and love, young man,
-If the lady be young and fair,"
-Ah, penny, brown penny, brown penny,
-I am looped in the loops of her hair.
-
-Oh, love is the crooked thing,
-There is nobody wise enough
-To find out all that is in it,
-For he would be thinking of love
-Till the stars had run away,
-And the shadows eaten the moon.
-Ah, penny, brown penny, brown penny,
-One cannot begin it too soon.
-
-## The Sorrow of Love
-
-The quarrel of the sparrows in the eaves,
-The full round moon and the star-laden sky,
-And the loud song of the ever-singing leaves,
-Had hid away earth's old and weary cry.
-
-And then you came with those red mournful lips,
-And with you came the whole of the world's tears,
-And all the sorrows of her labouring ships,
-And all the burden of her myriad years.
-
-And now the sparrows warring in the eaves,
-The curd-pale moon, the white stars in the sky,
-And the loud chaunting of the unquiet leaves
-Are shaken with earth's old and weary cry.
diff --git a/pages/docs/built-in-components.mdx b/pages/docs/built-in-components.mdx
deleted file mode 100644
index e944c5c..0000000
--- a/pages/docs/built-in-components.mdx
+++ /dev/null
@@ -1,81 +0,0 @@
-# Built-In Components
-
-Some helpful built-in components from `nextra-theme-docs`.
-
-## Callout
-
-import Callout from 'nextra-theme-docs/callout'
-
-#### Example
-
-
- A **callout** is a short piece of text intended to attract attention.
-
-
-
- The **dodo** is an extinct flightless bird that was endemic to the island of Mauritius, east of Madagascar in the Indian Ocean.
-
-
-#### Usage
-
-```mdx
-import Callout from 'nextra-theme-docs/callout'
-
-
- The **dodo** is an extinct flightless bird.
-
-```
-
-## Bleed
-
-import Bleed from 'nextra-theme-docs/bleed'
-
-#### Example
-
-When wrapping your content with ``, it will be slightly wider than the container
-and will overflow on both sides.
-
-
-
- _There is nothing to writing. All you do is sit down at a typewriter and **bleed**._
-
- — Ernest Hemingway
-