ragerender 0.1.8 → 0.1.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3398336663640ad12e5ca290c96e61fd8fbb19e9851b8944a6434a3eca2c2d2
4
- data.tar.gz: d00c31c1051eba512321b80e524c3d117f8d8970ebfd3fc8e9ad7ca4030b358d
3
+ metadata.gz: 20419a400d4c37d35c8c0aabe8c56f8ffedc814d155c47c5617d2434f1a8e29e
4
+ data.tar.gz: 9286ac86f23882cebb842164276366ddeb00bc5df86b07792bf23951224c8019
5
5
  SHA512:
6
- metadata.gz: 5d7674505e282530b8e19ad5f085b8516888e206bf7a28fb1c9b3e27b127665ca5be9cc056841aca784b382a1eedf8c60d566003a27a851ce227698d55fd2647
7
- data.tar.gz: d092d5d375481b8662ea97baa4cbf89e6c1d50347e132654a66af39599750a40dfc9531e1197d2e77761468666e78bd914a65472554254a4cd98e46772011bf7
6
+ metadata.gz: 4260db9a06ce8119bcc298b9a0d9c1c570ad3b6f11cae47ba1a53903facfb373d89afa17706285aff94a032af95ce7f6e15d0b19ea061182b42db31d7c29cff8
7
+ data.tar.gz: d3e93dfee30f0a42b19199f9dcaa0a63b236ae8185c6e56b4414f7d3ce271440674740cc3827bb6bdc01a411f7f0bbcbef401c32f8b8455786901d46cf970a4a
data/README.rdoc CHANGED
@@ -209,6 +209,44 @@ You control this by setting a <tt>frontpage</tt> key in your site config.
209
209
  - anything else will display the extra page that has the matching
210
210
  <tt>slug</tt> in its Front Matter
211
211
 
212
+ === Comics with custom HTML code
213
+
214
+ You can use custom HTML code in place of an image for your comic page. Instead
215
+ of creating an image, just create an HTML file in your <tt>images</tt> folder:
216
+
217
+ cat '<video src="/files/my-animation.webm"></video>" > images/1.html
218
+
219
+ === Multi-image comics
220
+
221
+ You can add up to 12 images to each comic page on ComicFury. To do that in
222
+ RageRender, add each image to an <tt>images</tt> key in your comic page:
223
+
224
+ ---
225
+ title: "Comic with many pages"
226
+ date: "2026-04-20 16:20"
227
+ images:
228
+ - /images/first.png
229
+ - /images/second.png
230
+ - /images/third.png
231
+ ---
232
+
233
+ === Testing search pages
234
+
235
+ Live search does not work in RageRender, as your site is statically built and
236
+ can't respond to new data from the browser. However, you can simulate a search
237
+ when you build the site to help test search results designs. To do that, add a
238
+ `searchterm` to the search page using defaults in your `_config.yml`:
239
+
240
+ defaults:
241
+ - scope:
242
+ path: ''
243
+ layout: search
244
+ values:
245
+ searchterm: "my character"
246
+
247
+ The search that gets performed will be somewhat similar to how ComicFury will
248
+ search your comic, but may not be exactly the same.
249
+
212
250
  === Putting changes on ComicFury
213
251
 
214
252
  Once you're done making changes, you can <tt>pack</tt> your layout:
@@ -1,3 +1,6 @@
1
1
  <h2>{{ title }}</h2>
2
2
 
3
+ [c:prevcomic]<a href="[v:prevcomic]">Prev</a>[/]
4
+ [c:nextcomic]<a href="[v:nextcomic]">Next</a>[/]
5
+
3
6
  {%- include "field_table", all_fields: all_fields, fields: fields, loops: loops -%}
@@ -125,34 +125,28 @@ module RageRender
125
125
  end
126
126
  end
127
127
 
128
- def_loop :comics_paginated, :number, :newchapter, :chapterend, *ComicDrop::PAGINATION_FIELDS, *ChapterDrop::PAGINATION_FIELDS
128
+ def_loop :comics_paginated, *PaginatedComicDrop.own_methods
129
129
  def comics_paginated
130
130
  number = @obj.data['number']
131
131
  comics = if number
132
132
  selected_comics.to_a[number - 1]
133
133
  else
134
134
  selected_comics.to_a.flatten
