Compare commits

..

4 Commits

Author SHA1 Message Date
Charlotte Allen ee2f6dcded Post types 2021-10-21 22:36:06 -07:00
Charlotte Allen 1f3183d9f6 Refactoring for dependency injection based IO 2020-07-22 22:32:55 -07:00
Charlotte Allen 462fef7cf6 Cleanup index 2020-07-22 18:53:25 -07:00
Charlotte Allen 0674314e0d Initial work for isolating post io 2020-07-22 15:51:29 -07:00
15 changed files with 212 additions and 729 deletions

3
.gitignore vendored
View File

@ -20,6 +20,3 @@ resources/posts/
resources/index/
.eastwood
code.code-workspace
.portal/
tags
**/public/css/**

View File

@ -3,36 +3,37 @@
:description "FIXME: write description"
:url "http://example.com/FIXME"
:dependencies [[ch.qos.logback/logback-classic "1.2.7"]
[cheshire "5.10.1"]
[clojure.java-time "0.3.3"]
[org.clojure/data.json "2.4.0"]
[cprop "0.1.19"]
:dependencies [[ch.qos.logback/logback-classic "1.2.3"]
[cheshire "5.9.0"]
[clojure.java-time "0.3.2"]
[org.clojure/data.json "0.2.7"]
[cprop "0.1.15"]
[clucy "0.4.0"]
[expound "0.8.10"]
[expound "0.8.3"]
[funcool/struct "1.4.0"]
[luminus-jetty "0.2.1"]
[luminus-jetty "0.1.7"]
[luminus-transit "0.1.2"]
[luminus/ring-ttl-session "0.3.3"]
[markdown-clj "1.10.7"]
[metosin/muuntaja "0.6.8"]
[metosin/reitit "0.5.15"]
[metosin/ring-http-response "0.9.3"]
[markdown-clj "1.10.1"]
[metosin/muuntaja "0.6.6"]
[metosin/reitit "0.3.10"]
[metosin/ring-http-response "0.9.1"]
[mount "0.1.16"]
[nrepl "0.8.3"]
[org.clojure/clojure "1.10.3"]
[org.clojure/tools.cli "1.0.206"]
[org.clojure/tools.logging "1.1.0"]
[org.webjars.npm/bulma "0.9.3"]
[org.webjars.npm/material-icons "1.7.1"]
[org.webjars/webjars-locator "0.42"]
[duratom "0.5.2"]
[nrepl "0.6.0"]
[org.clojure/clojure "1.10.1"]
[org.clojure/tools.cli "0.4.2"]
[org.clojure/tools.logging "0.5.0"]
[org.webjars.npm/bulma "0.8.0"]
[org.webjars.npm/material-icons "0.3.1"]
[org.webjars/webjars-locator "0.38"]
[ring-webjars "0.2.0"]
[ring/ring-core "1.9.4"]
[ring/ring-defaults "0.3.3"]
[selmer "1.12.45"]]
:plugins [[lein-sass "0.4.0"]]
:sass {:src "resources/sass"
:output-directory "resources/public/css"}
[ring/ring-core "1.8.0"]
[ring/ring-defaults "0.3.2"]
[lein-cljfmt "0.6.6"]
[selmer "1.12.18"]]
:min-lein-version "2.0.0"
:source-paths ["src/clj"]
@ -40,6 +41,10 @@
:resource-paths ["resources"]
:target-path "target/%s/"
:main ^:skip-aot shapey-shifty.core
:plugins [ [lein-cljfmt "0.6.6"]
]
:profiles
{:uberjar {:omit-source true
:aot :all
@ -51,9 +56,9 @@
:test [:project/dev :project/test :profiles/test]
:project/dev {:jvm-opts ["-Dconf=dev-config.edn"]
:dependencies [[pjstadig/humane-test-output "0.11.0"]
[prone "2021-04-23"]
[ring/ring-devel "1.9.4"]
:dependencies [[pjstadig/humane-test-output "0.10.0"]
[prone "2019-07-08"]
[ring/ring-devel "1.8.0"]
[ring/ring-mock "0.4.0"]]
:plugins [[com.jakemccrary/lein-test-refresh "0.24.1"]
[jonase/eastwood "0.3.5"]]

View File

@ -10,7 +10,6 @@
{% style "/assets/material-icons/css/material-icons.min.css" %}
{% style "/css/screen.css" %}
{% style "/css/minima.css" %}
</head>
<body>
<!-- navbar -->

View File

@ -1,63 +0,0 @@
@charset "utf-8";
// Define defaults for each variable.
$base-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
$base-font-size: 16px !default;
$base-font-weight: 400 !default;
$small-font-size: $base-font-size * 0.875 !default;
$base-line-height: 1.5 !default;
$spacing-unit: 30px !default;
$green: #C5DCA0;
$yellow: #F5F2B8;
$peach: #F9DAD0;
$lavender: #A491D3;
$gray: #818AA3;
$background-color: $green !default;
$brand-color: $lavender !default;
$block-color: $peach !default;
$contrast-color: $yellow !default;
$dark-brand: darken($brand-color, 25%) !default;
$grey-color: $gray !default;
$grey-color-light: lighten($grey-color, 40%) !default;
$grey-color-dark: darken($grey-color, 25%) !default;
$text-color: $grey-color-dark !default;
$table-text-align: left !default;
// Width of the content area
$content-width: 1000px !default;
$on-palm: 600px !default;
$on-laptop: 800px !default;
// Use media queries like this:
// @include media-query($on-palm) {
// .wrapper {
// padding-right: $spacing-unit / 2;
// padding-left: $spacing-unit / 2;
// }
// }
@mixin media-query($device) {
@media screen and (max-width: $device) {
@content;
}
}
@mixin relative-font-size($ratio) {
font-size: $base-font-size * $ratio;
}
// Import partials.
@import
"minima/base",
"minima/layout",
"minima/syntax-highlighting"
;

View File

@ -1,255 +0,0 @@
/**
* Reset some basic elements
*/
body, h1, h2, h3, h4, h5, h6,
p, blockquote, pre, hr,
dl, dd, ol, ul, figure {
margin: 0;
padding: 0;
}
/**
* Basic styling
*/
body {
font: $base-font-weight #{$base-font-size}/#{$base-line-height} $base-font-family;
color: $text-color;
background-color: $background-color;
-webkit-text-size-adjust: 100%;
-webkit-font-feature-settings: "kern" 1;
-moz-font-feature-settings: "kern" 1;
-o-font-feature-settings: "kern" 1;
font-feature-settings: "kern" 1;
font-kerning: normal;
display: flex;
min-height: 100vh;
flex-direction: column;
}
/**
* Set `margin-bottom` to maintain vertical rhythm
*/
h1, h2, h3, h4, h5, h6,
p, blockquote, pre,
ul, ol, dl, figure,
%vertical-rhythm {
margin-bottom: $spacing-unit / 2;
}
/**
* `main` element
*/
main {
display: block; /* Default value of `display` of `main` element is 'inline' in IE 11. */
}
/**
* Images
*/
img {
max-width: 100%;
vertical-align: middle;
}
/**
* Figures
*/
figure > img {
display: block;
}
figcaption {
font-size: $small-font-size;
}
/**
* Lists
*/
ul, ol {
margin-left: $spacing-unit;
}
li {
> ul,
> ol {
margin-bottom: 0;
}
}
/**
* Headings
*/
h1, h2, h3, h4, h5, h6 {
font-weight: $base-font-weight;
}
/**
* Links
*/
a {
color: $brand-color;
text-decoration: none;
&:visited {
color: darken($brand-color, 15%);
}
&:hover {
color: $text-color;
text-decoration: underline;
}
.social-media-list &:hover {
text-decoration: none;
.username {
text-decoration: underline;
}
}
}
/**
* Blockquotes
*/
blockquote {
color: $grey-color;
border-left: 4px solid $grey-color-light;
padding-left: $spacing-unit / 2;
@include relative-font-size(1.125);
letter-spacing: -1px;
font-style: italic;
> :last-child {
margin-bottom: 0;
}
}
/**
* Code formatting
*/
pre,
code {
@include relative-font-size(0.9375);
border: 1px solid $grey-color-light;
border-radius: 3px;
background-color: #eef;
}
code {
padding: 1px 5px;
}
pre {
padding: 8px 12px;
overflow-x: auto;
> code {
border: 0;
padding-right: 0;
padding-left: 0;
}
}
/**
* Wrapper
*/
.wrapper {
max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit} * 2));
max-width: calc(#{$content-width} - (#{$spacing-unit} * 2));
margin-right: auto;
margin-left: auto;
padding-right: $spacing-unit;
padding-left: $spacing-unit;
@extend %clearfix;
@include media-query($on-laptop) {
max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit}));
max-width: calc(#{$content-width} - (#{$spacing-unit}));
padding-right: $spacing-unit / 2;
padding-left: $spacing-unit / 2;
}
}
/**
* Clearfix
*/
%clearfix:after {
content: "";
display: table;
clear: both;
}
/**
* Icons
*/
.svg-icon {
width: 16px;
height: 16px;
display: inline-block;
fill: #{$grey-color};
padding-right: 5px;
vertical-align: text-top;
}
.social-media-list {
li + li {
padding-top: 5px;
}
}
/**
* Tables
*/
table {
margin-bottom: $spacing-unit;
width: 100%;
text-align: $table-text-align;
color: lighten($text-color, 18%);
border-collapse: collapse;
border: 1px solid $grey-color-light;
tr {
&:nth-child(even) {
background-color: lighten($grey-color-light, 6%);
}
}
th, td {
padding: ($spacing-unit / 3) ($spacing-unit / 2);
}
th {
background-color: lighten($grey-color-light, 3%);
border: 1px solid darken($grey-color-light, 4%);
border-bottom-color: darken($grey-color-light, 12%);
}
td {
border: 1px solid $grey-color-light;
}
}

