Skip to content

Commit 7353171

Browse files
gfantonalexiscolin
andauthored
feat(gnoweb): Add gno-columns extension (#3763)
Addresses #3255 This PR implements column extension into `gnoweb` following this format: ``` -- input.md -- <gno-columns> ## Title 1 content 1 ## Title 2 content 2 </gno-columns> ``` ### Notes - Check `testdatas` files for example of input/output - i've also added an example in `/r/demo/mardown_test` that need to be improved with usage, example and description (cc @leohhhn) ### Preview #### example output code ![Screenshot 2025-02-17 at 09 36 44](https://github.com/user-attachments/assets/8db014b1-6c41-4f74-ad41-a8ce02281e8f) #### example with images (empty heading) ![image](https://github.com/user-attachments/assets/2ebb934d-a34b-4d2d-9026-cf2af61014a6) ### TODO - [x] In order to support headings without creating columns, we probably want to use the first heading as a reference for column separator - [x] More edge cases for tests - [x] Add css to correctly render column in gnoweb (cc @alexiscolin ) --------- Signed-off-by: gfanton <[email protected]> Co-authored-by: alexiscolin <[email protected]>
1 parent 1a4178e commit 7353171

30 files changed

+1244
-16
lines changed

examples/gno.land/r/docs/markdown/markdown.gno

+161-7
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ You can format text using the following syntax:
4848
***All bold and italic***
4949
±±±
5050

51-
**Bold text**
52-
*Italic text*
53-
~~Strikethrough text~~
54-
**Bold and _nested italic_**
55-
***All bold and italic***
51+
**Bold text**
52+
*Italic text*
53+
~~Strikethrough text~~
54+
**Bold and _nested italic_**
55+
***All bold and italic***
5656

5757
### Links
5858

@@ -63,7 +63,7 @@ Links can be created using the following syntax:
6363
[Link with title](https://example.com "Link title")
6464
±±±
6565

66-
[Link text](https://example.com)
66+
[Link text](https://example.com)
6767
[Link with title](https://example.com "Link title")
6868

6969
XXX: custom CSS for internal/external links and if possible for "in the same realm/namespace".
@@ -212,7 +212,161 @@ This approach allows for a more consistent rendering experience across different
212212

213213
### Columns
214214

215-
XXX: in progress in https://github.com/gnolang/gno/pull/3763
215+
Gno Flavored Markdown introduces a column layout system using special HTML-like tags. This system allows content to be organized into multiple vertical columns using heading elements as separators.
216+
On GnoWeb, up to four columns can be displayed in a single row; exceeding this limit will transfer additional columns to another row, and so on.
217+
218+
#### Basic Syntax
219+
Wrap your column content in ±<gno-columns>± tags and use standard markdown headings (from h1 ±#± to h6 ±######±) to define column breaks:
220+
221+
±±±markdown
222+
<gno-columns>
223+
## Column 1 Title
224+
225+
Column 1 content
226+
227+
## Column 2 Title
228+
229+
Column 2 content
230+
</gno-columns>
231+
±±±
232+
233+
This will render as:
234+
235+
<gno-columns>
236+
## Column 1 Title
237+
238+
Column 1 content
239+
240+
## Column 2 Title
241+
242+
Column 2 content
243+
</gno-columns>
244+
---
245+
246+
#### Key Features
247+
248+
1. **Heading Levels**: Any heading level from ±#± (h1) to ±######± (h6) can be used as column separators. The first one will be the reference for subsequent separator.
249+
250+
±±±markdown
251+
<gno-columns>
252+
# Main Section
253+
254+
Content
255+
256+
## Subsection
257+
258+
More content
259+
260+
# Second section
261+
262+
Content
263+
264+
## Subsection
265+
266+
More content
267+
</gno-columns>
268+
±±±
269+
270+
<gno-columns>
271+
## Main Section
272+
Content
273+
### Subsection
274+
More content
275+
## Second section
276+
Content
277+
### Subsection
278+
More content
279+
</gno-columns>
280+
281+
---
282+
283+
2. **Empty Headings**: Use empty headings to create columns without titles:
284+
285+
±±±markdown
286+
<gno-columns>
287+
###
288+
289+
![Alt text](/public/imgs/gnoland.svg "Optional title")
290+
Content without title
291+
292+
### Second Column
293+
294+
Another column
295+
</gno-columns>
296+
±±±
297+
298+
<gno-columns>
299+
###
300+
301+
![Alt text](/public/imgs/gnoland.svg "Optional title")
302+
Content without title
303+
304+
### Second Column
305+
306+
Another column
307+
</gno-columns>
308+
309+
310+
#### Validation Rules
311+
312+
The column system will ignore invalid structures and generate errors in the form of comments in the following cases:
313+
314+
1. Unclosed Tags
315+
±±±markdown
316+
<gno-columns>
317+
## Title
318+
Content
319+
<!-- Missing closing tag -->
320+
±±±
321+
322+
2. Nested Columns
323+
324+
Nested columns tag will be ignored, e.g.
325+
326+
±±±markdown
327+
<gno-columns>
328+
## Parent
329+
<gno-columns> <!-- this tag will be ignored -->
330+
## Child
331+
</gno-columns>
332+
</gno-columns> <!-- this tag will be ignored -->
333+
±±±
334+
335+
3. Invalid Headings.
336+
337+
Invalid stating heading will generate an error, e.g.
338+
339+
- Headings in list:
340+
±±±markdown
341+
<gno-columns>
342+
- ## List Heading
343+
</gno-columns>
344+
±±±
345+
346+
- Headings beyond h6:
347+
±±±markdown
348+
<gno-columns>
349+
####### Invalid
350+
</gno-columns>
351+
±±±
352+
353+
4. Content Before First Heading
354+
355+
Setting content before first heading, is considered as invalid and will generate an error.
356+
357+
±±±markdown
358+
<gno-columns>
359+
Invalid content
360+
## Title
361+
</gno-columns>
362+
±±±
363+
364+
#### Best Pratices
365+
- Always start column content with a heading
366+
- Maintain consistent heading levels within a columns block
367+
- Close tags immediately after final column content
368+
- Prefer simple markdown structures within columns
369+
- Use empty headings (##) for image-focused columns
216370

217371
### Usernames
218372

Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{{ define "layout/article" }}
2-
<article class="{{ if .Classes }}{{ .Classes }}{{ end }} mt-4 lg:mt-0 lg:col-span-7 pb-24">{{ render .ComponentContent }}</article>
2+
<md-renderer class="{{ if .Classes }}{{ .Classes }}{{ end }} mt-4 lg:mt-0 lg:col-span-7 pb-24">{{ render .ComponentContent }}</md-renderer>
33
{{ end }}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
{{ define "status" }}
2-
<div class="col-span-10 flex flex-col h-full w-full mt-10 pb-24 justify-center items-center">
2+
<div class="col-span-1 flex flex-col h-full w-full mt-10 pb-24 justify-center items-center">
33
<img src="/public/imgs/gnoland.svg" alt="gno land" width="70px" height="70px" />
4-
<h1 class="text-600 font-bold text-gray-600 pb-4 capitalize">
5-
{{ .Title }}
6-
</h1>
4+
<h1 class="text-600 font-bold text-gray-600 pb-4 capitalize">{{ .Title }}</h1>
75
<p class="pb-3">{{ .Body }}</p>
8-
<a href="{{ .ButtonURL }}" class="rounded border py-1 px-2 hover:bg-gray-100">
9-
{{ .ButtonText }}
10-
</a>
6+
<a href="{{ .ButtonURL }}" class="rounded border py-1 px-2 hover:bg-gray-100"> {{ .ButtonText }} </a>
117
</div>
128
{{ end }}

gno.land/pkg/gnoweb/frontend/css/input.css

+8
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,14 @@
255255
::selection {
256256
@apply bg-green-600 text-light;
257257
}
258+
259+
/* MD components */
260+
.realm-view .gno-columns {
261+
@apply flex flex-wrap gap-x-10 xxl:gap-x-12;
262+
}
263+
.realm-view .gno-columns > * {
264+
@apply grow shrink basis-52 lg:basis-44;
265+
}
258266
}
259267

260268
@layer components {

gno.land/pkg/gnoweb/markdown/ext.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// This file serves as the entry point to load the Gno Goldmark extension.
2+
// Goldmark extensions are designed as follows:
3+
//
4+
// <Markdown in []byte, parser.Context>
5+
// |
6+
// V
7+
// +-------- parser.Parser ---------------------------
8+
// | 1. Parse block elements into AST
9+
// | 1. If a parsed block is a paragraph, apply
10+
// | ast.ParagraphTransformer
11+
// | 2. Traverse AST and parse blocks.
12+
// | 1. Process delimiters (emphasis) at the end of
13+
// | block parsing
14+
// | 3. Apply parser.ASTTransformers to AST
15+
// |
16+
// V
17+
// <ast.Node>
18+
// |
19+
// V
20+
// +------- renderer.Renderer ------------------------
21+
// | 1. Traverse AST and apply renderer.NodeRenderer
22+
// | corresponding to the node type
23+
//
24+
// |
25+
// V
26+
// <Output>
27+
//
28+
// More information can be found on the Goldmark repository page:
29+
// https://github.com/yuin/goldmark#goldmark-internalfor-extension-developers
30+
31+
package markdown
32+
33+
import (
34+
"github.com/yuin/goldmark"
35+
)
36+
37+
var _ goldmark.Extender = (*gnoExtension)(nil)
38+
39+
type gnoExtension struct{}
40+
41+
var GnoExtension = &gnoExtension{}
42+
43+
// Extend adds the Gno extension to the provided Goldmark markdown processor.
44+
func (e *gnoExtension) Extend(m goldmark.Markdown) {
45+
Columns.Extend(m)
46+
}

0 commit comments

Comments
 (0)