--- .title = "SuperMD Basics", .date = .date("2023-06-16T00:00:00"), .layout = "documentation.shtml", --- # [Intro]($section.id('intro')) **Make sure to read [Scripty Basics]($link.page('docs/scripty')) first.** SuperMD is an extension of Markdown that adds Scripty expression support. There are [plenty](https://github.github.com/gfm/) [of](https://github.com/iamgio/quarkdown) Markdown dialects in the wild that add new syntax to it, and there are also [plenty](https://mdxjs.com/) [of](https://gohugo.io/content-management/shortcodes/) templating languages that allow you to *template* your Markdown content. The issue with the first approach is that new syntax complicates an already overcomplicated language (to parse) and it usually only solves very specific problems. The issue with the second approach is that, while templating (like [Hugo Shortcodes](https://gohugo.io/content-management/shortcodes/)) does allow you to extend Markdown in a very general way, it usually translates into pulling layouting concerns into the content, which is the exact thing we were trying to minimize by writing Markdown in the first place. ## [Two Columns]($section.id('two-columns')) For example let's say that you would like to have the middle section of a page to have a two column layout, this is how you could solve it: - In [CommonMark](https://commonmark.org/) (with inline HTML support enabled): ```markdown
# Left side
# Right side
``` - In [MDX](https://mdxjs.com) *(semi-jokingly)*: ```markdown import { Row, Left, Right } from '@leftpad-inc/two-columns'; # Left Side # Right Side ``` - In Hugo (using [Shortcodes](https://gohugo.io/content-management/shortcodes/)): ```markdown {{< row >}} {{% div %}} # Left Side {{% /div %}}{{% div %}} # Right Side {{% /div %}} {{< /row >}} ``` SuperMD takes a completely different approach by allowing the templating language to access the content in *sections*: ***`two-columns.smd`*** ```markdown # [Left Section]($section.id('left')) Lorem Ipsum # [Right Section]($section.id('right')) Dolor Something Something ``` ***`layout.shtml`*** ```superhtml
``` ## [Design Goals]($section.id('design-goals')) The main design goal of SuperMD is to upgrade Markdown to a full-fledged markup format that is not dependent on HTML. Markdown is [often times](https://buttondown.com/hillelwayne/archive/why-i-prefer-rst-to-markdown/) considered too simplistic for serious markup work (e.g. creating a book) in good part also because of its ties to HTML. SuperMD doesn't allow inlined HTML and instead gives you the ability to define a variety of "embedded assets" through a unified syntax. It is planned for Zine to eventually gain support for generating PDFs (and potentially other file formats), at which point it will be critical for the content markup language to have the ability to define embedded assets (and styling elements) without using HTML as a crutch. ### [Roadmap]($section.id('roadmap')) Compared to other parts of Zine, SuperMD is very new and many parts of it are still in their first design iteration. The general similarity to Markdown is set in stone for SuperMD, but actual CommonMark adherence is not guaranteed. All other file formats in Zine have a parser written from scratch, except SuperMD (which uses [cmark-gfm](https://github.com/kristoff-it/cmark-gfm)) and it might be that at some point we'll switch to a more sane (parsing-wise) language that still has the same general feeling of writing Markdown. ># [Concepts vs Syntax]($block) >We are currently using link syntax for embedding Scripty expressions, but there >are some limitations in how links are defined in the Markdown grammar that are >problematic for our use case. > >As we gain experience and confidence in the direction of the design we will >address syntax concerns more directly. In other words, we're prioritizing the >design of *concepts* and delaying the design of *syntax*. # [File Extension]($section.id('file-extension')) SuperMD files have a `.smd` file extension. # [Developer Tooling]($section.id('devtools')) We don't have yet any developer tooling for SuperMD files, but it's high on our list of priorities. You should expect grammars for syntax highlighting and a language server for immediate feedback on syntax errors. # [Frontmatter]($section.id('frontmatter')) As mentioned in the main documentation page, every SuperMD file in Zine must start with a frontmatter that contains all the metadata relative to the page. SuperMD uses [Ziggy](https://ziggy-lang.io) as its frontmatter data serialization language. This is the full Ziggy Schema for the frontmatter: ***`page.ziggy-schema`*** []($code.siteAsset('page.ziggy-schema').language('ziggy-schema')) The frontmatter data fill become available in SuperHTML inside of instances of [`Page`]($link.page('docs/superhtml/scripty').ref('Page')). # [Markdown Syntax]($section.id('md-syntax')) SuperMD uses [cmark-gfm](https://github.com/kristoff-it/cmark-gfm) so it supports all the common extensions (tables, strikethrough, autolinks, etc) that you can normally find in the wild. Currently SuperMD adds only one new syntactical construct: **a Scripty expression embedded in link syntax**. ***`image example`*** ```markdown []($image.asset('cat.jpg')) ``` In normal Markdown this example would result in a (invalid) link element. In SuperMD the resulting type of that construct depends on the value that the embedded Scripty expression evaluates to. In the previous example the expression evaluates to an [`Image`]($link.page('docs/supermd/scripty').ref('Image')), making it equivalent to the vanilla `![](cat.jpg)`. This might not seem particularly exciting, but things become more interesting once you realize that this way of doing things allows you to easily give `id`s and other attributes to both emdedded assets and pieces of content. ***`image example`*** ```markdown []($image.asset('cat.jpg').id('foo')) ``` ***`rendered html`*** ```html ``` Additionally, it also gives you the ability to define embedded assets that are not supported by Markdown without the help of HTML. For example this how you can define a video embed: ```markdown []($video.asset('video.mp4').loop(true).autoplay(true)) ``` What we described up until now as "emdedded assets", are called "rendering directives" in Zine. Most of them do describe embedded assets, but `$section` (as seen in the two columns example) for example does not. # [Directives]($section.id('directives')) ># [NOTE]($block) >Directives are a very recent addition to Zine and new ones will be >added over time. Make sure to check this page and the Scripty reference whenever >you update Zine. Most Directives are very straight forward to use. The only thing to keep in mind is that calling functions on them sets their internal state in a way that is order-independent (some might call this a *builder pattern* or a *fluent interface*). For example both of these invocations will yield the same final result: ```markdown []($link.page('foo').id('bar')) []($link.id('bar').page('foo')) ``` One last thing to know about Directives is that all allow you to set `id()` and `attrs()` (shorthand for attributes), which will be rendered in HTML as and `id` and a `class` attribute respectively. You can find the full list of available Directives in the [SuperMD Scripty Reference]($link.page('docs/supermd/scripty')). ## [Spaces in SuperMD Directives]($section.id('spaces')) SuperMD is currently built on top of Markdown syntax and as such it has to obey Markdown rules. One situation where this can be source of confusion is when you need to place a space in a Scripty expression, as doing so will cause a parsing error. To be able use spaces you must enclose the expression in diamond brackets, like so: ```markdown Wrong: []($link.page('foo').title('a link to my favorite foo page')) Correct: [](<$link.page('foo').title('a link to my favorite foo page')>) ``` ## [Section Directive]($section.id('section-directive')) The section directive lets you split a page into *content sections*. Doing so has three main benefits: - Creates a container element that groups the section's inner elements, useful for styling purposes. - (when given an id) The ability to deep-link content from other pages while also having the deep-linking be validated by Zine. - (when given an id) The ability to optionally render the page section-by-section, which is critical when the layout needs nuanced control over the content (see the two columns example at the top of this page). ### [Usage]($section.id('usage')) There are two main ways to use the section directive: 1. as a top-level element 2. as a wrapper around the text of a *heading* In both cases the section directive will create a container element that wraps all subsequent markdown content until another Section Directive is found or the document ends. ***`example`*** ```markdown []($section) # First Lorem Ipsum # Second []($image.asset('cat.jpg')) []($section.id('third')) # Third ``` ***`rendered html`*** ```html

