Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: extend markdown rendering #439

Open
moul opened this issue Dec 21, 2022 · 11 comments
Open

Proposal: extend markdown rendering #439

moul opened this issue Dec 21, 2022 · 11 comments
Assignees
Labels
help wanted Want to contribute? We recommend these issues. 🌱 feature New update to Gno

Comments

@moul
Copy link
Member

moul commented Dec 21, 2022

Context

Currently, we embrace markdown, which is the default way to consume a smart contract using the Render function and the official website.

I propose extending markdown, so we preserve its main advantage -> being human-readable. But making it easier to programmatically interact with the contracts in richer ways.


Current state

Right now we can have rich rendering for humans with standard markdown.

# Title

Some content.

```json
{
  "lorem": "ipsum"
}
```

Dolor sit amet.

New feature examples

Using frontmatter

Not a big fan of this approach, but it's interesting to show how other systems extended markdown.

On most markdown-driven static website generators, the engines are using frontmatter to allow writing context as yaml.

---
title: Lorem
words: 42
keywords: [a, b, c]
---

Hello [world](link).

Adding metadata to JSON

We can add additional parameters to the language selector after the triple-backticks. We could use this to help machines understand the goal of each JSON entries.

Blah blah.

```json,form
{
  "input": [
    {"title": "firstname", "name": "fn", "default": "Satoshi"},
    {"title": "lastname", "name": "ln", "default": "Nakamoto"},
  ]
}
```

Which would give valid markdown on a standard editor, but would allow the default gnoland website to generate a dynamic HTML form, and would allow a wallet to make dynamic sections too.

We could imagine things like:

`warning`: to have visual indicators on the main website, and maybe confirmation boxes on wallets.
```text,warning
Please, make sure to have enough tokens before calling.
```

`API`: to indicate which part of the markdown is the JSON API. Then we could add optional parameters like `?format=JSON` to just extract this part.
```json,API
{...}
```

`collapsed`: as a way to indicate that the content is not important by default, but people can choose to expand it.
```yaml,collapsed
{...}
```

`error`: like HTTP errors, allow to give more details about the error, and suggest people to redirect, retry, etc.
```json,error
{
  "text": "the content moved.",
  "redirect": "/new/location",
```

Conclusion

My proposal is to extend markdown in a way that stays compatible with standard markdown renderer, and remains human-readable-first, but provides more context to machines and systems.

If we decide a system like this, then we could:

  • write helper libraries for writing contracts that return "typed errors" or important helpers like the current p/demo/dom.
  • update the gnoland website to support them out of the box.
  • write guidelines to continue extending it when it makes sense, but also try to keep this minimalist, so people won't have to learn something new.

Related with #903

@tbruyelle
Copy link
Contributor

Some interpreters cannot read the lang properly if it's not immediately followed by a space or a new line, so eventually I would suggest to use attributes, which is more widely accepted and in addition gives more flexibility. For instance :

