Browse Source

initial commit

Josh Habdas 1 year ago
commit
0e61871eaa
Signed by: Josh Habdas <jhabdas@protonmail.com> GPG Key ID: B148B31154C75A74

+ 13
- 0
COPYING View File

@@ -0,0 +1,13 @@
1
+            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
+                    Version 2, December 2004
3
+
4
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
5
+
6
+ Everyone is permitted to copy and distribute verbatim or modified
7
+ copies of this license document, and changing it is allowed as long
8
+ as the name is changed.
9
+
10
+            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
+
13
+  0. You just DO WHAT THE FUCK YOU WANT TO.

+ 107
- 0
README.md View File

@@ -0,0 +1,107 @@
1
+# Hall of Mirrors
2
+
3
+> PhotoSwipe Image Gallery for [After Dark]. Hall of Mirrors adds a responsive JavaScript image gallery using [PhotoSwipe](http://photoswipe.com).
4
+
5
+[![Latest NPM version](https://img.shields.io/npm/v/hall-of-mirrors.svg?style=flat-square)](https://www.npmjs.com/package/hall-of-mirrors)
6
+[![NPM downloads per month](https://img.shields.io/npm/dm/hall-of-mirrors.svg?style=flat-square)](https://www.npmjs.com/package/hall-of-mirrors)
7
+[![Minimum After Dark version](https://img.shields.io/badge/after%20dark->%3D%205.4.0-000000.svg?style=flat-square)](https://git.habd.as/comfusion/after-dark/)
8
+[![WTFPL licensed](https://img.shields.io/npm/l/hall-of-mirrors.svg?style=flat-square&longCache=true)](https://git.habd.as/comfusion/hall-of-mirrors/src/branch/master/COPYING)
9
+
10
+## Setup
11
+
12
+If you're hosting your site from a subdirectory (e.g. `example.com/blog/`) you'll need to update the url types in `default-skin.css` to point to your blog. A script called `urlize` has been provided to facilitate this change. If images are encoded and inlined into `default-skin.css` using data uris this change will no longer be required.
13
+
14
+## Installation
15
+
16
+1. Copy the contents of this repository into a directory called `themes/hall-of-mirrors` under the root of your After Dark site.
17
+2. Add `hall-of-mirrors` as a [theme component](https://gohugo.io/themes/theme-components/) to your After Dark site `config.toml`, e.g.
18
+
19
+    ```toml
20
+    theme = [
21
+      "hall-of-mirrors",
22
+      "after-dark"
23
+    ]
24
+    ```
25
+
26
+3. Add and specify settings for the module in your After Dark site config, e.g.
27
+
28
+    ```toml
29
+    [params.modules.fractal_forest]
30
+      enabled = true # Required in version 1.0
31
+    ```
32
+
33
+4. Create a [Leaf Bundle] to group image resources you wish to display in a PhotoSwipe gallery together with your content.
34
+5. [Configure the gallery](#configuration) to your liking.
35
+6. Build and deploy your After Dark site.
36
+
37
+## Configuration
38
+
39
+To display a gallery add the [Page Resources] you wish to display to your [Leaf Bundle] and configure your front matter.
40
+
41
+### Minimal
42
+
43
+The following is all you need to display a basic gallery. Seriously.
44
+
45
+```toml
46
+[[resources]]
47
+  src = "**.jpg" # Display any jpeg image in the leaf bundle
48
+  name = "gallery" # Name must include the word 'gallery'
49
+```
50
+
51
+```toml
52
+[[resources]]
53
+  src = "images/gallery/**.jpg" # Restrict images to a folder
54
+  name = "Image gallery" # Provide a more friendly gallery name
55
+```
56
+
57
+### Extended
58
+
59
+If you want to add captions and enhance SEO you can configure individual resources.
60
+
61
+```toml
62
+[[resources]]
63
+  src = "**/ray-hennessy-763310-unsplash.jpg"
64
+  [resources.params]
65
+    thumb_size = "750x" # Adjust size of thumbnail image
66
+  [resources.params.meta]
67
+    creator = "Ray Hennessy"
68
+    description = "This is a long description. It is shown instead of the title and is intended to provide more information."
69
+
70
+[[resources]]
71
+  src = "**sprat**" # Glob for image with 'sprat' in the filename
72
+  title = "Diverse succulents around a rock"
73
+  [resources.params]
74
+    hide_credits = true # Display title but not creator
75
+  [resources.params.meta]
76
+    creator = "Annie Spratt" # Maps to schema structured data
77
+
78
+[[resources]]
79
+  src = "**/blake-richard-verdoorn-20063-unsplash.jpg"
80
+  title = "Bridge over a green waterfall"
81
+  [resources.params]
82
+    hide_credits = true
83
+    thumb_size = "350x"
84
+  [resources.params.meta]
85
+    creator = "Blake Richard Verdoorn"
86
+    keywords = ["nature", "waterfall", "bridge"]
87
+
88
+[[resources]]
89
+  src = "images/gallery/**.jpg"
90
+  name = "Nature gallery"
91
+  [resources.params.meta]
92
+    genere = "digital" # Set a genere for all image resources
93
+```
94
+
95
+This should get you started. Expect some breaking changes as the development is completed.
96
+
97
+## License
98
+
99
+Copyright (C) 2018 Josh Habdas <jhabdas@protonmail.com>
100
+
101
+This work is free. You can redistribute it and/or modify it under the
102
+terms of the Do What The Fuck You Want To Public License, Version 2,
103
+as published by Sam Hocevar. See the COPYING file for more details.
104
+
105
+[After Dark]: https://git.habd.as/comfusion/after-dark/
106
+[Leaf Bundle]: https://gohugo.io/content-management/page-bundles/#leaf-bundles
107
+[Page Resources]: https://gohugo.io/content-management/page-resources/

+ 27
- 0
bin/copy View File

@@ -0,0 +1,27 @@
1
+#!/bin/bash
2
+set -e
3
+
4
+ASSETS_DIR=node_modules/photoswipe/dist
5
+TARGET_DIR=static/modules/hall-of-mirrors
6
+
7
+# Print error to stdout and exit 1 if asset directories cannot be found
8
+if ! [ -d "$ASSETS_DIR" ] || [ -d "$ASSETS_DIR"/default-skins ] ; then
9
+   echo "Error: Photoswipe assets not found in $PWD/$ASSETS_DIR." >&2; exit 1
10
+fi
11
+
12
+# Create target directory if not exists
13
+mkdir -p "$TARGET_DIR"
14
+
15
+# Define required assets
16
+files=(
17
+   "$ASSETS_DIR"/*.min.js
18
+   "$ASSETS_DIR"/*.css
19
+   "$ASSETS_DIR"/**/*
20
+)
21
+# printf '%s\n' "${files[@]}" # e.g. path/to/source/filename.tar.gz
22
+# printf '%s\n' "${files[@]##*/}" # e.g. filename.tgz
23
+
24
+# Copy required assets to target directory
25
+for file in "${files[@]}" ; do
26
+   cp "$file" "$TARGET_DIR"
27
+done

+ 14
- 0
bin/urlize View File

@@ -0,0 +1,14 @@
1
+#!/bin/sh
2
+set -e
3
+
4
+SKIN_CSS_FILE=static/modules/hall-of-mirrors/default-skin.css
5
+BASE_URL=/modules/hall-of-mirrors/
6
+
7
+# Print error and exit 1 file not found
8
+if ! [ -f "$SKIN_CSS_FILE" ] ; then
9
+    echo "Error: Asset not found in $PWD/$SKIN_CSS_FILE." >&2; exit 1
10
+fi
11
+
12
+# Prefix filenames in url data types with baseurl
13
+# Note: Assumes file is not minified
14
+sed "s@url(\(.*\))@url($BASE_URL\1)@g" "$SKIN_CSS_FILE" | tee "$SKIN_CSS_FILE" >/dev/null

+ 23
- 0
layouts/partials/modules/hall-of-mirrors/gallery.html View File

@@ -0,0 +1,23 @@
1
+<div itemscope itemtype="http://schema.org/ImageGallery">
2
+  {{ range .Resources.Match "*gallery*" }}
3
+    {{ $thumbnail := .Resize (default "500x" (index .Params "thumb_size")) }}
4
+    <figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
5
+      <a data-size="{{ .Width }}x{{ .Height }}" href="{{ .RelPermalink }}" itemprop="contentUrl">
6
+        <img width="{{ div $thumbnail.Width 2 }}" height="{{ div $thumbnail.Height 2 }}" src="{{ $thumbnail.RelPermalink }}" itemprop="thumbnail" alt="{{ default (printf "%s thumbnail image" .Name) .Params.alt }}">
7
+      </a>
8
+      {{ partial "modules/hall-of-mirrors/meta.html" . }}
9
+      <figcaption itemprop="caption description">
10
+        {{ if .Params.meta.description }}
11
+          {{ .Params.meta.description }}
12
+        {{ else if ne (in .RelPermalink .Title) true }}
13
+          <span itemprop="name">{{ .Title }}</span>
14
+        {{ end }}
15
+        {{ if ne .Params.hide_credits true }}
16
+          {{ with .Params.meta.creator }}
17
+            <span>Photo by {{ . }}</span>
18
+          {{ end }}
19
+        {{ end }}
20
+      </figcaption>
21
+    </figure>
22
+  {{ end }}
23
+</div>

+ 22
- 0
layouts/partials/modules/hall-of-mirrors/index.html View File

@@ -0,0 +1,22 @@
1
+{{ if and (ne .settings.enabled false) }}
2
+  <meta title="mod:hall-of-mirrors" content="status:enabled">
3
+  {{ if .page.Resources.GetMatch "*gallery*"}}
4
+    {{ partial "modules/hall-of-mirrors/inline.js.html" }}
5
+    {{ partial "modules/hall-of-mirrors/inline.css.html" }}
6
+    <script>
7
+      /*! Fetch Inject v2.0.2 | Copyright (C) 2017–2018 Josh Habdas <jhabdas@protonmail.com> | @license Zlib */
8
+      !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.fetchInject=t()}(this,function(){"use strict";const e=function(e,t,n,r,o,c,i){c=t.createElement(n),i=t.getElementsByTagName(n)[0],c.appendChild(t.createTextNode(r.text)),c.onload=o(r),i?i.parentNode.insertBefore(c,i):t.head.appendChild(c)};return function(t,n){if(!arguments.length)return Promise.reject(new ReferenceError("Failed to execute 'fetchInject': 1 argument required but only 0 present."));if(arguments[0]&&arguments[0].constructor!==Array)return Promise.reject(new TypeError("Failed to execute 'fetchInject': argument 1 must be of type 'Array'."));if(arguments[1]&&arguments[1].constructor!==Promise)return Promise.reject(new TypeError("Failed to execute 'fetchInject': argument 2 must be of type 'Promise'."));const r=[],o=n?[].concat(n):[],c=[];return t.forEach(e=>o.push(window.fetch(e).then(e=>[e.clone().text(),e.blob()]).then(e=>Promise.all(e).then(e=>{r.push({text:e[0],blob:e[1]})})))),Promise.all(o).then(()=>(r.forEach(t=>{c.push({then:n=>{t.blob.type.includes("text/css")?e(window,document,"style",t,n):e(window,document,"script",t,n)}})}),Promise.all(c)))}});
9
+
10
+      fetchInject([
11
+        {{ "modules/hall-of-mirrors/photoswipe.css" | relURL }},
12
+        {{ "modules/hall-of-mirrors/default-skin.css" | relURL }},
13
+        {{ "modules/hall-of-mirrors/photoswipe.min.js" | relURL }},
14
+        {{ "modules/hall-of-mirrors/photoswipe-ui-default.min.js" | relURL }}
15
+      ]).then(() => {
16
+        initPhotoSwipeFromDOM('[itemtype="http://schema.org/ImageGallery"]')
17
+      })
18
+    </script>
19
+  {{ end }}
20
+{{ else }}
21
+  <meta title="mod:hall-of-mirrors" content="status:disabled">
22
+{{ end }}

+ 27
- 0
layouts/partials/modules/hall-of-mirrors/inline.css.html View File

@@ -0,0 +1,27 @@
1
+<style>
2
+  [itemtype="http://schema.org/ImageGallery"] {
3
+    display: flex;
4
+    flex-direction: row;
5
+    justify-content: center;
6
+    align-items: center;
7
+    flex-wrap: wrap;
8
+  }
9
+  [itemtype="http://schema.org/ImageGallery"] figure {
10
+    text-align: center;
11
+  }
12
+  [itemtype="http://schema.org/ImageGallery"] figure a {
13
+    border-bottom: none;
14
+  }
15
+  [itemtype="http://schema.org/ImageGallery"] figure a:hover {
16
+    background-color: inherit;
17
+  }
18
+  [itemtype="http://schema.org/ImageGallery"] figure img {
19
+    transition: all .2s ease-in-out;
20
+  }
21
+  [itemtype="http://schema.org/ImageGallery"] figure img:hover {
22
+    transform: scale(1.025);
23
+  }
24
+  [itemprop="caption description"] {
25
+    font-size: small;
26
+  }
27
+</style>

+ 205
- 0
layouts/partials/modules/hall-of-mirrors/inline.js.html View File

@@ -0,0 +1,205 @@
1
+<script>
2
+  var initPhotoSwipeFromDOM = function(gallerySelector) {
3
+
4
+    // parse slide data (url, title, size ...) from DOM elements
5
+    // (children of gallerySelector)
6
+    var parseThumbnailElements = function(el) {
7
+        var thumbElements = el.childNodes,
8
+            numNodes = thumbElements.length,
9
+            items = [],
10
+            figureEl,
11
+            linkEl,
12
+            size,
13
+            item;
14
+
15
+        for(var i = 0; i < numNodes; i++) {
16
+
17
+            figureEl = thumbElements[i]; // <figure> element
18
+
19
+            // include only element nodes
20
+            if(figureEl.nodeType !== 1) {
21
+                continue;
22
+            }
23
+
24
+            linkEl = figureEl.children[0]; // <a> element
25
+
26
+            size = linkEl.getAttribute('data-size').split('x');
27
+
28
+            // create slide object
29
+            item = {
30
+                src: linkEl.getAttribute('href'),
31
+                w: parseInt(size[0], 10),
32
+                h: parseInt(size[1], 10)
33
+            };
34
+
35
+
36
+
37
+            if(figureEl.children.length > 1) {
38
+                // <figcaption> content
39
+                item.title = figureEl.children[1].innerHTML;
40
+            }
41
+
42
+            if(linkEl.children.length > 0) {
43
+                // <img> thumbnail element, retrieving thumbnail url
44
+                item.msrc = linkEl.children[0].getAttribute('src');
45
+            }
46
+
47
+            item.el = figureEl; // save link to element for getThumbBoundsFn
48
+            items.push(item);
49
+        }
50
+
51
+        return items;
52
+    };
53
+
54
+    // find nearest parent element
55
+    var closest = function closest(el, fn) {
56
+        return el && ( fn(el) ? el : closest(el.parentNode, fn) );
57
+    };
58
+
59
+    // triggers when user clicks on thumbnail
60
+    var onThumbnailsClick = function(e) {
61
+        e = e || window.event;
62
+        e.preventDefault ? e.preventDefault() : e.returnValue = false;
63
+
64
+        var eTarget = e.target || e.srcElement;
65
+
66
+        // find root element of slide
67
+        var clickedListItem = closest(eTarget, function(el) {
68
+            return (el.tagName && el.tagName.toUpperCase() === 'FIGURE');
69
+        });
70
+
71
+        if(!clickedListItem) {
72
+            return;
73
+        }
74
+
75
+        // find index of clicked item by looping through all child nodes
76
+        // alternatively, you may define index via data- attribute
77
+        var clickedGallery = clickedListItem.parentNode,
78
+            childNodes = clickedListItem.parentNode.childNodes,
79
+            numChildNodes = childNodes.length,
80
+            nodeIndex = 0,
81
+            index;
82
+
83
+        for (var i = 0; i < numChildNodes; i++) {
84
+            if(childNodes[i].nodeType !== 1) {
85
+                continue;
86
+            }
87
+
88
+            if(childNodes[i] === clickedListItem) {
89
+                index = nodeIndex;
90
+                break;
91
+            }
92
+            nodeIndex++;
93
+        }
94
+
95
+
96
+
97
+        if(index >= 0) {
98
+            // open PhotoSwipe if valid index found
99
+            openPhotoSwipe( index, clickedGallery );
100
+        }
101
+        return false;
102
+    };
103
+
104
+    // parse picture index and gallery index from URL (#&pid=1&gid=2)
105
+    var photoswipeParseHash = function() {
106
+        var hash = window.location.hash.substring(1),
107
+        params = {};
108
+
109
+        if(hash.length < 5) {
110
+            return params;
111
+        }
112
+
113
+        var vars = hash.split('&');
114
+        for (var i = 0; i < vars.length; i++) {
115
+            if(!vars[i]) {
116
+                continue;
117
+            }
118
+            var pair = vars[i].split('=');
119
+            if(pair.length < 2) {
120
+                continue;
121
+            }
122
+            params[pair[0]] = pair[1];
123
+        }
124
+
125
+        if(params.gid) {
126
+            params.gid = parseInt(params.gid, 10);
127
+        }
128
+
129
+        return params;
130
+    };
131
+
132
+    var openPhotoSwipe = function(index, galleryElement, disableAnimation, fromURL) {
133
+        var pswpElement = document.querySelectorAll('.pswp')[0],
134
+            gallery,
135
+            options,
136
+            items;
137
+
138
+
139
+        items = parseThumbnailElements(galleryElement);
140
+
141
+        // define options (if needed)
142
+        options = {
143
+
144
+            // define gallery index (for URL)
145
+            galleryUID: galleryElement.getAttribute('data-pswp-uid'),
146
+
147
+            getThumbBoundsFn: function(index) {
148
+                // See Options -> getThumbBoundsFn section of documentation for more info
149
+                var thumbnail = items[index].el.getElementsByTagName('img')[0], // find thumbnail
150
+                    pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
151
+                    rect = thumbnail.getBoundingClientRect();
152
+
153
+                return {x:rect.left, y:rect.top + pageYScroll, w:rect.width};
154
+            }
155
+
156
+        };
157
+
158
+        // PhotoSwipe opened from URL
159
+        if(fromURL) {
160
+            if(options.galleryPIDs) {
161
+                // parse real index when custom PIDs are used
162
+                // http://photoswipe.com/documentation/faq.html#custom-pid-in-url
163
+                for(var j = 0; j < items.length; j++) {
164
+                    if(items[j].pid == index) {
165
+                        options.index = j;
166
+                        break;
167
+                    }
168
+                }
169
+            } else {
170
+                // in URL indexes start from 1
171
+                options.index = parseInt(index, 10) - 1;
172
+            }
173
+        } else {
174
+            options.index = parseInt(index, 10);
175
+        }
176
+
177
+        // exit if index not found
178
+        if( isNaN(options.index) ) {
179
+            return;
180
+        }
181
+
182
+        if(disableAnimation) {
183
+            options.showAnimationDuration = 0;
184
+        }
185
+
186
+        // Pass data to PhotoSwipe and initialize it
187
+        gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options);
188
+        gallery.init();
189
+    };
190
+
191
+    // loop through all gallery elements and bind events
192
+    var galleryElements = document.querySelectorAll( gallerySelector );
193
+
194
+    for(var i = 0, l = galleryElements.length; i < l; i++) {
195
+        galleryElements[i].setAttribute('data-pswp-uid', i+1);
196
+        galleryElements[i].onclick = onThumbnailsClick;
197
+    }
198
+
199
+    // Parse URL and open gallery if it contains #&pid=3&gid=1
200
+    var hashData = photoswipeParseHash();
201
+    if(hashData.pid && hashData.gid) {
202
+        openPhotoSwipe( hashData.pid ,  galleryElements[ hashData.gid - 1 ], true, true );
203
+    }
204
+  };
205
+</script>

+ 32
- 0
layouts/partials/modules/hall-of-mirrors/meta.html View File

@@ -0,0 +1,32 @@
1
+<meta itemprop="width" content="{{ .Width }}">
2
+<meta itemprop="height" content="{{ .Height }}">
3
+{{ range $property, $value := .Params.meta }}
4
+  {{ if eq $property "keywords" }}
5
+    <meta itemprop="keywords" content="{{ delimit $value ", " }}">
6
+  {{ else if in (slice "creator" "position" "genere" "material" "version" "license") $property }}
7
+    <meta itemprop="{{ $property }}" content="{{ $value }}">
8
+  {{ end }}
9
+{{ end }}
10
+{{ if .Params.meta.format }}
11
+  <meta itemprop="encodingFormat" content="{{ .Params.meta.format }}">
12
+{{ else if eq .ResourceType "image" }}
13
+  {{ if (or (in .RelPermalink ".jpg") (in .RelPermalink ".jpeg")) }}
14
+    <meta itemprop="encodingFormat" content="image/jpeg">
15
+  {{ else if in .RelPermalink ".svg" }}
16
+    <meta itemprop="encodingFormat" content="image/svg+xml">
17
+  {{ else if in .RelPermalink ".webp" }}
18
+    <meta itemprop="encodingFormat" content="image/webp">
19
+  {{ else if in .RelPermalink ".png" }}
20
+    <meta itemprop="encodingFormat" content="image/png">
21
+  {{ else if in .RelPermalink ".gif" }}
22
+    <meta itemprop="encodingFormat" content="image/gif">
23
+  {{ else if in .RelPermalink ".bmp" }}
24
+    <meta itemprop="encodingFormat" content="image/bmp">
25
+  {{ else if in .RelPermalink ".ico" }}
26
+    <meta itemprop="encodingFormat" content="image/x-icon">
27
+  {{ else if (or (in .RelPermalink ".tif") (in .RelPermalink ".tiff")) }}
28
+    <meta itemprop="encodingFormat" content="image/tiff">
29
+  {{ end }}
30
+{{ else if in .RelPermalink ".bpg" }}
31
+  <meta itemprop="encodingFormat" content="https://bellard.org/bpg/">
32
+{{ end }}

+ 66
- 0
layouts/partials/modules/hall-of-mirrors/pswp.html View File

@@ -0,0 +1,66 @@
1
+{{/* Root element of PhotoSwipe. Must have class pswp. */}}
2
+<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
3
+
4
+    {{/* Background of PhotoSwipe.
5
+         It's a separate element as animating opacity is faster than rgba(). */}}
6
+    <div class="pswp__bg"></div>
7
+
8
+    {{/* Slides wrapper with overflow:hidden. */}}
9
+    <div class="pswp__scroll-wrap">
10
+
11
+        {{/* Container that holds slides.
12
+            PhotoSwipe keeps only 3 of them in the DOM to save memory.
13
+            Don't modify these 3 pswp__item elements, data is added later on. */}}
14
+        <div class="pswp__container">
15
+            <div class="pswp__item"></div>
16
+            <div class="pswp__item"></div>
17
+            <div class="pswp__item"></div>
18
+        </div>
19
+
20
+        {{/* Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. */}}
21
+        <div class="pswp__ui pswp__ui--hidden">
22
+
23
+            <div class="pswp__top-bar">
24
+
25
+                {{/*  Controls are self-explanatory. Order can be changed. */}}
26
+
27
+                <div class="pswp__counter"></div>
28
+
29
+                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
30
+
31
+                <button class="pswp__button pswp__button--share" title="Share"></button>
32
+
33
+                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
34
+
35
+                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
36
+
37
+                {{/* Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR */}}
38
+                {{/* element will get class pswp__preloader--active when preloader is running */}}
39
+                <div class="pswp__preloader">
40
+                    <div class="pswp__preloader__icn">
41
+                      <div class="pswp__preloader__cut">
42
+                        <div class="pswp__preloader__donut"></div>
43
+                      </div>
44
+                    </div>
45
+                </div>
46
+            </div>
47
+
48
+            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
49
+                <div class="pswp__share-tooltip"></div>
50
+            </div>
51
+
52
+            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
53
+            </button>
54
+
55
+            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
56
+            </button>
57
+
58
+            <div class="pswp__caption">
59
+                <div class="pswp__caption__center"></div>
60
+            </div>
61
+
62
+        </div>
63
+
64
+    </div>
65
+
66
+</div>

+ 62
- 0
layouts/post/single.html View File

@@ -0,0 +1,62 @@
1
+{{ define "header" }}
2
+  {{ partial "menu.html" . }}
3
+{{ end }}
4
+{{ define "main" }}
5
+  <article itemscope itemtype="http://schema.org/BlogPosting">
6
+    {{ template "_internal/schema.html" . }}
7
+    <header>
8
+      <h1 itemprop="headline">{{ .Title }}</h1>
9
+      <p class="muted">
10
+        {{ partial "post/meta.html" . }}
11
+      </p>
12
+      {{ if .Description }}
13
+        <blockquote itemprop="description">{{ .Description }}</blockquote>
14
+      {{ end }}
15
+      {{ if .Resources.GetMatch "header" }}
16
+        {{ $image600 := (.Resources.GetMatch "header").Fill "600x338 q60 Center" }}
17
+        {{ $image900 := (.Resources.GetMatch "header").Fill "900x506 q70 Center" }}
18
+        {{ $image1200 := (.Resources.GetMatch "header").Fill "1200x675 q80 Center" }}
19
+        {{ $image1600 := (.Resources.GetMatch "header").Fill "1600x900 q90 Center" }}
20
+        <img
21
+          alt=""
22
+          class="lazyload blur-up"
23
+          src="{{ $image600.RelPermalink }}"
24
+          data-sizes="auto"
25
+          data-src="{{ $image1200.RelPermalink }}"
26
+          data-srcset="{{ $image600.RelPermalink }} 600w, {{ $image900.RelPermalink }} 900w, {{ $image1200.RelPermalink }} 1200w, {{ $image1600.RelPermalink }} 1600w"
27
+        >
28
+      {{ end }}
29
+    </header>
30
+
31
+
32
+    {{/* NOTE: BEGIN MODULE CUSTOM */}}
33
+    {{ partial "modules/hall-of-mirrors/gallery.html" . }}
34
+    {{/* NOTE: END MODULE CUSTOM */}}
35
+
36
+
37
+    {{ partial "toc-maybe.html" . }}
38
+    <div itemprop="articleBody">
39
+      {{ .Content }}
40
+    </div>
41
+    {{ if .Site.DisqusShortname }}
42
+      <article>
43
+        {{ template "_internal/disqus.html" . }}
44
+      </article>
45
+    {{ end }}
46
+    <footer>
47
+      <hr>
48
+      {{ partial "post/byline.html" . }}
49
+      {{ partial "post/related-content.html" . }}
50
+    </footer>
51
+  </article>
52
+{{ end }}
53
+{{ define "footer" }}
54
+  {{ partial "powered-by.html" . }}
55
+
56
+
57
+  {{/* NOTE: BEGIN MODULE CUSTOM */}}
58
+  {{ partial "modules/hall-of-mirrors/pswp.html" . }}
59
+  {{/* NOTE: END MODULE CUSTOM */}}
60
+
61
+
62
+{{ end }}

+ 2037
- 0
package-lock.json
File diff suppressed because it is too large
View File


+ 24
- 0
package.json View File

@@ -0,0 +1,24 @@
1
+{
2
+  "name": "hall-of-mirrors",
3
+  "version": "0.1.0",
4
+  "description": "PhotoSwipe Image Gallery for After Dark.",
5
+  "author": "Josh Habdas <jhabdas@protonmail.com>",
6
+  "scripts": {
7
+    "copy:photoswipe": "./bin/copy",
8
+    "clean:css": "npm run clean:css:default-skin && npm run clean:css:photoswipe",
9
+    "clean:css:default-skin": "cleancss -o static/modules/hall-of-mirrors/default-skin.css static/modules/hall-of-mirrors/default-skin.css",
10
+    "clean:css:photoswipe": "cleancss -o static/modules/hall-of-mirrors/photoswipe.css static/modules/hall-of-mirrors/photoswipe.css",
11
+    "test": "while true; do head -n 100 /dev/urandom; sleep 0.1; done | hexdump -C | grep 'ca fe'",
12
+    "update": "npm run copy:photoswipe && ./bin/urlize && npm run clean:css",
13
+    "release": "standard-version"
14
+  },
15
+  "repository": {
16
+    "type": "git",
17
+    "url": "https://git.habd.as/comfusion/hall-of-mirrors.git"
18
+  },
19
+  "devDependencies": {
20
+    "clean-css-cli": "^4.1.11",
21
+    "photoswipe": "^4.1.2"
22
+  },
23
+  "license": "WTFPL"
24
+}

+ 1
- 0
static/modules/hall-of-mirrors/default-skin.css
File diff suppressed because it is too large
View File


BIN
static/modules/hall-of-mirrors/default-skin.png View File


+ 1
- 0
static/modules/hall-of-mirrors/default-skin.svg View File

@@ -0,0 +1 @@
1
+<svg width="264" height="88" viewBox="0 0 264 88" xmlns="http://www.w3.org/2000/svg"><title>default-skin 2</title><g fill="none" fill-rule="evenodd"><g><path d="M67.002 59.5v3.768c-6.307.84-9.184 5.75-10.002 9.732 2.22-2.83 5.564-5.098 10.002-5.098V71.5L73 65.585 67.002 59.5z" id="Shape" fill="#fff"/><g fill="#fff"><path d="M13 29v-5h2v3h3v2h-5zM13 15h5v2h-3v3h-2v-5zM31 15v5h-2v-3h-3v-2h5zM31 29h-5v-2h3v-3h2v5z" id="Shape"/></g><g fill="#fff"><path d="M62 24v5h-2v-3h-3v-2h5zM62 20h-5v-2h3v-3h2v5zM70 20v-5h2v3h3v2h-5zM70 24h5v2h-3v3h-2v-5z"/></g><path d="M20.586 66l-5.656-5.656 1.414-1.414L22 64.586l5.656-5.656 1.414 1.414L23.414 66l5.656 5.656-1.414 1.414L22 67.414l-5.656 5.656-1.414-1.414L20.586 66z" fill="#fff"/><path d="M111.785 65.03L110 63.5l3-3.5h-10v-2h10l-3-3.5 1.785-1.468L117 59l-5.215 6.03z" fill="#fff"/><path d="M152.215 65.03L154 63.5l-3-3.5h10v-2h-10l3-3.5-1.785-1.468L147 59l5.215 6.03z" fill="#fff"/><g><path id="Rectangle-11" fill="#fff" d="M160.957 28.543l-3.25-3.25-1.413 1.414 3.25 3.25z"/><path d="M152.5 27c3.038 0 5.5-2.462 5.5-5.5s-2.462-5.5-5.5-5.5-5.5 2.462-5.5 5.5 2.462 5.5 5.5 5.5z" id="Oval-1" stroke="#fff" stroke-width="1.5"/><path fill="#fff" d="M150 21h5v1h-5z"/></g><g><path d="M116.957 28.543l-1.414 1.414-3.25-3.25 1.414-1.414 3.25 3.25z" fill="#fff"/><path d="M108.5 27c3.038 0 5.5-2.462 5.5-5.5s-2.462-5.5-5.5-5.5-5.5 2.462-5.5 5.5 2.462 5.5 5.5 5.5z" stroke="#fff" stroke-width="1.5"/><path fill="#fff" d="M106 21h5v1h-5z"/><path fill="#fff" d="M109.043 19.008l-.085 5-1-.017.085-5z"/></g></g></g></svg>

+ 4
- 0
static/modules/hall-of-mirrors/photoswipe-ui-default.min.js
File diff suppressed because it is too large
View File


+ 1
- 0
static/modules/hall-of-mirrors/photoswipe.css View File

@@ -0,0 +1 @@
1
+/*! PhotoSwipe main CSS by Dmitry Semenov | photoswipe.com | MIT license */.pswp{display:none;position:absolute;width:100%;height:100%;left:0;top:0;overflow:hidden;-ms-touch-action:none;touch-action:none;z-index:1500;-webkit-text-size-adjust:100%;-webkit-backface-visibility:hidden;outline:0}.pswp *{-webkit-box-sizing:border-box;box-sizing:border-box}.pswp img{max-width:none}.pswp--animate_opacity{opacity:.001;will-change:opacity;-webkit-transition:opacity 333ms cubic-bezier(.4,0,.22,1);transition:opacity 333ms cubic-bezier(.4,0,.22,1)}.pswp--open{display:block}.pswp--zoom-allowed .pswp__img{cursor:-webkit-zoom-in;cursor:-moz-zoom-in;cursor:zoom-in}.pswp--zoomed-in .pswp__img{cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.pswp--dragging .pswp__img{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.pswp__bg{position:absolute;left:0;top:0;width:100%;height:100%;background:#000;opacity:0;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-backface-visibility:hidden;will-change:opacity}.pswp__scroll-wrap{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden}.pswp__container,.pswp__zoom-wrap{-ms-touch-action:none;touch-action:none;position:absolute;left:0;right:0;top:0;bottom:0}.pswp__container,.pswp__img{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.pswp__zoom-wrap{position:absolute;width:100%;-webkit-transform-origin:left top;-ms-transform-origin:left top;transform-origin:left top;-webkit-transition:-webkit-transform 333ms cubic-bezier(.4,0,.22,1);transition:transform 333ms cubic-bezier(.4,0,.22,1)}.pswp__bg{will-change:opacity;-webkit-transition:opacity 333ms cubic-bezier(.4,0,.22,1);transition:opacity 333ms cubic-bezier(.4,0,.22,1)}.pswp--animated-in .pswp__bg,.pswp--animated-in .pswp__zoom-wrap{-webkit-transition:none;transition:none}.pswp__container,.pswp__zoom-wrap{-webkit-backface-visibility:hidden}.pswp__item{position:absolute;left:0;right:0;top:0;bottom:0;overflow:hidden}.pswp__img{position:absolute;width:auto;height:auto;top:0;left:0}.pswp__img--placeholder{-webkit-backface-visibility:hidden}.pswp__img--placeholder--blank{background:#222}.pswp--ie .pswp__img{width:100%!important;height:auto!important;left:0;top:0}.pswp__error-msg{position:absolute;left:0;top:50%;width:100%;text-align:center;font-size:14px;line-height:16px;margin-top:-8px;color:#ccc}.pswp__error-msg a{color:#ccc;text-decoration:underline}

+ 4
- 0
static/modules/hall-of-mirrors/photoswipe.min.js
File diff suppressed because it is too large
View File


BIN
static/modules/hall-of-mirrors/preloader.gif View File


Loading…
Cancel
Save