First

Lorem Ipsum

Second

Third

``` The second method additionally makes the heading link to the section: ***`example`*** ```markdown # [First]($section.id('first')) Lorem Ipsum ``` ***`rendered html`*** ```html

First

Lorem Ipsum

``` This syntax might seem to suggest that you could create a nested section by attaching it to, say, a `##` heading, but that's not the case. **Heading levels are not taken into consideration when defining sections**. In other words, sections don't nest. You can "attach" a section to a heading of any level, but that will immediately end any previous section. This second way of defining a Section directive can be seen as syntax sugar for: ```markdown []($section.id('first')) # [First]($link.ref('first')) Lorem Ipsum ``` ### [Rendering content sections]($section.id('rendering-content-sections')) The previous examples showcased the result of rendering the page in its entirety, but sections that are given an `id` can also be rendered in isolation. When rendering a section in isolation you are expected to provide the container element in your template. ***`example`*** ```markdown # [First]($section.id('first')) Lorem Ipsum ``` ***`superhtml`*** ```html
``` ***`rendered html`*** ```html

First

Lorem Ipsum

``` # [Vanilla Image and Link Syntax]($section.id('vanilla-syntax')) Using vanilla image / link Markdown syntax in SuperMD is allowed, but the syntax still has to be resolved to a Directive. This means that **you can use vanilla syntax as a shortcut for most common use cases**. ## [Links]($section.id('links')) Full URLs (i.e. inclusive of protocol) map to [`$link.url()`]($link.page('docs/supermd/scripty').ref('Link.url')) and [`$link.new()`]($link.page('docs/supermd/scripty').ref('Link.new')) : ```markdown [Zine](https://zine-ssg.io) └─➤ [Zine]($link.url('https://zine-ssg.io').new(true)) ``` A leading `#` means [`$link.ref()`]($link.page('docs/supermd/scripty').ref('Link.ref')): ```markdown [Docs](#foo) └─➤ [Docs]($link.ref('foo')) ``` A leading `/` means [`$link.page()`]($link.page('docs/supermd/scripty').ref('Link.page')): ```markdown [Docs](/docs/) └─➤ [Docs]($link.page('docs')) ``` A leading `./` means [`$link.sub()`]($link.page('docs/supermd/scripty').ref('Link.sub')): ```markdown [Reference](./scripty) └─➤ [Reference]($link.sub('scripty')) ``` Absence of leading punctuation means [`$link.sibling()`]($link.page('docs/supermd/scripty').ref('Link.sibling')): ```markdown [Reference](superhtml) └─➤ [Reference]($link.sibling('superhtml')) ``` ## [Images]($section.id('images')) Full URLs (i.e. inclusive of protocol) map to [`$image.url()`]($link.page('docs/supermd/scripty').ref('Image.url')): ```markdown ![](https://zine-ssg.io/picture.jpg) └─➤ []($image.url('https://zine-ssg.io/picture.jpg')) ``` ># [Hotlinking]($block.attrs('warning')) >Embedding directly images from the network (sometimes referred to as *hotlinking*) >is frowned upon, unless explicitly endorsed by the target host. > >Additionally, links to remote assets can eventually become *temporarily* or >*permanently* unavailable, making the choice of copying assets locally >preferable in general. A leading `/` means [`$image.siteAsset()`]($link.page('docs/supermd/scripty').ref('Image.siteAsset')): ```markdown ![](/logo.jpg) └─➤ []($image.siteAsset('logo.jpg')) ``` Absence of a leading `/` means [`$image.asset()`]($link.page('docs/supermd/scripty').ref('Image.asset')): ```markdown ![](cat.jpg) └─➤ []($image.asset('cat.jpg')) ``` Additionally, any text put inside of `![]` will be used as a caption, while the Markdown "title" text will be used to fill the `alt` attribute of the image: ```markdown ![Caption](cat.jpg "alt text") └─➤ [Caption]($image.asset('cat.jpg').alt('alt text')) ``` ># [Warning]($block.attrs('warning')) >In Markdown any text inside of `![]` is used as the `alt` attribute, >while the extra string after the image location is used as the `title` >attribute. > >We break compatibility because within `![]` you can use >Markdown syntax to style your captions, which is a capability that >is lost in Markdown since `alt` only accepts simple strings. > >As a consequence of this change, `alt` takes the place of `title` >simply because it's more important. You can still give titles to >images (and more) by using explicit directive syntax, if you so wish. # [Inline HTML Escape Hatch]($section.id('inline-html')) SuperMD forbids inline HTML in order to make it possible to render content files to non-HTML formats. That said, sometimes one only plans to target HTML and would like to be able to embed, say, a YouTube video without too much fuss. For those cases, you can still embed arbitrary HTML in a content page by creating a `=html` code block, like so: ```=html ``` Zine will parse and validate the HTML code before inlining. # [Syntax Highlighting]($section.id('syntax-highlighting')) Zine comes with a [good list](https://github.com/neurocyte/flow-syntax/) of Tree Sitter grammars for syntax highlighting, but not all languages are supported. When a language is not recognized, Zine will produce an error. If you'd like to see support for a new language added to Zine, first find (or write `:^)`) a Tree Sitter grammar for it, and then [let us](/community) know that you'd like to see it added to Zine. In the future Zine will support the ability for users to add grammars independently of the main project. ## Special languages Zine supports some special "meta-languages" that are syntax-highlighted without using tree-sitter. ### `console` For code blocks that represent interaction with a terminal. It only highlights the command prompt. Example: ```console $ ping localhost PING localhost (127.0.0.1): 56 data bytes 64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.072 ms 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.252 ms ^C --- localhost ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.072/0.162/0.252/0.090 ms $ su [root@mymachine]# exit $ shutdown now ``` Recognized prompts: `$`, `#`, `[]$`, `[]#`. You can leverage prompt recognition to implement a "copy this command" button in JS. ### Equal sign Some languages support prefixing their name with a `=` to perform inlining instead of syntax highlighting. Currently supported inlineable languages: - `=html`: inlines the HTML content verbatim, see [the relative FAQ section](/docs/frequent/#inline-html). # [Next Steps]($section.id('next-steps')) - [Read the SuperMD Scripty Reference Documentation](./scripty/) - [Learn more about SuperHTML](superhtml/) - [Learn more about Zine's Asset System](assets/)