View File

@ -1,297 +0,0 @@
/**
* Site header
*/
.site-header {
border-top: 5px solid $grey-color;
border-bottom: 1px dotted $grey-color;
min-height: $spacing-unit * 1.865;
// Positioning context for the mobile navigation icon
position: relative;
}
.site-title {
@include relative-font-size(1.625);
font-weight: 300;
line-height: $base-line-height * $base-font-size * 2.25;
letter-spacing: -1px;
margin-bottom: 0;
float: left;
&,
&:visited {
color: $grey-color-dark;
}
}
.site-nav {
float: right;
line-height: $base-line-height * $base-font-size * 2.25;
.nav-trigger {
display: none;
}
.menu-icon {
display: none;
}
.page-link {
color: $text-color;
line-height: $base-line-height;
// Gaps between nav items, but not on the last one
&:not(:last-child) {
margin-right: 20px;
}
}
@include media-query($on-palm) {
position: absolute;
top: 9px;
right: $spacing-unit / 2;
background-color: $background-color;
border: 1px solid $grey-color-light;
border-radius: 5px;
text-align: right;
label[for="nav-trigger"] {
display: block;
float: right;
width: 36px;
height: 36px;
z-index: 2;
cursor: pointer;
}
.menu-icon {
display: block;
float: right;
width: 36px;
height: 26px;
line-height: 0;
padding-top: 10px;
text-align: center;
> svg {
fill: $grey-color-dark;
}
}
input ~ .trigger {
clear: both;
display: none;
}
input:checked ~ .trigger {
display: block;
padding-bottom: 5px;
}
.page-link {
display: block;
padding: 5px 10px;
&:not(:last-child) {
margin-right: 0;
}
margin-left: 20px;
}
}
}
/**
* Site footer
*/
.site-footer {
border-top: 1px dotted $grey-color;
padding: $spacing-unit 0;
.u-photo {
border-radius: 50%;
}
}
.footer-heading {
@include relative-font-size(1.125);
margin-bottom: $spacing-unit / 2;
}
.contact-list,
.social-media-list {
list-style: none;
margin-left: 0;
}
.footer-col-wrapper {
@include relative-font-size(0.9375);
color: $grey-color;
margin-left: -$spacing-unit / 2;
@extend %clearfix;
}
.footer-col {
float: left;
margin-bottom: $spacing-unit / 2;
padding-left: $spacing-unit / 2;
}
.footer-col-1 {
width: -webkit-calc(25% - (#{$spacing-unit} / 2));
width: calc(25% - (#{$spacing-unit} / 2));
}
.footer-col-2 {
width: -webkit-calc(20% - (#{$spacing-unit} / 2));
width: calc(20% - (#{$spacing-unit} / 2));
}
.footer-col-3 {
width: -webkit-calc(55% - (#{$spacing-unit} / 2));
width: calc(55% - (#{$spacing-unit} / 2));
}
@include media-query($on-laptop) {
.footer-col-1,
.footer-col-2 {
width: -webkit-calc(50% - (#{$spacing-unit} / 2));
width: calc(50% - (#{$spacing-unit} / 2));
}
.footer-col-3 {
width: -webkit-calc(100% - (#{$spacing-unit} / 2));
width: calc(100% - (#{$spacing-unit} / 2));
}
}
@include media-query($on-palm) {
.footer-col {
float: none;
width: -webkit-calc(100% - (#{$spacing-unit} / 2));
width: calc(100% - (#{$spacing-unit} / 2));
}
}
/**
* Page content
*/
.page-content {
padding: $spacing-unit 0;
flex: 1;
}
.page-heading {
@include relative-font-size(2);
}
.post-list-heading {
@include relative-font-size(1.75);
}
.post-list {
margin-left: 0;
list-style: none;
> li {
margin-bottom: $spacing-unit;
}
}
.post-meta {
font-size: $small-font-size;
color: $grey-color;
}
.post-link {
display: block;
@include relative-font-size(1.5);
}
/**
* Posts
*/
.post-header {
margin-bottom: $spacing-unit;
}
.post-title {
@include relative-font-size(2.625);
letter-spacing: -1px;
line-height: 1;
@include media-query($on-laptop) {
@include relative-font-size(2.25);
}
}
.post-content {
margin-bottom: $spacing-unit;
h2 {
@include relative-font-size(2);
@include media-query($on-laptop) {
@include relative-font-size(1.75);
}
}
h3 {
@include relative-font-size(1.625);
@include media-query($on-laptop) {
@include relative-font-size(1.375);
}
}
h4 {
@include relative-font-size(1.25);
@include media-query($on-laptop) {
@include relative-font-size(1.125);
}
}
}
.h-entry {
background-color: $block-color;
padding: $spacing-unit / 1.5;
border-radius: $spacing-unit;
border: 4px solid $grey-color;
//border-top: 1px solid $contrast-color;
//border-left: 1px solid $contrast-color;
//box-shadow: ($spacing-unit / 30) ($spacing-unit / 15) $grey-color;
}
.reply-context {
border-top: 1px solid $grey-color;
border-bottom: 1px solid $grey-color;
}
a {
&.pgp::before {
content: "";
}
&.u-in-reply-to::before {
content: "" ;
}
&.u-like-of::before {
content: "" ;
}
&.u-bookmark-of::before {
content: "🔖 " ;
}
&.u-checkin::before {
content: "";
}
}

View File

@ -1,71 +0,0 @@
/**
* Syntax highlighting styles
*/
.highlight {
background: #fff;
@extend %vertical-rhythm;
.highlighter-rouge & {
background: #eef;
}
.c { color: #998; font-style: italic } // Comment
.err { color: #a61717; background-color: #e3d2d2 } // Error
.k { font-weight: bold } // Keyword
.o { font-weight: bold } // Operator
.cm { color: #998; font-style: italic } // Comment.Multiline
.cp { color: #999; font-weight: bold } // Comment.Preproc
.c1 { color: #998; font-style: italic } // Comment.Single
.cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special
.gd { color: #000; background-color: #fdd } // Generic.Deleted
.gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific
.ge { font-style: italic } // Generic.Emph
.gr { color: #a00 } // Generic.Error
.gh { color: #999 } // Generic.Heading
.gi { color: #000; background-color: #dfd } // Generic.Inserted
.gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific
.go { color: #888 } // Generic.Output
.gp { color: #555 } // Generic.Prompt
.gs { font-weight: bold } // Generic.Strong
.gu { color: #aaa } // Generic.Subheading
.gt { color: #a00 } // Generic.Traceback
.kc { font-weight: bold } // Keyword.Constant
.kd { font-weight: bold } // Keyword.Declaration
.kp { font-weight: bold } // Keyword.Pseudo
.kr { font-weight: bold } // Keyword.Reserved
.kt { color: #458; font-weight: bold } // Keyword.Type
.m { color: #099 } // Literal.Number
.s { color: #d14 } // Literal.String
.na { color: #008080 } // Name.Attribute
.nb { color: #0086B3 } // Name.Builtin
.nc { color: #458; font-weight: bold } // Name.Class
.no { color: #008080 } // Name.Constant
.ni { color: #800080 } // Name.Entity
.ne { color: #900; font-weight: bold } // Name.Exception
.nf { color: #900; font-weight: bold } // Name.Function
.nn { color: #555 } // Name.Namespace
.nt { color: #000080 } // Name.Tag
.nv { color: #008080 } // Name.Variable
.ow { font-weight: bold } // Operator.Word
.w { color: #bbb } // Text.Whitespace
.mf { color: #099 } // Literal.Number.Float
.mh { color: #099 } // Literal.Number.Hex
.mi { color: #099 } // Literal.Number.Integer
.mo { color: #099 } // Literal.Number.Oct
.sb { color: #d14 } // Literal.String.Backtick
.sc { color: #d14 } // Literal.String.Char
.sd { color: #d14 } // Literal.String.Doc
.s2 { color: #d14 } // Literal.String.Double
.se { color: #d14 } // Literal.String.Escape
.sh { color: #d14 } // Literal.String.Heredoc
.si { color: #d14 } // Literal.String.Interpol
.sx { color: #d14 } // Literal.String.Other
.sr { color: #009926 } // Literal.String.Regex
.s1 { color: #d14 } // Literal.String.Single
.ss { color: #990073 } // Literal.String.Symbol
.bp { color: #999 } // Name.Builtin.Pseudo
.vc { color: #008080 } // Name.Variable.Class
.vg { color: #008080 } // Name.Variable.Global
.vi { color: #008080 } // Name.Variable.Instance
.il { color: #099 } // Literal.Number.Integer.Long
}

View File

@ -0,0 +1,9 @@
(ns shapey-shifty.context.core
(:require [clojure.spec.alpha :as s]
[shapey-shifty.posts.core :as posts]
[shapey-shifty.index.index :as index]))
(s/def ::posts (s/coll-of :posts/post))
(s/def ::index :index/index)
(s/def ::context (s/keys :req [::posts ::current-time ::index]))

View File

@ -2,10 +2,12 @@
(:require
[shapey-shifty.handler :as handler]
[shapey-shifty.nrepl :as nrepl]
[shapey-shifty.index.index :as index]
[luminus.http-server :as http]
[shapey-shifty.config :refer [env]]
[clojure.tools.cli :refer [parse-opts]]
[clojure.tools.logging :as log]
[shapey-shifty.posts.post-io :as io]
[mount.core :as mount])
(:gen-class))
@ -21,6 +23,11 @@
[["-p" "--port PORT" "Port number"
:parse-fn #(Integer/parseInt %)]])
(mount/defstate index :start (if-let [path (env :index-path)]
(index/create-index path)
(index/create-index "resources/index.edn")))
(mount/defstate file-keeper :start)
(mount/defstate ^{:on-reload :noop} http-server
:start
(http/start

View File

@ -1,13 +1,20 @@
(ns shapey-shifty.index.index
(:require [clucy.core :as clucy]
[shapey-shifty.posts.posts-io :as post-io]))
(:require
[clojure.spec.alpha :as s]
[duratom.core :as dur]
[shapey-shifty.posts.posts-io :as post-io]))
(def index-path (atom "resources/index"))
(s/def ::index-item (s/keys :req [::filename ::key ::created-date ::stub]))
(s/def ::index (s/coll-of ::index-item))
(def post-index (clucy/disk-index @index-path))
(defn create-index [index-path]
(let [index (dur/duratom :local-file :file-path index-path :init [])]
index))
(defn add-post-to-index [post]
(clucy/add post-index post))
(defn add-post-to-index [index post]
(let [metadata (dissoc post :content)]
(if-let [existing-post (empty (filter #(= (:key %) (:key post)) index))]
(conj index metadata))))
(defn crawl-posts!
([path]
@ -17,5 +24,5 @@
clojure.java.io/file
file-seq
(filter #(.isFile %))
(mapv #(parsing-fn %))
(mapv parsing-fn)
(apply add-post-to-index))))

View File

@ -1,6 +1,38 @@
(ns shapey-shifty.posts.core)
(ns shapey-shifty.posts.core
(:require [clojure.spec.alpha :as s]))
(defn create-empty-post [] {:type nil :properties {:name nil :author nil :published nil :content nil}})
(defn create-empty-post [] {::type :note ::key (java.util.UUID/randomUUID) ::content ""
::properties
{::name nil
::author nil
::published nil
::created (java.time.LocalDateTime/now)
::stub nil
::filename nil
::status :preview}})
(s/def ::name (s/nilable string?))
(s/def ::author (s/nilable string?))
(s/def ::published (s/nilable keyword?))
(s/def ::content (s/nilable string?))
(s/def ::stub (s/nilable string?))
(s/def ::filename (s/nilable string?))
(s/def ::type keyword?)
(s/def ::key uuid?)
(s/def ::status keyword?)
(s/def ::properties
(s/keys :req-un [::name ::author ::published ::stub ::filename ::created]))
(s/def ::post
(s/keys :req-un [::type ::properties ::content]))
(defprotocol PostKeeper
(create-post [this post])
(search-posts [this post-filter index])
(get-all-posts [this])
(update-post [this post])
(delete-post [this post]))
(defn set-publish-date [post date]
(assoc-in post [:properties :published] date))

View File

@ -3,7 +3,7 @@
[shapey-shifty.posts.core :as core]
[shapey-shifty.authors.author-core :as author]))
(def post-filename "post.json")
(def post-filename "post.edn")
(def base-posts-path "resources/posts")
(defn create-path-by-date [year month day]
@ -43,3 +43,29 @@
(let [path (format "%s/%s/%s/%s" base-posts-path (pathmap-to-path dt-path) n post-filename)
f (clojure.java.io/file path)]
(read-post f))))
(defn datetime-filename-resolver [post]
(if (:filename post)
(:filename post)))
(defrecord FileBasedPostKeeper [filename-resolver base-path filename index]
core/PostKeeper
(create-post [this post]
(let [path (str base-path (filename-resolver post) filename)]
(clojure.java.io/make-parents path)
(spit path post)))
(search-posts [this post-filter index]
(-> index
post-filter
(partial map #(:filename %))
(partial map #(clojure.java.io/file))
file-seq
(partial map read-post)))
(get-all-posts [this]
(->> base-path
clojure.java.io/file
file-seq
(filter #(.isFile %))
(map read-post)))
(update-post [this post] nil)
(delete-post [this post] nil))

View File

@ -31,5 +31,4 @@
{:middleware @middleware}
["/" {:get home-page}]
["/about/:name" {:get about-page}]
["/:year/:month/:day/:n" {:get post-view}]])
["/blog/:year/:month/:day/:n" {:get post-view}]])

88
tags Normal file
View File

@ -0,0 +1,88 @@
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/
!_TAG_PROGRAM_URL https://ctags.io/ /official site/
!_TAG_PROGRAM_VERSION 0.0.0 //
-main src/clj/shapey_shifty/core.clj /^(defn -main [& args]$/;" f namespace:shapey-shifty.core
.material-icons resources/public/css/screen.css /^.material-icons {$/;" c
Error: {{status}} resources/html/error.html /^ <h1><span class="is-size-4 has-text-danger">Error: {{status}}<\/span><\/h1>$/;" h
License README.md /^## License$/;" s
Managing your middleware resources/docs/docs.md /^#### Managing your middleware$/;" t
Need some help? resources/docs/docs.md /^#### Need some help?$/;" t
Organizing the routes resources/docs/docs.md /^#### Organizing the routes$/;" t
Prerequisites README.md /^## Prerequisites$/;" s
Running README.md /^## Running$/;" s
Why are you seeing this page? resources/docs/docs.md /^#### Why are you seeing this page?$/;" t
about-page src/clj/shapey_shifty/routes/home.clj /^(defn about-page [request]$/;" f namespace:shapey-shifty.routes.home
add-load-post-step src/clj/shapey_shifty/pipeline/core.clj /^(defn add-load-post-step [f]$/;" f namespace:shapey-shifty.pipeline.core
add-pipeline src/clj/shapey_shifty/pipeline/core.clj /^(defn add-pipeline [k v]$/;" f namespace:shapey-shifty.pipeline.core
add-post-to-index src/clj/shapey_shifty/index/index.clj /^(defn add-post-to-index [index post]$/;" f namespace:shapey-shifty.index.index
add-render-post-step src/clj/shapey_shifty/pipeline/core.clj /^(defn add-render-post-step [f]$/;" f namespace:shapey-shifty.pipeline.core
add-write-post-step src/clj/shapey_shifty/pipeline/core.clj /^(defn add-write-post-step [f]$/;" f namespace:shapey-shifty.pipeline.core
app src/clj/shapey_shifty/handler.clj /^(defn app []$/;" f namespace:shapey-shifty.handler
assoc-author src/clj/shapey_shifty/posts/posts_io.clj /^(defn assoc-author [post]$/;" f namespace:shapey-shifty.posts.posts-io
body resources/public/css/screen.css /^body {$/;" s
count-posts-in-date src/clj/shapey_shifty/posts/posts_io.clj /^(defn count-posts-in-date [dt-path]$/;" f namespace:shapey-shifty.posts.posts-io
crawl-posts! src/clj/shapey_shifty/index/index.clj /^(defn crawl-posts!$/;" f namespace:shapey-shifty.index.index
create-author src/clj/shapey_shifty/authors/author_core.clj /^(defn create-author []$/;" f namespace:shapey-shifty.authors.author-core
create-empty-post src/clj/shapey_shifty/posts/core.clj /^(defn create-empty-post [] {::type :note ::key (java.util.UUID\/randomUUID) ::content ""$/;" f namespace:shapey-shifty.posts.core
create-index src/clj/shapey_shifty/index/index.clj /^(defn create-index [index-path]$/;" f namespace:shapey-shifty.index.index
create-path-by-date src/clj/shapey_shifty/posts/posts_io.clj /^(defn create-path-by-date [year month day]$/;" f namespace:shapey-shifty.posts.posts-io
datetime-filename-resolver src/clj/shapey_shifty/posts/posts_io.clj /^(defn datetime-filename-resolver [post]$/;" f namespace:shapey-shifty.posts.posts-io
error-page src/clj/shapey_shifty/layout.clj /^(defn error-page$/;" f namespace:shapey-shifty.layout
execute-pipeline src/clj/shapey_shifty/pipeline/core.clj /^(defn execute-pipeline [k params]$/;" f namespace:shapey-shifty.pipeline.core
get-post src/clj/shapey_shifty/routes/post_router.clj /^(defn get-post$/;" f namespace:shapey-shifty.routes.post-router
home-page src/clj/shapey_shifty/routes/home.clj /^(defn home-page [request]$/;" f namespace:shapey-shifty.routes.home
home-routes src/clj/shapey_shifty/routes/home.clj /^(defn home-routes []$/;" f namespace:shapey-shifty.routes.home
html resources/public/css/screen.css /^html,$/;" s
load-all-authors src/clj/shapey_shifty/authors/author_core.clj /^(defn load-all-authors []$/;" f namespace:shapey-shifty.authors.author-core
load-author src/clj/shapey_shifty/authors/author_core.clj /^(defn load-author [author-name]$/;" f namespace:shapey-shifty.authors.author-core
nav-menu resources/html/base.html /^ <div id="nav-menu" class="navbar-menu">$/;" I
parse-json test/clj/shapey_shifty/test/handler.clj /^(defn parse-json [body]$/;" f namespace:shapey-shifty.test.handler
pathmap-to-path src/clj/shapey_shifty/posts/posts_io.clj /^(defn pathmap-to-path [{:keys [year month day]}]$/;" f namespace:shapey-shifty.posts.posts-io
post-view src/clj/shapey_shifty/routes/home.clj /^(defn post-view [request]$/;" f namespace:shapey-shifty.routes.home
read-post src/clj/shapey_shifty/posts/posts_io.clj /^(defn read-post$/;" f namespace:shapey-shifty.posts.posts-io
render src/clj/shapey_shifty/layout.clj /^(defn render$/;" f namespace:shapey-shifty.layout
restart env/dev/clj/user.clj /^(defn restart$/;" f namespace:user
set-author src/clj/shapey_shifty/posts/core.clj /^(defn set-author [post author]$/;" f namespace:shapey-shifty.posts.core
set-content src/clj/shapey_shifty/posts/core.clj /^(defn set-content [post post-content]$/;" f namespace:shapey-shifty.posts.core
set-name src/clj/shapey_shifty/posts/core.clj /^(defn set-name [post post-name]$/;" f namespace:shapey-shifty.posts.core
set-publish-date src/clj/shapey_shifty/posts/core.clj /^(defn set-publish-date [post date]$/;" f namespace:shapey-shifty.posts.core
set-type src/clj/shapey_shifty/posts/core.clj /^(defn set-type [post post-type]$/;" f namespace:shapey-shifty.posts.core
shapey-shifty README.md /^# shapey-shifty$/;" c
shapey-shifty.authors.author-core src/clj/shapey_shifty/authors/author_core.clj /^(ns shapey-shifty.authors.author-core$/;" n
shapey-shifty.config src/clj/shapey_shifty/config.clj /^(ns shapey-shifty.config$/;" n
shapey-shifty.core src/clj/shapey_shifty/core.clj /^(ns shapey-shifty.core$/;" n
shapey-shifty.dev-middleware env/dev/clj/shapey_shifty/dev_middleware.clj /^(ns shapey-shifty.dev-middleware$/;" n
shapey-shifty.env env/dev/clj/shapey_shifty/env.clj /^(ns shapey-shifty.env$/;" n
shapey-shifty.env env/prod/clj/shapey_shifty/env.clj /^(ns shapey-shifty.env$/;" n
shapey-shifty.handler src/clj/shapey_shifty/handler.clj /^(ns shapey-shifty.handler$/;" n
shapey-shifty.index.index src/clj/shapey_shifty/index/index.clj /^(ns shapey-shifty.index.index$/;" n
shapey-shifty.layout src/clj/shapey_shifty/layout.clj /^(ns shapey-shifty.layout$/;" n
shapey-shifty.middleware src/clj/shapey_shifty/middleware.clj /^(ns shapey-shifty.middleware$/;" n
shapey-shifty.middleware.formats src/clj/shapey_shifty/middleware/formats.clj /^(ns shapey-shifty.middleware.formats$/;" n
shapey-shifty.nrepl src/clj/shapey_shifty/nrepl.clj /^(ns shapey-shifty.nrepl$/;" n
shapey-shifty.pipeline.core src/clj/shapey_shifty/pipeline/core.clj /^(ns shapey-shifty.pipeline.core)$/;" n
shapey-shifty.posts.core src/clj/shapey_shifty/posts/core.clj /^(ns shapey-shifty.posts.core$/;" n
shapey-shifty.posts.posts-io src/clj/shapey_shifty/posts/posts_io.clj /^(ns shapey-shifty.posts.posts-io$/;" n
shapey-shifty.routes.home src/clj/shapey_shifty/routes/home.clj /^(ns shapey-shifty.routes.home$/;" n
shapey-shifty.routes.post-router src/clj/shapey_shifty/routes/post_router.clj /^(ns shapey-shifty.routes.post-router$/;" n
shapey-shifty.test.handler test/clj/shapey_shifty/test/handler.clj /^(ns shapey-shifty.test.handler$/;" n
start env/dev/clj/user.clj /^(defn start$/;" f namespace:user
start src/clj/shapey_shifty/nrepl.clj /^(defn start$/;" f namespace:shapey-shifty.nrepl
start-app src/clj/shapey_shifty/core.clj /^(defn start-app [args]$/;" f namespace:shapey-shifty.core
stop env/dev/clj/user.clj /^(defn stop$/;" f namespace:user
stop src/clj/shapey_shifty/nrepl.clj /^(defn stop [server]$/;" f namespace:shapey-shifty.nrepl
stop-app src/clj/shapey_shifty/core.clj /^(defn stop-app []$/;" f namespace:shapey-shifty.core
update-pipeline src/clj/shapey_shifty/pipeline/core.clj /^(defn update-pipeline [k f]$/;" f namespace:shapey-shifty.pipeline.core
user env/dev/clj/user.clj /^(ns user$/;" n
wrap-base src/clj/shapey_shifty/middleware.clj /^(defn wrap-base [handler]$/;" f namespace:shapey-shifty.middleware
wrap-csrf src/clj/shapey_shifty/middleware.clj /^(defn wrap-csrf [handler]$/;" f namespace:shapey-shifty.middleware
wrap-dev env/dev/clj/shapey_shifty/dev_middleware.clj /^(defn wrap-dev [handler]$/;" f namespace:shapey-shifty.dev-middleware
wrap-formats src/clj/shapey_shifty/middleware.clj /^(defn wrap-formats [handler]$/;" f namespace:shapey-shifty.middleware
wrap-internal-error src/clj/shapey_shifty/middleware.clj /^(defn wrap-internal-error [handler]$/;" f namespace:shapey-shifty.middleware
write-post src/clj/shapey_shifty/posts/posts_io.clj /^(defn write-post [post dt-path]$/;" f namespace:shapey-shifty.posts.posts-io
{{post.name}} resources/html/post.html /^ <h1 class="p-name">{{post.name}}<\/h1>$/;" h
{{title}} resources/html/error.html /^ <h2 class="without-margin">{{title}}<\/h2>$/;" i