railsmaker-core 0.0.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.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +169 -0
  3. data/bin/railsmaker +344 -0
  4. data/lib/railsmaker/generators/app_generator.rb +157 -0
  5. data/lib/railsmaker/generators/auth_generator.rb +97 -0
  6. data/lib/railsmaker/generators/base_generator.rb +39 -0
  7. data/lib/railsmaker/generators/concerns/gsub_validation.rb +24 -0
  8. data/lib/railsmaker/generators/litestream_generator.rb +89 -0
  9. data/lib/railsmaker/generators/mailjet_generator.rb +68 -0
  10. data/lib/railsmaker/generators/opentelemetry_generator.rb +79 -0
  11. data/lib/railsmaker/generators/plausible_generator.rb +33 -0
  12. data/lib/railsmaker/generators/plausible_instrumentation_generator.rb +28 -0
  13. data/lib/railsmaker/generators/sentry_generator.rb +46 -0
  14. data/lib/railsmaker/generators/server_command_generator.rb +178 -0
  15. data/lib/railsmaker/generators/signoz_generator.rb +33 -0
  16. data/lib/railsmaker/generators/signoz_opentelemetry_generator.rb +37 -0
  17. data/lib/railsmaker/generators/templates/app/credentials.example.yml +14 -0
  18. data/lib/railsmaker/generators/templates/app/main_index.html.erb +71 -0
  19. data/lib/railsmaker/generators/templates/auth/app/controllers/omniauth_callbacks_controller.rb +18 -0
  20. data/lib/railsmaker/generators/templates/litestream/litestream.yml.erb +32 -0
  21. data/lib/railsmaker/generators/templates/opentelemetry/lograge.rb.erb +9 -0
  22. data/lib/railsmaker/generators/templates/shell_scripts/plausible.sh.erb +51 -0
  23. data/lib/railsmaker/generators/templates/shell_scripts/signoz.sh.erb +38 -0
  24. data/lib/railsmaker/generators/templates/shell_scripts/signoz_opentelemetry.sh.erb +49 -0
  25. data/lib/railsmaker/generators/templates/ui/app/assets/images/og-image.webp +0 -0
  26. data/lib/railsmaker/generators/templates/ui/app/assets/images/plausible-screenshot.png +0 -0
  27. data/lib/railsmaker/generators/templates/ui/app/assets/images/signoz-screenshot.png +0 -0
  28. data/lib/railsmaker/generators/templates/ui/app/controllers/demo_controller.rb +7 -0
  29. data/lib/railsmaker/generators/templates/ui/app/controllers/pages_controller.rb +4 -0
  30. data/lib/railsmaker/generators/templates/ui/app/helpers/seo_helper.rb +39 -0
  31. data/lib/railsmaker/generators/templates/ui/app/javascript/controllers/flash_controller.js +14 -0
  32. data/lib/railsmaker/generators/templates/ui/app/javascript/controllers/index.js +11 -0
  33. data/lib/railsmaker/generators/templates/ui/app/javascript/controllers/scroll_fade_controller.js +27 -0
  34. data/lib/railsmaker/generators/templates/ui/app/views/clearance_mailer/change_password.html.erb +8 -0
  35. data/lib/railsmaker/generators/templates/ui/app/views/clearance_mailer/change_password.text.erb +5 -0
  36. data/lib/railsmaker/generators/templates/ui/app/views/demo/analytics.html.erb +214 -0
  37. data/lib/railsmaker/generators/templates/ui/app/views/demo/index.html.erb +312 -0
  38. data/lib/railsmaker/generators/templates/ui/app/views/demo/support.html.erb +147 -0
  39. data/lib/railsmaker/generators/templates/ui/app/views/layouts/_navbar.html.erb +193 -0
  40. data/lib/railsmaker/generators/templates/ui/app/views/layouts/application.html.erb +62 -0
  41. data/lib/railsmaker/generators/templates/ui/app/views/main/index.html.erb +320 -0
  42. data/lib/railsmaker/generators/templates/ui/app/views/pages/privacy.html.erb +63 -0
  43. data/lib/railsmaker/generators/templates/ui/app/views/pages/terms.html.erb +54 -0
  44. data/lib/railsmaker/generators/templates/ui/app/views/passwords/create.html.erb +9 -0
  45. data/lib/railsmaker/generators/templates/ui/app/views/passwords/edit.html.erb +21 -0
  46. data/lib/railsmaker/generators/templates/ui/app/views/passwords/new.html.erb +26 -0
  47. data/lib/railsmaker/generators/templates/ui/app/views/sessions/new.html.erb +49 -0
  48. data/lib/railsmaker/generators/templates/ui/app/views/shared/_auth_layout.html.erb +24 -0
  49. data/lib/railsmaker/generators/templates/ui/app/views/shared/_flash.html.erb +19 -0
  50. data/lib/railsmaker/generators/templates/ui/app/views/shared/_footer.html.erb +52 -0
  51. data/lib/railsmaker/generators/templates/ui/app/views/shared/_structured_data.html.erb +20 -0
  52. data/lib/railsmaker/generators/templates/ui/app/views/users/new.html.erb +49 -0
  53. data/lib/railsmaker/generators/templates/ui/config/sitemap.rb +33 -0
  54. data/lib/railsmaker/generators/templates/ui/public/icon.png +0 -0
  55. data/lib/railsmaker/generators/templates/ui/public/icon.svg +5 -0
  56. data/lib/railsmaker/generators/templates/ui/public/robots.txt +8 -0
  57. data/lib/railsmaker/generators/ui_generator.rb +68 -0
  58. data/lib/railsmaker.rb +29 -0
  59. metadata +359 -0
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMaker
4
+ module Generators
5
+ class SignozGenerator < ServerCommandGenerator
6
+ source_root File.expand_path('templates/shell_scripts', __dir__)
7
+
8
+ class_option :signoz_version, type: :string, default: 'v0.71.0',
9
+ desc: 'Version of SigNoz to install'
10
+
11
+ def initialize(*args)
12
+ super
13
+ @signoz_version = options[:signoz_version]
14
+ end
15
+
16
+ private
17
+
18
+ def script_name
19
+ 'signoz'
20
+ end
21
+
22
+ def check_path
23
+ '~/signoz'
24
+ end
25
+
26
+ def title
27
+ "Installing SigNoz on remote server #{options[:ssh_user]}@#{options[:ssh_host]}"
28
+ end
29
+
30
+ attr_reader :signoz_version
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMaker
4
+ module Generators
5
+ class SignozOpentelemetryGenerator < ServerCommandGenerator
6
+ source_root File.expand_path('templates/shell_scripts', __dir__)
7
+
8
+ class_option :signoz_server_host, type: :string, required: true, desc: 'Host where SigNoz is running'
9
+ class_option :hostname, type: :string, desc: 'Override the server hostname'
10
+ class_option :signoz_version, type: :string, default: 'v0.71.0',
11
+ desc: 'Version of SigNoz to install'
12
+
13
+ def initialize(*args)
14
+ super
15
+ @signoz_server_host = options[:signoz_server_host]
16
+ @hostname = options[:hostname]
17
+ @signoz_version = options[:signoz_version]
18
+ end
19
+
20
+ private
21
+
22
+ def script_name
23
+ 'signoz_opentelemetry'
24
+ end
25
+
26
+ def check_path
27
+ '~/signoz-opentelemetry'
28
+ end
29
+
30
+ def title
31
+ "Installing SigNoz OpenTelemetry client on remote server #{options[:ssh_user]}@#{options[:ssh_host]}"
32
+ end
33
+
34
+ attr_reader :signoz_server_host, :hostname, :signoz_version
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,14 @@
1
+ # Needed credentials.yml. To edit yours:
2
+ # VISUAL="vim" bin/rails credentials:edit
3
+
4
+ secret_key_base: "your-secret-key-base"
5
+ google_oauth:
6
+ client_id: "your-client-id"
7
+ client_secret: "your-client-secret"
8
+ sentry_dsn: "your-sentry-dsn"
9
+ mailjet:
10
+ api_key: "your-api-key"
11
+ secret_key: "your-secret-key"
12
+ app:
13
+ host: "your-host"
14
+ mailer_sender: "YourApp <no-reply@your-host>"
@@ -0,0 +1,71 @@
1
+ <div class="navbar bg-base-100 fixed w-full z-20 top-0 start-0 border-b border-gray-200 dark:border-gray-600">
2
+ <div class="flex-1">
3
+ <a class="btn btn-ghost text-xl">RailsMaker</a>
4
+ </div>
5
+ <div class="flex-none">
6
+ <div class="dropdown dropdown-end">
7
+ <div tabindex="0" role="button" class="btn btn-ghost btn-circle">
8
+ <div class="indicator">
9
+ <svg
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ class="h-5 w-5"
12
+ fill="none"
13
+ viewBox="0 0 24 24"
14
+ stroke="currentColor">
15
+ <path
16
+ stroke-linecap="round"
17
+ stroke-linejoin="round"
18
+ stroke-width="2"
19
+ d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
20
+ </svg>
21
+ <span class="badge badge-sm indicator-item">8</span>
22
+ </div>
23
+ </div>
24
+ <div
25
+ tabindex="0"
26
+ class="card card-compact dropdown-content bg-base-100 z-1 mt-3 w-52 shadow">
27
+ <div class="card-body">
28
+ <span class="text-lg font-bold">8 Items</span>
29
+ <span class="text-info">Subtotal: $999</span>
30
+ <div class="card-actions">
31
+ <button class="btn btn-primary btn-block">View cart</button>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ <div class="dropdown dropdown-end">
37
+ <div tabindex="0" role="button" class="btn btn-ghost btn-circle avatar">
38
+ <div class="w-10 rounded-full">
39
+ <img
40
+ alt="Tailwind CSS Navbar component"
41
+ src="https://img.daisyui.com/images/stock/photo-1534528741775-53994a69daeb.webp" />
42
+ </div>
43
+ </div>
44
+ <ul
45
+ tabindex="0"
46
+ class="menu menu-sm dropdown-content bg-base-100 rounded-box z-1 mt-3 w-52 p-2 shadow">
47
+ <li>
48
+ <a class="justify-between">
49
+ Profile
50
+ <span class="badge">New</span>
51
+ </a>
52
+ </li>
53
+ <li><a>Settings</a></li>
54
+ <li><a>Logout</a></li>
55
+ </ul>
56
+ </div>
57
+ </div>
58
+ </div>
59
+
60
+ <div class="hero bg-base-200 min-h-screen">
61
+ <div class="hero-content text-center">
62
+ <div class="max-w-md">
63
+ <h1 class="text-5xl font-bold">Hello there</h1>
64
+ <p class="py-6">
65
+ Provident cupiditate voluptatem et in. Quaerat fugiat ut assumenda excepturi exercitationem
66
+ quasi. In deleniti eaque aut repudiandae et a id nisi.
67
+ </p>
68
+ <button class="btn btn-primary">Get Started</button>
69
+ </div>
70
+ </div>
71
+ </div>
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class OmniauthCallbacksController < ApplicationController
4
+ def google_oauth2
5
+ user = User.from_omniauth(request.env['omniauth.auth'])
6
+
7
+ if user.persisted?
8
+ sign_in user
9
+ redirect_to demo_url, notice: 'Successfully signed in with Google!'
10
+ else
11
+ redirect_to sign_in_url, alert: 'Failed to sign in with Google.'
12
+ end
13
+ end
14
+
15
+ def failure
16
+ redirect_to sign_in_url, alert: 'Failed to sign in with Google.'
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ access-key-id: ${LITESTREAM_ACCESS_KEY_ID}
2
+ secret-access-key: ${LITESTREAM_SECRET_ACCESS_KEY}
3
+
4
+ dbs:
5
+ - path: /rails/storage/production.sqlite3
6
+ replicas:
7
+ - type: s3
8
+ bucket: ${LITESTREAM_BUCKET_NAME}
9
+ path: db_backup/production
10
+ endpoint: ${LITESTREAM_ENDPOINT}
11
+ region: ${LITESTREAM_REGION}
12
+ - path: /rails/storage/production_cache.sqlite3
13
+ replicas:
14
+ - type: s3
15
+ bucket: ${LITESTREAM_BUCKET_NAME}
16
+ path: db_backup/production_cache
17
+ endpoint: ${LITESTREAM_ENDPOINT}
18
+ region: ${LITESTREAM_REGION}
19
+ - path: /rails/storage/production_queue.sqlite3
20
+ replicas:
21
+ - type: s3
22
+ bucket: ${LITESTREAM_BUCKET_NAME}
23
+ path: db_backup/production_queue
24
+ endpoint: ${LITESTREAM_ENDPOINT}
25
+ region: ${LITESTREAM_REGION}
26
+ - path: /rails/storage/production_cable.sqlite3
27
+ replicas:
28
+ - type: s3
29
+ bucket: ${LITESTREAM_BUCKET_NAME}
30
+ path: db_backup/production_cable
31
+ endpoint: ${LITESTREAM_ENDPOINT}
32
+ region: ${LITESTREAM_REGION}
@@ -0,0 +1,9 @@
1
+ Rails.application.configure do
2
+ config.lograge.enabled = true
3
+ config.lograge.formatter = Lograge::Formatters::Logstash.new
4
+ config.lograge.custom_options = lambda do |event|
5
+ {
6
+ params: event.payload[:params].except("controller", "action")
7
+ }
8
+ end
9
+ end
@@ -0,0 +1,51 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ if ! command -v docker &> /dev/null; then
5
+ echo "Error: Docker is not installed. Please install Docker first."
6
+ echo "Visit https://docs.docker.com/get-docker/ for installation instructions."
7
+ exit 1
8
+ fi
9
+
10
+ if ! command -v docker compose &> /dev/null; then
11
+ echo "Error: Docker Compose is not installed. Please install Docker Compose first."
12
+ echo "Visit https://docs.docker.com/compose/install/ for installation instructions."
13
+ exit 1
14
+ fi
15
+
16
+ if ! command -v git &> /dev/null; then
17
+ echo "Error: Git is not installed. Please install Git first."
18
+ echo "Visit https://git-scm.com/downloads for installation instructions."
19
+ exit 1
20
+ fi
21
+
22
+ echo "📝 Cloning Plausible repository..."
23
+ git clone -b v2.1.4 --single-branch https://github.com/plausible/community-edition plausible-ce
24
+ cd plausible-ce
25
+
26
+ echo "⚙️ Configuring environment..."
27
+ touch .env
28
+ echo "BASE_URL=https://<%= analytics_host %>" >> .env
29
+ echo "SECRET_KEY_BASE=$(openssl rand -base64 48)" >> .env
30
+ echo "HTTP_PORT=80" >> .env
31
+ echo "HTTPS_PORT=443" >> .env
32
+
33
+ echo "🔧 Creating docker-compose override..."
34
+ cat > compose.override.yml << 'EOF'
35
+ services:
36
+ plausible:
37
+ ports:
38
+ - 80:80
39
+ - 443:443
40
+ EOF
41
+
42
+ echo "🚀 Starting Plausible services... (it may take a while)"
43
+ docker compose up -d --quiet-pull
44
+
45
+ echo "✨ Verifying services..."
46
+ if docker compose ps --status running | grep -q "plausible"; then
47
+ echo "✅ Plausible Analytics is running successfully!"
48
+ else
49
+ echo "❌ Error: Plausible Analytics failed to start. Please check the logs with 'docker compose logs'"
50
+ exit 1
51
+ fi
@@ -0,0 +1,38 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ if ! command -v docker &> /dev/null; then
5
+ echo "Error: Docker is not installed. Please install Docker first."
6
+ echo "Visit https://docs.docker.com/get-docker/ for installation instructions."
7
+ exit 1
8
+ fi
9
+
10
+ if ! command -v docker compose &> /dev/null; then
11
+ echo "Error: Docker Compose is not installed. Please install Docker Compose first."
12
+ echo "Visit https://docs.docker.com/compose/install/ for installation instructions."
13
+ exit 1
14
+ fi
15
+
16
+ if ! command -v git &> /dev/null; then
17
+ echo "Error: Git is not installed. Please install Git first."
18
+ echo "Visit https://git-scm.com/downloads for installation instructions."
19
+ exit 1
20
+ fi
21
+
22
+ echo "📝 Cloning SigNoz repository..."
23
+ git clone -b main https://github.com/SigNoz/signoz.git --depth 1 --branch <%= signoz_version %>
24
+
25
+ cd signoz/deploy/
26
+
27
+ echo "🚀 Starting SigNoz services... (it may take a while)"
28
+ docker compose -f docker/docker-compose.yaml up -d --remove-orphans --quiet-pull
29
+
30
+ echo "✨ Verifying services..."
31
+ if docker compose -f docker/docker-compose.yaml ps --status running | grep -q "query-service"; then
32
+ echo "✅ SigNoz server is running successfully!"
33
+ else
34
+ echo "❌ Error: SigNoz server failed to start. Please check the logs with 'docker compose logs'"
35
+ exit 1
36
+ fi
37
+
38
+ docker compose -f docker/generator/infra/docker-compose.yaml up -d --remove-orphans --quiet-pull
@@ -0,0 +1,49 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ if ! command -v docker &> /dev/null; then
5
+ echo "Error: Docker is not installed. Please install Docker first."
6
+ echo "Visit https://docs.docker.com/get-docker/ for installation instructions."
7
+ exit 1
8
+ fi
9
+
10
+ if ! command -v docker compose &> /dev/null; then
11
+ echo "Error: Docker Compose is not installed. Please install Docker Compose first."
12
+ echo "Visit https://docs.docker.com/compose/install/ for installation instructions."
13
+ exit 1
14
+ fi
15
+
16
+ if ! command -v git &> /dev/null; then
17
+ echo "Error: Git is not installed. Please install Git first."
18
+ echo "Visit https://git-scm.com/downloads for installation instructions."
19
+ exit 1
20
+ fi
21
+
22
+ git clone -b main https://github.com/SigNoz/signoz.git --depth 1 signoz-opentelemetry --branch <%= signoz_version %>
23
+
24
+ cd signoz-opentelemetry/deploy/
25
+
26
+ echo "📝 Configuring SigNoz OpenTelemetry..."
27
+ sed -i "s|SIGNOZ_COLLECTOR_ENDPOINT=http://host.docker.internal:4317|SIGNOZ_COLLECTOR_ENDPOINT=http://<%= options[:signoz_server_host] %>:4317|" docker/generator/infra/docker-compose.yaml
28
+ sed -i "s|host.name=signoz-host|host.name=<%= options[:hostname] || 'signoz-host' %>|" docker/generator/infra/docker-compose.yaml
29
+ sed -i '/external: true/d' docker/generator/infra/docker-compose.yaml
30
+
31
+ # Add docker group permissions to the otel-agent service
32
+ DOCKER_GID=$(getent group docker | cut -d: -f3)
33
+ sed -i "/image: otel\/opentelemetry-collector-contrib/a\ group_add:\n - ${DOCKER_GID}" docker/generator/infra/docker-compose.yaml
34
+
35
+ # Uncomment the ports section
36
+ sed -i 's/# ports:/ports:/' docker/generator/infra/docker-compose.yaml
37
+ sed -i 's/# - / - /' docker/generator/infra/docker-compose.yaml
38
+ sed -i 's/# - / - /' docker/generator/infra/docker-compose.yaml
39
+
40
+ echo "🚀 Starting SigNoz OpenTelemetry services..."
41
+ docker compose -f docker/generator/infra/docker-compose.yaml up -d --remove-orphans --quiet-pull
42
+
43
+ echo "✨ Verifying services..."
44
+ if docker compose -f docker/generator/infra/docker-compose.yaml ps --status running | grep -q "otel-agent"; then
45
+ echo "✅ SigNoz OpenTelemetry collector is running successfully!"
46
+ else
47
+ echo "❌ Error: SigNoz OpenTelemetry collector failed to start. Please check the logs with 'docker compose logs'"
48
+ exit 1
49
+ fi
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DemoController < ApplicationController
4
+ before_action :require_login
5
+
6
+ def index; end
7
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PagesController < ApplicationController
4
+ end
@@ -0,0 +1,39 @@
1
+ module SeoHelper
2
+ def meta_title(title = nil)
3
+ content_for(:title) { title } if title.present?
4
+ content_for?(:title) ? content_for(:title) : 'RailsMaker - Ship Rails Apps in 15 Minutes'
5
+ end
6
+
7
+ def meta_description(desc = nil)
8
+ content_for(:description) { desc } if desc.present?
9
+ content_for?(:description) ? content_for(:description) : 'A fully self-hosted modern Rails template with authentication, analytics and observability. Ship production-ready apps in minutes, not weeks.'
10
+ end
11
+
12
+ def meta_image(image = nil)
13
+ content_for(:og_image) { image } if image.present?
14
+ content_for?(:og_image) ? content_for(:og_image) : asset_url('og-image.webp')
15
+ end
16
+
17
+ def meta_keywords(keywords = nil)
18
+ content_for(:keywords) { keywords } if keywords.present?
19
+ content_for?(:keywords) ? content_for(:keywords) : 'rails 8, ruby on rails, daisyui, tailwind, web development, starter template, template'
20
+ end
21
+
22
+ def meta_tags
23
+ {
24
+ title: meta_title,
25
+ description: meta_description,
26
+ image: meta_image,
27
+ keywords: meta_keywords,
28
+ canonical: request.original_url,
29
+ author: 'RailsMaker',
30
+ robots: 'index, follow',
31
+ type: 'website',
32
+ twitter_card: 'summary_large_image',
33
+ twitter_site: '@sgerov',
34
+ og_site_name: 'RailsMaker',
35
+ article_published_time: Time.current.iso8601,
36
+ article_modified_time: Time.current.iso8601
37
+ }
38
+ end
39
+ end
@@ -0,0 +1,14 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="flash"
4
+ export default class extends Controller {
5
+ connect() {
6
+ setTimeout(() => {
7
+ this.element.remove()
8
+ }, 5000)
9
+ }
10
+
11
+ dismiss() {
12
+ this.element.remove()
13
+ }
14
+ }
@@ -0,0 +1,11 @@
1
+ // This file is auto-generated by ./bin/rails stimulus:manifest:update
2
+ // Run that command whenever you add a new controller or create them with
3
+ // ./bin/rails generate stimulus controllerName
4
+
5
+ import { application } from "./application"
6
+
7
+ import FlashController from "./flash_controller"
8
+ application.register("flash", FlashController)
9
+
10
+ import ScrollFadeController from "./scroll_fade_controller"
11
+ application.register("scroll-fade", ScrollFadeController)
@@ -0,0 +1,27 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static values = {
5
+ offset: Number
6
+ }
7
+
8
+ connect() {
9
+ this.onScroll = this.onScroll.bind(this)
10
+ window.addEventListener('scroll', this.onScroll)
11
+ this.onScroll()
12
+ }
13
+
14
+ disconnect() {
15
+ window.removeEventListener('scroll', this.onScroll)
16
+ }
17
+
18
+ onScroll() {
19
+ if (window.scrollY > this.offsetValue) {
20
+ this.element.classList.add('opacity-0', 'pointer-events-none')
21
+ this.element.classList.remove('opacity-100')
22
+ } else {
23
+ this.element.classList.add('opacity-100')
24
+ this.element.classList.remove('opacity-0', 'pointer-events-none')
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,8 @@
1
+ <p><%= t(".opening") %></p>
2
+
3
+ <p>
4
+ <%= link_to t(".link_text", default: "Change my password"),
5
+ url_for([@user, :password, action: :edit, token: @user.confirmation_token]) %>
6
+ </p>
7
+
8
+ <p><%= t(".closing") %></p>
@@ -0,0 +1,5 @@
1
+ <%= t(".opening") %>
2
+
3
+ <%= url_for([@user, :password, action: :edit, token: @user.confirmation_token]) %>
4
+
5
+ <%= t(".closing") %>