jekyll_picture_tag 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +24 -0
  6. data/Rakefile +1 -0
  7. data/bin/console +14 -0
  8. data/bin/setup +7 -0
  9. data/examples/_config.yml +4 -0
  10. data/examples/_data/picture.yml +85 -0
  11. data/examples/post.md +18 -0
  12. data/jekyll_picture_tag.gemspec +39 -0
  13. data/lib/jekyll_picture_tag.rb +67 -0
  14. data/lib/jekyll_picture_tag/defaults/global.yml +10 -0
  15. data/lib/jekyll_picture_tag/defaults/presets.yml +7 -0
  16. data/lib/jekyll_picture_tag/generated_image.rb +66 -0
  17. data/lib/jekyll_picture_tag/instructions.rb +105 -0
  18. data/lib/jekyll_picture_tag/instructions/configuration.rb +82 -0
  19. data/lib/jekyll_picture_tag/instructions/html_attributes.rb +59 -0
  20. data/lib/jekyll_picture_tag/instructions/preset.rb +61 -0
  21. data/lib/jekyll_picture_tag/instructions/tag_parser.rb +48 -0
  22. data/lib/jekyll_picture_tag/output_formats.rb +9 -0
  23. data/lib/jekyll_picture_tag/output_formats/auto.rb +15 -0
  24. data/lib/jekyll_picture_tag/output_formats/basics.rb +105 -0
  25. data/lib/jekyll_picture_tag/output_formats/data_attributes.rb +44 -0
  26. data/lib/jekyll_picture_tag/output_formats/data_auto.rb +14 -0
  27. data/lib/jekyll_picture_tag/output_formats/data_img.rb +8 -0
  28. data/lib/jekyll_picture_tag/output_formats/data_picture.rb +8 -0
  29. data/lib/jekyll_picture_tag/output_formats/direct_url.rb +13 -0
  30. data/lib/jekyll_picture_tag/output_formats/img.rb +24 -0
  31. data/lib/jekyll_picture_tag/output_formats/picture.rb +66 -0
  32. data/lib/jekyll_picture_tag/source_image.rb +62 -0
  33. data/lib/jekyll_picture_tag/srcsets.rb +3 -0
  34. data/lib/jekyll_picture_tag/srcsets/basics.rb +88 -0
  35. data/lib/jekyll_picture_tag/srcsets/pixel_ratio.rb +32 -0
  36. data/lib/jekyll_picture_tag/srcsets/width.rb +45 -0
  37. data/lib/jekyll_picture_tag/utils.rb +67 -0
  38. data/lib/jekyll_picture_tag/version.rb +3 -0
  39. data/migration.md +178 -0
  40. data/readme.md +787 -0
  41. metadata +191 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b7fc61d571c945d859aac14c2a85a9b80752c3642a314456c89516ae7c9632d4
