jekyll_picture_tag 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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