trek 2.5.0 → 2.6.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 +4 -4
- data/.node-version +1 -1
- data/AGENTS.md +7 -4
- data/CHANGELOG.md +37 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +16 -3
- data/Makefile +2 -0
- data/app/components/trek/dashboard/tile_component/tile_component.css +9 -0
- data/app/components/trek/dashboard/tile_component/tile_component.html.slim +4 -2
- data/app/components/trek/dashboard/tile_component.rb +12 -2
- data/app/components/trek/form/content_editor_component/content_editor_component.css +5 -0
- data/app/components/trek/form/content_editor_component/content_editor_component.html.slim +19 -93
- data/app/components/trek/form/content_editor_component/content_editor_component.js +94 -251
- data/app/components/trek/form/content_editor_component/extensions/block_view.js +40 -0
- data/app/components/trek/form/content_editor_component/extensions/image_block.js +28 -26
- data/app/components/trek/form/content_editor_component/extensions/prompts_block.js +15 -26
- data/app/components/trek/form/content_editor_component/extensions/table_of_contents.js +1 -3
- data/app/components/trek/form/content_editor_component.rb +15 -0
- data/app/components/trek/form/image_field_component/image_field_component.css +40 -1
- data/app/components/trek/form/image_field_component/image_field_component.html.slim +0 -9
- data/app/components/trek/form/image_field_component.rb +36 -9
- data/app/content/trek/content/cleaner.rb +53 -0
- data/app/content/trek/content/document.rb +2 -2
- data/app/content/trek/content/prompts_block.rb +1 -2
- data/app/content/trek/content.rb +6 -0
- data/app/controllers/concerns/trek/reorderable.rb +24 -6
- data/app/controllers/trek/csp_reports_controller.rb +14 -1
- data/app/controllers/trek/panels/prompts_controller.rb +1 -1
- data/app/controllers/trek/resource_controller.rb +5 -5
- data/app/jobs/trek/purge_expired_sessions_job.rb +4 -3
- data/app/models/concerns/trek/contentable.rb +15 -1
- data/app/models/concerns/trek/users/sign_in_code.rb +70 -0
- data/app/models/concerns/trek/users/sign_in_lockout.rb +4 -2
- data/app/views/trek/panels/links/_form.html.slim +2 -4
- data/app/views/trek/panels/prompts/create.turbo_stream.slim +0 -1
- data/config/locales/trek.en.yml +26 -11
- data/config/locales/trek.fr.yml +26 -11
- data/docs/.vitepress/config.mjs +4 -1
- data/docs/background-jobs.md +69 -0
- data/docs/content-editor.md +219 -0
- data/docs/customize.md +2 -0
- data/docs/deploy.md +2 -2
- data/docs/getting-started.md +1 -1
- data/docs/index.md +1 -1
- data/docs/reference/components.md +2 -2
- data/docs/reference/concerns/contentable.md +10 -4
- data/docs/reference/concerns/formattable.md +1 -1
- data/docs/reference/environment-variables.md +1 -0
- data/docs/reference/formatters.md +2 -30
- data/docs/reference/forms.md +1 -1
- data/docs/reference/generators/audit-log.md +2 -2
- data/docs/reference/generators/install.md +3 -2
- data/docs/reference/generators/public-accounts.md +141 -0
- data/docs/reference/generators/security-headers.md +1 -1
- data/docs/reference/index.md +2 -1
- data/docs/reference/models/user.md +3 -1
- data/docs/what-is-trek.md +1 -1
- data/lib/generators/trek/audit_log_generator.rb +54 -0
- data/lib/generators/trek/install/admin/users_generator.rb +6 -1
- data/lib/generators/trek/install/audit_log_generator.rb +9 -45
- data/lib/generators/trek/install/good_job_generator.rb +161 -0
- data/lib/generators/trek/install/model_specs_generator.rb +3 -3
- data/lib/generators/trek/install/ruby_generator.rb +1 -1
- data/lib/generators/trek/install/scalingo_generator.rb +7 -45
- data/lib/generators/trek/install_generator.rb +15 -0
- data/lib/generators/trek/public_accounts_generator.rb +267 -0
- data/lib/generators/trek/scalingo_generator.rb +55 -0
- data/lib/generators/trek/templates/.gitlab-ci.yml +1 -1
- data/lib/generators/trek/templates/controllers/admin/password_renewals_controller.rb +11 -0
- data/lib/generators/trek/templates/controllers/admin/user_sessions_controller.rb +1 -1
- data/lib/generators/trek/templates/controllers/admin/users_controller.rb +0 -8
- data/lib/generators/trek/templates/initializers/content_security_policy.rb +3 -2
- data/lib/generators/trek/templates/initializers/good_job.rb.tt +38 -0
- data/lib/generators/trek/templates/jobs/mail_delivery_job.rb +6 -0
- data/lib/generators/trek/templates/layouts/admin.html.slim +5 -0
- data/lib/generators/trek/templates/mailers/admin_mailer.rb +4 -2
- data/lib/generators/trek/templates/package.json.tt +1 -1
- data/lib/generators/trek/templates/public_accounts/api/authentication.rb.tt +76 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/accounts_controller.rb.tt +22 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/active_sessions_controller.rb.tt +21 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/base_controller.rb.tt +71 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/email_changes_controller.rb.tt +55 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/email_confirmations_controller.rb.tt +19 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/password_resets_controller.rb.tt +28 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/passwords_controller.rb.tt +17 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/registrations_controller.rb.tt +17 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/sessions_controller.rb.tt +45 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/sign_in_codes_controller.rb.tt +15 -0
- data/lib/generators/trek/templates/public_accounts/jobs/sign_in_code_job.rb.tt +13 -0
- data/lib/generators/trek/templates/public_accounts/locales/accounts.en.yml.tt +205 -0
- data/lib/generators/trek/templates/public_accounts/locales/accounts.fr.yml.tt +205 -0
- data/lib/generators/trek/templates/public_accounts/mailers/account_mailer.rb.tt +85 -0
- data/lib/generators/trek/templates/public_accounts/migrations/create_accounts.rb.tt +46 -0
- data/lib/generators/trek/templates/public_accounts/models/account/session.rb.tt +47 -0
- data/lib/generators/trek/templates/public_accounts/models/account/sign_in_code.rb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/models/account.rb.tt +73 -0
- data/lib/generators/trek/templates/public_accounts/spec/api/accounts_spec.rb.tt +90 -0
- data/lib/generators/trek/templates/public_accounts/spec/api/sign_ins_spec.rb.tt +158 -0
- data/lib/generators/trek/templates/public_accounts/spec/models/account/sign_in_code_spec.rb.tt +56 -0
- data/lib/generators/trek/templates/public_accounts/spec/models/account_spec.rb.tt +109 -0
- data/lib/generators/trek/templates/public_accounts/spec/web/accounts_spec.rb.tt +126 -0
- data/lib/generators/trek/templates/public_accounts/spec/web/authentication_spec.rb.tt +43 -0
- data/lib/generators/trek/templates/public_accounts/spec/web/sign_ins_spec.rb.tt +215 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change.en.html.slim.tt +10 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change.en.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change.fr.html.slim.tt +13 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change.fr.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.en.html.slim.tt +9 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.en.text.erb.tt +11 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.fr.html.slim.tt +11 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.fr.text.erb.tt +11 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_confirmation.en.html.slim.tt +10 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_confirmation.en.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_confirmation.fr.html.slim.tt +10 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_confirmation.fr.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/password_reset.en.html.slim.tt +10 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/password_reset.en.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/password_reset.fr.html.slim.tt +13 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/password_reset.fr.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_code.en.html.slim.tt +9 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_code.en.text.erb.tt +11 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_code.fr.html.slim.tt +9 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_code.fr.text.erb.tt +11 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_locked.en.html.slim.tt +23 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_locked.en.text.erb.tt +14 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_locked.fr.html.slim.tt +24 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_locked.fr.text.erb.tt +14 -0
- data/lib/generators/trek/templates/public_accounts/web/authentication.rb.tt +97 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/accounts_controller.rb.tt +33 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/active_sessions_controller.rb.tt +15 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/base_controller.rb.tt +52 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/email_changes_controller.rb.tt +85 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/email_confirmations_controller.rb.tt +19 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/password_resets_controller.rb.tt +41 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/passwords_controller.rb.tt +23 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/registrations_controller.rb.tt +24 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/sessions_controller.rb.tt +78 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/sign_in_codes_controller.rb.tt +27 -0
- data/lib/generators/trek/templates/public_accounts/web/views/_flash.html.slim.tt +5 -0
- data/lib/generators/trek/templates/public_accounts/web/views/accounts/show.html.slim.tt +52 -0
- data/lib/generators/trek/templates/public_accounts/web/views/email_changes/edit.html.slim.tt +17 -0
- data/lib/generators/trek/templates/public_accounts/web/views/email_changes/new.html.slim.tt +15 -0
- data/lib/generators/trek/templates/public_accounts/web/views/password_resets/edit.html.slim.tt +26 -0
- data/lib/generators/trek/templates/public_accounts/web/views/password_resets/new.html.slim.tt +15 -0
- data/lib/generators/trek/templates/public_accounts/web/views/passwords/edit.html.slim.tt +25 -0
- data/lib/generators/trek/templates/public_accounts/web/views/registrations/new.html.slim.tt +28 -0
- data/lib/generators/trek/templates/public_accounts/web/views/sessions/new.html.slim.tt +38 -0
- data/lib/generators/trek/templates/public_accounts/web/views/sign_in_codes/new.html.slim.tt +17 -0
- data/lib/generators/trek/templates/spec/jobs/mail_delivery_job_spec.rb +11 -0
- data/lib/generators/trek/templates/spec/mailers/admin_mailer_spec.rb +10 -0
- data/lib/generators/trek/templates/spec/requests/admin/fragments_spec.rb +1 -1
- data/lib/generators/trek/templates/spec/requests/admin/good_job_spec.rb +34 -0
- data/lib/generators/trek/templates/spec/requests/admin/pages_spec.rb +1 -1
- data/lib/generators/trek/templates/spec/requests/admin/panels_spec.rb +16 -0
- data/lib/generators/trek/templates/spec/requests/admin/password_renewal_spec.rb +2 -2
- data/lib/generators/trek/templates/spec/requests/admin/sign_in_lockout_spec.rb +1 -1
- data/lib/generators/trek/templates/spec/requests/admin/user_sessions_spec.rb +2 -2
- data/lib/generators/trek/templates/views/admin/users/index.html.slim +1 -1
- data/lib/generators/trek/templates/views/admin_mailer/new_sign_in.en.html.slim +1 -1
- data/lib/generators/trek/templates/views/admin_mailer/new_sign_in.en.text.erb +1 -1
- data/lib/generators/trek/templates/views/admin_mailer/new_sign_in.fr.html.slim +1 -1
- data/lib/generators/trek/templates/views/admin_mailer/new_sign_in.fr.text.erb +1 -1
- data/lib/trek/csp_reports.rb +22 -4
- data/lib/trek/typography_formatter.rb +35 -4
- data/lib/trek/version.rb +1 -1
- data/package.json +12 -8
- data/trek.gemspec +1 -1
- data/vitest.config.mjs +24 -0
- data/yarn.lock +1004 -288
- metadata +90 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d783f048ea7c8129d6b101a8ccb10d0c33234e0d24ef08a57dc33499c88b09e4
|
|
4
|
+
data.tar.gz: 750d8fbdb051715fc9f68dc2891592f36adb79d85c2f890eabeecc142ea15e0b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3a7a0c78650fc92150bcf59a4923bc192c77759ac027ad30dd8ab3063f3097c83d1b12d397908bddb9e66ff2c3a123a5f4269333026756acd2e1bf15f7990abf
|
|
7
|
+
data.tar.gz: 010e0d3c431c219b0749ab01b98dbf224f4a63fc5d256fd62b7f7503f9a0def8140248eba61917ef5afed1ddfc86472d0ff49eb4918dc95e4edd3893a28f6c5a
|
data/.node-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
24.22.
|
|
1
|
+
24.22.1
|
data/AGENTS.md
CHANGED
|
@@ -9,10 +9,10 @@ Trek is a customizable CMS for Ruby on Rails, shipped as a **Ruby gem** (`trek`)
|
|
|
9
9
|
## Tech stack
|
|
10
10
|
|
|
11
11
|
- **Ruby** `>= 3.3` (RuboCop targets 3.4) · **Rails** `>= 8.0, < 8.2` (lockfile 8.1.4)
|
|
12
|
-
- **Node** 24.22.
|
|
12
|
+
- **Node** 24.22.1 (`.node-version`) · **Yarn** 4.18.1 with its defaults: no install scripts, no package published less than a day ago · **PostgreSQL** 12+ · **libvips** for images
|
|
13
13
|
- Backend: `action_policy`, `closure_tree`, `acts_as_list`, `mobility` + `i18n-tasks`, `shrine` (+ blurhash/image_processing/aws-sdk-s3), `view_component` + `slim-rails` + `lookbook`, `kaminari`, `deepl-rb`
|
|
14
14
|
- Frontend: **esbuild** (`esbuild.config.js`) + **PostCSS** (`postcss.config.js`); Stimulus/Turbo, TipTap, Uppy, Tom Select, SortableJS
|
|
15
|
-
- Tests: **RSpec** (`rspec-rails`, capybara, simplecov) · Docs: **VitePress** (`docs/`)
|
|
15
|
+
- Tests: **RSpec** (`rspec-rails`, capybara with Cuprite, simplecov), **Vitest** (browser mode, headless Chrome through Playwright) · Docs: **VitePress** (`docs/`)
|
|
16
16
|
|
|
17
17
|
## Commands
|
|
18
18
|
|
|
@@ -21,6 +21,7 @@ bin/setup # bundle install + yarn install (dev setup)
|
|
|
21
21
|
bin/console # IRB with trek loaded
|
|
22
22
|
rake # default: spec + rubocop
|
|
23
23
|
rake spec # run tests (or: bundle exec rspec)
|
|
24
|
+
yarn test # JavaScript tests (Vitest): the admin's Stimulus controllers, e.g. the content editor's
|
|
24
25
|
COVERAGE=1 bundle exec rspec # tests + SimpleCov report in coverage/ (fails under the minimum set in spec/spec_helper.rb)
|
|
25
26
|
make lint # all linters below (make -k lint to run them all despite a failure)
|
|
26
27
|
make security # brakeman + bundler-audit
|
|
@@ -50,9 +51,11 @@ Security: `bundle exec brakeman` · `bundle exec bundle-audit check --update`
|
|
|
50
51
|
- `config/locales/` — `trek.en.yml`, `trek.fr.yml`
|
|
51
52
|
- `spec/` — RSpec suite, two kinds of spec:
|
|
52
53
|
- **isolated** (`require_relative` the file under test, stub its host): concerns, helpers, simple components
|
|
53
|
-
- **Rails** (`require "rails_helper"`): boots `spec/dummy`, a minimal host app on PostgreSQL (`trek_test`, or `DATABASE_URL`). Its models, migrations, Shrine initializer and the whole admin (controllers, views, routes, policies, mailers) are not committed: `spec/dummy/lib/generated_files.rb` runs Trek's own generator steps into `tmp/dummy` on every boot, and the database is rebuilt from them. A new model or migration template must be added to its `STEPS
|
|
54
|
+
- **Rails** (`require "rails_helper"`): boots `spec/dummy`, a minimal host app on PostgreSQL (`trek_test`, or `DATABASE_URL`). Its models, migrations, Shrine initializer and the whole admin (controllers, views, routes, policies, mailers) are not committed: `spec/dummy/lib/generated_files.rb` runs Trek's own generator steps into `tmp/dummy` on every boot, and the database is rebuilt from them. A new model or migration template must be added to its `STEPS` (and a generator taking arguments, to its `ARGUMENTS`), or `spec/dummy/generated_files_spec.rb` fails.
|
|
54
55
|
- **Host-app specs**: model, admin request, policy and mailer specs and their [Oaken](https://github.com/kaspth/oaken) seeds are templates (`lib/generators/trek/templates/{spec/models,spec/requests,spec/policies,spec/mailers,db/seeds}/`), installed in host apps by `trek:install:model_specs` and run by Trek's suite from `tmp/dummy` (`spec/dummy/generated_specs_spec.rb`); test data comes from `users.create`, `pages.create` and `seed "cases/…"`, not factories. Write specs for Trek's models there, in host-app style (no `frozen_string_literal`, Ruby 3.3-compatible — no bare `it` block parameter), so host apps get them too.
|
|
55
56
|
- **Generators** (`spec/trek/generators_spec.rb`): every generator runs on a copy of a real `rails new` app (`spec/support/generators.rb`, built once per run into `tmp/generator_skeleton`), then again to check it changes nothing. Shell-outs are recorded in `shell_commands`, not run. A new generator is picked up automatically; if it needs arguments, an earlier Trek step or a starting file, add it to the spec's `arguments`, `prerequisites` or `setups`.
|
|
57
|
+
- **System** (`spec/system`, `type: :system`): the admin in a headless Chrome (Cuprite), for what needs a real browser: typing, Turbo panels, uploads. `spec/support/system.rb` builds Trek's JS and CSS once per run (`node esbuild.config.js`) and serves them as the admin's `admin.js` and `admin.css`. Keep them few: they take seconds each.
|
|
58
|
+
- `spec/javascript/` — Vitest tests (`yarn test`) of the admin's Stimulus controllers with their libraries, in a headless Chrome (the installed one, or `CHROME_PATH`): the content editor's controller and Tiptap, mounted on its component's markup, driven with the keyboard and the mouse (`userEvent`). Most editor behaviour is tested there: the whole file runs in about five seconds.
|
|
56
59
|
- Both kinds run in one process, so an isolated spec must restore any global it changes (`I18n`, `Shrine` storages…). `spec_helper` loads Rails and Action View before Trek, as a host app does: several dependencies (ActionPolicy, Slim, ViewComponent) configure themselves from what is already loaded.
|
|
57
60
|
- `docs/` — VitePress site
|
|
58
61
|
|
|
@@ -62,7 +65,7 @@ Security: `bundle exec brakeman` · `bundle exec bundle-audit check --update`
|
|
|
62
65
|
- **Slim** linted via slim_lint; **JS/CSS** via ESLint + Stylelint + Prettier 2.8.8
|
|
63
66
|
- **i18n**: keep English + French locales in sync (`config/locales/trek.*.yml`); DeepL auto-translation via `DEEPL_AUTH_KEY`
|
|
64
67
|
- **Versioning**: version lives in both `lib/trek/version.rb` and `package.json` — keep in sync via `make release`
|
|
65
|
-
- **CHANGELOG.md**: Keep-a-Changelog format. **Every MR must add an `[Unreleased]` entry**, except one that only changes specs. Keep entries short: one or two sentences on what changed for host apps, not how it was found or fixed — the MR description holds the details. When the change requires action in the host app on upgrade, end the entry with a bold `**Upgrade note:**` label followed by what to do. Use the same label when the change lets host apps remove or simplify existing patches or custom implementations (e.g. "**Upgrade note:** you can now drop your custom …") — never as an unlabelled trailing sentence.
|
|
68
|
+
- **CHANGELOG.md**: Keep-a-Changelog format. **Every MR must add an `[Unreleased]` entry**, except one that only changes specs or the repository's own tooling (`Makefile`, CI, Renovate config), which host apps never see. Keep entries short: one or two sentences on what changed for host apps, not how it was found or fixed — the MR description holds the details. When the change requires action in the host app on upgrade, end the entry with a bold `**Upgrade note:**` label followed by what to do. Use the same label when the change lets host apps remove or simplify existing patches or custom implementations (e.g. "**Upgrade note:** you can now drop your custom …") — never as an unlabelled trailing sentence.
|
|
66
69
|
- **Generated model names**: a new model template belonging to another model is nested under it, in `models/<owner>/` (`User::Session`, `User::PreviousPassword`), not prefixed (`UserSession`). Nested in an Active Record model, it keeps the prefixed table name (`user_sessions`) and its owner's `has_many` finds it without `class_name:`. The older `PagePath`, `PageVersion` and `TagCategory` move in Trek 3 (#248).
|
|
67
70
|
- **Generators' npm packages**: the install generators' `NPM_DEPENDENCIES` (`lib/generators/trek/install/*_generator.rb`) add to host apps the packages needed by the config files they copy from Trek's root (`esbuild.config.js`, `postcss.config.js`, `.eslintrc.json`, `.stylelintrc.json`, `lefthook.yml`). When a package is bumped in Trek's `package.json` — by hand or by Renovate, which doesn't touch the generators — bump its range in the generator in the same MR, or new apps get a version the copied config may not work with (as esbuild 0.15 did). List only packages those configs or the generated scripts use.
|
|
68
71
|
- **Public code**: Trek ships publicly (gem, npm, docs), so nothing committed may mention a client or project name, nor a client's domain models or business logic — not in code, comments, specs, templates, docs, CHANGELOG or commit messages. Use neutral examples (`Page`, `Shop::Product`, an engine's `Blog::Post`). Client context belongs in GitLab issues and MR descriptions only.
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [2.6.0] - 2026-10-28
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- The content editor's link, image and prompt panels give hints under their fields: what to write in an image's alternative text, credit and caption, that a link goes to a page or a URL, and what a prompt's title is for. **Upgrade note:** you can now drop your own `helpers.hint.trek/content_editor/*` translations.
|
|
8
|
+
- The content editor's link panel asks for the link's title, shown when hovering it, as its prompt panel does: Tiptap 3 keeps it on the link, where Tiptap 2 dropped it, and the site renders it.
|
|
9
|
+
- CSP violations reported to AppSignal (`Trek::CspReportsController`) tell what was blocked: they're tagged with the browser's user agent, where it happened (the source file and line) and, for an inline script, its first 40 characters, which the generated policy now asks for with `'report-sample'`. The log line gives the source and sample too. Tags are cut to 255 characters, as AppSignal silently drops longer ones. **Upgrade note:** add `:report_sample` to `policy.script_src` in `config/initializers/content_security_policy.rb` to get the samples.
|
|
10
|
+
- `rails g trek:install:good_job`, a new installer step (also runnable alone) making [GoodJob](https://github.com/bensheldon/good_job) the Active Job backend, as every Trek app was doing by hand: it swaps `solid_queue` for `good_job` in the Gemfile (Solid Cache stays), removes the Solid Queue setup `rails new` leaves behind (`config/queue.yml`, `config/recurring.yml`, `db/queue_schema.rb`, `bin/jobs`, the Puma plugin, the `queue:` database and Kamal's `SOLID_QUEUE_IN_PUMA`/`JOB_CONCURRENCY` variables), and configures the adapter (Active Job' test adapter in `config/environments/test.rb`, so specs can check what is enqueued), `:async` execution in production, the queues, cron and error reporting in `config/initializers/good_job.rb`. The dashboard is mounted at `/admin/good_job` with a menu entry in the admin, guarded by the Trek session: anyone who is not an administrator gets a 404 rather than a redirect. Two specs come with it (dashboard access per role, and the mail delivery job). Because GoodJob discards a failed job, every `deliver_later` email now goes through an installed `MailDeliveryJob` that retries five times with a growing delay, and `config/database.yml` reserves connections for the job threads on top of the web threads (`GOOD_JOB_MAX_THREADS`, which GoodJob defaults to `RAILS_MAX_THREADS`). See [Background jobs](https://trek.etamin.studio/background-jobs). **Upgrade note:** apps installed before this version can run `rails g trek:install:good_job` — it is idempotent and skips what is already in place — then add the dashboard entry to `app/views/layouts/admin.html.slim` (an item with `text: t("admin.jobs")`, `href: "/admin/good_job"`, `allowed_to: Current.user.admin?` in the settings section) and run the migration it generates. Apps already on GoodJob only need the Gemfile left alone and their `config/initializers/good_job.rb` compared with the generated one; apps still on Solid Queue must drop the `queue` database from their deploy target as well.
|
|
11
|
+
- Dashboard tiles (`Trek::Dashboard::TileComponent`) opening in a new tab (`target: "_blank"`) show an external link icon after their text, and a tile's color is the accent of what it holds (`data-accent-color`), which can use `var(--accent-*)`.
|
|
12
|
+
- Public accounts: `rails g trek:public_accounts Customer` gives the site's or the mobile app's users (customers, members…) a model of their own, apart from the admin's `User`, with its own table, sessions and sign-in, so nothing public can reach a staff account. They sign in either with a code emailed to them, which creates the account the first time, or with `--sign-in=password` with a password, the email confirmed and the password reset by a link; a website gets pages and a cookie, `--api` JSON endpoints and a JWT naming a session, so it can be revoked, and `--model-only` neither, for an app whose sign-in is its own. See [Public accounts](https://trek.etamin.studio/reference/generators/public-accounts).
|
|
13
|
+
- `Trek::Users::SignInLockout` sends its email through `sign_in_lockout_mailer` (`"AdminMailer"` by default), and `Trek::PurgeExpiredSessionsJob` takes the session model to purge (`User::Session` by default), for public accounts.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Trek requires the `prosemirror` gem 1.0 or later (was 0.7.1), and works with 1.1: rendering content (`formatted_content`) raised `ArgumentError` with it. `Trek::Content::Document#to_html` takes 1.1's `heading_ids: true`.
|
|
18
|
+
- `rails g trek:install` ends by listing the generators it doesn't run, to run as the app needs them: `trek:scaffold`, `trek:taxonomies`, `trek:audit_log`, `trek:public_accounts` and `trek:scalingo`.
|
|
19
|
+
- `trek:install:audit_log` and `trek:install:scalingo` are now `trek:audit_log` and `trek:scalingo`, as `trek:install` doesn't run them: `trek:install:*` is left to its own steps. The former names still work, with a deprecation warning, until Trek 3. **Upgrade note:** update the generator names in your docs and scripts.
|
|
20
|
+
- `trek:install:ruby` now pins **Ruby 4.0.9** (was 4.0.7), and the CI images (repo + generated `.gitlab-ci.yml` template) use the matching `4.0.9` tag. **Upgrade note:** existing apps can set `4.0.9` in `.ruby-version` and bump the `ci-ruby` image tag in `.gitlab-ci.yml`.
|
|
21
|
+
- Asking every user for a new password goes through its own controller, `Admin::PasswordRenewalsController#create` (`POST /admin/password_renewal`), instead of a `require_password_renewal` action of `Admin::UsersController`. **Upgrade note:** copy `app/controllers/admin/password_renewals_controller.rb` from Trek's templates (`lib/generators/trek/templates/controllers/admin/`), add `resource :password_renewal, only: :create` to the `admin` namespace of `config/routes.rb`, remove `post :require_password_renewal, on: :collection` from `resources :users` and the `require_password_renewal` action from `Admin::UsersController`, and point the button of `app/views/admin/users/index.html.slim` to `[:admin, :password_renewal]`.
|
|
22
|
+
- The new sign-in email (`AdminMailer#new_sign_in`) gives the IP address's host name next to it, as the active sessions do, looked up when the email is sent. **Upgrade note:** to get it, copy `new_sign_in` from Trek's `lib/generators/trek/templates/mailers/admin_mailer.rb`, and replace `@ip` with `@address` in `app/views/admin_mailer/new_sign_in.*`.
|
|
23
|
+
- Content is cleaned before it's saved (`Trek::Contentable`): empty paragraphs, empty list items and lists left empty are removed, as rendering already skipped them, so the stored JSON, `content_text` and searches no longer carry them. The document stays one the content editor opens, and node types or attributes the schema doesn't know are kept. The editor's JSON string is now stored as a document, which `Fragment.search` can search. **Upgrade note:** existing content is cleaned the next time it's saved; empty paragraphs authors used for spacing are removed for good. Apps that pruned empty paragraphs before saving can drop that code.
|
|
24
|
+
- The content editor's panels label their fields more explicitly: « Largeur d'affichage », « Légende de l'image », « Lien vers », « Ouvrir ce lien dans… », « Texte du lien », « Texte du bouton », and « Dépasse sur les côtés » for the wider image size (in English: "Display width", "Image caption", "Link to", "Open this link in…", "Link text", "Button text", "Extends past the sides").
|
|
25
|
+
- Trek is now developed and tested against **prosemirror 1.0**, its first stable release, which imports HTML and Markdown about a quarter faster. Trek already accepted it (`>= 0.7.1, < 2`), and doesn't use what 1.0 renames. **Upgrade note:** an app calling `Schema#parse_html`, `#parse_markdown` or `#parse_text`, or `Prosemirror::TextAlign`, renames them `#from_html`, `#from_markdown`, `#from_text` and `Prosemirror::Extensions::TextAlign` when it runs `bundle update prosemirror` (see [its changelog](https://github.com/etaminstudio/prosemirror/blob/main/CHANGELOG.md)).
|
|
26
|
+
- Failed form submissions answer with `:unprocessable_content` (422), Rack's name for it since 3.1, instead of the deprecated `:unprocessable_entity`, in `Trek::ResourceController`, the sign-in controller and the generated specs, which printed a deprecation warning in every run. **Upgrade note:** replace `:unprocessable_entity` with `:unprocessable_content` in the app's own controllers and specs to silence the warning.
|
|
27
|
+
- **Security:** the content editor runs on **Tiptap 3** (was 2), which fixes `mergeAttributes()` turning an own `__proto__` key into DOM attributes ([GHSA-cp6q-959q-f8rh](https://github.com/advisories/GHSA-cp6q-959q-f8rh)). Its floating menu uses Floating UI instead of Tippy. The editor behaves as before: no underline, and no empty paragraph added after a final block. **Upgrade note:** run `yarn up trek`, and update the app's own Tiptap extensions, if any, to Tiptap 3 (see [Upgrade from Tiptap v2](https://tiptap.dev/docs/guides/upgrade-tiptap-v2)).
|
|
28
|
+
- `Trek::Form::ImageFieldComponent` (`f.image_field`) shows two icons over its thumbnail, on hover and focus, opening the original image in a new tab or downloading it, instead of a « See original » button under « Replace » and « Remove », which wrapped onto two lines in French.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- `Trek::TypographyFormatter` broke content saved from the content editor: given the editor's JSON string, it formatted it as plain text, and the non-breaking spaces it added before colons made the JSON invalid. It now parses the document, and formats its text nodes. **Upgrade note:** an app that added `:content` to `format_attributes` may hold records whose content no longer parses (`formatted_content` raises `JSON::ParserError`), which the editor can't open either: restore them from a backup.
|
|
33
|
+
- `Trek::TypographyFormatter` no longer adds a space before a colon, semicolon, `!`, `?`, `%`, `€` or `$` inside a word: times (`10:30`), URLs (`https://…?a=1`) and ratios (`3:1`) are left alone, and one space goes before a group of signs (`Quoi ?!`). Apostrophes and the space after `«` now work next to accented letters (`l’été`, `« Été »`). Spaces earlier versions put inside a word (`10 :30`, `https ://`) are removed. **Upgrade note:** formatted titles and content are repaired the next time they're saved.
|
|
34
|
+
- `content_text` ran the content's paragraphs and lines together (`Line oneLine two`), which shows in the excerpts of the admin's fragments index: it now separates blocks with a blank line, and hard breaks with a newline (`Prosemirror::Document#to_text`).
|
|
35
|
+
- Reordering a list in the admin (`Trek::Reorderable`) could leave records out of place: it saved them one at a time while acts_as_list, and closure_tree for the trees ordered with `numeric_order`, renumbered the other records at each save. A list numbered from 1, acts_as_list's default, lost a record on most moves, as the list posts positions from 0. The posted order is now applied as a whole: in an `acts_as_list_no_update` block, from the list's `top_of_list`, or with closure_tree's `prepend_sibling` and `append_sibling` for a tree. Records missing from the list (deleted meanwhile, or left out by `reorderable_objects`) are skipped. **Upgrade note:** you can now drop your own `reorder` actions written to work around it.
|
|
36
|
+
- Adding a call to action from the content editor failed with `NoMethodError: undefined method 'color'`: the prompt panel's response read a `color` that `Trek::ContentEditor::Prompt` never had, and the panel has no field for. Prompts no longer have a color: the editor's block, the panel and `Trek::Content::PromptsBlock` drop it, and the site's link loses its `data-color`. A color already stored in content stays in the JSON, unrendered. **Upgrade note:** an app styling prompts with `[data-color]`, or reading `@color` in its own `PromptsBlock`, can drop that code.
|
|
37
|
+
- **Security:** the content editor showed image and call-to-action blocks by writing their attributes into HTML: an alternative text, caption or button text containing `"` or `<` broke the block, or injected markup into the admin. They are now built as DOM nodes, their texts as text.
|
|
38
|
+
- The content editor's toolbar buttons show the styles and the block where the cursor is right after a click: the bold, italic and heading buttons marked their icon instead of the button until the cursor moved.
|
|
39
|
+
|
|
3
40
|
## [2.5.0] - 2026-10-25
|
|
4
41
|
|
|
5
42
|
### Changed
|
data/Gemfile
CHANGED
|
@@ -24,8 +24,13 @@ end
|
|
|
24
24
|
group :test do
|
|
25
25
|
gem "bcrypt", "~> 3.1"
|
|
26
26
|
gem "capybara", "~> 3.38"
|
|
27
|
+
# System specs: a headless Chrome driven through its DevTools protocol, and the server it browses
|
|
28
|
+
gem "cuprite", "~> 0.19"
|
|
29
|
+
# The dummy app's API accounts (trek:public_accounts --api)
|
|
30
|
+
gem "jwt", "~> 3.1"
|
|
27
31
|
gem "oaken", "~> 1.0"
|
|
28
32
|
gem "pg", "~> 1.5"
|
|
33
|
+
gem "puma", "~> 8.0"
|
|
29
34
|
gem "simplecov", "~> 0.22.0"
|
|
30
35
|
gem "simplecov-cobertura", "~> 3.0"
|
|
31
36
|
end
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
trek (2.
|
|
4
|
+
trek (2.6.0)
|
|
5
5
|
action_policy (~> 0.6)
|
|
6
6
|
actioncable
|
|
7
7
|
acts_as_list (~> 1.1)
|
|
@@ -22,7 +22,7 @@ PATH
|
|
|
22
22
|
mobility (~> 1.3.2)
|
|
23
23
|
phonelib (~> 0.8)
|
|
24
24
|
postmark-rails
|
|
25
|
-
prosemirror (>= 0
|
|
25
|
+
prosemirror (>= 1.0, < 2)
|
|
26
26
|
rails (>= 8.0, < 8.2)
|
|
27
27
|
rails-healthcheck
|
|
28
28
|
rails-i18n (>= 6.0)
|
|
@@ -180,6 +180,9 @@ GEM
|
|
|
180
180
|
addressable
|
|
181
181
|
base64
|
|
182
182
|
ssrf_filter (~> 1.5)
|
|
183
|
+
cuprite (0.19)
|
|
184
|
+
capybara (~> 3.0)
|
|
185
|
+
ferrum (~> 0.19.1)
|
|
183
186
|
date (3.6.0)
|
|
184
187
|
deepl-rb (3.9.0)
|
|
185
188
|
diff-lcs (1.6.2)
|
|
@@ -222,6 +225,11 @@ GEM
|
|
|
222
225
|
erb (6.0.7)
|
|
223
226
|
erubi (1.13.1)
|
|
224
227
|
fastimage (2.4.1)
|
|
228
|
+
ferrum (0.19.1)
|
|
229
|
+
addressable (~> 2.5)
|
|
230
|
+
base64 (~> 0.2)
|
|
231
|
+
concurrent-ruby (~> 1.1)
|
|
232
|
+
websocket-driver (~> 0.7)
|
|
225
233
|
ffi (1.17.4-arm64-darwin)
|
|
226
234
|
ffi (1.17.4-x86_64-darwin)
|
|
227
235
|
ffi (1.17.4-x86_64-linux-gnu)
|
|
@@ -352,11 +360,13 @@ GEM
|
|
|
352
360
|
prettyprint
|
|
353
361
|
prettyprint (0.2.1)
|
|
354
362
|
prism (1.9.0)
|
|
355
|
-
prosemirror (
|
|
363
|
+
prosemirror (1.1.0)
|
|
356
364
|
literal (~> 1.9)
|
|
357
365
|
phlex (~> 2.4)
|
|
358
366
|
zeitwerk (~> 2.6)
|
|
359
367
|
public_suffix (7.0.5)
|
|
368
|
+
puma (8.0.2)
|
|
369
|
+
nio4r (~> 2.0)
|
|
360
370
|
racc (1.8.1)
|
|
361
371
|
rack (3.2.7)
|
|
362
372
|
rack-session (2.1.2)
|
|
@@ -603,8 +613,11 @@ DEPENDENCIES
|
|
|
603
613
|
brakeman (~> 7.0)
|
|
604
614
|
bundler-audit (~> 0.9)
|
|
605
615
|
capybara (~> 3.38)
|
|
616
|
+
cuprite (~> 0.19)
|
|
617
|
+
jwt (~> 3.1)
|
|
606
618
|
oaken (~> 1.0)
|
|
607
619
|
pg (~> 1.5)
|
|
620
|
+
puma (~> 8.0)
|
|
608
621
|
rake (~> 13.0)
|
|
609
622
|
reek (~> 6.1)
|
|
610
623
|
rspec-html-matchers (~> 0.10)
|
data/Makefile
CHANGED
|
@@ -51,6 +51,8 @@ i18n-check: i18n-normalize
|
|
|
51
51
|
git diff --exit-code config/locales
|
|
52
52
|
|
|
53
53
|
release:
|
|
54
|
+
@# Before bumping anything: with a missing or expired token, npm publish fails with a misleading 404
|
|
55
|
+
@npm whoami >/dev/null 2>&1 || { echo "Not signed in to npm, or the token expired: run npm login first."; exit 1; }
|
|
54
56
|
@read -p "New version (current: $$(sed -n 's/.*VERSION = "\(.*\)"/\1/p' lib/trek/version.rb)): " version; \
|
|
55
57
|
if [ -z "$$version" ]; then echo "Version cannot be empty"; exit 1; fi && \
|
|
56
58
|
sed -i '' "s/VERSION = \".*\"/VERSION = \"$$version\"/" lib/trek/version.rb && \
|
|
@@ -46,6 +46,15 @@
|
|
|
46
46
|
transition: transform 0.2s ease-in-out;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/* A tile opening in a new tab: the icon follows the text, on its last line */
|
|
50
|
+
.external {
|
|
51
|
+
--icon-size: 1.4rem;
|
|
52
|
+
|
|
53
|
+
display: inline-block;
|
|
54
|
+
margin-left: 0.6rem;
|
|
55
|
+
vertical-align: -0.1rem;
|
|
56
|
+
}
|
|
57
|
+
|
|
49
58
|
.root.color-amber {
|
|
50
59
|
--icon-color: var(--amber-11);
|
|
51
60
|
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
span(class=class_for("title")) = title
|
|
5
5
|
- if icon
|
|
6
6
|
= render Trek::IconComponent.new(icon, classnames: class_for("icon"))
|
|
7
|
-
span(class=class_for("text"))
|
|
7
|
+
span(class=class_for("text"))
|
|
8
|
+
= formatted_text
|
|
9
|
+
= external_icon
|
|
8
10
|
- else
|
|
9
|
-
div(class=classes)
|
|
11
|
+
div(class=classes data-accent-color=color)
|
|
10
12
|
- if title
|
|
11
13
|
span(class=class_for("title")) = title
|
|
12
14
|
- if icon
|
|
@@ -31,12 +31,22 @@ module Trek
|
|
|
31
31
|
)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
# The tile's color is the accent (`data-accent-color`) of what it holds, which can use `var(--accent-*)`
|
|
34
35
|
def link_data
|
|
35
|
-
|
|
36
|
+
{ accent_color: color }.merge(data, turbo_method: method).compact
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
def link_rel
|
|
39
|
-
rel || ("noopener" if
|
|
40
|
+
rel || ("noopener" if new_tab?)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def new_tab?
|
|
44
|
+
target == "_blank"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# After the text of a link opening in a new tab
|
|
48
|
+
def external_icon
|
|
49
|
+
render Trek::IconComponent.new("trek/external", classnames: class_for("external"), aria_hidden: true) if new_tab?
|
|
40
50
|
end
|
|
41
51
|
|
|
42
52
|
def formatted_text
|
|
@@ -8,34 +8,22 @@ div(
|
|
|
8
8
|
button.bold(
|
|
9
9
|
class=class_for("button")
|
|
10
10
|
type="button"
|
|
11
|
-
data
|
|
11
|
+
data=command_data("toggleBold", active: "bold")
|
|
12
12
|
) = render Trek::IconComponent.new("trek/bold", title: t(".bold"))
|
|
13
13
|
|
|
14
14
|
button.italic(
|
|
15
15
|
class=class_for("button")
|
|
16
16
|
type="button"
|
|
17
|
-
data
|
|
17
|
+
data=command_data("toggleItalic", active: "italic")
|
|
18
18
|
) = render Trek::IconComponent.new("trek/italic", title: t(".italic"))
|
|
19
19
|
|
|
20
|
-
/ button.strike(
|
|
21
|
-
/ class=class_for("button")
|
|
22
|
-
/ type="button"
|
|
23
|
-
/ data-action=stimulus_action("toggleStrike")
|
|
24
|
-
/ ) strike
|
|
25
|
-
|
|
26
|
-
/ button.code(
|
|
27
|
-
/ class=class_for("button")
|
|
28
|
-
/ type="button"
|
|
29
|
-
/ data-action=stimulus_action("toggleCode")
|
|
30
|
-
/ ) code
|
|
31
|
-
|
|
32
20
|
/ The panel opening is handled by the hidden button's
|
|
33
21
|
openStackedPanelWhenLoaded action — a direct openPanel here would
|
|
34
22
|
pop the (possibly empty) primary panel alongside the stacked one.
|
|
35
23
|
button.link(
|
|
36
24
|
class=class_for("button")
|
|
37
25
|
type="button"
|
|
38
|
-
data
|
|
26
|
+
data={ action: stimulus_action("toggleLink"), **state_data("link") }
|
|
39
27
|
) = render Trek::IconComponent.new("trek/link", title: t(".link"))
|
|
40
28
|
|
|
41
29
|
= link_to "",
|
|
@@ -51,7 +39,7 @@ div(
|
|
|
51
39
|
button(
|
|
52
40
|
class=class_for("button")
|
|
53
41
|
type="button"
|
|
54
|
-
data
|
|
42
|
+
data=command_data("unsetAllMarks")
|
|
55
43
|
)
|
|
56
44
|
= render Trek::IconComponent.new(\
|
|
57
45
|
"trek/eraser",
|
|
@@ -61,7 +49,7 @@ div(
|
|
|
61
49
|
button(
|
|
62
50
|
class=class_for("button")
|
|
63
51
|
type="button"
|
|
64
|
-
data
|
|
52
|
+
data=command_data("setHardBreak")
|
|
65
53
|
)
|
|
66
54
|
= render Trek::IconComponent.new(\
|
|
67
55
|
"trek/return",
|
|
@@ -74,86 +62,36 @@ div(
|
|
|
74
62
|
button.paragraph(
|
|
75
63
|
class=class_for("button")
|
|
76
64
|
type="button"
|
|
77
|
-
data
|
|
65
|
+
data=command_data("setParagraph", active: "paragraph")
|
|
78
66
|
)
|
|
79
67
|
= render Trek::IconComponent.new(\
|
|
80
68
|
"trek/paragraph",
|
|
81
69
|
title: t(".paragraph"),
|
|
82
70
|
)
|
|
83
71
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
class=class_for("button")
|
|
93
|
-
type="button"
|
|
94
|
-
data-action=stimulus_action("toggleHeading")
|
|
95
|
-
data-level=2
|
|
96
|
-
title=t(".h2")
|
|
97
|
-
) h2
|
|
98
|
-
|
|
99
|
-
button.h3(
|
|
100
|
-
class=class_for("button")
|
|
101
|
-
type="button"
|
|
102
|
-
data-action=stimulus_action("toggleHeading")
|
|
103
|
-
data-level=3
|
|
104
|
-
title=t(".h3")
|
|
105
|
-
) h3
|
|
106
|
-
|
|
107
|
-
button.h4(
|
|
108
|
-
class=class_for("button")
|
|
109
|
-
type="button"
|
|
110
|
-
data-action=stimulus_action("toggleHeading")
|
|
111
|
-
data-level=4
|
|
112
|
-
title=t(".h4")
|
|
113
|
-
) h4
|
|
114
|
-
|
|
115
|
-
/ button.h5(
|
|
116
|
-
/ class=class_for("button")
|
|
117
|
-
/ type="button"
|
|
118
|
-
/ data-action=stimulus_action("toggleHeading")
|
|
119
|
-
/ data-level=5
|
|
120
|
-
/ title=t(".h5")
|
|
121
|
-
/ ) h5
|
|
122
|
-
|
|
123
|
-
/ button.h6(
|
|
124
|
-
/ class=class_for("button")
|
|
125
|
-
/ type="button"
|
|
126
|
-
/ data-action=stimulus_action("toggleHeading")
|
|
127
|
-
/ data-level=6
|
|
128
|
-
/ title=t(".h6")
|
|
129
|
-
/ ) h6
|
|
72
|
+
- [2, 3, 4].each do |level|
|
|
73
|
+
button(
|
|
74
|
+
class=class_for("button")
|
|
75
|
+
class="h#{level}"
|
|
76
|
+
type="button"
|
|
77
|
+
data=command_data("toggleHeading", active: "heading", level:)
|
|
78
|
+
title=t(".h#{level}")
|
|
79
|
+
) = "h#{level}"
|
|
130
80
|
|
|
131
81
|
button.bulletList(
|
|
132
82
|
class=class_for("button")
|
|
133
83
|
type="button"
|
|
134
|
-
data
|
|
84
|
+
data=command_data("toggleBulletList", active: "bulletList")
|
|
135
85
|
)
|
|
136
86
|
= render Trek::IconComponent.new( \
|
|
137
87
|
"trek/list-bullets",
|
|
138
88
|
title: t(".bullet_list"),
|
|
139
89
|
)
|
|
140
90
|
|
|
141
|
-
/ button.orderedList(
|
|
142
|
-
/ class=class_for("button")
|
|
143
|
-
/ type="button"
|
|
144
|
-
/ data-action=stimulus_action("toggleOrderedList")
|
|
145
|
-
/ ) ordered list
|
|
146
|
-
|
|
147
|
-
/ button.codeBlock(
|
|
148
|
-
/ class=class_for("button")
|
|
149
|
-
/ type="button"
|
|
150
|
-
/ data-action=stimulus_action("toggleCodeBlock")
|
|
151
|
-
/ ) code block
|
|
152
|
-
|
|
153
91
|
button.blockquote(
|
|
154
92
|
class=class_for("button")
|
|
155
93
|
type="button"
|
|
156
|
-
data
|
|
94
|
+
data=command_data("toggleBlockquote", active: "blockquote")
|
|
157
95
|
)
|
|
158
96
|
= render Trek::IconComponent.new( \
|
|
159
97
|
"trek/quotation",
|
|
@@ -163,37 +101,25 @@ div(
|
|
|
163
101
|
button(
|
|
164
102
|
class=class_for("button")
|
|
165
103
|
type="button"
|
|
166
|
-
data
|
|
104
|
+
data=command_data("setHorizontalRule")
|
|
167
105
|
)
|
|
168
106
|
= render Trek::IconComponent.new( \
|
|
169
107
|
"trek/hr",
|
|
170
108
|
title: t(".horizontal_rule"),
|
|
171
109
|
)
|
|
172
110
|
|
|
173
|
-
/ button(
|
|
174
|
-
/ class=class_for("button")
|
|
175
|
-
/ type="button"
|
|
176
|
-
/ data-action=stimulus_action("clearNodes")
|
|
177
|
-
/ ) clear nodes
|
|
178
|
-
|
|
179
111
|
button(
|
|
180
112
|
class=class_names_for("button", "button-end", map_args: true)
|
|
181
113
|
type="button"
|
|
182
|
-
data
|
|
114
|
+
data=command_data("undo")
|
|
183
115
|
) = render Trek::IconComponent.new("trek/undo", title: t(".undo"))
|
|
184
116
|
|
|
185
117
|
button(
|
|
186
118
|
class=class_for("button")
|
|
187
119
|
type="button"
|
|
188
|
-
data
|
|
120
|
+
data=command_data("redo")
|
|
189
121
|
) = render Trek::IconComponent.new("trek/redo", title: t(".redo"))
|
|
190
122
|
|
|
191
|
-
/ button(
|
|
192
|
-
/ class=class_for("button")
|
|
193
|
-
/ type="button"
|
|
194
|
-
/ data-action=stimulus_action("insertFrame")
|
|
195
|
-
/ ) frame
|
|
196
|
-
|
|
197
123
|
div(
|
|
198
124
|
class=class_for("content")
|
|
199
125
|
data=content_data_attributes
|