secst
Version:
SECST is a semantic, extensible, computational, styleable tagged markup language. You can use it to joyfully create compelling, interactive documents backed by HTML.
961 lines (736 loc) • 74.3 kB
Plain Text
:header[:p({align:"left"})[:a(.#the-joy-of-secst)[SECST] Markup Language] :p({align:"right"})[:a(https://github.com/anywhichway/secst)[GitHub]]]
:footer[:p({align:"left"})[Copyright 2022, AnyWhichWay LLC]]
:section[
:h[The Joy of SECST]
:abbr[SECST] (:strong[S]emantic, :strong[E]xtensible, :strong[C]omputational, :strong[S]tyleable, :strong[T]agged) is a more expressive, but easy to learn and use, alternative to Markdown. It provides these features and more:
:ul[
- Support for almost all HTML tags :a(.#tags)[and then some...], with :a(.#theme)[themes and styles].
- :a(.#tables-of-contents)[Table of contents], :a(.#footnotes)[footnote], :a(.#hashtags)[hashtag] and :a(.#mentions)[social media] support.
- Reactive :a(.#values-and-formulas)[formulas and data import] that are as simple as Excel formulas, e.g. :code[:value[2 * 2]] = :value[2 * 2].
- SEO optimization via server rendering with JSON-LD :a(.#structured-data)[structured data] for both content generation and layout.
]
Use SECST to joyfully create compelling, interactive HTML documents.
This is the source for the introduction above:
:code({language:"secst"})[
:abbr[SECST] (:strong[S]emantic, :strong[E]xtensible, :strong[C]omputational, :strong[S]tyleable, :strong[T]agged) is a more expressive, but easy to learn and use, alternative to Markdown. It provides these features and more:
:ul[
- Support for almost all HTML tags :a(.#tags)[and then some...], with :a(.#theme)[themes and styles].
- :a(.#tables-of-contents)[Table of contents], :a(.#footnotes)[footnote], :a(.#hashtags)[hashtag] and :a(.#mentions)[social media] support.
- Reactive :a(.#values-and-formulas)[formulas and data import] that are as simple as Excel formulas, e.g. :code[:value[2 * 2]] = :value[2 * 2].
- SEO optimization via server rendering with JSON-LD :a(.#structured-data)[structured data] for both content generation and layout.
]
Use SECST to joyfully create compelling, interactive HTML documents.
]
]
:section[
:toc(toggle)[Table Of Contents]
]
:section[
:h[About This Guide]
The SECST language, reference HTML transpiler and runtime support implementations are currently in :strong[ALPHA]. Most, but not all, documented features are implemented, testing is far from complete and resource sizes have not been fully optimized.
This site's navigation, footnotes, computations, special styles like :kbd[Key] formatting and imported data are built entirely using SECST markup.
You can tap on the icon next to a heading to access a table of contents at any time. You can goto the top of the guide by tapping of SECST in the top left corner.
This guide is comprehensive, which may make it a little overwhelming. However, SECST has been designed so that you can start using it just a few tags and capabilities at a time.
The following order of learning is suggested:
:ol[
:li[Use tags that support markup similar to :a(.#basic-markdown)[Markdown].]
:li[Start leveraging attributes like :code[align] on :a(.#images)[img].]
:li[Try :a(.#theme)[themes or styles].]
:li[If you are into music, math, or chemistry try :a(.#sheet-music)[:code[sheetMusic]] or :a(.#latex)[:code[Latex]].]
:li[Add some simple :a(.#values-and-formulas)[values and formulas].]
- Anything else that gives you joy!
]
For gentle overviews see the Medium and Hackernoon articles:
:ul[
:li[:a(https://medium.com/@anywhichway/the-joy-of-secst-markup-333d16263225?sk=2f2c7ea14e3086e093b00ca7bec5252d)[Medium:The Joy of SECST Markup]]
:li[:a(https://hackernoon.com/the-joy-of-using-secst-markup)[Hackernoon:The Joy of Using SECST Markup]]
]
]
:section[
:h[Why Another Language]
:dl[
:dt[Semantic Tag]
:dd[A tag that has meaning beyond that used to facilitate document layout and style.]
:dd[:code[<b>] for bold is not semantic, but :code[<strong>] for indicating importance and rendering as bold is semantic.]
]
:section[
:h[HTML and Markdown Issues]
:ul[
:li[HTML is verbose as a result of the need for matching open and close named tags.]
:li[Markdown's goal is simplicity, for which it sacrifices a lot of expressive power. This sacrifice is the result of a non-uniform, non-semantic syntax used to support its simplicity.]
:li[Ensuring that HTML documents are meaningful for textual analysis or supportive of assistive software is hard.]
:li[Markdown is not semantic, you must learn the different annotations to format your document and the resulting HTML is not necessarily meaningful to textual analysis or assistive software. When Markdown initially had a very limited number of ways to format documents, its syntax was a benefit, for some it is now becoming a burden.]
:li[Some Markdown syntax is invisible, e.g. spaces for line breaks]
:li[The built-in self creating document navigation capabilities of HTML and Markdown are limited.]
:li[Using HTML's computational capabilities, i.e. JavaScript, requires programming skills.]
:li[Markdown provides no intrinsic computational capability. You must use something like Jupyter Notebook to support computation.]
:li[Markdown provides no way to bundle assets for delivery. HTML supports asset bundling through the use of data URLs, but it is rather obscure and not automatic.]
:li[Both HTML and Markdown are require specialized programming skills to extend.]
:li[HTML's legacy allows the creation of documents with security flaws.]
]
]
:section[
:h[SECST Benefits]
:ul[
:li[A consistent, uniform compact representation. Where SECST can become verbose, it has shorthand notation similar to Markdown.]
:li[Semantic tags, which make it easier to learn and remember than Markdown and encourages more meaningful documents than straight HTML. Many tags are named after their semantic HTML counterparts to make SECST easier to learn, maintain, and extend.]
:li[Enforcement of required attributes and valid values for proper behavior or accessibility reasons.]
:li[Extensive, built-in :a(.#tables-of-contents)[document navigation] for tables of contents and footnotes (more than Markdown).]
:li[Using SECST's built-in :a({href:"#values-and-formulas"})[computational capability] for math and text expressions is no harder than writing Excel formulas.]
:li[A predominantly declarative extension technique make SECTS easier to extend than HTML. Expertise in programming custom elements is not required.]
:li[Asset bundling via the use of the attribute :code[static] on :code[audio], :code[img], :code[video] and :code[value] tags.]
:li[SECST is easier to extend than Markdown. Expertise in parsers or regular expressions is not required.]
:li[SECST is translated to safe HTML constructs to limit the chance of XSS and other attacks.]
]
]
]
:section[
:h[When To Use SECST]
If you only need basic Markdown, then SECST is probably not for you.
If you need extended Markdown, then SECST may be a good option.
If you need more than Markdown, then SECST may be your only option short of HTML, CSS, and JavaScript so long as you are focused on interactive document authoring. If you are building an application use Svelte, VUE, React or some other framework.
:section[
:h[Basic Markdown]
See :a[https://www.markdownguide.org/basic-syntax/].
:table[
:thead[
Document Item | Markdown | SECST | Example
]
:tr[
headings | :td[:code[h# heading text]] :td[:code[h#[heading text]]] :td[]
]
:tr[
bold | :td[:code[**text**]] :td[:code[:strong[text]]] :td[:strong[text]]
]
:tr[
italics | :td[:code[*text*]] :td[:code[:em[text]]] :td[:em[text]]
]
:tr[
blockquote | :td[:code[> quote text]] :td[:code[:blockquote[quote text]]] :td[]
]
:tr[
nested blockquote | :td[:code[> quote text] :kbd[Enter] :code[>> nested quote text]] :td[:code[:blockquote[quote text :blockquote[nested quote text]]]] :td[]
]
:tr[
code | :td[:code['the code']] :td[:code[:code[the code]]] :td[:code[the code]]
]
:tr[
horizontal rule | :td[:code[***]] :td[:code[:hr]] :td[]
]
:tr[
newline | a new line | :td[a new line or :code[:br]] :td[]
]
:tr[
paragraph | two new lines, i.e. an empty line | :td[two new lines or :code[:p[<content>...]]] :td[]
]
]
Where SECST can become un-necessarily verbose, e.g. lists items and table cells, it has shorthand notation similar to Markdown.
Also see :a({href:"#lists"})[Lists], :a({href:"#code"})[Code], :a({href:"#links"})[Links], :a({href:"#images"})[Images].
]
:section[
:h[Extended Markdown]
See :a[https://www.markdownguide.org/extended-syntax/].
:table[
:thead[
Document Item | Markdown | SECST | Example
]
:tr[
:td[:a(.#footnotes)[footnotes]] :td[:code[[number]]] :td[:code[:footnote[number] or :footnote[] for automatic numbering]] :td[]
]
:tr[
heading ids | :td[:code[# My Heading {#my-id}]] :td[:code[:h1(#my-id)[My Heading]]] :td[]
]
:tr[
definition lists | :td[see :a({href:"#definition-lists"})[definition lists]] :td[] :td[]
]
:tr[
strikethrough | :td[:code[~~struck out~~]] :td[:code[:strike[struck out]]] :td[:strike[struck out]]
]
:tr[
task lists | :td[see :a({href:"#task-lists"})[task lists]] :td[] :td[]
]
:tr[
emojis | :td[:code[:]:code[emoji-name:]] :td[:code[:emoji[emoji-name]]] :td[:emoji[smile]]
]
:tr[
highlight | :td[:code[==marked words==]] :td[:code[:mark[marked words]]] :td[:mark[marked words]]
]
:tr[
subscript | :td[:code[H~2~O]] :td[:code[H:sub[2]0]] :td[H:sub[2]0]
]
:tr[
superscript | :td[:code[X^2^]] :td[:code[X:sup[2]]] :td[X:sup[2]]
]
:tr[
automatic URL linking | :td[:code[https://my.url.com]] :td[:code[:a[https://my.url.com]]]
]
]
]
:section[
:h[Markdown Gaps]
:ul[
:li[:a({href:"#hashtags"})[hashtags]]
:li[:a({href:"#audio"})[audio]]
:li[:a({href:"#video"})[video]]
:li[:ins[inserted] and :del[deleted], see :a({href:"inserted-and-deleted"})[inserted and deleted]]
:li[:a({href:"#tables-of-contents"})[tables of contents]]
:li[:a({href:"#social-media-and-other-mentions"})[social media and other mentions]]
]
]
]
:section[
:h[Authoring]
Authors write documents using semantic tags with the format :code[<tag>[<content>]] or :code[<tag>(<parameters>)[<content>]].
For example:
:ul[
:li[:code[:strong[bolded important content]] produces :strong[bolded important content]]
:li[:code[:em[italicized emphasized content]] produces :em[italicized emphasized content]]
]
:section[
:h[Markup Tags With HTML Names]
Almost every semantic tag supported by HTML5 is one of the :a({href:"#tags"})[tags supported by SECST]. Most non-semantic tags are excluded from SECST, e.g. :code[<div>] and :code[<span>]. Exceptions are :code[<hr>], :code[<table>], :code[<ol>], :code[<ul>] and :code[<style>]; however, since they are so commonly used :code[:b[]] for :b[bold] and :code[:i[]] for :i[italic] are included, as are aliases :code[:bold[]] and :code[:italic[]].
A few tags of note are documented below to illustrate the use of SECST or highlight special features.
:section[
:h[Tags of Note]
:section[
:h[Paragraph]
SECST will treat two newlines in sequence as a paragraph break. There is also a paragraph tag :code[:p[]]. Newlines inside a :code[p] tag will produce separate HTML :code[<br>] elements. A :code[:p[]] tag is not strictly necessary for really simple content. A SECST parser/transpiler will do a reasonable job of figuring out where paragraph breaks are required; however behavior may vary from implementation to implementation.
If you get an unexpected document layout, try putting content inside a :code[:p[]] tag.
]
:section[
:h[Code]
Contents wrapped in :code[:code[]] will be inline unless the contents contain a newline, in which case the code will be displayed in block format.
If you have a single line you wish to show as a block, end it with a newline.
]
:section[
:h[Headings]
Headings automatically get ids you can use for the destination of links. The id is the same as the text content in lower case with spaces and special characters replaced by dashes. To make it more convenient, you can also provide your own ids, e.g. :code[:h1(#myheading)[My Heading]] with link :code[:a({href:"#myheading"})[Go To My Heading]].
:em[Note: All tags can optionally take an id starting with :code[#]. If an id is present, it must be the first parameter.]
]
:section[
:h[Hyperlinks]
Sometimes, e.g. with hyperlinks, you need to specify more than content. This is provided using an attribute block in parentheses, e.g.
:code[:a({href:"./index.txt",target:"_tab"})[SECST]] yields :a({href:"./index.txt",target:"_tab"})[SECST] , where you can access the source of this document.
For convenience, any tag that can accept a url (either :code[src] or :code[href] in HTML) does not require the attribute, just provide the URL. And, single quotes can be used for attribute values, e.g.
:code[:a(./index.txt {target:'_tab'})[SECST]] yields :a(./index.txt {target:'_tab'})[SECST].
You can also use document ids prefixed with a period as targets, e.g. :code[.#headings] for this section. The period prefix is necessary to distinguish from providing an id for the link itself.
You can also specify hyperlinks with just a content value, e.g. :code[:a({target:"_tab"})[./index.txt]] renders as :a({target:"_tab"})[./index.txt].
By default, relative URLS and ids, i.e. those starting with a period, have a target that is the current window or tab. And, those starting with a protocol, e.g. :code[https://] have a target of a new tab.
All tags that take more than just content are fully documented in the :a({href:"#tags"})[complete list of tags].
]
:section[
:h[Lists]
:section[
:h[Unordered And Ordered Lists]
Both ordered and unordered lists are supported using :code[ol] and :code[ul] tags with :code[li] tags.
:code[:ul[:li[LinkedIn] :li[Facebook] :li[Twitter]]]
:ul[
:li[LinkedIn]
:li[Facebook]
:li[Twitter]
]
There is also a shorthand:
:code[
:ul[
- LinkedIn
- Facebook
- Twitter
]
]
The same shorthand also works for :code[ol]. Since SECST already knows the list is ordered, numbers are inserted. The main utility of using numbers, is to reset numbering:
:code[
:ol[
2. LinkedIn
- Facebook
- Twitter
]
]
:ol[
2. LinkedIn
- Facebook
- Twitter
]
The standard HTML attributes for configuring ordered lists, :code[reversed], :code[start], :code[type] are :a(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol)[also supported].
:code[
:ol({type:"a"})[
- LinkedIn
- Facebook
- Twitter
]
]
:ol({type:"a"})[
- LinkedIn
- Facebook
- Twitter
]
]
:section[
:h[Description Lists]
Definition lists follow the :a(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl)[MDN documentation] for their parallel HTML tags except non-semantic tags can't be used.
:code[
:dl[
:dt[Beast of Bodmin]
:dd[A large feline inhabiting Bodmin Moor.]
:dt[Morgawr]
:dd[A sea serpent.]
:dt[Owlman]
:dd[A giant owl-like creature.]
]
]
:dl[
:dt[Beast of Bodmin]
:dd[A large feline inhabiting Bodmin Moor.]
:dt[Morgawr]
:dd[A sea serpent.]
:dt[Owlman]
:dd[A giant owl-like creature.]
]
]
:section[
:h[Task Lists]
]
]
:section[
:h[Meta Tags]
The :code[:meta[]] tag inserts values into the head of a document. It takes the form :code[:meta({name:"my-name"})[my value]], e.g. :code[:meta({name:"author"})[John Jones]] injects the HTML :transpiled[:meta({name:"author"})[John Jones]].
Suggested meta tag names include:
:ul({title:"suggested meta tag names"})[
- :em[keywords], comma separated key words, but consider using :a({href:"#hashtags"})[Hashtags]
- :em[description] for a description of the document
- :em[publisher] for the publisher of the document
- :em[author] for the author of the document
- :em[copyright] for a copyright notice of the document
- :em[robots] with the comma separated values of :code[index] or :code[noindex] and :code[follow] or :code[nofollow].
]
Also see the section :a(.#structured-data)[Structured Data] under :a(.#seo)[SEO].
]
:section[
:h[Multimedia]
:section[
:h[Images]
Since SECST has a focus on semantics, images must be specified with alt text braces, even if they contain no content.
:code[:img(static ./anywhichway_mobius_138.png)] will not transpile.
Images can be loaded statically at transpile time and delivered bundled into the output HTML.
:ul[
:li[The tag :code[:img(static ./anywhichway_mobius_138.png)[Test]]]
:li[renders as :img(static ./anywhichway_mobius_138.png)[Test]]
:li[instead of a reference there is a data url in :code[src] attribute of the :details[:summary[generated HTML.] :transpiled[:img(static ./anywhichway_mobius_138.png)[Test]]]]
]
If static loading fails, the standard link will stay in place and dynamic loading may still render the image.
The callout for the generated HTML above is implemented using the :a({href:"#details"})[details tag].
]
:section[
:h[Audio]
]
:section[
:h[Video]
]
]
]
:section[
:h[HTML Entities and Special Characters]
:a(https://www.toptal.com/designers/htmlarrows/)[Toptal] has a great reference for this.
Special characters and symbols can be displayed using either :code[&<character-id>]:code[;] or :code[:&[<character-id>...]]. The second form can display multiple characters or symbols, just leave off the leading "&" and trailing ";" in the listed items.
The code :code[☻] renders as ☻ .
The code :code[:&[female male #9893]] renders as :&[female male #9893].
]
:section[
:h[Other Tags]
:section[
:h[Inserted And Deleted]
:code[:ins[inserted]] renders as :ins[inserted]
:code[:del[deleted]] renders as :del[deleted]
]
:section[
:h[Details]
The :code[:details[]] tag supports the conditional display of content. It has one required sub-tag :code[:summary[<short text>]] and the rest of the content is conditionally displayed. If a :code[summary] tag is missing, then the first word is used as the summary.
:code[:details[:summary[See the content...] Hello there!]] renders as :details[:summary[See the content...] Hello there!]
:code[:details[... Hello there!]] renders as :details[... Hello there!]
]
]
]
:section[
:h[Markup Without HTML Names]
:section[
:h[Hashtags]
Hashtags can take the form :code[#<value>[]] or :code[#[<value>...]], or :code[:hashtag[<value>...]] where :code[<value>...] is a space separated list of words to hashtag. The short form :strong[MUST] be followed by :code[[]] to distinguish them from ids used to identify :code[:value[]] and other tags in the document.
:code[#sects-is-great[]] renders as #sects-is-great[].
:code[#[sects-is-great javascript-is-great]] renders as #[sects-is-great javascript-is-great].
:code[:hashtag[sects-is-great javascript-is-great]] renders as :hashtag[sects-is-great javascript-is-great].
Hashtags are automatically added to the meta tags in the head of a document for indexing and SEO purposes.
]
:section[
:h[Emojis]
Emojis can take the form :code[:emoji[<emoji-name>...]], where :code[<emoji-name>...] is a space separated list of emoji names.
There are over 1,800 emojis. If a match for the emoji name can't be found, it is displayed as plain text.
See :a(https://missiveapp.com/open/emoji-mart)[EmjoiMart] to find just the right emoji.
:code[:emoji[smile]] renders as :smile:.
:code[:emoji[smile frowning jumping]] renders as :emoji[smile frowning jumping].
Most emoji's are colored. You can use grayscale emojis by providing the attribute :code[grayscale].
:code[:emoji(grayscale)[smile]] renders as :emoji(grayscale)[smile].
:code[:emoji(grayscale)[smile frowning jumping]] renders as :emoji(grayscale)[smile frowning jumping].
]
:section[
:h(#tables-of-contents)[Tables of Contents]
Tables of contents are placed at the location of the tag :code[toc[<title>]]. The :code[:toc[]] tag should occur at the same level, i.e. outside of, :code[:section[]].
If you do not provide a title, "Table of Contents" is used. All content after the tag is analyzed for sections with a heading as the first child tag. These are used for the table.
Levels are determined based on section nesting. You can use the heading tag :code[:h[]] that has no number and the headings will be automatically sized.
Only the first occurrence of :code[toc] is used, others are ignored.
After transpilation, each heading in the document will have an :&[#9783] icon preceding it. When this icon is clicked, the table of contents will hover over the heading until something in the document is clicked.
Each heading will have up and down arrows placed after it to facilitate jumping to the previous and next section.
The tag can take the boolean attribute :code[toggle] to collapse the table of contents into an :a(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details)[HTML details element].
]
:section[
:h[Footnotes/Endnotes]
Footnotes are inserted with the :code[:footnote[<footnote-text>]] tag. The content between the braces is used as the footnote and placed at the end of the document. Auto-numbering is done so that authors do not have to keep updating footnotes as the document changes. :footnote(#markdown-footnote)[Markdown does not autonumber footnotes, which makes them hard to maintain. Although, it does create back-references.]
The source for the above footnote is:
:code[
:footnote(#markdown-footnote)[Markdown does not autonumber footnotes, which makes them hard to maintain. Although, it does create back-references.]
].
To re-use a footnote, give the first occurrence an id. Then, give the subsequent uses an :code[href] attribute or shorthand relative URL reference using the id and leave the content section between the braces empty. This will override the anchors for numbered links generated by the SECST transpiler, but not break ordering. :footnote(.#markdown-footnote)[] If you do provide content when reusing, it will be ignored.
The source for the second footnote is: :code[:footnote(.#markdown-footnote)].
And, here is a third, :code[:footnote[Footnote management does not get much easier!]], that just gets numbered. :footnote[Footnote management does not get much easier!]
]
:section[
:h[forEach]
The :code[:forEach[]] tag supports repeating content based on an iterable object, typically an array or the results of using a CSS selector to gather values from a document.
The variables :code[item], :code[index], :code[iterable] are available to string template literals in the content.
:code[
:ol[
:forEach({iterable:["a","b","c"]})[
:li[${item} at ${index}]
]
]
]
renders as
:ol[
:forEach({iterable:["a","b","c"]})[:li[${item} at ${index}]]
]
:code[
:value(#a hidden literal)[a] :value(#b hidden literal)[b] :value(#c hidden litral)[c]
:ol[
:forEach({iterable:"#a, #b, #c"})[
:li[${item} at ${index}]
]
]
]
renders as :value(#a hidden literal)[a] :value(#b hidden literal)[b] :value(#c hidden literal)[c]
:ol[
:forEach({iterable:"#a, #b, #c"})[:li[${item} at ${index}]]
]
]
:macro({name:"profile",tag:"p",contentAllowed:true})[
:em[${name}]
:em[${age}]
]
:section[
:h[Macros]
New tags can be defined in the content of any document through the use of macros.
A macro takes a :code[name] attribute, which will be the new tag name and a :code[tag] attribute which will be the top level tag to use for replacing the macro tag.
The content of the macro is used as a substitute for the macro. The content can contain variables that are populated based on the attributes provided to the new tag when it is used.
An optional attribute :code[contentAllowed] specifies if instances of the macro tag can provide content to append at the end.
:code[
:macro({name:"profile",tag:"p",contentAllowed:true})[
:em[${name}]
:em[${age}]
]
:profile({name:"joe",age:26})[Hi there ${name}!]
]
renders as
:profile({name:"joe",age:26})[Hi there ${name}!]
]
:section[
:h[Questions]
Questions can be used to create a quiz like experience.
:code[
:question({type:"number",showanswer:true})[
:text[What is the :code[sqrt(4)]?]
:answer[sqrt(4)]
]
]
renders as:
:question({type:"number",showanswer:true})[
:text[What is the :code[sqrt(4)]?]
:answer[sqrt(4)]
]
Clicking on the ✓ or leaving the input field tests the answer. If incorrect, the question will be surrounded with a red box based on the style :code[secst-error].
Questions take most of the same type attribute values as :a(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input)[input]. They can also take the attribute :code[showanswer:true] if the correct answer is supposed to be shown after a user provides the wrong response.
Questions have two required content tags, :code[:text[<question-body>]] and :code[:answer[<some-formula>]], that must be provided in order. The :code[<question-body>] can be just about any content that would normally go in a paragraph. Formulas are :a(.#values-and-formulas)[documented later]. The :code[:answer[]] tag can also take the attribute :code[literal], e.g. :code[:answer(literal)[2]].
]
:section[
:h[Theme]
If a :code[:theme[]] tag with a URL or :code[:link]] content exists in document, then the default theme of :a(./assets/themes/secst.css {target:"_tab"})[sects.css] is not applied.
The theme :code[:theme(./assets/themes/html.css)[]] provides only those styles dependent on the :code[.secst] class. Default browser HTML styling is used elsewhere. It is kind of ugly!
The content of a theme can be any tag, except most have a special interpretation. The tag content is the CSS to apply to the tag, e.g. :code[:theme[:p[border:solid black 1px;]]] will put a black border around all paragraphs.
The theme content tags permitted but not treated in a special way are :code[:link[]], :code[:style[]], and :code[:class[]] (which is unique to :code[:theme[]]).
The tag :code[:class[]] takes a name attribute (without a prefixed period) and the content is the CSS, e.g. :code[:theme[:class({name:"italic-paragraph"})[font-style:italic;]]] creates a class :code[.italic-paragraph].
Theme tags can exist as :a(.#body-content)[Body Content] or :a(.#block-content)[Block Content]. They should be placed as close to the top of the document as possible.
Themes can be scoped using the scope attribute, the value of which is a CSS selector string, e.g. :code[:theme({scope:#special-section})[:p[border:solid black 1px;]]] will only put borders around paragraphs that are inside a :code[:section(#special-section)[]].
:code[
:theme[:class({name:"italic-paragraph"})[font-style:italic;]]
:theme({scope:"#special-section"})[:p[border:solid black 1px;]]
:section[
:p(.italic-paragraph)[Italic paragraph with no border.]
]
:section(#special-section)[
:p[Paragraph with border.]
]
]
renders as
:theme[:class({name:"italic-paragraph"})[font-style:italic;]]
:theme({scope:"#special-section"})[:p[border:solid black 1px;]]
:section[
:p(.italic-paragraph)[Italic paragraph with no border]
]
:section(#special-section)[
:p[Paragraph with border]
]
]
:section[
:h[Transpiled SECST]
The HTML of transpiled SECST can be displayed as plain text, e.g. :code[:transpiled[:strong[test]]] renders as :transpiled[:strong[test]].
If you desire the transpiled code to be displayed as a block, end the content between the :code[[]] with a newline.
]
]
:section[
:h(#mentions)[Social Media And Other Mentions]
Several platforms provide :code[@mention] capability, but only for their users, e.g. GitHub and StackExchange. SECST allows you to mention people on any platform, although they do not get notified.
Mentions take the form :code[@<platform>[<space separated profile-names>]]. The target for mentions will always be another browser tab, unless a :code[target] attribute is provided.
The mark-up :code[@github[anywhichway]] renders as @github[anywhichway].
Alternatively you can name the user and provide your own content, e.g. :code[@github({user:"anywhichway"})[AnyWhichWay]] renders as @github({user:"anywhichway"})[AnyWhichWay].
The supported platforms are:
:ul[
- LinkedIn
- Facebook
- GitHub
- Twitter
]
]
:section[
:h[Latex]
Math and chemical formulas can be displayed using the :code[:latex[]] tag.
:code({language:"latex"})[:latex[Lift = \frac{1}{2} \rho v^2 S C_L]] renders as :latex[Lift = \frac{1}{2} \rho v^2 S C_L]
:code({language:"latex"})[:latex[\ce{CO2 + C -> 2 CO}]] renders as :latex[\ce{CO2 + C -> 2 CO}]
To display the generated formula as a block, end the content between the :code[[]] with a newline.
]
:section[
:h[Mermaid Chart]
:code[:mermaidChart[]] is a block level element, it belongs outside of paragraphs. Just provide :a(https://mermaid.js.org/intro/)[Mermaid notation] as the content.
:code[
:mermaidChart[
graph LR
A --- B
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner);
]
]
renders as
:mermaidChart[
graph LR
A --- B
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner);
]
There are lots of charts to choose from:
:ul[
- :a(https://mermaid.js.org/syntax/flowchart.html)[Flowchart]
- :a(https://mermaid.js.org/syntax/sequenceDiagram.html)[Sequence Diagram]
- :a(https://mermaid.js.org/syntax/classDiagram.html)[Class Diagram]
- :a(https://mermaid.js.org/syntax/stateDiagram.html)[State Diagram]
- :a(https://mermaid.js.org/syntax/entityRelationshipDiagram.html)[Entity Relationship Diagram]
- :a(https://mermaid.js.org/syntax/userJourney.html)[User Journey]
- :a(https://mermaid.js.org/syntax/gantt.html)[Gannt]
- :a(https://mermaid.js.org/syntax/pie.html)[Pie Chart]
- :a(https://mermaid.js.org/syntax/requirementDiagram.html)[Requirement Diagram]
- :a(https://mermaid.js.org/syntax/gitgraph.html)[Gitgraph Diagram]
- :a(https://mermaid.js.org/syntax/c4c.html)[C4C Diagram]
- :a(https://mermaid.js.org/syntax/mindmap.html)[Mindmaps]
]
]
:section[
:h(#sheet-music)[Sheet Music (ABC Notation)]
:code[:sheetMusic[]] is a block level element, it belongs outside of paragraphs. Just provide :a(https://abcnotation.com/examples)[ABC notation] as the content.
:code[
:sheetMusic[
X: 1
T: Nokia Tune
M: 3/4
L: 1/8
K: Amaj
|: e'd' f2 g2 | c'b d2 e2 | ba c2 e2 | a6 |
]
]
renders as
:sheetMusic[
X: 1
T: Nokia Tune
M: 3/4
L: 1/8
K: Amaj
|: e'd' f2 g2 | c'b d2 e2 | ba c2 e2 | a6 |
]
If you drop the :code[:] from the second position in the last line, the play button will disappear.
:code[
:sheetMusic[
X:1
T: Paper
K:D
| DDAA | BBA2|
]
]
renders as
:sheetMusic[
X:1
T: Paper
K:D
| DDAA | BBA2|
]
]
:section[
:h[Escaping SECST]
SECST tagging inside of :code[:code[]] is automatically escaped. If you wish to escape it elsewhere use the tag :code[:escape[]].
:code[:code[:strong[text]]] renders as :code[:strong[text]].
:code[:escape[:strong[text]]] renders as :escape[:strong[text]].
]
]
:section[
:h[Values and Formulas]
SECST supports the tag :code[:value[]] for adding reactive variables and formulas to documents.
:ul[
- The value of a :code[:value[]] is the content, i.e the text between the :code[[]]. It should be either a literal value or a formula, e.g. :code[:value[2 * 2]] = :value[2 * 2].
- By default values are visible. Use the boolean attribute :code[hidden] to hide them, e.g. :code[:value(hidden)[2 * 2]] = :value(hidden)[2 * 2].
- So that readers know the value may be computed, computed ones are rendered as disabled, readonly input. To render them as plaintext use the attribute :code[plaintext], e.g. :code[:value(plaintext)[2 * 2]] = :value(plaintext)[2 * 2].
- To make a value editable by readers, use the attribute :code[editable], e.g. code[:value(editable)[2 * 2]] = :value(editable)[2 * 2].
- Everything between the :code[[]] is treated as a formula for evaluation, if your readers may be entering formula like text and you do not want it evaluated, use the attribute :code[literal], e.g. :code[:value(literal)[2 *2]] = :value(literal)[2 * 2].
- If values are not given a :code[title] attribute, e.g. :code[:value({title:"Two times two"})[2 * 2]], then the content is used as the mouseover title unless the content is provided by a URL, in which case the URL is the title, e.g. :code[:value(./sample.json type="application/json")] has a mouseover title of :code[./sample.json].
]
Formulas are actually just valid JavaScript expressions that also support standard and symbolic math. SECST attempts to process most values as math expressions first:footnote[A parser is used to match potential math expressions.] and if this fails, as JavaScript.
:ul[
- :code[2 * 3] = :value[2 * 2],
- :code[2^3] when used as part of a math expression:footnote[If the expression cannot be parsed as math, then 2^3 will be treated as XOR as it is in regular JavaScript.], is the same as :code[2**3], which is the same as :code[pow(2,3)], which is the same as :code[Math.pow(2,3)] = :value[2^3].
]
To use a value in another formula, the value must be named with an id, e.g.
:code[:value(#v1)[2]] + :code[:value(#v2)[2]] = :code[:value(plaintext)[$(#v1) + $(#v2)]]
:value(#v1)[2] + :value(#v2)[2] = :value(plaintext)[$(#v1) + $(#v2)] (try changing one of the inputs)
The code :code[$(#<some-id>)] is used to substitute named values into formulas. See :a(.#advanced-formulas)[Advanced Formulas] for use of more general CSS selectors and arrays.
:section[
:h[Typed Data]
The :code[:value[]] tag supports the type attribute, valid types include :a(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input)[those supported by the HTML input element] except :code[button], :code[file], :code[hidden], :code[image], :code[search] and :code[submit].
The type can also be one of the mime-types :code[text/plain], :code[text/csv], :code[application/json], e.g. :code[:value(editable {type:"application/json"})[{name:"Joe"}]] as shown below in :a(.#importing-data)[Importing Data]..
If you provide a type, e.g. :code[:value(editable {type:"number"})], then the type will be enforced when the value is edited: :value(editable {type:"number"}).
If the value is computed, a red border will surround type check failures.
]
:section[
:h[String Manipulation]
Strings can be combined using the :code[+] sign, e.g. :code[:value["Hello" + " " + "world!"]] = :value["Hello" + " " + "world!"].
Strings can be manipulated using the :a(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)[standard JavaScript methods], e.g. :code[:value["Hello world!".substring(0,5)]] = :value["Hello world!".substring(0,5)].
]
:section[
:h[Basic Math]
Math formulas include anything that can use the normal operators, :code[,%,^,*,-,+,<,<=,==,>=,>] and any functions available via :a(https://mathjs.org/docs/reference/functions.html)[MathJS].
Formulas can include :a(https://mathjs.org/docs/datatypes/units.html#physical-constants)[physical constants], e.g :code[:value[pi * 3^2]] = :value[pi * 3^2].
This includes these items (most links goto MathJS documentation):
:ul[
- :a(https://mathjs.org/docs/reference/functions.html#algebra-functions)[Algebraic functions], covered in :a(.#algebraic-functions)[more detail] later.
- :a(https://mathjs.org/docs/reference/functions.html#artihmetic-functions)[Arithmetic functions]
- :a(https://mathjs.org/docs/reference/functions.html#bitwise-functions)[Bitwise functions]
- :a(https://mathjs.org/docs/reference/functions.html#combinatorics-functions)[Combinatorics functions]
- :a(https://mathjs.org/docs/reference/functions.html#complex-functions)[Complex functions]
- :a(https://mathjs.org/docs/reference/functions.html#geometry-functions)[Geometry functions]
- :a(https://mathjs.org/docs/reference/functions.html#logical-functions)[Logical functions]
- :a(https://mathjs.org/docs/reference/functions.html#matrix-functions)[Matrix functions]
- :a(https://mathjs.org/docs/reference/functions.html#probability-functions)[Probability functions]
- :a(https://mathjs.org/docs/reference/functions.html#relational-functions)[Relational functions]
- :a(https://mathjs.org/docs/reference/functions.html#set-functions)[Set functions]
- :a(https://mathjs.org/docs/reference/functions.html#special-functions)[Special functions]
- :a(https://mathjs.org/docs/reference/functions.html#statistics-functions)[Statistics functions]
- :a(https://mathjs.org/docs/reference/functions.html#string-functions)[String functions]
- :a(https://mathjs.org/docs/reference/functions.html#trigonometry-functions)[Trigonometry functions]
- :a(https://mathjs.org/docs/reference/functions.html#unit-functions)[Unit functions]
- :a(https://mathjs.org/docs/reference/functions.html#utils-functions)[Utility functions]
]
:section[
:h[Algebraic Functions]
You can ...
:dl[
:dt[Compute derivatives:]
:dd[:code[:value[derivative('x^2 + x', 'x')]]]
:dd[:value[derivative('x^2 + x', 'x')]]
:dt[Simplify equations:]
:dd[:code[:value[simplify('x^2 + x + 3 + x^2')]]]
:dd[:value[simplify('x^2 + x + 3 + x^2')]]
:dt[Solve equations:]
:dd[:code[:value[solve('Math.pow(r,2)',{r:3})}]]]
:dd[:value[solve('Math.pow(r,2)',{r:3})]]
:dt[Give your readers the opportunity to provide the values for which to solve:]
:dd[
:code[
Math.pow(r,2)
where r = :value(#v1d)[0]
is :value[solve('Math.pow(r,2)',{r:$(#v1d)})]
]
renders as
:br :br
Math.pow(r,2) where r = :value(#v1d)[0] is :value[solve('Math.pow(r,2)',{r:$(#v1d)})]
:br
:code[
The derivative of :value(#formula literal editable)[x^2 + x]
for :value(#variable literal editable)[x]
is :value[derivative($(#formula),$(#variable))]
]
renders as
:br :br
The derivative of :value(#formula literal editable)[x^2 + x] for :value(#variable literal editable)[x] is :value[derivative($(#formula),$(#variable))]
]]
]
]
]
:section[
:h[Unit Math]
Unit math :a(https://mathjs.org/docs/datatypes/units.html)[from MathJS] allows fro conversions using the word :code[to], as well as units for numbers, e.g. :code[45 deg].
There are many :a(https://mathjs.org/docs/datatypes/units.html#reference)[supported units].
Here are a few examples:
:code[:value[2 inch to cm]] = :value[2 inch to cm]
:code[:value[90 km/h to mi/h]] = :value[90 km/h to mi/h]
:code[:value[90 km/h to m/h]] = :value[90 km/h to m/h] :code[m/h] is meters per hour
:code[:value[(1 week + 1 day) to days]] = value[(1 week + 1 day) to days]
:code[:value[cos(45 deg)]] = :value[cos(45 deg)]
:code[:value[8.314 m^3 Pa / mol / K]] = :value[8.314 m^3 Pa / mol / K]
Remember, if you have a value that looks like a formula, but is not, you can use the attribute :code[literal], e.g. :code[:value(literal)[2 inch to cm]] = :value(literal)[2 inch to cm].
And, you can use :code[plaintext] to display values without any styling, e.g. :code[:value(plaintext)[90 km/h to mi/h]] = :value(plaintext)[90 km/h to mi/h].
]
:section[
:h[Importing Data]
Values can included imported data using the :code[src] attribute and a mime type provided in the :code[type] attribute. The trailing :code[[]] are optional.
Values with the boolean attribute :code[static] is import data at transpile time. If importing fails, another attempt is made at runtime.
JSON is formatted for readability and :a(https://json5.org)[JSON5] is supported to make it easier to handle remote data.
:code[
:value(https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson static {type:"application/json"})
]
:value(https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson static {type:"application/json"})
Imported data is readonly because it is essentially a computation. To make it editable, use the attribute :code[editable].
:code[
:value(https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson editable {type:"application/json"})
]
:value(https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson editable {type:"application/json"})
If an id is added, the data can be used in a computation.
:code[
:value(#earthquake-data https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson {type:"application/json"})
:value[$(#earthquake-data).metadata]
]
:value(#earthquake-data https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson {type:"application/json"})
:value({type:"application/json"})[$(#earthquake-data).metadata]
]
]
:section[
:h(#seo)[Search Engine Optimization]
SECST provides several features to support :abbr[SEO] Search Engine Optimization.
:ul({title:"SEO features"})[
:li[:a({href:"#hastags"})[hashtags]]
:li[:a({href:"#meta-tags"})[meta tags]]
:li[:a({href:"#structured-data"})[structured data]]
:li[:a({href:"#server-transpilation"})[server transpilation]]
]
:section[
:h[Structured Data]
For select tags, SECST can generate JSON-LD directly from SECST markup. Content, layout, and SEO optimization will always be