135
- end&.group_by {|c| c.data['chapter'] } || []
136
-
137
- comics.map do |chapter, comics|
138
- chapter_data = ChapterDrop.new(@obj.site.collections['chapters'].docs.detect {|c| c.data['slug'] == chapter })
139
- comics.each_with_index.map do |comic, index|
140
- drop = ComicDrop.new(comic)
141
- {
142
- **ComicDrop::PAGINATION_FIELDS.map {|field| [field, drop[field]] }.to_h,
143
- **ChapterDrop::PAGINATION_FIELDS.map {|field| [field, chapter_data[field]] }.to_h,
144
- 'number' => index + 1,
145
- 'newchapter' => index == 0,
146
- 'chapterend' => index == comics.size - 1,
147
- }
148
- end
149
- end.flatten
135
+ end || []
136
+
137
+ comics.map do |comic|
138
+ PaginatedComicDrop.new(comic, comics)
139
+ end
150
140
  end
151
141
 
152
142
  def lastpagenumber
153
143
  selected_comics.size
154
144
  end
155
145
 
146
+ def thumbnail_box_styles
147
+ 'position:fixed; opacity:0; pointer-events:none; z-index:10000;'
148
+ end
149
+
156
150
  private
157
151
  def selected_comics
158
152
  comics = @obj.site.collections['comics'].docs.reject {|c| SPECIAL_COMIC_SLUGS.include? c.data['slug'] }
@@ -1,8 +1,13 @@
1
1
  require 'jekyll/hooks'
2
2
  require 'jekyll/drops/document_drop'
3
3
  require_relative '../date_formats'
4
+ require_relative 'setup_collection'
4
5
  require_relative 'pipettes'
5
6
 
7
+ Jekyll::Hooks.register :site, :after_init do |site|
8
+ setup_collection site, :posts, '/blogarchive/:slug/', layout: 'blog-display'
9
+ end
10
+
6
11
  Jekyll::Hooks.register :posts, :pre_render do |post, payload|
7
12
  RageRender::Pipettes.clean_payload payload
8
13
  payload.merge! RageRender::BlogDrop.new(post).to_liquid
@@ -90,31 +90,16 @@ module RageRender
90
90
  all_blogs[number-1]&.map {|blog| PaginatedBlogDrop.new(blog).to_liquid } || []
91
91
  end
92
92
 
93
- def lastpagenumber
94
- all_blogs.size
95
- end
96
-
97
- # Objects used for laying out page numbers.
98
- #
99
- # The page numbers always include:
100
- # - the first page
101
- # - the last page
102
- # - two pages around the current page
103
- def pages
104
- [1].chain([1, all_blogs.size, *(number-2..number+2).to_a].uniq).select {|i| i >= 1 && i <= all_blogs.size }.sort.each_cons(2).map do |prev, page|
105
- {
106
- 'page' => page,
107
- 'pagelink' => File.join(@obj.url, 'page', page.to_s),
108
- 'is_current' => page == number,
109
- 'skipped_ahead' => page - prev > 1,
110
- }
111
- end
112
- end
113
- def_loop :pages, :page, :pagelink, :is_current, :skipped_ahead
93
+ def_pages :all_pages
114
94
 
115
95
  private
116
96
  def all_blogs
117
97
  @all_blogs = @obj.site.posts.docs.each_slice(BLOGS_PER_PAGE).to_a
118
98
  end