```json type="form"

About warnings and errors, the triple colons is also something widely used to create colored containers/boxes around labels. For instance :

:::warning
This is a warning
:::

@moul
Copy link
Member Author

moul commented Jan 24, 2023

About your comment on the other PR: #463 (comment)

We'll do some server-side parsing, but no HTML server-side rendering.

The goal is to make something that:

  • is still readable as pure ASCII-text when rendering is disabled.
  • is still valid as markdown, i.e., renders OK-enough GitHub gist.
  • can have enhanced rendering from JS clients.
  • can be parsed by the server, not for HTML rendering, but to extract some specific parts, i.e., "gives me the JSON output named foobar in a valid JSON syntax, without the markdown around."

@actuallymentor
Copy link

What is the context of applying markdown? I'm trying to understand what Render function you are referring to, or how markdown relates to smart contracts and gnolang.

May I recommend taking a more async approach in issues that are (excessively) expressive in their context so that outside collaborators can be more helpful?

@moul
Copy link
Member Author

moul commented Jan 30, 2023

I'm trying to understand what Render function you are referring to, or how markdown relates to smart contracts and gnolang.

Looks like a good fit for #408 :)

@moul
Copy link
Member Author

moul commented Feb 24, 2023

Can be useful for testing: https://staging.gno.land/r/demo/markdown_test

@alexiscolin
Copy link
Member

alexiscolin commented Mar 15, 2023

Considering the fact the rendering is done by the client, I would opt for a javascript approach. So, it would be possible to generate the UI without need of any backend templating system. The ideal solution should also let the content to be readable when the javascript engine is disabled in the browser.

Two kind of (related) approches come in my mind to enhance the markdown:

1. Markdown shortcodes

Shortcodes could be used like in SSG solutions (let's say Hugo) in order to add more complexes UIs to the classic markdown. It’s also a good solution to avoid getting too much HTML/CSS in Markdown files and improve the DRY principles by reusing piece of code. Here is an example from an old project in Hugo:

<!-- SHORTCODE - BUTTON -->

{{ if .IsNamedParams }}

  <!-- Get button type -->
  <!-- DDL type -->
  {{ with (eq (.Get "type") "ddl") }}
    {{ $.Scratch.Add "icoClass" "button__ico--ddl"}}
    {{ $.Scratch.Add "typeLabel" "Download"}}
  {{end }}

   [...]
 
  <!-- Get icon -->
  {{ $icon := .Get "type"}}
  {{ $icon_template := printf "icons/ico-%s.html" $icon }}


  <!-- rendu html -->
    <a class="button-action button-action--aside" href="{{ with .Get "url"}}{{.}}{{ end }}"><span class=" button__ico">{{ partial $icon_template . }}</span>
      <div class="button__text">
        <span class="button__text__label">{{ with .Get "title"}}{{.}}{{ end }}</span>
        <span class="button__text__action">{{ $.Scratch.Get "typeLabel" }}{{ if (eq (.Get "type") "target")}}{{ .Get "site" }}{{end}}</span>
      </div>
    </a>

{{ end }}

<!-- MD FILE -->
## So What Should I Do About Cookies Right Now?

I gave you an update on everything that's happened with GDPR since 2018. (TL;DR: A lot has changed.) In this article, we'll look at cookie consent: specifically, the paradox where marketers are heavily reliant on Google Analytics cookie data ...

>  In this article, we'll look at cookie consent: specifically, the paradox where marketers are heavily reliant on Google Analytics ...

[...]

{{< button title="Get the data" type="ddl" site="Github" url="https://github.com/alexiscolin" >}}

The last part {{< button title="Get the data" type="ddl" site="Github" url="https://github.com/alexiscolin" >}}
is a shortcode used to render a button in the md file from various variables (title, type, site (for the icon), url). It’s rendered from a Hugo templating system in this example but could be rendered from a JS templating system if using Hugo’s one (or other Go templating system) is impossible. In this case, we could imagine use/code a JS rendering lib to render predefined shortcodes or allow users to create their own shortcodes trough a dedicated syntax.

2. MDX rendering

Very similar to shortcodes, Mdx is an extended md syntax that improves the markdown creation by adding JSX components and variables to it. For example, adding components, such as interactive charts or alerts, and embed them within the content. It become possible to add JS expressions and render the content trough any JSX runtime (vue, react, emotion, custom...). Here is an mdx example from mdx doc website:

import {Chart} from './snowfall.js'
export const year = 2018

# Last year's snowfall

In {year}, the snowfall was above average.
It was followed by a warm spring which caused
flood conditions in many of the nearby rivers.

<Chart year={year} color="#fcb32c" />

Update

@tbruyelle reminds me that marked.js, the library we use may offer many ways to create or develop these kinds of system above (by using or writing extensions). Using what we currently have is a good choice for a minimalist approach and we should avoid to reinvent the wheel when it's possible.

@moul
Copy link
Member Author

moul commented Mar 17, 2023

Finding the right balance between readability and staying standard can be a challenge. To ensure the best user experience, it is important to explore alternative ways to manage HTML forms that are both easy to read and adhere to standards. For instance, a multi-column support could be implemented using <div class=""> elements, which are small enough to not cause any issues.

To further improve readability, I suggest focusing on defining the minimal CSS necessary to create the most essential new widgets. Additionally, I propose continuing my initiative of creating a p/demo/ui (#527) library to make the .gno part more idiomatic.

Once we have made the initial modifications, we can move on to more advanced alterations to finish the task.

@moul moul mentioned this issue Mar 18, 2023
@alexiscolin
Copy link
Member

alexiscolin commented Apr 19, 2023

With the goal of creating a small library of pure CSS components. Here is a list of basic components we should incorporate. They are highly inspired by Notion components (meaning we they are simple inline block components), from Bootstrap classes and from the Gno.land 2.0 website Figma file (clean design). Of course we will be able to more later.

  • Accordion
  • Dropdown
  • Container
  • Icon link
  • Breadcrumb
  • Pagination
  • Buttons
  • Navbar
  • Jumbotron / frame
  • Column
  • Stack
  • Typography (title, lists, link, quotes, alignments...)
  • Forms control
  • Form select
  • Form checkboxes and radio
  • Table

In addition to these components, others style config could be added such as: breakpoints (media queries) or reboot css (reset style). Other design systems such as composition and utility style can be achieved by using CubeCSS Principles : Simplicity, Progressive Enhancement, Agnostic patterns.

@moul
Copy link
Member Author

moul commented Apr 19, 2023

Great, I suggest providing a quickstart in your preferred format so that we can review and discuss the approach. Please let me know if you require assistance setting up your environment, and feel free to reach out for early review. My goal is to facilitate your work so that we can move in the right direction with ease.

Edit: In addition to widgets, some common rules may also be necessary, such as:

  • improving typography (Improve UX with better typography? #539)
  • limiting image width by default and making them clickable
  • using href pattern detection to differentiate internal and external links with icons

@tbruyelle
Copy link
Contributor

@moul We had a discussion with @alexiscolin and we decided to work on this next week. Thanks for your the additional rules, I think they are important ones and they shouldn't be hard to implement, so it's probably a good start.

@moul
Copy link
Member Author

moul commented Oct 21, 2024

Proposal for a markdown convention to support columns without extending markdown while maintaining an acceptable representation on standard markdown renderers:

The concept is to establish a way to indicate "start columns mode" and "stop columns mode." I have chosen --- for this purpose, but it could also be ---- or a more specific keyword. The key aspect of this approach is that a column always begins with an H3 title (###). This eliminates the need for parameters or customization; it is simply a convention.

It also takes a stance on not asking "how many columns" and instead defaults to 3 columns for gnoweb. We can expect a smarter approach when there are fewer than 3 columns, such as using a 50/50 layout for 2 columns or no columns when there is only one.


# my awesome realm

hello world.

## subtitle

blah blah

- a
- b
- c

>>> hello, i'm an alert

---

### col 1

lorem ipsum

- a
- b
- c

### col 2

lorem ipsum

### col 3

lorem ipsum

### col 4

lorem ipsum

---

and here is a footer

<gno-playground>
Example with GitHub default renderer

my awesome realm

hello world.

subtitle

blah blah

  • a
  • b
  • c

hello, i'm an alert


col 1

lorem ipsum

  • a
  • b
  • c

col 2

lorem ipsum

col 3

lorem ipsum

col 4

lorem ipsum


and here is a footer


An alternative idea is to consider that "H4," "H5," or any sufficiently deep heading can serve as a column. This way, we wouldn't need --- separators at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Want to contribute? We recommend these issues. 🌱 feature New update to Gno
Projects
Status: 🌟 Wanted for Launch
Development

Successfully merging a pull request may close this issue.

5 participants