4
+ data.tar.gz: 27f70f0b0a73101606ef098a4aceaf8183356607b9d3145c5bb514c9ea9c92cb
5
+ SHA512:
6
+ metadata.gz: b008e590e962f46f83de4506b9c0a1da77f887b89987442ef9af9756987dd1bbaaa9964703ed2da3245496c02ca0fa274014a788bfd623aa719e6d098a665d4b
7
+ data.tar.gz: 795bf04f0b5aa155f6386bb41f33d12643699ff0065cc88f80273589179234d1ba26b801aa12da6028b03283365309ea4449038386820eaa3b1f0a634d023dac
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .idea
11
+ jekyll-picture-tag.iml
@@ -0,0 +1 @@
1
+ 2.5.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jekyll-picture-tag.gemspec
4
+ gemspec
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2013, Robert Wierzbowski
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+ * Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ * Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+ * Neither the name of the <organization> nor the
12
+ names of its contributors may be used to endorse or promote products
13
+ derived from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'jekyll-picture-tag'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,4 @@
1
+ # Sample Jekyll Picture Tag settings
2
+ picture:
3
+ source: assets/images/_fullsize
4
+ output: generated
@@ -0,0 +1,85 @@
1
+ # Example picture presets:
2
+ # TODO: change to EMs, because safari sucks.
3
+
4
+ # Media presets are used in several places:
5
+ # - To specify alternate source images (for art direction)
6
+ # - To build the 'sizes' attribute
7
+ # - When given alternate source images, specify which sizes to generate.
8
+ media_presets:
9
+ wide_desktop: 'min-width: 1801px'
10
+ desktop: 'max-width: 1800px'
11
+ wide_tablet: 'max-width: 1200px'
12
+ tablet: 'max-width: 900px'
13
+ mobile: 'max-width: 600px'
14
+
15
+ # Markup presets allow you to group settings together, and select one of them by name in your jekyll
16
+ # tag. All settings are optional.
17
+ markup_presets:
18
+ default:
19
+
20
+ # Optionally specify a markup type. Your current options are 'picture', 'img', or 'auto'
21
+ # (default).
22
+ markup: auto
23
+
24
+ # Must be an array, in order of decreasing preference. Defaults to just 'original'.
25
+ formats: [webp, original]
26
+
27
+ # Must be an array: which image sizes (width in pixels) to generate (unless directed otherwise
28
+ # below). If not specified, will use sensible default values.
29
+ widths: [200, 400, 800, 1600]
30
+
31
+ # Alternate source images (for art direction) are associated with media query presets. Here, you
32
+ # can optionally specify a different set of sizes to generate for those alternate source images.
33
+ # This is how you avoid generating a 1800 pixel wide image that's only shown on narrow screens.
34
+ # Must be arrays.
35
+ media_widths:
36
+ mobile: [200, 400, 600]
37
+ tablet: [400, 600, 800]
38
+
39
+ # Specifies an optional, unconditional size attribute. Can be given alone, or if specified in
40
+ # combination with 'sizes' below, will be given last (when no media queries apply).
41
+ size: 800px
42
+
43
+ # For building the 'sizes' attribute on img and source tags. specifies how wide the image will
44
+ # be when a given media query is true. Note that every source in a given <picture> tag will have
45
+ # the same associated sizes attribute.
46
+ sizes:
47
+ mobile: 100vw
48
+ desktop: 60vw
49
+
50
+ # Specify the properties of the fallback image. If not specified, will return a 900 pixel
51
+ # wide image in the original format.
52
+ fallback_width: 800
53
+ fallback_format: original
54
+
55
+ # Attributes can be added to each HTML element, by type:
56
+ attributes:
57
+ picture: 'class="awesome" data-volume="11"'
58
+ img: 'class="some-other-class"'
59
+
60
+ # This is an example of how you would create a 'multiplier' based srcset; useful when an image
61
+ # will always be the same size on all screens, but you'd like to supply higher resolution images
62
+ # to devices with higher pixel ratios.
63
+ icon:
64
+ base_width: 20
65
+ pixel_ratios: [1, 1.5, 2]
66
+ fallback_width: 20
67
+ attributes:
68
+ img: 'class="icon"'
69
+
70
+ # Here's an example of how you'd configure jekyll-picture-tag to work with something like
71
+ # lazyload:
72
+ # https://github.com/verlok/lazyload
73
+ lazy:
74
+ markup: data_auto
75
+ formats: [webp, original]
76
+ widths: [200, 400, 600, 800]
77
+ noscript: true # Default: false
78
+ attributes:
79
+ img: class="lazy"
80
+
81
+ # This is an example of how you'd get generated image and a URL, and nothing else.
82
+ direct:
83
+ markup: direct_url
84
+ fallback_format: webp # Default original
85
+ fallback_width: 600 # Default 800
@@ -0,0 +1,18 @@
1
+ ---
2
+ layout: post
3
+ title: Tag examples
4
+ ---
5
+
6
+ {% picture portrait.jpg --alt An unsual picture %}
7
+
8
+ What was the narrative that this representation was meant to embellish and complete? As I regarded
9
+ the work, I slowly sensed that the underlying tale was the picture itself. The painting wasn’t the
10
+ extension of a story at all, it was something in its own right.
11
+
12
+ ### Variations
13
+
14
+ With a preset specified:
15
+ {% picture gallery portrait.jpg --alt An unsual picture --picture data-downloadable="true" %}
16
+
17
+ With an alternate source images:
18
+ {% picture half portrait.jpg tablet: dream-midrange.jpg desktop: dream-fullpage.jpg --alt An unsual picture --picture data-downloadable="true" %}
@@ -0,0 +1,39 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'jekyll_picture_tag/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'jekyll_picture_tag'
7
+ spec.version = PictureTag::VERSION
8
+ spec.authors = ['Robert Wierzbowski', 'Brendan Tobolaski',
9
+ 'Robert Buchberger']
10
+ spec.email = ['hello@robwierzbowski.com', 'brendan@tobolaski.com',
11
+ 'robert@buchberger.cc']
12
+
13
+ spec.summary = 'Easy responsive images for Jekyll.'
14
+ spec.description = <<-HEREDOC
15
+ Jekyll Picture Tag is a liquid tag that adds responsive images to your Jekyll static site. It follows the picture
16
+ element pattern, and polyfills older browsers with Picturefill. Jekyll Picture Tag automatically creates resized
17
+ source images, is fully configurable, and covers all use cases — including art direction and resolution switching —
18
+ with a little YAML configuration and a simple template tag.
19
+ HEREDOC
20
+ spec.homepage = 'https://github.com/robwierzbowski/jekyll-picture-tag'
21
+ spec.license = 'BSD-3-Clause'
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
25
+ f.match(%r{^(test|spec|features)/})
26
+ end
27
+
28
+ spec.required_ruby_version = ['>= 2.5', '< 3']
29
+
30
+ spec.add_development_dependency 'bundler', '~> 1.16'
31
+ spec.add_development_dependency 'pry'
32
+ spec.add_development_dependency 'rake', '~> 12.3'
33
+
34
+ spec.add_dependency 'fastimage', '~> 2'
35
+ spec.add_dependency 'mini_magick', '~> 4'
36
+ spec.add_dependency 'objective_elements', '~> 1.1'
37
+
38
+ spec.add_runtime_dependency 'jekyll', '< 4'
39
+ end
@@ -0,0 +1,67 @@
1
+ require 'objective_elements'
2
+
3
+ require_relative 'jekyll_picture_tag/generated_image'
4
+ require_relative 'jekyll_picture_tag/source_image'
5
+ require_relative 'jekyll_picture_tag/instructions'
6
+ require_relative 'jekyll_picture_tag/output_formats'
7
+ require_relative 'jekyll_picture_tag/srcsets'
8
+ require_relative 'jekyll_picture_tag/utils'
9
+ require_relative 'jekyll_picture_tag/version'
10
+
11
+ module PictureTag
12
+ ROOT_PATH = __dir__
13
+ # Title: Jekyll Picture Tag
14
+ # Authors: Rob Wierzbowski : @robwierzbowski
15
+ # Justin Reese : @justinxreese
16
+ # Welch Canavan : @xiwcx
17
+ # Robert Buchberger : @celeritas_5k
18
+ #
19
+ # Description: Easy responsive images for Jekyll.
20
+ #
21
+ # Download: https://github.com/robwierzbowski/jekyll-picture-tag
22
+ # Documentation: https://github.com/robwierzbowski/jekyll-picture-tag/readme.md
23
+ # Issues: https://github.com/robwierzbowski/jekyll-picture-tag/issues
24
+ #
25
+ # Syntax:
26
+ # {% picture [preset] img.jpg [media_query: alt-img.jpg] [attr="value"] %}
27
+ #
28
+ # Example:
29
+ # {% picture poster.jpg --alt The strange case of responsive images %}
30
+ # {% picture gallery poster.jpg source_small: poster_closeus.jpg
31
+ # alt="The strange case of responsive images" class="gal-img" %}
32
+ #
33
+ # See the documentation for full configuration and usage instructions.
34
+ class Picture < Liquid::Tag
35
+ def initialize(tag_name, raw_params, tokens)
36
+ @raw_params = raw_params
37
+ super
38
+ end
39
+
40
+ def render(context)
41
+ # We can't initialize the tag until we have a context.
42
+ PictureTag.init(@raw_params, context)
43
+
44
+ # Return a string:
45
+ build_markup.to_s
46
+ end
47
+
48
+ private
49
+
50
+ # Super clever metaprogramming. It's the dynamic version of MyClass.new;
51
+ # instantiate the class defined in our config.
52
+ def build_markup
53
+ Object.const_get(output_class).new
54
+ end
55
+
56
+ # This is the class name of whichever output format we are selecting:
57
+ def output_class
58
+ 'PictureTag::OutputFormats::' + titleize(PictureTag.preset['markup'])
59
+ end
60
+
61
+ def titleize(input)
62
+ input.split('_').map(&:capitalize).join
63
+ end
64
+ end
65
+ end
66
+
67
+ Liquid::Template.register_tag('picture', PictureTag::Picture)
@@ -0,0 +1,10 @@
1
+ # Default settings for _config.yml
2
+ picture:
3
+ source: ''
4
+ output: generated
5
+ suppress_warnings: false
6
+ relative_url: true
7
+ nomarkdown: true
8
+
9
+ url: ''
10
+ baseurl: ''
@@ -0,0 +1,7 @@
1
+ markup: auto
2
+ formats: [original]
3
+ widths: [400, 600, 800, 1000]
4
+ fallback_width: 800
5
+ fallback_format: original
6
+ noscript: false
7
+ link_source: false
@@ -0,0 +1,66 @@
1
+ # Generated Image
2
+ # Represents a generated source file.
3
+ class GeneratedImage
4
+ require 'mini_magick'
5
+ require 'fastimage'
6
+
7
+ def initialize(source_file:, width:, format:)
8
+ @source = source_file
9
+ @format = format
10
+
11
+ @size = build_size(width)
12
+
13
+ generate_image unless File.exist? absolute_filename
14
+ end
15
+
16
+ def name
17
+ name = @source.base_name
18
+ name << "-#{@size[:width]}by#{@size[:height]}-"
19
+ name << @source.digest
20
+ name << '.' + @format
21
+ end
22
+
23
+ def absolute_filename
24
+ @absolute_filename ||= File.join(PictureTag.config.dest_dir, name)
25
+ end
26
+
27
+ def width
28
+ @size[:width]
29
+ end
30
+
31
+ private
32
+
33
+ def build_size(width)
34
+ if width < @source.width
35
+ {
36
+ width: width,
37
+ height: (width / @source.aspect_ratio).round
38
+ }
39
+ else
40
+ @source.size
41
+ end
42
+ end
43
+
44
+ def generate_image
45
+ puts 'Generating new image file: ' + name
46
+ image = MiniMagick::Image.open(@source.name)
47
+ # Scale and crop
48
+ image.combine_options do |i|
49
+ i.resize "#{@size[:width]}x#{@size[:height]}^"
50
+ i.auto_orient
51
+ i.strip
52
+ end
53
+
54
+ image.format @format
55
+
56
+ check_dest_dir
57
+
58
+ image.write absolute_filename
59
+ end
60
+
61
+ # Make sure destination directory exists
62
+ def check_dest_dir
63
+ dir = File.dirname absolute_filename
64
+ FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
65
+ end
66
+ end
@@ -0,0 +1,105 @@
1
+ require_relative './instructions/configuration'
2
+ require_relative './instructions/html_attributes'
3
+ require_relative './instructions/preset'
4
+ require_relative './instructions/tag_parser'
5
+
6
+ # Allows us to access settings as methods on PictureTag itself.
7
+ module PictureTag
8
+ class << self
9
+ attr_reader :context, :config, :params, :preset, :html_attributes
10
+
11
+ def init(raw_tag_params, context)
12
+ @context = context
13
+
14
+ # Create global config (big picture). Config class loads jekyll
15
+ # data/config files, and the j-p-t defaults from included yml files.
16
+ @config = Instructions::Configuration.new
17
+
18
+ # Parse tag params. We must do this before setting the preset, because
19
+ # it's one of the params.
20
+ @params = Instructions::TagParser.new(raw_tag_params)
21
+
22
+ # Create preset. Takes preset name from params, merges associated settings
23
+ # with default values.
24
+ @preset = Instructions::Preset.new
25
+
26
+ # Create HTML attributes. Depends on both the preset and tag params, so
27
+ # we must do this after creating both.
28
+ @html_attributes = Instructions::HTMLAttributeSet.new(
29
+ @params.html_attributes_raw
30
+ )
31
+
32
+ # Keep our generated files
33
+ Utils.keep_files
34
+ end
35
+
36
+ # Global site data
37
+ def site
38
+ @context.registers[:site]
39
+ end
40
+
41
+ # Page which tag is called from
42
+ def page
43
+ @context.registers[:page]
44
+ end
45
+
46
+ # Media query presets. It's really just a hash, and there are no default
47
+ # values, so extracting it to its own class is overkill.
48
+ def media_presets
49
+ site.data.dig('picture', 'media_presets') || {}
50
+ end
51
+
52
+ # The rest of the application doesn't care where the instruction logic
53
+ # resides. For example, I don't want to use PictureTag.config.source_dir and
54
+ # PictureTag.params.source_images, I just want to use PictureTag.source_dir
55
+ # and PictureTag.source_images. The following method definitions accomplish
56
+ # that.
57
+
58
+ # At first I thought I'd do some sweet dynamic metaprogramming here, but it
59
+ # ended up more complicated and clever than convenient. This way is not
60
+ # strictly DRY, but it's understandable and readable.
61
+
62
+ # Config Forwarding
63
+ def source_dir
64
+ @config.source_dir
65
+ end
66
+
67
+ def dest_dir
68
+ @config.dest_dir
69
+ end
70
+
71
+ def build_url(filename)
72
+ @config.build_url(filename)
73
+ end
74
+
75
+ def build_source_url(filename)
76
+ @config.build_source_url(filename)
77
+ end
78
+
79
+ def nomarkdown?
80
+ @config.nomarkdown?
81
+ end
82
+
83
+ # Preset forwarding
84
+ def widths(media)
85
+ @preset.widths(media)
86
+ end
87
+
88
+ def fallback_format
89
+ @preset.fallback_format
90
+ end
91
+
92
+ def fallback_width
93
+ @preset.fallback_width
94
+ end
95
+
96
+ # Params forwarding
97
+ def preset_name
98
+ @params.preset_name
99
+ end
100
+
101
+ def source_images
102
+ @params.source_images
103
+ end
104
+ end
105
+ end