product_tours 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: 82d70df0c0b3463d2b4e49de5d2d8736c1ef50ab732a86bca87d5fcf2ebe0b51
4
- data.tar.gz: 2e010ecadc7381f7176f6525cddc4ed93719dc07528fd4fb17d8c63852abcc24
3
+ metadata.gz: f48e747fd564905f78ca0c5f2609c0a2cef62352e8789ec4ce0fc8e9fb632dd0
4
+ data.tar.gz: 4dea4cbd842d0e1c3acafc5abe71719d4b882ae20750bc7441294d52e6ad7e10
5
5
  SHA512:
6
- metadata.gz: f89e331dd2c34ffb12821a5f9159abc39c8f21bd78c6577048cdccf9895bed7eab76048a165234c8dd612f9c22a959440fc5d4d644eaa36807c3c6173a12e8d0
7
- data.tar.gz: 3a34a6f113643ba9076c69805e586ca073187124de304f51ef6ebf353b9baba42c3f8c7c0f4a59e8118e9044185adc36bc79b93f4f01334a222336b7eca2c537
6
+ metadata.gz: ca825401c59636fb1ca6f4ad5f243344e8ff83e976d2357c5b0b536336a824464c98bde51f61773d679935cb3ebe23b80cc6c22b13a6af202a19e261630e3fc5
7
+ data.tar.gz: ccff1b7cefeed57de45b8581c4ecd31c73a6a14d1983333dbb13bb39ee07f2c07244dff11166220d2390afa32da8b7889f2bfc0eb5b6b4feda79f2019c457f98
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.1.1] - 2026-08-04
6
+
7
+ - Reworked the README into an installation-first, skimmable product guide that
8
+ accurately documents walkthroughs, video providers, translations, demo data,
9
+ configuration, lifecycle events, security, and intentional non-goals.
10
+ - Replaced the implementation-era PRD with a concise contract for the shipped
11
+ product boundary and current behavior.
12
+ - Added real desktop dashboard, editor, walkthrough, and mobile screenshots from
13
+ the seeded dummy application.
14
+
5
15
  ## [0.1.0] - 2026-08-03
6
16
 
7
17
  - Initial Rails engine, post dashboard, modal widget, video providers,
@@ -37,5 +47,6 @@
37
47
  - Removed generic tutorial duplication now that translations provide the only
38
48
  intentional content-copying workflow.
39
49
 
40
- [Unreleased]: https://github.com/yshmarov/product_tours/compare/v0.1.0...HEAD
50
+ [Unreleased]: https://github.com/yshmarov/product_tours/compare/v0.1.1...HEAD
51
+ [0.1.1]: https://github.com/yshmarov/product_tours/compare/v0.1.0...v0.1.1
41
52
  [0.1.0]: https://github.com/yshmarov/product_tours/releases/tag/v0.1.0
data/README.md CHANGED
@@ -1,126 +1,198 @@
1
1
  # product_tours
2
2
 
