diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2018-02-15 23:07:37 -0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2018-02-15 23:07:37 -0800 |
commit | c0c84ce814bb535fd770521dc1acf16b2c172c4e (patch) | |
tree | 876ca0d2a75338d42245f198ed13616e2d6824f4 | |
parent | 4014f989b5bbea2737bb2b7125410115041a6a6a (diff) | |
download | mill-c0c84ce814bb535fd770521dc1acf16b2c172c4e.tar.gz mill-c0c84ce814bb535fd770521dc1acf16b2c172c4e.tar.bz2 mill-c0c84ce814bb535fd770521dc1acf16b2c172c4e.zip |
generate a reasonable-looking docsite using my blog code
-rwxr-xr-x | ci/publish-docs.sh | 9 | ||||
-rw-r--r-- | docs/_config.yml | 1 | ||||
-rw-r--r-- | docs/build.sc | 189 | ||||
-rw-r--r-- | docs/favicon.png | bin | 0 -> 206 bytes | |||
-rw-r--r-- | docs/index.md | 21 | ||||
-rw-r--r-- | docs/logo-white.svg | 1 | ||||
-rw-r--r-- | docs/pageStyles.sc | 130 | ||||
-rw-r--r-- | docs/pages.sc | 192 | ||||
-rw-r--r-- | docs/pages/1 - Intro to Mill.md (renamed from docs/intro.md) | 12 | ||||
-rw-r--r-- | docs/pages/2 - Configuring Mill.md (renamed from docs/configure.md) | 0 | ||||
-rw-r--r-- | docs/pages/3 - Common Project Layouts.md (renamed from docs/example.md) | 20 | ||||
-rw-r--r-- | docs/pages/3 - Tasks.md (renamed from docs/tasks.md) | 0 | ||||
-rw-r--r-- | docs/pages/4 - Modules.md (renamed from docs/modules.md) | 0 | ||||
-rw-r--r-- | docs/pages/5 - Cross Builds.md (renamed from docs/cross.md) | 0 | ||||
-rw-r--r-- | docs/pages/6 - Extending Mill.md (renamed from docs/extending.md) | 0 | ||||
-rw-r--r-- | docs/pages/7 - Mill Internals.md (renamed from docs/internals.md) | 0 |
16 files changed, 542 insertions, 33 deletions
diff --git a/ci/publish-docs.sh b/ci/publish-docs.sh new file mode 100755 index 00000000..044b2ff5 --- /dev/null +++ b/ci/publish-docs.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -eux + +curl -L -o ~/bin/amm https://github.com/lihaoyi/Ammonite/releases/download/1.0.0/2.11-1.0.0 && chmod +x ~/bin/amm; fi + +cd docs + +amm build.sc --publish true
\ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index b8497135..00000000 --- a/docs/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-leap-day
\ No newline at end of file diff --git a/docs/build.sc b/docs/build.sc new file mode 100644 index 00000000..7c5ff442 --- /dev/null +++ b/docs/build.sc @@ -0,0 +1,189 @@ +// Load dependencies +import $ivy.{`org.pegdown:pegdown:1.6.0`, `com.lihaoyi::scalatags:0.6.5`} +import $file.pageStyles, pageStyles._ +import $file.pages, pages._ +import scalatags.Text.all._ + +import ammonite.ops._ +import collection.JavaConverters._ +import org.pegdown.{PegDownProcessor, ToHtmlSerializer, LinkRenderer, Extensions} +import org.pegdown.ast.{VerbatimNode, ExpImageNode, HeaderNode, TextNode, SimpleNode, TableNode} + +val postsFolder = cwd/'pages + +interp.watch(postsFolder) + +val targetFolder = cwd/'target + + +val (markdownFiles, otherFiles) = ls! postsFolder partition (_.ext == "md") +markdownFiles.foreach(println) +// Walk the posts/ folder and parse out the name, full- and first-paragraph- +// HTML of each post to be used on their respective pages and on the index + +val posts = { + val split = for(path <- markdownFiles) yield { + val Array(number, name) = path.last.split(" - ", 2) + (number, name.stripSuffix(".md"), path) + } + for ((index, name, path) <- split.sortBy(_._1.toInt)) yield { + val processor = new PegDownProcessor( + Extensions.FENCED_CODE_BLOCKS | Extensions.TABLES | Extensions.AUTOLINKS + ) + val ast = processor.parseMarkdown(read! path toArray) + val headers = collection.mutable.Buffer.empty[(String, Int)] + class Serializer extends ToHtmlSerializer(new LinkRenderer){ + override def printImageTag(rendering: LinkRenderer.Rendering) { + printer.print("<div style=\"text-align: center\"><img") + printAttribute("src", rendering.href) + // shouldn't include the alt attribute if its empty + if(!rendering.text.equals("")){ + printAttribute("alt", rendering.text) + } + import collection.JavaConversions._ + for (attr <- rendering.attributes) { + printAttribute(attr.name, attr.value) + } + printer.print(" style=\"max-width: 100%; max-height: 500px\"") + printer.print(" /></div>") + } + override def visit(node: HeaderNode) = { + val tag = "h" + node.getLevel() + + + val id = + node + .getChildren + .asScala + .collect{case t: TextNode => t.getText} + .mkString + + headers.append(id -> node.getLevel()) + + + val setId = s"id=${'"'+sanitize(id)+'"'}" + printer.print(s"""<$tag $setId class="${Styles.hoverBox.name}">""") + visitChildren(node) + printer.print( + a(href := ("#" + sanitize(id)), Styles.hoverLink)( + i(cls := "fa fa-link", aria.hidden := true) + ).render + ) + printer.print(s"</$tag>") + } + + override def visit(node: VerbatimNode) = { + printer.println().print( + """<pre style="background-color: #f8f8f8">""" + + s"""<code style="white-space:pre; background-color: #f8f8f8" class="${node.getType()}">""" + ) + + var text = node.getText() + // print HTML breaks for all initial newlines + while(text.charAt(0) == '\n') { + printer.print("\n") + text = text.substring(1) + } + printer.printEncoded(text) + printer.print("</code></pre>") + } + override def visit(node: TableNode) = { + currentTableNode = node + printer.print("<table class=\"table table-bordered\">") + visitChildren(node) + printer.print("</table>") + currentTableNode = null + } + } + + val postlude = Seq[Frag]( + hr, + + p( + b("About the Author:"), + i( + " Haoyi is a software engineer, an early contributor to ", + a(href:="http://www.scala-js.org/")("Scala.js"), + ", and the author of many open-source Scala tools such as Mill, the ", + a(href:="lihaoyi.com/Ammonite", "Ammonite REPL"), " and ", + a(href:="https://github.com/lihaoyi/fastparse", "FastParse"), ". " + ) + ), + p( + i( + "If you've enjoy using Mill, or enjoyed using Haoyi's other open ", + "source libraries, please chip in (or get your Company to chip in!) via ", + a(href:="https://www.patreon.com/lihaoyi", "Patreon"), " so he can ", "continue his open-source work" + ) + ), + hr + ).render + + val rawHtmlContent = new Serializer().toHtml(ast) + postlude + PostInfo(name, headers, rawHtmlContent) + } +} + +def formatRssDate(date: java.time.LocalDate) = { + date + .atTime(0, 0) + .atZone(java.time.ZoneId.of("UTC")) + .format(java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME) +} + +@main +def main(publish: Boolean = false) = { + + rm! targetFolder + + mkdir! targetFolder/'page + for(otherFile <- otherFiles){ + cp(otherFile, targetFolder/'page/(otherFile relativeTo postsFolder)) + } + + cp(cwd/"favicon.png", targetFolder/"favicon.ico") + cp(cwd/"logo-white.svg", targetFolder/"logo-white.svg") + + for(i <- posts.indices){ + val post = posts(i) + + val adjacentLinks = div(display.flex, flexDirection.row, justifyContent.spaceBetween)( + for((j, isNext) <- Seq(i-1 -> false, i+1 -> true)) + yield posts.lift(j) match{ + case None => div() + case Some(dest) => + renderAdjacentLink( + isNext, + dest.name, + (i == 0, j == 0) match { + case (true, true) => s"index.html" + case (true, false) => s"page/${sanitize(dest.name)}.html" + case (false, true) => s"../index.html" + case (false, false) => s"${sanitize(dest.name)}.html" + } + ) + } + ) + + + write( + if (i == 0) targetFolder / "index.html" + else targetFolder/'page/s"${sanitize(post.name)}.html", + postContent( + i == 0, + post, + adjacentLinks, + posts.map(_.name) + ) + ) + } + + if (publish){ + implicit val wd = cwd/'target + %git 'init + %git('add, "-A", ".") + %git('commit, "-am", "first commit") + %git('remote, 'add, 'origin, "git@github.com:lihaoyi/mill.git") + %git('push, "-uf", 'origin, "master:gh-pages") + } +}
\ No newline at end of file diff --git a/docs/favicon.png b/docs/favicon.png Binary files differnew file mode 100644 index 00000000..82430a78 --- /dev/null +++ b/docs/favicon.png diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 0b6577c5..00000000 --- a/docs/index.md +++ /dev/null @@ -1,21 +0,0 @@ -Mill is your shiny new Scala build tool! Confused by SBT? Frustrated by Maven? -Perplexed by Gradle? Give Mill a try! - -Mill is a general purpose build-tool. It has built in support for the -[Scala](https://www.scala-lang.org/) programming language, and can serve as a -replacement for [SBT](http://www.scala-sbt.org/), but can also be extended to -support any other language or platform via modules (written in Java or Scala) or -through external subprocesses. - -Mill aims for simplicity by re-using concepts you are already familiar with to -let you define your project's build. Mill's `build.sc` files are Scala scripts. - - -- [Introduction](intro.html) -- [Configuring Mill](configure.html) -- [Example Project Layouts](example.html) -- [Extending](extending.html) -- [Tasks](tasks.html) -- [Modules](modules.html) -- [Cross Building](cross.html) -- [Internals](internals.html)
\ No newline at end of file diff --git a/docs/logo-white.svg b/docs/logo-white.svg new file mode 100644 index 00000000..a681aa9f --- /dev/null +++ b/docs/logo-white.svg @@ -0,0 +1 @@ +<!DOCTYPE html><svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><polyline points="24,-44.0 0,4.0 0,20.0 24,-28.0" fill="#f8f8f8"></polyline><polyline points="24,-20.0 0,28.0 0,44.0 24,-4.0" fill="#f8f8f8"></polyline><polyline points="24,4.0 0,52.0 0,68.0 24,20.0" fill="#f8f8f8"></polyline></svg>
\ No newline at end of file diff --git a/docs/pageStyles.sc b/docs/pageStyles.sc new file mode 100644 index 00000000..06651b1d --- /dev/null +++ b/docs/pageStyles.sc @@ -0,0 +1,130 @@ +import $ivy.`com.lihaoyi::scalatags:0.6.5` + +import scalatags.stylesheet._ +import scalatags.Text.all._ + + +val marginWidth = "25%" +object WideStyles extends StyleSheet{ + initStyleSheet() + override def customSheetName = Some("WideStyles") + def header = cls( + position.fixed, + top := 0, + bottom := 0, + width := marginWidth, + justifyContent.center, + display.flex, + flexDirection.column + ) + def tableOfContentsItem = cls( + // We have to use inline-block and verticalAlign.middle and width: 100% + // here, instead of simply using display.block, because display.block items + // with overflow.hidden seem to misbehave and render badly in different ways + // between firefox (renders correctly), chrome (body of list item is offset + // one row from the bullet) and safari (bullet is entirely missing) + display.`inline-block`, + width := "100%", + verticalAlign.middle, + overflow.hidden, + textOverflow.ellipsis + + ) + def tableOfContents = cls( + display.flex, + flexDirection.column, + flexGrow := 1, + flexShrink := 1, + minHeight := 0, + width := "100%" + + ) + def content = cls( + padding := "2em 3em 0", + padding := 48, + marginLeft := marginWidth, + boxSizing.`border-box` + ) + def footer = cls( + position.fixed, + bottom := 0, + height := 50, + width := marginWidth + ) + def marginLeftZero = cls( + marginLeft := 0 + ) +} +object NarrowStyles extends StyleSheet{ + initStyleSheet() + override def customSheetName = Some("NarrowStyles") + def header = cls( + marginBottom := 10 + ) + def content = cls( + padding := 16 + ) + def headerContent = cls( + flexDirection.row, + width := "100%", + display.flex, + alignItems.center + ) + + def flexFont = cls( + fontSize := "4vw" + ) + def disappear = cls( + display.none + ) + def floatLeft = cls( + float.left, + marginLeft := 30 + ) +} +object Styles extends CascadingStyleSheet{ + initStyleSheet() + override def customSheetName = Some("Styles") + def hoverBox = cls( + display.flex, + flexDirection.row, + alignItems.center, + justifyContent.spaceBetween, + &hover( + hoverLink( + opacity := 0.5 + ) + ) + ) + def hoverLink = cls( + opacity := 0.1, + &hover( + opacity := 1.0 + ) + ) + def headerStyle = cls( + backgroundColor := "rgb(61, 79, 93)", + display.flex, + boxSizing.`border-box` + ) + def headerLinkBox = cls( + flex := 1, + display.flex, + flexDirection.column, + ) + def headerLink = cls( + flex := 1, + display.flex, + justifyContent.center, + alignItems.center, + padding := "10px 10px" + ) + def footerStyle = cls( + display.flex, + justifyContent.center, + color := "rgb(158, 167, 174)" + ) + def subtleLink = cls( + textDecoration.none + ) +}
\ No newline at end of file diff --git a/docs/pages.sc b/docs/pages.sc new file mode 100644 index 00000000..81ca009b --- /dev/null +++ b/docs/pages.sc @@ -0,0 +1,192 @@ +import $ivy.`com.lihaoyi::scalatags:0.6.5` +import scalatags.Text.all._, scalatags.Text.tags2 +import java.time.LocalDate +import $file.pageStyles, pageStyles._ + +case class PostInfo(name: String, + headers: Seq[(String, Int)], + rawHtmlContent: String) + + +def sanitize(s: String): String = { + s.split(" |-", -1).map(_.filter(_.isLetterOrDigit)).mkString("-").toLowerCase +} +def pageChrome(titleText: Option[String], + homePage: Boolean, + contents: Frag, + contentHeaders: Seq[(String, Int)], + pageHeaders: Seq[String]): String = { + val pageTitle = titleText.getOrElse("Mill") + val sheets = Seq( + "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css", + "https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css", + "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/styles/github-gist.min.css" + ) + + + html( + head( + meta(charset := "utf-8"), + for(sheet <- sheets) + yield link(href := sheet, rel := "stylesheet", `type` := "text/css" ), + tags2.title(pageTitle), + tags2.style(s"@media (min-width: 60em) {${WideStyles.styleSheetText}}"), + tags2.style(s"@media (max-width: 60em) {${NarrowStyles.styleSheetText}}"), + tags2.style(Styles.styleSheetText), + script(src:="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"), + script(src:="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/languages/scala.min.js"), + script(raw("hljs.initHighlightingOnLoad();")), + // This makes media queries work on iphone (???) + // http://stackoverflow.com/questions/13002731/responsive-design-media-query-not-working-on-iphone + meta(name:="viewport", content:="initial-scale = 1.0,maximum-scale = 1.0") + ), + body(margin := 0, backgroundColor := "#f8f8f8")( + navBar(homePage, contentHeaders, pageHeaders), + div( + WideStyles.content, + NarrowStyles.content, + maxWidth := 900, + titleText.map(h1(_)), + contents + ), + if (contentHeaders.nonEmpty) frag() + else div( + WideStyles.footer, + Styles.footerStyle, + "Last published ", currentTimeText + ) + + ) + ).render +} + +def navBar(homePage: Boolean, contentHeaders: Seq[(String, Int)], pageHeaders: Seq[String]) = { + def navList(navLabel: String, frags: Frag, narrowHide: Boolean) = { + div( + WideStyles.tableOfContents, + if(narrowHide) NarrowStyles.disappear else frag(), + color := "#f8f8f8" + )( + div(paddingLeft := 40, NarrowStyles.disappear)( + b(navLabel) + ), + div(overflowY.scroll, flexShrink := 1, minHeight := 0)( + ul( + overflow.hidden, + textAlign.start, + marginTop := 10, + whiteSpace.nowrap, + textOverflow.ellipsis, + marginRight := 10 + )( + frags + ) + ) + ) + } + val pageList = navList( + "Pages", + for((header, i) <- pageHeaders.zipWithIndex) yield li( + WideStyles.marginLeftZero, + NarrowStyles.floatLeft + )( + a( + color := "#f8f8f8", + WideStyles.tableOfContentsItem, + href := { + (homePage, i == 0) match { + case (true, true) => s"index.html" + case (true, false) => s"page/${sanitize(header)}.html" + case (false, true) => s"../index.html" + case (false, false) => s"${sanitize(header)}.html" + } + } + )( + header + ) + ), + narrowHide = false + ) + + val headerBox = div( + NarrowStyles.headerContent, + h1( + textAlign.center, + a( + img( + src := {homePage match{ + case false => s"../logo-white.svg" + case true => "logo-white.svg" + }}, + height := 30, + marginTop := -5 + ), + color := "#f8f8f8", + " Mill", + href := (if (homePage) "" else ".."), + Styles.subtleLink, + NarrowStyles.flexFont, + fontWeight.bold + ), + padding := "30px 30px", + margin := 0 + ), + div( + Styles.headerLinkBox, + pageList + ) + ) + + + val tableOfContents = navList( + "Table of Contents", + for { + (header, indent) <- contentHeaders + offset <- indent match{ + case 2 => Some(0) + case 3 => Some(20) + case _ => None + } + } yield li(marginLeft := offset)( + a( + color := "#f8f8f8", + WideStyles.tableOfContentsItem, + href := s"#${sanitize(header)}" + )( + header + ) + ), + narrowHide = true + ) + + div( + WideStyles.header, + NarrowStyles.header, + Styles.headerStyle, + headerBox, + hr(NarrowStyles.disappear, backgroundColor := "#f8f8f8", width := "80%"), + tableOfContents + ) +} + + +val currentTimeText = LocalDate.now.toString + + +def renderAdjacentLink(next: Boolean, name: String, url: String) = { + a(href := url)( + if(next) frag(name, " ", i(cls:="fa fa-arrow-right" , aria.hidden:=true)) + else frag(i(cls:="fa fa-arrow-left" , aria.hidden:=true), " ", name) + ) +} +def postContent(homePage: Boolean, post: PostInfo, adjacentLinks: Frag, posts: Seq[String]) = pageChrome( + Some(post.name), + homePage, + Seq[Frag]( + div(adjacentLinks, marginBottom := 10), + raw(post.rawHtmlContent), + adjacentLinks + ), + post.headers, + pageHeaders = posts +)
\ No newline at end of file diff --git a/docs/intro.md b/docs/pages/1 - Intro to Mill.md index 575efccc..022bc212 100644 --- a/docs/intro.md +++ b/docs/pages/1 - Intro to Mill.md @@ -1,3 +1,15 @@ +Mill is your shiny new Scala build tool! Confused by SBT? Frustrated by Maven? +Perplexed by Gradle? Give Mill a try! + +Mill is a general purpose build-tool. It has built in support for the +[Scala](https://www.scala-lang.org/) programming language, and can serve as a +replacement for [SBT](http://www.scala-sbt.org/), but can also be extended to +support any other language or platform via modules (written in Java or Scala) or +through external subprocesses. + +Mill aims for simplicity by re-using concepts you are already familiar with to +let you define your project's build. Mill's `build.sc` files are Scala scripts. + To get started, download Mill and install it into your system via the following `curl`/`chmod` command: diff --git a/docs/configure.md b/docs/pages/2 - Configuring Mill.md index 8fee9354..8fee9354 100644 --- a/docs/configure.md +++ b/docs/pages/2 - Configuring Mill.md diff --git a/docs/example.md b/docs/pages/3 - Common Project Layouts.md index 04ebfc7c..e69ab984 100644 --- a/docs/example.md +++ b/docs/pages/3 - Common Project Layouts.md @@ -1,11 +1,9 @@ -## Common Project Layouts - Above, we have shown how to work with the Mill default Scala module layout. Here we will explore some other common project layouts that you may want in your Scala build: -### Cross Scala-Version Modules +## Cross Scala-Version Modules ```scala import mill._ @@ -37,7 +35,7 @@ foo/ Code common to all Scala versions lives in `src`, while code specific to one version lives in `src-x.y`. -### Scala.js Modules +## Scala.js Modules ```scala import mill._ @@ -55,7 +53,7 @@ latter of which runs your code on Node.js, which must be pre-installed) `ScalaJSModule` also exposes the `foo.fastOpt` and `foo.fullOpt` tasks for generating the optimized Javascript file. -### SBT-Compatible Modules +## SBT-Compatible Modules ```scala import mill._ @@ -83,7 +81,7 @@ Useful if you want to migrate an existing project built with SBT without having to re-organize all your files -### SBT-Compatible Cross Scala-Version Modules +## SBT-Compatible Cross Scala-Version Modules ```scala import mill._ @@ -113,7 +111,7 @@ foo/ scala-2.12/ ``` -### Publishing +## Publishing ```scala import mill._ import mill.scalalib._ @@ -184,7 +182,7 @@ Mill comes bundled with example builds for existing open-source projects, as integration tests and examples: -### Acyclic +## Acyclic - [Mill Build](https://github.com/lihaoyi/mill/blob/master/integration/test/resources/acyclic/build.sc#L1) @@ -192,7 +190,7 @@ A small single-module cross-build, with few sources minimal dependencies, and wired up for publishing to Maven Central -### Better-Files +## Better-Files - [Mill Build](https://github.com/lihaoyi/mill/blob/master/integration/test/resources/better-files/build.sc#L1) @@ -201,7 +199,7 @@ A collection of small modules compiled for a single Scala version. Also demonstrates how to define shared configuration in a `trait`, enable Scala compiler flags, and download artifacts as part of the build. -### Jawn +## Jawn - [Mill Build](https://github.com/lihaoyi/mill/blob/master/integration/test/resources/jawn/build.sc#L1) @@ -209,7 +207,7 @@ A collection of relatively small modules, all cross-built across the same few versions of Scala. -### Ammonite +## Ammonite - [Mill Build](https://github.com/lihaoyi/mill/blob/master/integration/test/resources/ammonite/build.sc#L1) diff --git a/docs/tasks.md b/docs/pages/3 - Tasks.md index 73695bb8..73695bb8 100644 --- a/docs/tasks.md +++ b/docs/pages/3 - Tasks.md diff --git a/docs/modules.md b/docs/pages/4 - Modules.md index c4dd3f8b..c4dd3f8b 100644 --- a/docs/modules.md +++ b/docs/pages/4 - Modules.md diff --git a/docs/cross.md b/docs/pages/5 - Cross Builds.md index f92678d5..f92678d5 100644 --- a/docs/cross.md +++ b/docs/pages/5 - Cross Builds.md diff --git a/docs/extending.md b/docs/pages/6 - Extending Mill.md index 299d8e76..299d8e76 100644 --- a/docs/extending.md +++ b/docs/pages/6 - Extending Mill.md diff --git a/docs/internals.md b/docs/pages/7 - Mill Internals.md index d10860dc..d10860dc 100644 --- a/docs/internals.md +++ b/docs/pages/7 - Mill Internals.md |