Skip to content

Commit

Permalink
Implement #181 - web app manifest support
Browse files Browse the repository at this point in the history
This feature will allow sites built with Perun to be installed as an
app on systems that support it. When paired with #180, this will be
a slick offline experience.
  • Loading branch information
bhagany committed Dec 30, 2017
1 parent ff736bb commit 2325338
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 2 deletions.
58 changes: 58 additions & 0 deletions src/io/perun.clj
Original file line number Diff line number Diff line change
Expand Up @@ -1285,3 +1285,61 @@
:passthru-fn content-passthru
:task-name "inject-scripts"
:tracer :io.perun/inject-scripts}))))

(def ^:private ^:deps manifest-deps
'[[org.clojure/tools.namespace "0.3.0-alpha3"]
[cheshire "5.7.0"]])

(def +manifest-defaults+
{:out-dir "public"
:icon-path "icon.png"
:resolutions #{192 512}
:theme-color "#ffffff"
:display "standalone"
:scope "/"})

(deftask manifest*
[o out-dir OUTDIR str "the output directory"
t site-title TITLE str "name for the installable web application"
c theme-color COLOR str "background color theme for icon (default \"#ffffff\")"
d display DISPLAY str "display mode for browser (default \"standalone\")"
s scope SCOPE str "the scope to which the manifest applies (default \"/\")"]
(let [{:keys [site-title] :as opts} (merge +manifest-defaults+ *opts*)
pod (create-pod manifest-deps)]
(letfn [(manifest-path [fileset]
(let [icon-metas (filter-meta-by-ext fileset {:filterer :manifest-icon})
path (perun/create-filepath out-dir "manifest.json")
global-meta (pm/get-global-meta fileset)
args (merge opts
{:icons icon-metas
:input-paths (into #{} (map :path icon-metas))
:site-title (or site-title (:site-title global-meta))})]
{path args}))]
(content-task
{:render-form-fn (fn [data] `(io.perun.manifest/manifest ~data))
:paths-fn manifest-path
:task-name "manifest"
:tracer :io.perun/manifest
:pod pod}))))

(deftask manifest
"Creates a manifest.json for Android (currently)"
[o out-dir OUTDIR str "the output directory"
i icon-path PATH str "The input icon to be resized (default \"icon.png\""
r resolutions RESOLUTIONS #{int} "resolutions to which images should be resized (default #{192 512})"
t site-title TITLE str "name for the installable web application"
c theme-color COLOR str "background color theme for icon (default \"#ffffff\")"
d display DISPLAY str "display mode for browser (default \"standalone\")"
s scope SCOPE str "the scope to which the manifest applies (default \"/\")"]
(let [{:keys [out-dir icon-path resolutions site-title theme-color display scope]}
(merge +manifest-defaults+ *opts*)]
(comp (images-resize :out-dir out-dir
:resolutions resolutions
:filterer #(= (:path %) icon-path)
:meta {:manifest-icon true})
(mime-type :filterer :manifest-icon)
(manifest* :out-dir out-dir
:site-title site-title
:theme-color theme-color
:display display
:scope scope))))
15 changes: 15 additions & 0 deletions src/io/perun/manifest.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
(ns io.perun.manifest
(:require [cheshire.core :refer [generate-string]]))

(defn manifest
[{:keys [icons site-title theme-color display scope input-paths] :as data}]
(let [manifest {:name site-title
:icons (for [{:keys [permalink width height mime-type]} icons]
{:src permalink
:sizes (str width "x" height)
:type mime-type})
:theme_color theme-color
:display display
:scope scope}]
{:rendered (generate-string manifest)
:input-paths input-paths}))
28 changes: 26 additions & 2 deletions test/io/perun_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,17 @@ This --- be _asciidoc_.")
(testing "draft"
(file-exists? :path (perun/url-to-path "public/test/index.html")
:negate? true
:msg "`draft` should remove files"))))
:msg "`draft` should remove files"))

(add-image :path "icon.png" :type "PNG" :width 10 :height 10)
(p/manifest)
(testing "manifest"
(file-exists? :path (perun/url-to-path "public/manifest.json")
:msg "`manifest` should write manifest.json")
(file-exists? :path (perun/url-to-path "public/icon_192.png")
:msg "`manifest` should write icon resized to 192px")
(file-exists? :path (perun/url-to-path "public/icon_512.png")
:msg "`manifest` should write icon resized to 512px"))))

(deftesttask with-arguments-test []
(comp (boot/with-pre-wrap fileset
Expand Down Expand Up @@ -757,7 +767,21 @@ This --- be _asciidoc_.")
(content-check :path "baz.htm"
:content (str "<script>" js-content "</script>")
:negate? true
:msg "`inject-scripts` should not alter the contents of a removed file")))))
:msg "`inject-scripts` should not alter the contents of a removed file")))

(add-image :path "an-icon.png" :type "PNG" :width 10 :height 10)
(p/manifest :out-dir "foop"
:icon-path "an-icon.png"
:resolutions #{20}
:site-title "Blarg"
:theme-color "#f0987d"
:display "fullscreen"
:scope "/blarp")
(testing "manifest"
(file-exists? :path (perun/url-to-path "foop/manifest.json")
:msg "`manifest` should write manifest.json")
(file-exists? :path (perun/url-to-path "foop/an-icon_20.png")
:msg "`manifest` should write icon resized to 20px"))))

(deftesttask content-tests []
(comp (testing "Collection works without input files" ;; #77
Expand Down

0 comments on commit 2325338

Please sign in to comment.