3
+ [![Gem Version](https://img.shields.io/gem/v/product_tours)](https://rubygems.org/gems/product_tours)
4
+ [![Downloads](https://img.shields.io/gem/dt/product_tours)](https://rubygems.org/gems/product_tours)
3
5
  [![CI](https://github.com/yshmarov/product_tours/actions/workflows/ci.yml/badge.svg)](https://github.com/yshmarov/product_tours/actions/workflows/ci.yml)
4
- [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](MIT-LICENSE)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](MIT-LICENSE)
7
+ [![GitHub stars](https://img.shields.io/github/stars/yshmarov/product_tours?style=social)](https://github.com/yshmarov/product_tours/stargazers)
5
8
 
6
- `product_tours` is a self-hosted Rails engine for in-app product tutorials and
7
- lightweight multi-step walkthroughs. Your app owns the trigger UI; the gem owns
8
- the tutorial editor, translations, safe video embeds, and modal navigation.
9
+ **Self-hosted product tours and video tutorials for Rails.** Publish one useful
10
+ guide, open it from any button in your app, or link several guides into a
11
+ Next/Back walkthrough. Your content, videos, translations, and lifecycle events
12
+ stay in your Rails application.
9
13
 
10
- Requires Ruby 3.2+ and Rails 7.1+.
14
+ No SaaS account. No third-party script. No visual page builder trying to attach
15
+ a tooltip to a DOM node that changed last Tuesday.
16
+
17
+ ![A multi-step product tour showing an embedded YouTube tutorial with Back and Next controls](docs/screenshots/01-walkthrough.jpg)
11
18
 
12
19
  ## Install
13
20
 
14
21
  ```ruby
22
+ # Gemfile
15
23
  gem "product_tours"
16
24
  ```
17
25
 
18
26
  ```bash
27
+ bundle install
19
28
  bin/rails generate product_tours:install
20
29
  bin/rails db:migrate
21
30
  ```
22
31
 
23
- The migration automatically creates ready-to-use demo tutorials in development.
24
- Production databases are never populated with demo content.
25
-
26
- Add the widget before `</body>` in your application layout:
27
-
28
32
  ```erb
33
+ <%# app/views/layouts/application.html.erb, before </body> %>
29
34
  <%= product_tours_tag %>
30
35
  ```
31
36
 
32
- Use any host-owned button, link, or icon as the trigger:
37
+ Put a trigger wherever the tutorial is useful:
33
38
 
34
39
  ```erb
35
- <button class="btn btn-primary" data-product-tour="billing_setup">
36
- Watch setup guide
37
- </button>
40
+ <button data-product-tour="billing_setup">Watch the billing guide</button>
38
41
  ```
39
42
 
40
- Create and publish `billing_setup` in the dashboard at `/product_tours`. Keys
41
- are unique per locale. Draft, missing, invalid, or disabled keys open nothing
42
- and raise in development/test; production reports them through `Rails.error`
43
- and `product_tours.unresolved_trigger` instrumentation.
43
+ That's it. Create and publish `billing_setup` at `/product_tours`, then click
44
+ your button.
45
+
46
+ The generator writes the initializer and migration, mounts the engine, and
47
+ prints copy-ready demo buttons. In development, the migration also creates a
48
+ small set of working tutorials so you can try the modal immediately.
49
+
50
+ > [!IMPORTANT]
51
+ > The dashboard defaults to **development only**. Set `authorize_admin` before
52
+ > deploying it — see [Configure](#configure).
44
53
 
45
- ### Host-controlled invocation
54
+ Ruby >= 3.2 · Rails >= 7.1 · Active Storage only for uploaded videos · Action
55
+ Text only for rich descriptions.
46
56
 
47
- The host app decides where and when a guide opens. It can use a visible button,
48
- compose several buttons into its own Help menu, or activate a hidden trigger
49
- after page load. For example, Rails flash state and a host Stimulus controller
50
- can open a guide after a redirect:
57
+ ## What you get
51
58
 
52
- ```erb
53
- <% if flash[:product_tour].present? %>
54
- <button hidden
55
- data-controller="product-tour-autoplay"
56
- data-product-tour="<%= flash[:product_tour] %>"></button>
57
- <% end %>
58
- ```
59
+ | | |
60
+ | --- | --- |
61
+ | **Tutorials** | Title, optional rich description, optional video, one clear primary action |
62
+ | **Walkthroughs** | Link any tutorial to another. Next opens it in place; Back uses modal history |
63
+ | **Video** | YouTube, Vimeo, Loom, Tella, Voomly, direct MP4/WebM, or an upload |
64
+ | **Dashboard** | Published/draft tabs, key search, live preview, explicit publish controls |
65
+ | **Translations** | One record per language, created from the tutorial page, with locale fallback |
66
+ | **Demo data** | Provider examples, a complete multi-step walkthrough, draft and missing-key cases |
67
+ | **Events** | `viewed`, `dismissed`, `completed` through `ActiveSupport::Notifications` |
68
+ | **Deps** | Rails only. Plain JS — no Tailwind, Stimulus, importmap, npm, CDN, or build step |
69
+ | **Auth** | Lambdas over the raw request — Devise, Rails 8 auth, anything |
70
+ | **i18n** | 26 bundled languages, including RTL |
71
+ | **Turbo/CSP** | Turbo Drive, nonce-based CSP, and supported iframe origins out of the box |
59
72
 
60
- ```js
61
- // product_tour_autoplay_controller.js in the host app
62
- connect() {
63
- this.element.click()
64
- }
65
- ```
73
+ ## The whole flow
66
74
 
67
- The gem deliberately has no page-rule engine, automatic display scheduler,
68
- resource center, or guides launcher. Those are host navigation and presentation
69
- choices built from the same `data-product-tour` attribute.
75
+ 1. A developer places `data-product-tour="some_key"` where help belongs.
76
+ 2. An admin creates that key, adds text/video, chooses Draft or Published, and
77
+ decides what the main button does.
78
+ 3. A visitor clicks the host app's button. The gem resolves the current locale,
79
+ opens its own modal, and emits `product_tours.viewed`.
80
+ 4. The main action closes, opens an app page, or continues to another tutorial.
81
+ Linked tutorials stay in the same modal and get a Back button automatically.
70
82
 
71
- ## Tutorials
83
+ | Product-tour dashboard | Tutorial editor |
84
+ | --- | --- |
85
+ | ![The dashboard with published tutorials on the left and a selected YouTube tutorial on the right](docs/screenshots/02-dashboard.jpg) | ![The editor previewing a YouTube URL and choosing another tutorial as the primary action](docs/screenshots/04-editor.jpg) |
86
+ | The default language is the canonical list. Preview, publish, translate, or edit without a deploy. | Paste a supported URL and the preview appears immediately. Choose URL or upload, then one action. |
72
87
 
73
- A tutorial is stored internally as a `ProductTours::Post`. It has a title, key,
74
- locale, `draft`/`published` status,
75
- optional video, optional rich description, and one primary action. Video URLs
76
- support YouTube, Vimeo, Loom, Tella, Voomly, and direct MP4/WebM files.
88
+ <img src="docs/screenshots/03-mobile.jpg" alt="The product tutorial modal filling a mobile viewport with a video and primary action" width="390">
77
89
 
78
- The dashboard previews a pasted video URL immediately. YouTube, Vimeo, and Loom
79
- metadata is fetched through oEmbed; the other supported providers still get a
80
- safe resolved preview. Direct videos seek to an early frame so they do not look
81
- like an empty player before playback.
90
+ On screens up to 480px the modal becomes a full-screen sheet, respects safe
91
+ areas, and follows `visualViewport` while the mobile keyboard is open.
82
92
 
83
- The admin sidebar treats `I18n.default_locale` as the canonical tutorial list.
84
- The New product tour button always creates that default-language record. Open a
85
- tutorial to see its existing languages or add another available locale; each
86
- translation remains an ordinary draft/published `Post` with the same key.
93
+ ## Why a gem
87
94
 
88
- When the host has a Rails Content Security Policy, the engine preserves its
89
- existing `frame-src` entries and automatically adds the supported embed origins.
90
- For a direct video hosted on a custom origin, the host remains responsible for
91
- allowing that origin in `media-src` (or can allow HTTPS media generally).
95
+ | | `product_tours` | Hosted tour SaaS |
96
+ | --- | --- | --- |
97
+ | Cost | Free, MIT | Monthly, usually tied to MAU |
98
+ | Where content lives | Your database | The vendor's |
99
+ | Trigger placement | Your Rails views and product logic | A remote visual builder |
100
+ | Videos | Your URLs or Active Storage | Their upload/storage rules |
101
+ | User/account data | Not collected by the gem | Usually synced for targeting |
102
+ | Analytics | Events for the tool you already use | Another dashboard |
103
+ | Frontend | One same-origin plain-JS file | Third-party script and network calls |
104
+ | If you remove it | Delete the helper and mount | Untangle remote campaigns and targeting |
92
105
 
93
- ### Link tutorials into a walkthrough
106
+ This is intentionally the reliable half of product tours: self-contained
107
+ guidance modals, not DOM-anchored tooltip choreography.
94
108
 
95
- In the tutorial editor, choose what the primary button does: finish and close,
96
- open a page, or continue to another tutorial. Continuing opens the selected
97
- tutorial in the
98
- same modal and automatically gives visitors a Back button.
109
+ ## Build a walkthrough
99
110
 
100
- Tutorials remain independently invokable—there is no separate course, step, or
101
- sequence model. The Back history exists only for the open modal, so a tutorial opened
102
- directly never shows a misleading Back button.
111
+ Every tutorial has one primary action:
103
112
 
104
- Video uploads require Active Storage:
113
+ | Choice | What visitors get |
114
+ | --- | --- |
115
+ | **Finish and close** | Emits `completed` and closes the modal |
116
+ | **Continue to another tutorial** | Opens that key in the same modal and adds Back history |
117
+ | **Open a page** | Emits `completed`, then follows a relative path or HTTP(S) URL |
105
118
 
106
- ```bash
107
- bin/rails active_storage:install
108
- bin/rails db:migrate
109
- ```
119
+ Select **Continue to another tutorial** in the editor and pick a tutorial in the
120
+ same language. Draft targets are selectable while you assemble the walkthrough;
121
+ publish the complete chain before exposing its first trigger.
110
122
 
111
- Rich descriptions require Action Text:
123
+ There is deliberately no Course, Tour, or Step model. Tutorials remain
124
+ independently invokable. The modal remembers only the path the current visitor
125
+ took, so opening a middle tutorial directly never shows a misleading Back
126
+ button.
127
+
128
+ ## Video
129
+
130
+ Paste any supported HTTPS URL:
131
+
132
+ | Provider | Accepted examples |
133
+ | --- | --- |
134
+ | YouTube | `youtube.com/watch`, Shorts, Live, embed, `youtu.be` |
135
+ | Vimeo | Public and unlisted links; privacy hashes are preserved |
136
+ | Loom | Share and embed links |
137
+ | Tella | Video links |
138
+ | Voomly | Share, video, and embed links |
139
+ | Direct | URLs ending in `.mp4` or `.webm` |
140
+
141
+ YouTube, Vimeo, and Loom metadata comes from their oEmbed endpoints. Metadata is
142
+ best-effort: a timeout never prevents you from saving a valid URL. YouTube uses
143
+ `youtube-nocookie.com`; unsupported hosts and lookalike URLs fail closed.
144
+
145
+ Direct videos seek to an early frame for a useful preview instead of showing an
146
+ empty player.
147
+
148
+ <details>
149
+ <summary><b>Upload videos or add rich descriptions</b></summary>
150
+
151
+ Both are optional Rails features:
112
152
 
113
153
  ```bash
154
+ bin/rails active_storage:install
114
155
  bin/rails action_text:install
115
156
  bin/rails db:migrate
116
157
  ```
117
158
 
118
- The post form hides either feature when its Rails framework is not installed.
159
+ Once the tables exist, the editor offers **Use a video link / Upload a video**
160
+ and a compact rich-text description editor. Uploaded videos are reached through
161
+ the engine's gated media route.
162
+
163
+ </details>
164
+
165
+ ## Translations
166
+
167
+ The dashboard sidebar shows only `I18n.default_locale`. Open a tutorial to see
168
+ every existing language and add another from `I18n.available_locales`.
169
+
170
+ - New product tours always start in the default locale.
171
+ - A translation copies the source into a new **draft** with the same key.
172
+ - The key and language become locked identity; translate, review, then publish.
173
+ - A trigger tries `I18n.locale`, then `I18n.default_locale` only when no current-
174
+ locale record exists.
175
+ - A draft translation does **not** silently fall back to published English. It
176
+ stays unavailable until you publish it.
177
+
178
+ This keeps one stable developer key while giving admins an obvious place to
179
+ manage every language.
119
180
 
120
181
  ## Demo tutorials
121
182
 
122
- The installer seeds the app's default locale in development. Copy the block it
123
- prints into any ERB view to open every demo entry point immediately:
183
+ Development installs seed the app's default locale automatically. Refresh the
184
+ full idempotent set in English, French, and Bulgarian whenever you like:
185
+
186
+ ```bash
187
+ bin/rails product_tours:seed_demo
188
+ ```
189
+
190
+ The demo includes every video provider, a walkthrough through all of them, a
191
+ direct MP4, a normal URL action, an unpublished key, and an intentionally missing
192
+ key. Running the task again updates those records instead of duplicating them.
193
+
194
+ <details>
195
+ <summary><b>Copy-ready demo buttons</b></summary>
124
196
 
125
197
  ```erb
126
198
  <div class="product-tours-demo">
@@ -138,48 +210,82 @@ prints into any ERB view to open every demo entry point immediately:
138
210
  <%= product_tours_tag %>
139
211
  ```
140
212
 
141
- `demo_walkthrough_start` introduces the collection, then continues through the
142
- YouTube, Vimeo, Loom, Tella, Voomly, and direct-video tutorials before its final
143
- step. Every transition demonstrates the automatic Back button. The individual
144
- provider buttons remain available so each video can also be opened directly.
145
- The final two buttons deliberately exercise unresolved triggers: `demo_draft`
146
- exists but remains unpublished, while `demo_missing_post` is never seeded.
147
-
148
- Refresh the full idempotent demo set in English, French, and Bulgarian at any
149
- time:
150
-
151
- ```bash
152
- bin/rails product_tours:seed_demo
153
- ```
213
+ </details>
154
214
 
155
- Along with the provider examples, it creates `demo_walkthrough_start`,
156
- `demo_walkthrough_features`, `demo_walkthrough_finish`, and the unpublished
157
- `demo_draft` in the default demo locales (`en`, `fr`, and `bg`). The missing-key
158
- button intentionally has no matching record. Running the task again refreshes
159
- the seeded records instead of duplicating them and prints the copy-ready block
160
- again. To seed only one locale from application code, call
161
- `ProductTours::Seeds.load!(locale: :fr)`.
215
+ ## Configure
162
216
 
163
- ## Configuration
217
+ Everything is optional — a development install works with zero config. In
218
+ `config/initializers/product_tours.rb`:
164
219
 
165
- The installer creates `config/initializers/product_tours.rb`. Important hooks:
220
+ | Option | Default | What it does |
221
+ | --- | --- | --- |
222
+ | `enabled` | everyone | Who can resolve and open published tutorials |
223
+ | `authorize_admin` | development only | **Who can manage content at the mount path** |
224
+ | `admin_layout` | gem layout | Render the dashboard inside your admin shell |
225
+ | `storage_service` | app default | Named Active Storage service for uploaded videos |
226
+ | `mount_path` | `/product_tours` | Keep in sync only when mounting the engine manually |
166
227
 
167
228
  ```ruby
168
229
  ProductTours.configure do |config|
230
+ config.enabled = ->(request) { request.env["warden"]&.user.present? }
169
231
  config.authorize_admin = ->(request) { request.env["warden"]&.user&.admin? }
232
+ config.admin_layout = "admin/application"
233
+ config.storage_service = :product_tours
170
234
  end
171
235
  ```
172
236
 
173
- Tutorial lookup automatically uses the page's current `I18n.locale`, then falls
174
- back to `I18n.default_locale` when that key has no current-locale record. An
175
- existing draft translation is not bypassed by the fallback.
237
+ Gates receive the **raw request**, so Devise, Rails 8 authentication, Flipper,
238
+ or your own session model all work without an adapter.
239
+
240
+ ## Trigger it from your own UI
241
+
242
+ The gem ships no floating launcher. A trigger belongs in the navigation,
243
+ settings card, empty state, or success screen where it makes sense:
244
+
245
+ ```erb
246
+ <a href="#" data-product-tour="invite_team">How team invitations work</a>
247
+ ```
248
+
249
+ Keep `<%= product_tours_tag %>` in the layout when triggers appear across the
250
+ app. When `enabled` returns false, the helper renders nothing and the endpoints
251
+ also reject the request.
252
+
253
+ <details>
254
+ <summary><b>Open a tutorial after a redirect</b></summary>
255
+
256
+ The host owns timing. Rails flash plus a tiny Stimulus controller is enough:
257
+
258
+ ```erb
259
+ <% if flash[:product_tour].present? %>
260
+ <button hidden
261
+ data-controller="product-tour-autoplay"
262
+ data-product-tour="<%= flash[:product_tour] %>"></button>
263
+ <% end %>
264
+ ```
265
+
266
+ ```js
267
+ // product_tour_autoplay_controller.js in your app
268
+ connect() {
269
+ this.element.click()
270
+ }
271
+ ```
272
+
273
+ </details>
274
+
275
+ ## Lifecycle events
176
276
 
177
- ## Lifecycle Notifications
277
+ The gem persists no analytics, user identity, cookies, progress, or completion
278
+ table. It emits three Rails notifications:
178
279
 
179
- The widget emits `product_tours.viewed`, `product_tours.dismissed`, and
180
- `product_tours.completed` through `ActiveSupport::Notifications`. The gem does
181
- not persist analytics and does not depend on Ahoy. `completed` means the visitor
182
- used the tutorial's primary action; video playback does not imply completion.
280
+ | Event | Meaning |
281
+ | --- | --- |
282
+ | `product_tours.viewed` | The modal became visible and focused |
283
+ | `product_tours.dismissed` | The visitor closed it before using the primary action |
284
+ | `product_tours.completed` | The visitor used the primary action |
285
+
286
+ Payload: `post_id`, `key`, `locale`, query-free `page_url`, and `source`.
287
+
288
+ Bridge them to Ahoy—or anything else—in your host app:
183
289
 
184
290
  ```ruby
185
291
  ActiveSupport::Notifications.subscribe(/^product_tours\./) do |name, _start, _finish, _id, payload|
@@ -187,23 +293,67 @@ ActiveSupport::Notifications.subscribe(/^product_tours\./) do |name, _start, _fi
187
293
  end
188
294
  ```
189
295
 
190
- The host may store these events with Ahoy and attach its own user or account
191
- context in the subscriber. Persistence, dashboards, identity, and vendor-specific
192
- integrations remain outside this gem.
296
+ Your subscriber can attach `Current.user` or account context. That identity does
297
+ not need to become product-tour configuration.
298
+
299
+ ## Broken triggers fail loudly, not publicly
300
+
301
+ `data-product-tour="key"` is a contract between code and dashboard content.
302
+ Invalid, missing, draft, or disabled keys open nothing for the visitor.
303
+
304
+ - Development/test: raises `ProductTours::UnresolvedTriggerError`.
305
+ - Production: reports through `Rails.error`, logs as a fallback, and emits
306
+ `product_tours.unresolved_trigger` with `invalid_key`, `missing`,
307
+ `unpublished`, or `disabled`.
193
308
 
194
- ## Scope
309
+ No end user gets a Rails error page because somebody renamed a tutorial.
195
310
 
196
- `product_tours` owns tutorial persistence and editing, safe media rendering, the
197
- modal experience, linked-tutorial navigation, and lifecycle notifications. The host
198
- app owns trigger timing and placement, Help/resource menus, analytics storage,
199
- reporting, and downstream integrations.
311
+ ## Security
312
+
313
+ - Admin authorization runs server-side on every dashboard request.
314
+ - Public resolution returns only published tutorials allowed by `enabled`.
315
+ - Video providers are an HTTPS allowlist; unsupported URLs render no iframe.
316
+ - Action URLs accept relative app paths or HTTP(S), never script schemes.
317
+ - Widget/dashboard assets are same-origin and fingerprinted.
318
+ - Rails CSP nonces are preserved. Supported provider origins are merged into
319
+ `frame-src` without replacing the host policy.
320
+ - For direct videos on another origin, allow that origin in the host app's
321
+ `media-src` policy.
322
+
323
+ ## What it doesn't do
324
+
325
+ No anchored tooltips, selector recorder, page-rule engine, automatic scheduler,
326
+ checklists, persisted progress, analytics dashboard, resource center, AI writer,
327
+ Segment/Mixpanel/Slack integration, or user/account sync.
328
+
329
+ The host app owns trigger timing and Help navigation. Ahoy or your analytics
330
+ stack owns persistence and reporting. The gem stays small enough to understand.
200
331
 
201
332
  ## Development
202
333
 
203
334
  ```bash
204
- bundle install
205
335
  bundle exec rake test
206
336
  bundle exec rubocop
207
337
  ```
208
338
 
209
- Rails 7.1+ and Ruby 3.2+ are supported.
339
+ CI runs Rails 7.1 / 7.2 / 8.0 / 8.1 against Ruby 3.2 / 3.3 / 3.4.
340
+
341
+ Bug reports and pull requests are welcome. The most useful report is a real
342
+ Rails app and the exact point where installation or authoring felt confusing.
343
+
344
+ ## Also by the same author
345
+
346
+ - [testimonials](https://github.com/yshmarov/testimonials) — testimonials,
347
+ video reviews, and NPS for Rails.
348
+ - [livechat](https://github.com/yshmarov/livechat) — in-app support messaging
349
+ for Rails.
350
+ - [ideasbugs](https://github.com/yshmarov/ideasbugs) — in-app bug reports and
351
+ feature requests.
352
+ - [i18n_proofreading](https://github.com/yshmarov/i18n_proofreading) — in-context
353
+ translation proofreading.
354
+ - [SupeRails](https://superails.com) — Rails screencasts.
355
+
356
+ ## License
357
+
358
+ MIT. If it saved you a subscription, a
359
+ [⭐](https://github.com/yshmarov/product_tours) is a fair trade.
Binary file
Binary file
Binary file
Binary file
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ProductTours
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: product_tours
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
  - Yaroslav Shmarov
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-08-03 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -83,6 +82,10 @@ files:
83
82
  - config/locales/product_tours.vi.yml
84
83
  - config/locales/product_tours.zh-CN.yml
85
84
  - config/routes.rb
85
+ - docs/screenshots/01-walkthrough.jpg
86
+ - docs/screenshots/02-dashboard.jpg
87
+ - docs/screenshots/03-mobile.jpg
88
+ - docs/screenshots/04-editor.jpg
86
89
  - lib/generators/product_tours/install/install_generator.rb
87
90
  - lib/generators/product_tours/install/templates/create_product_tours_posts.rb.tt
88
91
  - lib/generators/product_tours/install/templates/initializer.rb
@@ -109,7 +112,6 @@ metadata:
109
112
  changelog_uri: https://github.com/yshmarov/product_tours/blob/main/CHANGELOG.md
110
113
  bug_tracker_uri: https://github.com/yshmarov/product_tours/issues
111
114
  rubygems_mfa_required: 'true'
112
- post_install_message:
113
115
  rdoc_options: []
114
116
  require_paths:
115
117
  - lib
@@ -124,8 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
126
  - !ruby/object:Gem::Version
125
127
  version: '0'
126
128
  requirements: []
127
- rubygems_version: 3.5.21
128
- signing_key:
129
+ rubygems_version: 3.6.9
129
130
  specification_version: 4
130
131
  summary: Self-hosted product tours and video tutorials for Rails apps.
131
132
  test_files: []