Skip to content

Commit

Permalink
打印页面的前置工作
Browse files Browse the repository at this point in the history
  • Loading branch information
chai2010 committed Oct 29, 2023
1 parent 15fcda2 commit 8e71327
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 2 deletions.
2 changes: 1 addition & 1 deletion pkg/mnbook/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestBookToml_String(t *testing.T) {
var tExpect = BookToml{
Book: BookConfig{
Title: "Book Title",
Authors: []string{"chai2010"},
Authors: []string{"mnbook author"},
Language: "zh",
Src: ".",
},
Expand Down
4 changes: 4 additions & 0 deletions pkg/render/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ type PageInfo struct {
NextUrl string
}

type StaticPageInfo struct {
Content string
}

type SidebarItem struct {
Prefix string
Number string // 1.1, 1.2, ...
Expand Down
9 changes: 9 additions & 0 deletions pkg/render/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import (
//go:embed tmpl/page.html
var tmplPage string

//go:embed tmpl/print.html
var tmplPrintPage string

func (p *BookRendor) run(book *mnbook.Book) (err error) {
if err := p.init(book); err != nil {
return err
Expand Down Expand Up @@ -89,6 +92,12 @@ func (p *BookRendor) renderAllPages() error {
return err
}
}
if err := p.renderPrintPage(); err != nil {
return nil
}
if err := p.render404Page(); err != nil {
return nil
}
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/render/page_404.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ import (
"path/filepath"
)

func (p *BookRendor) render404page() error {
func (p *BookRendor) render404Page() error {
return os.WriteFile(filepath.Join(p.Book.Root, "book", "404.html"), []byte("TODO"), 0666)
}
99 changes: 99 additions & 0 deletions pkg/render/page_print.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2023 <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package render

import (
"bytes"
"os"
"path/filepath"
"strings"
"text/template"

"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/text"
)

func (p *BookRendor) renderPrintPage() error {
var b strings.Builder
for i, page := range p.PageInfos {
s, err := p.renderMarkdownString(i, page)
if err != nil {
return err
}
b.WriteString(s)
}

// todo
printInfo := &StaticPageInfo{
Content: b.String(),
}

// render to page
var fnMap = template.FuncMap{
"genSidebarItems": func(pageRoot string, pageIndex int) string {
return SidebarTree(p.SidebarItems).GenHTML(pageRoot, pageIndex)
},
}

var buf bytes.Buffer
t := template.Must(template.New("").Funcs(fnMap).Parse(tmplPage))
err := t.Execute(&buf, printInfo)
if err != nil {
return err
}

dstAbsPath := filepath.Join(p.Book.Root, "book/print.html")

os.MkdirAll(filepath.Dir(dstAbsPath), 0777)
if err := os.WriteFile(dstAbsPath, buf.Bytes(), 0666); err != nil {
return err
}

return nil
}

func (p *BookRendor) renderMarkdownString(idx int, page *PageInfo) (string, error) {
markdown := goldmark.New(
goldmark.WithExtensions(extension.GFM),
)

reader := text.NewReader([]byte(page.Content))
doc := markdown.Parser().Parse(reader)
p.fixupLinkPath(doc, page)

var b strings.Builder
if err := markdown.Renderer().Render(&b, []byte(page.Content), doc); err != nil {
return "", err
}

return b.String(), nil
}

func (p *BookRendor) fixupLinkPath(n ast.Node, page *PageInfo) {
ast.Walk(n, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
switch n := n.(type) {
case *ast.Image:
var dest = string(n.Destination)
for strings.HasPrefix(dest, "../") {
dest = strings.TrimPrefix(dest, "../")
}
n.Destination = []byte(dest)
case *ast.Link:
var dest = string(n.Destination)
for strings.HasPrefix(dest, "../") {
dest = strings.TrimPrefix(dest, "../")
}
if ext := filepath.Ext(dest); strings.EqualFold(ext, ".md") {
dest = dest[:len(dest)-len(".md")] + ".html"
}
n.Destination = []byte(dest)
}
}
return ast.WalkContinue, nil
})
}
166 changes: 166 additions & 0 deletions pkg/render/tmpl/print.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<!DOCTYPE HTML>{{$page := .}}
<html lang="zh" class="sidebar-visible no-js light">
<head>
<!-- Book generated using https://github.com/wa-lang/mnbook -->
<meta charset="UTF-8">
<title>{{$page.Title}}</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />

<link rel="icon" href="{{$page.Root}}/favicon.svg">
<link rel="shortcut icon" href="{{$page.Root}}/favicon.png">
<link rel="stylesheet" href="{{$page.Root}}/css/variables.css">
<link rel="stylesheet" href="{{$page.Root}}/css/general.css">
<link rel="stylesheet" href="{{$page.Root}}/css/chrome.css">
<link rel="stylesheet" href="{{$page.Root}}/css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="{{$page.Root}}/FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="{{$page.Root}}/fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="{{$page.Root}}/highlight.css">
<link rel="stylesheet" href="{{$page.Root}}/tomorrow-night.css">
<link rel="stylesheet" href="{{$page.Root}}/ayu-highlight.css">

<!-- Custom theme stylesheets -->
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "{{$page.Root}}/";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>

<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mnbook-theme');
var sidebar = localStorage.getItem('mnbook-sidebar');

if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mnbook-theme', theme.slice(1, theme.length - 1));
}

if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mnbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>

<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mnbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>

<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mnbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>

<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
{{genSidebarItems $page.Root $page.Index}}
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>

<div id="page-wrapper" class="page-wrapper">

<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
</div>

<h1 class="menu-title"><a href="{{$page.Root}}/index.html">{{$page.Book.Title}}</a></h1>

<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
{{if $page.Book.GitRepoUrl}}
<a href="{{$page.Book.GitRepoUrl}}" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa {{$page.Book.GitRepoIcon}}"></i>
</a>
{{end}}
{{if $page.Book.EditUrlTemplate}}
<a href="{{$page.EditUrlTemplate}}" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
{{end}}
</div>
</div>

<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>

<div id="content" class="content">
<main>
{{$page.RawHtml}}
</main>

<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
{{if $page.HasPrev}}
<a rel="prev" href="{{$page.Root}}/{{$page.PrevUrl}}" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
{{end}}
{{if $page.HasNext}}
<!-- {{$page.Root}}/{{$page.NextUrl}} -->
<a rel="next" href="{{$page.Root}}/{{$page.NextUrl}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
{{end}}
<div style="clear: both"></div>
</nav>
</div>
</div>

</div>

<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="{{$page.Root}}/mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="{{$page.Root}}/clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="{{$page.Root}}/highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="{{$page.Root}}/book.js" type="text/javascript" charset="utf-8"></script>

<!-- Custom JS scripts -->
</body>
</html>

0 comments on commit 8e71327

Please sign in to comment.