Flesh out about page.

This commit is contained in:
Joshua Bemenderfer 2023-02-14 15:04:12 -05:00
parent 8b9a136d88
commit 54ad373744
23 changed files with 379 additions and 80 deletions

View File

@ -9,6 +9,7 @@
"devDependencies": {
"@11ty/eleventy": "^2.0.0",
"@11ty/eleventy-plugin-vite": "^4.0.0",
"@sindresorhus/slugify": "^2.2.0",
"@tailwindcss/typography": "^0.5.9",
"@terrace/js": "workspace:*",
"eleventy-google-fonts": "^0.1.0",

View File

@ -10,9 +10,9 @@
{% eleventyGoogleFonts 'https://fonts.googleapis.com/css2?family=Fredoka:wght@300;400;500&display=swap' %}
</head>
<body class="text-base">
{{ Node('Navbar') }}
{{ Node('Navbar', {}, page) }}
{% for child in children %}
{{ Node(child.type, child) }}
{{ Node(child.type, child, page) }}
{% endfor %}
<script type="module" src="/main.js"></script>
</body>

View File

@ -1,9 +1,9 @@
{% from "./Node.njk" import Node %}
{% macro render(node) %}
{% macro render(node, page) %}
<div class="{{ node.class }}">
{% for child in node.children %}
{{ Node(child.type, child) }}
{{ Node(child.type, child, page) }}
{% endfor %}
</div>
{% endmacro %}

View File

@ -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) %}
<a
href="{{ node.href }}"

View 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 %}

View File

@ -20,13 +20,20 @@ set languageMeta = {
onclick="[...this.parentElement.children].forEach(c => (c.open = false))"
>
<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>
{{ languageMeta[id].name }}
</summary>
<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();"
>{{ code | highlight(id) | safe }}</pre>
</details>

View File

@ -6,6 +6,7 @@
{% macro render(node) %}
<h{{ node.level }}
id="{{ node.slug }}"
{% if levelClasses[node.level] %}
class="{{ levelClasses[node.level] }} {{ node.class }}"
{% endif %}

View File

@ -1,9 +1,10 @@
{% macro render(node) %}
<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
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 }}
</div>

View File

@ -1,6 +1,12 @@
{% 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">
<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>
@ -23,9 +29,10 @@
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>
{{ navlink("/docs/", "Docs", page.url) }}
{{ navlink("/examples/", "Examples", page.url) }}
{{ navlink("/about/", "About", page.url) }}
{{ navlink("/contribute/", "Contribute", page.url) }}
<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">

View File

@ -1,4 +1,4 @@
{% macro Node(name, params) %}
{% macro Node(name, params, page) %}
{% from "./" + name + ".njk" import render %}
{{ render(params) }}
{{ render(params, page) }}
{% endmacro %}

View File

@ -1,19 +1,19 @@
{% from "./Node.njk" import Node %}
{% 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"
}
%}
{% 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">
<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] }}">
<section class="group/{{node.variant}} {{ variants[node.variant] }}">
<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) }}
{{ Node(child.type, child, page) }}
{% endfor %}
</div>
</section>

View File

@ -4,22 +4,230 @@ 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
Section dark
class pt-40 md:pt-32 max-w-prose
Header 1 About Terrace
Heading 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
Terrace is a tiny system for storing data in human-friendly text files.
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
Header 2 Development Philosophy
class max-w-prose
Heading 2 Development Goals
Markdown
- No “framework”
- Tiny core, no dependencies
- As few rules as possible, let users do what they want
- Be memory friendly, dont do any work you dont have to
- Use underlying syntax, not custom patterns
class prose-invert
Terrace development is guided by the following goals.
- **Tiny, primitive core - no “framework”**
- 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

View File

