formblocks 0.1.0 → 0.1.1

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: 541957d6f438fd71c7ab933fa6c69fdbfe8272c419de1809d37bff23be6bf0fc
4
- data.tar.gz: cfe0f10f96076537705ea63160371959b456a0b9a71cf8f723b5acf24d05a3a7
3
+ metadata.gz: e2b04f8207b4d1d2916bf97d98dc73087aac5362d5062595e8db6825f7be7e7e
4
+ data.tar.gz: 0b865be55ddc3b825e4a514fac4978d7f097c6ec92aa93802578cc07ea08a5e1
5
5
  SHA512:
6
- metadata.gz: 972771ede7be90bbccda2a0fc633e351582733a577b72b3e94781cfb0166f97708eefcdf1ac3e740000df18563705ab48370f8968dd5242a2c5be24a45789c0d
7
- data.tar.gz: 4e061cf018881bce8a2bae93f8ec60332b5a3b45a0cae94b1442eef1981e44948ee839c937087d05305ffca29dd5da308d0c5934984e96680af7eeba49569a57
6
+ metadata.gz: f4fd405a7e97b459806ad8ee1dea28ad19ef55775bac6b12d46516caa1c745b6577a7b774f894cc5de5ea0853b1dec6b0fd0fe7c7e24e4a4a93de7cb4eb923aa
7
+ data.tar.gz: dfe1386a1db2f2b62271c0ba003366cc8a9c8e700528deb619c979c1703b2068c235e90240f63fd039c8afe38f69f58e72777b53afab016549968333060b96f8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1 — 2026-09-15
4
+
5
+ - Responses: a URL answer that points at an image (an image file extension, or
6
+ a Cloudinary-style `/image/upload/` path) is shown as a small thumbnail that
7
+ links to the full image, on the response page and in the responses table.
8
+
3
9
  ## 0.1.0 — 2026-09-15
4
10
 
5
11
  Initial release.
data/README.md CHANGED
@@ -317,8 +317,9 @@ config.on_submit = lambda do |response|
317
317
  end
318
318
  ```
319
319
 
320
- The dashboard lists them fifty at a time, shows one in full, and **Download
321
- CSV** exports every response with one column per input plus a column for
320
+ The dashboard lists them fifty at a time, shows one in full a URL answer
321
+ that points at an image appears as a thumbnail linking to the picture — and
322
+ **Download CSV** exports every response with one column per input — plus a column for
322
323
  any key a since-deleted block left behind, so nothing collected is lost. Cells
323
324
  a spreadsheet would run as formulas are escaped.
324
325
 
@@ -68,6 +68,16 @@ module Formblocks
68
68
  'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'aria-hidden': 'true', **options)
69
69
  end
70
70
 
71
+ # An answer as the dashboard shows it: a small thumbnail linking to the
72
+ # full image when a URL answer points at a picture, else the block's text.
73
+ def fb_answer(block, value)
74
+ return block.display_answer(value) unless block.respond_to?(:image_answer?) && block.image_answer?(value)
75
+
76
+ link_to(value, target: '_blank', rel: 'noopener', class: 'fb-answer-thumb-link', title: value) do
77
+ image_tag(value, class: 'fb-answer-thumb', alt: '', loading: 'lazy')
78
+ end
79
+ end
80
+
71
81
  def fb_status_badge(form)
72
82
  tag.span(t("formblocks.status.#{form.status}"), class: "fb-badge fb-badge--#{form.status}")
73
83
  end
@@ -5,12 +5,21 @@ require 'uri'
5
5
  module Formblocks
6
6
  module Blocks
7
7
  class Url < Text
8
+ # A URL the dashboard can show as a picture: an image file extension, or
9
+ # an image delivery path in the Cloudinary style (/image/upload/).
10
+ IMAGE_URL = %r{\Ahttps?://\S+(?:\.(?:png|jpe?g|gif|webp|avif|svg)(?:\?\S*)?\z|/image/upload/)}i
11
+
8
12
  def self.autocomplete = 'url'
9
13
 
10
14
  def html_input_type
11
15
  'url'
12
16
  end
13
17
 
18
+ # True when the stored answer is a link to an image.
19
+ def image_answer?(value)
20
+ value.to_s.match?(IMAGE_URL)
21
+ end
22
+
14
23
  def validate_present_answer(value, errors)
15
24
  uri = begin
16
25
  URI.parse(value.to_s)
@@ -29,7 +29,7 @@
29
29
  <td><%= link_to fb_time(response.created_at), form_response_path(@form, response), class: 'fb-link fb-link--strong' %></td>
30
30
  <% @columns.each do |block| %>
31
31
  <td class="fb-cell-clip">
32
- <%= block.display_answer(response.answer(block)).presence || tag.span(t('formblocks.responses.show.empty'), class: 'fb-muted') %>
32
+ <%= fb_answer(block, response.answer(block)).presence || tag.span(t('formblocks.responses.show.empty'), class: 'fb-muted') %>
33
33
  </td>
34
34
  <% end %>
35
35
  <td class="fb-table__actions"><%= link_to t('.view'), form_response_path(@form, response), class: 'fb-btn fb-btn--sm' %></td>
@@ -11,7 +11,7 @@
11
11
  <% blocks.each do |block| %>
12
12
  <div class="fb-dl__row">
13
13
  <dt><%= block.label.presence || block.key %></dt>
14
- <dd class="fb-pre"><%= block.display_answer(@response.answer(block)).presence || tag.span(t('.empty'), class: 'fb-muted') %></dd>
14
+ <dd class="fb-pre"><%= fb_answer(block, @response.answer(block)).presence || tag.span(t('.empty'), class: 'fb-muted') %></dd>
15
15
  </div>
16
16
  <% end %>
17
17
  <% orphans.each do |key| %>
@@ -200,6 +200,9 @@ html:has(.fb-builder-footer) { scroll-padding-bottom: 110px; }
200
200
  .fb-admin .fb-dl dd { margin: 0; }
201
201
  .fb-admin .fb-pre { white-space: pre-wrap; overflow-wrap: anywhere; }
202
202
  .fb-admin .fb-break { overflow-wrap: anywhere; }
203
+ .fb-admin .fb-answer-thumb-link { display: inline-block; line-height: 0; }
204
+ .fb-admin .fb-answer-thumb { display: block; max-width: 160px; max-height: 120px; border-radius: 8px; border: 1px solid var(--fb-border); }
205
+ .fb-admin .fb-cell-clip .fb-answer-thumb { max-width: 64px; max-height: 40px; border-radius: 4px; }
203
206
 
204
207
  @media (max-width: 640px) {
205
208
  .fb-admin .fb-container { padding: 16px 16px 48px; }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Formblocks
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: formblocks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Koper