jekyll-image-links 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6b9c59cd6053f748b0f8dcf7552df298abb667f7298ff717af6acd4dffab5148
4
+ data.tar.gz: c3855e305456f92098aacd45ff07a8ae188b6eae6df1cc95cd9866faef3c96cf
5
+ SHA512:
6
+ metadata.gz: c8d2a5dc878d212dd91f299e837c09dc789bda8eefdbd745287a7bbd0c646df81694e8b9cdf05487fa68b231509661e3947a0d188defc955c1d3fa94ad77871d
7
+ data.tar.gz: '008678f930adeaad4ebcbdeaa93b32c87f16dc1fa99ab546634c4d89b3b21fc9b7f103f0e2a0c134d1f68f7c548cb0369c0232ea08645ff7de99fed48c41d6a3'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 directsun
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,195 @@
1
+ # jekyll-image-links
2
+
3
+ A Jekyll plugin for [Just the Docs](https://github.com/just-the-docs/just-the-docs) sites that adds clickable polygon regions on images.
4
+
5
+ Inspired by the Dynamic Map Viewer in [5etools](https://github.com/5etools/5etools-src), which uses custom JavaScript (not HTML `<map>` tags) to define polygon click areas on large map images.
6
+
7
+ ## Features
8
+
9
+ - Define polygon click regions in Markdown using a Liquid tag
10
+ - Click a region to navigate to an internal or external link
11
+ - Hold **Shift** while clicking to open the link in a new tab
12
+ - Integrates with [jekyll-hover-popup](https://github.com/directsun/jekyll-hover-popup) when both plugins are enabled: region clicks open pinned hover-popup windows (no page darkening), and the map viewer opens inside a hover-popup window too
13
+ - Optional **Dynamic Map Viewer** button with zoom, pan, and region highlighting
14
+ - Optional region labels overlaid on the image
15
+ - Load region data inline or from a YAML file
16
+
17
+ ## Install
18
+
19
+ Add to your site `Gemfile`:
20
+
21
+ ```ruby
22
+ group :jekyll_plugins do
23
+ gem "jekyll-image-links", path: "/path/to/image-links"
24
+ end
25
+ ```
26
+
27
+ Then in `_config.yml`:
28
+
29
+ ```yml
30
+ plugins:
31
+ - jekyll-image-links
32
+ ```
33
+
34
+ ## Configuration
35
+
36
+ Optional `_config.yml` settings:
37
+
38
+ ```yml
39
+ image_links:
40
+ enabled: true
41
+ assets_path: /assets/jekyll-image-links
42
+ viewer_by_default: true
43
+ inline_by_default: true
44
+ labels_by_default: false
45
+ use_hover_popup: auto # auto | true | false
46
+ ```
47
+
48
+ When `jekyll-hover-popup` is also installed, image map region clicks open section previews in hover-popup windows instead of navigating the page. Set `use_hover_popup: false` to disable that integration.
49
+
50
+ ## Usage
51
+
52
+ ### Inline regions
53
+
54
+ ```liquid
55
+ {% image_map src="/assets/maps/example.webp" width="1200" height="800" title="Example Map" %}
56
+ - href: /docs/room-a/
57
+ title: Room A
58
+ label: A
59
+ points:
60
+ - [120, 80]
61
+ - [420, 80]
62
+ - [420, 320]
63
+ - [120, 320]
64
+ - href: /docs/room-b/
65
+ title: Room B
66
+ label: B
67
+ points:
68
+ - [480, 120]
69
+ - [760, 120]
70
+ - [760, 420]
71
+ - [480, 420]
72
+ {% endimage_map %}
73
+ ```
74
+
75
+ ### External YAML file
76
+
77
+ `assets/maps/example-map.yml`:
78
+
79
+ ```yml
80
+ width: 1200
81
+ height: 800
82
+ regions:
83
+ - href: /docs/room-a/
84
+ title: Room A
85
+ points: [[120, 80], [420, 80], [420, 320], [120, 320]]
86
+ - href: /docs/room-b/
87
+ title: Room B
88
+ points: [[480, 120], [760, 120], [760, 420], [480, 420]]
89
+ ```
90
+
91
+ When `width` and `height` are in the YAML file, you can omit them from the tag and control display size separately:
92
+
93
+ ```liquid
94
+ {% image_map src="/assets/maps/example.webp" file="assets/maps/example-map.yml" style="width:100%;max-width:900px;height:auto" %}
95
+ {% endimage_map %}
96
+ ```
97
+
98
+ Legacy form still works — numeric `width`/`height` on the tag or `<img>` define the native coordinate system when the YAML file does not include them:
99
+
100
+ ```liquid
101
+ {% image_map src="/assets/maps/example.webp" width="1200" height="800" file="assets/maps/example-map.yml" %}
102
+ {% endimage_map %}
103
+ ```
104
+
105
+ ### Tag options
106
+
107
+ | Attribute | Description |
108
+ |-----------|-------------|
109
+ | `src` | Image URL (required) |
110
+ | `width` | Native image width in pixels (required unless set in YAML) |
111
+ | `height` | Native image height in pixels (required unless set in YAML) |
112
+ | `title` | Caption and viewer title |
113
+ | `alt` | Image alt text (defaults to `title`) |
114
+ | `file` | Path to a YAML regions file relative to site source |
115
+ | `style` | CSS display sizing (for example `width:100%;max-width:900px;height:auto`) |
116
+ | `viewer="false"` | Disable the Dynamic Map Viewer button |
117
+ | `inline="false"` | Disable direct click regions on the inline image |
118
+ | `labels="true"` | Show region labels on the inline image |
119
+
120
+ ### Manual HTML (portable markup)
121
+
122
+ You can also write image maps directly in Markdown using `{::nomarkdown}` blocks. Only an `<img>` tag is required — no `<figure>` wrapper. Put configuration on the image itself using `data-jil-*` attributes.
123
+
124
+ Store the **native** image dimensions in the YAML file. Region `points` use that coordinate system. Use CSS on the `<img>` for **display** size (percentages, max width/height, and so on). At build time those display styles are moved to the surrounding `.jil-map-host` wrapper so percentage sizes resolve against the page layout correctly.
125
+
126
+ If the plugin is disabled or not installed, the image still renders normally and browsers ignore the extra `data-jil-*` attributes.
127
+
128
+ ```markdown
129
+ {::nomarkdown}
130
+ <img
131
+ class="jil-map-image"
132
+ src="/assets/images/a-familiar-tower/tower-1-combined-cropped.png"
133
+ alt="Level 1"
134
+ style="width: 100%; max-width: 900px; height: auto;"
135
+ loading="lazy"
136
+ data-jil-title="Level 1"
137
+ data-jil-regions="assets/maps/a-familiar-tower-1.yml"
138
+ data-jil-viewer="true"
139
+ data-jil-inline="true"
140
+ data-jil-labels="true"
141
+ />
142
+ {:/nomarkdown}
143
+ ```
144
+
145
+ `assets/maps/a-familiar-tower-1.yml`:
146
+
147
+ ```yml
148
+ width: 1413
149
+ height: 1455
150
+ regions:
151
+ - href: /docs/room-a/
152
+ title: Room A
153
+ points: [[120, 80], [420, 80], [420, 320], [120, 320]]
154
+ ```
155
+
156
+ Display sizing alternatives on the `<img>`:
157
+
158
+ | Attribute | Example | Description |
159
+ |-----------|---------|-------------|
160
+ | `style` | `width:100%;max-width:900px;height:auto` | Full CSS control (recommended) |
161
+ | `width` / `height` | `width="100%"` or `width="800"` | Display size when YAML provides native dimensions |
162
+ | `data-jil-max-width` | `900px` or `80%` | Shorthand for `max-width` |
163
+ | `data-jil-max-height` | `600px` | Shorthand for `max-height` |
164
+
165
+ Portable images are detected by `class="jil-map-image"` together with region data (`data-jil-regions`, an adjacent `<script class="jil-regions-data">` block, or legacy `data-jil-map="true"`). Legacy `<figure data-jil-map="true">` markup is still supported.
166
+
167
+ | Attribute | Description |
168
+ |-----------|-------------|
169
+ | `class="jil-map-image"` | Marks the image for enhancement (required) |
170
+ | `data-jil-regions` | Path to a YAML regions file relative to site source |
171
+ | `data-jil-title` | Caption and viewer title |
172
+ | `data-jil-viewer` | Enable/disable the Dynamic Map Viewer button |
173
+ | `data-jil-inline` | Enable/disable direct click regions on the inline image |
174
+ | `data-jil-labels` | Show region labels on the inline image |
175
+
176
+ ## Coordinate system
177
+
178
+ Region `points` use the image's native pixel coordinates, matching the 5etools `mapRegions` format. Define the native size once in the YAML file (`width` and `height`) or on the tag/image when not using YAML dimensions. For example, a 4937×3439 map uses coordinates in that range.
179
+
180
+ The plugin scales clicks from whatever size the image is displayed at back into that native coordinate system. Changing display size with CSS, percentages, or max width/height does not require editing region points.
181
+
182
+ ## How this relates to 5etools
183
+
184
+ 5etools stores regions as `mapRegions` on image entries in JSON data, then renders them with a custom `RenderMap` class (`js/render-map.js`) that:
185
+
186
+ - draws the image on a `<canvas>`
187
+ - overlays clickable polygons
188
+ - uses a ray-casting algorithm for hit detection
189
+ - opens linked adventure content in hover windows
190
+
191
+ This plugin uses the same polygon coordinate model and the same hit-detection approach, adapted for Jekyll pages with normal `href` links instead of 5etools' internal book area IDs.
192
+
193
+ ## License
194
+
195
+ MIT
@@ -0,0 +1,180 @@
1
+ .jil-figure {
2
+ margin: 1.25rem 0;
3
+ }
4
+
5
+ .jil-map-host {
6
+ position: relative;
7
+ display: block;
8
+ max-width: 100%;
9
+ }
10
+
11
+ .jil-map-host.jil-inline .jil-map-image {
12
+ display: block;
13
+ width: 100%;
14
+ height: auto;
15
+ max-width: 100%;
16
+ vertical-align: top;
17
+ }
18
+
19
+ .jil-map-host.jil-height-constrained {
20
+ overflow: hidden;
21
+ }
22
+
23
+ .jil-map-host.jil-height-constrained.jil-inline .jil-map-image {
24
+ width: auto;
25
+ max-width: 100%;
26
+ max-height: 100%;
27
+ height: auto;
28
+ }
29
+
30
+ .jil-caption {
31
+ margin-top: 0.5rem;
32
+ font-size: 0.95rem;
33
+ color: var(--jil-caption-color, inherit);
34
+ }
35
+
36
+ .jil-toolbar {
37
+ margin-top: 0.75rem;
38
+ }
39
+
40
+ .jil-viewer-button {
41
+ font: inherit;
42
+ }
43
+
44
+ .jil-label-layer {
45
+ position: absolute;
46
+ pointer-events: none;
47
+ }
48
+
49
+ .jil-label {
50
+ position: absolute;
51
+ transform: translate(-50%, -50%);
52
+ pointer-events: auto;
53
+ padding: 0.1rem 0.35rem;
54
+ border-radius: 0.2rem;
55
+ background: rgba(255, 255, 255, 0.82);
56
+ color: #1f2937;
57
+ font-size: 0.75rem;
58
+ font-weight: 700;
59
+ text-decoration: none;
60
+ line-height: 1.2;
61
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
62
+ }
63
+
64
+ .jil-viewer-backdrop {
65
+ position: fixed;
66
+ inset: 0;
67
+ z-index: 10050;
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ padding: 1rem;
72
+ background: rgba(0, 0, 0, 0.55);
73
+ }
74
+
75
+ .jil-viewer-panel {
76
+ display: flex;
77
+ flex-direction: column;
78
+ width: min(96vw, 1200px);
79
+ height: min(92vh, 900px);
80
+ background: var(--body-background-color, #fff);
81
+ color: var(--body-text-color, #272727);
82
+ border: 1px solid var(--border-color, #dee2e6);
83
+ border-radius: 0.35rem;
84
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
85
+ overflow: hidden;
86
+ }
87
+
88
+ .jil-viewer-backdrop .jil-viewer-panel {
89
+ width: min(96vw, 1200px);
90
+ height: min(92vh, 900px);
91
+ }
92
+
93
+ .jil-viewer-header {
94
+ display: flex;
95
+ align-items: center;
96
+ justify-content: space-between;
97
+ gap: 1rem;
98
+ padding: 0.75rem 1rem;
99
+ border-bottom: 1px solid var(--border-color, #dee2e6);
100
+ }
101
+
102
+ .jil-viewer-title {
103
+ font-weight: 700;
104
+ }
105
+
106
+ .jil-viewer-controls {
107
+ display: flex;
108
+ flex-wrap: wrap;
109
+ gap: 0.5rem;
110
+ padding: 0.75rem 1rem;
111
+ border-bottom: 1px solid var(--border-color, #dee2e6);
112
+ }
113
+
114
+ .jil-viewer-scroll {
115
+ flex: 1;
116
+ overflow: auto;
117
+ background: #111;
118
+ }
119
+
120
+ .jil-viewer-canvas {
121
+ display: block;
122
+ cursor: grab;
123
+ }
124
+
125
+ .jil-viewer-close {
126
+ margin-left: auto;
127
+ }
128
+
129
+ .jhp-hwin__content:has(.jil-viewer-in-popup) {
130
+ display: flex;
131
+ flex-direction: column;
132
+ overflow: hidden;
133
+ }
134
+
135
+ .jhp-hwin__content .jil-viewer-in-popup {
136
+ display: flex;
137
+ flex-direction: column;
138
+ flex: 1 1 auto;
139
+ width: 100%;
140
+ min-width: min(88vw, 760px);
141
+ min-height: 0;
142
+ max-height: none;
143
+ overflow: hidden;
144
+ background: transparent;
145
+ color: inherit;
146
+ border: 0;
147
+ border-radius: 0;
148
+ box-shadow: none;
149
+ }
150
+
151
+ .jhp-hwin__content .jil-viewer-in-popup .jil-viewer-header,
152
+ .jhp-hwin__content .jil-viewer-in-popup .jil-viewer-close {
153
+ display: none;
154
+ }
155
+
156
+ .jhp-hwin__content .jil-viewer-in-popup .jil-viewer-controls {
157
+ flex: 0 0 auto;
158
+ padding: 0.5rem 0 0.75rem;
159
+ border-bottom: 1px solid var(--jhp-border-color, var(--border-color, #dee2e6));
160
+ }
161
+
162
+ .jhp-hwin__content .jil-viewer-in-popup .jil-viewer-scroll {
163
+ flex: 1 1 auto;
164
+ min-height: 240px;
165
+ max-height: none;
166
+ overflow: auto;
167
+ background: #111;
168
+ }
169
+
170
+ .jhp-hwin__content .jil-viewer-in-popup .jil-viewer-canvas {
171
+ display: block;
172
+ cursor: grab;
173
+ }
174
+
175
+ @media (prefers-color-scheme: dark) {
176
+ .jil-label {
177
+ background: rgba(24, 24, 24, 0.88);
178
+ color: #f3f4f6;
179
+ }
180
+ }