Browse Source

add github css style

master v0_20240128
arnaucube 3 months ago
parent
commit
3ee114df27
7 changed files with 3463 additions and 104 deletions
  1. +1
    -1
      README.md
  2. +3383
    -0
      css.go
  3. +1
    -1
      go.mod
  4. +11
    -2
      main.go
  5. +46
    -96
      templates.go
  6. +14
    -0
      test.md
  7. +7
    -4
      utils.go

+ 1
- 1
README.md

@ -2,6 +2,7 @@
Server that renders markdown files and live updates the page each time that the file is updated.
![screenshot00](https://raw.githubusercontent.com/arnaucube/md-live-server/master/screenshot00.png 'screenshot00')
*(Current visual style is more similar to GitHub's style)*
## Usage
Put the binary file `md-live-server` in your `$PATH`, and then go to the directory where are the markdown files that want to live render, and just use:
@ -23,4 +24,3 @@ set backupcopy=yes
- [x] LaTex support
- [x] mermaidjs
- [ ] graphviz
- [ ] colour `<code>` with syntax highlighting

+ 3383
- 0
css.go
File diff suppressed because it is too large
View File


+ 1
- 1
go.mod

@ -1,6 +1,6 @@
module md-live-server
go 1.19
go 1.21
require (
github.com/fatih/color v1.9.0

+ 11
- 2
main.go

@ -8,12 +8,13 @@ import (
"strings"
"time"
"github.com/fatih/color"
"github.com/fsnotify/fsnotify"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
)
const version = "v0_20230804"
const version = "v0_20240128"
var (
upgrader = websocket.Upgrader{
@ -31,6 +32,10 @@ type PageModel struct {
func main() {
fmt.Println("md-live-server version:", version)
// fill the CSS into the HTML templates
dirTemplate = fillCSSintoTemplate(dirTemplate)
htmlTemplate = fillCSSintoTemplate(htmlTemplate)
router := mux.NewRouter()
router.HandleFunc("/", getDir).Methods("GET")
router.HandleFunc("/{path}", getPage).Methods("GET")
@ -76,7 +81,11 @@ func getPage(w http.ResponseWriter, r *http.Request) {
}
content, err := fileToHTML(path)
check(err)
if err != nil {
color.Red(err.Error())
fmt.Fprintf(w, errTemplate)
return
}
var page PageModel
page.Title = path

+ 46
- 96
templates.go

@ -1,25 +1,41 @@
package main
import (
"strings"
)
// html templates are here instead of an .html file to avoid depending on external files
// in this way, everything is inside the binary
const dirTemplate = `
func fillCSSintoTemplate(template string) string {
if strings.Contains(template, "[CSS]") {
template = strings.Replace(template, "[CSS]", cssTemplate, -1)
}
return template
}
var dirTemplate = `
<!DOCTYPE html>
<html>
<title>{{.Title}}</title>
[CSS]
<style>
body {
font-family: Arial, Helvetica, sans-serif;
box-sizing: border-box;
min-width: 200px;
max-width: 980px;
margin: 0 auto;
padding: 45px;
}
.dark {
background:#1d2021;
color:#cccccc;
}
.dark a, a:hover, a:visited {
color: #458588;
@media (prefers-color-scheme: dark) {
body {
background-color: #0d1117;
}
}
</style>
<body class="dark">
<body class="dark-theme">
<article class="markdown-body">
<input onclick="switchThemeClick()" type="checkbox" id="themeSwitcher" style="float:right;">
{{.Content}}
@ -29,13 +45,15 @@ body {
if (theme === "light") {
document.getElementById("themeSwitcher").checked = false;
document.body.className = theme;
} else {
document.getElementById("themeSwitcher").checked = true;
}
function switchThemeClick() {
theme = localStorage.getItem("theme");
if (theme === "light") {
document.getElementById("themeSwitcher").checked = true;
theme = "dark";
theme = "dark-theme";
localStorage.setItem("theme", theme);
} else {
document.getElementById("themeSwitcher").checked = false;
@ -46,105 +64,34 @@ body {
}
</script>
</article>
</body>
</html>
`
const htmlTemplate = `
var htmlTemplate = `
<!DOCTYPE html>
<html>
<title>{{.Title}}</title>
[CSS]
<style>
body {
font-family: Arial, Helvetica, sans-serif;
}
.dark {
background:#1d2021;
color:#cccccc;
}
a, a:hover, a:visited {
color: #458588;
}
pre, code{
padding-left: 3px;
padding-right: 3px;
border-radius: 3px;
background: #cccccc;
}
.dark pre, .dark code{
padding-left: 3px;
padding-right: 3px;
border-radius: 3px;
background: #333333;
}
pre{
padding: 5px;
}
pre>code {
color: #000000;
}
.dark pre>code {
color: #c0fffa;
}
h1:after{
content:' ';
display:block;
border:1px solid #cccccc;
}
h2:after{
content:' ';
display:block;
border:0.7px solid #cccccc;
}
.dark th{
padding: 3px;
border: 1px solid #234b4f;
background-color: #143134;
}
td{
padding: 3px;
border: 1px solid #234b4f;
}
.container {
width: 100%;
padding-right: 1rem;
padding-left: 1rem;
margin-right: auto;
margin-left: auto;
}
@media (min-width: 576px) {
.container {
max-width: 540px;
}
}
@media (min-width: 768px) {
.container {
max-width: 720px;
}
box-sizing: border-box;
min-width: 200px;
max-width: 980px;
margin: 0 auto;
padding: 45px;
}
@media (min-width: 992px) {
.container {
max-width: 800px;
}
}
@media (min-width: 1200px) {
.container {
max-width: 800px;
}
}
@media (min-width: 1400px) {
.container {
max-width: 800px;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #0d1117;
}
}
</style>
<body class="dark">
<body class="dark-theme">
<article class="markdown-body">
<input onclick="switchThemeClick()" type="checkbox" id="themeSwitcher" style="float:right;">
<a href="/" title="go to root">root</a>
<div id="content" class="container">
@ -219,13 +166,15 @@ td{
if (theme === "light") {
document.getElementById("themeSwitcher").checked = false;
document.body.className = theme;
} else {
document.getElementById("themeSwitcher").checked = true;
}
function switchThemeClick() {
theme = localStorage.getItem("theme");
if (theme === "light") {
document.getElementById("themeSwitcher").checked = true;
theme = "dark";
theme = "dark-theme";
localStorage.setItem("theme", theme);
} else {
document.getElementById("themeSwitcher").checked = false;
@ -236,6 +185,7 @@ td{
}
</script>
</article>
</body>
</html>
`

+ 14
- 0
test.md

@ -13,6 +13,7 @@
### third header
Asdf asdf asdf
- Lorem ipsum bla bla `ipsum` bla bla
- Lorem ipsum bla bla `ipsum` bla bla
### Some code
@ -46,3 +47,16 @@ graph LR
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner);
</pre>
## Lorem ipsum
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Fermentum dui faucibus in ornare quam viverra orci sagittis. Augue lacus viverra vitae congue eu consequat ac. Integer quis auctor elit sed vulputate mi. Dolor purus non enim praesent elementum facilisis. In ornare quam viverra orci sagittis. Feugiat vivamus at augue eget. Dui nunc mattis enim ut. Pellentesque diam volutpat commodo sed egestas. Ut consequat semper viverra nam libero justo. Nisi porta lorem mollis aliquam ut porttitor. Nulla facilisi etiam dignissim diam quis enim. Vestibulum sed arcu non odio.
Eleifend quam adipiscing vitae proin sagittis nisl rhoncus. Vel risus commodo viverra maecenas accumsan lacus vel facilisis. Integer enim neque volutpat ac tincidunt vitae semper quis lectus. Faucibus scelerisque eleifend donec pretium. Eu facilisis sed odio morbi quis commodo. Phasellus vestibulum lorem sed risus ultricies tristique nulla. Magnis dis parturient montes nascetur ridiculus mus. Lorem mollis aliquam ut porttitor leo a. A lacus vestibulum sed arcu. Egestas fringilla phasellus faucibus scelerisque eleifend. Erat velit scelerisque in dictum non consectetur a erat. Neque sodales ut etiam sit amet. Montes nascetur ridiculus mus mauris vitae.
Ac feugiat sed lectus vestibulum mattis. Cum sociis natoque penatibus et magnis dis. Lectus urna duis convallis convallis tellus id interdum velit. Fermentum leo vel orci porta non pulvinar. Volutpat diam ut venenatis tellus. Sagittis id consectetur purus ut. Felis donec et odio pellentesque diam volutpat. Tortor dignissim convallis aenean et tortor at risus viverra. Justo donec enim diam vulputate ut pharetra. A cras semper auctor neque. Id interdum velit laoreet id donec ultrices. Ac auctor augue mauris augue neque gravida in fermentum et. At tellus at urna condimentum mattis pellentesque. Diam quam nulla porttitor massa id neque aliquam vestibulum. Cursus vitae congue mauris rhoncus aenean. Nunc sed id semper risus in hendrerit.
Ornare arcu odio ut sem. Volutpat ac tincidunt vitae semper quis lectus. Elit scelerisque mauris pellentesque pulvinar. Metus dictum at tempor commodo ullamcorper a lacus vestibulum. Tincidunt lobortis feugiat vivamus at. Quam id leo in vitae turpis massa sed elementum tempus. Feugiat in fermentum posuere urna nec tincidunt. Nec tincidunt praesent semper feugiat nibh sed pulvinar proin. Pharetra et ultrices neque ornare aenean. Dui vivamus arcu felis bibendum ut tristique et egestas. Ultrices eros in cursus turpis massa. Parturient montes nascetur ridiculus mus mauris vitae. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Egestas dui id ornare arcu odio ut sem nulla pharetra. Vel facilisis volutpat est velit egestas. Cras semper auctor neque vitae tempus quam pellentesque. Mi ipsum faucibus vitae aliquet nec ullamcorper sit.
Etiam erat velit scelerisque in. Mauris vitae ultricies leo integer. Duis convallis convallis tellus id interdum velit laoreet id donec. Vitae elementum curabitur vitae nunc sed velit dignissim. Arcu bibendum at varius vel pharetra vel turpis nunc. Pretium aenean pharetra magna ac placerat vestibulum. Velit egestas dui id ornare arcu odio. At tempor commodo ullamcorper a lacus vestibulum sed arcu non. Blandit libero volutpat sed cras ornare. Nulla facilisi nullam vehicula ipsum a arcu cursus. Interdum posuere lorem ipsum dolor sit amet. Turpis egestas maecenas pharetra convallis posuere morbi. Nunc sed blandit libero volutpat. Felis eget velit aliquet sagittis id consectetur purus ut. Ac felis donec et odio pellentesque diam volutpat. Varius sit amet mattis vulputate enim nulla aliquet porttitor lacus.

+ 7
- 4
utils.go

@ -25,13 +25,13 @@ func readDir(dirpath string) []string {
return elems
}
func readFile(path string) string {
func readFile(path string) (string, error) {
dat, err := ioutil.ReadFile(path)
if err != nil {
color.Red(path)
return "", err
}
check(err)
return string(dat)
return string(dat), nil
}
func fileToHTML(path string) (string, error) {
@ -39,7 +39,10 @@ func fileToHTML(path string) (string, error) {
parser.Autolink | parser.Strikethrough | parser.SpaceHeadings | parser.HeadingIDs |
parser.BackslashLineBreak | parser.DefinitionLists | parser.MathJax
mdcontent := readFile(path)
mdcontent, err := readFile(path)
if err != nil {
return "", err
}
mdParser := parser.NewWithExtensions(mdExtensions)
htmlcontent := markdown.ToHTML([]byte(mdcontent), mdParser, nil)

Loading…
Cancel
Save