Move to custom SSG instead of eleventy.
This commit is contained in:
16
docs/read-page/helpers.js
Normal file
16
docs/read-page/helpers.js
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
export async function contentAsText (doc, rootLevel, includeCurrent = false) {
|
||||
const { level, next, line, head } = doc
|
||||
const linesAsArray = []
|
||||
if (includeCurrent) linesAsArray.push(line())
|
||||
let contentDepth = includeCurrent ? level() : -1
|
||||
|
||||
while(await next(rootLevel)) {
|
||||
if (contentDepth === -1 && !!line()) contentDepth = level()
|
||||
|
||||
const indent = ''.padStart(level() - contentDepth, ' ')
|
||||
linesAsArray.push(indent + line())
|
||||
}
|
||||
|
||||
return linesAsArray.join('\n')
|
||||
}
|
||||
50
docs/read-page/index.js
Normal file
50
docs/read-page/index.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import knownNodes from './nodes/index.js'
|
||||
import { useDocument } from '@terrace-lang/js'
|
||||
import { createFileReader } from '@terrace-lang/js/readers/node-readline'
|
||||
|
||||
export default async function(inputPath) {
|
||||
const doc = useDocument(createFileReader(inputPath))
|
||||
const { next, line, match, tail, level, head } = doc
|
||||
|
||||
const pageData = {
|
||||
type: `Page`,
|
||||
path: inputPath,
|
||||
title: '',
|
||||
description: [],
|
||||
layout: '',
|
||||
headings: [],
|
||||
children: []
|
||||
}
|
||||
|
||||
while(await next()) {
|
||||
if (!line()) continue
|
||||
if (match('title')) pageData.title = tail()
|
||||
else if (match('layout')) pageData.layout = tail()
|
||||
else if (match('description')) {
|
||||
const l = level()
|
||||
while(await next(l)) {
|
||||
pageData.description.push(line(l))
|
||||
}
|
||||
}
|
||||
else if (match('Section')) {
|
||||
pageData.children.push(await knownNodes.Section(doc, level(), pageData))
|
||||
}
|
||||
}
|
||||
|
||||
// Structure headings into tree.
|
||||
pageData.headings.forEach((heading, index) => {
|
||||
let parent = null
|
||||
for (let i = index; i > 0; --i) {
|
||||
if (pageData.headings[i].level === heading.level - 1) {
|
||||
parent = pageData.headings[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (parent) parent.children.push(heading)
|
||||
})
|
||||
|
||||
pageData.headings = pageData.headings.filter(h => h.level === 2)
|
||||
|
||||
return pageData
|
||||
}
|
||||
23
docs/read-page/nodes/Button.js
Normal file
23
docs/read-page/nodes/Button.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { contentAsText } from '../helpers.js'
|
||||
|
||||
export default async function (doc, rootLevel) {
|
||||
const { next, line, match, tail, level, head } = doc
|
||||
|
||||
const node = {
|
||||
type: head(),
|
||||
variant: tail() || 'neutral',
|
||||
class: '',
|
||||
href: '',
|
||||
text: ''
|
||||
}
|
||||
|
||||
while (await next(rootLevel)) {
|
||||
if (match('class')) node.class = tail()
|
||||
else if (match('href')) node.href = tail()
|
||||
else {
|
||||
node.text = await contentAsText(doc, rootLevel, true)
|
||||
}
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
21
docs/read-page/nodes/CodeBlock.js
Normal file
21
docs/read-page/nodes/CodeBlock.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import { contentAsText } from '../helpers.js'
|
||||
|
||||
export default async (doc, rootLevel) => {
|
||||
const { next, level, line, head, tail, match } = doc
|
||||
|
||||
const node = {
|
||||
type: head(),
|
||||
language: tail(),
|
||||
class: '',
|
||||
text: ''
|
||||
}
|
||||
|
||||
while (await next(rootLevel)) {
|
||||
if (match('class')) node.class = tail()
|
||||
else node.text = await contentAsText(doc, rootLevel, true)
|
||||
}
|
||||
|
||||
node.text = node.text.trimEnd()
|
||||
|
||||
return node
|
||||
}
|
||||
32
docs/read-page/nodes/CodeExample.js
Normal file
32
docs/read-page/nodes/CodeExample.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { contentAsText } from '../helpers.js'
|
||||
|
||||
const languages = ['terrace', 'json', 'yaml', 'toml', 'javascript', 'typescript', 'c', 'python', 'sh']
|
||||
|
||||
export default async (doc, rootLevel) => {
|
||||
const { next, level, line, head, tail, match } = doc
|
||||
|
||||
const node = {
|
||||
type: head(),
|
||||
class: '',
|
||||
summaryClass: 'mb-[400px]',
|
||||
preClass: 'max-h-[400px]',
|
||||
examples: []
|
||||
}
|
||||
|
||||
while (await next(rootLevel)) {
|
||||
if (match('class')) node.class = tail()
|
||||
if (match('summary-class')) node.summaryClass = tail()
|
||||
if (match('pre-class')) node.preClass = tail()
|
||||
|
||||
const exampleLevel = level()
|
||||
if (languages.includes(head())) {
|
||||
node.examples.push({
|
||||
language: head(),
|
||||
name: tail() || '',
|
||||
code: (await contentAsText(doc, exampleLevel)).trimEnd('\n')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
21
docs/read-page/nodes/Footer.js
Normal file
21
docs/read-page/nodes/Footer.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import { contentAsText } from '../helpers.js'
|
||||
import { parse } from 'marked'
|
||||
|
||||
const FOOTER_TEXT = `
|
||||
Maintained by the Terrace Team. Find an issue? [Let us know](/issues)!
|
||||
|
||||
Site contents licensed under the [CC BY 3.0 license](https://creativecommons.org/licenses/by/3.0/)<br/>
|
||||
All code examples licensed under the [MIT license](https://opensource.org/licenses/MIT)
|
||||
`
|
||||
|
||||
export default async function (doc, rootLevel) {
|
||||
const { next, line, match, tail, level, head } = doc
|
||||
|
||||
const node = {
|
||||
type: `Markdown`,
|
||||
class: 'text-center mt-32 mx-auto text-neutral-50/75 prose-a:text-primary-100/75',
|
||||
text: parse(FOOTER_TEXT)
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
28
docs/read-page/nodes/Heading.js
Normal file
28
docs/read-page/nodes/Heading.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import slugify from '@sindresorhus/slugify'
|
||||
|
||||
export default async function (doc, rootLevel, pageData) {
|
||||
const { next, line, match, tail, level, head } = doc
|
||||
|
||||
const headingLevel = +tail().split(' ')[0]
|
||||
const text = tail().split(' ').slice(1).join(' ')
|
||||
const slug = slugify(text)
|
||||
|
||||
const node = {
|
||||
type: head(),
|
||||
level: headingLevel,
|
||||
text,
|
||||
slug,
|
||||
class: '',
|
||||
href: '',
|
||||
children: []
|
||||
}
|
||||
|
||||
while (await next(rootLevel)) {
|
||||
if (match('class')) node.class = tail()
|
||||
if (match('href')) node.href = tail()
|
||||
}
|
||||
|
||||
pageData.headings.push(node)
|
||||
|
||||
return node
|
||||
}
|
||||
10
docs/read-page/nodes/Icon.js
Normal file
10
docs/read-page/nodes/Icon.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export default async function (doc) {
|
||||
const { head, tail } = doc
|
||||
|
||||
const node = {
|
||||
type: head(),
|
||||
icon: tail()
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
26
docs/read-page/nodes/Include.js
Normal file
26
docs/read-page/nodes/Include.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useDocument } from '@terrace-lang/js/document'
|
||||
import { createFileReader } from '@terrace-lang/js/readers/node-readline'
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import knownNodes from './index.js'
|
||||
|
||||
export default async function (originalDoc, rootLevel, ...args) {
|
||||
const includedDoc = useDocument(createFileReader(originalDoc.tail()))
|
||||
const { next, head, tail, level } = includedDoc
|
||||
|
||||
const node = {
|
||||
type: originalDoc.head(),
|
||||
class: '',
|
||||
children: []
|
||||
}
|
||||
|
||||
while (await next()) {
|
||||
if (!head()) continue
|
||||
const block = head()
|
||||
|
||||
if (!knownNodes[block]) continue
|
||||
node.children.push(await knownNodes[block](includedDoc, level(), ...args))
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
17
docs/read-page/nodes/Logo.js
Normal file
17
docs/read-page/nodes/Logo.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { contentAsText } from '../helpers.js'
|
||||
|
||||
export default async function (doc, rootLevel) {
|
||||
const { next, line, match, tail, level, head } = doc
|
||||
|
||||
const node = {
|
||||
type: head(),
|
||||
variant: tail() || 'neutral',
|
||||
class: ''
|
||||
}
|
||||
|
||||
while (await next(rootLevel)) {
|
||||
if (match('class')) node.class = tail()
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
19
docs/read-page/nodes/Markdown.js
Normal file
19
docs/read-page/nodes/Markdown.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { contentAsText } from '../helpers.js'
|
||||
import { parse } from 'marked'
|
||||
|
||||
export default async function (doc, rootLevel) {
|
||||
const { next, line, match, tail, level, head } = doc
|
||||
|
||||
const node = {
|
||||
type: head(),
|
||||
class: '',
|
||||
text: ''
|
||||
}
|
||||
|
||||
while (await next(rootLevel)) {
|
||||
if (match('class')) node.class = tail()
|
||||
else node.text = parse(await contentAsText(doc, rootLevel, true))
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
26
docs/read-page/nodes/Node.js
Normal file
26
docs/read-page/nodes/Node.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import knownNodes from './index.js'
|
||||
|
||||
export default async function (doc, rootLevel, ...args) {
|
||||
const { next, line, match, tail, level, head } = doc
|
||||
|
||||
const node = {
|
||||
type: head(),
|
||||
class: '',
|
||||
children: []
|
||||
}
|
||||
|
||||
while (await next(rootLevel)) {
|
||||
if (!head()) continue
|
||||
const block = head()
|
||||
|
||||
if (match('class')) {
|
||||
node.class = tail()
|
||||
continue
|
||||
}
|
||||
|
||||
if (!knownNodes[block]) continue
|
||||
node.children.push(await knownNodes[block](doc, level(), ...args))
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
14
docs/read-page/nodes/TableOfContents.js
Normal file
14
docs/read-page/nodes/TableOfContents.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export default async function (doc, rootLevel) {
|
||||
const { next, head, tail, match } = doc
|
||||
|
||||
const node = {
|
||||
type: head(),
|
||||
class: '',
|
||||
}
|
||||
|
||||
while (await next(rootLevel)) {
|
||||
if (match('class')) node.class = tail()
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
32
docs/read-page/nodes/index.js
Normal file
32
docs/read-page/nodes/index.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import parseNode from './Node.js'
|
||||
import Include from './Include.js'
|
||||
import TableOfContents from './TableOfContents.js'
|
||||
import Heading from './Heading.js'
|
||||
import Button from './Button.js'
|
||||
import Icon from './Icon.js'
|
||||
import Markdown from './Markdown.js'
|
||||
import CodeBlock from './CodeBlock.js'
|
||||
import CodeExample from './CodeExample.js'
|
||||
import Logo from './Logo.js'
|
||||
import Footer from './Footer.js'
|
||||
|
||||
const Block = parseNode
|
||||
const Section = async (doc, rootLevel, ...args) => {
|
||||
const variant = doc.tail()
|
||||
return { variant, ...(await parseNode(doc, rootLevel, ...args)) }
|
||||
}
|
||||
|
||||
export default {
|
||||
Include,
|
||||
TableOfContents,
|
||||
Block,
|
||||
Section,
|
||||
Heading,
|
||||
Button,
|
||||
Icon,
|
||||
Markdown,
|
||||
CodeBlock,
|
||||
CodeExample,
|
||||
Logo,
|
||||
Footer
|
||||
}
|
||||
Reference in New Issue
Block a user