99
+
100
+ def all_pages
101
+ root = Pathname.new(@obj.permalink).split.first.to_s
102
+ @obj.site.pages.select {|page| page.permalink =~ /#{root}\/page/ }
103
+ end
119
104
  end
120
105
  end
@@ -74,8 +74,6 @@ module RageRender
74
74
  COVER_MAX_HEIGHT = 420
75
75
  COVER_MAX_WIDTH = 300
76
76
 
77
- PAGINATION_FIELDS = %w[ chaptername chapterdescription chapterid ]
78
-
79
77
  extend Pipettes
80
78
  extend Forwardable
81
79
 
@@ -84,7 +82,7 @@ module RageRender
84
82
  def_delegator :@obj, :url, :chapterarchiveurl
85
83
 
86
84
  def chapterid
87
- @obj.collection.docs.index @obj
85
+ @obj.collection.docs.sort_by(&:path).index @obj
88
86
  end
89
87
 
90
88
  def chaptername
@@ -92,23 +90,11 @@ module RageRender
92
90
  end
93
91
 
94
92
  def cover_width_small
95
- return nil if cover_width.nil?
96
-
97
- if (cover_height.to_f / COVER_MAX_HEIGHT) > (cover_width.to_f / COVER_MAX_WIDTH)
98
- (cover_height_small * cover_width) / cover_height
99
- else
100
- [COVER_MAX_WIDTH, cover_width].min
101
- end
93
+ scaled_width(cover_width, cover_height, COVER_MAX_WIDTH, COVER_MAX_HEIGHT)
102
94
  end
103
95
 
104
96
  def cover_height_small
105
- return nil if cover_height.nil?
106
-
107
- if (cover_height.to_f / COVER_MAX_HEIGHT) > (cover_width.to_f / COVER_MAX_WIDTH)
108
- [COVER_MAX_HEIGHT, cover_height].min
109
- else
110
- (cover_width_small * cover_height) / cover_width
111
- end
97
+ scaled_height(cover_width, cover_height, COVER_MAX_WIDTH, COVER_MAX_HEIGHT)
112
98
  end
113
99
 
114
100
  def firstcomicinchapter
@@ -8,8 +8,14 @@ require 'jekyll/drops/drop'
8
8
  require 'jekyll/drops/document_drop'
9
9
  require_relative '../date_formats'
10
10
  require_relative 'chapter'
11
+ require_relative 'image'
12
+ require_relative 'setup_collection'
11
13
  require_relative 'pipettes'
12
14
 
15
+ Jekyll::Hooks.register :site, :after_init do |site|
16
+ setup_collection site, :comics, '/:collection/:slug/', layout: 'comic-page', chapter: '0'
17
+ end
18
+
13
19
  Jekyll::Hooks.register :comics, :pre_render do |page, payload|
14
20
  RageRender::Pipettes.clean_payload payload
15
21
  payload.merge! RageRender::ComicDrop.new(page).to_liquid
@@ -20,16 +26,40 @@ module RageRender
20
26
 
21
27
  BASE_DIR = File.join(File.dirname(__FILE__), '..', '..', '..')
22
28
 
29
+ # If there are any HTML pages in the /images directory, we treat these as
30
+ # HTML-comics where the author has specified their own HTML to use instead of
31
+ # a comic image. We turn these into static files so that they don't appear as
32
+ # extra pages.
33
+ class ComicHTMLToStaticFileGenerator < Jekyll::Generator
34
+ priority :highest
35
+
36
+ def generate site
37
+ site.pages.select {|f| f.relative_path.start_with? 'images' }.each do |html|
38
+ site.pages.delete html
39
+ static_file = Jekyll::StaticFile.new(
40
+ site,
41
+ html.instance_variable_get(:"@base"),
42
+ # Jekyll::Pages have their leading slash removed, but we need it
43
+ html.instance_variable_get(:"@dir").gsub(/^([^\/])/) {|s| '/' + s},
44
+ html.instance_variable_get(:"@name"),
45
+ )
46
+ static_file.data['content'] = html.content
47
+ static_file.defaults['published'] = false
48
+ site.static_files.append static_file
49
+ end
50
+ end
51
+ end
52
+
23
53
  # Creates comics for each file found in the 'images' directory
24
54
  # that does not already have an associated comic object.
25
55
  class ComicFromImageGenerator < Jekyll::Generator
26
- priority :highest
56
+ priority :high
27
57
 
28
58
  def generate site
29
59
  images = site.static_files.select {|f| f.relative_path.start_with? '/images' }.map {|f| [f.basename, f] }.to_h
30
60
  comics = site.collections['comics'].docs.map {|c| [c.basename_without_ext, c] }.to_h
31
61
  missing = Set.new(images.keys) - Set.new(comics.keys)
32
- missing -= Set.new(comics.map {|k, c| c.data['image'] }.reject(&:nil?).map {|img| File.basename(img, '.*') })
62
+ missing -= Set.new(comics.flat_map {|k, c| (c.data['images'] || []) + [c.data['image']] }.reject(&:nil?).map {|img| File.basename(img, '.*') })
33
63
  missing.each do |slug|
34
64
  comic = Jekyll::Document.new(images[slug].relative_path, site: site, collection: site.collections['comics'])
35
65
  comic.send(:merge_defaults)
@@ -93,16 +123,79 @@ module RageRender
93
123
  end
94
124
  end
95
125
 
96
- class ComicDrop < Jekyll::Drops::DocumentDrop
126
+ class PaginatedComicDrop < Jekyll::Drops::DocumentDrop
97
127
  extend Pipettes
98
128
 
99
- PAGINATION_FIELDS = %w[ comicurl comictitle posttime ]
129
+ THUMBNAIL_MAX_HEIGHT = 420
130
+ THUMBNAIL_MAX_WIDTH = 400
131
+ THUMBNAIL_SMALL_MAX_HEIGHT = 210
132
+ THUMBNAIL_SMALL_MAX_WIDTH = 200
133
+
134
+ def initialize obj, all
135
+ super(obj)
136
+ @all = all
137
+ end
138
+
139
+ def_delegators :comicdrop, :comicurl, :comictitle, :posttime
140
+ def_safe_delegator :chapterdrop, :chaptername, :chaptername
141
+ def_safe_delegator :chapterdrop, :chapterdescription, :chapterdescription
142
+ def_safe_delegator :chapterdrop, :chapterid, :chapterid
143
+
144
+ def number
145
+ @all.index(@obj) + 1
146
+ end
147
+
148
+ def newchapter
149
+ @all.select {|c| c.data['chapter'] == @obj.data['chapter'] }.first == @obj
150
+ end
151
+
152
+ def chapterend
153
+ @all.select {|c| c.data['chapter'] == @obj.data['chapter'] }.last == @obj
154
+ end
155
+
156
+ def_delegator :comicdrop, :comicimageurl, :thumbnail_url
157
+
158
+ def thumbnail_width
159
+ scaled_width(comicdrop.comicwidth, comicdrop.comicheight, THUMBNAIL_MAX_WIDTH, THUMBNAIL_MAX_HEIGHT) || 0
160
+ end
161
+
162
+ def thumbnail_height
163
+ scaled_height(comicdrop.comicwidth, comicdrop.comicheight, THUMBNAIL_MAX_WIDTH, THUMBNAIL_MAX_HEIGHT) || 0
164
+ end
165
+
166
+ def thumbnail_width_small
167
+ scaled_width(comicdrop.comicwidth, comicdrop.comicheight, THUMBNAIL_SMALL_MAX_WIDTH, THUMBNAIL_SMALL_MAX_HEIGHT) || 0
168
+ end
169
+
170
+ def thumbnail_height_small
171
+ scaled_height(comicdrop.comicwidth, comicdrop.comicheight, THUMBNAIL_SMALL_MAX_WIDTH, THUMBNAIL_SMALL_MAX_HEIGHT) || 0
172
+ end
173
+
174
+ private
175
+ def comicdrop
176
+ @comicdrop ||= ComicDrop.new(@obj)
177
+ end
178
+
179
+ def chapterdrop
180
+ comicdrop.send(:chapterdrop)
181
+ end
182
+
183
+ def index
184
+ @index ||= chapterdrop.send(:comics).index(@obj)
185
+ end
186
+ end
187
+
188
+ class ComicDrop < Jekyll::Drops::DocumentDrop
189
+ extend Pipettes
100
190
 
101
191
  delegate_method_as :id, :comicid
102
192
  def_delegator :@obj, :url, :comicurl
103
- def_delegator :@obj, :url, :permalink
104
193
  data_delegator 'rating'
105
194
  data_delegator 'votecount'
195
+
196
+ def permalink
197
+ URI.join(@obj.site.config["url"], @obj.site.baseurl || '/', @obj.url).to_s
198
+ end
106
199
  data_delegator 'comments'
107
200
 
108
201
  def comictitle
@@ -125,10 +218,6 @@ module RageRender
125
218
  1 + all_comics.index(@obj)
126
219
  end
127
220
 
128
- def comicsnum
129
- all_comics.size
130
- end
131
-
132
221
  def posttime
133
222
  comicfury_date(@obj.date)
134
223
  end
@@ -250,23 +339,43 @@ module RageRender
250
339
  end&.url
251
340
  end
252
341
 
342
+ def comicimagetype
343
+ if imagedrops.size > 1
344
+ 'multiimage'
345
+ elsif imagedrop.send(:image_obj).extname == '.html'
346
+ 'html'
347
+ else
348
+ 'image'
349
+ end
350
+ end
351
+
352
+ def isimage
353
+ comicimagetype == 'image'
354
+ end
355
+
356
+ def_loop :comicparts, *(RageRender::ImageDrop.invokable_methods - Jekyll::Drops::DocumentDrop.invokable_methods)
357
+ def comicparts
358
+ imagedrops.map(&:to_liquid)
359
+ end
360
+
253
361
  # An HTML tag to print for the comic image. If there is a future image, then
254
362
  # this is also a link to the next comic page.
255
363
  def comicimage
256
- linkopen = nextcomic ? <<~HTML : ''
257
- <a href="#{nextcomic}">
258
- HTML
259
- image = <<~HTML
260
- <img id="comicimage" src="#{comicimageurl}" alt="#{comictitle}"
261
- width="#{comicwidth}" height="#{comicheight}"
262
- title="#{comicdescription}">
263
- HTML
264
- linkclose = nextcomic ? <<~HTML : ''
265
- </a>
266
- HTML
267
- [linkopen, image, linkclose].join
364
+ if comicimagetype == 'multiimage'
365
+ <<~HTML
366
+ <div class="comicsegments">
367
+ #{imagedrops.map(&:html).join}
368
+ </div>
369
+ HTML
370
+ else
371
+ imagedrop.html
372
+ end
268
373
  end
269
374
 
375
+ def_safe_delegator :imagedrop, :imageurl, :comicimageurl
376
+ def_safe_delegator :imagedrop, :width, :comicwidth, default=0
377
+ def_safe_delegator :imagedrop, :height, :comicheight, default=0
378
+
270
379
  def keys
271
380
  super.reject {|k| private_methods.include? k.to_sym }
272
381
  end
@@ -306,13 +415,20 @@ module RageRender
306
415
  chapter&.next_doc.nil? ? nil : ChapterDrop.new(chapter.next_doc)
307
416
  end
308
417
 
418
+ data_delegator 'images'
309
419
  data_delegator 'image'
310
- def_image_metadata :image
311
- private :image, :image_url, :image_width, :image_height
312
420
 
313
- public
314
- alias comicimageurl image_url
315
- alias comicwidth image_width
316
- alias comicheight image_height
421
+ def imagedrops
422
+ paths = (images || []) + [image]
423
+ paths.reject(&:nil?).map do |image|
424
+ relative_path = Pathname.new('/').join(image).to_path
425
+ obj = @obj.site.static_files.detect {|f| f.relative_path == relative_path }
426
+ (paths.size > 1 ? MultiImageDrop : ImageDrop).new(obj, self)
427
+ end
428
+ end
429
+
430
+ def imagedrop
431
+ imagedrops.first
432
+ end
317
433
  end
318
434
  end
@@ -0,0 +1,78 @@
1
+ require 'forwardable'
2
+ require 'jekyll/drops/drop'
3
+ require_relative 'pipettes'
4
+
5
+ module RageRender
6
+ class ImageDrop < Jekyll::Drops::Drop
7
+ extend Forwardable
8
+ extend Pipettes
9
+
10
+ def initialize(obj, comicdrop)
11
+ super(obj)
12
+ @comic = comicdrop
13
+ @image_obj = obj
14
+ end
15
+
16
+ # an <img> tag containing the image, without surrounding link
17
+ def imageonlyhtml
18
+ filehtml || <<~HTML
19
+ <img id="comicimage" src="#{imageurl}" alt="#{comictitle}"
20
+ width="#{width}" height="#{height}"
21
+ title="#{comicdescription}">
22
+ HTML
23
+ end
24
+
25
+ # the html contents of this loop iteration. this includes stuff like a
26
+ # surrounding link to the next page
27
+ def html
28
+ filehtml || [
29
+ nextcomic ? "<a href=\"#{nextcomic}\">" : '',
30
+ imageonlyhtml,
31
+ nextcomic ? '</a>' : '',
32
+ ].join
33
+ end
34
+
35
+ private
36
+ def image
37
+ @obj.relative_path
38
+ end
39
+
40
+ def filehtml
41
+ image_obj.data['content']
42
+ end
43
+
44
+ def_delegators :@comic, :nextcomic, :comictitle, :comicdescription
45
+ private :nextcomic, :comictitle, :comicdescription
46
+
47
+ def_image_metadata :image
48
+ private :image_url, :image_width, :image_height
49
+
50
+ def imageurl
51
+ image_url unless filehtml
52
+ end
53
+
54
+ alias width image_width
55
+ alias height image_height
56
+ public :imageurl, :width, :height
57
+
58
+ def fallback_data; {}; end
59
+ end
60
+
61
+ class MultiImageDrop < ImageDrop
62
+ def imageonlyhtml
63
+ <<~HTML
64
+ <img src="#{imageurl}" alt="#{comictitle}"
65
+ width="#{width}" height="#{height}"
66
+ title="#{comicdescription}" class="comicsegmentimage">
67
+ HTML
68
+ end
69
+
70
+ def html
71
+ <<~HTML
72
+ <div class="segmentcontainer">
73
+ #{super}
74
+ </div>
75
+ HTML
76
+ end
77
+ end
78
+ end
@@ -1,3 +1,5 @@
1
+ require_relative 'pipettes'
2
+
1
3
  module RageRender
2
4
  module PaginationGenerator
3
5
  def handle_page page
@@ -27,4 +29,30 @@ module RageRender
27
29
  end
28
30
  end
29
31
  end
32
+
33
+ class PaginatedPageDrop < Jekyll::Drops::Drop
34
+ extend Pipettes
35
+
36
+ def initialize obj, current_page, prev_page
37
+ super(obj)
38
+ @current = current_page
39
+ @prev = prev_page
40
+ end
41
+
42
+ def page
43
+ @obj.data['number']
44
+ end
45
+
46
+ def pagelink
47
+ @obj.permalink
48
+ end
49
+
50
+ def is_current
51
+ page == @current.data['number']
52
+ end
53
+
54
+ def skipped_ahead
55
+ page - @prev.data['number'] > 1
56
+ end
57
+ end
30
58
  end
@@ -1,6 +1,7 @@
1
1
  # Pipettes help you make drops.
2
2
  require 'cgi'
3
3
  require 'dimensions'
4
+ require 'jekyll/drops/document_drop'
4
5
 
5
6
  module RageRender
6
7
  module Pipettes
@@ -11,9 +12,13 @@ module RageRender
11
12
  payload.send(:fallback_data).delete_if {|k| methods.include? k}
12
13
  end
13
14
 
14
- def def_safe_delegator obj, key, aliaz
15
+ def own_methods
16
+ invokable_methods - Jekyll::Drops::DocumentDrop.invokable_methods
17
+ end
18
+
19
+ def def_safe_delegator obj, key, aliaz, default=nil
15
20
  define_method(aliaz.to_sym) do
16
- send(obj.to_sym)&.send(key.to_sym)
21
+ send(obj.to_sym)&.send(key.to_sym) || default
17
22
  end
18
23
  end
19
24
 
@@ -41,6 +46,28 @@ module RageRender
41
46
  Pathname.new(@obj.path).extname != '.html' ? escape(str) : str
42
47
  end
43
48
  mod.send(:private, :maybe_escape)
49
+
50
+ mod.define_method(:scaled_width) do |width, height, max_width, max_height|
51
+ return nil if width.nil? || height.zero?
52
+
53
+ if (height.to_f / max_height) > (width.to_f / max_width)
54
+ (scaled_height(width, height, max_width, max_height) * width) / height
55
+ else
56
+ [max_width, width].min
57
+ end
58
+ end
59
+ mod.send(:private, :scaled_width)
60
+
61
+ mod.define_method(:scaled_height) do |width, height, max_width, max_height|
62
+ return nil if height.nil? || width.zero?
63
+
64
+ if (height.to_f / max_height) > (width.to_f / max_width)
65
+ [max_height, height].min
66
+ else
67
+ (scaled_width(width, height, max_width, max_height) * height) / width
68
+ end
69
+ end
70
+ mod.send(:private, :scaled_height)
44
71
  end
45
72
 
46
73
  def def_image_metadata prefix
@@ -50,7 +77,8 @@ module RageRender
50
77
  private :"#{prefix}_relative_path"
51
78
 
52
79
  define_method(:"#{prefix}_url") do
53
- File.join (@obj.site.baseurl || ''), send(:"#{prefix}_relative_path")
80
+ site = @obj.instance_variable_get(:"@site") || @obj.send(:site)
81
+ File.join (site.baseurl || ''), send(:"#{prefix}_relative_path")
54
82
  end
55
83
 
56
84
  define_method(:"#{prefix}_obj") do
@@ -74,5 +102,28 @@ module RageRender
74
102
  send(:"#{prefix}_obj") && (send(:"#{prefix}_obj").data['height'] ||= Dimensions.height(send(:"#{prefix}_path")) rescue nil)
75
103
  end
76
104
  end
105
+
106
+ def def_pages all_pages
107
+ define_method(:lastpagenumber) do
108
+ send(all_pages).size
109
+ end
110
+
111
+ # Objects used for laying out page numbers.
112
+ #
113
+ # The page numbers always include:
114
+ # - the first page
115
+ # - the last page
116
+ # - two pages around the current page
117
+ define_method(:pages) do
118
+ pages = send(all_pages)
119
+ [1].chain([1, pages.size, *(number-2..number+2).to_a].uniq).select {|i| i >= 1 && i <= pages.size }.sort.map do |i|
120
+ pages[i-1]
121
+ end.each_cons(2).map do |prev, page|
122
+ PaginatedPageDrop.new(page, @obj, prev)
123
+ end
124
+ end
125
+
126
+ def_loop :pages, *PaginatedBlogDrop.own_methods
127
+ end
77
128
  end
78
129
  end
@@ -1,3 +1,7 @@
1
+ require 'jekyll/generator'
2
+ require 'jekyll/drops/drop'
3
+ require_relative 'pagination'
4
+
1
5
  Jekyll::Hooks.register :pages, :pre_render do |page, payload|
2
6
  if page.data['layout'] == 'search'
3
7
  RageRender::Pipettes.clean_payload payload
@@ -6,36 +10,87 @@ Jekyll::Hooks.register :pages, :pre_render do |page, payload|
6
10
  end
7
11
 
8
12
  module RageRender
13
+ RESULTS_PER_PAGE = 60
14
+
15
+ class SearchPaginationGenerator < Jekyll::Generator
16
+ priority :low
17
+
18
+ def generate site
19
+ site.pages.select {|p| p.data['layout'] == 'search' }.each do |page|
20
+ SearchPaginator.new(page).generate(site)
21
+ end
22
+ end
23
+ end
24
+
25
+ class SearchPaginator
26
+ include PaginationGenerator
27
+
28
+ def initialize page
29
+ @page = page
30
+ end
31
+
32
+ def source_page site
33
+ @page
34
+ end
35
+
36
+ def searchterm
37
+ @page.data['searchterm']
38
+ end
39
+
40
+ def num_pages site
41
+ RageRender::search(site, searchterm).each_slice(RESULTS_PER_PAGE).size
42
+ end
43
+
44
+ def permalink
45
+ "/search/id/#{searchterm.hash}/:number"
46
+ end
47
+ end
48
+
49
+ def self.search site, searchterm
50
+ return [] unless searchterm
51
+ site.collections['comics'].docs.reject {|c| SPECIAL_COMIC_SLUGS.include? c.data['slug'] }.select do |comic|
52
+ [
53
+ *comic.data.fetch('tags', []),
54
+ comic.content,
55
+ *comic.data.fetch('authornotes', []).flat_map {|n| n['comment'] },
56
+ ].map(&:downcase).any? {|c| c.include?(searchterm.downcase) }
57
+ end
58
+ end
59
+
9
60
  class SearchDrop < Jekyll::Drops::Drop
10
61
  extend Pipettes
11
62
 
12
63
  private delegate_method_as :data, :fallback_data
13
64
  data_delegator 'searchterm'
65
+ data_delegator 'number'
66
+ private :number
14
67
 
15
68
  def searched
16
69
  !searchterm.nil?
17
70
  end
18
71
 
19
- def_loop :searchresults, :number, *ComicDrop::PAGINATION_FIELDS
72
+ def_loop :searchresults, *PaginatedComicDrop.own_methods
20
73
  def searchresults
21
74
  return [] unless searched
22
- @results ||= @obj.site.collections['comics'].docs.select do |comic|
23
- [
24
- *comic.data.fetch('tags', []),
25
- comic.content,
26
- *comic.data.fetch('authornotes', []).flat_map {|n| n['comment'] },
27
- ].map(&:downcase).any? {|c| c.include?(searchterm.downcase) }
28
- end.map.each_with_index do |comic, index|
29
- drop = ComicDrop.new(comic)
30
- {
31
- 'number' => index + 1,
32
- **ComicDrop::PAGINATION_FIELDS.map {|f| [f.to_s, drop[f]] }.to_h,
33
- }
75
+ comics = all_results[number-1]
76
+ comics.map do |comic|
77
+ PaginatedComicDrop.new(comic, comics)
34
78
  end
35
79
  end
36
80
 
37
81
  def foundresults
38
82
  searchresults.any?
39
83
  end
84
+
85
+ def_pages :all_pages
86
+
87
+ private
88
+ def all_results
89
+ @all_results ||= RageRender::search(@obj.site, searchterm).each_slice(RESULTS_PER_PAGE).to_a
90
+ end
91
+
92
+ def all_pages
93
+ @obj.site.pages.select {|p| p.data['searchterm'] == searchterm && p.permalink =~ /id/ }
94
+ end
40
95
  end
41
96
  end
@@ -64,9 +64,6 @@ Jekyll::Hooks.register :site, :after_init do |site|
64
64
  site.config['url'] ||= "https://#{File.basename(site.source)}.thecomicseries.com"
65
65
  site.config = site.config
66
66
 
67
- setup_collection site, :comics, '/:collection/:slug/', layout: 'comic-page', chapter: '0'
68
- setup_collection site, :posts, '/blogarchive/:slug/', layout: 'blog-display'
69
-
70
67
  site.config['defaults'].push({
71
68
  'scope' => {
72
69
  'path' => '',
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ragerender
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Worthington
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-14 00:00:00.000000000 Z
11
+ date: 2026-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rsec
@@ -301,6 +301,44 @@ description: |-
301
301
  - anything else will display the extra page that has the matching
302
302
  <tt>slug</tt> in its Front Matter
303
303
 
304
+ === Comics with custom HTML code
305
+
306
+ You can use custom HTML code in place of an image for your comic page. Instead
307
+ of creating an image, just create an HTML file in your <tt>images</tt> folder:
308
+
309
+ cat '<video src="/files/my-animation.webm"></video>" > images/1.html
310
+
311
+ === Multi-image comics
312
+
313
+ You can add up to 12 images to each comic page on ComicFury. To do that in
314
+ RageRender, add each image to an <tt>images</tt> key in your comic page:
315
+
316
+ ---
317
+ title: "Comic with many pages"
318
+ date: "2026-04-20 16:20"
319
+ images:
320
+ - /images/first.png
321
+ - /images/second.png
322
+ - /images/third.png
323
+ ---
324
+
325
+ === Testing search pages
326
+
327
+ Live search does not work in RageRender, as your site is statically built and
328
+ can't respond to new data from the browser. However, you can simulate a search
329
+ when you build the site to help test search results designs. To do that, add a
330
+ `searchterm` to the search page using defaults in your `_config.yml`:
331
+
332
+ defaults:
333
+ - scope:
334
+ path: ''
335
+ layout: search
336
+ values:
337
+ searchterm: "my character"
338
+
339
+ The search that gets performed will be somewhat similar to how ComicFury will
340
+ search your comic, but may not be exactly the same.
341
+
304
342
  === Putting changes on ComicFury
305
343
 
306
344
  Once you're done making changes, you can <tt>pack</tt> your layout:
@@ -387,6 +425,7 @@ files:
387
425
  - lib/ragerender/jekyll/chapter.rb
388
426
  - lib/ragerender/jekyll/comics.rb
389
427
  - lib/ragerender/jekyll/error.rb
428
+ - lib/ragerender/jekyll/image.rb
390
429
  - lib/ragerender/jekyll/overview.rb
391
430
  - lib/ragerender/jekyll/pagination.rb
392
431
  - lib/ragerender/jekyll/pipettes.rb