-
-
Notifications
You must be signed in to change notification settings - Fork 47
/
doc.go
156 lines (140 loc) · 4.21 KB
/
doc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright 2020 The golang.design Initiative.
// All rights reserved. Use of this source code
// is governed by a MIT license that can be found
// in the LICENSE file.
package main
import (
"bytes"
"fmt"
"html/template"
"io/ioutil"
"log"
"os"
"strings"
"time"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer/html"
)
var (
md goldmark.Markdown
pctx parser.Context
)
type data struct {
Lang string
Selected string
Navigation template.HTML
Content template.HTML
UpdatedAt string
}
func init() {
md = goldmark.New(
goldmark.WithExtensions(extension.Table),
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
),
goldmark.WithRendererOptions(
// html.WithHardWraps(), // do this someday.
html.WithUnsafe(),
),
)
pctx = parser.NewContext(parser.WithIDs(newIDs()))
}
func main() {
index := convertMD("README.md")
parseTemplate("en", "index", index)
cn := convertMD("README_cn.md", parser.WithContext(pctx))
parseTemplate("cn", "cn", cn)
fmt.Println("golang-design/history: A Documentary of Go")
}
// convertMD convert md to html
func convertMD(filename string, opts ...parser.ParseOption) bytes.Buffer {
d, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatalf("Read: cannot read README.md, err: %v", err)
}
var b bytes.Buffer
err = md.Convert(d, &b, opts...)
if err != nil {
log.Fatalf("Convert: cannot convert README from markdown to html, err: %v", err)
}
return b
}
// parseTemplate Add md data to the template
func parseTemplate(lang, target string, b bytes.Buffer) {
f, err := os.Create("public/" + target + ".html")
if err != nil {
log.Fatalf("Create: cannot create index.html, err: %v", err)
}
// Find TOC, and remove all hard coded all back to top. Then use
// back to top button for navigation.
//
// This is urgly, I know. At least this works so far with least efforts.
// A better and generic way obviously is to do DOM tree analysis.
dom := b.String()
tocStart := strings.Index(dom, "<p><strong>Table of Contents</strong></p>")
tocEnd := strings.Index(dom, `<hr>`)
toc := dom[tocStart:tocEnd]
dom = dom[:tocStart] + `<div class="doc-nav-mobile">` +
dom[tocStart:tocEnd] + `</div>` + dom[tocEnd:]
dom = strings.ReplaceAll(dom, `<p><a href="#top">Back To Top</a></p>`, "")
tmpl := template.Must(template.New(target).Parse(indexTemplate))
var selected string
if "index" != target {
selected = "selected"
}
tmpl.Execute(f, data{
Lang: lang,
Selected: selected,
Navigation: template.HTML(toc),
Content: template.HTML(dom),
UpdatedAt: time.Now().UTC().Format("2006.01.02"),
})
}
const indexTemplate = `
<!DOCTYPE html>
<html lang="{{.Lang}}">
<head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-80889616-4"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-80889616-4');
</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Go: A Documentary</title>
<link rel="stylesheet" href="bootstrap.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="header row">
<div class="col-3 dark-switch">
<label>
<select Onchange="window.open(this.options[this.selectedIndex].value,target='_self')">
<option value="index.html">English</option>
<option {{.Selected}} value="cn.html">简体中文</option>
</select>
</label>
</div>
<div class="col-6"></div>
<div class="col-3 dark-switch">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="darkSwitch" />
<label class="custom-control-label" for="darkSwitch">Dark Mode</label>
</div>
</div>
</div>
<div id="btt"><a href="#top">⬆</a></div>
<div id="container" class="row">
<div class="doc-content col-lg-9">{{.Content}} <p>Last Updated: {{.UpdatedAt}}</p></div>
<nav class="doc-nav col-lg-3">{{.Navigation}}</nav>
</div>
<script src="dark.js"></script>
<script async src="//changkun.de/urlstat/client.js"></script>
</body>
</html>
`