ragerender 0.1.7 → 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: 152c14ba01c06c930b537a0e1c72a994e673fa8aea1176b82f92adfc912e5e77
4
- data.tar.gz: bfb9fa9e0e5d4e1dae45c3bdc7fc09fd7de45fdcbb3043fd45c26e11404b0d1d
3
+ metadata.gz: 20419a400d4c37d35c8c0aabe8c56f8ffedc814d155c47c5617d2434f1a8e29e
4
+ data.tar.gz: 9286ac86f23882cebb842164276366ddeb00bc5df86b07792bf23951224c8019
5
5
  SHA512:
6
- metadata.gz: 78e6690eb005da5ac9604c4111612b3e3dcf2d68c52bb8b351dc6165d3fecf9acc8267cfb69d551a6ee8374bb6b660d812465e2bb14875e2d95199c5b1a81a6e
7
- data.tar.gz: 841b860abb04b124f88aa730ece8650fce559f08a889598f4121b503eb6d5c3ef03bb396f6afffe860ded22cffb92d887750cd597b170369dbc74e7660d8f1ea
6
+ metadata.gz: 4260db9a06ce8119bcc298b9a0d9c1c570ad3b6f11cae47ba1a53903facfb373d89afa17706285aff94a032af95ce7f6e15d0b19ea061182b42db31d7c29cff8
7
+ data.tar.gz: d3e93dfee30f0a42b19199f9dcaa0a63b236ae8185c6e56b4414f7d3ce271440674740cc3827bb6bdc01a411f7f0bbcbef401c32f8b8455786901d46cf970a4a
data/README.rdoc CHANGED
@@ -92,6 +92,7 @@ Put something like this in your webcomic folder and call it
92
92
  description: >
93
93
  My epic story about how him and her
94
94
  fell into a romantic polycule with they and them
95
+ status: active
95
96
  genres:
96
97
  - Comedy
97
98
  - Romance
@@ -154,6 +155,8 @@ details of your author notes and blogs manually:
154
155
  date: "2025-03-05 16:20"
155
156
  image: "images/ghost.png"
156
157
  author: "Jane doe"
158
+ description: "Some spooky mouseover text"
159
+ keywords: [excellent, comic page, spooky]
157
160
  custom:
158
161
  # use yes and no for tickbox settings
159
162
  spooky: yes
@@ -164,6 +167,9 @@ details of your author notes and blogs manually:
164
167
  Testing webcomics
165
168
  Now easier than ever
166
169
  Thanks to RageRender
170
+ transcript: >
171
+ The transcript contains a machine-readable version
172
+ of all the text in your comic image.
167
173
  comments:
168
174
  - author: "Skippy"
169
175
  date: "13 Mar 2025, 3.45 PM"
@@ -203,6 +209,44 @@ You control this by setting a <tt>frontpage</tt> key in your site config.
203
209
  - anything else will display the extra page that has the matching
204
210
  <tt>slug</tt> in its Front Matter
205
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
+
206
250
  === Putting changes on ComicFury
207
251
 
208
252
  Once you're done making changes, you can <tt>pack</tt> your layout:
