docs.mdin: /docs/cmd/demo-server/


This is one part where the code isn't executed as is. I've embedded the root /docs/ directory of this repo into using the embed package.

And if we want to render one of these documents we can use the md.View() that we create here.

import (
	"net/http"
	"strings"

	"github.com/stanistan/veun"
	"github.com/stanistan/veun/el"
	"github.com/stanistan/veun/vhttp/request"

	"github.com/stanistan/veun-http-demo/docs"
	"github.com/stanistan/veun-http-demo/internal/components"
	"github.com/stanistan/veun-http-demo/internal/view/doc_tree"
	"github.com/stanistan/veun-http-demo/internal/view/md"
	"github.com/stanistan/veun-http-demo/internal/view/title"
	"github.com/stanistan/veun-http-demo/internal/view/two_column"
)

Request Handlers

A fun part here is to use the built-in request.Handler, Always to make the actual HTML page we're going to look at for the indexes.

Home Page

var index = request.Always(&two_column.View{
    Title: "veun-http-demo",
    Nav:   doc_tree.View("/"),
    Main:  el.Article{el.Content{md.View(docs.Index)}},
})

Docs Page

Each individual document is mounted at a /docs/$SLUG looking URL, so we can use a request handler specificlaly for that and mapping it back to the path in our static file server.

So /docs/$THING.md maps to /docs/$THING.go.md in our repo.

Our handler can also set the title for the page using page.DataMutator.

// FIXME: this specific function/handler should not be looking up the file by path
// but walking the doc tree, and that way if something is a directory, we can
// treat it differently than if if were a file.
var docsHandler = request.HandlerFunc(func(r *http.Request) (veun.AsView, http.Handler, error) {
	var (
		rawUrl = r.URL.Path
		url    = strings.TrimPrefix(rawUrl, "/docs")
		docUrl = strings.TrimSuffix(strings.TrimPrefix(url, "/"), ".md") + ".go.md"

		next http.Handler
	)

	content := docPageContent(rawUrl, docUrl)
	if content == nil {
        return nil, http.NotFoundHandler(), nil
	}

	return &two_column.View{
		Nav:   doc_tree.View(rawUrl),
		Main:  content,
		Title: rawUrl + " | veun-http-demo",
	}, next, nil
})

The page content itself reads the file from the static documentation and attempts to render it into markdown.

Importantly, if the file also has an associated component, then that gets prepended to the content as well.

func docPageContent(currentUrl, pathToFile string) veun.AsView {
	bs, err := docs.Docs.ReadFile(pathToFile)
	if err != nil {
        return nil
	}

    content := md.View(bs)
    if component, ok := components.ForFullURL(currentUrl); ok {
        content = veun.Views{component, content}
    }

    return el.Article{
        title.View(currentUrl),
        el.Hr{},
        el.Content{content},
    }
}