collections via markdown files
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
4a9a3eec06
commit
ff1da084af
@ -2,6 +2,7 @@ NEUERUNGEN:
|
||||
|
||||
- Cached Collection Webrequests
|
||||
- recursive Collections
|
||||
- Datei basierte Collections
|
||||
- markdown-Filter `s=SYNTAX_HIGHLIGHT_SHEMA` Parameter
|
||||
- image_process nutzt alle CPU-Kerne
|
||||
- GZIP/Brotli Vor-Komprimierung der Inhalte und Assets
|
||||
|
@ -130,7 +130,7 @@ func ImageProcessFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *
|
||||
}
|
||||
} else {
|
||||
// local file
|
||||
imgSource = mark2web.ResolveInputPath(imgSource)
|
||||
imgSource = mark2web.CurrentTreeNode.ResolveInputPath(imgSource)
|
||||
if p.Filename == "" {
|
||||
p.Filename = fmt.Sprintf(
|
||||
"%s_%s",
|
||||
@ -142,7 +142,7 @@ func ImageProcessFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *
|
||||
|
||||
var imgTarget string
|
||||
if p.TargetDir != "" {
|
||||
imgTarget = mark2web.ResolveOutputPath(
|
||||
imgTarget = mark2web.CurrentTreeNode.ResolveOutputPath(
|
||||
path.Clean(p.TargetDir) + "/" +
|
||||
p.Filename,
|
||||
)
|
||||
@ -158,10 +158,10 @@ func ImageProcessFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *
|
||||
}
|
||||
}
|
||||
|
||||
p.Filename = mark2web.ResolveNavPath(p.TargetDir + "/" + p.Filename)
|
||||
p.Filename = mark2web.CurrentTreeNode.ResolveNavPath(p.TargetDir + "/" + p.Filename)
|
||||
|
||||
} else {
|
||||
imgTarget = mark2web.ResolveOutputPath(p.Filename)
|
||||
imgTarget = mark2web.CurrentTreeNode.ResolveOutputPath(p.Filename)
|
||||
}
|
||||
|
||||
if f, err := os.Stat(imgTarget); err == nil && !f.IsDir() {
|
||||
@ -226,5 +226,5 @@ func ImageProcessFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *
|
||||
helper.Log.Noticef("finished image: %s", imgTarget)
|
||||
})
|
||||
}
|
||||
return pongo2.AsValue(mark2web.ResolveNavPath(p.Filename)), nil
|
||||
return pongo2.AsValue(mark2web.CurrentTreeNode.ResolveNavPath(p.Filename)), nil
|
||||
}
|
||||
|
@ -36,9 +36,6 @@ func TestImageProcessFilter(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
mark2web.CurrentContext = &pongo2.Context{
|
||||
"CurrentPath": "",
|
||||
}
|
||||
|
||||
os.Remove("../../test/out/fit_300x300_q060_test.jpg")
|
||||
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
// RelativePathFilter returns the relative path to navpoint based on current nav
|
||||
func RelativePathFilter(in, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
|
||||
return pongo2.AsValue(
|
||||
mark2web.ResolveNavPath(
|
||||
mark2web.CurrentTreeNode.ResolveNavPath(
|
||||
in.String(),
|
||||
),
|
||||
), nil
|
||||
|
@ -17,10 +17,23 @@ func TestRelativePathFilter(t *testing.T) {
|
||||
"testabs": "/abs",
|
||||
"testsub": "../sub/rel",
|
||||
}
|
||||
|
||||
mark2web.Config.Directories.Output = "../../test/out"
|
||||
|
||||
mark2web.CurrentTreeNode = &mark2web.TreeNode{
|
||||
InputPath: "../../test/in/content",
|
||||
OutputPath: "../../test/out/sub",
|
||||
Config: &mark2web.PathConfig{
|
||||
Imaging: &mark2web.ImagingConfig{
|
||||
Quality: 60,
|
||||
Height: 300,
|
||||
Width: 300,
|
||||
Process: "fit",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Convey("parse template", func() {
|
||||
mark2web.CurrentContext = &pongo2.Context{
|
||||
"CurrentPath": "sub",
|
||||
}
|
||||
|
||||
output, err := pongo2.RenderTemplateString("{{ testrel|relative_path }}", ctx)
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -2,7 +2,6 @@ package helper
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CreateDirectory creates direcory with all missing parents and panic if error
|
||||
@ -25,14 +24,3 @@ func CreateDirectory(dir string) {
|
||||
Log.Panicf("unknown error for output directory '%s': %s", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
// BackToRoot builds ../../ string
|
||||
func BackToRoot(curNavPath string) string {
|
||||
tmpPath := ""
|
||||
if curNavPath != "" {
|
||||
for i := strings.Count(curNavPath, "/") + 1; i > 0; i-- {
|
||||
tmpPath += "../"
|
||||
}
|
||||
}
|
||||
return tmpPath
|
||||
}
|
||||
|
18
pkg/helper/regexp.go
Normal file
18
pkg/helper/regexp.go
Normal file
@ -0,0 +1,18 @@
|
||||
package helper
|
||||
|
||||
import "regexp"
|
||||
|
||||
// GetRegexpParams gets a map of named regexp group matches
|
||||
// use pe. (?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2}) as regexp
|
||||
func GetRegexpParams(regEx *regexp.Regexp, str string) (paramsMap map[string]string) {
|
||||
|
||||
match := regEx.FindStringSubmatch(str)
|
||||
|
||||
paramsMap = make(map[string]string)
|
||||
for i, name := range regEx.SubexpNames() {
|
||||
if i > 0 && i <= len(match) {
|
||||
paramsMap[name] = match[i]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
@ -35,13 +35,13 @@ func ProcessAssets() {
|
||||
}
|
||||
|
||||
// fixAssetsPath replaces assets path based on current path
|
||||
func fixAssetsPath(str, curNavPath string) string {
|
||||
func (node *TreeNode) fixAssetsPath(str string) string {
|
||||
if find := Config.Assets.FixTemplate.Find; find != "" {
|
||||
helper.Log.Debugf("fixing assets paths for path '%s'", curNavPath)
|
||||
helper.Log.Debugf("fixing assets paths for path '%s'", node.CurrentNavPath())
|
||||
repl := Config.Assets.FixTemplate.Replace
|
||||
toPath := Config.Assets.ToPath
|
||||
|
||||
bToRoot := helper.BackToRoot(curNavPath)
|
||||
bToRoot := node.BackToRootPath()
|
||||
regex, err := regexp.Compile(find)
|
||||
if err != nil {
|
||||
log.Panicf("could not compile regexp '%s' for assets path: %s", find, err)
|
||||
|
@ -1,7 +1,9 @@
|
||||
package mark2web
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"gitbase.de/apairon/mark2web/pkg/helper"
|
||||
@ -20,13 +22,12 @@ var colCache = make(map[string]*colCacheEntry)
|
||||
func (node *TreeNode) handleCollections() {
|
||||
collections := append(node.Config.Collections, node.Config.This.Collections...)
|
||||
for _, colConfig := range collections {
|
||||
if colConfig != nil {
|
||||
if colConfig.Name == nil || *colConfig.Name == "" {
|
||||
helper.Log.Panicf("missing Name in collection config in '%s'", node.InputPath)
|
||||
}
|
||||
if colConfig.URL == nil || *colConfig.URL == "" {
|
||||
helper.Log.Panicf("missing EntriesJSON in collection config in '%s'", node.InputPath)
|
||||
}
|
||||
if colConfig.Name == nil || *colConfig.Name == "" {
|
||||
helper.Log.Panicf("missing Name in collection config in '%s'", node.InputPath)
|
||||
}
|
||||
if (colConfig.URL == nil || *colConfig.URL == "") &&
|
||||
(colConfig.Directory == nil) {
|
||||
helper.Log.Panicf("missing URL and Directory in collection config in '%s'", node.InputPath)
|
||||
}
|
||||
|
||||
if node.ColMap == nil {
|
||||
@ -36,21 +37,73 @@ func (node *TreeNode) handleCollections() {
|
||||
ctx["This"] = node.Config.This
|
||||
ctx["Data"] = node.Config.Data
|
||||
|
||||
url, err := pongo2.RenderTemplateString(*colConfig.URL, ctx)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("invalid template string for Collection Element.URL in '%s': %s", node.InputPath, err)
|
||||
}
|
||||
|
||||
var colData interface{}
|
||||
if cacheEntry, ok := colCache[url]; ok {
|
||||
colData = cacheEntry.data
|
||||
cacheEntry.hit++
|
||||
} else {
|
||||
colData = helper.JSONWebRequest(url)
|
||||
colCache[url] = &colCacheEntry{
|
||||
data: colData,
|
||||
navnames: make([]string, 0),
|
||||
|
||||
errSrcText := ""
|
||||
cacheKey := ""
|
||||
|
||||
if colConfig.URL != nil {
|
||||
url, err := pongo2.RenderTemplateString(*colConfig.URL, ctx)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("invalid template string for Collection Element.URL in '%s': %s", node.InputPath, err)
|
||||
}
|
||||
|
||||
errSrcText = "URL " + url
|
||||
cacheKey = url
|
||||
|
||||
if cacheEntry, ok := colCache[url]; ok {
|
||||
colData = cacheEntry.data
|
||||
cacheEntry.hit++
|
||||
} else {
|
||||
helper.Log.Noticef("reading collection from: %s", errSrcText)
|
||||
colData = helper.JSONWebRequest(url)
|
||||
colCache[url] = &colCacheEntry{
|
||||
data: colData,
|
||||
navnames: make([]string, 0),
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
path := node.ResolveInputPath(colConfig.Directory.Path)
|
||||
errSrcText = "DIR " + path
|
||||
|
||||
helper.Log.Noticef("reading collection from: %s", errSrcText)
|
||||
d, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("could not read directory '%s': %s", path, err)
|
||||
}
|
||||
|
||||
mStr := "."
|
||||
if colConfig.Directory.MatchFilename != "" {
|
||||
mStr = colConfig.Directory.MatchFilename
|
||||
}
|
||||
matcher, err := regexp.Compile(mStr)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("could not compile regex for MatchFilename '%s' in '%s': %s", mStr, path, err)
|
||||
}
|
||||
|
||||
if colConfig.Directory.ReverseOrder {
|
||||
for i := len(d)/2 - 1; i >= 0; i-- {
|
||||
opp := len(d) - 1 - i
|
||||
d[i], d[opp] = d[opp], d[i]
|
||||
}
|
||||
}
|
||||
|
||||
fcolData := make([]pongo2.Context, 0)
|
||||
for _, fh := range d {
|
||||
if !fh.IsDir() && matcher.MatchString(fh.Name()) {
|
||||
inFile := path + "/" + fh.Name()
|
||||
md, err := ioutil.ReadFile(inFile)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("could not read file '%s': %s", inFile, err)
|
||||
}
|
||||
_, ctx := node.processMarkdownWithHeader(md, inFile)
|
||||
(*ctx)["FilenameMatch"] = helper.GetRegexpParams(matcher, fh.Name())
|
||||
fcolData = append(fcolData, *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
colData = fcolData
|
||||
}
|
||||
|
||||
node.ColMap[*colConfig.Name] = colData
|
||||
@ -64,7 +117,7 @@ func (node *TreeNode) handleCollections() {
|
||||
entries, ok = colDataMap[navT.EntriesAttribute].([]interface{})
|
||||
if !ok {
|
||||
helper.Log.Debug(spew.Sdump(colDataMap))
|
||||
helper.Log.Panicf("invalid json data in [%s] from url '%s' for entries", navT.EntriesAttribute, url)
|
||||
helper.Log.Panicf("invalid json data in [%s] from '%s' for entries", navT.EntriesAttribute, errSrcText)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -72,7 +125,7 @@ func (node *TreeNode) handleCollections() {
|
||||
}
|
||||
if !ok {
|
||||
helper.Log.Debug(spew.Sdump(colData))
|
||||
helper.Log.Panicf("invalid json data from url '%s', need array of objects for entries or object with configured NavTemplate.EntriesAttribute", url)
|
||||
helper.Log.Panicf("invalid json data from '%s', need array of objects for entries or object with configured NavTemplate.EntriesAttribute", errSrcText)
|
||||
}
|
||||
|
||||
// build navigation with detail sites
|
||||
@ -85,7 +138,7 @@ func (node *TreeNode) handleCollections() {
|
||||
var jsonCtx map[string]interface{}
|
||||
if jsonCtx, ok = colEl.(map[string]interface{}); !ok {
|
||||
helper.Log.Debug(spew.Sdump(colEl))
|
||||
helper.Log.Panicf("no json object for entry index %d from url '%s'", idx, url)
|
||||
helper.Log.Panicf("no json object for entry index %d from '%s'", idx, errSrcText)
|
||||
}
|
||||
err = helper.Merge(&ctxE, pongo2.Context(jsonCtx))
|
||||
if err != nil {
|
||||
@ -143,14 +196,14 @@ func (node *TreeNode) handleCollections() {
|
||||
}
|
||||
}
|
||||
|
||||
if l := len(colCache[url].navnames); colCache[url].hit > 1 &&
|
||||
if l := len(colCache[cacheKey].navnames); colCache[cacheKey].hit > 1 &&
|
||||
l > 0 &&
|
||||
navname == colCache[url].navnames[l-1] {
|
||||
navname == colCache[cacheKey].navnames[l-1] {
|
||||
// navname before used same url, so recursion loop
|
||||
helper.Log.Panicf("collection request loop detected for in '%s' for url: %s", node.InputPath, url)
|
||||
helper.Log.Panicf("collection request loop detected for in '%s' for : %s", node.InputPath, errSrcText)
|
||||
}
|
||||
|
||||
colCache[url].navnames = append(colCache[url].navnames, navname)
|
||||
colCache[cacheKey].navnames = append(colCache[cacheKey].navnames, navname)
|
||||
|
||||
node.addSubNode(tpl, goTo, navname, colEl, dataKey, body, navT.Hidden)
|
||||
}
|
||||
|
@ -2,10 +2,18 @@ package mark2web
|
||||
|
||||
import "gitbase.de/apairon/mark2web/pkg/helper"
|
||||
|
||||
// CollectionDirectoryConfig specifies how to handle a directory of markdown files as a collection
|
||||
type CollectionDirectoryConfig struct {
|
||||
Path string `yaml:"Path"`
|
||||
MatchFilename string `yaml:"MatchFilename"`
|
||||
ReverseOrder bool `yaml:"ReverseOrder"`
|
||||
}
|
||||
|
||||
// CollectionConfig describes a collection
|
||||
type CollectionConfig struct {
|
||||
Name *string `yaml:"Name"`
|
||||
URL *string `yaml:"URL"`
|
||||
Name *string `yaml:"Name"`
|
||||
URL *string `yaml:"URL"`
|
||||
Directory *CollectionDirectoryConfig `yaml:"Directory"`
|
||||
NavTemplate *struct {
|
||||
EntriesAttribute string `yaml:"EntriesAttribute"`
|
||||
GoTo string `yaml:"GoTo"`
|
||||
|
@ -65,24 +65,104 @@ func (node *TreeNode) ReadContentDir(inBase string, outBase string, dir string,
|
||||
}
|
||||
}
|
||||
|
||||
func (node *TreeNode) processMarkdownWithHeader(md []byte, errorRef string) (*PathConfig, *pongo2.Context) {
|
||||
|
||||
newConfig := new(PathConfig)
|
||||
|
||||
headerRegex := regexp.MustCompile("(?s)^---(.*?)\\r?\\n\\r?---\\r?\\n\\r?")
|
||||
yamlData := headerRegex.Find(md)
|
||||
if string(yamlData) != "" {
|
||||
// replace tabs
|
||||
yamlData = bytes.Replace(yamlData, []byte("\t"), []byte(" "), -1)
|
||||
|
||||
helper.Log.Debugf("found yaml header in '%s', merging config", errorRef)
|
||||
err := yaml.Unmarshal(yamlData, newConfig)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("could not parse YAML header from '%s': %s", errorRef, err)
|
||||
}
|
||||
|
||||
helper.Log.Debug("merging config with upper config")
|
||||
oldThis := newConfig.This
|
||||
helper.Merge(newConfig, node.Config)
|
||||
newConfig.This = oldThis
|
||||
|
||||
helper.Log.Debug(spew.Sdump(newConfig))
|
||||
|
||||
md = headerRegex.ReplaceAll(md, []byte(""))
|
||||
} else {
|
||||
helper.Merge(newConfig, node.Config)
|
||||
}
|
||||
|
||||
// use --- for splitting document in markdown parts
|
||||
regex := regexp.MustCompile("\\r?\\n\\r?---\\r?\\n\\r?")
|
||||
inputParts := regex.Split(string(md), -1)
|
||||
htmlParts := make([]*pongo2.Value, 0)
|
||||
|
||||
chromaRenderer := false
|
||||
chromaStyle := "monokai"
|
||||
if m := newConfig.Markdown; m != nil {
|
||||
if m.ChromaRenderer != nil && *m.ChromaRenderer {
|
||||
chromaRenderer = true
|
||||
}
|
||||
if m.ChromaStyle != nil && *m.ChromaStyle != "" {
|
||||
chromaStyle = *m.ChromaStyle
|
||||
}
|
||||
}
|
||||
for _, iPart := range inputParts {
|
||||
htmlParts = append(htmlParts,
|
||||
pongo2.AsSafeValue(
|
||||
string(helper.RenderMarkdown([]byte(iPart), chromaRenderer, chromaStyle))))
|
||||
}
|
||||
|
||||
// build navigation
|
||||
navMap := make(map[string]*NavElement)
|
||||
navSlice := make([]*NavElement, 0)
|
||||
navActive := make([]*NavElement, 0)
|
||||
node.buildNavigation(&navMap, &navSlice, &navActive)
|
||||
|
||||
// read yaml header as data for template
|
||||
ctx := NewContext()
|
||||
ctx["This"] = newConfig.This
|
||||
ctx["Meta"] = newConfig.Meta
|
||||
ctx["Markdown"] = newConfig.Markdown
|
||||
ctx["Data"] = newConfig.Data
|
||||
ctx["ColMap"] = node.root.ColMap // root as NavMap and NavSlice, for sub go to NavElement.ColMap
|
||||
ctx["NavMap"] = navMap
|
||||
ctx["NavSlice"] = navSlice
|
||||
ctx["NavActive"] = navActive
|
||||
ctx["Body"] = pongo2.AsSafeValue(string(helper.RenderMarkdown(md, chromaRenderer, chromaStyle)))
|
||||
ctx["BodyParts"] = htmlParts
|
||||
ctx["CurrentPath"] = node.CurrentNavPath()
|
||||
// set active nav element
|
||||
if len(navActive) > 0 {
|
||||
ctx["NavElement"] = navActive[len(navActive)-1]
|
||||
} else {
|
||||
// if no active path to content, we are in root dir
|
||||
ctx["NavElement"] = &NavElement{
|
||||
GoTo: node.BackToRootPath(),
|
||||
Active: true,
|
||||
ColMap: node.ColMap,
|
||||
Data: node.Config.Data,
|
||||
This: node.Config.This,
|
||||
SubMap: &navMap,
|
||||
SubSlice: &navSlice,
|
||||
}
|
||||
}
|
||||
|
||||
return newConfig, &ctx
|
||||
}
|
||||
|
||||
// ProcessContent walks recursivly through the input paths and processes all files for output
|
||||
func (node *TreeNode) ProcessContent() {
|
||||
helper.CreateDirectory(node.OutputPath)
|
||||
|
||||
curNavPath := strings.TrimPrefix(node.OutputPath, Config.Directories.Output)
|
||||
curNavPath = strings.TrimPrefix(curNavPath, "/")
|
||||
curNavPath = path.Clean(curNavPath)
|
||||
if curNavPath == "." {
|
||||
curNavPath = ""
|
||||
}
|
||||
|
||||
if node.root != node {
|
||||
// write htaccess for rewrites, root will be written in WriteWebserverConfig()
|
||||
goTo := node.Config.This.GoTo
|
||||
if goTo != nil && *goTo != "" {
|
||||
goToFixed := *goTo
|
||||
if strings.HasPrefix(goToFixed, "/") {
|
||||
goToFixed = helper.BackToRoot(curNavPath) + goToFixed
|
||||
goToFixed = node.BackToRootPath() + goToFixed
|
||||
}
|
||||
goToFixed = path.Clean(goToFixed)
|
||||
|
||||
@ -91,82 +171,63 @@ func (node *TreeNode) ProcessContent() {
|
||||
}
|
||||
|
||||
for _, file := range node.InputFiles {
|
||||
var input []byte
|
||||
inFile := "InputString"
|
||||
|
||||
if file != "" {
|
||||
inFile = node.InputPath + "/" + file
|
||||
helper.Log.Debugf("reading file: %s", inFile)
|
||||
|
||||
var err error
|
||||
input, err = ioutil.ReadFile(inFile)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("could not read '%s':%s", inFile, err)
|
||||
}
|
||||
helper.Log.Infof("processing input file '%s'", inFile)
|
||||
} else {
|
||||
// use input string if available and input filename == ""
|
||||
var inputString *string
|
||||
if i := node.Config.Index; i != nil {
|
||||
inputString = i.InputString
|
||||
}
|
||||
if inputString != nil {
|
||||
helper.Log.Debugf("using input string instead of file")
|
||||
input = []byte(*inputString)
|
||||
}
|
||||
}
|
||||
|
||||
newConfig := new(PathConfig)
|
||||
|
||||
regex := regexp.MustCompile("(?s)^---(.*?)\\r?\\n\\r?---\\r?\\n\\r?")
|
||||
yamlData := regex.Find(input)
|
||||
if string(yamlData) != "" {
|
||||
// replace tabs
|
||||
yamlData = bytes.Replace(yamlData, []byte("\t"), []byte(" "), -1)
|
||||
|
||||
helper.Log.Debugf("found yaml header in '%s', merging config", inFile)
|
||||
err := yaml.Unmarshal(yamlData, newConfig)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("could not parse YAML header from '%s': %s", inFile, err)
|
||||
}
|
||||
|
||||
helper.Log.Debug("merging config with upper config")
|
||||
oldThis := newConfig.This
|
||||
helper.Merge(newConfig, node.Config)
|
||||
newConfig.This = oldThis
|
||||
|
||||
helper.Log.Debug(spew.Sdump(newConfig))
|
||||
|
||||
input = regex.ReplaceAll(input, []byte(""))
|
||||
} else {
|
||||
helper.Merge(newConfig, node.Config)
|
||||
}
|
||||
|
||||
// ignore ???
|
||||
ignoreFile := false
|
||||
var ignoreRegex *string
|
||||
var stripRegex *string
|
||||
var outputExt *string
|
||||
if f := newConfig.Filename; f != nil {
|
||||
ignoreRegex = f.Ignore
|
||||
stripRegex = f.Strip
|
||||
outputExt = f.OutputExtension
|
||||
}
|
||||
if ignoreRegex != nil && *ignoreRegex != "" {
|
||||
regex, err := regexp.Compile(*ignoreRegex)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("could not compile filename.ignore regexp '%s' for file '%s': %s", *ignoreRegex, inFile, err)
|
||||
if file != "" {
|
||||
inFile = node.InputPath + "/" + file
|
||||
var ignoreRegex *string
|
||||
if f := node.Config.Filename; f != nil {
|
||||
ignoreRegex = f.Ignore
|
||||
}
|
||||
if ignoreRegex != nil && *ignoreRegex != "" {
|
||||
regex, err := regexp.Compile(*ignoreRegex)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("could not compile filename.ignore regexp '%s' for file '%s': %s", *ignoreRegex, inFile, err)
|
||||
}
|
||||
ignoreFile = regex.MatchString(file)
|
||||
}
|
||||
ignoreFile = regex.MatchString(file)
|
||||
}
|
||||
|
||||
if ignoreFile {
|
||||
helper.Log.Infof("ignoring file '%s', because of filename.ignore", inFile)
|
||||
} else {
|
||||
var input []byte
|
||||
|
||||
if file != "" {
|
||||
helper.Log.Debugf("reading file: %s", inFile)
|
||||
|
||||
var err error
|
||||
input, err = ioutil.ReadFile(inFile)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("could not read '%s':%s", inFile, err)
|
||||
}
|
||||
helper.Log.Infof("processing input file '%s'", inFile)
|
||||
} else {
|
||||
// use input string if available and input filename == ""
|
||||
var inputString *string
|
||||
if i := node.Config.Index; i != nil {
|
||||
inputString = i.InputString
|
||||
}
|
||||
if inputString != nil {
|
||||
helper.Log.Debugf("using input string instead of file")
|
||||
input = []byte(*inputString)
|
||||
}
|
||||
}
|
||||
|
||||
newConfig, ctx := node.processMarkdownWithHeader(input, inFile)
|
||||
|
||||
// build output filename
|
||||
outputFilename := file
|
||||
|
||||
var stripRegex *string
|
||||
var outputExt *string
|
||||
if f := newConfig.Filename; f != nil {
|
||||
stripRegex = f.Strip
|
||||
outputExt = f.OutputExtension
|
||||
}
|
||||
|
||||
var indexInputFile *string
|
||||
var indexOutputFile *string
|
||||
if i := newConfig.Index; i != nil {
|
||||
@ -194,71 +255,14 @@ func (node *TreeNode) ProcessContent() {
|
||||
|
||||
outFile := node.OutputPath + "/" + outputFilename
|
||||
helper.Log.Debugf("using '%s' as output file", outFile)
|
||||
|
||||
// use --- for splitting document in markdown parts
|
||||
regex := regexp.MustCompile("\\r?\\n\\r?---\\r?\\n\\r?")
|
||||
inputParts := regex.Split(string(input), -1)
|
||||
htmlParts := make([]*pongo2.Value, 0)
|
||||
|
||||
chromaRenderer := false
|
||||
chromaStyle := "monokai"
|
||||
if m := newConfig.Markdown; m != nil {
|
||||
if m.ChromaRenderer != nil && *m.ChromaRenderer {
|
||||
chromaRenderer = true
|
||||
}
|
||||
if m.ChromaStyle != nil && *m.ChromaStyle != "" {
|
||||
chromaStyle = *m.ChromaStyle
|
||||
}
|
||||
}
|
||||
for _, iPart := range inputParts {
|
||||
htmlParts = append(htmlParts,
|
||||
pongo2.AsSafeValue(
|
||||
string(helper.RenderMarkdown([]byte(iPart), chromaRenderer, chromaStyle))))
|
||||
}
|
||||
|
||||
// build navigation
|
||||
navMap := make(map[string]*NavElement)
|
||||
navSlice := make([]*NavElement, 0)
|
||||
navActive := make([]*NavElement, 0)
|
||||
buildNavigation(node.root, &navMap, &navSlice, &navActive, curNavPath)
|
||||
|
||||
// read yaml header as data for template
|
||||
ctx := NewContext()
|
||||
ctx["This"] = newConfig.This
|
||||
ctx["Meta"] = newConfig.Meta
|
||||
ctx["Markdown"] = newConfig.Markdown
|
||||
ctx["Data"] = newConfig.Data
|
||||
ctx["ColMap"] = node.root.ColMap // root as NavMap and NavSlice, for sub go to NavElement.ColMap
|
||||
ctx["NavMap"] = navMap
|
||||
ctx["NavSlice"] = navSlice
|
||||
ctx["NavActive"] = navActive
|
||||
ctx["Body"] = pongo2.AsSafeValue(string(helper.RenderMarkdown(input, chromaRenderer, chromaStyle)))
|
||||
ctx["BodyParts"] = htmlParts
|
||||
ctx["CurrentPath"] = curNavPath
|
||||
// set active nav element
|
||||
if len(navActive) > 0 {
|
||||
ctx["NavElement"] = navActive[len(navActive)-1]
|
||||
} else {
|
||||
// if no active path to content, we are in root dir
|
||||
ctx["NavElement"] = &NavElement{
|
||||
GoTo: helper.BackToRoot(curNavPath),
|
||||
Active: true,
|
||||
ColMap: node.ColMap,
|
||||
Data: node.Config.Data,
|
||||
This: node.Config.This,
|
||||
SubMap: &navMap,
|
||||
SubSlice: &navSlice,
|
||||
}
|
||||
}
|
||||
|
||||
helper.Log.Debugf("rendering template '%s' for '%s'", *newConfig.Template, outFile)
|
||||
templateFilename := *newConfig.Template
|
||||
result, err := renderTemplate(*newConfig.Template, node, newConfig, &ctx)
|
||||
result, err := renderTemplate(*newConfig.Template, node, newConfig, ctx)
|
||||
if err != nil {
|
||||
helper.Log.Panicf("could not execute template '%s' for input file '%s': %s", templateFilename, inFile, err)
|
||||
}
|
||||
|
||||
result = fixAssetsPath(result, curNavPath)
|
||||
result = node.fixAssetsPath(result)
|
||||
|
||||
helper.Log.Noticef("writing to output file: %s", outFile)
|
||||
err = ioutil.WriteFile(outFile, []byte(result), 0644)
|
||||
|
@ -25,7 +25,11 @@ type NavElement struct {
|
||||
}
|
||||
|
||||
// buildNavigation builds the navigation trees for use in templates
|
||||
func buildNavigation(tree *TreeNode, curNavMap *map[string]*NavElement, curNavSlice *[]*NavElement, navActive *[]*NavElement, activeNav string) {
|
||||
func (node *TreeNode) buildNavigation(curNavMap *map[string]*NavElement, curNavSlice *[]*NavElement, navActive *[]*NavElement) {
|
||||
buildNavigationRecursive(node.root, curNavMap, curNavSlice, navActive, node.CurrentNavPath(), node.BackToRootPath())
|
||||
}
|
||||
|
||||
func buildNavigationRecursive(tree *TreeNode, curNavMap *map[string]*NavElement, curNavSlice *[]*NavElement, navActive *[]*NavElement, activeNav string, backToRoot string) {
|
||||
for _, el := range tree.Sub {
|
||||
if el.Hidden {
|
||||
continue // ignore hidden nav points from collections
|
||||
@ -88,8 +92,7 @@ func buildNavigation(tree *TreeNode, curNavMap *map[string]*NavElement, curNavSl
|
||||
|
||||
if activeNav != "" && activeNav != "/" {
|
||||
// calculate relative path
|
||||
bToRoot := helper.BackToRoot(activeNav)
|
||||
navEl.GoTo = bToRoot + navEl.GoTo
|
||||
navEl.GoTo = backToRoot + navEl.GoTo
|
||||
navEl.GoTo = path.Clean(navEl.GoTo)
|
||||
}
|
||||
|
||||
@ -98,6 +101,6 @@ func buildNavigation(tree *TreeNode, curNavMap *map[string]*NavElement, curNavSl
|
||||
*curNavSlice = append(*curNavSlice, &navEl)
|
||||
}
|
||||
|
||||
buildNavigation(el, &subMap, &subSlice, navActive, activeNav)
|
||||
buildNavigationRecursive(el, &subMap, &subSlice, navActive, activeNav, backToRoot)
|
||||
}
|
||||
}
|
||||
|
@ -3,36 +3,58 @@ package mark2web
|
||||
import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"gitbase.de/apairon/mark2web/pkg/helper"
|
||||
)
|
||||
|
||||
// ResolveNavPath fixes nav target relative to current navigation path
|
||||
func ResolveNavPath(target string) string {
|
||||
curNavPath := (*CurrentContext)["CurrentPath"].(string)
|
||||
func (node *TreeNode) ResolveNavPath(target string) string {
|
||||
if strings.HasPrefix(target, "/") {
|
||||
target = helper.BackToRoot(curNavPath) + target
|
||||
target = node.BackToRootPath() + target
|
||||
}
|
||||
target = path.Clean(target)
|
||||
return target
|
||||
}
|
||||
|
||||
// ResolveOutputPath fixes output directory relative to current navigation path
|
||||
func ResolveOutputPath(target string) string {
|
||||
func (node *TreeNode) ResolveOutputPath(target string) string {
|
||||
if strings.HasPrefix(target, "/") {
|
||||
target = Config.Directories.Output + "/" + target
|
||||
} else {
|
||||
target = CurrentTreeNode.OutputPath + "/" + target
|
||||
target = node.OutputPath + "/" + target
|
||||
}
|
||||
return path.Clean(target)
|
||||
}
|
||||
|
||||
// ResolveInputPath fixes input directory relative to current navigation path
|
||||
func ResolveInputPath(target string) string {
|
||||
func (node *TreeNode) ResolveInputPath(target string) string {
|
||||
if strings.HasPrefix(target, "/") {
|
||||
target = Config.Directories.Input + "/" + target
|
||||
} else {
|
||||
target = CurrentTreeNode.InputPath + "/" + target
|
||||
target = node.InputPath + "/" + target
|
||||
}
|
||||
return path.Clean(target)
|
||||
}
|
||||
|
||||
// CurrentNavPath is current navigation path for this node
|
||||
func (node *TreeNode) CurrentNavPath() string {
|
||||
curNavPath := strings.TrimPrefix(node.OutputPath, Config.Directories.Output)
|
||||
curNavPath = strings.TrimPrefix(curNavPath, "/")
|
||||
curNavPath = path.Clean(curNavPath)
|
||||
if curNavPath == "." {
|
||||
curNavPath = ""
|
||||
}
|
||||
|
||||
return curNavPath
|
||||
}
|
||||
|
||||
// BackToRootPath builds ../../ string
|
||||
func (node *TreeNode) BackToRootPath() string {
|
||||
curNavPath := node.CurrentNavPath()
|
||||
|
||||
tmpPath := ""
|
||||
if curNavPath != "" {
|
||||
for i := strings.Count(curNavPath, "/") + 1; i > 0; i-- {
|
||||
tmpPath += "../"
|
||||
}
|
||||
}
|
||||
return tmpPath
|
||||
}
|
||||
|
@ -10,23 +10,16 @@ Data:
|
||||
---
|
||||
# Installation
|
||||
|
||||
Damit die korrekten Versionsinformationen dynamisch in das finale mark2web-Binary eingefügt wurde, ist eine manuelle Installation aus dem Git-Repository sinnvoll.
|
||||
Da die benötigten Pakete über die Go "vendor"-Funktionalität eingebunden sind ist ein `git submodule --init --recursive` nötig, wie im folgenden Abschnitt zu sehen ist:
|
||||
|
||||
```sh
|
||||
mkdir -p $GOPATH/src/gitbase.de/apairon
|
||||
git clone https://gitbase.de/apairon/mark2web.git $GOPATH/src/gitbase.de/apairon/mark2web
|
||||
go get -v gitbase.de/apairon/mark2web/cmd/mark2web
|
||||
|
||||
cd $GOPATH/src/gitbase.de/apairon/mark2web
|
||||
git submodule update --init --recursive
|
||||
|
||||
./build.sh
|
||||
# setze Versioninformationen ins Binary
|
||||
pkg=$GOPATH/src/gitbase.de/apairon/mark2web
|
||||
go install -v -ldflags "-X main.Version=`cat $pkg/build/VERSION` -X main.GitHash=`git --git-dir $pkg/.git rev-parse HEAD` -X main.BuildTime=`date -u '+%Y-%m-%d_%I:%M:%S%p'`" gitbase.de/apairon/mark2web/cmd/mark2web
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Eine Installation über `go install gitbase.de/apairon/mark2web` wird derzeit noch nicht unterstützt, da dabei die Informationen für `mark2web -version` nicht generiert werden.
|
||||
|
||||
## Releases
|
||||
|
||||
Vorkompilierte Binaries finden Sie auf der [Releases-Seite auf gitbase.de](https://gitbase.de/apairon/mark2web/releases).
|
Binary file not shown.
Before Width: | Height: | Size: 790 KiB |
@ -1,150 +0,0 @@
|
||||
---
|
||||
Data:
|
||||
background: /img/wire.jpg
|
||||
|
||||
slider:
|
||||
- img: /img/wire.jpg
|
||||
alt:
|
||||
opacity: 1
|
||||
|
||||
---
|
||||
|
||||
# Konfiguration
|
||||
|
||||
Die Konfigurationsdatein sind im YAML-Format gehalten (siehe: [Wikipedia](https://de.wikipedia.org/wiki/YAML)).
|
||||
|
||||
## globale Einstellungen
|
||||
|
||||
Die obersten Verzeichnis sich befindende Datei `config.yml` kann z.B. folgenden Inhalt haben:
|
||||
|
||||
```yaml
|
||||
Webserver:
|
||||
Type: "apache"
|
||||
|
||||
Assets:
|
||||
FromPath: "assets"
|
||||
ToPath: "assets"
|
||||
Action: "copy"
|
||||
FixTemplate:
|
||||
Find: "\\.\\./assets/"
|
||||
Replace: ""
|
||||
|
||||
OtherFiles:
|
||||
Action: "copy"
|
||||
```
|
||||
|
||||
### Sektion `Webserver:`
|
||||
|
||||
#### `Type:`
|
||||
|
||||
Derzeit wird hier nur der Wert `apache` unterstützt. Ist dieser Wert gesetzt werden automatische .htaccess-Dateien mit mod_rewrite-Anweisungen generiert, die eine saubere Weiterleitung bei entsprechenden Konfig-Anweisungen im `content`-Verzeichnis ermöglichen.
|
||||
|
||||
### Sektion `Assets:`
|
||||
|
||||
`Assets:` steuert, wie mit Bild/JS/CSS Dateien umgegangen werden soll.
|
||||
|
||||
#### `FromPath:`
|
||||
|
||||
Lage des Asset-Verzeichnis unterhalb des `content`-Verzeichnis
|
||||
|
||||
#### `ToPath:`
|
||||
|
||||
Zielverzeichnis im Ausgabe-Verzeichnis der fertig generierten Website
|
||||
|
||||
#### `Action:`
|
||||
|
||||
Derzeit nur `copy`, also das Kopieren der Dateien und Unterordner ins Zielverzeichnis
|
||||
|
||||
#### `FixTemplate:`
|
||||
|
||||
Wenn hier `Find:` (regulärer Ausdruck) und `Replace:` (Ersetzung) angeben sind, werden die gefundenden Pfadangaben in der generierten HTML-Dateien durch den korrekten relativen Pfad zum Asset-Verzeichnis ersetzt.
|
||||
|
||||
### Sektion `OtherFiles:`
|
||||
|
||||
`OtherFiles:` definiert, wie mit anderen Dateien innerhalb des `content`-Verzeichnis umgegangen werden soll.
|
||||
|
||||
#### `Action:`
|
||||
|
||||
Derzeit nur `copy`, also das Kopieren der Dateien in das entsprechende Unterverzeichnis im Ausgabe-Verzeichnis
|
||||
|
||||
---
|
||||
|
||||
## Konfiguration im `content`-Verzeichnis
|
||||
|
||||
Im `content`-Verzeichnis, sowie in jedem Unterverzeichnis unterhalb von `content` kann sich eine `config.yml`-Datei befinden, wie aus folgendem Beispiel:
|
||||
|
||||
```yaml
|
||||
This:
|
||||
GoTo: "/de/service/impressum/"
|
||||
Navname: "Impressumsverweis"
|
||||
|
||||
```
|
||||
|
||||
oder
|
||||
|
||||
```yaml
|
||||
This:
|
||||
Navname: "FAQ's"
|
||||
Data:
|
||||
slogan: "Wer nicht fragt, bekommt keine Antwort."
|
||||
|
||||
Template: "base.html"
|
||||
|
||||
Index:
|
||||
InputFile: "README.md"
|
||||
OutputFile: "index.html"
|
||||
|
||||
Meta:
|
||||
Title: "Fragen und Antworten"
|
||||
Description: "Dies ist die Fragen und Antworten Unterseite."
|
||||
Keywords: "FAQ, Fragen, Antworten"
|
||||
|
||||
Data:
|
||||
background: "bg.jpg"
|
||||
slider:
|
||||
- img: "assets/img/slider1.jpg"
|
||||
alt: "Alternativtext 1"
|
||||
- img: "assets/img/slider2.jpg"
|
||||
alt: "Alternativtext 2"
|
||||
- img: "assets/img/slider3.jpg"
|
||||
alt: "Alternativtext 3"
|
||||
|
||||
```
|
||||
|
||||
### `This:` Sektion
|
||||
|
||||
Sämtlich Werte unterhalb dieser Sektion gelten nur für den Inhalt, bzw. Navigationspunkt in dessen Ordner sich die `config.yml` befindet. Die Werte werden nicht an Unterordner wertervererbt.
|
||||
|
||||
#### `GoTo:`
|
||||
|
||||
Falls der Navigationspunkt selbst keinen Inhalt darstellen soll, sondern nur weiterleiten soll, so wird hier das Weiterleitungsziel eingegeben.
|
||||
Das Ziel ist der absolute (startend mit `/`) oder relative Pfad zum Zielnavigationspunkt.
|
||||
Die Schreibweise des Pfades ist so zu verwenden, wie der Pfad nach Umschreibung und Säuberung des Pfades im Zielverzeichnis dargestellt wird.
|
||||
Aus `de/mainnav/03_Fragen und Antworten` wird also z.B. `de/mainnav/fragen-und-antworten`.
|
||||
|
||||
#### `Navname:`
|
||||
|
||||
Dieser Wert überschreibt den aus dem Ordnernamen automatisch abgeleiteten Navigationspunkt-Namen. Dies ist zum Beispiel dann nützlich, wenn Sonderzeichen im Verzeichnisnamen nicht vorkommen sollen, aber im Namen des Navigationspunkts gebraucht werden.
|
||||
|
||||
#### `Data:`
|
||||
|
||||
Unterhalb von `Data:` können beliebige Datenstrukturen erfasst werden. Da diese Struktur unterhalb von `This:` angeordnet ist, werden auch die Daten nicht weiter an Unterordner vererbt.
|
||||
Hier können z.B. Informationen zum Navigationspunkt abgelegt werden, die im Template Zusatzinformationen darstellen (z.B. ein Slogan zu einem Navigationspunkt).
|
||||
|
||||
### `Meta:` Sektion
|
||||
|
||||
Unter `Title:`, `Description:` und `Keywords:` werden die typischen Metaangaben abgelegt, die im
|
||||
|
||||
```html
|
||||
<head>
|
||||
...
|
||||
</head>
|
||||
```
|
||||
|
||||
übllicherweise Verwendung finden. Die entsprechenden Platzhalter stehen im Template zur Verfügung.
|
||||
|
||||
`Meta:` vererbt seine individuellen Informationen an die Unterordner weiter, sofern diese dort nicht selbst in einer `config.yml` oder im Kopf der Markdown-Datei definiert sind.
|
||||
|
||||
### `Data:` Sektion
|
||||
|
||||
`Data:` an dieser Stelle kann, wie auch `Data:` unterhalb von `This:`, beliebige Daten aufnehmen. Die Daten hier allerdings werden an Unterordner weitervererbt, sofern diese nicht dort oder in der Markdown-Datei selbst festegelegt überschrieben wurden.
|
@ -1,3 +0,0 @@
|
||||
This:
|
||||
Data:
|
||||
teaser: Globale Konfiguration und individuelle Content-Einstellungen
|
@ -0,0 +1,16 @@
|
||||
---
|
||||
Template: base_doc.html
|
||||
|
||||
Data:
|
||||
background: /img/wire.jpg
|
||||
|
||||
slider:
|
||||
- img: /img/wire.jpg
|
||||
alt:
|
||||
opacity: 1
|
||||
|
||||
---
|
||||
|
||||
# Konfiguration
|
||||
|
||||
Die Konfigurationsdatein sind im YAML-Format gehalten (siehe: [Wikipedia](https://de.wikipedia.org/wiki/YAML)).
|
@ -0,0 +1,17 @@
|
||||
Die obersten Verzeichnis sich befindende Datei `config.yml` kann z.B. folgenden Inhalt haben:
|
||||
|
||||
```yaml
|
||||
Webserver:
|
||||
Type: "apache"
|
||||
|
||||
Assets:
|
||||
FromPath: "assets"
|
||||
ToPath: "assets"
|
||||
Action: "copy"
|
||||
FixTemplate:
|
||||
Find: "\\.\\./assets/"
|
||||
Replace: ""
|
||||
|
||||
OtherFiles:
|
||||
Action: "copy"
|
||||
```
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Derzeit wird hier nur der Wert `apache` unterstützt. Ist dieser Wert gesetzt werden automatische .htaccess-Dateien mit mod_rewrite-Anweisungen generiert, die eine saubere Weiterleitung bei entsprechenden Konfig-Anweisungen im `content`-Verzeichnis ermöglichen.
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
`Assets:` steuert, wie mit Bild/JS/CSS Dateien umgegangen werden soll.
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Lage des Asset-Verzeichnis unterhalb des `content`-Verzeichnis
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Zielverzeichnis im Ausgabe-Verzeichnis der fertig generierten Website
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Derzeit nur `copy`, also das Kopieren der Dateien und Unterordner ins Zielverzeichnis
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Wenn hier `Find:` (regulärer Ausdruck) und `Replace:` (Ersetzung) angeben sind, werden die gefundenden Pfadangaben in der generierten HTML-Dateien durch den korrekten relativen Pfad zum Asset-Verzeichnis ersetzt.
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
`OtherFiles:` definiert, wie mit anderen Dateien innerhalb des `content`-Verzeichnis umgegangen werden soll.
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Derzeit nur `copy`, also das Kopieren der Dateien in das entsprechende Unterverzeichnis im Ausgabe-Verzeichnis
|
@ -0,0 +1,45 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Im `content`-Verzeichnis, sowie in jedem Unterverzeichnis unterhalb von `content` kann sich eine `config.yml`-Datei befinden, wie aus folgendem Beispiel:
|
||||
|
||||
```yaml
|
||||
This:
|
||||
GoTo: "/de/service/impressum/"
|
||||
Navname: "Impressumsverweis"
|
||||
|
||||
```
|
||||
|
||||
oder
|
||||
|
||||
```yaml
|
||||
This:
|
||||
Navname: "FAQ's"
|
||||
Data:
|
||||
slogan: "Wer nicht fragt, bekommt keine Antwort."
|
||||
|
||||
Template: "base.html"
|
||||
|
||||
Index:
|
||||
InputFile: "README.md"
|
||||
OutputFile: "index.html"
|
||||
|
||||
Meta:
|
||||
Title: "Fragen und Antworten"
|
||||
Description: "Dies ist die Fragen und Antworten Unterseite."
|
||||
Keywords: "FAQ, Fragen, Antworten"
|
||||
|
||||
Data:
|
||||
background: "bg.jpg"
|
||||
slider:
|
||||
- img: "assets/img/slider1.jpg"
|
||||
alt: "Alternativtext 1"
|
||||
- img: "assets/img/slider2.jpg"
|
||||
alt: "Alternativtext 2"
|
||||
- img: "assets/img/slider3.jpg"
|
||||
alt: "Alternativtext 3"
|
||||
|
||||
```
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Sämtlich Werte unterhalb dieser Sektion gelten nur für den Inhalt, bzw. Navigationspunkt in dessen Ordner sich die `config.yml` befindet. Die Werte werden nicht an Unterordner wertervererbt.
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Falls der Navigationspunkt selbst keinen Inhalt darstellen soll, sondern nur weiterleiten soll, so wird hier das Weiterleitungsziel eingegeben.
|
||||
Das Ziel ist der absolute (startend mit `/`) oder relative Pfad zum Zielnavigationspunkt.
|
||||
Die Schreibweise des Pfades ist so zu verwenden, wie der Pfad nach Umschreibung und Säuberung des Pfades im Zielverzeichnis dargestellt wird.
|
||||
Aus `de/mainnav/03_Fragen und Antworten` wird also z.B. `de/mainnav/fragen-und-antworten`.
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Dieser Wert überschreibt den aus dem Ordnernamen automatisch abgeleiteten Navigationspunkt-Namen. Dies ist zum Beispiel dann nützlich, wenn Sonderzeichen im Verzeichnisnamen nicht vorkommen sollen, aber im Namen des Navigationspunkts gebraucht werden.
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Unterhalb von `Data:` können beliebige Datenstrukturen erfasst werden. Da diese Struktur unterhalb von `This:` angeordnet ist, werden auch die Daten nicht weiter an Unterordner vererbt.
|
||||
Hier können z.B. Informationen zum Navigationspunkt abgelegt werden, die im Template Zusatzinformationen darstellen (z.B. ein Slogan zu einem Navigationspunkt).
|
@ -0,0 +1,17 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
Unter `Title:`, `Description:` und `Keywords:` werden die typischen Metaangaben abgelegt, die im
|
||||
|
||||
```html
|
||||
<head>
|
||||
...
|
||||
</head>
|
||||
```
|
||||
|
||||
übllicherweise Verwendung finden. Die entsprechenden Platzhalter stehen im Template zur Verfügung.
|
||||
|
||||
`Meta:` vererbt seine individuellen Informationen an die Unterordner weiter, sofern diese dort nicht selbst in einer `config.yml` oder im Kopf der Markdown-Datei definiert sind.
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
Data:
|
||||
Version: "ab v1.0"
|
||||
|
||||
---
|
||||
|
||||
`Data:` an dieser Stelle kann, wie auch `Data:` unterhalb von `This:`, beliebige Daten aufnehmen. Die Daten hier allerdings werden an Unterordner weitervererbt, sofern diese nicht dort oder in der Markdown-Datei selbst festegelegt überschrieben wurden.
|
@ -0,0 +1,9 @@
|
||||
This:
|
||||
Data:
|
||||
teaser: Globale Konfiguration und individuelle Content-Einstellungen
|
||||
Collections:
|
||||
- Name: doccoll
|
||||
Directory:
|
||||
Path: "."
|
||||
MatchFilename: "^_\\d+(?P<lowdash>_*)(?P<title>.+)\\.md"
|
||||
ReverseOrder: False
|
@ -292,4 +292,14 @@ code.language-mermaid svg {
|
||||
border-radius: 5px;
|
||||
display:inline-block;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.versionBadge {
|
||||
text-align: right;
|
||||
color: #444;
|
||||
font-size: 10px;
|
||||
padding: 3px;
|
||||
background: #ddd;
|
||||
border: #444 solid 1px;
|
||||
border-radius: 5px;
|
||||
}
|
19
website/templates/base_doc.html
Normal file
19
website/templates/base_doc.html
Normal file
@ -0,0 +1,19 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block part0 %}
|
||||
{{ Body }}
|
||||
{% endblock part0 %}
|
||||
|
||||
{% block part1 %}
|
||||
{% for e in NavElement.ColMap.doccoll %}
|
||||
{% with e.FilenameMatch.lowdash|count + 1 as h %}
|
||||
<h{{ h }}>
|
||||
{{ e.FilenameMatch.title }}
|
||||
{% if e.Data.Version %}
|
||||
<span class="versionBadge">{{ e.Data.Version }}</span>
|
||||
{% endif %}
|
||||
</h{{ h }}>
|
||||
{% endwith %}
|
||||
{{ e.Body }}
|
||||
{% endfor %}
|
||||
{% endblock part1 %}
|
5
website/templates/filters/count.js
Normal file
5
website/templates/filters/count.js
Normal file
@ -0,0 +1,5 @@
|
||||
function count(el, param) {
|
||||
return el.length
|
||||
}
|
||||
|
||||
module.exports = count;
|
Loading…
Reference in New Issue
Block a user