@ -0,0 +1,13 @@ | |||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |||
Version 2, December 2004 | |||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> | |||
Everyone is permitted to copy and distribute verbatim or modified | |||
copies of this license document, and changing it is allowed as long | |||
as the name is changed. | |||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |||
0. You just DO WHAT THE FUCK YOU WANT TO. |
@ -0,0 +1,107 @@ | |||
# Hall of Mirrors | |||
> PhotoSwipe Image Gallery for [After Dark]. Hall of Mirrors adds a responsive JavaScript image gallery using [PhotoSwipe](http://photoswipe.com). | |||
[](https://www.npmjs.com/package/hall-of-mirrors) | |||
[](https://www.npmjs.com/package/hall-of-mirrors) | |||
[](https://git.habd.as/comfusion/after-dark/) | |||
[](https://git.habd.as/comfusion/hall-of-mirrors/src/branch/master/COPYING) | |||
## Setup | |||
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. | |||
## Installation | |||
1. Copy the contents of this repository into a directory called `themes/hall-of-mirrors` under the root of your After Dark site. | |||
2. Add `hall-of-mirrors` as a [theme component](https://gohugo.io/themes/theme-components/) to your After Dark site `config.toml`, e.g. | |||
```toml | |||
theme = [ | |||
"hall-of-mirrors", | |||
"after-dark" | |||
] | |||
``` | |||
3. Add and specify settings for the module in your After Dark site config, e.g. | |||
```toml | |||
[params.modules.fractal_forest] | |||
enabled = true # Required in version 1.0 | |||
``` | |||
4. Create a [Leaf Bundle] to group image resources you wish to display in a PhotoSwipe gallery together with your content. | |||
5. [Configure the gallery](#configuration) to your liking. | |||
6. Build and deploy your After Dark site. | |||
## Configuration | |||
To display a gallery add the [Page Resources] you wish to display to your [Leaf Bundle] and configure your front matter. | |||
### Minimal | |||
The following is all you need to display a basic gallery. Seriously. | |||
```toml | |||
[[resources]] | |||
src = "**.jpg" # Display any jpeg image in the leaf bundle | |||
name = "gallery" # Name must include the word 'gallery' | |||
``` | |||
```toml | |||
[[resources]] | |||
src = "images/gallery/**.jpg" # Restrict images to a folder | |||
name = "Image gallery" # Provide a more friendly gallery name | |||
``` | |||
### Extended | |||
If you want to add captions and enhance SEO you can configure individual resources. | |||
```toml | |||
[[resources]] | |||
src = "**/ray-hennessy-763310-unsplash.jpg" | |||
[resources.params] | |||
thumb_size = "750x" # Adjust size of thumbnail image | |||
[resources.params.meta] | |||
creator = "Ray Hennessy" | |||
description = "This is a long description. It is shown instead of the title and is intended to provide more information." | |||
[[resources]] | |||
src = "**sprat**" # Glob for image with 'sprat' in the filename | |||
title = "Diverse succulents around a rock" | |||
[resources.params] | |||
hide_credits = true # Display title but not creator | |||
[resources.params.meta] | |||
creator = "Annie Spratt" # Maps to schema structured data | |||
[[resources]] | |||
src = "**/blake-richard-verdoorn-20063-unsplash.jpg" | |||
title = "Bridge over a green waterfall" | |||
[resources.params] | |||
hide_credits = true | |||
thumb_size = "350x" | |||
[resources.params.meta] | |||
creator = "Blake Richard Verdoorn" | |||
keywords = ["nature", "waterfall", "bridge"] | |||
[[resources]] | |||
src = "images/gallery/**.jpg" | |||
name = "Nature gallery" | |||
[resources.params.meta] | |||
genere = "digital" # Set a genere for all image resources | |||
``` | |||
This should get you started. Expect some breaking changes as the development is completed. | |||
## License | |||
Copyright (C) 2018 Josh Habdas <jhabdas@protonmail.com> | |||
This work is free. You can redistribute it and/or modify it under the | |||
terms of the Do What The Fuck You Want To Public License, Version 2, | |||
as published by Sam Hocevar. See the COPYING file for more details. | |||
[After Dark]: https://git.habd.as/comfusion/after-dark/ | |||
[Leaf Bundle]: https://gohugo.io/content-management/page-bundles/#leaf-bundles | |||
[Page Resources]: https://gohugo.io/content-management/page-resources/ |
@ -0,0 +1,27 @@ | |||
#!/bin/bash | |||
set -e | |||
ASSETS_DIR=node_modules/photoswipe/dist | |||
TARGET_DIR=static/modules/hall-of-mirrors | |||
# Print error to stdout and exit 1 if asset directories cannot be found | |||
if ! [ -d "$ASSETS_DIR" ] || [ -d "$ASSETS_DIR"/default-skins ] ; then | |||
echo "Error: Photoswipe assets not found in $PWD/$ASSETS_DIR." >&2; exit 1 | |||
fi | |||
# Create target directory if not exists | |||
mkdir -p "$TARGET_DIR" | |||
# Define required assets | |||
files=( | |||
"$ASSETS_DIR"/*.min.js | |||
"$ASSETS_DIR"/*.css | |||
"$ASSETS_DIR"/**/* | |||
) | |||
# printf '%s\n' "${files[@]}" # e.g. path/to/source/filename.tar.gz | |||
# printf '%s\n' "${files[@]##*/}" # e.g. filename.tgz | |||
# Copy required assets to target directory | |||
for file in "${files[@]}" ; do | |||
cp "$file" "$TARGET_DIR" | |||
done |
@ -0,0 +1,14 @@ | |||
#!/bin/sh | |||
set -e | |||
SKIN_CSS_FILE=static/modules/hall-of-mirrors/default-skin.css | |||
BASE_URL=/modules/hall-of-mirrors/ | |||
# Print error and exit 1 file not found | |||
if ! [ -f "$SKIN_CSS_FILE" ] ; then | |||
echo "Error: Asset not found in $PWD/$SKIN_CSS_FILE." >&2; exit 1 | |||
fi | |||
# Prefix filenames in url data types with baseurl | |||
# Note: Assumes file is not minified | |||
sed "s@url(\(.*\))@url($BASE_URL\1)@g" "$SKIN_CSS_FILE" | tee "$SKIN_CSS_FILE" >/dev/null |
@ -0,0 +1,23 @@ | |||
<div itemscope itemtype="http://schema.org/ImageGallery"> | |||
{{ range .Resources.Match "*gallery*" }} | |||
{{ $thumbnail := .Resize (default "500x" (index .Params "thumb_size")) }} | |||
<figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject"> | |||
<a data-size="{{ .Width }}x{{ .Height }}" href="{{ .RelPermalink }}" itemprop="contentUrl"> | |||
<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 }}"> | |||
</a> | |||
{{ partial "modules/hall-of-mirrors/meta.html" . }} | |||
<figcaption itemprop="caption description"> | |||
{{ if .Params.meta.description }} | |||
{{ .Params.meta.description }} | |||
{{ else if ne (in .RelPermalink .Title) true }} | |||
<span itemprop="name">{{ .Title }}</span> | |||
{{ end }} | |||
{{ if ne .Params.hide_credits true }} | |||
{{ with .Params.meta.creator }} | |||
<span>Photo by {{ . }}</span> | |||
{{ end }} | |||
{{ end }} | |||
</figcaption> | |||
</figure> | |||
{{ end }} | |||
</div> |
@ -0,0 +1,22 @@ | |||
{{ if and (ne .settings.enabled false) }} | |||
<meta title="mod:hall-of-mirrors" content="status:enabled"> | |||
{{ if .page.Resources.GetMatch "*gallery*"}} | |||
{{ partial "modules/hall-of-mirrors/inline.js.html" }} | |||
{{ partial "modules/hall-of-mirrors/inline.css.html" }} | |||
<script> | |||
/*! Fetch Inject v2.0.2 | Copyright (C) 2017–2018 Josh Habdas <jhabdas@protonmail.com> | @license Zlib */ | |||
!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)))}}); | |||
fetchInject([ | |||
{{ "modules/hall-of-mirrors/photoswipe.css" | relURL }}, | |||
{{ "modules/hall-of-mirrors/default-skin.css" | relURL }}, | |||
{{ "modules/hall-of-mirrors/photoswipe.min.js" | relURL }}, | |||
{{ "modules/hall-of-mirrors/photoswipe-ui-default.min.js" | relURL }} | |||
]).then(() => { | |||
initPhotoSwipeFromDOM('[itemtype="http://schema.org/ImageGallery"]') | |||
}) | |||
</script> | |||
{{ end }} | |||
{{ else }} | |||
<meta title="mod:hall-of-mirrors" content="status:disabled"> | |||
{{ end }} |
@ -0,0 +1,27 @@ | |||
<style> | |||
[itemtype="http://schema.org/ImageGallery"] { | |||
display: flex; | |||
flex-direction: row; | |||
justify-content: center; | |||
align-items: center; | |||
flex-wrap: wrap; | |||
} | |||
[itemtype="http://schema.org/ImageGallery"] figure { | |||
text-align: center; | |||
} | |||
[itemtype="http://schema.org/ImageGallery"] figure a { | |||
border-bottom: none; | |||
} | |||
[itemtype="http://schema.org/ImageGallery"] figure a:hover { | |||
background-color: inherit; | |||
} | |||
[itemtype="http://schema.org/ImageGallery"] figure img { | |||
transition: all .2s ease-in-out; | |||
} | |||
[itemtype="http://schema.org/ImageGallery"] figure img:hover { | |||
transform: scale(1.025); | |||
} | |||
[itemprop="caption description"] { | |||
font-size: small; | |||
} | |||
</style> |
@ -0,0 +1,205 @@ | |||
<script> | |||
var initPhotoSwipeFromDOM = function(gallerySelector) { | |||
// parse slide data (url, title, size ...) from DOM elements | |||
// (children of gallerySelector) | |||
var parseThumbnailElements = function(el) { | |||
var thumbElements = el.childNodes, | |||
numNodes = thumbElements.length, | |||
items = [], | |||
figureEl, | |||
linkEl, | |||
size, | |||
item; | |||
for(var i = 0; i < numNodes; i++) { | |||
figureEl = thumbElements[i]; // <figure> element | |||
// include only element nodes | |||
if(figureEl.nodeType !== 1) { | |||
continue; | |||
} | |||
linkEl = figureEl.children[0]; // <a> element | |||
size = linkEl.getAttribute('data-size').split('x'); | |||
// create slide object | |||
item = { | |||
src: linkEl.getAttribute('href'), | |||
w: parseInt(size[0], 10), | |||
h: parseInt(size[1], 10) | |||
}; | |||
if(figureEl.children.length > 1) { | |||
// <figcaption> content | |||
item.title = figureEl.children[1].innerHTML; | |||
} | |||
if(linkEl.children.length > 0) { | |||
// <img> thumbnail element, retrieving thumbnail url | |||
item.msrc = linkEl.children[0].getAttribute('src'); | |||
} | |||
item.el = figureEl; // save link to element for getThumbBoundsFn | |||
items.push(item); | |||
} | |||
return items; | |||
}; | |||
// find nearest parent element | |||
var closest = function closest(el, fn) { | |||
return el && ( fn(el) ? el : closest(el.parentNode, fn) ); | |||
}; | |||
// triggers when user clicks on thumbnail | |||
var onThumbnailsClick = function(e) { | |||
e = e || window.event; | |||
e.preventDefault ? e.preventDefault() : e.returnValue = false; | |||
var eTarget = e.target || e.srcElement; | |||
// find root element of slide | |||
var clickedListItem = closest(eTarget, function(el) { | |||
return (el.tagName && el.tagName.toUpperCase() === 'FIGURE'); | |||
}); | |||
if(!clickedListItem) { | |||
return; | |||
} | |||
// find index of clicked item by looping through all child nodes | |||
// alternatively, you may define index via data- attribute | |||
var clickedGallery = clickedListItem.parentNode, | |||
childNodes = clickedListItem.parentNode.childNodes, | |||
numChildNodes = childNodes.length, | |||
nodeIndex = 0, | |||
index; | |||
for (var i = 0; i < numChildNodes; i++) { | |||
if(childNodes[i].nodeType !== 1) { | |||
continue; | |||
} | |||
if(childNodes[i] === clickedListItem) { | |||
index = nodeIndex; | |||
break; | |||
} | |||
nodeIndex++; | |||
} | |||
if(index >= 0) { | |||
// open PhotoSwipe if valid index found | |||
openPhotoSwipe( index, clickedGallery ); | |||
} | |||
return false; | |||
}; | |||
// parse picture index and gallery index from URL (#&pid=1&gid=2) | |||
var photoswipeParseHash = function() { | |||
var hash = window.location.hash.substring(1), | |||
params = {}; | |||
if(hash.length < 5) { | |||
return params; | |||
} | |||
var vars = hash.split('&'); | |||
for (var i = 0; i < vars.length; i++) { | |||
if(!vars[i]) { | |||
continue; | |||
} | |||
var pair = vars[i].split('='); | |||
if(pair.length < 2) { | |||
continue; | |||
} | |||
params[pair[0]] = pair[1]; | |||
} | |||
if(params.gid) { | |||
params.gid = parseInt(params.gid, 10); | |||
} | |||
return params; | |||
}; | |||
var openPhotoSwipe = function(index, galleryElement, disableAnimation, fromURL) { | |||
var pswpElement = document.querySelectorAll('.pswp')[0], | |||
gallery, | |||
options, | |||
items; | |||
items = parseThumbnailElements(galleryElement); | |||
// define options (if needed) | |||
options = { | |||
// define gallery index (for URL) | |||
galleryUID: galleryElement.getAttribute('data-pswp-uid'), | |||
getThumbBoundsFn: function(index) { | |||
// See Options -> getThumbBoundsFn section of documentation for more info | |||
var thumbnail = items[index].el.getElementsByTagName('img')[0], // find thumbnail | |||
pageYScroll = window.pageYOffset || document.documentElement.scrollTop, | |||
rect = thumbnail.getBoundingClientRect(); | |||
return {x:rect.left, y:rect.top + pageYScroll, w:rect.width}; | |||
} | |||
}; | |||
// PhotoSwipe opened from URL | |||
if(fromURL) { | |||
if(options.galleryPIDs) { | |||
// parse real index when custom PIDs are used | |||
// http://photoswipe.com/documentation/faq.html#custom-pid-in-url | |||
for(var j = 0; j < items.length; j++) { | |||
if(items[j].pid == index) { | |||
options.index = j; | |||
break; | |||
} | |||
} | |||
} else { | |||
// in URL indexes start from 1 | |||
options.index = parseInt(index, 10) - 1; | |||
} | |||
} else { | |||
options.index = parseInt(index, 10); | |||
} | |||
// exit if index not found | |||
if( isNaN(options.index) ) { | |||
return; | |||
} | |||
if(disableAnimation) { | |||
options.showAnimationDuration = 0; | |||
} | |||
// Pass data to PhotoSwipe and initialize it | |||
gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options); | |||
gallery.init(); | |||
}; | |||
// loop through all gallery elements and bind events | |||
var galleryElements = document.querySelectorAll( gallerySelector ); | |||
for(var i = 0, l = galleryElements.length; i < l; i++) { | |||
galleryElements[i].setAttribute('data-pswp-uid', i+1); | |||
galleryElements[i].onclick = onThumbnailsClick; | |||
} | |||
// Parse URL and open gallery if it contains #&pid=3&gid=1 | |||
var hashData = photoswipeParseHash(); | |||
if(hashData.pid && hashData.gid) { | |||
openPhotoSwipe( hashData.pid , galleryElements[ hashData.gid - 1 ], true, true ); | |||
} | |||
}; | |||
</script> |
@ -0,0 +1,32 @@ | |||
<meta itemprop="width" content="{{ .Width }}"> | |||
<meta itemprop="height" content="{{ .Height }}"> | |||
{{ range $property, $value := .Params.meta }} | |||
{{ if eq $property "keywords" }} | |||
<meta itemprop="keywords" content="{{ delimit $value ", " }}"> | |||
{{ else if in (slice "creator" "position" "genere" "material" "version" "license") $property }} | |||
<meta itemprop="{{ $property }}" content="{{ $value }}"> | |||
{{ end }} | |||
{{ end }} | |||
{{ if .Params.meta.format }} | |||
<meta itemprop="encodingFormat" content="{{ .Params.meta.format }}"> | |||
{{ else if eq .ResourceType "image" }} | |||
{{ if (or (in .RelPermalink ".jpg") (in .RelPermalink ".jpeg")) }} | |||
<meta itemprop="encodingFormat" content="image/jpeg"> | |||
{{ else if in .RelPermalink ".svg" }} | |||
<meta itemprop="encodingFormat" content="image/svg+xml"> | |||
{{ else if in .RelPermalink ".webp" }} | |||
<meta itemprop="encodingFormat" content="image/webp"> | |||
{{ else if in .RelPermalink ".png" }} | |||
<meta itemprop="encodingFormat" content="image/png"> | |||
{{ else if in .RelPermalink ".gif" }} | |||
<meta itemprop="encodingFormat" content="image/gif"> | |||
{{ else if in .RelPermalink ".bmp" }} | |||
<meta itemprop="encodingFormat" content="image/bmp"> | |||
{{ else if in .RelPermalink ".ico" }} | |||
<meta itemprop="encodingFormat" content="image/x-icon"> | |||
{{ else if (or (in .RelPermalink ".tif") (in .RelPermalink ".tiff")) }} | |||
<meta itemprop="encodingFormat" content="image/tiff"> | |||
{{ end }} | |||
{{ else if in .RelPermalink ".bpg" }} | |||
<meta itemprop="encodingFormat" content="https://bellard.org/bpg/"> | |||
{{ end }} |
@ -0,0 +1,66 @@ | |||
{{/* Root element of PhotoSwipe. Must have class pswp. */}} | |||
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true"> | |||
{{/* Background of PhotoSwipe. | |||
It's a separate element as animating opacity is faster than rgba(). */}} | |||
<div class="pswp__bg"></div> | |||
{{/* Slides wrapper with overflow:hidden. */}} | |||
<div class="pswp__scroll-wrap"> | |||
{{/* Container that holds slides. | |||
PhotoSwipe keeps only 3 of them in the DOM to save memory. | |||
Don't modify these 3 pswp__item elements, data is added later on. */}} | |||
<div class="pswp__container"> | |||
<div class="pswp__item"></div> | |||
<div class="pswp__item"></div> | |||
<div class="pswp__item"></div> | |||
</div> | |||
{{/* Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. */}} | |||
<div class="pswp__ui pswp__ui--hidden"> | |||
<div class="pswp__top-bar"> | |||
{{/* Controls are self-explanatory. Order can be changed. */}} | |||
<div class="pswp__counter"></div> | |||
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button> | |||
<button class="pswp__button pswp__button--share" title="Share"></button> | |||
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button> | |||
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button> | |||
{{/* Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR */}} | |||
{{/* element will get class pswp__preloader--active when preloader is running */}} | |||
<div class="pswp__preloader"> | |||
<div class="pswp__preloader__icn"> | |||
<div class="pswp__preloader__cut"> | |||
<div class="pswp__preloader__donut"></div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap"> | |||
<div class="pswp__share-tooltip"></div> | |||
</div> | |||
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)"> | |||
</button> | |||
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)"> | |||
</button> | |||
<div class="pswp__caption"> | |||
<div class="pswp__caption__center"></div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |
@ -0,0 +1,62 @@ | |||
{{ define "header" }} | |||
{{ partial "menu.html" . }} | |||
{{ end }} | |||
{{ define "main" }} | |||
<article itemscope itemtype="http://schema.org/BlogPosting"> | |||
{{ template "_internal/schema.html" . }} | |||
<header> | |||
<h1 itemprop="headline">{{ .Title }}</h1> | |||
<p class="muted"> | |||
{{ partial "post/meta.html" . }} | |||
</p> | |||
{{ if .Description }} | |||
<blockquote itemprop="description">{{ .Description }}</blockquote> | |||
{{ end }} | |||
{{ if .Resources.GetMatch "header" }} | |||
{{ $image600 := (.Resources.GetMatch "header").Fill "600x338 q60 Center" }} | |||
{{ $image900 := (.Resources.GetMatch "header").Fill "900x506 q70 Center" }} | |||
{{ $image1200 := (.Resources.GetMatch "header").Fill "1200x675 q80 Center" }} | |||
{{ $image1600 := (.Resources.GetMatch "header").Fill "1600x900 q90 Center" }} | |||
<img | |||
alt="" | |||
class="lazyload blur-up" | |||
src="{{ $image600.RelPermalink }}" | |||
data-sizes="auto" | |||
data-src="{{ $image1200.RelPermalink }}" | |||
data-srcset="{{ $image600.RelPermalink }} 600w, {{ $image900.RelPermalink }} 900w, {{ $image1200.RelPermalink }} 1200w, {{ $image1600.RelPermalink }} 1600w" | |||
> | |||
{{ end }} | |||
</header> | |||
{{/* NOTE: BEGIN MODULE CUSTOM */}} | |||
{{ partial "modules/hall-of-mirrors/gallery.html" . }} | |||
{{/* NOTE: END MODULE CUSTOM */}} | |||
{{ partial "toc-maybe.html" . }} | |||
<div itemprop="articleBody"> | |||
{{ .Content }} | |||
</div> | |||
{{ if .Site.DisqusShortname }} | |||
<article> | |||
{{ template "_internal/disqus.html" . }} | |||
</article> | |||
{{ end }} | |||
<footer> | |||
<hr> | |||
{{ partial "post/byline.html" . }} | |||
{{ partial "post/related-content.html" . }} | |||
</footer> | |||
</article> | |||
{{ end }} | |||
{{ define "footer" }} | |||
{{ partial "powered-by.html" . }} | |||
{{/* NOTE: BEGIN MODULE CUSTOM */}} | |||
{{ partial "modules/hall-of-mirrors/pswp.html" . }} | |||
{{/* NOTE: END MODULE CUSTOM */}} | |||
{{ end }} |
@ -0,0 +1,24 @@ | |||
{ | |||
"name": "hall-of-mirrors", | |||
"version": "0.1.0", | |||
"description": "PhotoSwipe Image Gallery for After Dark.", | |||
"author": "Josh Habdas <jhabdas@protonmail.com>", | |||
"scripts": { | |||
"copy:photoswipe": "./bin/copy", | |||
"clean:css": "npm run clean:css:default-skin && npm run clean:css:photoswipe", | |||
"clean:css:default-skin": "cleancss -o static/modules/hall-of-mirrors/default-skin.css static/modules/hall-of-mirrors/default-skin.css", | |||
"clean:css:photoswipe": "cleancss -o static/modules/hall-of-mirrors/photoswipe.css static/modules/hall-of-mirrors/photoswipe.css", | |||
"test": "while true; do head -n 100 /dev/urandom; sleep 0.1; done | hexdump -C | grep 'ca fe'", | |||
"update": "npm run copy:photoswipe && ./bin/urlize && npm run clean:css", | |||
"release": "standard-version" | |||
}, | |||
"repository": { | |||
"type": "git", | |||
"url": "https://git.habd.as/comfusion/hall-of-mirrors.git" | |||
}, | |||
"devDependencies": { | |||
"clean-css-cli": "^4.1.11", | |||
"photoswipe": "^4.1.2" | |||
}, | |||
"license": "WTFPL" | |||
} |
@ -0,0 +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> |
@ -0,0 +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} |