From 01754a7d57fbe55577fe5e6de4fc55e2f025e9ec Mon Sep 17 00:00:00 2001 From: Christian Mueller Date: Sun, 10 Jun 2012 18:26:03 +0200 Subject: [PATCH] plain text hidden behind a function call (to make localization easier) --- messages | 26 +++++++++ project.clj | 1 + src/NoteHub/crossover/lib.clj | 9 +-- src/NoteHub/settings.clj | 26 +++++++-- src/NoteHub/storage.clj | 1 - src/NoteHub/views/common.clj | 3 +- src/NoteHub/views/css_generator.clj | 19 ++++-- src/NoteHub/views/pages.clj | 90 +++++++++++------------------ 8 files changed, 102 insertions(+), 73 deletions(-) create mode 100644 messages diff --git a/messages b/messages new file mode 100644 index 0000000..c8e6f66 --- /dev/null +++ b/messages @@ -0,0 +1,26 @@ +title = Free and Hassle-free Markdown Hosting. +name = NoteHub +new-page = New Page + +column-why = Why? +column-why-long = Not every person, who occasionally wants to express some thoughts, needs a blog. Blogs are __tedious__ for writers and for readers. Most people are not interested in thoughts of other random people. Moreover, nowadays everything rotates around social networks and not individual blogs. It makes much more sense to publish something somewhere and to share the link with the audience on the community or social network of your choice, than to maintain a blog trying to keep your readers interested. __NoteHub__ should be the place, where you can publish your thoughts without hassle. + +column-how = How to Use? +column-how-long = First [create](/new) a new page using the [Markdown](http://daringfireball.net/projects/markdown/) syntax. Now, besides just sharing the link, you can view some rudimentary statistics by appending `/stats` to the note url:
notehub.org/.../title/stats
If you want to export a note in the original Markdown format, append `/export`:
notehub.org/.../title/export
You also can invert the color scheme by appending `?theme=dark` to the note url:
notehub.org/.../title?theme=dark
+ +column-geeks = For Geeks! +column-geeks-long = NoteHub was an one-app-one-language experiment and is implemented entirely in [Clojure](http://clojure.org) and ClojureScript. Its [source code](https://github.com/chmllr/NoteHub) can be found on GitHub. Look at the code to find some undocumented NoteHub features (or bugs) and — feel free to contribute! (If you are interested in more detailed code overview, read [this note](http://notehub.org).) NoteHub's design is intentionally kept extremelly simple and minimalistic, and should stay like this. NoteHub's persistence layer bases on the key-value store [redis](http://redis.io). Currently, NoteHub is hosted for free on [Heroku](http://heroku.com). Send your feedback and comments directly to [@chmllr](http://twitter.com/chmllr) or [open an issue](https://github.com/chmllr/NoteHub/issues) on GitHub. + +status-404 = Nothing found. +status-400 = Bad Request. +status-500 = OMG, Server Exploded. + +created-by = Created by [@chmllr](http://twitter.com/chmllr) + +loading = Loading... +preview = Preview +publish = Publish +published = Published +article-views = Article Views +statistics = Statistics +new-note = New Markdown Note diff --git a/project.clj b/project.clj index e6f5689..e23d536 100644 --- a/project.clj +++ b/project.clj @@ -1,6 +1,7 @@ (defproject NoteHub "0.1.0-SNAPSHOT" :description "A free and anonymous hosting for markdown pages." :dependencies [[org.clojure/clojure "1.4.0"] + [org.clojure/clojure-contrib "1.2.0"] [hiccup "1.0.0"] [cssgen "0.2.6"] [jayq "0.1.0-alpha2"] diff --git a/src/NoteHub/crossover/lib.clj b/src/NoteHub/crossover/lib.clj index 86900cf..cd27197 100644 --- a/src/NoteHub/crossover/lib.clj +++ b/src/NoteHub/crossover/lib.clj @@ -4,15 +4,16 @@ (defn hash "A simple hash-function, which computes a hash from the text field content and given session number. It is intended to be used as a spam - protection / captcha alternative. (Probably doesn't work for URF-16)" + protection / captcha alternative (let's see whether spambots evaluate heavy JS). + (Probably doesn't work for UTF-16)" [f s] (let [short-mod #(mod % 32767) - char-codes (map f - (filter #(not (contains? #{"\n" "\r"} %)) (map str s)))] + char-codes (map f (remove #(contains? #{"\n" "\r"} %) (map str s))) + zip-with-index (map list char-codes (range))] (reduce #(short-mod (+ % (short-mod (* (first %2) ((if (odd? %) bit-xor bit-and) 16381 (second %2)))))) - 0 (map list char-codes (range))))) + 0 zip-with-index))) diff --git a/src/NoteHub/settings.clj b/src/NoteHub/settings.clj index 09cd6b3..c5dc519 100644 --- a/src/NoteHub/settings.clj +++ b/src/NoteHub/settings.clj @@ -1,19 +1,33 @@ (ns NoteHub.settings + (:require [clojure.contrib.string :as ccs]) (:refer-clojure :exclude [replace reverse]) (:use [clojure.string])) -; Load and parse te settings file returning a map -(def settings-map - (let [file-content (slurp "settings") - lines (split file-content #"\n") - pairs (map #(map trim (split % #"=")) lines)] +; Loads and parses the settings file; returns a key-value map. +; Assumes, that all string of the setings file are in format: +; key = value +(defn- get-pairs-map [file] + (let [file-content (slurp file) + pairs (map #(map trim (split % #"=" 2)) + (remove ccs/blank? (ccs/split-lines file-content)))] (apply hash-map (mapcat #(list (keyword (first %)) (second %)) pairs)))) +(def settings-map + (get-pairs-map "settings")) + +(def messages-map + (get-pairs-map "messages")) + +(defn get-message [key] + "Returns messages used in layouts. Every key should be a keyword, e.g. (get-message :title)." + (messages-map key)) + (defn get-setting "Takes a settings key, a converter function and a default value, and returns a corresponding setting value. The default value is returned back when no setting value was found. - The converter function can be provided to convert the setting from string to a needed type." + The converter function can be provided to convert the setting from string to a needed type. + Every key should be a keyword, e.g. (get-setting :page-width)." [key & more] (let [converter (first more) default (second more) diff --git a/src/NoteHub/storage.clj b/src/NoteHub/storage.clj index f36b16e..5573772 100644 --- a/src/NoteHub/storage.clj +++ b/src/NoteHub/storage.clj @@ -13,7 +13,6 @@ (def note "note") (def views "views") - ; Concatenates all fields to a string (defn- build-key [[year month day] title] (print-str year month day title)) diff --git a/src/NoteHub/views/common.clj b/src/NoteHub/views/common.clj index 8c29706..4ce0bdc 100644 --- a/src/NoteHub/views/common.clj +++ b/src/NoteHub/views/common.clj @@ -1,5 +1,6 @@ (ns NoteHub.views.common (:use + [NoteHub.settings :only [get-message]] [NoteHub.views.css-generator] [noir.core :only [defpartial]] [hiccup.page :only [include-js html5]] @@ -10,7 +11,7 @@ [params title & content] (html5 [:head - [:title "NoteHub — " title] + [:title (print-str (get-message :name) "—" title)] [:link {:href (clojure.string/replace (str "http://fonts.googleapis.com/css?family=" diff --git a/src/NoteHub/views/css_generator.clj b/src/NoteHub/views/css_generator.clj index fd25d34..f9241ba 100644 --- a/src/NoteHub/views/css_generator.clj +++ b/src/NoteHub/views/css_generator.clj @@ -54,12 +54,19 @@ background-halftone (color theme :background-halftone) foreground-halftone (color theme :foreground-halftone)] (css + (rule "a" + :color :#097 + :text-decoration :none + :border-bottom [:1px :dotted] + (rule "&:hover" + :color :#0a8) + (rule "&:visited" + :color :#054)) (rule ".landing-button" :box-shadow [0 :2px :5px :#aaa] :text-decoration :none :font-size :1.5em :background :#0a2 - :color :white :border :none :border-radius :10px :padding :10px @@ -77,6 +84,7 @@ (rule "td" :padding :0.5em) (rule ".one-third-column" + :line-height (% 120) :text-align :justify :vertical-align :top ; Replace this by arithmetic with css-lengths as soon as they fix the bug @@ -94,16 +102,19 @@ :margin :2em)) (rule "article" central-element - :line-height (% 140) :font-family text-fonts :text-align :justify :font-size :1.2em + (rule "p" + :line-height (% 140)) (rule "& > h1:first-child" :text-align :center :margin :2em)) + (rule ".centered" + :text-align :center) (rule "pre" :border-radius :3px - :padding :1em + :padding :0.5em :border [:1px :dotted foreground-halftone] :background background-halftone) (rule "*:focus" @@ -129,7 +140,7 @@ central-element) (rule "h1" :font-size :2em) - (rule "#preview-start-line" + (rule ".dashed-line" :border-bottom [:1px :dashed foreground-halftone] :margin-bottom :5em) (rule "h1, h2, h3, h4" diff --git a/src/NoteHub/views/pages.clj b/src/NoteHub/views/pages.clj index 5f647da..e322c99 100644 --- a/src/NoteHub/views/pages.clj +++ b/src/NoteHub/views/pages.clj @@ -1,5 +1,6 @@ (ns NoteHub.views.pages - (:require [NoteHub.crossover.lib :as lib]) + (:require [NoteHub.crossover.lib :as lib] + [clojure.contrib.string :as ccs]) (:use [NoteHub.storage] [NoteHub.settings] @@ -34,23 +35,18 @@ (layout params title [:article (md-to-html md-text)])) (status 404 (get-page 404)))) -; Template for the error sites -(defn page-setter [code message] +; Sets a custom message for each corresponding HTTP status +(doseq [code [400 404 500]] (set-page! code - (layout message - [:article - [:h1 message]]))) - -; Sets a message for each corresponding HTTP status -(page-setter 404 "Nothing Found.") -(page-setter 400 "Bad request.") -(page-setter 500 "OMG, Server Exploded.") + (let [message (get-message (keyword (str "status-" code)))] + (layout message + [:article [:h1 message]])))) ; Routes ; ====== ; This function answers to a AJAX request: it gets a sesion key and markdown text. -; IT return html version of the provided markdown and a new session key +; It returns the html code of the provided markdown and a new session key. (defremote get-preview-md [session-key md] (when (flash-get session-key) {:session-key (get-flash-key) @@ -58,58 +54,38 @@ ; Landing Page (defpage "/" {} - (layout "Free Markdown Hosting" + (layout (get-message :title) [:div#hero - [:h1 "NoteHub"] - [:h2 "Free and hassle-free hosting for markdown pages."] + [:h1 (get-message :name)] + [:h2 (get-message :title)] [:br] - [:a.landing-button {:href "/new"} "New Page"]] - [:div#preview-start-line] - [:table.central-element.helvetica-neue - [:tr - [:td.one-third-column - [:h2 "Why?"] - "Not every person, who occasionally wants to express some thoughts, needs a blog. - Blogs are tedious for writers and for readers. Most people are not interested in thoughts - of other random people. Moreover, nowadays everything rotates around social networks and not - individual blogs. It makes much more sense to publish something somewhere and to share - the link with the audience on the community or social network of your choice, than to maintain a blog - trying to keep your readers interested. - NoteHub should be the place, where you can publish your thoughts without hassle."] - [:td.one-third-column - [:h2 "How to Use?"] - "First create a new page using the markdown syntax. Now, besides just sharing the link, you can - view some rudimentary statistics by appending /stats to the note url: -
notehub.org/.../title/stats
- If you want to export a note in the original Markdown format, append /export -
notehub.org/.../title/export
- And if you want, you also can invert the color scheme by appending ?theme=dark to the note url. -
notehub.org/.../title?theme=dark
"] - [:td.one-third-column - [:h2 "For Geeks!"] - "NoteHub was an experiment and is implemented entirely in Clojure and ClojureScript. Its source code can - be found on GitHub. Look at the code to find some undocumented NoteHub features (or bugs) and — feel free to contribute! - (If you are interested in more detailed code overview, read the following note.) NoteHub's design - is intentionally kept extremelly simple and minimalistic, and should stay like this. - NoteHub's persistence layer bases on the key-value store redis. - Currently, NoteHub is hosted for free on Heroku. - Send your feedback and comments directly to @chmllr."]]])) + [:a.landing-button {:href "/new" :style "color: white"} (get-message :new-page)]] + [:div.dashed-line] + [:table.central-element.helvetica-neue + [:tr + [:td.one-third-column + [:h2 (get-message :column-why)] (md-to-html (get-message :column-why-long))] + [:td.one-third-column + [:h2 (get-message :column-how)] (md-to-html (get-message :column-how-long))] + [:td.one-third-column + [:h2 (get-message :column-geeks)] (md-to-html (get-message :column-geeks-long))]]] + [:div.centered.helvetica-neue (md-to-html (get-message :created-by))])) ; New Note Page (defpage "/new" {} - (layout {:js true} "New Markdown Note" + (layout {:js true} (get-message :new-note) [:div.central-element (form-to [:post "/post-note"] (hidden-field :session-key (get-flash-key)) (hidden-field {:id :session-value} :session-value) - (text-area {:class :max-width} :draft "Loading...") + (text-area {:class :max-width} :draft (get-message :loading)) [:div#buttons.hidden (submit-button {:style "float: left" :class :button - :id :publish-button} "Publish") + :id :publish-button} (get-message :publish)) [:button#preview-button.button {:type :button - :style "float: right"} "Preview"]])] - [:div#preview-start-line.hidden] + :style "float: right"} (get-message :preview)]])] + [:div#preview-start-line.dashed-line.hidden] [:article#preview])) ; Display the note @@ -127,14 +103,14 @@ (defpage "/:year/:month/:day/:title/stat" {:keys [year month day title]} (let [views (get-views [year month day] title)] (if views - (layout "Statistics" + (layout (get-message :statistics) [:article.helvetica-neue [:table {:style "width: 100%"} [:tr - [:td "Published"] + [:td (get-message :published)] [:td (interpose "-" [year month day])]] [:tr - [:td "Article views"] + [:td (get-message :article-views)] [:td views]]]]) (status 404 (get-page 404))))) @@ -151,11 +127,11 @@ (let [[year month day] (map #(+ (second %) (.get (Calendar/getInstance) (first %))) {Calendar/YEAR 0, Calendar/MONTH 1, Calendar/DAY_OF_MONTH 0}) untrimmed-line (filter #(or (= \- %) (Character/isLetterOrDigit %)) - (-> draft (split #"\n") first (sreplace " " "-") lower-case)) + (-> draft ccs/split-lines first (sreplace " " "-") lower-case)) trim (fn [s] (apply str (drop-while #(= \- %) s))) title-uncut (-> untrimmed-line trim reverse trim reverse) - proposed-title (apply str (take (get-setting :max-title-length #(Integer/parseInt %) 80) - title-uncut)) + max-length (get-setting :max-title-length #(Integer/parseInt %) 80) + proposed-title (apply str (take max-length title-uncut)) date [year month day] title (first (drop-while #(note-exists? date %) (cons proposed-title