@@ -0,0 +1,2 @@
1
+ _layouts
2
+ test-layout.cflxml
@@ -0,0 +1,51 @@
1
+ require 'forwardable'
2
+ require 'liquid'
3
+ require_relative '../lib/ragerender/cflxml'
4
+ require_relative '../lib/ragerender/jekyll'
5
+
6
+ TEMPLATE_DROPS = {
7
+ 'archive' => RageRender::ArchiveDrop,
8
+ 'comic-page' => RageRender::ComicDrop,
9
+ 'error-page' => RageRender::ErrorDrop,
10
+ 'blog-archive' => RageRender::BlogArchiveDrop,
11
+ 'blog-display' => RageRender::BlogDrop,
12
+ 'overview' => RageRender::OverviewDrop,
13
+ 'search' => RageRender::SearchDrop,
14
+ }
15
+
16
+ Liquid::Template.error_mode = :strict
17
+ Liquid::Template.file_system = Liquid::LocalFileSystem.new('_includes', '%s.html')
18
+
19
+ directory '_layouts'
20
+
21
+ TEMPLATE_DROPS.each do |layout, drop|
22
+ file "_layouts/#{layout}.html" => ['_layouts', RageRender.const_source_location(drop.name).first, "_templates/#{layout}.html", __FILE__] do |t|
23
+ fields = Set.new(drop.invokable_methods) -
24
+ Set.new(Jekyll::Drops::DocumentDrop.invokable_methods)
25
+ all_fields = Set.new(RageRender::WebcomicDrop.invokable_methods) -
26
+ Set.new(Jekyll::Drops::DocumentDrop.invokable_methods)
27
+ template_name = "_templates/#{layout}.html"
28
+ template = Liquid::Template.parse File::read template_name, environment: ENV
29
+
30
+ rake_output_message "liquid ... >#{t.name} <#{template_name}"
31
+ File::write t.name, template.render!({
32
+ 'title' => "#{drop.name.rpartition(/[A-Z]/).first.split('::').last} Page",
33
+ 'all_fields' => all_fields.to_a.sort,
34
+ 'fields' => fields.to_a.sort,
35
+ 'loops' => [*drop.loops, *RageRender::WebcomicDrop.loops].map {|k, v| {"name" => k.to_s, "fields" => v.map(&:to_s)} },
36
+ }, strict_variables: true, strict_filters: true)
37
+ end
38
+ end
39
+
40
+ file '_layouts/overall.html' => '_templates/overall.html' do |t|
41
+ cp t.source, t.name
42
+ end
43
+
44
+ file 'test-layout.cflxml' => ['layout.css', '_layouts/overall.html', *TEMPLATE_DROPS.keys.map {|n| "_layouts/#{n}.html"}] do |t|
45
+ File.open t.name, 'w' do |f|
46
+ rake_output_message 'bundle exec jekyll pack'
47
+ RageRender.pack '_layouts', '.', f
48
+ end
49
+ end
50
+
51
+ task :default => 'test-layout.cflxml'
@@ -0,0 +1,8 @@
1
+ <tr>
2
+ <td>{{ name }}</td>
3
+ <td>[v:{{field}}]</td>
4
+ <td>
5
+ <script type="text/javascript">document.currentScript.parentElement.append(document.createTextNode([f:js|v:{{field}}]))</script>
6
+ </td>
7
+ <td>[c:{{field}}]true[/][c:!{{field}}]false[/]</td>
8
+ </tr>
@@ -0,0 +1,15 @@
1
+ {% assign looped_fields = loops | map: "name" %}
2
+ {% for field in fields -%}
3
+ {%- include "field_row", name: field, field: field -%}
4
+ {% if looped_fields contains field %}
5
+ {% assign field_obj = loops | where: "name", field %}
6
+ {% assign field_fields = field_obj[0].fields %}
7
+ [l:{{field}}]
8
+ {% for field_field in field_fields %}
9
+ {% capture name %}{{field}}&lbrack;[v:l.aiteration]&rbrack; → {{ field_field }}{% endcapture %}
10
+ {% assign field_name = field_field | prepend: "l." %}
11
+ {%- include "field_row", name: name, field: field_name %}
12
+ {% endfor %}
13
+ [/]
14
+ {% endif %}
15
+ {% endfor -%}
@@ -0,0 +1,22 @@
1
+ <table>
2
+ <thead>
3
+ <tr>
4
+ <th>Variable name</th>
5
+ <th>Value on this page</th>
6
+ <th>Value (escaped)</th>
7
+ <th>True or false in conditional</th>
8
+ </tr>
9
+ </thead>
10
+ <tbody>
11
+ <tr>
12
+ <th colspan=4>Unique to this page</th>
13
+ </tr>
14
+ {%- include "field_rows", fields: fields, loops: loops -%}
15
+ </tbody>
16
+ <tbody>
17
+ <tr>
18
+ <th colspan=4>On all pages</th>
19
+ </tr>
20
+ {%- include "field_rows", fields: all_fields, loops: loops -%}
21
+ </tbody>
22
+ </table>
@@ -0,0 +1,3 @@
1
+ <h2>{{ title }}</h2>
2
+
3
+ {%- include "field_table", all_fields: all_fields, fields: fields, loops: loops -%}
@@ -0,0 +1,3 @@
1
+ <h2>{{ title }}</h2>
2
+
3
+ {%- include "field_table", all_fields: all_fields, fields: fields, loops: loops -%}
@@ -0,0 +1,3 @@
1
+ <h2>{{ title }}</h2>
2
+
3
+ {%- include "field_table", all_fields: all_fields, fields: fields, loops: loops -%}
@@ -0,0 +1,6 @@
1
+ <h2>{{ title }}</h2>
2
+
3
+ [c:prevcomic]<a href="[v:prevcomic]">Prev</a>[/]
4
+ [c:nextcomic]<a href="[v:nextcomic]">Next</a>[/]
5
+
6
+ {%- include "field_table", all_fields: all_fields, fields: fields, loops: loops -%}
@@ -0,0 +1,3 @@
1
+ <h2>{{ title }}</h2>
2
+
3
+ {%- include "field_table", all_fields: all_fields, fields: fields, loops: loops -%}
@@ -0,0 +1,90 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
6
+
7
+ <meta property="og:type" content="website" />
8
+ <meta property="og:title" content="[v:webcomicname]" />
9
+ <meta property="og:description" content="[v:pagetitle]" />
10
+ [c:permalink]
11
+ <meta property="og:url" content="[v:permalink]" />
12
+ [/]
13
+ <meta name="twitter:card" content="summary_large_image" />
14
+ <meta name="twitter:title" content="[v:webcomicname]" />
15
+ <meta name="twitter:description" content="[v:pagetitle]" />
16
+
17
+ [c:previewimageurl]
18
+ <meta property="og:image" content="[v:previewimageurl]" />
19
+ <meta property="og:image:width" content="[v:previewimagewidth]" />
20
+ <meta property="og:image:height" content="[v:previewimageheight]" />
21
+ <meta name="twitter:image" content="[v:previewimageurl]" />
22
+ [/]
23
+
24
+ <link rel="alternate" type="application/rss+xml" title="RSS" href="/rss/" />
25
+
26
+ <title>[v:webcomicname] - [v:pagetitle]</title>
27
+ [v:layoutcss]
28
+ </head>
29
+ <body>
30
+ <header>
31
+ <h1><a href="/">[v:webcomicname]</a></h1>
32
+ <div id="slogan">[v:webcomicslogan]</div>
33
+ </header>
34
+
35
+
36
+ <nav class="site-nav">
37
+ <ul id="navigation">
38
+ <li><a href="/">Home</a></li>
39
+ <li><a href="/comics/#content-start">Latest</a></li>
40
+ <li><a href="/comics/1/#content-start">First</a></li>
41
+ [c:searchon]
42
+ <li><a href="/search/">Search</a></li>
43
+ [/]
44
+ <li><a href="/archive/">Archive</a></li>
45
+ [c:infinitescrollenabled]
46
+ <li><a href="[v:infinitescrolllink]">Scroll View</a></li>
47
+ [/]
48
+ [c:hasblogs]
49
+ <li><a href="/blog/">Blog</a></li>
50
+ [/]
51
+ [c:!hidefromhost]
52
+ <li><a href="[v:addsubscriptionlink]">Subscribe</a></li>
53
+ [/]
54
+ [l:extrapages]
55
+ <li><a href="[v:l.link]">[v:l.title]</a></li>
56
+ [/]
57
+ </ul>
58
+ </nav>
59
+
60
+ <!--layout:[content]-->
61
+ <footer>
62
+ <div>
63
+ <ul>
64
+ <li>
65
+ <a href="/rss/">RSS</a>
66
+ </li>
67
+ [c:!hidefromhost]
68
+ <li>
69
+ <a href="[v:comicprofile]">Comic Profile</a>
70
+ </li>
71
+ [/]
72
+ <li>
73
+ <a href="#">Top</a>
74
+ </li>
75
+ </ul>
76
+ </div>
77
+
78
+ <div class="hostedby">
79
+ <span>Hosted by </span>
80
+ <a href="https://comicfury.com">
81
+ <img src="https://comicfury.com/images/gator-icon-black.png" height="22" style="height:22px; width:auto;" />
82
+ ComicFury
83
+ </a>
84
+ </div>
85
+ <div>
86
+ &copy; [v:copyrights]<br />
87
+ </div>
88
+ </footer>
89
+ </body>
90
+ </html>
@@ -0,0 +1,3 @@
1
+ <h2>{{ title }}</h2>
2
+
3
+ {%- include "field_table", all_fields: all_fields, fields: fields, loops: loops -%}
@@ -0,0 +1,10 @@
1
+ <h2>{{ title }}</h2>
2
+
3
+ <form method="post" action="/search/" id="searchbox">
4
+ <div class="searchbar">
5
+ <input type="text" name="search" value="[v:searchterm]" placeholder="Search Term" id="bigsearchbox" />
6
+ <input type="submit" value="Search!" class="submit" />
7
+ </div>
8
+ </form>
9
+
10
+ {%- include "field_table", all_fields: all_fields, fields: fields, loops: loops -%}
@@ -0,0 +1,50 @@
1
+ body {
2
+ max-width: 1024px;
3
+ margin: 2em auto 0;
4
+
5
+ font-family: monospace;
6
+ }
7
+
8
+ body::before {
9
+ content: "";
10
+ display: block;
11
+ position: absolute;
12
+ left: 0;
13
+ top: 0;
14
+ right: 0;
15
+ height: 0;
16
+ background: yellow;
17
+ border-top: 1em black dashed;
18
+ transform: skewX(-35deg);
19
+ max-width: 99vw;
20
+ }
21
+
22
+ table td, table th {
23
+ background: white;
24
+ padding: 1ch;
25
+ }
26
+
27
+ table td:nth-child(2) {
28
+ max-width: 35vw;
29
+ overflow: scroll;
30
+ }
31
+
32
+ table td:nth-child(3) {
33
+ word-wrap: anywhere;
34
+ }
35
+
36
+ table tr:nth-child(even) {
37
+ filter: invert(0.1);
38
+ }
39
+
40
+ table th {
41
+ filter: invert(0.2);
42
+ }
43
+
44
+ td:empty::before {
45
+ content: 'blank';
46
+ display: inline-block;
47
+ background: rgba(0, 0, 0, 0.15);
48
+ padding: 0px 4px;
49
+ border-radius: 5px;
50
+ }
@@ -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,9 +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
- delegate_method_as :data, :fallback_data
80
77
  extend Pipettes
