Flesh out about page.
This commit is contained in:
parent
8b9a136d88
commit
54ad373744
@ -9,6 +9,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@11ty/eleventy": "^2.0.0",
|
"@11ty/eleventy": "^2.0.0",
|
||||||
"@11ty/eleventy-plugin-vite": "^4.0.0",
|
"@11ty/eleventy-plugin-vite": "^4.0.0",
|
||||||
|
"@sindresorhus/slugify": "^2.2.0",
|
||||||
"@tailwindcss/typography": "^0.5.9",
|
"@tailwindcss/typography": "^0.5.9",
|
||||||
"@terrace/js": "workspace:*",
|
"@terrace/js": "workspace:*",
|
||||||
"eleventy-google-fonts": "^0.1.0",
|
"eleventy-google-fonts": "^0.1.0",
|
||||||
|
@ -10,9 +10,9 @@
|
|||||||
{% eleventyGoogleFonts 'https://fonts.googleapis.com/css2?family=Fredoka:wght@300;400;500&display=swap' %}
|
{% eleventyGoogleFonts 'https://fonts.googleapis.com/css2?family=Fredoka:wght@300;400;500&display=swap' %}
|
||||||
</head>
|
</head>
|
||||||
<body class="text-base">
|
<body class="text-base">
|
||||||
{{ Node('Navbar') }}
|
{{ Node('Navbar', {}, page) }}
|
||||||
{% for child in children %}
|
{% for child in children %}
|
||||||
{{ Node(child.type, child) }}
|
{{ Node(child.type, child, page) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<script type="module" src="/main.js"></script>
|
<script type="module" src="/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{% from "./Node.njk" import Node %}
|
{% from "./Node.njk" import Node %}
|
||||||
|
|
||||||
{% macro render(node) %}
|
{% macro render(node, page) %}
|
||||||
<div class="{{ node.class }}">
|
<div class="{{ node.class }}">
|
||||||
{% for child in node.children %}
|
{% for child in node.children %}
|
||||||
{{ Node(child.type, child) }}
|
{{ Node(child.type, child, page) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% set commonClasses = "px-6 py-2 md:px-12 md:py-3 text-white rounded-md w-auto whitespace-nowrap" %}
|
{% set commonClasses = "px-6 py-2 md:px-12 md:py-3 text-white rounded-md w-auto whitespace-nowrap not-prose" %}
|
||||||
{% macro render(node) %}
|
{% macro render(node) %}
|
||||||
<a
|
<a
|
||||||
href="{{ node.href }}"
|
href="{{ node.href }}"
|
||||||
|
5
docs/src/_includes/nodes/CodeBlock.njk
Normal file
5
docs/src/_includes/nodes/CodeBlock.njk
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{% macro render(node) %}
|
||||||
|
<pre
|
||||||
|
class="my-8 p-4 bg-neutral-900 text-neutral-50 rounded-md whitespace-pre-wrap {{ node.class }}"
|
||||||
|
>{{ node.text | highlight(node.language) | safe }}</pre>
|
||||||
|
{% endmacro %}
|
@ -20,13 +20,20 @@ set languageMeta = {
|
|||||||
onclick="[...this.parentElement.children].forEach(c => (c.open = false))"
|
onclick="[...this.parentElement.children].forEach(c => (c.open = false))"
|
||||||
>
|
>
|
||||||
<summary
|
<summary
|
||||||
class="flex gap-2 items-center px-4 py-2 cursor-pointer text-neutral-50 group-open:text-primary-500 bg-neutral-800 border-b-2 border-b-neutral-50/25 group-open:border-b-primary-600"
|
class="
|
||||||
|
flex gap-2 items-center px-4 py-2 cursor-pointer
|
||||||
|
text-neutral-50 group-open:text-primary-500 bg-neutral-800 border-b-2 border-b-neutral-50/25 group-open:border-b-primary-600
|
||||||
|
h-12 mb-[400px]
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<div class="w-[16px] h-[16px] hidden md:block">{{ languageMeta[id].icon | safe }}</div>
|
<div class="w-[16px] h-[16px] hidden md:block">{{ languageMeta[id].icon | safe }}</div>
|
||||||
{{ languageMeta[id].name }}
|
{{ languageMeta[id].name }}
|
||||||
</summary>
|
</summary>
|
||||||
<pre
|
<pre
|
||||||
class="absolute left-0 right-0 w-full bg-neutral-800 text-neutral-50 p-4 rounded-bl-md rounded-br-md rounded-tr-md whitespace-pre-wrap"
|
class="
|
||||||
|
absolute top-12 left-0 right-0 w-full bg-neutral-900 text-neutral-50 p-4 rounded-bl-md rounded-br-md rounded-tr-md whitespace-pre-wrap
|
||||||
|
max-h-[400px] overflow-x-none overflow-y-auto
|
||||||
|
"
|
||||||
onclick="event.preventDefault(); event.stopPropagation();"
|
onclick="event.preventDefault(); event.stopPropagation();"
|
||||||
>{{ code | highlight(id) | safe }}</pre>
|
>{{ code | highlight(id) | safe }}</pre>
|
||||||
</details>
|
</details>
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
{% macro render(node) %}
|
{% macro render(node) %}
|
||||||
<h{{ node.level }}
|
<h{{ node.level }}
|
||||||
|
id="{{ node.slug }}"
|
||||||
{% if levelClasses[node.level] %}
|
{% if levelClasses[node.level] %}
|
||||||
class="{{ levelClasses[node.level] }} {{ node.class }}"
|
class="{{ levelClasses[node.level] }} {{ node.class }}"
|
||||||
{% endif %}
|
{% endif %}
|
@ -1,9 +1,10 @@
|
|||||||
{% macro render(node) %}
|
{% macro render(node) %}
|
||||||
<div class="
|
<div class="
|
||||||
prose prose-neutral text-base
|
prose text-base
|
||||||
prose-p:mb-2 prose-ul:my-1 prose-ul:pl-0 prose-ul:ml-6
|
prose-p:mb-2 prose-ul:my-1 prose-ul:pl-0 prose-ul:ml-6
|
||||||
md:prose-p:mb-4 md:prose-ul:pl-4 md:prose-ul:ml-2 md:prose-ul:my-2
|
md:prose-p:mb-4 md:prose-ul:pl-4 md:prose-ul:ml-2 md:prose-ul:my-2
|
||||||
prose-li:my-0 prose-a:text-primary-200 text-current {{node.class}}
|
prose-li:my-0 text-current
|
||||||
|
{{node.class}}
|
||||||
">
|
">
|
||||||
{{ node.text | safe }}
|
{{ node.text | safe }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
{% from "./Node.njk" import Node %}
|
{% from "./Node.njk" import Node %}
|
||||||
|
|
||||||
{% macro render(node) %}
|
{{ page | dump }}
|
||||||
|
|
||||||
|
{% macro navlink(href, text, active) %}
|
||||||
|
<a href="{{ href }}" class="flex items-center hover:text-primary-400 {{ 'text-primary-400' if href in active }}">{{ text }}</a>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro render(node, page) %}
|
||||||
<nav class="fixed left-0 right-0 top-0 lg:relative bg-neutral-800 text-neutral-50 h-20 flex items-center z-10">
|
<nav class="fixed left-0 right-0 top-0 lg:relative bg-neutral-800 text-neutral-50 h-20 flex items-center z-10">
|
||||||
<div class="container mx-auto px-8 flex items-center space-between">
|
<div class="container mx-auto px-8 flex items-center space-between">
|
||||||
<a id="nav" class="peer" href="#nav" aria-hidden="true" tabindex="-1"></a>
|
<a id="nav" class="peer" href="#nav" aria-hidden="true" tabindex="-1"></a>
|
||||||
@ -23,9 +29,10 @@
|
|||||||
lg:pointer-events-auto
|
lg:pointer-events-auto
|
||||||
lg:relative lg:top-0 lg:px-0 lg:flex-row lg:flex-1 lg:h-20 lg:bg-neutral-800 lg:text-white
|
lg:relative lg:top-0 lg:px-0 lg:flex-row lg:flex-1 lg:h-20 lg:bg-neutral-800 lg:text-white
|
||||||
">
|
">
|
||||||
<a href="/docs/" class="flex items-center hover:text-primary-400">Docs</a>
|
{{ navlink("/docs/", "Docs", page.url) }}
|
||||||
<a href="/docs/" class="flex items-center hover:text-primary-400">Examples</a>
|
{{ navlink("/examples/", "Examples", page.url) }}
|
||||||
<a href="/about/" class="flex items-center hover:text-primary-400">About</a>
|
{{ navlink("/about/", "About", page.url) }}
|
||||||
|
{{ navlink("/contribute/", "Contribute", page.url) }}
|
||||||
<a href="/docs/" class="flex items-center hover:text-primary-400">Contribute</a>
|
<a href="/docs/" class="flex items-center hover:text-primary-400">Contribute</a>
|
||||||
<div class="-order-1 lg:order-2 flex items-center">{{ Node('SearchBox', { class: 'w-full lg:w-72' }) }}</div>
|
<div class="-order-1 lg:order-2 flex items-center">{{ Node('SearchBox', { class: 'w-full lg:w-72' }) }}</div>
|
||||||
<a href="https://git.thederf.com/thederf/Terrace" target="_blank" class="flex items-center hover:text-primary-400 order-3">
|
<a href="https://git.thederf.com/thederf/Terrace" target="_blank" class="flex items-center hover:text-primary-400 order-3">
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% macro Node(name, params) %}
|
{% macro Node(name, params, page) %}
|
||||||
{% from "./" + name + ".njk" import render %}
|
{% from "./" + name + ".njk" import render %}
|
||||||
{{ render(params) }}
|
{{ render(params, page) }}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
{% from "./Node.njk" import Node %}
|
{% from "./Node.njk" import Node %}
|
||||||
|
|
||||||
{% set variants = {
|
{% set variants = {
|
||||||
light: "bg-gradient-to-b from-neutral-50 to-neutral-50/50",
|
light: "bg-gradient-to-b from-neutral-50 to-neutral-50/50 text-neutral-900",
|
||||||
dark: "bg-gradient-to-b from-neutral-800 to-neutral-900 text-neutral-50"
|
dark: "bg-gradient-to-b from-neutral-800 to-neutral-900 text-neutral-50"
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
{% macro render(node) %}
|
{% macro render(node, page) %}
|
||||||
<svg class="w-full -mt-[55px] {{ 'text-neutral-50' if node.variant == 'light' else 'text-neutral-800' }}" viewBox="0 0 1920 55">
|
<svg class="w-full -mt-[55px] {{ 'text-neutral-50' if node.variant == 'light' else 'text-neutral-800' }}" viewBox="0 0 1920 55">
|
||||||
<path d="M0 55H1920V6.99994C1811 55 1150 55 403.5 6.99994C141.541 -9.84407 0 6.99996 0 55Z" fill="currentColor"/>
|
<path d="M0 55H1920V6.99994C1811 55 1150 55 403.5 6.99994C141.541 -9.84407 0 6.99996 0 55Z" fill="currentColor"/>
|
||||||
</svg>
|
</svg>
|
||||||
<section class="{{ variants[node.variant] }}">
|
<section class="group/{{node.variant}} {{ variants[node.variant] }}">
|
||||||
<div class="{{ node.class }} container mx-auto px-8 pt-16 md:pt-8 pb-32">
|
<div class="{{ node.class }} container mx-auto px-8 pt-16 md:pt-8 pb-32">
|
||||||
{% for child in node.children %}
|
{% for child in node.children %}
|
||||||
{{ Node(child.type, child) }}
|
{{ Node(child.type, child, page) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@ -4,22 +4,230 @@ description
|
|||||||
A simple structured data syntax for configuration, content authoring, and DSLs.
|
A simple structured data syntax for configuration, content authoring, and DSLs.
|
||||||
Terrace gets out of your way to let you just write
|
Terrace gets out of your way to let you just write
|
||||||
|
|
||||||
Section light
|
Section dark
|
||||||
class pt-40 md:pt-32
|
class pt-40 md:pt-32 max-w-prose
|
||||||
|
|
||||||
Header 1 About Terrace
|
Heading 1 About Terrace
|
||||||
|
|
||||||
Markdown
|
Markdown
|
||||||
- Needed a way to define block-based content in plain text
|
Terrace is a tiny system for storing data in human-friendly text files.
|
||||||
- Initially based on S-Expressions
|
|
||||||
- Inspired by Tree Notation & I-Expressions
|
It allows you to mix all sorts of text and data formats together in an intuitive way without getting caught up in syntax pomp and ceremony.
|
||||||
|
|
||||||
|
CodeBlock terrace
|
||||||
|
title An Essay on Rockets
|
||||||
|
date 2022-02-22
|
||||||
|
by John Doe
|
||||||
|
|
||||||
|
heading The ideal rocket equation
|
||||||
|
|
||||||
|
equation LaTeX
|
||||||
|
\Delta v=v_{\text{e}}\ln {\frac {m_{0}}{m_{f}}}=I_{\text{sp}}g_{0}\ln {\frac {m_{0}}{m_{f}}}
|
||||||
|
|
||||||
|
markdown
|
||||||
|
A fundamental equation in astrophysics, the *ideal rocket equation* describes the total potential velocity of an idealized vehicle propelled by expelling some of its own mass.
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
class prose-invert
|
||||||
|
You can use Terrace to write documents, web pages, configuration files, data storage, or whatever else you come up with!
|
||||||
|
|
||||||
|
[This page](https://git.thederf.com/thederf/Terrace/src/branch/main/docs/src/about.tce) is written using Terrace!
|
||||||
|
|
||||||
|
Section light
|
||||||
|
class max-w-prose
|
||||||
|
Heading 2 Background
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
Terrace was originally envisioned out of frustration at the massive usability gulf for embedding custom blocks in simple, human-friendly markup formats such as [Markdown](), and capable but complex block-based systems such as [Project Gutenberg](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/writing-your-first-block-type/) and [Editor.js](https://editorjs.io/saving-data/).
|
||||||
|
|
||||||
|
Heading 3 The Complexity Problem
|
||||||
|
class mt-8 mb-4
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
**A simple markdown document:**
|
||||||
|
|
||||||
|
CodeBlock markdown
|
||||||
|
# My Page Title
|
||||||
|
|
||||||
|
Occaecat fugiat est ullamco aliqua ea dolor nostrud. Reprehenderit nisi minim sit commodo deserunt ullamco deserunt aute ex exercitation Lorem deserunt ad.
|
||||||
|
|
||||||
|
1. Magna id sint consequat quis esse tempor.
|
||||||
|
2. Veniam eu id esse occaecat eu.
|
||||||
|
3. Minim commodo nostrud eiusmod excepteur ea sint in enim esse aliqua.
|
||||||
|
|
||||||
|
[Put my-custom-component here somehow]
|
||||||
|
|
||||||
|
Dolor adipisicing amet aliquip nulla occaecat Lorem excepteur veniam. Voluptate pariatur sint anim tempor aliquip in. Id nulla est irure officia occaecat enim.
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
**That same document in a *simplified* Editor.js schema:**
|
||||||
|
|
||||||
|
CodeBlock javascript
|
||||||
|
class max-h-[500px] overflow-y-auto
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: "header",
|
||||||
|
data: {
|
||||||
|
level: 1,
|
||||||
|
text: "My Page Title"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "paragraph",
|
||||||
|
data: {
|
||||||
|
text: "Occaecat fugiat est ullamco aliqua ea dolor nostrud. Reprehenderit nisi minim sit commodo deserunt ullamco deserunt aute ex exercitation Lorem deserunt ad."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "list",
|
||||||
|
data: {
|
||||||
|
style: "ordered",
|
||||||
|
items: [
|
||||||
|
"Magna id sint consequat quis esse tempor.",
|
||||||
|
"Veniam eu id esse occaecat eu.",
|
||||||
|
"Minim commodo nostrud eiusmod excepteur ea sint in enim esse aliqua."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "my-custom-component",
|
||||||
|
data: {
|
||||||
|
option1: "value",
|
||||||
|
option2: "value",
|
||||||
|
text: "Text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "paragraph",
|
||||||
|
data: {
|
||||||
|
text: "Dolor adipisicing amet aliquip nulla occaecat Lorem excepteur veniam. Voluptate pariatur sint anim tempor aliquip in. Id nulla est irure officia occaecat enim."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Heading 3 MDX & MDC
|
||||||
|
class mt-16 mb-4
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
Other attempts, such as [MDX](https://mdxjs.com/) and [MDC](https://content.nuxtjs.org/guide/writing/mdc/) have been made to solve this problem, allowing you to incorporate complex content *inside* markup documents.
|
||||||
|
|
||||||
|
However, they suffer from a number of problems:
|
||||||
|
|
||||||
|
1. Tightly coupled to the JavaScript ecosystem
|
||||||
|
2. Lock you out of other markup formats, such as [AsciiDoc](https://asciidoc.org/)
|
||||||
|
3. Difficult to parse - Markdown was not intended as a general-purpose syntax
|
||||||
|
4. Data can't be extracted from markup without rendering the entire document to HTML
|
||||||
|
5. Ugly. Just look at this:
|
||||||
|
|
||||||
|
CodeBlock markdown
|
||||||
|
# My Page Title
|
||||||
|
|
||||||
|
Occaecat fugiat est ullamco aliqua ea dolor nostrud. Reprehenderit nisi minim sit commodo deserunt ullamco deserunt aute ex exercitation Lorem deserunt ad.
|
||||||
|
|
||||||
|
1. Magna id sint consequat quis esse tempor.
|
||||||
|
2. Veniam eu id esse occaecat eu.
|
||||||
|
3. Minim commodo nostrud eiusmod excepteur ea sint in enim esse aliqua.
|
||||||
|
|
||||||
|
[MDX Example]
|
||||||
|
<MyCustomComponent option1={{'value'}} option2={{'value'}}>
|
||||||
|
Text
|
||||||
|
</MyCustomComponent>
|
||||||
|
|
||||||
|
[MDC Example]
|
||||||
|
::MyCustomComponent{option1="value", option2="value"}
|
||||||
|
Text
|
||||||
|
::
|
||||||
|
|
||||||
|
|
||||||
|
Dolor adipisicing amet aliquip nulla occaecat Lorem excepteur veniam. Voluptate pariatur sint anim tempor aliquip in. Id nulla est irure officia occaecat enim.
|
||||||
|
|
||||||
|
Heading 3 Terrace Prototype
|
||||||
|
class mt-16 mb-4
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
I first attempted to solve this problem using an [S-Expression](https://en.wikipedia.org/wiki/S-expression)-based syntax for defining blocks.
|
||||||
|
|
||||||
|
CodeBlock lisp
|
||||||
|
(heading
|
||||||
|
(level 1)
|
||||||
|
My Page Title
|
||||||
|
)
|
||||||
|
|
||||||
|
(markdown
|
||||||
|
Occaecat fugiat est ullamco aliqua ea dolor nostrud. Reprehenderit nisi minim sit commodo deserunt ullamco deserunt aute ex exercitation Lorem deserunt ad.
|
||||||
|
|
||||||
|
1. Magna id sint consequat quis esse tempor.
|
||||||
|
2. Veniam eu id esse occaecat eu.
|
||||||
|
3. Minim commodo nostrud eiusmod excepteur ea sint in enim esse aliqua.
|
||||||
|
)
|
||||||
|
|
||||||
|
(my-custom-component
|
||||||
|
(option1 value)
|
||||||
|
(option2 value)
|
||||||
|
Text
|
||||||
|
)
|
||||||
|
|
||||||
|
(markdown
|
||||||
|
Dolor adipisicing amet aliquip nulla occaecat Lorem excepteur veniam. Voluptate pariatur sint anim tempor aliquip in. Id nulla est irure officia occaecat enim.
|
||||||
|
)
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
While quite flexible and clean-looking, problems became apparent with handling whitespace and escaping parenthesis in text.
|
||||||
|
The parser quickly became much more extensive than initially envisioned.
|
||||||
|
|
||||||
|
Nevertheless, it proved the concept that cleanly combining functional blocks and markup text was quite reasonable.
|
||||||
|
|
||||||
|
Not long after, I stumbled upon [Tree Notation](https://treenotation.org) by [Brek Yunits](https://www.breckyunits.com/). Playing around with it, the potential of just *getting rid of the parenthesis* was quite apparent. Simpler syntax for humans to write, and far less work required for parsing & escaping since the only control characters are newlines and spaces:
|
||||||
|
|
||||||
|
CodeBlock terrace
|
||||||
|
heading My Page Title
|
||||||
|
level 1
|
||||||
|
|
||||||
|
markdown
|
||||||
|
Occaecat fugiat est ullamco aliqua ea dolor nostrud. Reprehenderit nisi minim sit commodo deserunt ullamco deserunt aute ex exercitation Lorem deserunt ad.
|
||||||
|
|
||||||
|
1. Magna id sint consequat quis esse tempor.
|
||||||
|
2. Veniam eu id esse occaecat eu.
|
||||||
|
3. Minim commodo nostrud eiusmod excepteur ea sint in enim esse aliqua.
|
||||||
|
|
||||||
|
my-custom-block
|
||||||
|
option1 value
|
||||||
|
option2 value
|
||||||
|
Text
|
||||||
|
|
||||||
|
markdown
|
||||||
|
Dolor adipisicing amet aliquip nulla occaecat Lorem excepteur veniam. Voluptate pariatur sint anim tempor aliquip in. Id nulla est irure officia occaecat enim.
|
||||||
|
|
||||||
|
Markdown
|
||||||
|
Ultimately though, using Tree Notation still proved too messy. After working with the grammar system and spreadsheet-style data model for a good while, my gut said all this use case needed was a simple line-based parser.
|
||||||
|
|
||||||
|
I started Terrace to implement a similar syntax, but with the following goals:
|
||||||
|
|
||||||
|
1. Make as few decisions as possible for the user
|
||||||
|
2. Be as fast, tiny, and light on resources as possible
|
||||||
|
|
||||||
|
Six or seven parser rewrites later, it finally works mostly how I envisioned it. :)
|
||||||
|
|
||||||
Section dark
|
Section dark
|
||||||
Header 2 Development Philosophy
|
class max-w-prose
|
||||||
|
|
||||||
|
Heading 2 Development Goals
|
||||||
|
|
||||||
Markdown
|
Markdown
|
||||||
- No “framework”
|
class prose-invert
|
||||||
- Tiny core, no dependencies
|
Terrace development is guided by the following goals.
|
||||||
- As few rules as possible, let users do what they want
|
|
||||||
- Be memory friendly, don’t do any work you don’t have to
|
- **Tiny, primitive core - no “framework”**
|
||||||
- Use underlying syntax, not custom patterns
|
- Use the most boring patterns possible for implementing the core library.
|
||||||
|
- Avoid dependencies
|
||||||
|
- Easily port Terrace in any language or environment
|
||||||
|
- **Avoid dynamic allocation**
|
||||||
|
- Since we can work directly off of string slices without the need for ASTs and escaping systems, might as well avoid dynamic allocations altogether!
|
||||||
|
- **Minimize assumptions**
|
||||||
|
- Let people use Terrace as a building block for all sorts of languages
|
||||||
|
|
||||||
|
Make note of this before submitting change requests. If your changes don't fit these goals, they may be denied. In which case, you could try building a separate library on top of the Terrace cor.
|
||||||
|
|
||||||
|
Footer
|
||||||
|
@ -5,7 +5,7 @@ description
|
|||||||
Terrace gets out of your way to let you just write
|
Terrace gets out of your way to let you just write
|
||||||
|
|
||||||
Section light
|
Section light
|
||||||
class pt-40 md:pt-32 pb-48 md:pb-64 flex flex-col gap-16 md:flex-row md:gap-48
|
class pt-40 md:pt-36 pb-48 md:pb-64 flex flex-col gap-16 md:flex-row md:gap-48
|
||||||
Block
|
Block
|
||||||
class flex flex-col gap-8 w-full items-start
|
class flex flex-col gap-8 w-full items-start
|
||||||
Logo light
|
Logo light
|
||||||
@ -71,7 +71,7 @@ Section light
|
|||||||
- **just write**"""
|
- **just write**"""
|
||||||
|
|
||||||
Section dark
|
Section dark
|
||||||
Header 2 Uses
|
Heading 2 Uses
|
||||||
|
|
||||||
Block
|
Block
|
||||||
class flex flex-col space-between gap-16 md:flex-row md:gap-48
|
class flex flex-col space-between gap-16 md:flex-row md:gap-48
|
||||||
@ -81,7 +81,7 @@ Section dark
|
|||||||
Block
|
Block
|
||||||
class flex gap-4 items-center mb-4
|
class flex gap-4 items-center mb-4
|
||||||
Icon settings
|
Icon settings
|
||||||
Header 3 Configuration
|
Heading 3 Configuration
|
||||||
class mb-0
|
class mb-0
|
||||||
Markdown
|
Markdown
|
||||||
Terrace’s concise syntax (or lack thereof)
|
Terrace’s concise syntax (or lack thereof)
|
||||||
@ -95,7 +95,7 @@ Section dark
|
|||||||
Block
|
Block
|
||||||
class flex gap-4 items-center mb-4
|
class flex gap-4 items-center mb-4
|
||||||
Icon feather
|
Icon feather
|
||||||
Header 3 Content Authoring
|
Heading 3 Content Authoring
|
||||||
class mb-0
|
class mb-0
|
||||||
Markdown
|
Markdown
|
||||||
An unopinionated, indent-based syntax allows fulls blocks of plain-text or markup languages (such as markdown) to be embedded inside of Terrace documents.
|
An unopinionated, indent-based syntax allows fulls blocks of plain-text or markup languages (such as markdown) to be embedded inside of Terrace documents.
|
||||||
@ -107,7 +107,7 @@ Section dark
|
|||||||
Block
|
Block
|
||||||
class flex gap-4 items-center mb-4
|
class flex gap-4 items-center mb-4
|
||||||
Icon code
|
Icon code
|
||||||
Header 3 Domain-Specific Languages
|
Heading 3 Domain-Specific Languages
|
||||||
class mb-0
|
class mb-0
|
||||||
Markdown
|
Markdown
|
||||||
Terrace documents, at their core, are effectively their own AST (Abstract Syntax Tree). Every time you parse a Terrace document you’ve essentially parsed your own DSL.
|
Terrace documents, at their core, are effectively their own AST (Abstract Syntax Tree). Every time you parse a Terrace document you’ve essentially parsed your own DSL.
|
||||||
@ -119,40 +119,40 @@ Section dark
|
|||||||
See Examples
|
See Examples
|
||||||
|
|
||||||
Section light
|
Section light
|
||||||
Header 2 Core
|
Heading 2 Core
|
||||||
|
|
||||||
Block
|
Block
|
||||||
class flex flex-col space-between gap-16 md:flex-row md:gap-48
|
class flex flex-col space-between gap-16 md:flex-row md:gap-48
|
||||||
|
|
||||||
Block
|
Block
|
||||||
Header 3 Tiny - <strong>Really Tiny</strong>
|
Heading 3 Tiny - <strong>Really Tiny</strong>
|
||||||
class mb-4
|
class mb-4
|
||||||
Markdown
|
Markdown
|
||||||
The C version of the core parser is ~30 lines. Most other implementations are of comparable size.
|
The C version of the core parser is ~30 lines. Most other implementations are of comparable size.
|
||||||
|
|
||||||
Header 3 Easy to Implement
|
Heading 3 Easy to Implement
|
||||||
class mb-4 mt-16
|
class mb-4 mt-16
|
||||||
Markdown
|
Markdown
|
||||||
Need to use Terrace in another runtime? The tiny core and reliance on rudimentary control structures makes that a cinch!
|
Need to use Terrace in another runtime? The tiny core and reliance on rudimentary control structures makes that a cinch!
|
||||||
|
|
||||||
Block
|
Block
|
||||||
Header 3 Zero Dependencies
|
Heading 3 Zero Dependencies
|
||||||
class mb-4
|
class mb-4
|
||||||
Markdown
|
Markdown
|
||||||
All Terrace implementations rely only on the built-ins of their language. The header-only C core has no dependencies, not even libc.
|
All Terrace implementations rely only on the built-ins of their language. The header-only C core has no dependencies, not even libc.
|
||||||
|
|
||||||
Header 3 No Dynamic Memory
|
Heading 3 No Dynamic Memory
|
||||||
class mb-4 mt-16
|
class mb-4 mt-16
|
||||||
Markdown
|
Markdown
|
||||||
Terrace allocates no dynamic memory of its own, working entirely on the stack. A great fit for resource-constrained environments.
|
Terrace allocates no dynamic memory of its own, working entirely on the stack. A great fit for resource-constrained environments.
|
||||||
|
|
||||||
Block
|
Block
|
||||||
Header 3 Unopinionated
|
Heading 3 Unopinionated
|
||||||
class mb-4
|
class mb-4
|
||||||
Markdown
|
Markdown
|
||||||
Terrace makes as few assumptions as possible about how you intend to use it, leaving you with the tools you need to use it as you see fit.
|
Terrace makes as few assumptions as possible about how you intend to use it, leaving you with the tools you need to use it as you see fit.
|
||||||
|
|
||||||
Header 3 Available in 3+ languages
|
Heading 3 Available in 3+ languages
|
||||||
class mb-4 mt-16
|
class mb-4 mt-16
|
||||||
Markdown
|
Markdown
|
||||||
At launch, Terrace has a reference C implementation, a TypeScript/JavaScript implementation, and a Python version available as well. We’ll be adding more as time permits!
|
At launch, Terrace has a reference C implementation, a TypeScript/JavaScript implementation, and a Python version available as well. We’ll be adding more as time permits!
|
||||||
@ -162,7 +162,7 @@ Section light
|
|||||||
Add a Language
|
Add a Language
|
||||||
|
|
||||||
Section dark
|
Section dark
|
||||||
Header 2 Learn More
|
Heading 2 Learn More
|
||||||
|
|
||||||
Block
|
Block
|
||||||
class flex flex-col space-between gap-16 md:flex-row md:gap-48
|
class flex flex-col space-between gap-16 md:flex-row md:gap-48
|
||||||
@ -172,17 +172,17 @@ Section dark
|
|||||||
Block
|
Block
|
||||||
class flex gap-4 items-center mb-4
|
class flex gap-4 items-center mb-4
|
||||||
Icon info
|
Icon info
|
||||||
Header 3 About
|
Heading 3 About
|
||||||
class mb-0
|
class mb-0
|
||||||
Markdown
|
Markdown
|
||||||
Why does Terrace exist? What is it based on? What is the development philosophy?
|
Why does Terrace exist? What is it based on? What are the development goals?
|
||||||
|
|
||||||
Block
|
Block
|
||||||
class max-w-prose
|
class max-w-prose
|
||||||
Block
|
Block
|
||||||
class flex gap-4 items-center mb-4
|
class flex gap-4 items-center mb-4
|
||||||
Icon file-text
|
Icon file-text
|
||||||
Header 3 Documentation
|
Heading 3 Documentation
|
||||||
class mb-0
|
class mb-0
|
||||||
Markdown
|
Markdown
|
||||||
Setup instructions, API documentation, and recipes for how to perform common tasks with Terrace.
|
Setup instructions, API documentation, and recipes for how to perform common tasks with Terrace.
|
||||||
@ -192,14 +192,9 @@ Section dark
|
|||||||
Block
|
Block
|
||||||
class flex gap-4 items-center mb-4
|
class flex gap-4 items-center mb-4
|
||||||
Icon users
|
Icon users
|
||||||
Header 3 Contribute
|
Heading 3 Contribute
|
||||||
class mb-0
|
class mb-0
|
||||||
Markdown
|
Markdown
|
||||||
Join the community! Help out by answering issues, expanding documentation, or building additional language implementations!
|
Join the community! Help out by answering issues, expanding documentation, or building additional language implementations!
|
||||||
|
|
||||||
Markdown
|
Footer
|
||||||
class text-center mt-32 mx-auto text-neutral-50/75 prose-a:text-primary-100/75
|
|
||||||
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)
|
|
||||||
|
19
docs/src/parser/nodes/CodeBlock.js
Normal file
19
docs/src/parser/nodes/CodeBlock.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
const { contentAsText } = require('../helpers')
|
||||||
|
|
||||||
|
module.exports = 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
21
docs/src/parser/nodes/Footer.js
Normal file
21
docs/src/parser/nodes/Footer.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const { contentAsText } = require('../helpers.js')
|
||||||
|
const marked = require('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)
|
||||||
|
`
|
||||||
|
|
||||||
|
module.exports = 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: marked.parse(FOOTER_TEXT)
|
||||||
|
}
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
module.exports = async function (doc, rootLevel) {
|
|
||||||
const { next, line, match, tail, level, head } = doc
|
|
||||||
|
|
||||||
const node = {
|
|
||||||
type: head(),
|
|
||||||
level: tail().split(' ')[0],
|
|
||||||
text: tail().split(' ').slice(1).join(' '),
|
|
||||||
class: ''
|
|
||||||
}
|
|
||||||
|
|
||||||
while (await next(rootLevel)) {
|
|
||||||
if (match('class')) node.class = tail()
|
|
||||||
}
|
|
||||||
|
|
||||||
return node
|
|
||||||
}
|
|
26
docs/src/parser/nodes/Heading.js
Normal file
26
docs/src/parser/nodes/Heading.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
module.exports = async function (doc, rootLevel, pageData) {
|
||||||
|
const slugify = (await import('@sindresorhus/slugify')).default
|
||||||
|
|
||||||
|
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: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
while (await next(rootLevel)) {
|
||||||
|
if (match('class')) node.class = tail()
|
||||||
|
}
|
||||||
|
|
||||||
|
pageData.headings.push(node)
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
@ -12,9 +12,7 @@ module.exports = async function (doc, rootLevel) {
|
|||||||
|
|
||||||
while (await next(rootLevel)) {
|
while (await next(rootLevel)) {
|
||||||
if (match('class')) node.class = tail()
|
if (match('class')) node.class = tail()
|
||||||
else {
|
else node.text = marked.parse(await contentAsText(doc, rootLevel, true))
|
||||||
node.text = marked.parse(await contentAsText(doc, rootLevel, true))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const knownNodes = require('./index.js')
|
const knownNodes = require('./index.js')
|
||||||
|
|
||||||
module.exports = async function (doc, rootLevel) {
|
module.exports = async function (doc, rootLevel, ...args) {
|
||||||
const { next, line, match, tail, level, head } = doc
|
const { next, line, match, tail, level, head } = doc
|
||||||
|
|
||||||
const node = {
|
const node = {
|
||||||
@ -19,7 +19,7 @@ module.exports = async function (doc, rootLevel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!knownNodes[block]) continue
|
if (!knownNodes[block]) continue
|
||||||
node.children.push(await knownNodes[block](doc, level()))
|
node.children.push(await knownNodes[block](doc, level(), ...args))
|
||||||
}
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
const parseNode = require('./Node.js')
|
const parseNode = require('./Node.js')
|
||||||
|
|
||||||
module.exports.Block = parseNode
|
module.exports.Block = parseNode
|
||||||
module.exports.Section = async (doc, rootLevel) => {
|
module.exports.Section = async (doc, rootLevel, ...args) => {
|
||||||
const variant = doc.tail()
|
const variant = doc.tail()
|
||||||
return { variant, ...(await parseNode(doc, rootLevel)) }
|
return { variant, ...(await parseNode(doc, rootLevel, ...args)) }
|
||||||
}
|
}
|
||||||
module.exports.Header = require('./Header.js')
|
module.exports.Heading = require('./Heading.js')
|
||||||
module.exports.Button = require('./Button.js')
|
module.exports.Button = require('./Button.js')
|
||||||
module.exports.Icon = require('./Icon.js')
|
module.exports.Icon = require('./Icon.js')
|
||||||
|
|
||||||
module.exports.Markdown = require('./Markdown.js')
|
module.exports.Markdown = require('./Markdown.js')
|
||||||
|
module.exports.CodeBlock = require('./CodeBlock.js')
|
||||||
module.exports.CodeExample = require('./CodeExample.js')
|
module.exports.CodeExample = require('./CodeExample.js')
|
||||||
module.exports.Logo = doc => ({
|
module.exports.Logo = doc => ({
|
||||||
type: `Logo`,
|
type: `Logo`,
|
||||||
variant: doc.tail() || 'light'
|
variant: doc.tail() || 'light'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
module.exports.Footer = require('./Footer.js')
|
||||||
|
@ -8,6 +8,7 @@ module.exports = async function(doc) {
|
|||||||
title: '',
|
title: '',
|
||||||
description: [],
|
description: [],
|
||||||
layout: '',
|
layout: '',
|
||||||
|
headings: [],
|
||||||
children: []
|
children: []
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ module.exports = async function(doc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (match('Section')) {
|
else if (match('Section')) {
|
||||||
pageData.children.push(await knownNodes.Section(doc, level()))
|
pageData.children.push(await knownNodes.Section(doc, level(), pageData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ const defaultTheme = require('tailwindcss/defaultTheme');
|
|||||||
const colors = require('tailwindcss/colors')
|
const colors = require('tailwindcss/colors')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ['./src/**/*.njk', './src/**/*.tce'],
|
content: ['./src/**/*.js', './src/**/*.njk', './src/**/*.tce'],
|
||||||
theme: {
|
theme: {
|
||||||
colors: {
|
colors: {
|
||||||
...colors,
|
...colors,
|
||||||
|
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
@ -16,6 +16,7 @@ importers:
|
|||||||
specifiers:
|
specifiers:
|
||||||
'@11ty/eleventy': ^2.0.0
|
'@11ty/eleventy': ^2.0.0
|
||||||
'@11ty/eleventy-plugin-vite': ^4.0.0
|
'@11ty/eleventy-plugin-vite': ^4.0.0
|
||||||
|
'@sindresorhus/slugify': ^2.2.0
|
||||||
'@tailwindcss/typography': ^0.5.9
|
'@tailwindcss/typography': ^0.5.9
|
||||||
'@terrace/js': workspace:*
|
'@terrace/js': workspace:*
|
||||||
eleventy-google-fonts: ^0.1.0
|
eleventy-google-fonts: ^0.1.0
|
||||||
@ -27,6 +28,7 @@ importers:
|
|||||||
devDependencies:
|
devDependencies:
|
||||||
'@11ty/eleventy': 2.0.0
|
'@11ty/eleventy': 2.0.0
|
||||||
'@11ty/eleventy-plugin-vite': 4.0.0
|
'@11ty/eleventy-plugin-vite': 4.0.0
|
||||||
|
'@sindresorhus/slugify': 2.2.0
|
||||||
'@tailwindcss/typography': 0.5.9_tailwindcss@3.2.6
|
'@tailwindcss/typography': 0.5.9_tailwindcss@3.2.6
|
||||||
'@terrace/js': link:../packages/js
|
'@terrace/js': link:../packages/js
|
||||||
eleventy-google-fonts: 0.1.0
|
eleventy-google-fonts: 0.1.0
|
||||||
@ -1080,6 +1082,14 @@ packages:
|
|||||||
escape-string-regexp: 4.0.0
|
escape-string-regexp: 4.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@sindresorhus/slugify/2.2.0:
|
||||||
|
resolution: {integrity: sha512-9Vybc/qX8Kj6pxJaapjkFbiUJPk7MAkCh/GFCxIBnnsuYCFPIXKvnLidG8xlepht3i24L5XemUmGtrJ3UWrl6w==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
'@sindresorhus/transliterate': 1.6.0
|
||||||
|
escape-string-regexp: 5.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@sindresorhus/transliterate/0.1.2:
|
/@sindresorhus/transliterate/0.1.2:
|
||||||
resolution: {integrity: sha512-5/kmIOY9FF32nicXH+5yLNTX4NJ4atl7jRgqAJuIn/iyDFXBktOKDxCvyGE/EzmF4ngSUvjXxQUQlQiZ5lfw+w==}
|
resolution: {integrity: sha512-5/kmIOY9FF32nicXH+5yLNTX4NJ4atl7jRgqAJuIn/iyDFXBktOKDxCvyGE/EzmF4ngSUvjXxQUQlQiZ5lfw+w==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@ -1088,6 +1098,13 @@ packages:
|
|||||||
lodash.deburr: 4.1.0
|
lodash.deburr: 4.1.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@sindresorhus/transliterate/1.6.0:
|
||||||
|
resolution: {integrity: sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
escape-string-regexp: 5.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@sinonjs/commons/2.0.0:
|
/@sinonjs/commons/2.0.0:
|
||||||
resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==}
|
resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -2411,6 +2428,11 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/escape-string-regexp/5.0.0:
|
||||||
|
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/esprima/4.0.1:
|
/esprima/4.0.1:
|
||||||
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user