initial commit
This commit is contained in:
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.JPG filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
||||||
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.hugo_build.lock
|
||||||
|
public/
|
||||||
|
resources/_gen/
|
||||||
|
assets/jsconfig.json
|
||||||
|
hugo_stats.json
|
||||||
|
result
|
||||||
|
.direnv
|
||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "themes/gallery"]
|
||||||
|
path = themes/gallery
|
||||||
|
url = https://github.com/nicokaiser/hugo-theme-gallery.git
|
||||||
16
Makefile
Normal file
16
Makefile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
.PHONY: build exif_clean dev clean deploy
|
||||||
|
|
||||||
|
build: exif_clean
|
||||||
|
nix build '.?submodules=1#default'
|
||||||
|
|
||||||
|
exif_clean:
|
||||||
|
exiftool -r -overwrite_original -all= -tagsFromFile @ -Orientation -Canon -AllDates content/
|
||||||
|
|
||||||
|
dev:
|
||||||
|
hugo server
|
||||||
|
|
||||||
|
clean:
|
||||||
|
git clean -fdX
|
||||||
|
|
||||||
|
deploy: build
|
||||||
|
rsync -e 'ssh -J root@100.64.0.1' -cdr --progress --delete-after result/ root@100.64.0.3:/var/www/website
|
||||||
5
archetypes/default.md
Normal file
5
archetypes/default.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
+++
|
||||||
|
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
|
||||||
|
date = {{ .Date }}
|
||||||
|
draft = true
|
||||||
|
+++
|
||||||
0
content/_index.md
Normal file
0
content/_index.md
Normal file
BIN
content/gallery/CSI_2374.jpg
LFS
Normal file
BIN
content/gallery/CSI_2374.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/CSI_2390.jpg
LFS
Normal file
BIN
content/gallery/CSI_2390.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/CSI_3503.jpg
LFS
Normal file
BIN
content/gallery/CSI_3503.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/DSC00493.JPG
LFS
Normal file
BIN
content/gallery/DSC00493.JPG
LFS
Normal file
Binary file not shown.
BIN
content/gallery/DSC00495.JPG
LFS
Normal file
BIN
content/gallery/DSC00495.JPG
LFS
Normal file
Binary file not shown.
BIN
content/gallery/DSC00496.JPG
LFS
Normal file
BIN
content/gallery/DSC00496.JPG
LFS
Normal file
Binary file not shown.
BIN
content/gallery/DSC00497_1.JPG
LFS
Normal file
BIN
content/gallery/DSC00497_1.JPG
LFS
Normal file
Binary file not shown.
BIN
content/gallery/DSC04106.jpeg
LFS
Normal file
BIN
content/gallery/DSC04106.jpeg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/DSC04158.jpeg
LFS
Normal file
BIN
content/gallery/DSC04158.jpeg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/DSC04198.jpeg
LFS
Normal file
BIN
content/gallery/DSC04198.jpeg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/DSC04213.jpeg
LFS
Normal file
BIN
content/gallery/DSC04213.jpeg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0374.jpg
LFS
Normal file
BIN
content/gallery/IMG_0374.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0378.jpg
LFS
Normal file
BIN
content/gallery/IMG_0378.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0380.jpg
LFS
Normal file
BIN
content/gallery/IMG_0380.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0402.jpg
LFS
Normal file
BIN
content/gallery/IMG_0402.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0419.jpg
LFS
Normal file
BIN
content/gallery/IMG_0419.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0449.jpg
LFS
Normal file
BIN
content/gallery/IMG_0449.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0646.jpg
LFS
Normal file
BIN
content/gallery/IMG_0646.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0668.jpg
LFS
Normal file
BIN
content/gallery/IMG_0668.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0678.jpg
LFS
Normal file
BIN
content/gallery/IMG_0678.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0686.jpg
LFS
Normal file
BIN
content/gallery/IMG_0686.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0691.jpg
LFS
Normal file
BIN
content/gallery/IMG_0691.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0692.jpg
LFS
Normal file
BIN
content/gallery/IMG_0692.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0695.jpg
LFS
Normal file
BIN
content/gallery/IMG_0695.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_0979.jpg
LFS
Normal file
BIN
content/gallery/IMG_0979.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1035.jpg
LFS
Normal file
BIN
content/gallery/IMG_1035.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1042.jpg
LFS
Normal file
BIN
content/gallery/IMG_1042.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1088.jpg
LFS
Normal file
BIN
content/gallery/IMG_1088.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1584.jpg
LFS
Normal file
BIN
content/gallery/IMG_1584.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1818.jpg
LFS
Normal file
BIN
content/gallery/IMG_1818.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1828.jpg
LFS
Normal file
BIN
content/gallery/IMG_1828.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1832.jpg
LFS
Normal file
BIN
content/gallery/IMG_1832.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1833.jpg
LFS
Normal file
BIN
content/gallery/IMG_1833.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1834.jpg
LFS
Normal file
BIN
content/gallery/IMG_1834.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1929.jpg
LFS
Normal file
BIN
content/gallery/IMG_1929.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1930.jpg
LFS
Normal file
BIN
content/gallery/IMG_1930.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1939.jpg
LFS
Normal file
BIN
content/gallery/IMG_1939.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_1994.jpg
LFS
Normal file
BIN
content/gallery/IMG_1994.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_2013.jpg
LFS
Normal file
BIN
content/gallery/IMG_2013.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_2027.jpg
LFS
Normal file
BIN
content/gallery/IMG_2027.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_2152.jpg
LFS
Normal file
BIN
content/gallery/IMG_2152.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_2397.jpg
LFS
Normal file
BIN
content/gallery/IMG_2397.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_2567.jpg
LFS
Normal file
BIN
content/gallery/IMG_2567.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_3311.jpg
LFS
Normal file
BIN
content/gallery/IMG_3311.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_3426.jpg
LFS
Normal file
BIN
content/gallery/IMG_3426.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8499.JPG
LFS
Normal file
BIN
content/gallery/IMG_8499.JPG
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8510.JPG
LFS
Normal file
BIN
content/gallery/IMG_8510.JPG
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8511.JPG
LFS
Normal file
BIN
content/gallery/IMG_8511.JPG
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8515.JPG
LFS
Normal file
BIN
content/gallery/IMG_8515.JPG
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8538.jpg
LFS
Normal file
BIN
content/gallery/IMG_8538.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8559.jpg
LFS
Normal file
BIN
content/gallery/IMG_8559.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8565.jpg
LFS
Normal file
BIN
content/gallery/IMG_8565.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8591.jpg
LFS
Normal file
BIN
content/gallery/IMG_8591.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8592.jpg
LFS
Normal file
BIN
content/gallery/IMG_8592.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8600.jpg
LFS
Normal file
BIN
content/gallery/IMG_8600.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8611.jpg
LFS
Normal file
BIN
content/gallery/IMG_8611.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8632.jpg
LFS
Normal file
BIN
content/gallery/IMG_8632.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8634.jpg
LFS
Normal file
BIN
content/gallery/IMG_8634.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8708.jpg
LFS
Normal file
BIN
content/gallery/IMG_8708.jpg
LFS
Normal file
Binary file not shown.
BIN
content/gallery/IMG_8715.jpg
LFS
Normal file
BIN
content/gallery/IMG_8715.jpg
LFS
Normal file
Binary file not shown.
7
content/gallery/index.md
Normal file
7
content/gallery/index.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
sort_by: Date # Exif.Date
|
||||||
|
sort_order: desc
|
||||||
|
#type: gallery
|
||||||
|
params:
|
||||||
|
theme: dark
|
||||||
|
---
|
||||||
26
flake.lock
generated
Normal file
26
flake.lock
generated
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731245184,
|
||||||
|
"narHash": "sha256-vmLS8+x+gHRv1yzj3n+GTAEObwmhxmkkukB2DwtJRdU=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "aebe249544837ce42588aa4b2e7972222ba12e8f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
34
flake.nix
Normal file
34
flake.nix
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
description = "Rixxc's Personal Website and Blog";
|
||||||
|
|
||||||
|
inputs.nixpkgs.url = "nixpkgs/nixpkgs-unstable";
|
||||||
|
|
||||||
|
outputs = { nixpkgs, ... }:
|
||||||
|
let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
in
|
||||||
|
with pkgs;
|
||||||
|
{
|
||||||
|
packages.${system}.default = stdenv.mkDerivation
|
||||||
|
{
|
||||||
|
name = "Personal Website";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
hugo
|
||||||
|
rsync
|
||||||
|
exiftool
|
||||||
|
];
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
hugo
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir $out
|
||||||
|
cp -r public/* $out/
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
9
hugo.toml
Normal file
9
hugo.toml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
baseURL = 'https://photo.rixxc.de/'
|
||||||
|
languageCode = 'en-us'
|
||||||
|
#title = 'My New Hugo Site'
|
||||||
|
theme = 'gallery'
|
||||||
|
timeout = '120s'
|
||||||
|
defaultTheme = 'dark'
|
||||||
|
|
||||||
|
[params]
|
||||||
|
defaultTheme = 'dark'
|
||||||
3
themes/gallery/.github/FUNDING.yml
vendored
Normal file
3
themes/gallery/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
github: nicokaiser
|
||||||
|
ko_fi: nicokaiser
|
||||||
|
liberapay: nicokaiser
|
||||||
62
themes/gallery/.github/workflows/hugo.yml
vendored
Normal file
62
themes/gallery/.github/workflows/hugo.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
name: Deploy to Pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: "pages"
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
HUGO_VERSION: 0.124.0
|
||||||
|
steps:
|
||||||
|
- name: Install Hugo
|
||||||
|
run: |
|
||||||
|
wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
|
||||||
|
&& sudo dpkg -i ${{ runner.temp }}/hugo.deb
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Cache example images
|
||||||
|
id: cache-images
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ./exampleSite/content
|
||||||
|
key: images-${{ hashFiles('exampleSite/content/**') }}
|
||||||
|
- name: Download example images
|
||||||
|
if: steps.cache-images.outputs.cache-hit != 'true'
|
||||||
|
working-directory: ./exampleSite
|
||||||
|
run: ./pull-images.sh
|
||||||
|
- name: Setup Pages
|
||||||
|
id: pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
- name: Build with Hugo
|
||||||
|
working-directory: ./exampleSite
|
||||||
|
env:
|
||||||
|
HUGO_ENVIRONMENT: production
|
||||||
|
HUGO_ENV: production
|
||||||
|
run: hugo --gc --minify --baseURL "${{ steps.pages.outputs.base_url }}/"
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ./exampleSite/public
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
4
themes/gallery/.gitignore
vendored
Normal file
4
themes/gallery/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
.hugo_build.lock
|
||||||
|
exampleSite/assets/jsconfig.json
|
||||||
6
themes/gallery/.prettierignore
Normal file
6
themes/gallery/.prettierignore
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
assets/jsconfig.json
|
||||||
|
assets/js/justified-layout/
|
||||||
|
assets/js/photoswipe/
|
||||||
|
assets/css/photoswipe/
|
||||||
|
exampleSite/resources/
|
||||||
|
exampleSite/public/
|
||||||
9
themes/gallery/.stylelintrc.json
Normal file
9
themes/gallery/.stylelintrc.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": ["stylelint-config-standard-scss"],
|
||||||
|
"rules": {
|
||||||
|
"alpha-value-notation": "number",
|
||||||
|
"color-function-notation": "legacy",
|
||||||
|
"media-feature-range-notation": "prefix",
|
||||||
|
"property-no-vendor-prefix": null
|
||||||
|
}
|
||||||
|
}
|
||||||
21
themes/gallery/LICENSE
Normal file
21
themes/gallery/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023-2024 Nico Kaiser
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
250
themes/gallery/README.md
Normal file
250
themes/gallery/README.md
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
# Hugo Gallery Theme
|
||||||
|
|
||||||
|
A very simple and opinionated photo gallery theme for Hugo.
|
||||||
|
|
||||||
|
- [Demo](https://nicokaiser.github.io/hugo-theme-gallery/)
|
||||||
|
- [Example site source](https://github.com/nicokaiser/hugo-theme-gallery/tree/main/exampleSite)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Responsive design
|
||||||
|
- Dark color scheme (can be set per page)
|
||||||
|
- Private albums
|
||||||
|
- Justified album views with [Flickr's Justified Layout](https://github.com/flickr/justified-layout)
|
||||||
|
- Lightbox with [PhotoSwipe](https://photoswipe.com/)
|
||||||
|
- SEO with Open Graph tags
|
||||||
|
- Automatic (or manual) selection of feature/cover images
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
This theme requires Hugo Extended >= 0.121.2. Dependencies are bundled, so no Node.js/NPM and PostCSS is needed.
|
||||||
|
|
||||||
|
### As a Hugo Module
|
||||||
|
|
||||||
|
Requires the Go binary installed.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
hugo mod init github.com/<your_user>/<your_project>
|
||||||
|
```
|
||||||
|
|
||||||
|
Then add the theme to your `hugo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[module]
|
||||||
|
[[module.imports]]
|
||||||
|
path = "github.com/nicokaiser/hugo-theme-gallery/v4"
|
||||||
|
```
|
||||||
|
|
||||||
|
### As Git Submodule
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git submodule add --depth=1 https://github.com/nicokaiser/hugo-theme-gallery.git themes/gallery
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Page bundles which contain at least one image are listed as album or gallery:
|
||||||
|
|
||||||
|
```plain
|
||||||
|
content/
|
||||||
|
├── _index.md
|
||||||
|
├── about.md <-- not listed in album list
|
||||||
|
├── animals/
|
||||||
|
│ ├── _index.md
|
||||||
|
│ ├── cats/
|
||||||
|
│ | ├── index.md
|
||||||
|
│ | ├── cat1.jpg
|
||||||
|
│ | └── feature.jpg <-- album thumbnail
|
||||||
|
│ ├── dogs/
|
||||||
|
│ | ├── index.md
|
||||||
|
│ | ├── dog1.jpg <-- album thumbnail
|
||||||
|
│ | └── dog2.jpg
|
||||||
|
│ └── feature.jpg
|
||||||
|
├── bridge.jpg <-- site thumbnail (OpenGraph, etc.)
|
||||||
|
└── nature/
|
||||||
|
├── index.md <-- contains `featured_image: images/tree.jpg`
|
||||||
|
├── images/
|
||||||
|
| └── tree.jpg <-- album thumbnail
|
||||||
|
├── nature1.jpg
|
||||||
|
└── nature2.jpg
|
||||||
|
```
|
||||||
|
|
||||||
|
- `/about.md` is not a Page Bundle and does not have image resources. It is not displayed in the album list.
|
||||||
|
- `/nature` is a Leaf Bundle (has `index.md` and no children) => displayed as gallery (`single` layout).
|
||||||
|
- `/animals` is a Branch Bundle (has `_index.md` and has children) => displayed as album list (`list` layout).
|
||||||
|
- The image resource with `*feature*` in its name or the first image found is used as thumbnail image for album lists.
|
||||||
|
- Albums without an image are not shown.
|
||||||
|
|
||||||
|
### Front matter
|
||||||
|
|
||||||
|
- `title` -- title of the album, shown in the album list and on the album page.
|
||||||
|
- `date` -- album date, used for sorting (newest first).
|
||||||
|
- `description` -- description shown on the album page.
|
||||||
|
- `featured_image` -- name of the image file used for the album thumbnail. If not set, the first image which contains `feature` in its filename is used, otherwise the first image in the album.
|
||||||
|
- `weight` -- can be used to adjust sort order.
|
||||||
|
- `private` -- if set to `true`, this album is not shown in the album overview and is excluded from RSS feeds.
|
||||||
|
- `featured` -- if set to `true`, this album is featured on the homepage (even if private).
|
||||||
|
- `sort_by` -- property used for sorting images in an album. Default is `Name` (filename), but can also be `Date`.
|
||||||
|
- `sort_order` -- sort order. Default is `asc`.
|
||||||
|
- `params.theme` -- color theme for this page. Defaults to `defaultTheme` from configuration.
|
||||||
|
|
||||||
|
### Album Cover / Featured Image
|
||||||
|
|
||||||
|
By default, the cover image of an album is the first image in its folder. To select a specific image (which must be part of the album), use the `featured_image` frontmatter:
|
||||||
|
|
||||||
|
```plain
|
||||||
|
---
|
||||||
|
featured_image: img_1234.jpg
|
||||||
|
title: Cats
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
### Image Metadata
|
||||||
|
|
||||||
|
Image titles for the lightbox view are either taken from the `ImageDescription` EXIF tag, or the `title` in the resource metadata.
|
||||||
|
|
||||||
|
EXIF tags can be written using software like Adobe Lightroom or by using command line tools like exiftool:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
exiftool -ImageDescription="A closeup of a gray cat's face" cat-4.jpg
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, the image title can be set in the front matter:
|
||||||
|
|
||||||
|
```plain
|
||||||
|
---
|
||||||
|
date: 2024-02-18T14:12:44+0100
|
||||||
|
title: Cats
|
||||||
|
resources:
|
||||||
|
- src: cat-1.jpg
|
||||||
|
title: Brown tabby cat on white stairs
|
||||||
|
params:
|
||||||
|
date: 2024-02-18T13:04:30+0100
|
||||||
|
- src: cat-4.jpg
|
||||||
|
title: A closeup of a gray cat's face
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
### Categories
|
||||||
|
|
||||||
|
If you use categories in your albums, the homepage displays a list of categories.
|
||||||
|
Make sure `term` is not included in `disabledKinds` in the site config.
|
||||||
|
|
||||||
|
content/dogs/index.md:
|
||||||
|
|
||||||
|
```plain
|
||||||
|
---
|
||||||
|
date: 2023-01-12
|
||||||
|
featured_image: dogs-title-image.jpg
|
||||||
|
title: Dogs
|
||||||
|
categories: ["animals", "nature"]
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
Categories can also have custom titles and descriptions (by default, the "animals" category will have "Animals" as title and no description). Just create a `content/categories/<category>/_index.md`:
|
||||||
|
|
||||||
|
content/categories/animals/\_index.md:
|
||||||
|
|
||||||
|
```plain
|
||||||
|
---
|
||||||
|
title: Cute Animals
|
||||||
|
description: This is the description text of the "animals" category.
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
#### List of Categories
|
||||||
|
|
||||||
|
To enable a list of categories, each category must at least have an image in the `content/categores/<category>/` folder. Also, `taxonomy` must _not_ be included in the `disableKinds` in the site config.
|
||||||
|
|
||||||
|
Then, `/categories` displays a list of categories, with their featured image.
|
||||||
|
|
||||||
|
#### Other Taxonomies
|
||||||
|
|
||||||
|
You can also use other taxonomies like `series`. Note that only `categories` and `tags` are enabled by Hugo's default settings. Using `series` as additional taxonomy is left as an exercise for the reader.
|
||||||
|
|
||||||
|
### Featured Content on the Homepage
|
||||||
|
|
||||||
|
Albums (and als taxonomy pages like categories) can be marked as "featured":
|
||||||
|
|
||||||
|
```plain
|
||||||
|
---
|
||||||
|
title: Featured Album
|
||||||
|
featured: true
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
When used in combination with `private: true` this album is only shown as featured album on the homepage, and not in any album list.
|
||||||
|
|
||||||
|
Note that also categories or any other taxonomy term can be marked as featured, so you can feature a whole category, series, etc.
|
||||||
|
|
||||||
|
By default, the homepage displays
|
||||||
|
|
||||||
|
- the site title,
|
||||||
|
- links to all categories (if categories are enabled and used)
|
||||||
|
- the most recent featured content (even if private)
|
||||||
|
- all non-private top-level albums
|
||||||
|
|
||||||
|
This can easily be adjusted by using a local version of `layouts/_default/home.html`.
|
||||||
|
|
||||||
|
### Related Content
|
||||||
|
|
||||||
|
If related content is available for your site (e.g. when keywords or tags are used), related albums are shown below each gallery. Read more about this in the [Hugo Docs](https://gohugo.io/content-management/related/#configure-related-content).
|
||||||
|
|
||||||
|
Here is an example section in `config/_default/hugo.toml` to enable related content:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[related]
|
||||||
|
includeNewer = true
|
||||||
|
threshold = 10
|
||||||
|
toLower = false
|
||||||
|
[[related.indices]]
|
||||||
|
applyFilter = false
|
||||||
|
cardinalityThreshold = 0
|
||||||
|
name = 'categories'
|
||||||
|
pattern = ''
|
||||||
|
toLower = false
|
||||||
|
type = 'basic'
|
||||||
|
weight = 10
|
||||||
|
[[related.indices]]
|
||||||
|
applyFilter = false
|
||||||
|
cardinalityThreshold = 0
|
||||||
|
name = 'keywords'
|
||||||
|
pattern = ''
|
||||||
|
toLower = false
|
||||||
|
type = 'basic'
|
||||||
|
weight = 50
|
||||||
|
```
|
||||||
|
|
||||||
|
### Social Icons
|
||||||
|
|
||||||
|
Use the `socialIcons` configuration key to add social icons on the bottom of each page:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[params]
|
||||||
|
...
|
||||||
|
[params.socialIcons]
|
||||||
|
facebook = "https://www.facebook.com/"
|
||||||
|
instagram = "https://www.instagram.com/"
|
||||||
|
github = "https://github.com/nicokaiser/hugo-theme-gallery/"
|
||||||
|
youtube = "https://www.youtube.com/"
|
||||||
|
email = "mailto:user@example.com"
|
||||||
|
linkedin = "https://linkedin.com/"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom CSS
|
||||||
|
|
||||||
|
CSS is generated with Hugo Pipes, so you can add additional CSS in `assets/css/custom.css` (see example in `exampleSite`).
|
||||||
|
|
||||||
|
### Custom JavaScript
|
||||||
|
|
||||||
|
You can add additional JavaScript in `assets/js/custom.js`.
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
- [Nico Kaiser](https://kaiser.me/)
|
||||||
43
themes/gallery/assets/css/_colors.scss
Normal file
43
themes/gallery/assets/css/_colors.scss
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
:root {
|
||||||
|
color-scheme: light dark;
|
||||||
|
|
||||||
|
--surface-1-light: #fff;
|
||||||
|
--surface-2-light: #e5e5e5;
|
||||||
|
--text-1-light: #0a0a0a;
|
||||||
|
--text-2-light: #737373;
|
||||||
|
--surface-1-dark: #171717;
|
||||||
|
--surface-2-dark: #404040;
|
||||||
|
--text-1-dark: #fafafa;
|
||||||
|
--text-2-dark: #a3a3a3;
|
||||||
|
--surface-1: var(--surface-1-light);
|
||||||
|
--surface-2: var(--surface-2-light);
|
||||||
|
--text-1: var(--text-1-light);
|
||||||
|
--text-2: var(--text-2-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--surface-1: var(--surface-1-dark);
|
||||||
|
--surface-2: var(--surface-2-dark);
|
||||||
|
--text-1: var(--text-1-dark);
|
||||||
|
--text-2: var(--text-2-dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html.light {
|
||||||
|
color-scheme: light;
|
||||||
|
|
||||||
|
--surface-1: var(--surface-1-light);
|
||||||
|
--surface-2: var(--surface-2-light);
|
||||||
|
--text-1: var(--text-1-light);
|
||||||
|
--text-2: var(--text-2-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark {
|
||||||
|
color-scheme: dark;
|
||||||
|
|
||||||
|
--surface-1: var(--surface-1-dark);
|
||||||
|
--surface-2: var(--surface-2-dark);
|
||||||
|
--text-1: var(--text-1-dark);
|
||||||
|
--text-2: var(--text-2-dark);
|
||||||
|
}
|
||||||
99
themes/gallery/assets/css/_normalize.scss
Normal file
99
themes/gallery/assets/css/_normalize.scss
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
*,
|
||||||
|
::before,
|
||||||
|
::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
line-height: 1.5;
|
||||||
|
font-family: ui-sans-serif, system-ui, sans-serif;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-weight: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input {
|
||||||
|
font-family: inherit;
|
||||||
|
font-feature-settings: inherit;
|
||||||
|
font-variation-settings: inherit;
|
||||||
|
font-size: 100%;
|
||||||
|
font-weight: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
background-image: none;
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
:-moz-focusring {
|
||||||
|
outline: 1px dotted ButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
figure,
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
menu {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
svg,
|
||||||
|
video {
|
||||||
|
display: block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
video {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
428
themes/gallery/assets/css/_styles.scss
Normal file
428
themes/gallery/assets/css/_styles.scss
Normal file
@@ -0,0 +1,428 @@
|
|||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
background-color: var(--surface-1);
|
||||||
|
color: var(--text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body > header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.5rem;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 4rem;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
padding-right: 1rem;
|
||||||
|
padding-left: 1rem;
|
||||||
|
height: 3rem;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-square {
|
||||||
|
padding: 0;
|
||||||
|
width: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body > menu {
|
||||||
|
margin: 3rem auto 4rem;
|
||||||
|
padding-right: 1.5rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 768px;
|
||||||
|
color: var(--text-2);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: 1.75rem;
|
||||||
|
user-select: none;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&[aria-current="true"] {
|
||||||
|
color: var(--text-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body > main {
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
main > section {
|
||||||
|
margin: 3rem auto 4rem;
|
||||||
|
padding-right: 1.5rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > footer {
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
color: var(--text-2);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.25rem;
|
||||||
|
|
||||||
|
section:last-of-type {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 2.5rem;
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hgroup {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1.5rem;
|
||||||
|
margin: 3rem auto 4rem;
|
||||||
|
padding-right: 1.5rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
max-width: 1024px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.875rem;
|
||||||
|
line-height: 2.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: var(--text-2);
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
width: 83.3333%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 2.25rem;
|
||||||
|
line-height: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.875rem;
|
||||||
|
line-height: 2.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: 1.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section.galleries {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||||
|
gap: 2rem 1.5rem;
|
||||||
|
max-width: 1280px;
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
row-gap: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section.gallery {
|
||||||
|
padding-right: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
max-width: 1536px;
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
padding-right: 1.5rem /* 24px */;
|
||||||
|
padding-left: 1.5rem /* 24px */;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose {
|
||||||
|
max-width: 768px;
|
||||||
|
color: var(--text-1);
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.75;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--text-1);
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 1.25em;
|
||||||
|
margin-bottom: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
margin-top: 2em;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-top: 1.6em;
|
||||||
|
margin-bottom: 0.6em;
|
||||||
|
color: var(--text-1);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.25em;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin-top: 1.25em;
|
||||||
|
margin-bottom: 1.25em;
|
||||||
|
padding-left: 1.625em;
|
||||||
|
list-style-type: disc;
|
||||||
|
|
||||||
|
& > li {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
padding-left: 0.375em;
|
||||||
|
}
|
||||||
|
|
||||||
|
li::marker {
|
||||||
|
color: var(--text-2);
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
unicode-bidi: isolate;
|
||||||
|
text-align: start !important;
|
||||||
|
text-align-last: start !important;
|
||||||
|
text-indent: 0 !important;
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 + * {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin-top: 2em;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure > * {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> :first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> :last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 1rem;
|
||||||
|
|
||||||
|
& > figure {
|
||||||
|
aspect-ratio: 3/2;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > img, & figure > img {
|
||||||
|
transition-duration: 150ms;
|
||||||
|
transition-property: all;
|
||||||
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||||
|
border-radius: 1rem;
|
||||||
|
aspect-ratio: 3/2;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
object-fit: cover;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow:
|
||||||
|
0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
||||||
|
0 4px 6px -4px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
padding: 1rem;
|
||||||
|
|
||||||
|
& > h2 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: 1.375;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > p {
|
||||||
|
color: var(--text-2);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-item {
|
||||||
|
cursor: zoom-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group[aria-expanded="true"] {
|
||||||
|
.group-aria-expanded\:block {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-aria-expanded\:hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section.social-icons {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1.5rem;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 2rem;
|
||||||
|
padding-right: 1.5rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.featured {
|
||||||
|
margin: 3rem auto 4rem;
|
||||||
|
padding-right: 1.5rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
max-width: 1280px;
|
||||||
|
color: var(--text-1-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.featured-card {
|
||||||
|
display: flex;
|
||||||
|
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||||
|
border-radius: 1rem;
|
||||||
|
background-position: center;
|
||||||
|
background-size: cover;
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
transition-duration: 150ms;
|
||||||
|
transition-property: all;
|
||||||
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
aspect-ratio: 16/9;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 1rem;
|
||||||
|
background-image: linear-gradient(to top, RGB(0 0 0 / 0.8) 10%, transparent 50%);
|
||||||
|
padding: 1.5rem;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
& > h2 {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: 1.25;
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
font-size: 1.875rem;
|
||||||
|
line-height: 2.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > p {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow:
|
||||||
|
0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
||||||
|
0 4px 6px -4px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nav.categories {
|
||||||
|
padding-right: 1.5rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
|
||||||
|
& > ul {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
li {
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
display: block;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
border: 1px solid var(--text-2);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.25rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
themes/gallery/assets/css/custom.css
Normal file
1
themes/gallery/assets/css/custom.css
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/* custom.css */
|
||||||
20
themes/gallery/assets/css/main.scss
Normal file
20
themes/gallery/assets/css/main.scss
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@import "normalize";
|
||||||
|
@import "colors";
|
||||||
|
@import "styles";
|
||||||
|
@import "photoswipe/photoswipe";
|
||||||
|
@import "photoswipe/photoswipe-dynamic-caption-plugin";
|
||||||
|
@import "custom";
|
||||||
|
|
||||||
|
.lazyload,
|
||||||
|
.lazyloading {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lazyloaded {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 300ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.lazyload:not([src]) {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
.pswp__dynamic-caption {
|
||||||
|
color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
transition: opacity 120ms linear !important; /* override default */
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp-caption-content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__dynamic-caption a {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__dynamic-caption--faded {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__dynamic-caption--aside {
|
||||||
|
width: auto;
|
||||||
|
max-width: 300px;
|
||||||
|
padding: 20px 15px 20px 20px;
|
||||||
|
margin-top: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__dynamic-caption--below {
|
||||||
|
width: auto;
|
||||||
|
max-width: 700px;
|
||||||
|
padding: 15px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__dynamic-caption--on-hor-edge {
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__dynamic-caption--mobile {
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(0,0,0,0.5);
|
||||||
|
padding: 10px 15px;
|
||||||
|
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
|
||||||
|
/* override styles that were set via JS.
|
||||||
|
as they interfere with size measurement */
|
||||||
|
top: auto !important;
|
||||||
|
left: 0 !important;
|
||||||
|
}
|
||||||
420
themes/gallery/assets/css/photoswipe/photoswipe.css
Normal file
420
themes/gallery/assets/css/photoswipe/photoswipe.css
Normal file
@@ -0,0 +1,420 @@
|
|||||||
|
/*! PhotoSwipe main CSS by Dmytro Semenov | photoswipe.com */
|
||||||
|
|
||||||
|
.pswp {
|
||||||
|
--pswp-bg: #000;
|
||||||
|
--pswp-placeholder-bg: #222;
|
||||||
|
|
||||||
|
|
||||||
|
--pswp-root-z-index: 100000;
|
||||||
|
|
||||||
|
--pswp-preloader-color: rgba(79, 79, 79, 0.4);
|
||||||
|
--pswp-preloader-color-secondary: rgba(255, 255, 255, 0.9);
|
||||||
|
|
||||||
|
/* defined via js:
|
||||||
|
--pswp-transition-duration: 333ms; */
|
||||||
|
|
||||||
|
--pswp-icon-color: #fff;
|
||||||
|
--pswp-icon-color-secondary: #4f4f4f;
|
||||||
|
--pswp-icon-stroke-color: #4f4f4f;
|
||||||
|
--pswp-icon-stroke-width: 2px;
|
||||||
|
|
||||||
|
--pswp-error-text-color: var(--pswp-icon-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Styles for basic PhotoSwipe (pswp) functionality (sliding area, open/close transitions)
|
||||||
|
*/
|
||||||
|
|
||||||
|
.pswp {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: var(--pswp-root-z-index);
|
||||||
|
display: none;
|
||||||
|
touch-action: none;
|
||||||
|
outline: 0;
|
||||||
|
opacity: 0.003;
|
||||||
|
contain: layout style size;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevents focus outline on the root element,
|
||||||
|
(it may be focused initially) */
|
||||||
|
.pswp:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp img {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp--open {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp,
|
||||||
|
.pswp__bg {
|
||||||
|
transform: translateZ(0);
|
||||||
|
will-change: opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__bg {
|
||||||
|
opacity: 0.005;
|
||||||
|
background: var(--pswp-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp,
|
||||||
|
.pswp__scroll-wrap {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__scroll-wrap,
|
||||||
|
.pswp__bg,
|
||||||
|
.pswp__container,
|
||||||
|
.pswp__item,
|
||||||
|
.pswp__content,
|
||||||
|
.pswp__img,
|
||||||
|
.pswp__zoom-wrap {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__img,
|
||||||
|
.pswp__zoom-wrap {
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp--click-to-zoom.pswp--zoom-allowed .pswp__img {
|
||||||
|
cursor: -webkit-zoom-in;
|
||||||
|
cursor: -moz-zoom-in;
|
||||||
|
cursor: zoom-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp--click-to-zoom.pswp--zoomed-in .pswp__img {
|
||||||
|
cursor: move;
|
||||||
|
cursor: -webkit-grab;
|
||||||
|
cursor: -moz-grab;
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp--click-to-zoom.pswp--zoomed-in .pswp__img:active {
|
||||||
|
cursor: -webkit-grabbing;
|
||||||
|
cursor: -moz-grabbing;
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* :active to override grabbing cursor */
|
||||||
|
.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img,
|
||||||
|
.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img:active,
|
||||||
|
.pswp__img {
|
||||||
|
cursor: -webkit-zoom-out;
|
||||||
|
cursor: -moz-zoom-out;
|
||||||
|
cursor: zoom-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Prevent selection and tap highlights */
|
||||||
|
.pswp__container,
|
||||||
|
.pswp__img,
|
||||||
|
.pswp__button,
|
||||||
|
.pswp__counter {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__item {
|
||||||
|
/* z-index for fade transition */
|
||||||
|
z-index: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allow to click through pswp__content element, but not its children */
|
||||||
|
.pswp__content {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.pswp__content > * {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
PhotoSwipe UI
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Error message appears when image is not loaded
|
||||||
|
(JS option errorMsg controls markup)
|
||||||
|
*/
|
||||||
|
.pswp__error-msg-container {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
.pswp__error-msg {
|
||||||
|
margin: auto;
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1;
|
||||||
|
color: var(--pswp-error-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
class pswp__hide-on-close is applied to elements that
|
||||||
|
should hide (for example fade out) when PhotoSwipe is closed
|
||||||
|
and show (for example fade in) when PhotoSwipe is opened
|
||||||
|
*/
|
||||||
|
.pswp .pswp__hide-on-close {
|
||||||
|
opacity: 0.005;
|
||||||
|
will-change: opacity;
|
||||||
|
transition: opacity var(--pswp-transition-duration) cubic-bezier(0.4, 0, 0.22, 1);
|
||||||
|
z-index: 10; /* always overlap slide content */
|
||||||
|
pointer-events: none; /* hidden elements should not be clickable */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* class pswp--ui-visible is added when opening or closing transition starts */
|
||||||
|
.pswp--ui-visible .pswp__hide-on-close {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* <button> styles, including css reset */
|
||||||
|
.pswp__button {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
width: 50px;
|
||||||
|
height: 60px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
background: none;
|
||||||
|
border: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
opacity: 0.85;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__button:hover,
|
||||||
|
.pswp__button:active,
|
||||||
|
.pswp__button:focus {
|
||||||
|
transition: none;
|
||||||
|
padding: 0;
|
||||||
|
background: none;
|
||||||
|
border: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__button:disabled {
|
||||||
|
opacity: 0.3;
|
||||||
|
cursor: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__icn {
|
||||||
|
fill: var(--pswp-icon-color);
|
||||||
|
color: var(--pswp-icon-color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__icn {
|
||||||
|
position: absolute;
|
||||||
|
top: 14px;
|
||||||
|
left: 9px;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__icn-shadow {
|
||||||
|
stroke: var(--pswp-icon-stroke-color);
|
||||||
|
stroke-width: var(--pswp-icon-stroke-width);
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__icn:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
div element that matches size of large image,
|
||||||
|
large image loads on top of it,
|
||||||
|
used when msrc is not provided
|
||||||
|
*/
|
||||||
|
div.pswp__img--placeholder,
|
||||||
|
.pswp__img--with-bg {
|
||||||
|
background: var(--pswp-placeholder-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__top-bar {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
/* allow events to pass through top bar itself */
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
.pswp__top-bar > * {
|
||||||
|
pointer-events: auto;
|
||||||
|
/* this makes transition significantly more smooth,
|
||||||
|
even though inner elements are not animated */
|
||||||
|
will-change: opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Close button
|
||||||
|
|
||||||
|
*/
|
||||||
|
.pswp__button--close {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Arrow buttons
|
||||||
|
|
||||||
|
*/
|
||||||
|
.pswp__button--arrow {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 75px;
|
||||||
|
height: 100px;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__button--arrow:disabled {
|
||||||
|
display: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__button--arrow .pswp__icn {
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -30px;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
background: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp--one-slide .pswp__button--arrow {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hide arrows on touch screens */
|
||||||
|
.pswp--touch .pswp__button--arrow {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* show arrows only after mouse was used */
|
||||||
|
.pswp--has_mouse .pswp__button--arrow {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__button--arrow--prev {
|
||||||
|
right: auto;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__button--arrow--next {
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
.pswp__button--arrow--next .pswp__icn {
|
||||||
|
left: auto;
|
||||||
|
right: 14px;
|
||||||
|
/* flip horizontally */
|
||||||
|
transform: scale(-1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Zoom button
|
||||||
|
|
||||||
|
*/
|
||||||
|
.pswp__button--zoom {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp--zoom-allowed .pswp__button--zoom {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "+" => "-" */
|
||||||
|
.pswp--zoomed-in .pswp__zoom-icn-bar-v {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Loading indicator
|
||||||
|
|
||||||
|
*/
|
||||||
|
.pswp__preloader {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 50px;
|
||||||
|
height: 60px;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__preloader .pswp__icn {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s linear;
|
||||||
|
animation: pswp-clockwise 600ms linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp__preloader--active .pswp__icn {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pswp-clockwise {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
"1 of 10" counter
|
||||||
|
|
||||||
|
*/
|
||||||
|
.pswp__counter {
|
||||||
|
height: 30px;
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-inline-start: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 30px;
|
||||||
|
color: var(--pswp-icon-color);
|
||||||
|
text-shadow: 1px 1px 3px var(--pswp-icon-color-secondary);
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pswp--one-slide .pswp__counter {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
1
themes/gallery/assets/js/custom.js
Normal file
1
themes/gallery/assets/js/custom.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/* custom.js */
|
||||||
52
themes/gallery/assets/js/gallery.js
Normal file
52
themes/gallery/assets/js/gallery.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import justifiedLayout from "./justified-layout/index.js";
|
||||||
|
import * as params from "@params";
|
||||||
|
|
||||||
|
const gallery = document.getElementById("gallery");
|
||||||
|
|
||||||
|
if (gallery) {
|
||||||
|
let containerWidth = 0;
|
||||||
|
const items = gallery.querySelectorAll(".gallery-item");
|
||||||
|
|
||||||
|
const input = Array.from(items).map((item) => {
|
||||||
|
const img = item.querySelector("img");
|
||||||
|
img.style.width = "100%";
|
||||||
|
img.style.height = "auto";
|
||||||
|
return {
|
||||||
|
width: parseFloat(img.getAttribute("width")),
|
||||||
|
height: parseFloat(img.getAttribute("height")),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateGallery() {
|
||||||
|
if (containerWidth === gallery.getBoundingClientRect().width) return;
|
||||||
|
containerWidth = gallery.getBoundingClientRect().width;
|
||||||
|
|
||||||
|
const geometry = justifiedLayout(input, {
|
||||||
|
containerWidth,
|
||||||
|
containerPadding: 0,
|
||||||
|
boxSpacing: Number.isInteger(params.boxSpacing) ? params.boxSpacing : 10,
|
||||||
|
targetRowHeight: params.targetRowHeight || 288,
|
||||||
|
targetRowHeightTolerance: Number.isInteger(params.targetRowHeightTolerance) ? params.targetRowHeightTolerance : 0.25,
|
||||||
|
});
|
||||||
|
|
||||||
|
items.forEach((item, i) => {
|
||||||
|
const { width, height, top, left } = geometry.boxes[i];
|
||||||
|
item.style.position = "absolute";
|
||||||
|
item.style.width = width + "px";
|
||||||
|
item.style.height = height + "px";
|
||||||
|
item.style.top = top + "px";
|
||||||
|
item.style.left = left + "px";
|
||||||
|
item.style.overflow = "hidden";
|
||||||
|
});
|
||||||
|
|
||||||
|
gallery.style.position = "relative";
|
||||||
|
gallery.style.height = geometry.containerHeight + "px";
|
||||||
|
gallery.style.visibility = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("resize", updateGallery);
|
||||||
|
window.addEventListener("orientationchange", updateGallery);
|
||||||
|
|
||||||
|
updateGallery();
|
||||||
|
updateGallery();
|
||||||
|
}
|
||||||
248
themes/gallery/assets/js/justified-layout/index.js
Normal file
248
themes/gallery/assets/js/justified-layout/index.js
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright 2019 SmugMug, Inc.
|
||||||
|
* Licensed under the terms of the MIT license. Please see LICENSE file in the project root for terms.
|
||||||
|
* @license
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Row = require('./row');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new, empty row.
|
||||||
|
*
|
||||||
|
* @method createNewRow
|
||||||
|
* @param layoutConfig {Object} The layout configuration
|
||||||
|
* @param layoutData {Object} The current state of the layout
|
||||||
|
* @return A new, empty row of the type specified by this layout.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createNewRow(layoutConfig, layoutData) {
|
||||||
|
|
||||||
|
var isBreakoutRow;
|
||||||
|
|
||||||
|
// Work out if this is a full width breakout row
|
||||||
|
if (layoutConfig.fullWidthBreakoutRowCadence !== false) {
|
||||||
|
if (((layoutData._rows.length + 1) % layoutConfig.fullWidthBreakoutRowCadence) === 0) {
|
||||||
|
isBreakoutRow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Row({
|
||||||
|
top: layoutData._containerHeight,
|
||||||
|
left: layoutConfig.containerPadding.left,
|
||||||
|
width: layoutConfig.containerWidth - layoutConfig.containerPadding.left - layoutConfig.containerPadding.right,
|
||||||
|
spacing: layoutConfig.boxSpacing.horizontal,
|
||||||
|
targetRowHeight: layoutConfig.targetRowHeight,
|
||||||
|
targetRowHeightTolerance: layoutConfig.targetRowHeightTolerance,
|
||||||
|
edgeCaseMinRowHeight: 0.5 * layoutConfig.targetRowHeight,
|
||||||
|
edgeCaseMaxRowHeight: 2 * layoutConfig.targetRowHeight,
|
||||||
|
rightToLeft: false,
|
||||||
|
isBreakoutRow: isBreakoutRow,
|
||||||
|
widowLayoutStyle: layoutConfig.widowLayoutStyle
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a completed row to the layout.
|
||||||
|
* Note: the row must have already been completed.
|
||||||
|
*
|
||||||
|
* @method addRow
|
||||||
|
* @param layoutConfig {Object} The layout configuration
|
||||||
|
* @param layoutData {Object} The current state of the layout
|
||||||
|
* @param row {Row} The row to add.
|
||||||
|
* @return {Array} Each item added to the row.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addRow(layoutConfig, layoutData, row) {
|
||||||
|
|
||||||
|
layoutData._rows.push(row);
|
||||||
|
layoutData._layoutItems = layoutData._layoutItems.concat(row.getItems());
|
||||||
|
|
||||||
|
// Increment the container height
|
||||||
|
layoutData._containerHeight += row.height + layoutConfig.boxSpacing.vertical;
|
||||||
|
|
||||||
|
return row.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the current layout for all items in the list that require layout.
|
||||||
|
* "Layout" means geometry: position within container and size
|
||||||
|
*
|
||||||
|
* @method computeLayout
|
||||||
|
* @param layoutConfig {Object} The layout configuration
|
||||||
|
* @param layoutData {Object} The current state of the layout
|
||||||
|
* @param itemLayoutData {Array} Array of items to lay out, with data required to lay out each item
|
||||||
|
* @return {Object} The newly-calculated layout, containing the new container height, and lists of layout items
|
||||||
|
*/
|
||||||
|
|
||||||
|
function computeLayout(layoutConfig, layoutData, itemLayoutData) {
|
||||||
|
|
||||||
|
var laidOutItems = [],
|
||||||
|
itemAdded,
|
||||||
|
currentRow,
|
||||||
|
nextToLastRowHeight;
|
||||||
|
|
||||||
|
// Apply forced aspect ratio if specified, and set a flag.
|
||||||
|
if (layoutConfig.forceAspectRatio) {
|
||||||
|
itemLayoutData.forEach(function (itemData) {
|
||||||
|
itemData.forcedAspectRatio = true;
|
||||||
|
itemData.aspectRatio = layoutConfig.forceAspectRatio;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through the items
|
||||||
|
itemLayoutData.some(function (itemData, i) {
|
||||||
|
|
||||||
|
if (isNaN(itemData.aspectRatio)) {
|
||||||
|
throw new Error("Item " + i + " has an invalid aspect ratio");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not currently building up a row, make a new one.
|
||||||
|
if (!currentRow) {
|
||||||
|
currentRow = createNewRow(layoutConfig, layoutData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to add item to the current row.
|
||||||
|
itemAdded = currentRow.addItem(itemData);
|
||||||
|
|
||||||
|
if (currentRow.isLayoutComplete()) {
|
||||||
|
|
||||||
|
// Row is filled; add it and start a new one
|
||||||
|
laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow));
|
||||||
|
|
||||||
|
if (layoutData._rows.length >= layoutConfig.maxNumRows) {
|
||||||
|
currentRow = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRow = createNewRow(layoutConfig, layoutData);
|
||||||
|
|
||||||
|
// Item was rejected; add it to its own row
|
||||||
|
if (!itemAdded) {
|
||||||
|
|
||||||
|
itemAdded = currentRow.addItem(itemData);
|
||||||
|
|
||||||
|
if (currentRow.isLayoutComplete()) {
|
||||||
|
|
||||||
|
// If the rejected item fills a row on its own, add the row and start another new one
|
||||||
|
laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow));
|
||||||
|
if (layoutData._rows.length >= layoutConfig.maxNumRows) {
|
||||||
|
currentRow = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
currentRow = createNewRow(layoutConfig, layoutData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle any leftover content (orphans) depending on where they lie
|
||||||
|
// in this layout update, and in the total content set.
|
||||||
|
if (currentRow && currentRow.getItems().length && layoutConfig.showWidows) {
|
||||||
|
|
||||||
|
// Last page of all content or orphan suppression is suppressed; lay out orphans.
|
||||||
|
if (layoutData._rows.length) {
|
||||||
|
|
||||||
|
// Only Match previous row's height if it exists and it isn't a breakout row
|
||||||
|
if (layoutData._rows[layoutData._rows.length - 1].isBreakoutRow) {
|
||||||
|
nextToLastRowHeight = layoutData._rows[layoutData._rows.length - 1].targetRowHeight;
|
||||||
|
} else {
|
||||||
|
nextToLastRowHeight = layoutData._rows[layoutData._rows.length - 1].height;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRow.forceComplete(false, nextToLastRowHeight);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// ...else use target height if there is no other row height to reference.
|
||||||
|
currentRow.forceComplete(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow));
|
||||||
|
layoutConfig._widowCount = currentRow.getItems().length;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to clean up the bottom container padding
|
||||||
|
// First remove the height added for box spacing
|
||||||
|
layoutData._containerHeight = layoutData._containerHeight - layoutConfig.boxSpacing.vertical;
|
||||||
|
// Then add our bottom container padding
|
||||||
|
layoutData._containerHeight = layoutData._containerHeight + layoutConfig.containerPadding.bottom;
|
||||||
|
|
||||||
|
return {
|
||||||
|
containerHeight: layoutData._containerHeight,
|
||||||
|
widowCount: layoutConfig._widowCount,
|
||||||
|
boxes: layoutData._layoutItems
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes in a bunch of box data and config. Returns
|
||||||
|
* geometry to lay them out in a justified view.
|
||||||
|
*
|
||||||
|
* @method covertSizesToAspectRatios
|
||||||
|
* @param sizes {Array} Array of objects with widths and heights
|
||||||
|
* @return {Array} A list of aspect ratios
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function (input, config) {
|
||||||
|
var layoutConfig = {};
|
||||||
|
var layoutData = {};
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
var defaults = {
|
||||||
|
containerWidth: 1060,
|
||||||
|
containerPadding: 10,
|
||||||
|
boxSpacing: 10,
|
||||||
|
targetRowHeight: 320,
|
||||||
|
targetRowHeightTolerance: 0.25,
|
||||||
|
maxNumRows: Number.POSITIVE_INFINITY,
|
||||||
|
forceAspectRatio: false,
|
||||||
|
showWidows: true,
|
||||||
|
fullWidthBreakoutRowCadence: false,
|
||||||
|
widowLayoutStyle: 'left'
|
||||||
|
};
|
||||||
|
|
||||||
|
var containerPadding = {};
|
||||||
|
var boxSpacing = {};
|
||||||
|
|
||||||
|
config = config || {};
|
||||||
|
|
||||||
|
// Merge defaults and config passed in
|
||||||
|
layoutConfig = Object.assign(defaults, config);
|
||||||
|
|
||||||
|
// Sort out padding and spacing values
|
||||||
|
containerPadding.top = (!isNaN(parseFloat(layoutConfig.containerPadding.top))) ? layoutConfig.containerPadding.top : layoutConfig.containerPadding;
|
||||||
|
containerPadding.right = (!isNaN(parseFloat(layoutConfig.containerPadding.right))) ? layoutConfig.containerPadding.right : layoutConfig.containerPadding;
|
||||||
|
containerPadding.bottom = (!isNaN(parseFloat(layoutConfig.containerPadding.bottom))) ? layoutConfig.containerPadding.bottom : layoutConfig.containerPadding;
|
||||||
|
containerPadding.left = (!isNaN(parseFloat(layoutConfig.containerPadding.left))) ? layoutConfig.containerPadding.left : layoutConfig.containerPadding;
|
||||||
|
boxSpacing.horizontal = (!isNaN(parseFloat(layoutConfig.boxSpacing.horizontal))) ? layoutConfig.boxSpacing.horizontal : layoutConfig.boxSpacing;
|
||||||
|
boxSpacing.vertical = (!isNaN(parseFloat(layoutConfig.boxSpacing.vertical))) ? layoutConfig.boxSpacing.vertical : layoutConfig.boxSpacing;
|
||||||
|
|
||||||
|
layoutConfig.containerPadding = containerPadding;
|
||||||
|
layoutConfig.boxSpacing = boxSpacing;
|
||||||
|
|
||||||
|
// Local
|
||||||
|
layoutData._layoutItems = [];
|
||||||
|
layoutData._awakeItems = [];
|
||||||
|
layoutData._inViewportItems = [];
|
||||||
|
layoutData._leadingOrphans = [];
|
||||||
|
layoutData._trailingOrphans = [];
|
||||||
|
layoutData._containerHeight = layoutConfig.containerPadding.top;
|
||||||
|
layoutData._rows = [];
|
||||||
|
layoutData._orphans = [];
|
||||||
|
layoutConfig._widowCount = 0;
|
||||||
|
|
||||||
|
// Convert widths and heights to aspect ratios if we need to
|
||||||
|
return computeLayout(layoutConfig, layoutData, input.map(function (item) {
|
||||||
|
if (item.width && item.height) {
|
||||||
|
return { aspectRatio: item.width / item.height };
|
||||||
|
} else {
|
||||||
|
return { aspectRatio: item };
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
333
themes/gallery/assets/js/justified-layout/row.js
Normal file
333
themes/gallery/assets/js/justified-layout/row.js
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright 2019 SmugMug, Inc.
|
||||||
|
* Licensed under the terms of the MIT license. Please see LICENSE file in the project root for terms.
|
||||||
|
* @license
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Row
|
||||||
|
* Wrapper for each row in a justified layout.
|
||||||
|
* Stores relevant values and provides methods for calculating layout of individual rows.
|
||||||
|
*
|
||||||
|
* @param {Object} layoutConfig - The same as that passed
|
||||||
|
* @param {Object} Initialization parameters. The following are all required:
|
||||||
|
* @param params.top {Number} Top of row, relative to container
|
||||||
|
* @param params.left {Number} Left side of row relative to container (equal to container left padding)
|
||||||
|
* @param params.width {Number} Width of row, not including container padding
|
||||||
|
* @param params.spacing {Number} Horizontal spacing between items
|
||||||
|
* @param params.targetRowHeight {Number} Layout algorithm will aim for this row height
|
||||||
|
* @param params.targetRowHeightTolerance {Number} Row heights may vary +/- (`targetRowHeight` x `targetRowHeightTolerance`)
|
||||||
|
* @param params.edgeCaseMinRowHeight {Number} Absolute minimum row height for edge cases that cannot be resolved within tolerance.
|
||||||
|
* @param params.edgeCaseMaxRowHeight {Number} Absolute maximum row height for edge cases that cannot be resolved within tolerance.
|
||||||
|
* @param params.isBreakoutRow {Boolean} Is this row in particular one of those breakout rows? Always false if it's not that kind of photo list
|
||||||
|
* @param params.widowLayoutStyle {String} If widows are visible, how should they be laid out?
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Row = module.exports = function (params) {
|
||||||
|
|
||||||
|
// Top of row, relative to container
|
||||||
|
this.top = params.top;
|
||||||
|
|
||||||
|
// Left side of row relative to container (equal to container left padding)
|
||||||
|
this.left = params.left;
|
||||||
|
|
||||||
|
// Width of row, not including container padding
|
||||||
|
this.width = params.width;
|
||||||
|
|
||||||
|
// Horizontal spacing between items
|
||||||
|
this.spacing = params.spacing;
|
||||||
|
|
||||||
|
// Row height calculation values
|
||||||
|
this.targetRowHeight = params.targetRowHeight;
|
||||||
|
this.targetRowHeightTolerance = params.targetRowHeightTolerance;
|
||||||
|
this.minAspectRatio = this.width / params.targetRowHeight * (1 - params.targetRowHeightTolerance);
|
||||||
|
this.maxAspectRatio = this.width / params.targetRowHeight * (1 + params.targetRowHeightTolerance);
|
||||||
|
|
||||||
|
// Edge case row height minimum/maximum
|
||||||
|
this.edgeCaseMinRowHeight = params.edgeCaseMinRowHeight;
|
||||||
|
this.edgeCaseMaxRowHeight = params.edgeCaseMaxRowHeight;
|
||||||
|
|
||||||
|
// Widow layout direction
|
||||||
|
this.widowLayoutStyle = params.widowLayoutStyle;
|
||||||
|
|
||||||
|
// Full width breakout rows
|
||||||
|
this.isBreakoutRow = params.isBreakoutRow;
|
||||||
|
|
||||||
|
// Store layout data for each item in row
|
||||||
|
this.items = [];
|
||||||
|
|
||||||
|
// Height remains at 0 until it's been calculated
|
||||||
|
this.height = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Row.prototype = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to add a single item to the row.
|
||||||
|
* This is the heart of the justified algorithm.
|
||||||
|
* This method is direction-agnostic; it deals only with sizes, not positions.
|
||||||
|
*
|
||||||
|
* If the item fits in the row, without pushing row height beyond min/max tolerance,
|
||||||
|
* the item is added and the method returns true.
|
||||||
|
*
|
||||||
|
* If the item leaves row height too high, there may be room to scale it down and add another item.
|
||||||
|
* In this case, the item is added and the method returns true, but the row is incomplete.
|
||||||
|
*
|
||||||
|
* If the item leaves row height too short, there are too many items to fit within tolerance.
|
||||||
|
* The method will either accept or reject the new item, favoring the resulting row height closest to within tolerance.
|
||||||
|
* If the item is rejected, left/right padding will be required to fit the row height within tolerance;
|
||||||
|
* if the item is accepted, top/bottom cropping will be required to fit the row height within tolerance.
|
||||||
|
*
|
||||||
|
* @method addItem
|
||||||
|
* @param itemData {Object} Item layout data, containing item aspect ratio.
|
||||||
|
* @return {Boolean} True if successfully added; false if rejected.
|
||||||
|
*/
|
||||||
|
|
||||||
|
addItem: function (itemData) {
|
||||||
|
|
||||||
|
var newItems = this.items.concat(itemData),
|
||||||
|
// Calculate aspect ratios for items only; exclude spacing
|
||||||
|
rowWidthWithoutSpacing = this.width - (newItems.length - 1) * this.spacing,
|
||||||
|
newAspectRatio = newItems.reduce(function (sum, item) {
|
||||||
|
return sum + item.aspectRatio;
|
||||||
|
}, 0),
|
||||||
|
targetAspectRatio = rowWidthWithoutSpacing / this.targetRowHeight,
|
||||||
|
previousRowWidthWithoutSpacing,
|
||||||
|
previousAspectRatio,
|
||||||
|
previousTargetAspectRatio;
|
||||||
|
|
||||||
|
// Handle big full-width breakout photos if we're doing them
|
||||||
|
if (this.isBreakoutRow) {
|
||||||
|
// Only do it if there's no other items in this row
|
||||||
|
if (this.items.length === 0) {
|
||||||
|
// Only go full width if this photo is a square or landscape
|
||||||
|
if (itemData.aspectRatio >= 1) {
|
||||||
|
// Close out the row with a full width photo
|
||||||
|
this.items.push(itemData);
|
||||||
|
this.completeLayout(rowWidthWithoutSpacing / itemData.aspectRatio, 'justify');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newAspectRatio < this.minAspectRatio) {
|
||||||
|
|
||||||
|
// New aspect ratio is too narrow / scaled row height is too tall.
|
||||||
|
// Accept this item and leave row open for more items.
|
||||||
|
|
||||||
|
this.items.push(Object.assign({}, itemData));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (newAspectRatio > this.maxAspectRatio) {
|
||||||
|
|
||||||
|
// New aspect ratio is too wide / scaled row height will be too short.
|
||||||
|
// Accept item if the resulting aspect ratio is closer to target than it would be without the item.
|
||||||
|
// NOTE: Any row that falls into this block will require cropping/padding on individual items.
|
||||||
|
|
||||||
|
if (this.items.length === 0) {
|
||||||
|
|
||||||
|
// When there are no existing items, force acceptance of the new item and complete the layout.
|
||||||
|
// This is the pano special case.
|
||||||
|
this.items.push(Object.assign({}, itemData));
|
||||||
|
this.completeLayout(rowWidthWithoutSpacing / newAspectRatio, 'justify');
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate width/aspect ratio for row before adding new item
|
||||||
|
previousRowWidthWithoutSpacing = this.width - (this.items.length - 1) * this.spacing;
|
||||||
|
previousAspectRatio = this.items.reduce(function (sum, item) {
|
||||||
|
return sum + item.aspectRatio;
|
||||||
|
}, 0);
|
||||||
|
previousTargetAspectRatio = previousRowWidthWithoutSpacing / this.targetRowHeight;
|
||||||
|
|
||||||
|
if (Math.abs(newAspectRatio - targetAspectRatio) > Math.abs(previousAspectRatio - previousTargetAspectRatio)) {
|
||||||
|
|
||||||
|
// Row with new item is us farther away from target than row without; complete layout and reject item.
|
||||||
|
this.completeLayout(previousRowWidthWithoutSpacing / previousAspectRatio, 'justify');
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Row with new item is us closer to target than row without;
|
||||||
|
// accept the new item and complete the row layout.
|
||||||
|
this.items.push(Object.assign({}, itemData));
|
||||||
|
this.completeLayout(rowWidthWithoutSpacing / newAspectRatio, 'justify');
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// New aspect ratio / scaled row height is within tolerance;
|
||||||
|
// accept the new item and complete the row layout.
|
||||||
|
this.items.push(Object.assign({}, itemData));
|
||||||
|
this.completeLayout(rowWidthWithoutSpacing / newAspectRatio, 'justify');
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a row has completed its layout.
|
||||||
|
*
|
||||||
|
* @method isLayoutComplete
|
||||||
|
* @return {Boolean} True if complete; false if not.
|
||||||
|
*/
|
||||||
|
|
||||||
|
isLayoutComplete: function () {
|
||||||
|
return this.height > 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set row height and compute item geometry from that height.
|
||||||
|
* Will justify items within the row unless instructed not to.
|
||||||
|
*
|
||||||
|
* @method completeLayout
|
||||||
|
* @param newHeight {Number} Set row height to this value.
|
||||||
|
* @param widowLayoutStyle {String} How should widows display? Supported: left | justify | center
|
||||||
|
*/
|
||||||
|
|
||||||
|
completeLayout: function (newHeight, widowLayoutStyle) {
|
||||||
|
|
||||||
|
var itemWidthSum = this.left,
|
||||||
|
rowWidthWithoutSpacing = this.width - (this.items.length - 1) * this.spacing,
|
||||||
|
clampedToNativeRatio,
|
||||||
|
clampedHeight,
|
||||||
|
errorWidthPerItem,
|
||||||
|
roundedCumulativeErrors,
|
||||||
|
singleItemGeometry,
|
||||||
|
centerOffset;
|
||||||
|
|
||||||
|
// Justify unless explicitly specified otherwise.
|
||||||
|
if (typeof widowLayoutStyle === 'undefined' || ['justify', 'center', 'left'].indexOf(widowLayoutStyle) < 0) {
|
||||||
|
widowLayoutStyle = 'left';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp row height to edge case minimum/maximum.
|
||||||
|
clampedHeight = Math.max(this.edgeCaseMinRowHeight, Math.min(newHeight, this.edgeCaseMaxRowHeight));
|
||||||
|
|
||||||
|
if (newHeight !== clampedHeight) {
|
||||||
|
|
||||||
|
// If row height was clamped, the resulting row/item aspect ratio will be off,
|
||||||
|
// so force it to fit the width (recalculate aspectRatio to match clamped height).
|
||||||
|
// NOTE: this will result in cropping/padding commensurate to the amount of clamping.
|
||||||
|
this.height = clampedHeight;
|
||||||
|
clampedToNativeRatio = (rowWidthWithoutSpacing / clampedHeight) / (rowWidthWithoutSpacing / newHeight);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// If not clamped, leave ratio at 1.0.
|
||||||
|
this.height = newHeight;
|
||||||
|
clampedToNativeRatio = 1.0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute item geometry based on newHeight.
|
||||||
|
this.items.forEach(function (item) {
|
||||||
|
|
||||||
|
item.top = this.top;
|
||||||
|
item.width = item.aspectRatio * this.height * clampedToNativeRatio;
|
||||||
|
item.height = this.height;
|
||||||
|
|
||||||
|
// Left-to-right.
|
||||||
|
// TODO right to left
|
||||||
|
// item.left = this.width - itemWidthSum - item.width;
|
||||||
|
item.left = itemWidthSum;
|
||||||
|
|
||||||
|
// Increment width.
|
||||||
|
itemWidthSum += item.width + this.spacing;
|
||||||
|
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// If specified, ensure items fill row and distribute error
|
||||||
|
// caused by rounding width and height across all items.
|
||||||
|
if (widowLayoutStyle === 'justify') {
|
||||||
|
|
||||||
|
itemWidthSum -= (this.spacing + this.left);
|
||||||
|
|
||||||
|
errorWidthPerItem = (itemWidthSum - this.width) / this.items.length;
|
||||||
|
roundedCumulativeErrors = this.items.map(function (item, i) {
|
||||||
|
return Math.round((i + 1) * errorWidthPerItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (this.items.length === 1) {
|
||||||
|
|
||||||
|
// For rows with only one item, adjust item width to fill row.
|
||||||
|
singleItemGeometry = this.items[0];
|
||||||
|
singleItemGeometry.width -= Math.round(errorWidthPerItem);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// For rows with multiple items, adjust item width and shift items to fill the row,
|
||||||
|
// while maintaining equal spacing between items in the row.
|
||||||
|
this.items.forEach(function (item, i) {
|
||||||
|
if (i > 0) {
|
||||||
|
item.left -= roundedCumulativeErrors[i - 1];
|
||||||
|
item.width -= (roundedCumulativeErrors[i] - roundedCumulativeErrors[i - 1]);
|
||||||
|
} else {
|
||||||
|
item.width -= roundedCumulativeErrors[i];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (widowLayoutStyle === 'center') {
|
||||||
|
|
||||||
|
// Center widows
|
||||||
|
centerOffset = (this.width - itemWidthSum) / 2;
|
||||||
|
|
||||||
|
this.items.forEach(function (item) {
|
||||||
|
item.left += centerOffset + this.spacing;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force completion of row layout with current items.
|
||||||
|
*
|
||||||
|
* @method forceComplete
|
||||||
|
* @param fitToWidth {Boolean} Stretch current items to fill the row width.
|
||||||
|
* This will likely result in padding.
|
||||||
|
* @param fitToWidth {Number}
|
||||||
|
*/
|
||||||
|
|
||||||
|
forceComplete: function (fitToWidth, rowHeight) {
|
||||||
|
|
||||||
|
// TODO Handle fitting to width
|
||||||
|
// var rowWidthWithoutSpacing = this.width - (this.items.length - 1) * this.spacing,
|
||||||
|
// currentAspectRatio = this.items.reduce(function (sum, item) {
|
||||||
|
// return sum + item.aspectRatio;
|
||||||
|
// }, 0);
|
||||||
|
|
||||||
|
if (typeof rowHeight === 'number') {
|
||||||
|
|
||||||
|
this.completeLayout(rowHeight, this.widowLayoutStyle);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Complete using target row height.
|
||||||
|
this.completeLayout(this.targetRowHeight, this.widowLayoutStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return layout data for items within row.
|
||||||
|
* Note: returns actual list, not a copy.
|
||||||
|
*
|
||||||
|
* @method getItems
|
||||||
|
* @return Layout data for items within row.
|
||||||
|
*/
|
||||||
|
|
||||||
|
getItems: function () {
|
||||||
|
return this.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
805
themes/gallery/assets/js/lazysizes.js
Normal file
805
themes/gallery/assets/js/lazysizes.js
Normal file
@@ -0,0 +1,805 @@
|
|||||||
|
(function (window, factory) {
|
||||||
|
var lazySizes = factory(window, window.document, Date);
|
||||||
|
window.lazySizes = lazySizes;
|
||||||
|
if (typeof module == "object" && module.exports) {
|
||||||
|
module.exports = lazySizes;
|
||||||
|
}
|
||||||
|
})(
|
||||||
|
typeof window != "undefined" ? window : {},
|
||||||
|
/**
|
||||||
|
* import("./types/global")
|
||||||
|
* @typedef { import("./types/lazysizes-config").LazySizesConfigPartial } LazySizesConfigPartial
|
||||||
|
*/
|
||||||
|
function l(window, document, Date) {
|
||||||
|
// Pass in the window Date function also for SSR because the Date class can be lost
|
||||||
|
"use strict";
|
||||||
|
/*jshint eqnull:true */
|
||||||
|
|
||||||
|
var lazysizes,
|
||||||
|
/**
|
||||||
|
* @type { LazySizesConfigPartial }
|
||||||
|
*/
|
||||||
|
lazySizesCfg;
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var prop;
|
||||||
|
|
||||||
|
var lazySizesDefaults = {
|
||||||
|
lazyClass: "lazyload",
|
||||||
|
loadedClass: "lazyloaded",
|
||||||
|
loadingClass: "lazyloading",
|
||||||
|
preloadClass: "lazypreload",
|
||||||
|
errorClass: "lazyerror",
|
||||||
|
//strictClass: 'lazystrict',
|
||||||
|
autosizesClass: "lazyautosizes",
|
||||||
|
fastLoadedClass: "ls-is-cached",
|
||||||
|
iframeLoadMode: 0,
|
||||||
|
srcAttr: "data-src",
|
||||||
|
srcsetAttr: "data-srcset",
|
||||||
|
sizesAttr: "data-sizes",
|
||||||
|
//preloadAfterLoad: false,
|
||||||
|
minSize: 40,
|
||||||
|
customMedia: {},
|
||||||
|
init: true,
|
||||||
|
expFactor: 1.5,
|
||||||
|
hFac: 0.8,
|
||||||
|
loadMode: 2,
|
||||||
|
loadHidden: true,
|
||||||
|
ricTimeout: 0,
|
||||||
|
throttleDelay: 125,
|
||||||
|
};
|
||||||
|
|
||||||
|
lazySizesCfg = window.lazySizesConfig || window.lazysizesConfig || {};
|
||||||
|
|
||||||
|
for (prop in lazySizesDefaults) {
|
||||||
|
if (!(prop in lazySizesCfg)) {
|
||||||
|
lazySizesCfg[prop] = lazySizesDefaults[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (!document || !document.getElementsByClassName) {
|
||||||
|
return {
|
||||||
|
init: function () {},
|
||||||
|
/**
|
||||||
|
* @type { LazySizesConfigPartial }
|
||||||
|
*/
|
||||||
|
cfg: lazySizesCfg,
|
||||||
|
/**
|
||||||
|
* @type { true }
|
||||||
|
*/
|
||||||
|
noSupport: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var docElem = document.documentElement;
|
||||||
|
|
||||||
|
var supportPicture = window.HTMLPictureElement;
|
||||||
|
|
||||||
|
var _addEventListener = "addEventListener";
|
||||||
|
|
||||||
|
var _getAttribute = "getAttribute";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update to bind to window because 'this' becomes null during SSR
|
||||||
|
* builds.
|
||||||
|
*/
|
||||||
|
var addEventListener = window[_addEventListener].bind(window);
|
||||||
|
|
||||||
|
var setTimeout = window.setTimeout;
|
||||||
|
|
||||||
|
var requestAnimationFrame = window.requestAnimationFrame || setTimeout;
|
||||||
|
|
||||||
|
var requestIdleCallback = window.requestIdleCallback;
|
||||||
|
|
||||||
|
var regPicture = /^picture$/i;
|
||||||
|
|
||||||
|
var loadEvents = ["load", "error", "lazyincluded", "_lazyloaded"];
|
||||||
|
|
||||||
|
var regClassCache = {};
|
||||||
|
|
||||||
|
var forEach = Array.prototype.forEach;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ele {Element}
|
||||||
|
* @param cls {string}
|
||||||
|
*/
|
||||||
|
var hasClass = function (ele, cls) {
|
||||||
|
if (!regClassCache[cls]) {
|
||||||
|
regClassCache[cls] = new RegExp("(\\s|^)" + cls + "(\\s|$)");
|
||||||
|
}
|
||||||
|
return regClassCache[cls].test(ele[_getAttribute]("class") || "") && regClassCache[cls];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ele {Element}
|
||||||
|
* @param cls {string}
|
||||||
|
*/
|
||||||
|
var addClass = function (ele, cls) {
|
||||||
|
if (!hasClass(ele, cls)) {
|
||||||
|
ele.setAttribute("class", (ele[_getAttribute]("class") || "").trim() + " " + cls);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ele {Element}
|
||||||
|
* @param cls {string}
|
||||||
|
*/
|
||||||
|
var removeClass = function (ele, cls) {
|
||||||
|
var reg;
|
||||||
|
if ((reg = hasClass(ele, cls))) {
|
||||||
|
ele.setAttribute("class", (ele[_getAttribute]("class") || "").replace(reg, " "));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var addRemoveLoadEvents = function (dom, fn, add) {
|
||||||
|
var action = add ? _addEventListener : "removeEventListener";
|
||||||
|
if (add) {
|
||||||
|
addRemoveLoadEvents(dom, fn);
|
||||||
|
}
|
||||||
|
loadEvents.forEach(function (evt) {
|
||||||
|
dom[action](evt, fn);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param elem { Element }
|
||||||
|
* @param name { string }
|
||||||
|
* @param detail { any }
|
||||||
|
* @param noBubbles { boolean }
|
||||||
|
* @param noCancelable { boolean }
|
||||||
|
* @returns { CustomEvent }
|
||||||
|
*/
|
||||||
|
var triggerEvent = function (elem, name, detail, noBubbles, noCancelable) {
|
||||||
|
var event = document.createEvent("Event");
|
||||||
|
|
||||||
|
if (!detail) {
|
||||||
|
detail = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
detail.instance = lazysizes;
|
||||||
|
|
||||||
|
event.initEvent(name, !noBubbles, !noCancelable);
|
||||||
|
|
||||||
|
event.detail = detail;
|
||||||
|
|
||||||
|
elem.dispatchEvent(event);
|
||||||
|
return event;
|
||||||
|
};
|
||||||
|
|
||||||
|
var updatePolyfill = function (el, full) {
|
||||||
|
var polyfill;
|
||||||
|
if (!supportPicture && (polyfill = window.picturefill || lazySizesCfg.pf)) {
|
||||||
|
if (full && full.src && !el[_getAttribute]("srcset")) {
|
||||||
|
el.setAttribute("srcset", full.src);
|
||||||
|
}
|
||||||
|
polyfill({ reevaluate: true, elements: [el] });
|
||||||
|
} else if (full && full.src) {
|
||||||
|
el.src = full.src;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var getCSS = function (elem, style) {
|
||||||
|
return (getComputedStyle(elem, null) || {})[style];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param elem { Element }
|
||||||
|
* @param parent { Element }
|
||||||
|
* @param [width] {number}
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
var getWidth = function (elem, parent, width) {
|
||||||
|
width = width || elem.offsetWidth;
|
||||||
|
|
||||||
|
while (width < lazySizesCfg.minSize && parent && !elem._lazysizesWidth) {
|
||||||
|
width = parent.offsetWidth;
|
||||||
|
parent = parent.parentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return width;
|
||||||
|
};
|
||||||
|
|
||||||
|
var rAF = (function () {
|
||||||
|
var running, waiting;
|
||||||
|
var firstFns = [];
|
||||||
|
var secondFns = [];
|
||||||
|
var fns = firstFns;
|
||||||
|
|
||||||
|
var run = function () {
|
||||||
|
var runFns = fns;
|
||||||
|
|
||||||
|
fns = firstFns.length ? secondFns : firstFns;
|
||||||
|
|
||||||
|
running = true;
|
||||||
|
waiting = false;
|
||||||
|
|
||||||
|
while (runFns.length) {
|
||||||
|
runFns.shift()();
|
||||||
|
}
|
||||||
|
|
||||||
|
running = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
var rafBatch = function (fn, queue) {
|
||||||
|
if (running && !queue) {
|
||||||
|
fn.apply(this, arguments);
|
||||||
|
} else {
|
||||||
|
fns.push(fn);
|
||||||
|
|
||||||
|
if (!waiting) {
|
||||||
|
waiting = true;
|
||||||
|
(document.hidden ? setTimeout : requestAnimationFrame)(run);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
rafBatch._lsFlush = run;
|
||||||
|
|
||||||
|
return rafBatch;
|
||||||
|
})();
|
||||||
|
|
||||||
|
var rAFIt = function (fn, simple) {
|
||||||
|
return simple
|
||||||
|
? function () {
|
||||||
|
rAF(fn);
|
||||||
|
}
|
||||||
|
: function () {
|
||||||
|
var that = this;
|
||||||
|
var args = arguments;
|
||||||
|
rAF(function () {
|
||||||
|
fn.apply(that, args);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var throttle = function (fn) {
|
||||||
|
var running;
|
||||||
|
var lastTime = 0;
|
||||||
|
var gDelay = lazySizesCfg.throttleDelay;
|
||||||
|
var rICTimeout = lazySizesCfg.ricTimeout;
|
||||||
|
var run = function () {
|
||||||
|
running = false;
|
||||||
|
lastTime = Date.now();
|
||||||
|
fn();
|
||||||
|
};
|
||||||
|
var idleCallback =
|
||||||
|
requestIdleCallback && rICTimeout > 49
|
||||||
|
? function () {
|
||||||
|
requestIdleCallback(run, { timeout: rICTimeout });
|
||||||
|
|
||||||
|
if (rICTimeout !== lazySizesCfg.ricTimeout) {
|
||||||
|
rICTimeout = lazySizesCfg.ricTimeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: rAFIt(function () {
|
||||||
|
setTimeout(run);
|
||||||
|
}, true);
|
||||||
|
return function (isPriority) {
|
||||||
|
var delay;
|
||||||
|
|
||||||
|
if ((isPriority = isPriority === true)) {
|
||||||
|
rICTimeout = 33;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
running = true;
|
||||||
|
|
||||||
|
delay = gDelay - (Date.now() - lastTime);
|
||||||
|
|
||||||
|
if (delay < 0) {
|
||||||
|
delay = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPriority || delay < 9) {
|
||||||
|
idleCallback();
|
||||||
|
} else {
|
||||||
|
setTimeout(idleCallback, delay);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//based on http://modernjavascript.blogspot.de/2013/08/building-better-debounce.html
|
||||||
|
var debounce = function (func) {
|
||||||
|
var timeout, timestamp;
|
||||||
|
var wait = 99;
|
||||||
|
var run = function () {
|
||||||
|
timeout = null;
|
||||||
|
func();
|
||||||
|
};
|
||||||
|
var later = function () {
|
||||||
|
var last = Date.now() - timestamp;
|
||||||
|
|
||||||
|
if (last < wait) {
|
||||||
|
setTimeout(later, wait - last);
|
||||||
|
} else {
|
||||||
|
(requestIdleCallback || run)(run);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return function () {
|
||||||
|
timestamp = Date.now();
|
||||||
|
|
||||||
|
if (!timeout) {
|
||||||
|
timeout = setTimeout(later, wait);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var loader = (function () {
|
||||||
|
var preloadElems, isCompleted, resetPreloadingTimer, loadMode, started;
|
||||||
|
|
||||||
|
var eLvW, elvH, eLtop, eLleft, eLright, eLbottom, isBodyHidden;
|
||||||
|
|
||||||
|
var regImg = /^img$/i;
|
||||||
|
var regIframe = /^iframe$/i;
|
||||||
|
|
||||||
|
var supportScroll = "onscroll" in window && !/(gle|ing)bot/.test(navigator.userAgent);
|
||||||
|
|
||||||
|
var shrinkExpand = 0;
|
||||||
|
var currentExpand = 0;
|
||||||
|
|
||||||
|
var isLoading = 0;
|
||||||
|
var lowRuns = -1;
|
||||||
|
|
||||||
|
var resetPreloading = function (e) {
|
||||||
|
isLoading--;
|
||||||
|
if (!e || isLoading < 0 || !e.target) {
|
||||||
|
isLoading = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var isVisible = function (elem) {
|
||||||
|
if (isBodyHidden == null) {
|
||||||
|
isBodyHidden = getCSS(document.body, "visibility") == "hidden";
|
||||||
|
}
|
||||||
|
|
||||||
|
return isBodyHidden || !(getCSS(elem.parentNode, "visibility") == "hidden" && getCSS(elem, "visibility") == "hidden");
|
||||||
|
};
|
||||||
|
|
||||||
|
var isNestedVisible = function (elem, elemExpand) {
|
||||||
|
var outerRect;
|
||||||
|
var parent = elem;
|
||||||
|
var visible = isVisible(elem);
|
||||||
|
|
||||||
|
eLtop -= elemExpand;
|
||||||
|
eLbottom += elemExpand;
|
||||||
|
eLleft -= elemExpand;
|
||||||
|
eLright += elemExpand;
|
||||||
|
|
||||||
|
while (visible && (parent = parent.offsetParent) && parent != document.body && parent != docElem) {
|
||||||
|
visible = (getCSS(parent, "opacity") || 1) > 0;
|
||||||
|
|
||||||
|
if (visible && getCSS(parent, "overflow") != "visible") {
|
||||||
|
outerRect = parent.getBoundingClientRect();
|
||||||
|
visible = eLright > outerRect.left && eLleft < outerRect.right && eLbottom > outerRect.top - 1 && eLtop < outerRect.bottom + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return visible;
|
||||||
|
};
|
||||||
|
|
||||||
|
var checkElements = function () {
|
||||||
|
var eLlen, i, rect, autoLoadElem, loadedSomething, elemExpand, elemNegativeExpand, elemExpandVal, beforeExpandVal, defaultExpand, preloadExpand, hFac;
|
||||||
|
var lazyloadElems = lazysizes.elements;
|
||||||
|
|
||||||
|
if ((loadMode = lazySizesCfg.loadMode) && isLoading < 8 && (eLlen = lazyloadElems.length)) {
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
lowRuns++;
|
||||||
|
|
||||||
|
for (; i < eLlen; i++) {
|
||||||
|
if (!lazyloadElems[i] || lazyloadElems[i]._lazyRace) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!supportScroll || (lazysizes.prematureUnveil && lazysizes.prematureUnveil(lazyloadElems[i]))) {
|
||||||
|
unveilElement(lazyloadElems[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(elemExpandVal = lazyloadElems[i][_getAttribute]("data-expand")) || !(elemExpand = elemExpandVal * 1)) {
|
||||||
|
elemExpand = currentExpand;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defaultExpand) {
|
||||||
|
defaultExpand = !lazySizesCfg.expand || lazySizesCfg.expand < 1 ? (docElem.clientHeight > 500 && docElem.clientWidth > 500 ? 500 : 370) : lazySizesCfg.expand;
|
||||||
|
|
||||||
|
lazysizes._defEx = defaultExpand;
|
||||||
|
|
||||||
|
preloadExpand = defaultExpand * lazySizesCfg.expFactor;
|
||||||
|
hFac = lazySizesCfg.hFac;
|
||||||
|
isBodyHidden = null;
|
||||||
|
|
||||||
|
if (currentExpand < preloadExpand && isLoading < 1 && lowRuns > 2 && loadMode > 2 && !document.hidden) {
|
||||||
|
currentExpand = preloadExpand;
|
||||||
|
lowRuns = 0;
|
||||||
|
} else if (loadMode > 1 && lowRuns > 1 && isLoading < 6) {
|
||||||
|
currentExpand = defaultExpand;
|
||||||
|
} else {
|
||||||
|
currentExpand = shrinkExpand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beforeExpandVal !== elemExpand) {
|
||||||
|
eLvW = innerWidth + elemExpand * hFac;
|
||||||
|
elvH = innerHeight + elemExpand;
|
||||||
|
elemNegativeExpand = elemExpand * -1;
|
||||||
|
beforeExpandVal = elemExpand;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect = lazyloadElems[i].getBoundingClientRect();
|
||||||
|
|
||||||
|
if ((eLbottom = rect.bottom) >= elemNegativeExpand && (eLtop = rect.top) <= elvH && (eLright = rect.right) >= elemNegativeExpand * hFac && (eLleft = rect.left) <= eLvW && (eLbottom || eLright || eLleft || eLtop) && (lazySizesCfg.loadHidden || isVisible(lazyloadElems[i])) && ((isCompleted && isLoading < 3 && !elemExpandVal && (loadMode < 3 || lowRuns < 4)) || isNestedVisible(lazyloadElems[i], elemExpand))) {
|
||||||
|
unveilElement(lazyloadElems[i]);
|
||||||
|
loadedSomething = true;
|
||||||
|
if (isLoading > 9) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (!loadedSomething && isCompleted && !autoLoadElem && isLoading < 4 && lowRuns < 4 && loadMode > 2 && (preloadElems[0] || lazySizesCfg.preloadAfterLoad) && (preloadElems[0] || (!elemExpandVal && (eLbottom || eLright || eLleft || eLtop || lazyloadElems[i][_getAttribute](lazySizesCfg.sizesAttr) != "auto")))) {
|
||||||
|
autoLoadElem = preloadElems[0] || lazyloadElems[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoLoadElem && !loadedSomething) {
|
||||||
|
unveilElement(autoLoadElem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var throttledCheckElements = throttle(checkElements);
|
||||||
|
|
||||||
|
var switchLoadingClass = function (e) {
|
||||||
|
var elem = e.target;
|
||||||
|
|
||||||
|
if (elem._lazyCache) {
|
||||||
|
delete elem._lazyCache;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetPreloading(e);
|
||||||
|
addClass(elem, lazySizesCfg.loadedClass);
|
||||||
|
removeClass(elem, lazySizesCfg.loadingClass);
|
||||||
|
addRemoveLoadEvents(elem, rafSwitchLoadingClass);
|
||||||
|
triggerEvent(elem, "lazyloaded");
|
||||||
|
};
|
||||||
|
var rafedSwitchLoadingClass = rAFIt(switchLoadingClass);
|
||||||
|
var rafSwitchLoadingClass = function (e) {
|
||||||
|
rafedSwitchLoadingClass({ target: e.target });
|
||||||
|
};
|
||||||
|
|
||||||
|
var changeIframeSrc = function (elem, src) {
|
||||||
|
var loadMode = elem.getAttribute("data-load-mode") || lazySizesCfg.iframeLoadMode;
|
||||||
|
|
||||||
|
// loadMode can be also a string!
|
||||||
|
if (loadMode == 0) {
|
||||||
|
elem.contentWindow.location.replace(src);
|
||||||
|
} else if (loadMode == 1) {
|
||||||
|
elem.src = src;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var handleSources = function (source) {
|
||||||
|
var customMedia;
|
||||||
|
|
||||||
|
var sourceSrcset = source[_getAttribute](lazySizesCfg.srcsetAttr);
|
||||||
|
|
||||||
|
if ((customMedia = lazySizesCfg.customMedia[source[_getAttribute]("data-media") || source[_getAttribute]("media")])) {
|
||||||
|
source.setAttribute("media", customMedia);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceSrcset) {
|
||||||
|
source.setAttribute("srcset", sourceSrcset);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var lazyUnveil = rAFIt(function (elem, detail, isAuto, sizes, isImg) {
|
||||||
|
var src, srcset, parent, isPicture, event, firesLoad;
|
||||||
|
|
||||||
|
if (!(event = triggerEvent(elem, "lazybeforeunveil", detail)).defaultPrevented) {
|
||||||
|
if (sizes) {
|
||||||
|
if (isAuto) {
|
||||||
|
addClass(elem, lazySizesCfg.autosizesClass);
|
||||||
|
} else {
|
||||||
|
elem.setAttribute("sizes", sizes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srcset = elem[_getAttribute](lazySizesCfg.srcsetAttr);
|
||||||
|
src = elem[_getAttribute](lazySizesCfg.srcAttr);
|
||||||
|
|
||||||
|
if (isImg) {
|
||||||
|
parent = elem.parentNode;
|
||||||
|
isPicture = parent && regPicture.test(parent.nodeName || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
firesLoad = detail.firesLoad || ("src" in elem && (srcset || src || isPicture));
|
||||||
|
|
||||||
|
event = { target: elem };
|
||||||
|
|
||||||
|
addClass(elem, lazySizesCfg.loadingClass);
|
||||||
|
|
||||||
|
if (firesLoad) {
|
||||||
|
clearTimeout(resetPreloadingTimer);
|
||||||
|
resetPreloadingTimer = setTimeout(resetPreloading, 2500);
|
||||||
|
addRemoveLoadEvents(elem, rafSwitchLoadingClass, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPicture) {
|
||||||
|
forEach.call(parent.getElementsByTagName("source"), handleSources);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcset) {
|
||||||
|
elem.setAttribute("srcset", srcset);
|
||||||
|
} else if (src && !isPicture) {
|
||||||
|
if (regIframe.test(elem.nodeName)) {
|
||||||
|
changeIframeSrc(elem, src);
|
||||||
|
} else {
|
||||||
|
elem.src = src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isImg && (srcset || isPicture)) {
|
||||||
|
updatePolyfill(elem, { src: src });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elem._lazyRace) {
|
||||||
|
delete elem._lazyRace;
|
||||||
|
}
|
||||||
|
removeClass(elem, lazySizesCfg.lazyClass);
|
||||||
|
|
||||||
|
rAF(function () {
|
||||||
|
// Part of this can be removed as soon as this fix is older: https://bugs.chromium.org/p/chromium/issues/detail?id=7731 (2015)
|
||||||
|
var isLoaded = elem.complete && elem.naturalWidth > 1;
|
||||||
|
|
||||||
|
if (!firesLoad || isLoaded) {
|
||||||
|
if (isLoaded) {
|
||||||
|
addClass(elem, lazySizesCfg.fastLoadedClass);
|
||||||
|
}
|
||||||
|
switchLoadingClass(event);
|
||||||
|
elem._lazyCache = true;
|
||||||
|
setTimeout(function () {
|
||||||
|
if ("_lazyCache" in elem) {
|
||||||
|
delete elem._lazyCache;
|
||||||
|
}
|
||||||
|
}, 9);
|
||||||
|
}
|
||||||
|
if (elem.loading == "lazy") {
|
||||||
|
isLoading--;
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param elem { Element }
|
||||||
|
*/
|
||||||
|
var unveilElement = function (elem) {
|
||||||
|
if (elem._lazyRace) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var detail;
|
||||||
|
|
||||||
|
var isImg = regImg.test(elem.nodeName);
|
||||||
|
|
||||||
|
//allow using sizes="auto", but don't use. it's invalid. Use data-sizes="auto" or a valid value for sizes instead (i.e.: sizes="80vw")
|
||||||
|
var sizes = isImg && (elem[_getAttribute](lazySizesCfg.sizesAttr) || elem[_getAttribute]("sizes"));
|
||||||
|
var isAuto = sizes == "auto";
|
||||||
|
|
||||||
|
if ((isAuto || !isCompleted) && isImg && (elem[_getAttribute]("src") || elem.srcset) && !elem.complete && !hasClass(elem, lazySizesCfg.errorClass) && hasClass(elem, lazySizesCfg.lazyClass)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
detail = triggerEvent(elem, "lazyunveilread").detail;
|
||||||
|
|
||||||
|
if (isAuto) {
|
||||||
|
autoSizer.updateElem(elem, true, elem.offsetWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
elem._lazyRace = true;
|
||||||
|
isLoading++;
|
||||||
|
|
||||||
|
lazyUnveil(elem, detail, isAuto, sizes, isImg);
|
||||||
|
};
|
||||||
|
|
||||||
|
var afterScroll = debounce(function () {
|
||||||
|
lazySizesCfg.loadMode = 3;
|
||||||
|
throttledCheckElements();
|
||||||
|
});
|
||||||
|
|
||||||
|
var altLoadmodeScrollListner = function () {
|
||||||
|
if (lazySizesCfg.loadMode == 3) {
|
||||||
|
lazySizesCfg.loadMode = 2;
|
||||||
|
}
|
||||||
|
afterScroll();
|
||||||
|
};
|
||||||
|
|
||||||
|
var onload = function () {
|
||||||
|
if (isCompleted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Date.now() - started < 999) {
|
||||||
|
setTimeout(onload, 999);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isCompleted = true;
|
||||||
|
|
||||||
|
lazySizesCfg.loadMode = 3;
|
||||||
|
|
||||||
|
throttledCheckElements();
|
||||||
|
|
||||||
|
addEventListener("scroll", altLoadmodeScrollListner, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
_: function () {
|
||||||
|
started = Date.now();
|
||||||
|
|
||||||
|
lazysizes.elements = document.getElementsByClassName(lazySizesCfg.lazyClass);
|
||||||
|
preloadElems = document.getElementsByClassName(lazySizesCfg.lazyClass + " " + lazySizesCfg.preloadClass);
|
||||||
|
|
||||||
|
addEventListener("scroll", throttledCheckElements, true);
|
||||||
|
|
||||||
|
addEventListener("resize", throttledCheckElements, true);
|
||||||
|
|
||||||
|
addEventListener("pageshow", function (e) {
|
||||||
|
if (e.persisted) {
|
||||||
|
var loadingElements = document.querySelectorAll("." + lazySizesCfg.loadingClass);
|
||||||
|
|
||||||
|
if (loadingElements.length && loadingElements.forEach) {
|
||||||
|
requestAnimationFrame(function () {
|
||||||
|
loadingElements.forEach(function (img) {
|
||||||
|
if (img.complete) {
|
||||||
|
unveilElement(img);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window.MutationObserver) {
|
||||||
|
new MutationObserver(throttledCheckElements).observe(docElem, { childList: true, subtree: true, attributes: true });
|
||||||
|
} else {
|
||||||
|
docElem[_addEventListener]("DOMNodeInserted", throttledCheckElements, true);
|
||||||
|
docElem[_addEventListener]("DOMAttrModified", throttledCheckElements, true);
|
||||||
|
setInterval(throttledCheckElements, 999);
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener("hashchange", throttledCheckElements, true);
|
||||||
|
|
||||||
|
//, 'fullscreenchange'
|
||||||
|
["focus", "mouseover", "click", "load", "transitionend", "animationend"].forEach(function (name) {
|
||||||
|
document[_addEventListener](name, throttledCheckElements, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (/d$|^c/.test(document.readyState)) {
|
||||||
|
onload();
|
||||||
|
} else {
|
||||||
|
addEventListener("load", onload);
|
||||||
|
document[_addEventListener]("DOMContentLoaded", throttledCheckElements);
|
||||||
|
setTimeout(onload, 20000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lazysizes.elements.length) {
|
||||||
|
checkElements();
|
||||||
|
rAF._lsFlush();
|
||||||
|
} else {
|
||||||
|
throttledCheckElements();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkElems: throttledCheckElements,
|
||||||
|
unveil: unveilElement,
|
||||||
|
_aLSL: altLoadmodeScrollListner,
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
var autoSizer = (function () {
|
||||||
|
var autosizesElems;
|
||||||
|
|
||||||
|
var sizeElement = rAFIt(function (elem, parent, event, width) {
|
||||||
|
var sources, i, len;
|
||||||
|
elem._lazysizesWidth = width;
|
||||||
|
width += "px";
|
||||||
|
|
||||||
|
elem.setAttribute("sizes", width);
|
||||||
|
|
||||||
|
if (regPicture.test(parent.nodeName || "")) {
|
||||||
|
sources = parent.getElementsByTagName("source");
|
||||||
|
for (i = 0, len = sources.length; i < len; i++) {
|
||||||
|
sources[i].setAttribute("sizes", width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!event.detail.dataAttr) {
|
||||||
|
updatePolyfill(elem, event.detail);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param elem {Element}
|
||||||
|
* @param dataAttr
|
||||||
|
* @param [width] { number }
|
||||||
|
*/
|
||||||
|
var getSizeElement = function (elem, dataAttr, width) {
|
||||||
|
var event;
|
||||||
|
var parent = elem.parentNode;
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
width = getWidth(elem, parent, width);
|
||||||
|
event = triggerEvent(elem, "lazybeforesizes", { width: width, dataAttr: !!dataAttr });
|
||||||
|
|
||||||
|
if (!event.defaultPrevented) {
|
||||||
|
width = event.detail.width;
|
||||||
|
|
||||||
|
if (width && width !== elem._lazysizesWidth) {
|
||||||
|
sizeElement(elem, parent, event, width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var updateElementsSizes = function () {
|
||||||
|
var i;
|
||||||
|
var len = autosizesElems.length;
|
||||||
|
if (len) {
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
for (; i < len; i++) {
|
||||||
|
getSizeElement(autosizesElems[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var debouncedUpdateElementsSizes = debounce(updateElementsSizes);
|
||||||
|
|
||||||
|
return {
|
||||||
|
_: function () {
|
||||||
|
autosizesElems = document.getElementsByClassName(lazySizesCfg.autosizesClass);
|
||||||
|
addEventListener("resize", debouncedUpdateElementsSizes);
|
||||||
|
},
|
||||||
|
checkElems: debouncedUpdateElementsSizes,
|
||||||
|
updateElem: getSizeElement,
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
var init = function () {
|
||||||
|
if (!init.i && document.getElementsByClassName) {
|
||||||
|
init.i = true;
|
||||||
|
autoSizer._();
|
||||||
|
loader._();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
if (lazySizesCfg.init) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
lazysizes = {
|
||||||
|
/**
|
||||||
|
* @type { LazySizesConfigPartial }
|
||||||
|
*/
|
||||||
|
cfg: lazySizesCfg,
|
||||||
|
autoSizer: autoSizer,
|
||||||
|
loader: loader,
|
||||||
|
init: init,
|
||||||
|
uP: updatePolyfill,
|
||||||
|
aC: addClass,
|
||||||
|
rC: removeClass,
|
||||||
|
hC: hasClass,
|
||||||
|
fire: triggerEvent,
|
||||||
|
gW: getWidth,
|
||||||
|
rAF: rAF,
|
||||||
|
};
|
||||||
|
|
||||||
|
return lazysizes;
|
||||||
|
},
|
||||||
|
);
|
||||||
83
themes/gallery/assets/js/lightbox.js
Normal file
83
themes/gallery/assets/js/lightbox.js
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import PhotoSwipeLightbox from "./photoswipe/photoswipe-lightbox.esm.js";
|
||||||
|
import PhotoSwipe from "./photoswipe/photoswipe.esm.js";
|
||||||
|
import PhotoSwipeDynamicCaption from "./photoswipe/photoswipe-dynamic-caption-plugin.esm.min.js";
|
||||||
|
import * as params from "@params";
|
||||||
|
|
||||||
|
const gallery = document.getElementById("gallery");
|
||||||
|
|
||||||
|
if (gallery) {
|
||||||
|
const lightbox = new PhotoSwipeLightbox({
|
||||||
|
gallery,
|
||||||
|
children: ".gallery-item",
|
||||||
|
showHideAnimationType: "zoom",
|
||||||
|
bgOpacity: 1,
|
||||||
|
pswpModule: PhotoSwipe,
|
||||||
|
imageClickAction: "close",
|
||||||
|
paddingFn: (viewportSize) => {
|
||||||
|
return viewportSize.x < 700
|
||||||
|
? {
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
top: 30,
|
||||||
|
bottom: 30,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
closeTitle: params.closeTitle,
|
||||||
|
zoomTitle: params.zoomTitle,
|
||||||
|
arrowPrevTitle: params.arrowPrevTitle,
|
||||||
|
arrowNextTitle: params.arrowNextTitle,
|
||||||
|
errorMsg: params.errorMsg,
|
||||||
|
});
|
||||||
|
|
||||||
|
lightbox.on("uiRegister", () => {
|
||||||
|
lightbox.pswp.ui.registerElement({
|
||||||
|
name: "download-button",
|
||||||
|
order: 8,
|
||||||
|
isButton: true,
|
||||||
|
tagName: "a",
|
||||||
|
html: {
|
||||||
|
isCustomSVG: true,
|
||||||
|
inner: '<path d="M20.5 14.3 17.1 18V10h-2.2v7.9l-3.4-3.6L10 16l6 6.1 6-6.1ZM23 23H9v2h14Z" id="pswp__icn-download"/>',
|
||||||
|
outlineID: "pswp__icn-download",
|
||||||
|
},
|
||||||
|
onInit: (el, pswp) => {
|
||||||
|
el.setAttribute("download", "");
|
||||||
|
el.setAttribute("target", "_blank");
|
||||||
|
el.setAttribute("rel", "noopener");
|
||||||
|
el.setAttribute("title", params.downloadTitle || "Download");
|
||||||
|
pswp.on("change", () => {
|
||||||
|
el.href = pswp.currSlide.data.element.href;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
lightbox.on("change", () => {
|
||||||
|
history.replaceState("", document.title, "#" + lightbox.pswp.currSlide.index);
|
||||||
|
});
|
||||||
|
|
||||||
|
lightbox.on("close", () => {
|
||||||
|
history.replaceState("", document.title, window.location.pathname);
|
||||||
|
});
|
||||||
|
|
||||||
|
new PhotoSwipeDynamicCaption(lightbox, {
|
||||||
|
mobileLayoutBreakpoint: 700,
|
||||||
|
type: "auto",
|
||||||
|
mobileCaptionOverlapRatio: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
lightbox.init();
|
||||||
|
|
||||||
|
if (window.location.hash.substring(1).length > 0) {
|
||||||
|
const index = parseInt(window.location.hash.substring(1), 10);
|
||||||
|
if (!Number.isNaN(index) && index >= 0 && index < gallery.querySelectorAll("a").length) {
|
||||||
|
lightbox.loadAndOpen(index, { gallery });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
themes/gallery/assets/js/main.js
Normal file
5
themes/gallery/assets/js/main.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import "./menu.js";
|
||||||
|
import "./gallery.js";
|
||||||
|
import "./lazysizes.js";
|
||||||
|
import "./lightbox.js";
|
||||||
|
import "./custom.js";
|
||||||
9
themes/gallery/assets/js/menu.js
Normal file
9
themes/gallery/assets/js/menu.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const el = document.getElementById("menu-toggle");
|
||||||
|
if (el) {
|
||||||
|
el.addEventListener("click", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const target = document.getElementById("menu");
|
||||||
|
el.ariaExpanded = target.classList.contains("hidden");
|
||||||
|
target.classList.toggle("hidden");
|
||||||
|
});
|
||||||
|
}
|
||||||
5
themes/gallery/assets/js/photoswipe/photoswipe-dynamic-caption-plugin.esm.min.js
vendored
Normal file
5
themes/gallery/assets/js/photoswipe/photoswipe-dynamic-caption-plugin.esm.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1960
themes/gallery/assets/js/photoswipe/photoswipe-lightbox.esm.js
Normal file
1960
themes/gallery/assets/js/photoswipe/photoswipe-lightbox.esm.js
Normal file
File diff suppressed because it is too large
Load Diff
7081
themes/gallery/assets/js/photoswipe/photoswipe.esm.js
Normal file
7081
themes/gallery/assets/js/photoswipe/photoswipe.esm.js
Normal file
File diff suppressed because it is too large
Load Diff
10
themes/gallery/assets/jsconfig.json
Normal file
10
themes/gallery/assets/jsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"*": [
|
||||||
|
"*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
themes/gallery/exampleSite/.gitignore
vendored
Normal file
6
themes/gallery/exampleSite/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
node_modules/
|
||||||
|
public/
|
||||||
|
resources/
|
||||||
|
.hugo_build.lock
|
||||||
|
hugo_stats.json
|
||||||
|
content/**/*.jpg
|
||||||
11
themes/gallery/exampleSite/README.md
Normal file
11
themes/gallery/exampleSite/README.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Example site for hugo-theme-gallery
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
# Install Hugo module
|
||||||
|
hugo mod get
|
||||||
|
|
||||||
|
# Pull example images from Unsplash
|
||||||
|
./pull-images.sh
|
||||||
|
```
|
||||||
10
themes/gallery/exampleSite/assets/css/custom.css
Normal file
10
themes/gallery/exampleSite/assets/css/custom.css
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
:root {
|
||||||
|
--surface-1-light: #ffffff;
|
||||||
|
--surface-2-light: #f0f0f0; /* gray-3 */
|
||||||
|
--text-1-light: #202020; /* gray-12 */
|
||||||
|
--text-2-light: #646464; /* gray-11 */
|
||||||
|
--surface-1-dark: #111111; /* gray-1-dark */
|
||||||
|
--surface-2-dark: #222222; /* gray-3-dark */
|
||||||
|
--text-1-dark: #eeeeee; /* gray-12-dark */
|
||||||
|
--text-2-dark: #b4b4b4; /* gray-11-dark */
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user