Permalink
Browse files

First commit, post-squash

  • Loading branch information...
0 parents commit bd4a7ebcece2f8168d9f507a3b626169f22938c1 @lihaoyi committed Jan 7, 2016
Showing with 428 additions and 0 deletions.
  1. +10 −0 .gitignore
  2. +89 −0 build.scala
  3. +149 −0 pages.scala
  4. +96 −0 posts/0 - Hello World Blog.md
  5. +84 −0 styles.scala
@@ -0,0 +1,10 @@
+target/
+*.iml
+.idea
+.settings
+.classpath
+.project
+.cache
+.sbtserver
+project/.sbtserver
+tags
@@ -0,0 +1,89 @@
+// Load dependencies
+load.ivy("org.pegdown" % "pegdown" % "1.6.0")
+load.ivy("com.lihaoyi" %% "scalatags" % "0.5.3")
+load.module(ammonite.ops.cwd/"styles.scala")
+load.module(ammonite.ops.cwd/"pages.scala")
+@
+import scalatags.Text.all.{width, height, _}
+
+import scalatags.Text._
+import ammonite.ops._
+import org.pegdown.{PegDownProcessor, ToHtmlSerializer, LinkRenderer}
+
+
+val postsFolder = cwd/'posts
+val targetFolder = cwd/'target
+
+object DatesFor{
+ import ammonite.ops.ImplicitWd._
+ val commitChunks = %%('git, 'log, "--date=short").out.string.split("\n(?=commit)")
+ val commits = for(chunk <- commitChunks.dropRight(1)) yield {
+ val lines = chunk.lines.toSeq
+ val sha = lines(0).stripPrefix("commit ")
+ val author = lines(1).stripPrefix("Author: ")
+ val date = lines(2).stripPrefix("Date: ")
+ val files = %%('git, 'diff, "--name-only", sha, sha + "~1").out.lines
+ (sha, author, date, files)
+ }
+
+ val fileChanges = for{
+ (sha, author, date, files) <- commits
+ file <- files
+ } yield (file, sha, author, date)
+
+ def apply(filePrefix: String) = for {
+ (file, sha, author, date) <- fileChanges
+ if file.startsWith(filePrefix)
+ } yield (sha, java.time.LocalDate.parse(date))
+
+}
+
+
+// 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 <- ls.rec! postsFolder if path.ext == "md") yield {
+ val Array(number, name) = path.last.split(" - ")
+ (number, name.stripSuffix(".md"), path)
+ }
+ for ((index, name, path) <- split.sortBy(_._1.toInt)) yield {
+ val processor = new PegDownProcessor()
+ val ast = processor.parseMarkdown(read! path toArray)
+ val rawHtmlContent = new ToHtmlSerializer(new LinkRenderer).toHtml(ast)
+ if (ast.getChildren.size > 0) {
+ val firstNode = ast.getChildren.get(0)
+ ast.getChildren.clear()
+ ast.getChildren.add(firstNode)
+ }
+ val rawHtmlSnippet = new ToHtmlSerializer(new LinkRenderer).toHtml(ast)
+ val updates = DatesFor(s"posts/$index - ").toSeq
+ (name, rawHtmlContent, rawHtmlSnippet, updates)
+ }
+}
+
+
+def main(publish: Boolean = false) = {
+
+ rm! targetFolder
+
+ write(
+ targetFolder/s"index.html",
+ mainContent(posts)
+ )
+
+ for((name, rawHtmlContent, _, dates) <- posts){
+ write(
+ targetFolder/'post/s"$name.html",
+ postContent(name, rawHtmlContent, dates)
+ )
+ }
+
+ if (publish){
+ implicit val publishWd = cwd/'target
+ %git 'init
+ %git('add, "-A", ".")
+ %git('commit, "-am", "first commit")
+ %git('remote, 'add, 'origin, "git@github.com:lihaoyi/lihaoyi.github.io.git")
+ %git('push, "-uf", 'origin, 'master)
+ }
+}
@@ -0,0 +1,149 @@
+load.ivy("com.lihaoyi" %% "scalatags" % "0.5.3")
+load.module(ammonite.ops.cwd/"styles.scala")
+@
+
+import scalatags.Text.all.{width, height, _}
+import scalatags.Text._
+import java.time.LocalDate
+@
+def pageChrome(titleText: Option[String], unNesting: String, contents: Frag): String = {
+
+ 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"
+ )
+ val headerLinks = Seq(
+ div(div(i(cls:= "fa fa-question-circle")), " About") -> s"$unNesting/post/Hello%20World%20Blog.html",
+ div(div(i(cls:= "fa fa-file-text-o")), " Resume") -> "https://lihaoyi.github.io/Resume/",
+ div(div(i(cls:= "fa fa-github")), " Github") -> "https://github.com/lihaoyi"
+ )
+ html(
+ head(
+ meta(charset := "utf-8"),
+ for(sheet <- sheets)
+ yield link(href := sheet, rel := "stylesheet", `type` := "text/css" ),
+ tags2.title("lihaoyi.com: " + titleText),
+ tags2.style(s"@media (min-width: 48em) {${WideStyles.styleSheetText}}"),
+ tags2.style(s"@media (max-width: 48em) {${NarrowStyles.styleSheetText}}"),
+ tags2.style(Styles.styleSheetText)
+ ),
+ body(
+ margin := 0,
+ div(
+ WideStyles.header,
+ NarrowStyles.header,
+ Styles.header,
+ div(
+ NarrowStyles.headerContent,
+ WideStyles.headerContent,
+ h1(
+ a(
+ i(cls:= "fa fa-cogs"),
+ color := "white",
+ " Haoyi's Programming Blog", href := s"$unNesting/index.html",
+ Styles.subtleLink,
+ fontWeight.bold
+ ),
+ padding := "10px 10px",
+ margin := 0
+ ),
+ div(
+ Styles.headerLinkBox,
+ NarrowStyles.linkFlex,
+ for ((name, url) <- headerLinks) yield div(
+ Styles.headerLink,
+ a(name, href := url, Styles.subtleLink, color := "white")
+ )
+ )
+ )
+ ),
+ div(
+ WideStyles.content,
+ NarrowStyles.content,
+ maxWidth := 900,
+ titleText.map(h1(_)),
+ contents
+ ),
+ div(
+ WideStyles.footer,
+ Styles.footer,
+ "Last published ", currentTimeText
+ )
+
+ )
+ ).render
+}
+val currentTimeText = LocalDate.now.toString
+
+def commentBox(titleText: String): Frag = Seq(
+ div(id:="disqus_thread"),
+ script(raw(s"""
+ /**
+ * RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
+ * LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
+ */
+ /*
+ var disqus_config = function () {
+ this.page.url = "https://www.lihaoyi.com/p/$titleText"; // Replace PAGE_URL with your page's canonical URL variable
+ this.page.identifier = "$titleText"; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
+ };
+ */
+ (function() { // DON'T EDIT BELOW THIS LINE
+ var d = document, s = d.createElement('script');
+
+ s.src = '//lihaoyi.disqus.com/embed.js';
+
+ s.setAttribute('data-timestamp', +new Date());
+ (d.head || d.body).appendChild(s);
+ })();
+ """))
+)
+
+def metadata(dates: Seq[(String, LocalDate)]) = div(
+ color := "#999",
+ marginBottom := 20,
+ "Posted ",
+ for ((sha, date) <- dates.headOption) yield a(
+ date.toString, href := s"https://github.com/lihaoyi/site/commit/$sha"
+ )
+)
+def mainContent(posts: Seq[(String, String, String, Seq[(String, LocalDate)])]) = pageChrome(
+ None,
+ ".",
+ div(
+ for((name, _, rawHtmlSnippet, dates) <- posts.reverse) yield div(
+ h1(a(
+ name,
+ href := s"post/$name.html",
+ Styles.subtleLink,
+ color := "rgb(34, 34, 34)"
+ )),
+ metadata(dates),
+ raw(rawHtmlSnippet),
+ hr(margin := "50px 0px 50px 0px")
+ )
+ )
+)
+def postContent(name: String, rawHtmlContent: String, dates: Seq[(String, LocalDate)]) = pageChrome(
+ Some(name),
+ "..",
+ Seq[Frag](
+ metadata(dates),
+ raw(rawHtmlContent),
+ if (dates.length < 2) ""
+ else {
+ div(
+ hr,
+ div(
+ color := "rgb(158, 167, 174)",
+ "Updated ",
+ for((sha, date) <- dates.drop(1)) yield a(
+ date.toString, " ", href := s"https://github.com/lihaoyi/site/commit/$sha"
+ )
+
+ )
+ )
+ },
+ commentBox(name)
+ )
+)
@@ -0,0 +1,96 @@
+I have a new programming blog, and you're looking at it! I'll post things
+about programming on it and there'll be a comment box at the bottom of each
+post if anyone wants to discuss the things I posted. I'm currently working with
+the Scala, Python and Javascript programming languages, and am interested in
+static analysis, compilers, web development and developer tools.
+
+I am not the first person to have a blog, nor the first person to have a
+programming blog, nor is this my first blog. Nevertheless, for me, doing
+this is a mix of new and old ideas.
+
+## The Old
+
+This is not the first time I have had a blog/site. I had built one back
+in 2011 while in college, and it was very much my own introduction to
+web development and distributed systems. The [source code][0] is online, in
+all its gory details: it's custom templating language, it's now-defunct
+Facebook API keys, random server logs, and other things. The content is
+missing, because I misplaced it, and who used version control back then
+anyway? Some can be retrieved from the [Web Archive], while others
+(like all the static assets and images) seems lost forever
+
+This is not the first time I have published things on the internet. I've
+written hundreds of pages of documentation for the open source projects I've
+been involved in [1] [2] [3], including the [Hands-on Scala.js] e-book.
+
+Nor is this the first time I've had discussions with other people online.
+I'm relatively active on Twitter, on the mailing lists, on the programming
+reddits, and on the Gitter channels of various projects.
+
+## The New
+
+Given that all these things have already happened, what then is the value
+of starting a blog, yet *another* place to write things, for people to look
+at, and all that?
+
+### Audience
+
+Unlike the 2011 blog, this one actually has a target audience.
+
+The original was a somewhat meandering smattering of "things I thought were
+cool": programming, photography, DIY pneumatics and electronics. Although I
+don't have the content anymore, none of it was all that interesting to begin
+with, and given how un-targeted it was it's unlikely a random passer-by would
+find it interesting. In contrast this one is a lot more targeted: I will talk
+about programming, and presumably the people coming here will be interested in
+programming, and everyone will find something they're interested it. As for
+my other interests, they may start appearing here eventually, or I may simple
+continue publishing those on other channels like Facebook or mailing-lists.
+
+### Lifetimes
+
+This blog is meant to bridge a gap between the forever-lived documentation
+sites I publish for projects and short-lived emails, tweets and chat messages.
+
+A chat message (e.g. on Gitter) takes seconds to compose and lives for minutes
+before being buried. An email or tweet may takes minutes to write and live for
+days, but they soon get buried too (The entire thread of exchange may last
+longer for weeks, but the individual messages get buried quickly and disappear
+from the public eye).
+
+At the other extreme are the documentation sites: things like the documentation
+for [Ammonite][1] or [FastParse][3] are built up over multiple days or weeks,
+and I expect them to last forever. That slows things down, as I have to make
+sure new additions "fit in" to the existing docs, and need to be careful to
+keep things in sync and ensure the docs don't get broken.
+
+The posts on this blog are expected to take hours to a day compose and live for
+months to a year.
+
+While a doc-site has to be maintained and kept updated as the thing it's
+documenting changes, the content here will be in plain markdown. It will be
+neither maintainable nor maintained, will not be well organized, and will
+definitely become stale over time. This freedom from maintenance to write more
+and more varied things that I'd be able to fit into a doc-site'.
+
+Unlike channels like Twitter or Gitter or Mailing lists, the content here
+will be longer-form and longer-lived. The short time on chat or social-media
+limit how in-depth you can discuss things: there simply isn't enough time to
+tell a story or to build upon knowledge you've earlier presented to the reader.
+This blog should provide plenty of opportunities to tell stories and educate
+the reader, building upon their knowledge throughout a single post.
+
+-------------------------------------------------------------------------------
+
+Where will this blog go? Will people read it? Will I have the commitment to
+keep it alive, or will it die a slow, lonely death like so many others before
+it? Only time will tell!
+
+[0]: https://github.com/lihaoyi/mysite
+[Web Archive]: https://web.archive.org/web/20111203164223/http://www.techcreation.sg/
+[1]: http://lihaoyi.github.io/Ammonite/
+[2]: http://lihaoyi.github.io/scalatags/
+[3]: http://lihaoyi.github.io/fastparse/
+[Hands-on Scala.js]: http://lihaoyi.github.io/hands-on-scala-js/
+[4]: http://lihaoyi.github.io/Scalatex/
+[5]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
Oops, something went wrong.

0 comments on commit bd4a7eb

Please sign in to comment.