81
78
  extend Forwardable
82
79
 
@@ -85,7 +82,7 @@ module RageRender
85
82
  def_delegator :@obj, :url, :chapterarchiveurl
86
83
 
87
84
  def chapterid
88
- @obj.collection.docs.index @obj
85
+ @obj.collection.docs.sort_by(&:path).index @obj
89
86
  end
90
87
 
91
88
  def chaptername
@@ -93,19 +90,11 @@ module RageRender
93
90
  end
94
91
 
95
92
  def cover_width_small
96
- if (cover_height.to_f / COVER_MAX_HEIGHT) > (cover_width.to_f / COVER_MAX_WIDTH)
97
- (cover_height_small * cover_width) / cover_height
98
- else
99
- [COVER_MAX_WIDTH, cover_width].min
100
- end
93
+ scaled_width(cover_width, cover_height, COVER_MAX_WIDTH, COVER_MAX_HEIGHT)
101
94
  end
102
95
 
103
96
  def cover_height_small
104
- if (cover_height.to_f / COVER_MAX_HEIGHT) > (cover_width.to_f / COVER_MAX_WIDTH)
105
- [COVER_MAX_HEIGHT, cover_height].min
106
- else
107
- (cover_width_small * cover_height) / cover_width
108
- end
97
+ scaled_height(cover_width, cover_height, COVER_MAX_WIDTH, COVER_MAX_HEIGHT)
109
98
  end
110
99
 
111
100
  def firstcomicinchapter
@@ -122,8 +111,16 @@ module RageRender
122
111
  def_image_metadata :image
123
112
  private :image_url, :image_width, :image_height
124
113
 
114
+ def comics
115
+ @obj.site.collections['comics'].docs.select {|c| c.data['chapter'] == @obj.data['slug'] }
116
+ end
117
+
125
118
  def first_comic
126
- @obj.site.collections['comics'].docs.select {|c| c.data['chapter'] == @obj.data['slug'] }.first
119
+ comics.first
120
+ end
121
+
122
+ def fallback_data
123
+ {}
127
124
  end
128
125
 
129
126
  public