Start working on responsiveness and about page.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
{% set commonClasses = "px-12 py-3 text-white rounded-md w-auto" %}
|
||||
{% set commonClasses = "px-6 py-2 md:px-12 md:py-3 text-white rounded-md w-auto whitespace-nowrap" %}
|
||||
{% macro render(node) %}
|
||||
<a
|
||||
href="{{ node.href }}"
|
||||
|
||||
@@ -12,7 +12,7 @@ set languageMeta = {
|
||||
%}
|
||||
|
||||
{% macro render(node) %}
|
||||
<div class="text-white text-base relative flex w-full">
|
||||
<div class="text-white text-sm md:text-base relative flex w-full {{ node.class }}">
|
||||
{% macro Language(id, code, isFirst) %}
|
||||
<details
|
||||
{{ 'open' if isFirst else '' }}
|
||||
@@ -22,7 +22,7 @@ set languageMeta = {
|
||||
<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"
|
||||
>
|
||||
<div class="w-[16px] h-[16px]">{{ languageMeta[id].icon | safe }}</div>
|
||||
<div class="w-[16px] h-[16px] hidden md:block">{{ languageMeta[id].icon | safe }}</div>
|
||||
{{ languageMeta[id].name }}
|
||||
</summary>
|
||||
<pre
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{% set levelClasses = {
|
||||
'2': 'text-5xl text-transparent bg-clip-text bg-gradient-to-b from-primary-400 to-primary-600 mb-12',
|
||||
'3': 'text-2xl font-light'
|
||||
'1': 'text-5xl text-transparent bg-clip-text bg-gradient-to-b from-primary-400 to-primary-600 mb-12',
|
||||
'2': 'text-4xl text-transparent bg-clip-text bg-gradient-to-b from-primary-400 to-primary-600 mb-12',
|
||||
'3': 'text-lg md:text-2xl font-light'
|
||||
} %}
|
||||
|
||||
{% macro render(node) %}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="flex gap-4 items-center">
|
||||
<img src="/logo.png" class="w-16 h-16" alt=""/>
|
||||
<h1 class="text-5xl text-transparent bg-clip-text bg-gradient-to-b from-primary-400 to-primary-600">Terrace</h1>
|
||||
<img src="/logo.png" class="w-8 h-8 md:w-16 md:h-16" alt=""/>
|
||||
<h1 class="text-xl md:text-5xl text-transparent bg-clip-text bg-gradient-to-b from-primary-400 to-primary-600">Terrace</h1>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
{% macro render(node) %}
|
||||
<div class="prose prose-neutral prose-lg text-base prose-p:mb-4 prose-ul:my-2 prose-ul:list-none prose-li:my-0 prose-a:text-primary-200 text-current {{node.class}}">
|
||||
<div class="
|
||||
prose prose-neutral text-base
|
||||
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
|
||||
prose-li:my-0 prose-a:text-primary-200 text-current {{node.class}}
|
||||
">
|
||||
{{ node.text | safe }}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,21 +1,44 @@
|
||||
{% from "./Node.njk" import Node %}
|
||||
|
||||
{% macro render(node) %}
|
||||
<nav class="relative bg-neutral-800 text-neutral-50 h-20 flex items-center">
|
||||
<div class="container mx-auto flex items-center space-between">
|
||||
<a href="/" class="w-full">
|
||||
<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">
|
||||
<a id="nav" class="peer" href="#nav" aria-hidden="true" tabindex="-1"></a>
|
||||
|
||||
<div class="absolute z-10 bg-neutral-800 w-full h-full top-0 left-0 lg:hidden"></div>
|
||||
|
||||
<a href="/" class="relative w-full z-20">
|
||||
{{ Node('Logo', { variant: 'small' }) }}
|
||||
</a>
|
||||
<div class="flex gap-8 items-stretch">
|
||||
<a href="/docs" class="flex items-center hover:text-primary-400">Docs</a>
|
||||
<a href="/docs" class="flex items-center hover:text-primary-400">Examples</a>
|
||||
<a href="/docs" class="flex items-center hover:text-primary-400">About</a>
|
||||
<a href="/docs" class="flex items-center hover:text-primary-400">Contribute</a>
|
||||
{{ Node('SearchBox', { class: 'w-72' }) }}
|
||||
<a href="https://git.thederf.com/thederf/Terrace" target="_blank" class="flex items-center hover:text-primary-400">
|
||||
{{ Node('Icon', { icon: 'github' }) }}
|
||||
|
||||
<div class="
|
||||
group
|
||||
fixed flex flex-col gap-8 items-stretch w-full bg-neutral-800 text-neutral-50 top-20 bottom-0 left-0 px-7
|
||||
transition-transform
|
||||
-translate-y-full
|
||||
pointer-events-none
|
||||
peer-target:translate-y-0
|
||||
peer-target:pointer-events-auto
|
||||
lg:translate-y-0
|
||||
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
|
||||
">
|
||||
<a href="/docs/" class="flex items-center hover:text-primary-400">Docs</a>
|
||||
<a href="/docs/" class="flex items-center hover:text-primary-400">Examples</a>
|
||||
<a href="/about/" class="flex items-center hover:text-primary-400">About</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>
|
||||
<a href="https://git.thederf.com/thederf/Terrace" target="_blank" class="flex items-center hover:text-primary-400 order-3">
|
||||
{{ Node('Icon', { icon: 'github' }) }}<div class="ml-4 lg:hidden">Code</div>
|
||||
</a>
|
||||
</div>
|
||||
<a href="#nav" title="Open Menu" class="absolute right-4 flex peer-target:hidden lg:hidden h-16 w-16 items-center justify-center z-20">
|
||||
{{ Node('Icon', { icon: 'menu' }) }}
|
||||
</a>
|
||||
|
||||
<a href="#" title="Close Menu" class="absolute right-4 hidden peer-target:flex lg:hidden lg:peer-target:hidden h-16 w-16 items-center justify-center text-primary-500 z-20">
|
||||
{{ Node('Icon', { icon: 'x' }) }}
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% from "./Node.njk" import Node %}
|
||||
|
||||
{% macro render(node) %}
|
||||
<div class="{{ node.class }} flex gap-4 px-4 py-2 rounded-md border-2 border-neutral-50/75 focus-within:border-primary-400 focus-within:text-primary-400 bg-transparent text-neutral-50">
|
||||
<div class="flex gap-4 px-4 py-2 rounded-md border-2 border-neutral-50/75 focus-within:border-primary-400 focus-within:text-primary-400 bg-transparent text-neutral-50 {{ node.class }}">
|
||||
<input type="text" placeholder="Search" class="w-full bg-transparent outline-none"/>
|
||||
{{ Node('Icon', { icon: 'search' }) }}
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<path d="M0 55H1920V6.99994C1811 55 1150 55 403.5 6.99994C141.541 -9.84407 0 6.99996 0 55Z" fill="currentColor"/>
|
||||
</svg>
|
||||
<section class="{{ variants[node.variant] }}">
|
||||
<div class="container mx-auto pt-8 pb-32 {{ node.class }}">
|
||||
<div class="{{ node.class }} container mx-auto px-8 pt-16 md:pt-8 pb-32">
|
||||
{% for child in node.children %}
|
||||
{{ Node(child.type, child) }}
|
||||
{% endfor %}
|
||||
|
||||
25
docs/src/about.tce
Normal file
25
docs/src/about.tce
Normal file
@@ -0,0 +1,25 @@
|
||||
layout layout.njk
|
||||
title About - Terrace - A simple structured data language
|
||||
description
|
||||
A simple structured data syntax for configuration, content authoring, and DSLs.
|
||||
Terrace gets out of your way to let you just write
|
||||
|
||||
Section light
|
||||
class pt-40 md:pt-32
|
||||
|
||||
Header 1 About Terrace
|
||||
|
||||
Markdown
|
||||
- Needed a way to define block-based content in plain text
|
||||
- Initially based on S-Expressions
|
||||
- Inspired by Tree Notation & I-Expressions
|
||||
|
||||
Section dark
|
||||
Header 2 Development Philosophy
|
||||
|
||||
Markdown
|
||||
- No “framework”
|
||||
- Tiny core, no dependencies
|
||||
- As few rules as possible, let users do what they want
|
||||
- Be memory friendly, don’t do any work you don’t have to
|
||||
- Use underlying syntax, not custom patterns
|
||||
@@ -5,11 +5,12 @@ description
|
||||
Terrace gets out of your way to let you just write
|
||||
|
||||
Section light
|
||||
class pt-32 pb-64 flex gap-48
|
||||
Div
|
||||
class pt-40 md:pt-32 pb-48 md:pb-64 flex flex-col gap-16 md:flex-row md:gap-48
|
||||
Block
|
||||
class flex flex-col gap-8 w-full items-start
|
||||
Logo light
|
||||
Markdown
|
||||
class prose-ul:list-none
|
||||
A simple structured data syntax for
|
||||
- **Configuration**
|
||||
- **Content authoring**
|
||||
@@ -22,6 +23,7 @@ Section light
|
||||
Get Started
|
||||
|
||||
CodeExample
|
||||
class min-h-[350px]
|
||||
terrace
|
||||
title Terrace - A simple structured data language
|
||||
description
|
||||
@@ -71,12 +73,12 @@ Section light
|
||||
Section dark
|
||||
Header 2 Uses
|
||||
|
||||
Div
|
||||
class flex gap-48 space-between
|
||||
Block
|
||||
class flex flex-col space-between gap-16 md:flex-row md:gap-48
|
||||
|
||||
Div
|
||||
Block
|
||||
class max-w-prose
|
||||
Div
|
||||
Block
|
||||
class flex gap-4 items-center mb-4
|
||||
Icon settings
|
||||
Header 3 Configuration
|
||||
@@ -88,9 +90,9 @@ Section dark
|
||||
|
||||
If you wish, you can build in your own input validation and type casting while parsing configuration files.
|
||||
|
||||
Div
|
||||
Block
|
||||
class max-w-prose
|
||||
Div
|
||||
Block
|
||||
class flex gap-4 items-center mb-4
|
||||
Icon feather
|
||||
Header 3 Content Authoring
|
||||
@@ -100,9 +102,9 @@ Section dark
|
||||
|
||||
This enables effortless mixing of data, prose, and functional blocks in human-written documents. No more need for clumsy frontmatter or custom Markdown extensions!
|
||||
|
||||
Div
|
||||
Block
|
||||
class max-w-prose
|
||||
Div
|
||||
Block
|
||||
class flex gap-4 items-center mb-4
|
||||
Icon code
|
||||
Header 3 Domain-Specific Languages
|
||||
@@ -119,10 +121,10 @@ Section dark
|
||||
Section light
|
||||
Header 2 Core
|
||||
|
||||
Div
|
||||
class flex gap-48 space-between
|
||||
Block
|
||||
class flex flex-col space-between gap-16 md:flex-row md:gap-48
|
||||
|
||||
Div
|
||||
Block
|
||||
Header 3 Tiny - <strong>Really Tiny</strong>
|
||||
class mb-4
|
||||
Markdown
|
||||
@@ -133,7 +135,7 @@ Section light
|
||||
Markdown
|
||||
Need to use Terrace in another runtime? The tiny core and reliance on rudimentary control structures makes that a cinch!
|
||||
|
||||
Div
|
||||
Block
|
||||
Header 3 Zero Dependencies
|
||||
class mb-4
|
||||
Markdown
|
||||
@@ -144,7 +146,7 @@ Section light
|
||||
Markdown
|
||||
Terrace allocates no dynamic memory of its own, working entirely on the stack. A great fit for resource-constrained environments.
|
||||
|
||||
Div
|
||||
Block
|
||||
Header 3 Unopinionated
|
||||
class mb-4
|
||||
Markdown
|
||||
@@ -162,12 +164,12 @@ Section light
|
||||
Section dark
|
||||
Header 2 Learn More
|
||||
|
||||
Div
|
||||
class flex gap-48 space-between
|
||||
Block
|
||||
class flex flex-col space-between gap-16 md:flex-row md:gap-48
|
||||
|
||||
Div
|
||||
Block
|
||||
class max-w-prose
|
||||
Div
|
||||
Block
|
||||
class flex gap-4 items-center mb-4
|
||||
Icon info
|
||||
Header 3 About
|
||||
@@ -175,9 +177,9 @@ Section dark
|
||||
Markdown
|
||||
Why does Terrace exist? What is it based on? What is the development philosophy?
|
||||
|
||||
Div
|
||||
Block
|
||||
class max-w-prose
|
||||
Div
|
||||
Block
|
||||
class flex gap-4 items-center mb-4
|
||||
Icon file-text
|
||||
Header 3 Documentation
|
||||
@@ -185,9 +187,9 @@ Section dark
|
||||
Markdown
|
||||
Setup instructions, API documentation, and recipes for how to perform common tasks with Terrace.
|
||||
|
||||
Div
|
||||
Block
|
||||
class max-w-prose
|
||||
Div
|
||||
Block
|
||||
class flex gap-4 items-center mb-4
|
||||
Icon users
|
||||
Header 3 Contribute
|
||||
|
||||
16
docs/src/parser/helpers.js
Normal file
16
docs/src/parser/helpers.js
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
module.exports.contentAsText = async function(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')
|
||||
}
|
||||
23
docs/src/parser/nodes/Button.js
Normal file
23
docs/src/parser/nodes/Button.js
Normal file
@@ -0,0 +1,23 @@
|
||||
const { contentAsText } = require('../helpers.js')
|
||||
|
||||
module.exports = 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
|
||||
}
|
||||
24
docs/src/parser/nodes/CodeExample.js
Normal file
24
docs/src/parser/nodes/CodeExample.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const { contentAsText } = require('../helpers')
|
||||
|
||||
const languages = ['terrace', 'json', 'yaml', 'toml', 'javascript', 'typescript', 'c', 'python']
|
||||
|
||||
module.exports = async (doc, rootLevel) => {
|
||||
const { next, level, line, head, tail, match } = doc
|
||||
|
||||
const node = {
|
||||
type: head(),
|
||||
class: '',
|
||||
languages: {}
|
||||
}
|
||||
|
||||
while (await next(rootLevel)) {
|
||||
if (match('class')) node.class = tail()
|
||||
|
||||
const languageLevel = level()
|
||||
if (languages.includes(head())) {
|
||||
node.languages[head()] = await contentAsText(doc, languageLevel)
|
||||
}
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
16
docs/src/parser/nodes/Header.js
Normal file
16
docs/src/parser/nodes/Header.js
Normal file
@@ -0,0 +1,16 @@
|
||||
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
|
||||
}
|
||||
10
docs/src/parser/nodes/Icon.js
Normal file
10
docs/src/parser/nodes/Icon.js
Normal file
@@ -0,0 +1,10 @@
|
||||
module.exports = async function (doc) {
|
||||
const { head, tail } = doc
|
||||
|
||||
const node = {
|
||||
type: head(),
|
||||
icon: tail()
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
21
docs/src/parser/nodes/Markdown.js
Normal file
21
docs/src/parser/nodes/Markdown.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const { contentAsText } = require('../helpers.js')
|
||||
const marked = require('marked')
|
||||
|
||||
module.exports = 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 = marked.parse(await contentAsText(doc, rootLevel, true))
|
||||
}
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
26
docs/src/parser/nodes/Node.js
Normal file
26
docs/src/parser/nodes/Node.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const knownNodes = require('./index.js')
|
||||
|
||||
module.exports = async function (doc, rootLevel) {
|
||||
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()))
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
17
docs/src/parser/nodes/index.js
Normal file
17
docs/src/parser/nodes/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const parseNode = require('./Node.js')
|
||||
|
||||
module.exports.Block = parseNode
|
||||
module.exports.Section = async (doc, rootLevel) => {
|
||||
const variant = doc.tail()
|
||||
return { variant, ...(await parseNode(doc, rootLevel)) }
|
||||
}
|
||||
module.exports.Header = require('./Header.js')
|
||||
module.exports.Button = require('./Button.js')
|
||||
module.exports.Icon = require('./Icon.js')
|
||||
|
||||
module.exports.Markdown = require('./Markdown.js')
|
||||
module.exports.CodeExample = require('./CodeExample.js')
|
||||
module.exports.Logo = doc => ({
|
||||
type: `Logo`,
|
||||
variant: doc.tail() || 'light'
|
||||
})
|
||||
32
docs/src/parser/page.js
Normal file
32
docs/src/parser/page.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const knownNodes = require('./nodes/index.js')
|
||||
|
||||
module.exports = async function(doc) {
|
||||
const { next, line, match, tail, level, head } = doc
|
||||
|
||||
const pageData = {
|
||||
type: `Page`,
|
||||
title: '',
|
||||
description: [],
|
||||
layout: '',
|
||||
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()))
|
||||
}
|
||||
}
|
||||
|
||||
console.dir(pageData, { depth: null })
|
||||
|
||||
return pageData
|
||||
}
|
||||
BIN
docs/src/public/favicon.ico
Normal file
BIN
docs/src/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
Reference in New Issue
Block a user