├── resources
├── public
│ ├── styles
│ │ ├── 600up.css
│ │ ├── responsive.css
│ │ ├── unresponsive.css
│ │ ├── reset.css
│ │ └── base.css
│ ├── favicon.ico
│ ├── images
│ │ ├── rss.png
│ │ ├── itunes.png
│ │ ├── logo.png
│ │ ├── splash.png
│ │ ├── twitter.png
│ │ └── dark-leather.png
│ └── scripts
│ │ └── ga.js
├── commands
│ ├── repeat.html
│ ├── sgml-close-tag.html
│ ├── forward-list.html
│ ├── ace-jump-mode.html
│ ├── digit-argument.html
│ ├── flush-lines.html
│ ├── downcase-word.html
│ ├── query-replace.html
│ ├── describe-key.html
│ ├── kmacro-start-macro.html
│ ├── slime-js-send-defun.html
│ ├── yas-expand.html
│ ├── eval-last-sexp.html
│ ├── iy-go-to-char.html
│ ├── key-chord-define-global.html
│ ├── kmacro-name-last-macro.html
│ ├── sgml-delete-tag.html
│ ├── transpose-words.html
│ ├── dired-toggle-read-only.html
│ ├── insert-kbd-macro.html
│ ├── transpose-chars.html
│ ├── transpose-lines.html
│ ├── yank-rectangle.html
│ ├── inline-string-rectangle.html
│ ├── isearch-forward.html
│ ├── mark-next-like-this.html
│ ├── expand-region.html
│ ├── zencoding-expand-line.html
│ ├── rename-sgml-tag.html
│ ├── string-rectangle.html
│ ├── eval-and-replace.html
│ ├── cleanup-buffer.html
│ ├── mc-mark-all-like-this.html
│ ├── mc-mark-next-like-this.html
│ ├── ido-imenu.html
│ ├── set-rectangular-region-anchor.html
│ └── slime-js-jack-in-node.html
├── extending-episodes.edn
└── episodes.edn
├── .gitignore
├── src
└── emacs_rocks
│ ├── server.clj
│ ├── content.clj
│ ├── pages.clj
│ ├── system.clj
│ ├── rss.clj
│ ├── layout.clj
│ ├── page
│ ├── episodes.clj
│ ├── extending.clj
│ └── index.clj
│ └── web.clj
├── dev
└── user.clj
├── README.md
└── project.clj
/resources/public/styles/600up.css:
--------------------------------------------------------------------------------
1 | .episode_list a {float: left; margin: 14px;}
--------------------------------------------------------------------------------
/resources/commands/repeat.html:
--------------------------------------------------------------------------------
1 |
C-x z repeat
2 |
3 | Repeat the last command.
4 |
5 |
--------------------------------------------------------------------------------
/resources/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/magnars/emacsrocks.com/master/resources/public/favicon.ico
--------------------------------------------------------------------------------
/resources/public/images/rss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/magnars/emacsrocks.com/master/resources/public/images/rss.png
--------------------------------------------------------------------------------
/resources/public/images/itunes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/magnars/emacsrocks.com/master/resources/public/images/itunes.png
--------------------------------------------------------------------------------
/resources/public/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/magnars/emacsrocks.com/master/resources/public/images/logo.png
--------------------------------------------------------------------------------
/resources/public/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/magnars/emacsrocks.com/master/resources/public/images/splash.png
--------------------------------------------------------------------------------
/resources/commands/sgml-close-tag.html:
--------------------------------------------------------------------------------
1 | C-c C-e sgml-close-tag
2 |
3 | Close the current tag.
4 |
5 |
--------------------------------------------------------------------------------
/resources/public/images/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/magnars/emacsrocks.com/master/resources/public/images/twitter.png
--------------------------------------------------------------------------------
/resources/commands/forward-list.html:
--------------------------------------------------------------------------------
1 | C-M-N forward-list
2 |
3 | Jump forward to matching paren.
4 |
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | /classes
3 | /checkouts
4 | pom.xml
5 | pom.xml.asc
6 | *.jar
7 | *.class
8 | /.lein-*
9 | /.nrepl-port
10 |
--------------------------------------------------------------------------------
/resources/public/images/dark-leather.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/magnars/emacsrocks.com/master/resources/public/images/dark-leather.png
--------------------------------------------------------------------------------
/resources/public/styles/responsive.css:
--------------------------------------------------------------------------------
1 | @import 'reset.css';
2 | @import 'base.css';
3 | @import "600up.css" screen and (min-width: 600px);
4 |
--------------------------------------------------------------------------------
/resources/public/styles/unresponsive.css:
--------------------------------------------------------------------------------
1 | @import 'reset.css';
2 | @import 'base.css';
3 | @import "600up.css";
4 | #main {width: 560px;}
5 |
--------------------------------------------------------------------------------
/resources/commands/ace-jump-mode.html:
--------------------------------------------------------------------------------
1 | C-ø ace-jump-mode
2 |
3 | Jump to a word starting with a given char.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/digit-argument.html:
--------------------------------------------------------------------------------
1 | C-9 digit-argument
2 |
3 | Execute the following command 9 times.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/flush-lines.html:
--------------------------------------------------------------------------------
1 | M-x flush-lines
2 |
3 | Delete lines after point matching a given regexp.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/downcase-word.html:
--------------------------------------------------------------------------------
1 | M-l downcase-word
2 |
3 | Convert following word to lower case, moving over.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/query-replace.html:
--------------------------------------------------------------------------------
1 | M-% query-replace
2 |
3 | Replace some occurrences of one string with another.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/describe-key.html:
--------------------------------------------------------------------------------
1 | C-h k describe-key
2 |
3 | Describe the function bound to a given key combination.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/kmacro-start-macro.html:
--------------------------------------------------------------------------------
1 | F3 kmacro-start-macro
2 |
3 | Record your keyboard input to play it back later.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/slime-js-send-defun.html:
--------------------------------------------------------------------------------
1 | C-M-x slime-js-send-defun
2 |
3 | Sends the function at point to the js-repl.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/yas-expand.html:
--------------------------------------------------------------------------------
1 | <tab> yas/expand
2 |
3 | If the preceeding text matches a yasnippet, expand it.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/eval-last-sexp.html:
--------------------------------------------------------------------------------
1 | C-x C-e eval-last-sexp
2 |
3 | Evaluate sexp before point; print value in minibuffer.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/iy-go-to-char.html:
--------------------------------------------------------------------------------
1 | M-m iy-go-to-char
2 |
3 | Move point to next occurrence of char. Can start typing immediately.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/key-chord-define-global.html:
--------------------------------------------------------------------------------
1 | key-chord-define-global
2 |
3 | Define a two-char key chord to invoke a command.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/kmacro-name-last-macro.html:
--------------------------------------------------------------------------------
1 | M-x kmacro-name-last-macro
2 |
3 | Assign a name to the last keyboard macro defined.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/sgml-delete-tag.html:
--------------------------------------------------------------------------------
1 | C-c DEL sgml-delete-tag
2 |
3 | Delete the current tag along with its respective other tag.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/transpose-words.html:
--------------------------------------------------------------------------------
1 | M-t transpose-words
2 |
3 | Switch the words around point, leaving point at end of them.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/dired-toggle-read-only.html:
--------------------------------------------------------------------------------
1 | C-x C-q dired-toggle-read-only
2 |
3 | Edit dired buffer with Wdired, or set it read-only.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/insert-kbd-macro.html:
--------------------------------------------------------------------------------
1 | M-x insert-kbd-macro
2 |
3 | Insert in buffer the definition of kbd macro NAME, as Lisp code.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/transpose-chars.html:
--------------------------------------------------------------------------------
1 | C-t transpose-chars
2 |
3 | Switch the characters around point, moving forward one character.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/transpose-lines.html:
--------------------------------------------------------------------------------
1 | C-x C-t transpose-lines
2 |
3 | Switch the current and previous lines, leaving point after both.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/yank-rectangle.html:
--------------------------------------------------------------------------------
1 | C-x r y yank-rectangle
2 |
3 | Yank the last killed rectangle with upper left corner at point.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/inline-string-rectangle.html:
--------------------------------------------------------------------------------
1 | C-x r t inline-string-rectangle
2 |
3 | Replace rectangle contents with visual feedback as you type.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/isearch-forward.html:
--------------------------------------------------------------------------------
1 | C-s isearch-forward
2 |
3 | Search incrementally forward.
4 | Note that mark is set at start of search on exit.
5 |
6 |
--------------------------------------------------------------------------------
/resources/commands/mark-next-like-this.html:
--------------------------------------------------------------------------------
1 | C-> mark-next-like-this
2 |
3 | Find and mark the next part of the buffer matching the currently active region.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/expand-region.html:
--------------------------------------------------------------------------------
1 | C-@ er/expand-region
2 |
3 | Increase selection by semantic units. Get it here.
4 |
5 |
--------------------------------------------------------------------------------
/resources/commands/zencoding-expand-line.html:
--------------------------------------------------------------------------------
1 | C-c C-j zencoding-expand-line
2 |
3 | Interactively create HTML out of CSS-selectors.
4 | Get it here.
5 |
6 |
--------------------------------------------------------------------------------
/resources/commands/rename-sgml-tag.html:
--------------------------------------------------------------------------------
1 | C-c C-r rename-sgml-tag
2 |
3 | Rename the current tag (closest from point nesting-wise).
4 | Get it here
5 |
6 |
--------------------------------------------------------------------------------
/resources/commands/string-rectangle.html:
--------------------------------------------------------------------------------
1 | C-x r t string-rectangle
2 |
3 | Point and mark together form a rectangle.
4 | This command removes the content in that rectangle, and
5 | inserts a given string on each line.
6 |
7 |
--------------------------------------------------------------------------------
/resources/commands/eval-and-replace.html:
--------------------------------------------------------------------------------
1 | C-x C-e eval-and-replace
2 |
3 | Evaluate the last sexp and replace it with the result.
4 | Get it here.
5 |
6 |
--------------------------------------------------------------------------------
/resources/commands/cleanup-buffer.html:
--------------------------------------------------------------------------------
1 | C-c n cleanup-buffer
2 |
3 | Perform a bunch of operations on the whitespace content of a buffer.
4 | Get it here.
5 |
6 |
--------------------------------------------------------------------------------
/resources/commands/mc-mark-all-like-this.html:
--------------------------------------------------------------------------------
1 | C-Æ mc/mark-all-like-this
2 |
3 | Find and mark all parts of the buffer matching the currently active
4 | region, while also keeping the current region.
5 | Get it here.
6 |
7 |
--------------------------------------------------------------------------------
/resources/commands/mc-mark-next-like-this.html:
--------------------------------------------------------------------------------
1 | C-æ mc/mark-next-like-this
2 |
3 | Find and mark the next part of the buffer matching the currently active
4 | region, while also keeping the current region.
5 | Get it here.
6 |
7 |
--------------------------------------------------------------------------------
/src/emacs_rocks/server.clj:
--------------------------------------------------------------------------------
1 | (ns emacs-rocks.server
2 | (:require [ring.adapter.jetty :as jetty]))
3 |
4 | (defn create-and-start
5 | [handler & {:keys [port]}]
6 | {:pre [(not (nil? port))]}
7 | (jetty/run-jetty handler {:port port :join? false}))
8 |
9 | (defn stop
10 | [server]
11 | (.stop server))
12 |
--------------------------------------------------------------------------------
/resources/commands/ido-imenu.html:
--------------------------------------------------------------------------------
1 | C-x C-i ido-imenu-push-mark
2 |
3 | Jump to a symbol, depending on major mode. Original is ido-imenu, that does not set
4 | the mark. ido-imenu-push-mark is available at
5 | this gist.
6 |
7 |
--------------------------------------------------------------------------------
/resources/commands/set-rectangular-region-anchor.html:
--------------------------------------------------------------------------------
1 | H-SPC set-rectangular-region-anchor
2 |
3 | Think of this one as `set-mark` except you're marking a rectangular region. It
4 | is an exceedingly quick way of adding multiple cursors to multiple lines.
5 | Get it here.
6 |
7 |
--------------------------------------------------------------------------------
/resources/commands/slime-js-jack-in-node.html:
--------------------------------------------------------------------------------
1 | M-x slime-js-jack-in-node
2 |
3 | And its sibling slime-js-jack-in-browser are some conveniences
4 | that I've built around slime-js. You can find
5 | them here
6 | in my .emacs.d on github.
7 |
8 |
--------------------------------------------------------------------------------
/src/emacs_rocks/content.clj:
--------------------------------------------------------------------------------
1 | (ns emacs-rocks.content
2 | (:require [clojure.java.io :as io]
3 | [stasis.core :refer [slurp-directory]]))
4 |
5 | (defn- load-edn [name]
6 | (read-string (slurp (io/resource name))))
7 |
8 | (defn load-content []
9 | {:episodes (load-edn "episodes.edn")
10 | :extending-episodes (load-edn "extending-episodes.edn")
11 | :commands (slurp-directory "resources/commands/" #"\.html$")})
12 |
--------------------------------------------------------------------------------
/dev/user.clj:
--------------------------------------------------------------------------------
1 | (ns user
2 | (:require [clojure.java.io :as io]
3 | [clojure.pprint :refer [pprint pp print-table]]
4 | [clojure.reflect]
5 | [clojure.repl :refer :all]
6 | [clojure.set :as set]
7 | [clojure.string :as str]
8 | [emacs-rocks.system]
9 | [quick-reset.core :refer [stop reset system]]))
10 |
11 | (quick-reset.core/set-constructor 'emacs-rocks.system/create-system)
12 |
--------------------------------------------------------------------------------
/resources/public/scripts/ga.js:
--------------------------------------------------------------------------------
1 | var _gaq = _gaq || [];
2 | _gaq.push(['_setAccount', 'UA-26477646-1']);
3 | _gaq.push(['_trackPageview']);
4 |
5 | (function() {
6 | var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
7 | ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
8 | var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
9 | })();
10 |
--------------------------------------------------------------------------------
/src/emacs_rocks/pages.clj:
--------------------------------------------------------------------------------
1 | (ns emacs-rocks.pages
2 | (:require [emacs-rocks.page.episodes :refer [get-episode-pages]]
3 | [emacs-rocks.page.extending :refer [get-extending-pages]]
4 | [emacs-rocks.page.index :refer [render-index-page]]
5 | [stasis.core :refer [merge-page-sources]]))
6 |
7 | (defn create-pages [content]
8 | (merge-page-sources
9 | {:general-pages {"/" {:title "Emacs Rocks!"
10 | :body (render-index-page content)}}
11 | :episode-pages (get-episode-pages content)
12 | :extending-pages (get-extending-pages content)}))
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Emacs Rocks
2 |
3 | The webpage for https://emacsrocks.com.
4 |
5 | Made with [Stasis](https://github.com/magnars/stasis) for static site
6 | generation, [Hiccup](https://github.com/weavejester/hiccup) to
7 | build HTML, and [Optimus](https://github.com/magnars/optimus) for
8 | frontend optimization.
9 |
10 | Start a local version:
11 |
12 | lein repl
13 | (reset)
14 |
15 | Build a new version of the site:
16 |
17 | ./build.sh
18 |
19 | ## License
20 |
21 | Copyright © (iterate inc 2014) Magnar Sveen
22 |
23 | Distributed under the Eclipse Public License either version 1.0 or (at
24 | your option) any later version.
25 |
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 | (defproject emacs-rocks "0.1.0"
2 | :description "The webpage for emacsrocks.com"
3 | :url "https://emacsrocks.com"
4 | :jvm-opts ["-Djava.awt.headless=true"]
5 | :dependencies [[org.clojure/clojure "1.7.0"]
6 | [stasis "2.2.2"]
7 | [optimus "0.15.1"]
8 | [ring "1.3.1"]
9 | [enlive "1.1.5"]
10 | [hiccup "1.0.4"]
11 | [prone "0.8.0"]
12 | [org.clojure/data.xml "0.0.7"]]
13 | :main emacs-rocks.system
14 | :profiles {:dev {:dependencies [[ciderale/quick-reset "0.1.1"]
15 | [org.clojure/tools.namespace "0.2.8"]]
16 | :source-paths ["dev"]}})
17 |
--------------------------------------------------------------------------------
/src/emacs_rocks/system.clj:
--------------------------------------------------------------------------------
1 | (ns emacs-rocks.system
2 | (:require [emacs-rocks.web :as web]
3 | [prone.middleware :as prone]
4 | [emacs-rocks.server :as server]))
5 |
6 | (defn start
7 | "Performs side effects to initialize the system, acquire resources,
8 | and start it running. Returns an updated instance of the system."
9 | [system]
10 | (let [handler (prone/wrap-exceptions (web/create-app))
11 | server (server/create-and-start handler :port (:port system))]
12 | (assoc system
13 | :handler handler
14 | :server server)))
15 |
16 | (defn stop
17 | "Performs side effects to shut down the system and release its
18 | resources. Returns an updated instance of the system."
19 | [system]
20 | (when (:server system)
21 | (server/stop (:server system)))
22 | (dissoc system :handler :server))
23 |
24 | (defn create-system
25 | "Returns a new instance of the whole application."
26 | []
27 | {:port 3456
28 | :start start
29 | :stop stop})
30 |
31 | (defn -main [& args]
32 | (let [system (create-system)]
33 | (start system)))
34 |
--------------------------------------------------------------------------------
/src/emacs_rocks/rss.clj:
--------------------------------------------------------------------------------
1 | (ns emacs-rocks.rss
2 | (:require [clojure.data.xml :as xml]
3 | [clojure.string :as str]
4 | [emacs-rocks.page.index :refer [episode-link]]
5 | [hiccup.core :refer [html]]))
6 |
7 | (defn to-id-str [str]
8 | "Replaces all special characters with dashes, avoiding leading,
9 | trailing and double dashes."
10 | (-> (.toLowerCase str)
11 | (str/replace #"[^a-zA-Z0-9]+" "-")
12 | (str/replace #"-$" "")
13 | (str/replace #"^-" "")))
14 |
15 | (defn- entry [episode]
16 | [:entry
17 | [:title (str (:number episode) ": " (:name episode))]
18 | [:updated (str (:date episode) "T00:00:00+02:00")]
19 | [:author [:name "Magnar Sveen"]]
20 | [:link {:href (str "http://emacsrocks.com" (episode-link episode))}]
21 | [:id (str "urn:emacsrocks-com:feed:episode:" (:number episode))]
22 | [:content {:type "html"} (html [:a {:href (str "http://emacsrocks.com" (episode-link episode))}
23 | "See the video"])]])
24 |
25 | (defn atom-xml [content]
26 | (xml/emit-str
27 | (xml/sexp-as-element
28 | [:feed {:xmlns "http://www.w3.org/2005/Atom"
29 | :xmlns:media "http://search.yahoo.com/mrss/"}
30 | [:id "urn:emacsrocks-com:feed"]
31 | [:updated
32 | (str (:date (last (:episodes content))) "T00:00:00+02:00")]
33 | [:title {:type "text"} "Emacs Rocks!"]
34 | [:link {:rel "self" :href "http://emacsrocks.com/atom.xml"}]
35 | (->> (:episodes content)
36 | reverse
37 | (map entry))])))
38 |
39 |
--------------------------------------------------------------------------------
/src/emacs_rocks/layout.clj:
--------------------------------------------------------------------------------
1 | (ns emacs-rocks.layout
2 | (:require [clojure.java.io :as io]
3 | [clojure.string :as str]
4 | [hiccup.page :refer [html5]]
5 | [optimus.link :as link]))
6 |
7 | (defn- serve-to-media-query-capable-browsers [tag]
8 | (list "" tag ""))
9 |
10 | (defn- serve-to-media-query-clueless-browsers [tag]
11 | (list ""))
12 |
13 | (defn render-page [page content request]
14 | (html5 {:lang "en"}
15 | [:head
16 | [:meta {:charset "utf-8"}]
17 | [:meta {:name "viewport"
18 | :content "width=device-width, initial-scale=1.0"}]
19 | (serve-to-media-query-capable-browsers
20 | [:link {:rel "stylesheet" :href (link/file-path request "/styles/responsive.css")}])
21 | (serve-to-media-query-clueless-browsers
22 | [:link {:rel "stylesheet" :href (link/file-path request "/styles/unresponsive.css")}])
23 | [:link {:href "/atom.xml" :rel "alternate" :title "Emacs Rocks!" :type "application/atom+xml"}]
24 | [:title (:title page)]]
25 | [:body
26 | [:script (slurp (io/resource "public/scripts/ga.js"))]
27 | [:div {:id "main"}
28 | [:a {:id "logo_link" :href "/"}
29 | [:img {:src "/images/logo.png" :alt "Emacs Rocks!"}]]
30 | (:body page)
31 | [:div {:id "footer"}
32 | "This work is licensed under " [:a {:href "https://creativecommons.org/licenses/by-sa/3.0/"}
33 | "Creative Commons Attribution-ShareAlike 3.0"]]]]))
34 |
--------------------------------------------------------------------------------
/resources/extending-episodes.edn:
--------------------------------------------------------------------------------
1 | [{:number "01" :date "2012-06-17" :size "97mb" :youtube "5axK-VUKJnk" :commits [{:hash "56e0b6e6" :msg "Initial commit."}
2 | {:hash "e123fabe" :msg "Tests up and running."}]}
3 | {:number "02" :date "2012-06-17" :size "129mb" :youtube "Zxt-c_N82_w" :commits [{:hash "b4a79c4e" :msg "Implemented toggle-deffered."}]}
4 | {:number "03" :date "2012-06-20" :size "205mb" :youtube "Dgcx5blog6s" :commits [{:hash "f3fe2dd2" :msg "Support hipster quotes."}
5 | {:hash "e83c3192" :msg "Create a buster minor-mode."}]}
6 | {:number "04" :date "2012-06-27" :size "197mb" :youtube "zI4KfUPRU5s" :commits [{:hash "6fb1cf17" :msg "Toggle without moving point."}
7 | {:hash "029eab32" :msg "Autotest."}
8 | {:hash "bf7fd38a" :msg "Remove bogus prose."}]}
9 | {:number "05" :date "2012-07-01" :size "173mb" :youtube "3-7nLXGf1Xg" :commits [{:hash "f5af5d31" :msg "Toggle focus rocket."}]}
10 | {:number "06" :date "2012-08-08" :size "159mb" :youtube "MrCSgAJJnc8" :commits [{:hash "714872b" :msg "Run tests within Emacs."}]}
11 | {:number "07" :date "2012-12-19" :size "118mb" :youtube "lcQWOSQ-PJo" :commits [{:hash "54f0681" :msg "Use compile and comint."}]}
12 | {:number "08" :date "2013-01-17" :size "90mb" :youtube "RSshC0vWoas" :commits [{:hash "ba7d8da" :msg "Clean up ansi mess."}]}
13 | ]
14 |
--------------------------------------------------------------------------------
/resources/public/styles/reset.css:
--------------------------------------------------------------------------------
1 | /*
2 | * YUI CSS Reset
3 | *
4 | * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
5 | * Code licensed under the BSD License:
6 | * http://developer.yahoo.net/yui/license.txt
7 | * version: 0.12.1
8 | */
9 | body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td {
10 | margin: 0;
11 | padding: 0;
12 | }
13 |
14 | table {
15 | border-collapse: collapse;
16 | border-spacing: 0;
17 | }
18 |
19 | fieldset,img {
20 | border: 0;
21 | }
22 |
23 | address,caption,cite,code,dfn,em,strong,th,var {
24 | font-style: normal;
25 | font-weight: normal;
26 | }
27 |
28 | ol,ul {
29 | list-style: none;
30 | }
31 |
32 | caption,th {
33 | text-align: left;
34 | }
35 |
36 | h1,h2,h3,h4,h5,h6 {
37 | font-size: 100%;
38 | font-weight: normal;
39 | }
40 |
41 | q:before,q:after {
42 | content: '';
43 | }
44 |
45 | abbr,acronym {
46 | border: 0;
47 | }
48 |
49 | /*
50 | Copyright (c) 2007, Yahoo! Inc. All rights reserved.
51 | Code licensed under the BSD License:
52 | http://developer.yahoo.net/yui/license.txt
53 | version: 2.4.1
54 | */
55 |
56 | /**
57 | * Percents could work for IE, but for backCompat purposes, we are using keywords.
58 | * x-small is for IE6/7 quirks mode.
59 | */
60 | body {
61 | font: 13px/1.231 arial,helvetica,clean,sans-serif;
62 | *font-size:small;
63 | *font:x-small;
64 | }
65 |
66 | table {
67 | font-size:inherit;
68 | font:100%;
69 | }
70 |
71 | /**
72 | * Bump up IE to get to 13px equivalent
73 | */
74 | pre,code,kbd,samp,tt {
75 | font-family:monospace;
76 | *font-size:108%;
77 | line-height:100%;
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/resources/public/styles/base.css:
--------------------------------------------------------------------------------
1 | html {background: black url(../images/dark-leather.png) repeat;}
2 |
3 | #main {max-width: 560px; margin: 0 auto; padding: 20px; font-family: Palatino, Arial; font-size: 22px; color: #fff;}
4 |
5 | #logo_link {display: block; text-align: center; margin: 0 auto 20px;}
6 |
7 | a,
8 | .episode_list .numb {color: #ff9143;}
9 | .episode_list .name {display: block; margin-top: 1em; color: #ffaf91;}
10 | .episode_list a {display: block; margin: 14px auto; width: 197px; height: 113px; padding: 65px 0 0 54px; font-family: monaco, "consolas", "andale mono", "courier new"; font-size: 10px; background: url(../images/splash.png) no-repeat; color: #fff; text-decoration: none;}
11 |
12 | #welcome_text { margin: 15px 25px; text-align: center;}
13 |
14 | #download {font-size: 12px; margin: 10px 0 20px;}
15 |
16 | #episode h1 {font-size: 26px; margin-bottom: 10px; color: #ffaf91;}
17 | #episode h1 span {color: #fff; font-size: 18px;}
18 |
19 | #episode,
20 | #comments,
21 | #next {background: #000; padding: 20px; margin: 20px -20px; border-radius: 20px;}
22 | #next ul {list-style: disc; margin-left: 15px;}
23 |
24 | #commits {margin: 1em 0;}
25 | #commits a {font-family: monospace; font-size: 10px; margin-right: 10px;}
26 | #commits p {font-size: 16px; color: #777; margin-top: 5px;}
27 |
28 | #commands {font-size: 16px; margin-top: 2em;}
29 | #commands h3 {font-size: 18px; font-family: monaco, "consolas", "andale mono", "courier new";}
30 | #commands p {margin-bottom: 1em; color: #777;}
31 |
32 | #github {font-size: 12px;}
33 |
34 | #comments {padding-top: 10px; font-size: 15px;}
35 | #dsq-subscribe {display: none !important;}
36 |
37 | .special_series_heading { margin-top: 60px; text-align: center; font-size: 30px; color: #ff9143;}
38 |
39 | #feeds { padding-top: 30px; text-align: center; }
40 |
41 | #footer { margin-bottom: 200px;}
42 |
43 | .nowrap {white-space: nowrap;}
44 |
45 | .video-embed { position: relative; padding-bottom: 56.25%; padding-top: 30px; height: 0; overflow: hidden; max-width: 100%; height: auto; }
46 | .video-embed iframe,
47 | .video-embed object,
48 | .video-embed embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
49 |
50 | #footer {font-size: 14px; text-align: center;}
51 | #footer a {white-space: nowrap;}
--------------------------------------------------------------------------------
/src/emacs_rocks/page/episodes.clj:
--------------------------------------------------------------------------------
1 | (ns emacs-rocks.page.episodes
2 | (:require [clojure.java.io :as io]
3 | [emacs-rocks.page.index :refer [episode-link]]
4 | [hiccup.core :refer [html]]))
5 |
6 | (defn render-episode-page [content episode next]
7 | (html
8 | [:div {:id "episode"}
9 | [:h1 "Emacs Rocks! "
10 | [:span.nowrap "Episode " (:number episode) ": " (:name episode)]]
11 | [:div.video-embed
12 | [:iframe {:src (str "https://www.youtube.com/embed/" (:youtube episode) "?hd=1")
13 | :frameborder "0"
14 | :allowfullscreen true}]]
15 | [:div {:id "download"}
16 | "Want to download this episode? Use youtube-dl, it's great!"]
17 | [:div {:id "commands"}
18 | (map #(get-in content [:commands (str "/" % ".html")])
19 | (:commands episode))]
20 | [:div {:id "github"}
21 | [:a {:href "https://github.com/magnars/.emacs.d/"}
22 | "My .emacs.d on github"] "."]]
23 | [:div {:id "more"}
24 | [:div {:id "next"}
25 | "Want more?"
26 | [:ul
27 | (when next
28 | [:li [:a {:href (episode-link next)} "See episode " (:number next)]])
29 | [:li [:a {:href "/"} "Browse all episodes"]]
30 | [:li [:a {:href "http://twitter.com/emacsrocks"} "Follow me on twitter"]]
31 | [:li "Read my blog: " [:a {:href "http://whattheemacsd.com"} "What the .emacs.d!?"]]]]
32 | [:div {:id "comments"}
33 | [:div {:id "disqus_thread"}
34 | [:script {:type "text/javascript"}
35 | "var disqus_shortname = 'emacsrocks';"
36 | "var disqus_identifier = 'episode" (:number episode) "';"
37 | "var disqus_url = 'http://emacsrocks.com" (episode-link episode) "';"
38 | "(function() {"
39 | "var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;"
40 | "dsq.src = 'https://' + disqus_shortname + '.disqus.com/embed.js';"
41 | "(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);"
42 | "})();"]]]]))
43 |
44 |
45 | (defn get-episode-page [content [episode next]]
46 | [(episode-link episode)
47 | {:title (str "Emacs Rocks! Episode " (:number episode) ": " (:name episode))
48 | :body (render-episode-page content episode next)}])
49 |
50 | (defn get-episode-pages [content]
51 | (->> (:episodes content)
52 | (partition-all 2 1)
53 | (map #(get-episode-page content %))
54 | (into {})))
55 |
--------------------------------------------------------------------------------
/src/emacs_rocks/page/extending.clj:
--------------------------------------------------------------------------------
1 | (ns emacs-rocks.page.extending
2 | (:require [emacs-rocks.page.index :refer [episode-link]]
3 | [hiccup.core :refer [html]]))
4 |
5 | (defn render-episode-page [content episode next]
6 | (html
7 | [:div {:id "episode"}
8 | [:h1 "Extending Emacs Rocks! "
9 | [:span.nowrap "Episode " (:number episode)]]
10 | [:div.video-embed
11 | [:iframe {:src (str "https://www.youtube.com/embed/" (:youtube episode) "?hd=1")
12 | :frameborder "0"
13 | :allowfullscreen true}]]
14 | [:div {:id "download"}
15 | "Want to download this episode? Use youtube-dl, it's great!"]
16 | [:div {:id "commits"}
17 | "In this episode: "
18 | (map (fn [commit]
19 | [:p [:a {:href (str "https://github.com/magnars/buster-mode/commit/" (:hash commit))}
20 | (:hash commit)]
21 | (:msg commit)])
22 | (:commits episode))]
23 | [:div {:id "github"}
24 | [:a {:href "https://github.com/magnars/buster-mode/"}
25 | "The buster-mode project on github"] "."]]
26 | [:div {:id "more"}
27 | [:div {:id "next"}
28 | "Want more?"
29 | [:ul
30 | (when next
31 | [:li [:a {:href (episode-link next)} "See episode " (:number next) " of Extending Emacs Rocks"]])
32 | [:li [:a {:href "/"} "Browse all episodes"]]
33 | [:li [:a {:href "http://twitter.com/emacsrocks"} "Follow me on twitter"]]]]
34 | [:div {:id "comments"}
35 | [:div {:id "disqus_thread"}
36 | [:script {:type "text/javascript"}
37 | "var disqus_shortname = 'emacsrocks';"
38 | "var disqus_identifier = 'extend-episode-" (:number episode) "';"
39 | "var disqus_url = 'http://emacsrocks.com" (episode-link episode) "';"
40 | "(function() {"
41 | "var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;"
42 | "dsq.src = 'https://' + disqus_shortname + '.disqus.com/embed.js';"
43 | "(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);"
44 | "})();"]]]]))
45 |
46 | (defn get-episode-page [content [episode next]]
47 | [(episode-link episode)
48 | {:title (str "Extending Emacs Rocks! Episode " (:number episode))
49 | :body (render-episode-page content episode next)}])
50 |
51 | (defn get-extending-pages [content]
52 | (->> (:extending-episodes content)
53 | (partition-all 2 1)
54 | (map #(get-episode-page content %))
55 | (into {})))
56 |
--------------------------------------------------------------------------------
/src/emacs_rocks/page/index.clj:
--------------------------------------------------------------------------------
1 | (ns emacs-rocks.page.index
2 | (:require [hiccup.core :refer [html]]))
3 |
4 | (defn episode-link [episode]
5 | (if (:commits episode)
6 | (str "/extend/e" (:number episode) ".html")
7 | (str "/e" (:number episode) ".html")))
8 |
9 | (defn- render-episode [episode]
10 | (html
11 | [:li
12 | [:a {:href (episode-link episode)}
13 | "@emacsrocks "
14 | [:span.numb ";; episode " (:number episode)]
15 | [:span.name "\"" (:name episode) "\""]]]))
16 |
17 | (defn- render-extending [episode]
18 | (html
19 | [:li
20 | [:a {:href (episode-link episode)}
21 | "extending emacs "
22 | [:span.numb ";; " (:number episode)]
23 | (map (fn [commit] [:span.name (:msg commit)]) (:commits episode))]]))
24 |
25 | (defn render-index-page [content]
26 | (html
27 | [:p {:id "welcome_text"}
28 | "Yes, emacs does rock. And here are some episodes to prove it. "
29 | "Follow me on "
30 | [:a {:href "http://twitter.com/emacsrocks"} "@emacsrocks"]
31 | [:span.nowrap " for more."]]
32 | [:div.episode_list
33 | [:ul
34 | (map render-episode (reverse (:episodes content)))]]
35 | [:div {:style "clear: both;"}]
36 | [:div {:id "feeds"}
37 | [:a {:href "http://twitter.com/emacsrocks"}
38 | [:img {:src "/images/twitter.png"}]] " "
39 | [:a {:href "/atom.xml"}
40 | [:img {:src "/images/rss.png"}]]]
41 | [:h2 {:class "special_series_heading"}
42 | "Extending Emacs"]
43 | [:p
44 | "Join me and " [:a {:href "http://twitter.com/cjno"} "@cjno"]
45 | " in this special edition Emacs Rocks series where we extend emacs"
46 | " with a minor-mode for the " [:a {:href "http://busterjs.org"} "Buster.JS"]
47 | " testing framework."]
48 | [:div.episode_list
49 | [:ul
50 | (map render-extending (:extending-episodes content))]]
51 | [:div {:style "clear: both;"}]
52 | [:h2 {:class "special_series_heading"}
53 | "What the .emacs.d!?"]
54 | [:p
55 | "I've also got a blog about setting up your .emacs.d. In the spirit "
56 | "of Emacs Rocks! all the posts are very short and instantly useful. "
57 | [:a {:href "http://whattheemacsd.com"}
58 | [:span.nowrap "Check it out here"]]]
59 | [:div {:style "clear: both;"}]
60 | [:h2 {:class "special_series_heading"}
61 | "Parens of the Dead"]
62 | [:p
63 | "Want to see Emacs Rocks in action? I made a new video series, making a game
64 | with Clojure. And Emacs doth rock in it. "
65 | [:a {:href "http://parens-of-the-dead.com"}
66 | [:span.nowrap "Watch Parens of the Dead"]]]
67 | [:div {:style "clear: both;"}]
68 | [:div {:id "footer"}]))
69 |
--------------------------------------------------------------------------------
/src/emacs_rocks/web.clj:
--------------------------------------------------------------------------------
1 | (ns emacs-rocks.web
2 | (:require [emacs-rocks.content :refer [load-content]]
3 | [emacs-rocks.layout :refer [render-page]]
4 | [emacs-rocks.pages :refer [create-pages]]
5 | [emacs-rocks.rss :as rss]
6 | [net.cgrand.enlive-html :refer [sniptest]]
7 | [optimus.assets :as assets]
8 | [optimus.assets.load-css :refer [external-url?]]
9 | [optimus.export]
10 | [optimus.link :as link]
11 | [optimus.optimizations :as optimizations]
12 | [optimus.prime :as optimus]
13 | [optimus.strategies :refer [serve-live-assets]]
14 | [prone.middleware :refer [wrap-exceptions]]
15 | [ring.middleware.content-type :refer [wrap-content-type]]
16 | [stasis.core :as stasis]))
17 |
18 | (defn get-assets []
19 | (assets/load-assets "public" ["/styles/responsive.css"
20 | "/styles/unresponsive.css"
21 | "/favicon.ico"
22 | #"/images/.+\..+"]))
23 |
24 | (defn- optimize-path-fn [request]
25 | (fn [src]
26 | (if (or (external-url? src)
27 | (= "/atom.xml" src))
28 | src
29 | (or (not-empty (link/file-path request src))
30 | (throw (Exception. (str "Asset not loaded: " src)))))))
31 |
32 | (defn- use-optimized-assets [html request]
33 | (sniptest html [:img] #(update-in % [:attrs :src] (optimize-path-fn request))))
34 |
35 | (defn- prepare-page [page content request]
36 | (-> page
37 | (render-page content request)
38 | (use-optimized-assets request)))
39 |
40 | (defn update-vals [m f]
41 | (into {} (for [[k v] m] [k (f v)])))
42 |
43 | (defn get-pages []
44 | (let [content (load-content)]
45 | (-> content
46 | create-pages
47 | (update-vals #(partial prepare-page % content))
48 | (merge {"/atom.xml" (rss/atom-xml content)})
49 | )))
50 |
51 | (def optimize optimizations/all)
52 |
53 | (defn create-app []
54 | (-> (stasis/serve-pages get-pages)
55 | wrap-exceptions
56 | (optimus/wrap get-assets optimize serve-live-assets)
57 | wrap-content-type))
58 |
59 | (def export-directory "./build")
60 |
61 | (defn- load-export-dir []
62 | (stasis/slurp-directory export-directory #"\.[^.]+$"))
63 |
64 | (defn export []
65 | (let [assets (optimize (get-assets) {})
66 | old-files (load-export-dir)]
67 | (stasis/empty-directory! export-directory)
68 | (optimus.export/save-assets assets export-directory)
69 | (stasis/export-pages (get-pages) export-directory {:optimus-assets assets})
70 | (println)
71 | (println "Export complete:")
72 | (stasis/report-differences old-files (load-export-dir))
73 | (println)))
74 |
--------------------------------------------------------------------------------
/resources/episodes.edn:
--------------------------------------------------------------------------------
1 | [{:number "01" :name "From var to this" :date "2011-10-21" :size "21mb" :duration 167 :youtube "O0UgY-DmFbU" :commands ["string-rectangle" "isearch-forward"]}
2 | {:number "02" :name "A vimgolf eagle" :date "2011-10-21" :size "30mb" :duration 195 :youtube "dE2haYu0co8" :commands ["kmacro-start-macro" "digit-argument"]}
3 | {:number "03" :name "A vimgolf albatross" :date "2011-10-22" :size "14mb" :duration 135 :youtube "ePIHUfFz8-c" :commands ["transpose-lines" "transpose-chars" "kmacro-start-macro" "digit-argument"]}
4 | {:number "04" :name "A rebind controversy" :date "2011-10-24" :size "14mb" :duration 152 :youtube "OA0AjzBgWU4" :commands ["iy-go-to-char" "downcase-word" "transpose-words"]}
5 | {:number "05" :name "Macros in style" :date "2011-10-26" :size "12mb" :duration 92 :youtube "o1jJS_aibPA" :commands ["forward-list" "kmacro-start-macro"]}
6 | {:number "06" :name "Yeah! Snippets!" :date "2011-11-02" :size "8mb" :duration 101 :youtube "1W66B3CHaUo" :commands ["yas-expand"]}
7 | {:number "07" :name "Mind. Exploded." :date "2011-11-09" :size "14mb" :duration 90 :youtube "NXTf8_Arl1w" :commands ["key-chord-define-global"]}
8 | {:number "08" :name "mark-multiple" :date "2011-11-22" :size "12mb" :duration 90 :youtube "r2o9HYi7DOY" :commands ["mark-next-like-this" "rename-sgml-tag" "inline-string-rectangle"]}
9 | {:number "09" :name "expand-region" :date "2012-01-25" :size "16mb" :duration 160 :youtube "_RvHz3vJ3kA" :commands ["expand-region"]}
10 | {:number "10" :name "Jumping around" :date "2012-04-10" :size "23mb" :duration 128 :youtube "UZkpmegySnc" :commands ["ace-jump-mode" "ido-imenu"]}
11 | {:number "11" :name "swank-js" :date "2012-07-04" :size "42mb" :duration 275 :youtube "qwtVtcQQfqc" :commands ["slime-js-send-defun" "slime-js-jack-in-node"]}
12 | {:number "12" :name "Working with HTML" :date "2012-09-20" :size "27mb" :duration 114 :youtube "sBhQ2NIcrLQ" :commands ["query-replace" "cleanup-buffer" "isearch-forward" "expand-region" "rename-sgml-tag" "sgml-delete-tag" "describe-key" "eval-last-sexp" "flush-lines" "sgml-close-tag" "repeat" "zencoding-expand-line"]}
13 | {:number "13" :name "multiple-cursors" :date "2012-09-24" :size "35mb" :duration 236 :youtube "jNa3axo40qM" :commands ["mc-mark-next-like-this" "yank-rectangle" "set-rectangular-region-anchor" "dired-toggle-read-only" "mc-mark-all-like-this" "eval-and-replace" "kmacro-name-last-macro" "insert-kbd-macro"]}
14 | {:number "14" :name "Paredit" :date "2013-03-21" :size "41mb" :duration 219 :youtube "D6h5dFyyUX0" :commands []}
15 | {:number "15" :name "restclient-mode" :date "2014-11-17" :size "5mb" :duration 144 :youtube "fTvQTMOGJaw" :commands []}
16 | {:number "16" :name "dired" :date "2017-09-16" :size "5mb" :duration 95 :youtube "8l4YVttibiI" :commands ["dired-toggle-read-only"]}
17 | {:number "17" :name "magit" :date "2017-09-28" :size "5mb" :duration 159 :youtube "rzQEIRRJ2T0" :commands []}
18 | ]
19 |
--------------------------------------------------------------------------------