@ -5,7 +5,7 @@ description
Terrace gets out of your way to let you just write
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
class flex flex-col gap-8 w-full items-start
Logo light
@ -71,7 +71,7 @@ Section light
- **just write**"""
Section dark
Header 2 Uses
Heading 2 Uses
Block
class flex flex-col space-between gap-16 md:flex-row md:gap-48
@ -81,7 +81,7 @@ Section dark
Block
class flex gap-4 items-center mb-4
Icon settings
Header 3 Configuration
Heading 3 Configuration
class mb-0
Markdown
Terraces concise syntax (or lack thereof)
@ -95,7 +95,7 @@ Section dark
Block
class flex gap-4 items-center mb-4
Icon feather
Header 3 Content Authoring
Heading 3 Content Authoring
class mb-0
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.
@ -107,7 +107,7 @@ Section dark
Block
class flex gap-4 items-center mb-4
Icon code
Header 3 Domain-Specific Languages
Heading 3 Domain-Specific Languages
class mb-0
Markdown
Terrace documents, at their core, are effectively their own AST (Abstract Syntax Tree). Every time you parse a Terrace document youve essentially parsed your own DSL.
@ -119,40 +119,40 @@ Section dark
See Examples
Section light
Header 2 Core
Heading 2 Core
Block
class flex flex-col space-between gap-16 md:flex-row md:gap-48
Block
Header 3 Tiny - <strong>Really Tiny</strong>
Heading 3 Tiny - <strong>Really Tiny</strong>
class mb-4
Markdown
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
Markdown
Need to use Terrace in another runtime? The tiny core and reliance on rudimentary control structures makes that a cinch!
Block
Header 3 Zero Dependencies
Heading 3 Zero Dependencies
class mb-4
Markdown
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
Markdown
Terrace allocates no dynamic memory of its own, working entirely on the stack. A great fit for resource-constrained environments.
Block
Header 3 Unopinionated
Heading 3 Unopinionated
class mb-4
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.
Header 3 Available in 3+ languages
Heading 3 Available in 3+ languages
class mb-4 mt-16
Markdown
At launch, Terrace has a reference C implementation, a TypeScript/JavaScript implementation, and a Python version available as well. Well be adding more as time permits!
@ -162,7 +162,7 @@ Section light
Add a Language
Section dark
Header 2 Learn More
Heading 2 Learn More
Block
class flex flex-col space-between gap-16 md:flex-row md:gap-48
@ -172,17 +172,17 @@ Section dark
Block
class flex gap-4 items-center mb-4
Icon info
Header 3 About
Heading 3 About
class mb-0
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
class max-w-prose
Block
class flex gap-4 items-center mb-4
Icon file-text
Header 3 Documentation
Heading 3 Documentation
class mb-0
Markdown
Setup instructions, API documentation, and recipes for how to perform common tasks with Terrace.
@ -192,14 +192,9 @@ Section dark
Block
class flex gap-4 items-center mb-4
Icon users
Header 3 Contribute
Heading 3 Contribute
class mb-0
Markdown
Join the community! Help out by answering issues, expanding documentation, or building additional language implementations!
Markdown
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)
Footer

View 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
}

View 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
}

View File

@ -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
}

View 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
}

View File

@ -12,9 +12,7 @@ module.exports = async function (doc, rootLevel) {
while (await next(rootLevel)) {
if (match('class')) node.class = tail()
else {
node.text = marked.parse(await contentAsText(doc, rootLevel, true))
}
else node.text = marked.parse(await contentAsText(doc, rootLevel, true))
}
return node

View File

@ -1,6 +1,6 @@
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 node = {
@ -19,7 +19,7 @@ module.exports = async function (doc, rootLevel) {
}
if (!knownNodes[block]) continue
node.children.push(await knownNodes[block](doc, level()))
node.children.push(await knownNodes[block](doc, level(), ...args))
}
return node

View File

@ -1,17 +1,20 @@
const parseNode = require('./Node.js')
module.exports.Block = parseNode
module.exports.Section = async (doc, rootLevel) => {
module.exports.Section = async (doc, rootLevel, ...args) => {
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.Icon = require('./Icon.js')
module.exports.Markdown = require('./Markdown.js')
module.exports.CodeBlock = require('./CodeBlock.js')
module.exports.CodeExample = require('./CodeExample.js')
module.exports.Logo = doc => ({
type: `Logo`,
variant: doc.tail() || 'light'
})
module.exports.Footer = require('./Footer.js')

View File

@ -8,6 +8,7 @@ module.exports = async function(doc) {
title: '',
description: [],
layout: '',
headings: [],
children: []
}
@ -22,7 +23,7 @@ module.exports = async function(doc) {
}
}
else if (match('Section')) {
pageData.children.push(await knownNodes.Section(doc, level()))
pageData.children.push(await knownNodes.Section(doc, level(), pageData))
}
}

View File

@ -2,7 +2,7 @@ const defaultTheme = require('tailwindcss/defaultTheme');
const colors = require('tailwindcss/colors')
module.exports = {
content: ['./src/**/*.njk', './src/**/*.tce'],
content: ['./src/**/*.js', './src/**/*.njk', './src/**/*.tce'],
theme: {
colors: {
...colors,

22
pnpm-lock.yaml generated
View File

@ -16,6 +16,7 @@ importers:
specifiers:
'@11ty/eleventy': ^2.0.0
'@11ty/eleventy-plugin-vite': ^4.0.0
'@sindresorhus/slugify': ^2.2.0
'@tailwindcss/typography': ^0.5.9
'@terrace/js': workspace:*
eleventy-google-fonts: ^0.1.0
@ -27,6 +28,7 @@ importers:
devDependencies:
'@11ty/eleventy': 2.0.0
'@11ty/eleventy-plugin-vite': 4.0.0
'@sindresorhus/slugify': 2.2.0
'@tailwindcss/typography': 0.5.9_tailwindcss@3.2.6
'@terrace/js': link:../packages/js
eleventy-google-fonts: 0.1.0
@ -1080,6 +1082,14 @@ packages:
escape-string-regexp: 4.0.0
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:
resolution: {integrity: sha512-5/kmIOY9FF32nicXH+5yLNTX4NJ4atl7jRgqAJuIn/iyDFXBktOKDxCvyGE/EzmF4ngSUvjXxQUQlQiZ5lfw+w==}
engines: {node: '>=10'}
@ -1088,6 +1098,13 @@ packages:
lodash.deburr: 4.1.0
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:
resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==}
dependencies:
@ -2411,6 +2428,11 @@ packages:
engines: {node: '>=10'}
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:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}