├── log └── .keep ├── storage └── .keep ├── tmp └── .keep ├── lib └── tasks │ └── .keep ├── .ruby-version ├── app ├── assets │ ├── builds │ │ └── .keep │ ├── stylesheets │ │ ├── components │ │ │ ├── pagination.css │ │ │ ├── cards.css │ │ │ ├── tables.css │ │ │ ├── base.css │ │ │ ├── forms.css │ │ │ ├── buttons.css │ │ │ ├── overrides.css │ │ │ └── modals.css │ │ └── application.css │ └── images │ │ └── icons │ │ ├── google.svg │ │ ├── facebook.svg │ │ └── github.svg ├── views │ ├── layouts │ │ ├── mailer.text.erb │ │ ├── mailer.html.erb │ │ └── application.html.erb │ ├── articles │ │ ├── new.html.erb │ │ ├── edit.html.erb │ │ ├── show.html.erb │ │ ├── _form.html.erb │ │ └── index.html.erb │ ├── errors │ │ ├── internal_server_error.html.erb │ │ ├── not_found.html.erb │ │ └── _error_page.html.erb │ ├── application │ │ ├── _flash_messages.html.erb │ │ ├── _error_messages.html.erb │ │ ├── _remote_modal.html.erb │ │ ├── _footer.html.erb │ │ └── _header.html.erb │ ├── devise │ │ ├── shared │ │ │ ├── _links.html.erb │ │ │ └── _social_signin.html.erb │ │ ├── passwords │ │ │ ├── new.html.erb │ │ │ └── edit.html.erb │ │ ├── sessions │ │ │ └── new.html.erb │ │ └── registrations │ │ │ └── new.html.erb │ ├── users │ │ ├── show.html.erb │ │ ├── index.html.erb │ │ └── edit.html.erb │ ├── home │ │ └── index.html.erb │ └── pages │ │ ├── terms.html.erb │ │ ├── privacy_policy.html.erb │ │ └── about.html.erb ├── controllers │ ├── home_controller.rb │ ├── errors_controller.rb │ ├── pages_controller.rb │ ├── application_controller.rb │ ├── users_controller.rb │ ├── users │ │ └── omniauth_callbacks_controller.rb │ └── articles_controller.rb ├── models │ ├── application_record.rb │ ├── ability.rb │ ├── article.rb │ └── user.rb ├── mailers │ └── application_mailer.rb ├── helpers │ ├── articles_helper.rb │ ├── users_helper.rb │ └── application_helper.rb └── javascript │ ├── components │ ├── tooltip.js │ └── remote_modal.js │ ├── controllers │ ├── app.js │ └── articles.js │ └── application.js ├── public ├── favicon.ico └── robots.txt ├── Procfile.dev ├── bin ├── rake ├── rails ├── dev └── setup ├── config ├── environment.rb ├── initializers │ ├── action_text.rb │ ├── heroicon.rb │ ├── filter_parameter_logging.rb │ ├── permissions_policy.rb │ ├── inflections.rb │ ├── content_security_policy.rb │ └── devise.rb ├── storage.yml ├── boot.rb ├── credentials.yml.enc ├── database.yml ├── application.rb ├── routes.rb ├── locales │ └── en.yml ├── puma.rb └── environments │ ├── test.rb │ ├── development.rb │ └── production.rb ├── db ├── migrate │ ├── 20220831235947_add_name_to_users.rb │ ├── 20220831194622_create_articles.rb │ ├── 20220831213127_devise_create_users.rb │ ├── 20230525120314_create_action_text_tables.action_text.rb │ └── 20221005175500_create_active_storage_tables.active_storage.rb ├── seeds.rb ├── schema.rb └── seed_data.rb ├── config.ru ├── Rakefile ├── .env.example ├── .gitignore ├── package.json ├── Gemfile ├── README.md ├── Gemfile.lock └── yarn.lock /log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /storage/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tmp/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.3.5 2 | -------------------------------------------------------------------------------- /app/assets/builds/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ralixjs/rails-ralix-tailwind/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /Procfile.dev: -------------------------------------------------------------------------------- 1 | web: bin/rails server -p 3000 2 | js: yarn build --watch 3 | css: yarn build:css --watch 4 | -------------------------------------------------------------------------------- /app/views/articles/new.html.erb: -------------------------------------------------------------------------------- 1 |

New article

2 | 3 | <%= render "form", article: @article %> 4 | -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | def index 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | primary_abstract_class 3 | end 4 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require_relative "../config/boot" 4 | require "rake" 5 | Rake.application.run 6 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: "from@example.com" 3 | layout "mailer" 4 | end 5 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | APP_PATH = File.expand_path("../config/application", __dir__) 4 | require_relative "../config/boot" 5 | require "rails/commands" 6 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/pagination.css: -------------------------------------------------------------------------------- 1 | .pagy a { 2 | @apply text-xl p-2; 3 | } 4 | 5 | .pagy a.current { 6 | @apply bg-indigo-600 text-white rounded-sm; 7 | } 8 | -------------------------------------------------------------------------------- /config/initializers/action_text.rb: -------------------------------------------------------------------------------- 1 | class ActionText::Record < ActiveRecord::Base 2 | def self.ransackable_attributes(auth_object = nil) 3 | ["body"] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /config/initializers/heroicon.rb: -------------------------------------------------------------------------------- 1 | Heroicon.configure do |config| 2 | config.variant = :outline 3 | config.default_class = { 4 | outline: "w-5 h-5 inline" 5 | } 6 | end 7 | -------------------------------------------------------------------------------- /config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | -------------------------------------------------------------------------------- /db/migrate/20220831235947_add_name_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddNameToUsers < ActiveRecord::Migration[7.0] 2 | def change 3 | add_column :users, :name, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/helpers/articles_helper.rb: -------------------------------------------------------------------------------- 1 | module ArticlesHelper 2 | def author_and_date(article) 3 | "by #{article.user.name} | #{format_time(article.created_at.to_date)}" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative "config/environment" 4 | 5 | run Rails.application 6 | Rails.application.load_server 7 | -------------------------------------------------------------------------------- /app/views/errors/internal_server_error.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'errors/error_page', 2 | code: 500, 3 | error_title: "OOOPS", 4 | error_description: "Looks like something went wrong!" %> 5 | -------------------------------------------------------------------------------- /bin/dev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if ! foreman version &> /dev/null 4 | then 5 | echo "Installing foreman..." 6 | gem install foreman 7 | fi 8 | 9 | foreman start -f Procfile.dev "$@" 10 | -------------------------------------------------------------------------------- /app/models/ability.rb: -------------------------------------------------------------------------------- 1 | class Ability 2 | include CanCan::Ability 3 | 4 | def initialize(user) 5 | can [:read, :create], Article 6 | can [:update, :destroy], Article, user: user 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/errors_controller.rb: -------------------------------------------------------------------------------- 1 | class ErrorsController < ApplicationController 2 | def not_found 3 | render status: 404 4 | end 5 | 6 | def internal_server_error 7 | render status: 500 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 2 | 3 | require "bundler/setup" # Set up gems listed in the Gemfile. 4 | require "bootsnap/setup" # Speed up boot time by caching expensive operations. 5 | -------------------------------------------------------------------------------- /app/controllers/pages_controller.rb: -------------------------------------------------------------------------------- 1 | class PagesController < ApplicationController 2 | def show 3 | render template: "pages/#{params[:page]}" 4 | rescue ActionView::MissingTemplate 5 | render "errors/not_found", status: 404 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative "config/application" 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/javascript/components/tooltip.js: -------------------------------------------------------------------------------- 1 | import tippy from 'tippy.js' 2 | 3 | export default class Tooltip { 4 | static onload() { 5 | tippy('[data-tippy-content]', { 6 | allowHTML: true, 7 | arrow: false 8 | }) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | FACEBOOK_CLIENT_ID=facebook_client_id 2 | FACEBOOK_CLIENT_SECRET=facebook_client_secret 3 | GOOGLE_CLIENT_ID=google_client_id 4 | GOOGLE_CLIENT_SECRET=google_client_secret 5 | GITHUB_CLIENT_ID=github_client_id 6 | GITHUB_CLIENT_SECRET=github_client_secret 7 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | include Pagy::Backend 3 | 4 | rescue_from CanCan::AccessDenied do |exception| 5 | redirect_to request.referer || root_path, alert: exception.message 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/views/application/_flash_messages.html.erb: -------------------------------------------------------------------------------- 1 | <% flash.each do |key, msg| %> 2 |
3 | <%= msg %> 4 | 5 |
6 | <% end %> 7 | -------------------------------------------------------------------------------- /db/migrate/20220831194622_create_articles.rb: -------------------------------------------------------------------------------- 1 | class CreateArticles < ActiveRecord::Migration[7.0] 2 | def change 3 | create_table :articles do |t| 4 | t.string :title 5 | t.references :user 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/views/articles/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Editing article

2 | 3 | <%= render "form", article: @article %> 4 | 5 |
6 |

Be careful! This action is irreversible.

7 | <%= button_to "Destroy", @article, method: :delete, class: "btn btn-danger" %> 8 |
9 | -------------------------------------------------------------------------------- /app/views/errors/not_found.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'errors/error_page', 2 | code: 404, 3 | error_title: "PAGE NOT FOUND", 4 | error_description: "The page you were looking for doesn't exist. 5 | You may have mistyped the address or the page may have moved." %> 6 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/javascript/controllers/app.js: -------------------------------------------------------------------------------- 1 | export default class AppCtrl { 2 | constructor() { 3 | this.isMobile = /Mobi/.test(navigator.userAgent) 4 | } 5 | 6 | toggleMenu() { 7 | toggleClass('.mobile-menu', 'hidden') 8 | } 9 | 10 | closeFlashAlert() { 11 | currentElement().parentElement.remove() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/cards.css: -------------------------------------------------------------------------------- 1 | .card { 2 | @apply rounded-sm bg-white p-4; 3 | } 4 | 5 | .card-title a { 6 | @apply text-gray-900; 7 | } 8 | 9 | .card-subtitle { 10 | @apply text-sm text-slate-400; 11 | } 12 | 13 | .card-body { 14 | @apply text-slate-600 my-2; 15 | } 16 | 17 | .card-actions { 18 | @apply mt-8 mb-4; 19 | } 20 | -------------------------------------------------------------------------------- /app/assets/images/icons/google.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /app/assets/images/icons/facebook.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/views/errors/_error_page.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= code %>

3 | 4 |

<%= error_title %>

5 |
<%= error_description %>
6 | 7 |

8 | Home 9 | Back 10 |

11 |
12 | -------------------------------------------------------------------------------- /app/views/application/_error_messages.html.erb: -------------------------------------------------------------------------------- 1 | <% if object.errors.any? %> 2 |
3 | <%= pluralize(object.errors.count, "error") %> found: 4 | 5 | 10 |
11 | <% end %> 12 | -------------------------------------------------------------------------------- /app/views/articles/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= @article.title %>

3 | 4 |

5 | <%= author_and_date(@article) %> 6 |

7 | 8 |
9 | <%= @article.body %> 10 |
11 | 12 |
13 | <%= link_to "Edit", edit_article_path(@article), class: 'btn' %> 14 |
15 |
16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/tables.css: -------------------------------------------------------------------------------- 1 | table { 2 | @apply w-full text-sm text-left; 3 | } 4 | 5 | table thead { 6 | @apply text-xs uppercase bg-slate-200; 7 | } 8 | 9 | table tbody { 10 | @apply bg-white; 11 | } 12 | 13 | table th, table td { 14 | @apply py-4 px-6; 15 | } 16 | 17 | table img { 18 | min-width: 30px; 19 | } 20 | 21 | .table-responsive { 22 | @apply overflow-x-auto relative; 23 | } 24 | -------------------------------------------------------------------------------- /app/views/articles/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_with(model: article) do |form| %> 2 | <%= render "application/error_messages", object: article %> 3 | 4 |
5 | <%= form.label :title %> 6 | <%= form.text_field :title %> 7 |
8 | 9 |
10 | <%= form.label :body %> 11 | <%= form.rich_text_area :body %> 12 |
13 | 14 |
15 | <%= form.submit nil, class: 'btn' %> 16 |
17 | <% end %> 18 | -------------------------------------------------------------------------------- /config/credentials.yml.enc: -------------------------------------------------------------------------------- 1 | qDh808AJiyxRn4Npr9Ux3LXJX3DGlIRpG888RrT3kfsq1j6yJkWOQ3PgMixQeoR61VHMWe3fOl3cyUcx8DDekkqSu568qzCPt+uy2R2tEl6JH7xP9jdvSVdmmEuNvyrVbpxayQlxna+JOqVzISadIFw0L974ZC1fLas5bND8r3mFrfApJrHClikMzV6g8C+FVywB1b4m7z4oQqEcg2A72uBwM67eAPibjXH0kDYc3H5JE4hdtcuWMnGXrQ3nybuZsY4c0BKqv3bq/1sl3OF7rzP+LmeqKCjKwIA3En/u0cvAZa+ToAmFVv435F7+MZfmaKJ15TRKypDxVYGyD3H6aYTzkX6Nu9gn8i+0P0Q9vabQM92Q/dgsztKH+nPX3CdtcI02qwTGKCoVLHlV/+OHDIe1eD3usIgcdFaa--X1OKn58uyWHMGamI--i30CtrHvN2/lDeRlD0OYyQ== -------------------------------------------------------------------------------- /app/models/article.rb: -------------------------------------------------------------------------------- 1 | class Article < ApplicationRecord 2 | belongs_to :user 3 | 4 | has_rich_text :body 5 | has_one :rich_text, class_name: 'ActionText::RichText', as: :record 6 | 7 | validates :title, :body, presence: true 8 | validates :title, length: { minimum: 5 } 9 | 10 | def self.ransackable_attributes(auth_object = nil) 11 | ["title"] 12 | end 13 | 14 | def self.ransackable_associations(auth_object = nil) 15 | ["rich_text"] 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | require_relative 'seed_data' 2 | 3 | if User.none? 4 | SeedData::USERS.each do |user_data| 5 | User.create!( 6 | name: user_data[:name], 7 | email: user_data[:email], 8 | password: "1234asdf" 9 | ) 10 | end 11 | end 12 | 13 | if Article.none? 14 | SeedData::ARTICLES.each do |article_data| 15 | Article.create!( 16 | title: article_data[:title], 17 | body: article_data[:body], 18 | user: User.all.sample 19 | ) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore bundler config. 2 | /.bundle 3 | 4 | # Ignore all logfiles and tempfiles. 5 | /log/* 6 | !/log/.keep 7 | /tmp/* 8 | !/tmp/.keep 9 | 10 | # Ignore uploaded files in development. 11 | /storage/* 12 | !/storage/.keep 13 | 14 | # Ignore master key for decrypting credentials and more. 15 | /config/master.key 16 | 17 | # Ignore compiled assets and node_modules 18 | /app/assets/builds/* 19 | !/app/assets/builds/.keep 20 | /public/assets 21 | /node_modules 22 | 23 | # Ignore ENV files 24 | .env 25 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: postgresql 3 | encoding: unicode 4 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 5 | 6 | development: 7 | <<: *default 8 | database: <%= ENV.fetch("DATABASE_NAME", "rails-ralix-tailwind_development") %> 9 | 10 | test: 11 | <<: *default 12 | database: <%= ENV.fetch("DATABASE_NAME", "rails-ralix-tailwind_test") %> 13 | 14 | production: 15 | <<: *default 16 | database: <%= ENV.fetch("DATABASE_NAME", "rails-ralix-tailwind_production") %> 17 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. 4 | # Use this to limit dissemination of sensitive information. 5 | # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. 6 | Rails.application.config.filter_parameters += [ 7 | :passw, :email, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn, :cvv, :cvc 8 | ] 9 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* Dependencies */ 2 | @import 'tailwindcss'; 3 | @plugin '@tailwindcss/forms'; 4 | @import 'tippy.js/dist/tippy.css'; 5 | @import 'trix/dist/trix'; 6 | 7 | /* Components */ 8 | @import './components/base.css' layer(utilities); 9 | @import './components/forms.css'; 10 | @import './components/tables.css'; 11 | @import './components/modals.css'; 12 | @import './components/buttons.css'; 13 | @import './components/cards.css'; 14 | @import './components/pagination.css'; 15 | @import './components/overrides.css'; 16 | -------------------------------------------------------------------------------- /app/views/devise/shared/_links.html.erb: -------------------------------------------------------------------------------- 1 | <% if controller_name != 'sessions' %> 2 |

<%= link_to "Sign in", new_session_path(resource_name) %>

3 | <% end %> 4 | 5 | <% if devise_mapping.registerable? && controller_name != 'registrations' %> 6 |

<%= link_to "Sign up", new_registration_path(resource_name) %>

7 | <% end %> 8 | 9 | <% if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> 10 |

<%= link_to "Forgot your password?", new_password_path(resource_name) %>

11 | <% end %> 12 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative "boot" 2 | 3 | require "rails/all" 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module RailsRalixTailwind 10 | class Application < Rails::Application 11 | # Load Rails defaults 12 | config.load_defaults 8.0 13 | 14 | # This tells Rails to serve error pages from the app itself, rather than using static error pages in public/ 15 | config.exceptions_app = self.routes 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /config/initializers/permissions_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide HTTP permissions policy. For further 4 | # information see: https://developers.google.com/web/updates/2018/06/feature-policy 5 | 6 | # Rails.application.config.permissions_policy do |policy| 7 | # policy.camera :none 8 | # policy.gyroscope :none 9 | # policy.microphone :none 10 | # policy.usb :none 11 | # policy.fullscreen :self 12 | # policy.payment :self, "https://secure.example.com" 13 | # end 14 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | devise_for :users, controllers: { 3 | omniauth_callbacks: 'users/omniauth_callbacks' 4 | } 5 | 6 | root "home#index" 7 | 8 | resources :articles 9 | resource :user, only: %i[edit update destroy] 10 | resources :users, only: %i[index show] 11 | 12 | get "/pages/:page" => "pages#show", as: :page 13 | 14 | match '/404', to: 'errors#not_found', via: :all 15 | match '/422', to: 'errors#internal_server_error', via: :all 16 | match '/500', to: 'errors#internal_server_error', via: :all 17 | end 18 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/base.css: -------------------------------------------------------------------------------- 1 | body { 2 | @apply bg-slate-100 leading-relaxed; 3 | } 4 | 5 | h1 { 6 | @apply text-4xl font-bold mt-2 my-4; 7 | } 8 | 9 | h2 { 10 | @apply text-3xl font-bold mt-2 my-4; 11 | } 12 | 13 | h3 { 14 | @apply text-2xl font-bold my-2; 15 | } 16 | 17 | p { 18 | @apply mt-2 mb-3; 19 | } 20 | 21 | a { 22 | @apply text-indigo-600 outline-hidden; 23 | } 24 | 25 | button { 26 | @apply cursor-pointer; 27 | } 28 | 29 | img { 30 | display: inline-block; 31 | } 32 | 33 | ul { 34 | @apply list-disc; 35 | } 36 | 37 | ol { 38 | @apply list-decimal; 39 | } 40 | -------------------------------------------------------------------------------- /app/views/devise/passwords/new.html.erb: -------------------------------------------------------------------------------- 1 |

Forgot your password?

2 | 3 | <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }, data: { turbo: "false" }) do |f| %> 4 | <%= render "application/error_messages", object: resource %> 5 | 6 |
7 | <%= f.label :email %> 8 | <%= f.email_field :email, autofocus: true, autocomplete: "email" %> 9 |
10 | 11 |
12 | <%= f.submit "Send me reset password instructions", class: "btn" %> 13 |
14 | <% end %> 15 | 16 | <%= render "devise/shared/links" %> 17 | -------------------------------------------------------------------------------- /app/javascript/components/remote_modal.js: -------------------------------------------------------------------------------- 1 | import MicroModal from 'micromodal' 2 | 3 | export default class RemoteModal { 4 | static onload() { 5 | findAll('[data-modal-url]').forEach(el => { 6 | on(el, 'click', () => { 7 | this.show(data(el)) 8 | }) 9 | }) 10 | } 11 | 12 | static show(data) { 13 | get(data.modalUrl).then(content => { 14 | insertHTML('#remote-modal .modal-title', data.modalTitle || '') 15 | insertHTML('#remote-modal main', content) 16 | 17 | MicroModal.show('remote-modal', { 18 | disableScroll: true 19 | }) 20 | }) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/views/application/_remote_modal.html.erb: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /app/views/users/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= avatar(@user, 200) %> 3 |

<%= @user.name %>

4 |

<%= mail_to @user.email %>

5 |
6 | 7 |
8 |

9 | Created at 10 | <%= time_ago @user.created_at %> 11 | <%= format_time @user.created_at %> 12 |

13 |

14 | Updated at 15 | <%= time_ago @user.updated_at %> 16 | <%= format_time @user.updated_at %> 17 |

18 |

Total Articles <%= @user.articles.size %>

19 |
20 | -------------------------------------------------------------------------------- /app/javascript/application.js: -------------------------------------------------------------------------------- 1 | // Dependencies 2 | import { RalixApp } from 'ralix' 3 | import "@hotwired/turbo-rails" 4 | import "trix" 5 | import "@rails/actiontext" 6 | 7 | // Controllers 8 | import AppCtrl from './controllers/app' 9 | import ArticlesCtrl from './controllers/articles' 10 | 11 | // Components 12 | import RemoteModal from './components/remote_modal' 13 | import Tooltip from './components/tooltip' 14 | 15 | const App = new RalixApp({ 16 | routes: { 17 | '/articles$': ArticlesCtrl, 18 | '/.*': AppCtrl 19 | }, 20 | components: [ 21 | RemoteModal, 22 | Tooltip 23 | ] 24 | }) 25 | 26 | App.start() 27 | -------------------------------------------------------------------------------- /app/javascript/controllers/articles.js: -------------------------------------------------------------------------------- 1 | import AppCtrl from "./app" 2 | 3 | export default class ArticlesCtrl extends AppCtrl { 4 | constructor() { 5 | super() 6 | 7 | this.searchForm = find('.article_search') 8 | this.searchInput = find('.search-input') 9 | this.currentValue = this.searchInput.value 10 | 11 | if (!this.isMobile) this.searchInput.focus() 12 | } 13 | 14 | search() { 15 | setTimeout(() => { 16 | const newValue = this.searchInput.value 17 | 18 | if (this.currentValue != newValue) { 19 | this.currentValue = newValue 20 | submit(this.searchForm) 21 | } 22 | }, 500) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "private": "true", 4 | "dependencies": { 5 | "@hotwired/turbo-rails": "^8.0.0", 6 | "@rails/actiontext": "^8.0.0", 7 | "@tailwindcss/cli": "^4.1.11", 8 | "@tailwindcss/forms": "^0.5.9", 9 | "esbuild": "^0.25.0", 10 | "micromodal": "^0.6.1", 11 | "ralix": "^1.8.0", 12 | "tailwindcss": "^4.1.11", 13 | "tippy.js": "^6.3.7", 14 | "trix": "^2.1.15" 15 | }, 16 | "scripts": { 17 | "build": "esbuild app/javascript/*.* --bundle --outdir=app/assets/builds", 18 | "build:css": "npx @tailwindcss/cli -i ./app/assets/stylesheets/application.css -o ./app/assets/builds/application.css --minify" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/helpers/users_helper.rb: -------------------------------------------------------------------------------- 1 | module UsersHelper 2 | def avatar(user, size = 40) 3 | image_tag avatar_url(user, size), 4 | size: size, 5 | class: "rounded-full" 6 | end 7 | 8 | def avatar_url(user, size) 9 | if user.avatar.attached? 10 | url_for(user.avatar.variant(resize_to_fill: [size, size])) 11 | else 12 | gravatar_url(user.email, size) 13 | end 14 | end 15 | 16 | def gravatar_url(email, size) 17 | gravatar_id = Digest::MD5.hexdigest(email).downcase 18 | gravatar_options = { 19 | s: size, 20 | d: "retro" 21 | } 22 | 23 | "https://www.gravatar.com/avatar/#{gravatar_id}?#{gravatar_options.to_param}" 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /db/migrate/20220831213127_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration[7.0] 2 | def change 3 | create_table :users do |t| 4 | # Database authenticatable 5 | t.string :email, null: false, default: "" 6 | t.string :encrypted_password, null: false, default: "" 7 | 8 | # Recoverable 9 | t.string :reset_password_token 10 | t.datetime :reset_password_sent_at 11 | 12 | # Rememberable 13 | t.datetime :remember_created_at 14 | 15 | t.timestamps null: false 16 | end 17 | 18 | add_index :users, :email, unique: true 19 | add_index :users, :reset_password_token, unique: true 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/views/application/_footer.html.erb: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /app/views/home/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

3 | Starter Kit
4 | Rails + Ralix + Tailwind 5 |

6 | 7 |

8 | Starter Kit to build Rails applications fast, with Ralix, Tailwind and more! 9 |

10 | 11 | 12 | <%= heroicon 'book-open' %> 13 | Get started 14 | 15 | 16 | <%= heroicon 'squares-2x2' %> 17 | Explore app 18 | 19 |
20 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, "\\1en" 8 | # inflect.singular /^(ox)en/i, "\\1" 9 | # inflect.irregular "person", "people" 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym "RESTful" 16 | # end 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/forms.css: -------------------------------------------------------------------------------- 1 | input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]), textarea { 2 | @apply w-full max-w-lg mt-2 mb-4 block rounded-sm focus:border-indigo-600 focus:ring-3 focus:ring-indigo-300/50; 3 | } 4 | 5 | input[type="file"] { 6 | @apply text-slate-400 bg-white border border-gray-500 cursor-pointer focus:outline-hidden file:mr-4 file:py-2 file:px-4 file:border-0 file:bg-gray-500 file:text-white hover:file:bg-gray-600; 7 | } 8 | 9 | input[type="checkbox"], input[type="radio"] { 10 | @apply p-2 mr-1 rounded-full text-indigo-600 focus:border-indigo-600 focus:ring-3 focus:ring-indigo-300/50; 11 | } 12 | 13 | input[hidden="true"] { 14 | @apply hidden!; 15 | } 16 | 17 | .form-actions { 18 | @apply flex gap-4 my-4; 19 | } 20 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | include Pagy::Frontend 3 | include Heroicon::Engine.helpers 4 | 5 | def page_title 6 | "Rails + Ralix + Tailwind | #{controller_name.humanize}" 7 | end 8 | 9 | def body_class 10 | "#{controller_name}-#{action_name}" 11 | end 12 | 13 | def nav_link_class(section, extra = nil) 14 | if section == controller_name 15 | "bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium #{extra}" 16 | else 17 | "text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium #{extra}" 18 | end 19 | end 20 | 21 | def time_ago(time_object) 22 | "#{time_ago_in_words(time_object)} ago" 23 | end 24 | 25 | def format_time(time_object) 26 | l(time_object, format: :long) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/assets/images/icons/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/views/devise/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 |

Sign in

2 | 3 | <%= form_for(resource, as: resource_name, url: session_path(resource_name), data: { turbo: "false" }) do |f| %> 4 |
5 | <%= f.label :email %> 6 | <%= f.email_field :email, autofocus: true, autocomplete: "email" %> 7 |
8 | 9 |
10 | <%= f.label :password %> 11 | <%= f.password_field :password, autocomplete: "current-password" %> 12 |
13 | 14 | <% if devise_mapping.rememberable? %> 15 |
16 | <%= f.check_box :remember_me %> 17 | <%= f.label :remember_me %> 18 |
19 | <% end %> 20 | 21 |
22 | <%= f.submit "Sign in", class: "btn" %> 23 |
24 | <% end %> 25 | 26 | <%= render "devise/shared/social_signin" %> 27 | <%= render "devise/shared/links" %> 28 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/buttons.css: -------------------------------------------------------------------------------- 1 | .btn { 2 | @apply bg-indigo-600 text-white border-2 border-indigo-600 py-3 px-6 rounded-sm cursor-pointer outline-hidden; 3 | } 4 | 5 | .btn-outline { 6 | @apply bg-transparent text-indigo-600; 7 | } 8 | 9 | .btn-outline:hover { 10 | @apply bg-indigo-600 text-white; 11 | } 12 | 13 | .btn-danger { 14 | @apply bg-transparent border-red-600 text-red-600; 15 | } 16 | 17 | .btn-danger:hover { 18 | @apply bg-red-600 text-white; 19 | } 20 | 21 | .btn-facebook { 22 | background-color: #1877F2; 23 | border-color: #1877F2; 24 | } 25 | 26 | .btn-github { 27 | background-color: #333; 28 | border-color: #333; 29 | } 30 | 31 | .btn-google { 32 | background-color: #EA4335; 33 | border-color: #EA4335; 34 | } 35 | 36 | .btn svg { 37 | display: inline; 38 | vertical-align: text-top; 39 | } 40 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "fileutils" 4 | 5 | # path to your application root. 6 | APP_ROOT = File.expand_path("..", __dir__) 7 | 8 | def system!(*args) 9 | system(*args) || abort("\n== Command #{args} failed ==") 10 | end 11 | 12 | FileUtils.chdir APP_ROOT do 13 | puts "== Installing dependencies ==" 14 | system! "gem install bundler --conservative" 15 | system("bundle check") || system!("bundle install") 16 | 17 | puts "\n== Installing front-end dependencies ==" 18 | system! "yarn install" 19 | 20 | puts "\n== Preparing database ==" 21 | system! "bin/rails db:prepare" 22 | system! "bin/rails db:seed" 23 | 24 | puts "\n== Removing old logs and tempfiles ==" 25 | system! "bin/rails log:clear tmp:clear" 26 | 27 | puts "\n== Restarting application server ==" 28 | system! "bin/rails restart" 29 | end 30 | -------------------------------------------------------------------------------- /app/views/devise/passwords/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Change your password

2 | 3 | <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }, data: { turbo: "false" }) do |f| %> 4 | <%= render "application/error_messages", object: resource %> 5 | <%= f.hidden_field :reset_password_token %> 6 | 7 |
8 | <%= f.label :password, "New password" %> 9 | <%= f.password_field :password, autofocus: true, autocomplete: "new-password" %> 10 |
11 | 12 |
13 | <%= f.label :password_confirmation, "Confirm new password" %> 14 | <%= f.password_field :password_confirmation, autocomplete: "new-password" %> 15 |
16 | 17 |
18 | <%= f.submit "Change my password", class: "btn" %> 19 |
20 | <% end %> 21 | 22 | <%= render "devise/shared/links" %> 23 | -------------------------------------------------------------------------------- /app/views/devise/shared/_social_signin.html.erb: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= page_title %> 5 | 6 | <%= csrf_meta_tags %> 7 | <%= csp_meta_tag %> 8 | 9 | <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> 10 | <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %> 11 | 12 | 13 | 14 | <%= render "application/header" %> 15 | <%= render "application/flash_messages" %> 16 |
17 |
18 | <%= yield %> 19 |
20 |
21 | <%= render "application/footer" %> 22 | <%= render "application/remote_modal" %> 23 | 24 | 25 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | ruby File.read(".ruby-version").strip 4 | 5 | # Core 6 | gem "rails", "~> 8.0" 7 | gem "pg", "~> 1.5" 8 | gem "puma", "~> 6.6" 9 | gem "bootsnap", "~> 1.18", require: false 10 | gem "ransack", "~> 4.2" 11 | gem "pagy", "~> 9.3" 12 | gem "image_processing", "~> 1.2" 13 | 14 | # Authentication and Authorization 15 | gem "devise", "~> 4.9" 16 | gem "omniauth-facebook", "~> 9.0" 17 | gem "omniauth-github", "~> 2.0" 18 | gem "omniauth-google-oauth2", "~> 1.1" 19 | gem "omniauth-rails_csrf_protection", "~> 1.0" 20 | gem "cancancan", "~> 3.4" 21 | 22 | # Front-end 23 | gem "propshaft", "~> 1.1" 24 | gem "jsbundling-rails", "~> 1.0" 25 | gem "cssbundling-rails", "~> 1.1" 26 | gem "turbo-rails", "~> 2.0" 27 | gem "heroicon", "~> 1.0" 28 | 29 | group :development do 30 | gem "web-console" 31 | gem "debug" 32 | gem "dotenv-rails" 33 | end 34 | -------------------------------------------------------------------------------- /app/views/devise/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 |

Sign up

2 | 3 | <%= form_for(resource, as: resource_name, url: registration_path(resource_name), data: { turbo: "false" }) do |f| %> 4 | <%= render "application/error_messages", object: resource %> 5 | 6 |
7 | <%= f.label :email %> 8 | <%= f.email_field :email, autofocus: true, autocomplete: "email" %> 9 |
10 | 11 |
12 | <%= f.label :password %> 13 | <%= f.password_field :password, autocomplete: "new-password" %> 14 |
15 | 16 |
17 | <%= f.label :password_confirmation %> 18 | <%= f.password_field :password_confirmation, autocomplete: "new-password" %> 19 |
20 | 21 |
22 | <%= f.submit "Sign up", class: "btn" %> 23 |
24 | <% end %> 25 | 26 | <%= render "devise/shared/social_signin" %> 27 | <%= render "devise/shared/links" %> 28 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/overrides.css: -------------------------------------------------------------------------------- 1 | /* Turbo */ 2 | .turbo-progress-bar { 3 | @apply h-1 bg-indigo-600; 4 | } 5 | 6 | /* Tippy */ 7 | .tippy-box { 8 | @apply bg-gray-800; 9 | } 10 | 11 | /* Trix */ 12 | trix-editor { 13 | @apply bg-white min-h-60 border-gray-500 focus:border-indigo-600 focus:ring-3 focus:ring-indigo-300/50; 14 | } 15 | 16 | trix-editor .trix-button--remove { 17 | @apply w-6 h-6 border-none; 18 | } 19 | 20 | trix-editor .attachment__caption-editor { 21 | @apply mt-2 p-1; 22 | } 23 | 24 | trix-editor [data-trix-mutable].attachment img { 25 | @apply shadow-none; 26 | } 27 | 28 | trix-toolbar .trix-button-group { 29 | @apply border-gray-500; 30 | } 31 | 32 | trix-toolbar .trix-button { 33 | @apply border-none; 34 | } 35 | 36 | trix-toolbar .trix-button.trix-active{ 37 | @apply bg-indigo-100; 38 | } 39 | 40 | trix-toolbar .trix-dialog { 41 | @apply top-2 left-2 py-2 rounded-sm border-none; 42 | } 43 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | before_action :authenticate_user! 3 | 4 | def index 5 | @q = User.ransack(params[:q]) 6 | @pagy, @users = pagy(@q.result.order(created_at: :desc), limit: 10) 7 | end 8 | 9 | def show 10 | @user = User.find(params[:id]) 11 | 12 | render layout: false 13 | end 14 | 15 | def edit 16 | end 17 | 18 | def update 19 | if current_user.update(user_params) 20 | redirect_to current_user, notice: "Account was successfully updated." 21 | else 22 | render :edit, status: :unprocessable_entity 23 | end 24 | end 25 | 26 | def destroy 27 | current_user.destroy 28 | 29 | redirect_to root_path, notice: "Account was successfully deleted." 30 | end 31 | 32 | private 33 | 34 | def user_params 35 | params.require(:user).permit(:avatar, :name, :email, :password, :password_confirmation) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /app/controllers/users/omniauth_callbacks_controller.rb: -------------------------------------------------------------------------------- 1 | class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController 2 | def google_oauth2 3 | omniauth_callback('Google', 'google_data') 4 | end 5 | 6 | def github 7 | omniauth_callback('GitHub', 'github_data') 8 | end 9 | 10 | def facebook 11 | omniauth_callback('Facebook', 'facebook_data') 12 | end 13 | 14 | private 15 | 16 | def omniauth_callback(kind, session_key) 17 | @user = User.from_omniauth(request.env['omniauth.auth']) 18 | 19 | if @user.persisted? 20 | flash[:notice] = I18n.t 'devise.omniauth_callbacks.success', kind: kind 21 | sign_in_and_redirect @user, event: :authentication 22 | else 23 | session["devise.#{session_key}"] = request.env['omniauth.auth'].except('extra') # Removing extra as it can overflow some session stores 24 | redirect_to new_user_registration_url, alert: @user.errors.full_messages.join("\n") 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ApplicationRecord 2 | devise :database_authenticatable, 3 | :registerable, 4 | :recoverable, 5 | :rememberable, 6 | :validatable, 7 | :omniauthable, 8 | omniauth_providers: [:facebook, :google_oauth2, :github] 9 | 10 | has_one_attached :avatar 11 | 12 | has_many :articles, dependent: :destroy 13 | 14 | def name 15 | @name ||= self[:name].presence || email.split("@").first 16 | end 17 | 18 | def self.from_omniauth(auth) 19 | data = auth.info 20 | 21 | User.where(email: data['email']).first_or_create do |user| 22 | user.name = data['name'] 23 | user.password = Devise.friendly_token[0,20] if user.new_record? 24 | end 25 | end 26 | 27 | def self.ransackable_attributes(auth_object = nil) 28 | ["name", "email", "created_at"] 29 | end 30 | 31 | protected 32 | 33 | def password_required? 34 | new_record? || password.present? 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t "hello" 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t("hello") %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # "true": "foo" 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/modals.css: -------------------------------------------------------------------------------- 1 | .modal { 2 | display: none; 3 | } 4 | 5 | .modal.is-open { 6 | display: block; 7 | } 8 | 9 | .modal-overlay { 10 | position: fixed; 11 | top: 0; 12 | left: 0; 13 | right: 0; 14 | bottom: 0; 15 | background: rgba(0,0,0,0.6); 16 | display: flex; 17 | justify-content: center; 18 | align-items: center; 19 | } 20 | 21 | .modal-container { 22 | background-color: #fff; 23 | padding: 30px; 24 | min-width: 450px; 25 | max-width: 650px; 26 | max-height: 90vh; 27 | border-radius: 4px; 28 | overflow-y: auto; 29 | box-sizing: border-box; 30 | } 31 | 32 | @keyframes mmfadeIn { 33 | from { opacity: 0; } 34 | to { opacity: 1; } 35 | } 36 | 37 | @keyframes mmslideIn { 38 | from { transform: translateY(15%); } 39 | to { transform: translateY(0); } 40 | } 41 | 42 | .modal[aria-hidden="false"] .modal-overlay { 43 | animation: mmfadeIn .3s cubic-bezier(0.0, 0.0, 0.2, 1); 44 | } 45 | 46 | .modal[aria-hidden="false"] .modal-container { 47 | animation: mmslideIn .3s cubic-bezier(0, 0, .2, 1); 48 | } 49 | -------------------------------------------------------------------------------- /db/migrate/20230525120314_create_action_text_tables.action_text.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from action_text (originally 20180528164100) 2 | class CreateActionTextTables < ActiveRecord::Migration[6.0] 3 | def change 4 | # Use Active Record's configured type for primary and foreign keys 5 | primary_key_type, foreign_key_type = primary_and_foreign_key_types 6 | 7 | create_table :action_text_rich_texts, id: primary_key_type do |t| 8 | t.string :name, null: false 9 | t.text :body, size: :long 10 | t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type 11 | 12 | t.timestamps 13 | 14 | t.index [ :record_type, :record_id, :name ], name: "index_action_text_rich_texts_uniqueness", unique: true 15 | end 16 | end 17 | 18 | private 19 | def primary_and_foreign_key_types 20 | config = Rails.configuration.generators 21 | setting = config.options[config.orm][:primary_key_type] 22 | primary_key_type = setting || :primary_key 23 | foreign_key_type = setting || :bigint 24 | [primary_key_type, foreign_key_type] 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /app/views/pages/terms.html.erb: -------------------------------------------------------------------------------- 1 |

Terms

2 | 3 |

These Terms of Service ("Terms") govern your use of our website and services. By accessing or using our platform, you agree to be bound by these Terms. If you disagree with any part of these terms, then you may not access the service. These Terms apply to all visitors, users, and others who access or use the service.

4 |

We reserve the right to update these Terms at any time without prior notice. Your continued use of the platform following the posting of any changes constitutes acceptance of those changes. We encourage you to review these Terms periodically for any updates. The most current version will always be available on this page with the date of last modification clearly indicated.

5 |

By using our service, you represent and warrant that you are at least 18 years old and have the legal capacity to enter into this agreement. If you are using the service on behalf of an organization, you represent that you have the authority to bind that organization to these Terms. You are responsible for maintaining the confidentiality of your account and password and for restricting access to your computer or device.

6 | -------------------------------------------------------------------------------- /config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy. 4 | # See the Securing Rails Applications Guide for more information: 5 | # https://guides.rubyonrails.org/security.html#content-security-policy-header 6 | 7 | # Rails.application.configure do 8 | # config.content_security_policy do |policy| 9 | # policy.default_src :self, :https 10 | # policy.font_src :self, :https, :data 11 | # policy.img_src :self, :https, :data 12 | # policy.object_src :none 13 | # policy.script_src :self, :https 14 | # policy.style_src :self, :https 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | # 19 | # # Generate session nonces for permitted importmap, inline scripts, and inline styles. 20 | # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } 21 | # config.content_security_policy_nonce_directives = %w(script-src style-src) 22 | # 23 | # # Report violations without enforcing the policy. 24 | # # config.content_security_policy_report_only = true 25 | # end 26 | -------------------------------------------------------------------------------- /app/views/users/index.html.erb: -------------------------------------------------------------------------------- 1 |

Users

2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | <% @users.each do |user| %> 16 | 17 | 20 | 23 | 26 | 29 | 32 | 33 | <% end %> 34 | 35 |
<%= sort_link(@q, :name) %><%= sort_link(@q, :email) %><%= sort_link(@q, :created_at) %>
18 | <%= avatar(user, 60) %> 19 | 21 | <%= user.name %> 22 | 24 | <%= mail_to user.email, 'data-tippy-content': 'Click to send an email' %> 25 | 27 | <%= time_ago user.created_at %> 28 | 30 | " data-modal-title="User details" class="btn btn-outline">Details 31 |
36 |
37 | 38 |
39 | <%== pagy_nav(@pagy) if @pagy.pages > 1 %> 40 |
41 | -------------------------------------------------------------------------------- /app/views/pages/privacy_policy.html.erb: -------------------------------------------------------------------------------- 1 |

Privacy policy

2 | 3 |

Your privacy is important to us. This Privacy Policy explains how we collect, use, disclose, and safeguard your information when you visit our website or use our services. Please read this policy carefully to understand our practices regarding your personal data and how we will treat it. If you do not agree with the terms of this privacy policy, please do not access the site.

4 |

We collect information you provide directly to us, such as when you create an account, subscribe to our newsletter, or contact us for support. This may include your name, email address, phone number, and any other information you choose to provide. We also automatically collect certain information about your device when you access our website, including your IP address, browser type, operating system, and browsing behavior.

5 |

We use your information to provide, maintain, and improve our services, process transactions, send you technical notices and support messages, respond to your comments and questions, and communicate with you about products, services, and promotional offers. We may also use your information to monitor and analyze trends, usage, and activities in connection with our services to enhance user experience and security.

6 | -------------------------------------------------------------------------------- /app/views/users/edit.html.erb: -------------------------------------------------------------------------------- 1 |

My account

2 | 3 | <%= form_with(model: current_user) do |form| %> 4 | <%= render "application/error_messages", object: current_user %> 5 | 6 |
7 | <%= avatar(current_user, 200) %> 8 |
9 | 10 |
11 | <%= form.label :avatar %> 12 | <%= form.file_field :avatar, accept: "image/*" %> 13 |
14 | 15 |
16 | <%= form.label :name %> 17 | <%= form.text_field :name %> 18 |
19 | 20 |
21 | <%= form.label :email %> 22 | <%= form.email_field :email %> 23 |
24 | 25 |
26 | <%= form.label :password %> 27 | <%= form.password_field :password %> 28 |
29 | 30 |
31 | <%= form.label :password_confirmation %> 32 | <%= form.password_field :password_confirmation %> 33 |
34 | 35 |
36 | <%= form.submit nil, class: 'btn' %> 37 |
38 | <% end %> 39 | 40 |
41 |

Sign out from my account.

42 | <%= button_to "Sign out", destroy_user_session_path, method: :delete, class: "btn btn-outline" %> 43 |
44 | 45 |
46 |

Be careful! This action is irreversible.

47 | <%= button_to "Delete my account", user_path(current_user), method: :delete, class: "btn btn-danger" %> 48 |
49 | -------------------------------------------------------------------------------- /app/controllers/articles_controller.rb: -------------------------------------------------------------------------------- 1 | class ArticlesController < ApplicationController 2 | before_action :authenticate_user!, only: %i[new create edit update destroy] 3 | before_action :set_article, only: %i[show edit update destroy] 4 | 5 | authorize_resource 6 | 7 | def index 8 | @q = Article.ransack(params[:q]) 9 | @pagy, @articles = pagy(@q.result.order(created_at: :desc), limit: 4) 10 | end 11 | 12 | def show 13 | end 14 | 15 | def new 16 | @article = Article.new 17 | end 18 | 19 | def edit 20 | end 21 | 22 | def create 23 | @article = Article.new(article_params.merge(user: current_user)) 24 | 25 | if @article.save 26 | redirect_to @article, notice: "Article was successfully created." 27 | else 28 | render :new, status: :unprocessable_entity 29 | end 30 | end 31 | 32 | def update 33 | if @article.update(article_params) 34 | redirect_to @article, notice: "Article was successfully updated." 35 | else 36 | render :edit, status: :unprocessable_entity 37 | end 38 | end 39 | 40 | def destroy 41 | @article.destroy 42 | 43 | redirect_to articles_url, notice: "Article was successfully destroyed." 44 | end 45 | 46 | private 47 | 48 | def set_article 49 | @article = Article.find(params[:id]) 50 | end 51 | 52 | def article_params 53 | params.require(:article).permit(:title, :body) 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /app/views/articles/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Articles

3 | <%= link_to new_article_path, class: 'btn' do %> 4 | <%= heroicon "plus" %> 5 | New article 6 | <% end %> 7 |
8 | 9 | <%= search_form_for @q, data: { turbo_frame: "search" } do |f| %> 10 |
11 |
12 | <%= heroicon "magnifying-glass" %> 13 |
14 | <%= f.text_field :title_or_rich_text_body_cont, class: "search-input p-3 pl-10 text-sm", onkeyup: "search()", placeholder: "Search ..." %> 15 |
16 | <% end %> 17 | 18 | <%= turbo_frame_tag "search", target: "_top" do %> 19 |
20 | <% @articles.each do |article| %> 21 |
22 |

23 | <%= link_to article.title, article %> 24 |

25 |

26 | <%= author_and_date(article) %> 27 |

28 |
29 | <%= truncate strip_tags(article.body.to_s), length: 160 %> 30 |
31 |
32 | <%= link_to article, class: 'btn btn-outline' do %> 33 | Read more 34 | <%= heroicon 'chevron-right' %> 35 | <% end %> 36 |
37 |
38 | <% end %> 39 |
40 | 41 |
42 | <%== pagy_nav(@pagy) if @pagy.pages > 1 %> 43 |
44 | <% end %> 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚀 Rails + Ralix + Tailwind 2 | 3 | > Starter Kit to build modern Rails applications fast 4 | 5 | Powered by: 6 | 7 | - [Rails](https://rubyonrails.org) 8 | - [Ralix](https://github.com/ralixjs/ralix) 9 | - [Tailwind CSS](https://tailwindcss.com) 10 | - [PostgreSQL](https://www.postgresql.org) 11 | - [Turbo](https://turbo.hotwired.dev) 12 | - [esbuild](https://esbuild.github.io) 13 | 14 | Rails v8 application template ready to start building your next project, with a pre-configured modern front-end stack and some extras: 15 | 16 | - 🎨 Minimalistic and responsive, clean layout 17 | - 🎯 Icons pack, via [Heroicons](https://heroicons.com) 18 | - 🔐 Authentication, via [Devise](https://github.com/heartcombo/devise) + [OmniAuth](https://github.com/omniauth/omniauth) for Social Logins 19 | - 👥 Authorization, via [CanCanCan](https://github.com/CanCanCommunity/cancancan) 20 | - 🔍 Searching, via [Ransack](https://github.com/activerecord-hackery/ransack) 21 | - 📝 Rich text edition, via [Trix](https://trix-editor.org) 22 | - 🔢 Pagination, via [Pagy](https://github.com/ddnexus/pagy) 23 | - 📄 Static pages controller (About, Terms, ...) 24 | - 🔴 Custom errors pages: 404, 422, 500 25 | - 📦 *Ready-to-use* components: Tables, Buttons, Forms, Cards, Modals and Tooltips 26 | 27 | ## Install 28 | 29 | Clone this repository (or use the GitHub *template* button), then `cd` into the folder and run: 30 | 31 | ``` 32 | > bin/setup 33 | ``` 34 | 35 | ## Run 36 | 37 | Start the development server: 38 | 39 | ``` 40 | > bin/dev 41 | ``` 42 | 43 | And open your browser at [`localhost:3000`](http://localhost:3000). 44 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | # This configuration file will be evaluated by Puma. The top-level methods that 2 | # are invoked here are part of Puma's configuration DSL. For more information 3 | # about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. 4 | 5 | # Puma starts a configurable number of processes (workers) and each process 6 | # serves each request in a thread from an internal thread pool. 7 | # 8 | # The ideal number of threads per worker depends both on how much time the 9 | # application spends waiting for IO operations and on how much you wish to 10 | # to prioritize throughput over latency. 11 | # 12 | # As a rule of thumb, increasing the number of threads will increase how much 13 | # traffic a given process can handle (throughput), but due to CRuby's 14 | # Global VM Lock (GVL) it has diminishing returns and will degrade the 15 | # response time (latency) of the application. 16 | # 17 | # The default is set to 3 threads as it's deemed a decent compromise between 18 | # throughput and latency for the average Rails application. 19 | # 20 | # Any libraries that use a connection pool or another resource pool should 21 | # be configured to provide at least as many connections as the number of 22 | # threads. This includes Active Record's `pool` parameter in `database.yml`. 23 | threads_count = ENV.fetch("RAILS_MAX_THREADS", 3) 24 | threads threads_count, threads_count 25 | 26 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 27 | port ENV.fetch("PORT", 3000) 28 | 29 | # Allow puma to be restarted by `bin/rails restart` command. 30 | plugin :tmp_restart 31 | 32 | # Specify the PID file. Defaults to tmp/pids/server.pid in development. 33 | # In other environments, only set the PID file if requested. 34 | pidfile ENV["PIDFILE"] if ENV["PIDFILE"] 35 | -------------------------------------------------------------------------------- /app/views/pages/about.html.erb: -------------------------------------------------------------------------------- 1 |

About us

2 | 3 |

Welcome to our company! We are dedicated to providing exceptional service and innovative solutions to our customers. Our team is passionate about delivering quality products that make a difference in people's lives. Founded with a vision to transform the industry, we have grown from a small startup to a leading organization that values integrity, excellence, and customer satisfaction above all else.

4 | 5 |

Mission

6 | 7 |

Our mission is to empower businesses and individuals through cutting-edge technology and unparalleled service. We strive to create value for our stakeholders while contributing positively to the communities we serve. By fostering innovation and maintaining the highest standards of quality, we aim to be the trusted partner for all your needs.

8 |

We believe in sustainable growth and responsible business practices. Our commitment extends beyond profit to include environmental stewardship and social responsibility. Every decision we make is guided by our core values and our dedication to making a positive impact on the world around us.

9 | 10 |

Values

11 | 12 |

Integrity is at the heart of everything we do. We build trust through transparency, honesty, and ethical behavior in all our interactions. Innovation drives us forward as we continuously seek new ways to improve and evolve. We embrace change and encourage creative thinking to solve complex challenges.

13 |

Excellence is our standard, not our goal. We are committed to delivering superior quality in every aspect of our work. Collaboration and teamwork enable us to achieve more together than we could individually. We value diverse perspectives and believe that our differences make us stronger.

14 | 15 |

Team

16 | 17 |

Our team consists of talented professionals from diverse backgrounds who share a common passion for excellence. Each member brings unique skills and perspectives that contribute to our collective success. We foster a culture of continuous learning and professional development, ensuring our team stays at the forefront of industry trends and best practices.

18 |

We believe that our people are our greatest asset. That's why we invest in their growth, provide opportunities for advancement, and maintain a supportive work environment where everyone can thrive. Our collaborative culture encourages open communication, mutual respect, and shared accountability for our success.

19 | -------------------------------------------------------------------------------- /db/migrate/20221005175500_create_active_storage_tables.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20170806125915) 2 | class CreateActiveStorageTables < ActiveRecord::Migration[5.2] 3 | def change 4 | # Use Active Record's configured type for primary and foreign keys 5 | primary_key_type, foreign_key_type = primary_and_foreign_key_types 6 | 7 | create_table :active_storage_blobs, id: primary_key_type do |t| 8 | t.string :key, null: false 9 | t.string :filename, null: false 10 | t.string :content_type 11 | t.text :metadata 12 | t.string :service_name, null: false 13 | t.bigint :byte_size, null: false 14 | t.string :checksum 15 | 16 | if connection.supports_datetime_with_precision? 17 | t.datetime :created_at, precision: 6, null: false 18 | else 19 | t.datetime :created_at, null: false 20 | end 21 | 22 | t.index [ :key ], unique: true 23 | end 24 | 25 | create_table :active_storage_attachments, id: primary_key_type do |t| 26 | t.string :name, null: false 27 | t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type 28 | t.references :blob, null: false, type: foreign_key_type 29 | 30 | if connection.supports_datetime_with_precision? 31 | t.datetime :created_at, precision: 6, null: false 32 | else 33 | t.datetime :created_at, null: false 34 | end 35 | 36 | t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true 37 | t.foreign_key :active_storage_blobs, column: :blob_id 38 | end 39 | 40 | create_table :active_storage_variant_records, id: primary_key_type do |t| 41 | t.belongs_to :blob, null: false, index: false, type: foreign_key_type 42 | t.string :variation_digest, null: false 43 | 44 | t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true 45 | t.foreign_key :active_storage_blobs, column: :blob_id 46 | end 47 | end 48 | 49 | private 50 | def primary_and_foreign_key_types 51 | config = Rails.configuration.generators 52 | setting = config.options[config.orm][:primary_key_type] 53 | primary_key_type = setting || :primary_key 54 | foreign_key_type = setting || :bigint 55 | [primary_key_type, foreign_key_type] 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | # The test environment is used exclusively to run your application's 2 | # test suite. You never need to work with it otherwise. Remember that 3 | # your test database is "scratch space" for the test suite and is wiped 4 | # and recreated between test runs. Don't rely on the data there! 5 | 6 | Rails.application.configure do 7 | # Settings specified here will take precedence over those in config/application.rb. 8 | 9 | # While tests run files are not watched, reloading is not necessary. 10 | config.enable_reloading = false 11 | 12 | # Eager loading loads your entire application. When running a single test locally, 13 | # this is usually not necessary, and can slow down your test suite. However, it's 14 | # recommended that you enable it in continuous integration systems to ensure eager 15 | # loading is working properly before deploying your code. 16 | config.eager_load = ENV["CI"].present? 17 | 18 | # Configure public file server for tests with cache-control for performance. 19 | config.public_file_server.headers = { "cache-control" => "public, max-age=3600" } 20 | 21 | # Show full error reports. 22 | config.consider_all_requests_local = true 23 | config.cache_store = :null_store 24 | 25 | # Render exception templates for rescuable exceptions and raise for other exceptions. 26 | config.action_dispatch.show_exceptions = :rescuable 27 | 28 | # Disable request forgery protection in test environment. 29 | config.action_controller.allow_forgery_protection = false 30 | 31 | # Store uploaded files on the local file system in a temporary directory. 32 | config.active_storage.service = :test 33 | 34 | # Tell Action Mailer not to deliver emails to the real world. 35 | # The :test delivery method accumulates sent emails in the 36 | # ActionMailer::Base.deliveries array. 37 | config.action_mailer.delivery_method = :test 38 | 39 | # Set host to be used by links generated in mailer templates. 40 | config.action_mailer.default_url_options = { host: "example.com" } 41 | 42 | # Print deprecation notices to the stderr. 43 | config.active_support.deprecation = :stderr 44 | 45 | # Raises error for missing translations. 46 | # config.i18n.raise_on_missing_translations = true 47 | 48 | # Annotate rendered view with file names. 49 | # config.action_view.annotate_rendered_view_with_filenames = true 50 | 51 | # Raise error when a before_action's only/except options reference missing actions. 52 | config.action_controller.raise_on_missing_callback_actions = true 53 | end 54 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # Make code changes take effect immediately without server restart. 7 | config.enable_reloading = true 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable server timing. 16 | config.server_timing = true 17 | 18 | # Enable/disable Action Controller caching. By default Action Controller caching is disabled. 19 | # Run rails dev:cache to toggle Action Controller caching. 20 | if Rails.root.join("tmp/caching-dev.txt").exist? 21 | config.action_controller.perform_caching = true 22 | config.action_controller.enable_fragment_cache_logging = true 23 | config.public_file_server.headers = { "cache-control" => "public, max-age=#{2.days.to_i}" } 24 | else 25 | config.action_controller.perform_caching = false 26 | end 27 | 28 | # Change to :null_store to avoid any caching. 29 | config.cache_store = :memory_store 30 | 31 | # Store uploaded files on the local file system (see config/storage.yml for options). 32 | config.active_storage.service = :local 33 | 34 | # Don't care if the mailer can't send. 35 | config.action_mailer.raise_delivery_errors = false 36 | 37 | # Make template changes take effect immediately. 38 | config.action_mailer.perform_caching = false 39 | 40 | # Set localhost to be used by links generated in mailer templates. 41 | config.action_mailer.default_url_options = { host: "localhost", port: 3000 } 42 | 43 | # Print deprecation notices to the Rails logger. 44 | config.active_support.deprecation = :log 45 | 46 | # Raise an error on page load if there are pending migrations. 47 | config.active_record.migration_error = :page_load 48 | 49 | # Highlight code that triggered database queries in logs. 50 | config.active_record.verbose_query_logs = true 51 | 52 | # Append comments with runtime information tags to SQL queries in logs. 53 | config.active_record.query_log_tags_enabled = true 54 | 55 | # Highlight code that enqueued background job in logs. 56 | config.active_job.verbose_enqueue_logs = true 57 | 58 | # Raises error for missing translations. 59 | # config.i18n.raise_on_missing_translations = true 60 | 61 | # Annotate rendered view with file names. 62 | config.action_view.annotate_rendered_view_with_filenames = true 63 | 64 | # Uncomment if you wish to allow Action Cable access from any origin. 65 | # config.action_cable.disable_request_forgery_protection = true 66 | 67 | # Raise error when a before_action's only/except options reference missing actions. 68 | config.action_controller.raise_on_missing_callback_actions = true 69 | end 70 | -------------------------------------------------------------------------------- /app/views/application/_header.html.erb: -------------------------------------------------------------------------------- 1 | 63 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # This file is the source Rails uses to define your schema when running `bin/rails 6 | # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to 7 | # be faster and is potentially less error prone than running all of your 8 | # migrations from scratch. Old migrations may fail to apply correctly if those 9 | # migrations use external dependencies or application code. 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema[7.2].define(version: 2024_09_27_114004) do 14 | # These are extensions that must be enabled in order to support this database 15 | enable_extension "plpgsql" 16 | 17 | create_table "action_text_rich_texts", force: :cascade do |t| 18 | t.string "name", null: false 19 | t.text "body" 20 | t.string "record_type", null: false 21 | t.bigint "record_id", null: false 22 | t.datetime "created_at", null: false 23 | t.datetime "updated_at", null: false 24 | t.index ["record_type", "record_id", "name"], name: "index_action_text_rich_texts_uniqueness", unique: true 25 | end 26 | 27 | create_table "active_storage_attachments", force: :cascade do |t| 28 | t.string "name", null: false 29 | t.string "record_type", null: false 30 | t.bigint "record_id", null: false 31 | t.bigint "blob_id", null: false 32 | t.datetime "created_at", null: false 33 | t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" 34 | t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true 35 | end 36 | 37 | create_table "active_storage_blobs", force: :cascade do |t| 38 | t.string "key", null: false 39 | t.string "filename", null: false 40 | t.string "content_type" 41 | t.text "metadata" 42 | t.string "service_name", null: false 43 | t.bigint "byte_size", null: false 44 | t.string "checksum" 45 | t.datetime "created_at", null: false 46 | t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true 47 | end 48 | 49 | create_table "active_storage_variant_records", force: :cascade do |t| 50 | t.bigint "blob_id", null: false 51 | t.string "variation_digest", null: false 52 | t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true 53 | end 54 | 55 | create_table "articles", force: :cascade do |t| 56 | t.string "title" 57 | t.text "body" 58 | t.bigint "user_id" 59 | t.datetime "created_at", null: false 60 | t.datetime "updated_at", null: false 61 | t.index ["user_id"], name: "index_articles_on_user_id" 62 | end 63 | 64 | create_table "users", force: :cascade do |t| 65 | t.string "email", default: "", null: false 66 | t.string "encrypted_password", default: "", null: false 67 | t.string "reset_password_token" 68 | t.datetime "reset_password_sent_at" 69 | t.datetime "remember_created_at" 70 | t.datetime "created_at", null: false 71 | t.datetime "updated_at", null: false 72 | t.string "name" 73 | t.index ["email"], name: "index_users_on_email", unique: true 74 | t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true 75 | end 76 | 77 | add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" 78 | add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" 79 | end 80 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # Code is not reloaded between requests. 7 | config.enable_reloading = false 8 | 9 | # Eager load code on boot for better performance and memory savings (ignored by Rake tasks). 10 | config.eager_load = true 11 | 12 | # Full error reports are disabled. 13 | config.consider_all_requests_local = false 14 | 15 | # Turn on fragment caching in view templates. 16 | config.action_controller.perform_caching = true 17 | 18 | # Cache assets for far-future expiry since they are all digest stamped. 19 | config.public_file_server.headers = { "cache-control" => "public, max-age=#{1.year.to_i}" } 20 | 21 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 22 | # config.asset_host = "http://assets.example.com" 23 | 24 | # Store uploaded files on the local file system (see config/storage.yml for options). 25 | config.active_storage.service = :local 26 | 27 | # Assume all access to the app is happening through a SSL-terminating reverse proxy. 28 | config.assume_ssl = true 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | config.force_ssl = true 32 | 33 | # Skip http-to-https redirect for the default health check endpoint. 34 | # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } 35 | 36 | # Log to STDOUT with the current request id as a default log tag. 37 | config.log_tags = [ :request_id ] 38 | config.logger = ActiveSupport::TaggedLogging.logger(STDOUT) 39 | 40 | # Change to "debug" to log everything (including potentially personally-identifiable information!) 41 | config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") 42 | 43 | # Prevent health checks from clogging up the logs. 44 | config.silence_healthcheck_path = "/up" 45 | 46 | # Don't log any deprecations. 47 | config.active_support.report_deprecations = false 48 | 49 | # Replace the default in-process memory cache store with a durable alternative. 50 | # config.cache_store = :mem_cache_store 51 | 52 | # Replace the default in-process and non-durable queuing backend for Active Job. 53 | # config.active_job.queue_adapter = :resque 54 | 55 | # Ignore bad email addresses and do not raise email delivery errors. 56 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 57 | # config.action_mailer.raise_delivery_errors = false 58 | 59 | # Set host to be used by links generated in mailer templates. 60 | config.action_mailer.default_url_options = { host: "example.com" } 61 | 62 | # Specify outgoing SMTP server. Remember to add smtp/* credentials via rails credentials:edit. 63 | # config.action_mailer.smtp_settings = { 64 | # user_name: Rails.application.credentials.dig(:smtp, :user_name), 65 | # password: Rails.application.credentials.dig(:smtp, :password), 66 | # address: "smtp.example.com", 67 | # port: 587, 68 | # authentication: :plain 69 | # } 70 | 71 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 72 | # the I18n.default_locale when a translation cannot be found). 73 | config.i18n.fallbacks = true 74 | 75 | # Do not dump schema after migrations. 76 | config.active_record.dump_schema_after_migration = false 77 | 78 | # Only use :id for inspections in production. 79 | config.active_record.attributes_for_inspect = [ :id ] 80 | 81 | # Enable DNS rebinding protection and other `Host` header attacks. 82 | # config.hosts = [ 83 | # "example.com", # Allow requests from example.com 84 | # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` 85 | # ] 86 | # 87 | # Skip DNS rebinding protection for the default health check endpoint. 88 | # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } 89 | end 90 | -------------------------------------------------------------------------------- /db/seed_data.rb: -------------------------------------------------------------------------------- 1 | # Seed data for the Rails application 2 | # This file contains static data used to seed the database 3 | 4 | module SeedData 5 | USERS = [ 6 | { name: "John Smith", email: "john@example.com" }, 7 | { name: "Jane Doe", email: "jane@example.com" }, 8 | { name: "Michael Johnson", email: "michael@example.com" }, 9 | { name: "Emily Davis", email: "emily@example.com" }, 10 | { name: "David Wilson", email: "david@example.com" }, 11 | { name: "Sarah Brown", email: "sarah@example.com" }, 12 | { name: "Chris Miller", email: "chris@example.com" }, 13 | { name: "Amanda Taylor", email: "amanda@example.com" }, 14 | { name: "Ryan Anderson", email: "ryan@example.com" }, 15 | { name: "Lisa Thompson", email: "lisa@example.com" } 16 | ].freeze 17 | 18 | ARTICLES = [ 19 | { 20 | title: "Getting Started with Ruby on Rails", 21 | body: "Ruby on Rails is a server-side web application framework written in Ruby. It is a model-view-controller framework, providing default structures for a database, a web service, and web pages. This article will guide you through the basics of setting up and building your first Rails application." 22 | }, 23 | { 24 | title: "Modern Frontend Development", 25 | body: "The landscape of frontend development has evolved significantly in recent years. With the introduction of new frameworks and tools, developers now have more options than ever to create engaging and interactive user interfaces. This article explores the latest trends and best practices in frontend development." 26 | }, 27 | { 28 | title: "Database Design Principles", 29 | body: "A well-designed database is crucial for any application's performance and scalability. Understanding the principles of database design, normalization, and optimization can make the difference between a slow, inefficient system and a fast, reliable one. Learn the fundamentals of creating robust database schemas." 30 | }, 31 | { 32 | title: "API Development Best Practices", 33 | body: "Building robust and scalable APIs requires careful planning and adherence to best practices. From choosing the right architectural patterns to implementing proper authentication and error handling, this guide covers everything you need to know about creating professional-grade APIs." 34 | }, 35 | { 36 | title: "Testing Strategies for Web Applications", 37 | body: "Testing is an essential part of the development process that ensures your application works as expected and remains stable as it grows. This article covers different types of testing, from unit tests to integration tests, and how to implement an effective testing strategy for your web applications." 38 | }, 39 | { 40 | title: "Performance Optimization Techniques", 41 | body: "Website performance directly impacts user experience and business success. Understanding how to identify bottlenecks, optimize database queries, implement caching strategies, and reduce load times can significantly improve your application's performance and user satisfaction." 42 | }, 43 | { 44 | title: "Security Considerations for Web Development", 45 | body: "Security should be a top priority in any web development project. From protecting against common vulnerabilities like SQL injection and cross-site scripting to implementing proper authentication and authorization mechanisms, this article covers essential security practices every developer should know." 46 | }, 47 | { 48 | title: "DevOps and Deployment Strategies", 49 | body: "Modern web development extends beyond just writing code. Understanding deployment pipelines, continuous integration, and infrastructure management is crucial for delivering reliable applications. Learn about different deployment strategies and tools that can streamline your development workflow." 50 | }, 51 | { 52 | title: "User Experience Design Principles", 53 | body: "Creating applications that users love requires understanding the principles of user experience design. From information architecture to visual design and usability testing, this article explores how to create intuitive and engaging user interfaces that meet user needs and business objectives." 54 | }, 55 | { 56 | title: "Scalability and Architecture Patterns", 57 | body: "As applications grow, scalability becomes a critical concern. Understanding different architectural patterns, microservices, load balancing, and database scaling strategies can help you build applications that can handle increased traffic and data volumes without compromising performance." 58 | }, 59 | { 60 | title: "Mobile-First Development Approach", 61 | body: "With the majority of web traffic now coming from mobile devices, adopting a mobile-first approach to development has become essential. This article discusses responsive design principles, performance considerations for mobile devices, and strategies for creating great mobile user experiences." 62 | }, 63 | { 64 | title: "Version Control and Collaboration", 65 | body: "Effective version control and collaboration practices are fundamental to successful software development. Understanding Git workflows, code review processes, and team collaboration tools can significantly improve productivity and code quality in development teams." 66 | }, 67 | { 68 | title: "Monitoring and Observability", 69 | body: "Once your application is deployed, monitoring its performance and health becomes crucial. Learn about different monitoring tools, logging strategies, error tracking, and observability practices that help you maintain reliable and performant applications in production." 70 | }, 71 | { 72 | title: "Progressive Web Applications", 73 | body: "Progressive Web Applications combine the best of web and mobile apps to provide users with an app-like experience directly in the browser. This article explores the key features of PWAs, including service workers, web app manifests, and offline functionality." 74 | }, 75 | { 76 | title: "Data Visualization and Analytics", 77 | body: "Making data meaningful and actionable requires effective visualization and analytics tools. From choosing the right chart types to implementing real-time dashboards and understanding data analysis techniques, this article covers the essentials of data presentation and interpretation." 78 | }, 79 | { 80 | title: "Accessibility in Web Development", 81 | body: "Creating inclusive web applications that work for users with disabilities is both a moral imperative and often a legal requirement. Learn about web accessibility standards, assistive technologies, and practical techniques for building accessible user interfaces." 82 | }, 83 | { 84 | title: "Microservices Architecture", 85 | body: "Microservices architecture has gained popularity for building scalable and maintainable applications. This article explores the benefits and challenges of microservices, service communication patterns, and strategies for breaking down monolithic applications into microservices." 86 | }, 87 | { 88 | title: "Cloud Computing Fundamentals", 89 | body: "Cloud computing has revolutionized how we deploy and scale applications. Understanding different cloud service models, infrastructure as code, containerization, and cloud-native development practices is essential for modern web developers." 90 | }, 91 | { 92 | title: "Machine Learning Integration", 93 | body: "Integrating machine learning capabilities into web applications is becoming increasingly common. This article covers the basics of ML model deployment, API integration, and practical considerations for incorporating artificial intelligence features into your applications." 94 | }, 95 | { 96 | title: "The Future of Web Development", 97 | body: "The web development landscape continues to evolve rapidly with new technologies, frameworks, and paradigms emerging regularly. This article explores upcoming trends, emerging technologies, and predictions for the future of web development, helping developers stay ahead of the curve." 98 | } 99 | ].freeze 100 | end -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (8.0.2.1) 5 | actionpack (= 8.0.2.1) 6 | activesupport (= 8.0.2.1) 7 | nio4r (~> 2.0) 8 | websocket-driver (>= 0.6.1) 9 | zeitwerk (~> 2.6) 10 | actionmailbox (8.0.2.1) 11 | actionpack (= 8.0.2.1) 12 | activejob (= 8.0.2.1) 13 | activerecord (= 8.0.2.1) 14 | activestorage (= 8.0.2.1) 15 | activesupport (= 8.0.2.1) 16 | mail (>= 2.8.0) 17 | actionmailer (8.0.2.1) 18 | actionpack (= 8.0.2.1) 19 | actionview (= 8.0.2.1) 20 | activejob (= 8.0.2.1) 21 | activesupport (= 8.0.2.1) 22 | mail (>= 2.8.0) 23 | rails-dom-testing (~> 2.2) 24 | actionpack (8.0.2.1) 25 | actionview (= 8.0.2.1) 26 | activesupport (= 8.0.2.1) 27 | nokogiri (>= 1.8.5) 28 | rack (>= 2.2.4) 29 | rack-session (>= 1.0.1) 30 | rack-test (>= 0.6.3) 31 | rails-dom-testing (~> 2.2) 32 | rails-html-sanitizer (~> 1.6) 33 | useragent (~> 0.16) 34 | actiontext (8.0.2.1) 35 | actionpack (= 8.0.2.1) 36 | activerecord (= 8.0.2.1) 37 | activestorage (= 8.0.2.1) 38 | activesupport (= 8.0.2.1) 39 | globalid (>= 0.6.0) 40 | nokogiri (>= 1.8.5) 41 | actionview (8.0.2.1) 42 | activesupport (= 8.0.2.1) 43 | builder (~> 3.1) 44 | erubi (~> 1.11) 45 | rails-dom-testing (~> 2.2) 46 | rails-html-sanitizer (~> 1.6) 47 | activejob (8.0.2.1) 48 | activesupport (= 8.0.2.1) 49 | globalid (>= 0.3.6) 50 | activemodel (8.0.2.1) 51 | activesupport (= 8.0.2.1) 52 | activerecord (8.0.2.1) 53 | activemodel (= 8.0.2.1) 54 | activesupport (= 8.0.2.1) 55 | timeout (>= 0.4.0) 56 | activestorage (8.0.2.1) 57 | actionpack (= 8.0.2.1) 58 | activejob (= 8.0.2.1) 59 | activerecord (= 8.0.2.1) 60 | activesupport (= 8.0.2.1) 61 | marcel (~> 1.0) 62 | activesupport (8.0.2.1) 63 | base64 64 | benchmark (>= 0.3) 65 | bigdecimal 66 | concurrent-ruby (~> 1.0, >= 1.3.1) 67 | connection_pool (>= 2.2.5) 68 | drb 69 | i18n (>= 1.6, < 2) 70 | logger (>= 1.4.2) 71 | minitest (>= 5.1) 72 | securerandom (>= 0.3) 73 | tzinfo (~> 2.0, >= 2.0.5) 74 | uri (>= 0.13.1) 75 | base64 (0.3.0) 76 | bcrypt (3.1.20) 77 | benchmark (0.4.1) 78 | bigdecimal (3.2.2) 79 | bindex (0.8.1) 80 | bootsnap (1.18.6) 81 | msgpack (~> 1.2) 82 | builder (3.3.0) 83 | cancancan (3.6.1) 84 | concurrent-ruby (1.3.5) 85 | connection_pool (2.5.3) 86 | crass (1.0.6) 87 | cssbundling-rails (1.4.3) 88 | railties (>= 6.0.0) 89 | date (3.4.1) 90 | debug (1.11.0) 91 | irb (~> 1.10) 92 | reline (>= 0.3.8) 93 | devise (4.9.4) 94 | bcrypt (~> 3.0) 95 | orm_adapter (~> 0.1) 96 | railties (>= 4.1.0) 97 | responders 98 | warden (~> 1.2.3) 99 | dotenv (3.1.8) 100 | dotenv-rails (3.1.8) 101 | dotenv (= 3.1.8) 102 | railties (>= 6.1) 103 | drb (2.2.3) 104 | erb (5.0.2) 105 | erubi (1.13.1) 106 | faraday (2.13.4) 107 | faraday-net_http (>= 2.0, < 3.5) 108 | json 109 | logger 110 | faraday-net_http (3.4.1) 111 | net-http (>= 0.5.0) 112 | ffi (1.17.2-arm64-darwin) 113 | ffi (1.17.2-x86_64-darwin) 114 | ffi (1.17.2-x86_64-linux-gnu) 115 | globalid (1.2.1) 116 | activesupport (>= 6.1) 117 | hashie (5.0.0) 118 | heroicon (1.0.0) 119 | rails (>= 5.2) 120 | i18n (1.14.7) 121 | concurrent-ruby (~> 1.0) 122 | image_processing (1.14.0) 123 | mini_magick (>= 4.9.5, < 6) 124 | ruby-vips (>= 2.0.17, < 3) 125 | io-console (0.8.1) 126 | irb (1.15.2) 127 | pp (>= 0.6.0) 128 | rdoc (>= 4.0.0) 129 | reline (>= 0.4.2) 130 | jsbundling-rails (1.3.1) 131 | railties (>= 6.0.0) 132 | json (2.13.1) 133 | jwt (3.1.2) 134 | base64 135 | logger (1.7.0) 136 | loofah (2.24.1) 137 | crass (~> 1.0.2) 138 | nokogiri (>= 1.12.0) 139 | mail (2.8.1) 140 | mini_mime (>= 0.1.1) 141 | net-imap 142 | net-pop 143 | net-smtp 144 | marcel (1.0.4) 145 | mini_magick (5.3.0) 146 | logger 147 | mini_mime (1.1.5) 148 | minitest (5.25.5) 149 | msgpack (1.8.0) 150 | multi_xml (0.7.2) 151 | bigdecimal (~> 3.1) 152 | net-http (0.6.0) 153 | uri 154 | net-imap (0.5.9) 155 | date 156 | net-protocol 157 | net-pop (0.1.2) 158 | net-protocol 159 | net-protocol (0.2.2) 160 | timeout 161 | net-smtp (0.5.1) 162 | net-protocol 163 | nio4r (2.7.4) 164 | nokogiri (1.18.9-arm64-darwin) 165 | racc (~> 1.4) 166 | nokogiri (1.18.9-x86_64-darwin) 167 | racc (~> 1.4) 168 | nokogiri (1.18.9-x86_64-linux-gnu) 169 | racc (~> 1.4) 170 | oauth2 (2.0.12) 171 | faraday (>= 0.17.3, < 4.0) 172 | jwt (>= 1.0, < 4.0) 173 | logger (~> 1.2) 174 | multi_xml (~> 0.5) 175 | rack (>= 1.2, < 4) 176 | snaky_hash (~> 2.0, >= 2.0.3) 177 | version_gem (>= 1.1.8, < 3) 178 | omniauth (2.1.3) 179 | hashie (>= 3.4.6) 180 | rack (>= 2.2.3) 181 | rack-protection 182 | omniauth-facebook (9.0.0) 183 | omniauth-oauth2 (~> 1.2) 184 | omniauth-github (2.0.1) 185 | omniauth (~> 2.0) 186 | omniauth-oauth2 (~> 1.8) 187 | omniauth-google-oauth2 (1.2.1) 188 | jwt (>= 2.9.2) 189 | oauth2 (~> 2.0) 190 | omniauth (~> 2.0) 191 | omniauth-oauth2 (~> 1.8) 192 | omniauth-oauth2 (1.8.0) 193 | oauth2 (>= 1.4, < 3) 194 | omniauth (~> 2.0) 195 | omniauth-rails_csrf_protection (1.0.2) 196 | actionpack (>= 4.2) 197 | omniauth (~> 2.0) 198 | orm_adapter (0.5.0) 199 | pagy (9.3.5) 200 | pg (1.5.9) 201 | pp (0.6.2) 202 | prettyprint 203 | prettyprint (0.2.0) 204 | propshaft (1.2.1) 205 | actionpack (>= 7.0.0) 206 | activesupport (>= 7.0.0) 207 | rack 208 | psych (5.2.6) 209 | date 210 | stringio 211 | puma (6.6.0) 212 | nio4r (~> 2.0) 213 | racc (1.8.1) 214 | rack (3.1.18) 215 | rack-protection (4.1.1) 216 | base64 (>= 0.1.0) 217 | logger (>= 1.6.0) 218 | rack (>= 3.0.0, < 4) 219 | rack-session (2.1.1) 220 | base64 (>= 0.1.0) 221 | rack (>= 3.0.0) 222 | rack-test (2.2.0) 223 | rack (>= 1.3) 224 | rackup (2.2.1) 225 | rack (>= 3) 226 | rails (8.0.2.1) 227 | actioncable (= 8.0.2.1) 228 | actionmailbox (= 8.0.2.1) 229 | actionmailer (= 8.0.2.1) 230 | actionpack (= 8.0.2.1) 231 | actiontext (= 8.0.2.1) 232 | actionview (= 8.0.2.1) 233 | activejob (= 8.0.2.1) 234 | activemodel (= 8.0.2.1) 235 | activerecord (= 8.0.2.1) 236 | activestorage (= 8.0.2.1) 237 | activesupport (= 8.0.2.1) 238 | bundler (>= 1.15.0) 239 | railties (= 8.0.2.1) 240 | rails-dom-testing (2.3.0) 241 | activesupport (>= 5.0.0) 242 | minitest 243 | nokogiri (>= 1.6) 244 | rails-html-sanitizer (1.6.2) 245 | loofah (~> 2.21) 246 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) 247 | railties (8.0.2.1) 248 | actionpack (= 8.0.2.1) 249 | activesupport (= 8.0.2.1) 250 | irb (~> 1.13) 251 | rackup (>= 1.0.0) 252 | rake (>= 12.2) 253 | thor (~> 1.0, >= 1.2.2) 254 | zeitwerk (~> 2.6) 255 | rake (13.3.0) 256 | ransack (4.3.0) 257 | activerecord (>= 6.1.5) 258 | activesupport (>= 6.1.5) 259 | i18n 260 | rdoc (6.14.2) 261 | erb 262 | psych (>= 4.0.0) 263 | reline (0.6.2) 264 | io-console (~> 0.5) 265 | responders (3.1.1) 266 | actionpack (>= 5.2) 267 | railties (>= 5.2) 268 | ruby-vips (2.2.4) 269 | ffi (~> 1.12) 270 | logger 271 | securerandom (0.4.1) 272 | snaky_hash (2.0.3) 273 | hashie (>= 0.1.0, < 6) 274 | version_gem (>= 1.1.8, < 3) 275 | stringio (3.1.7) 276 | thor (1.4.0) 277 | timeout (0.4.3) 278 | turbo-rails (2.0.16) 279 | actionpack (>= 7.1.0) 280 | railties (>= 7.1.0) 281 | tzinfo (2.0.6) 282 | concurrent-ruby (~> 1.0) 283 | uri (1.0.3) 284 | useragent (0.16.11) 285 | version_gem (1.1.8) 286 | warden (1.2.9) 287 | rack (>= 2.0.9) 288 | web-console (4.2.1) 289 | actionview (>= 6.0.0) 290 | activemodel (>= 6.0.0) 291 | bindex (>= 0.4.0) 292 | railties (>= 6.0.0) 293 | websocket-driver (0.8.0) 294 | base64 295 | websocket-extensions (>= 0.1.0) 296 | websocket-extensions (0.1.5) 297 | zeitwerk (2.7.3) 298 | 299 | PLATFORMS 300 | arm64-darwin-22 301 | x86_64-darwin-17 302 | x86_64-darwin-22 303 | x86_64-linux 304 | 305 | DEPENDENCIES 306 | bootsnap (~> 1.18) 307 | cancancan (~> 3.4) 308 | cssbundling-rails (~> 1.1) 309 | debug 310 | devise (~> 4.9) 311 | dotenv-rails 312 | heroicon (~> 1.0) 313 | image_processing (~> 1.2) 314 | jsbundling-rails (~> 1.0) 315 | omniauth-facebook (~> 9.0) 316 | omniauth-github (~> 2.0) 317 | omniauth-google-oauth2 (~> 1.1) 318 | omniauth-rails_csrf_protection (~> 1.0) 319 | pagy (~> 9.3) 320 | pg (~> 1.5) 321 | propshaft (~> 1.1) 322 | puma (~> 6.6) 323 | rails (~> 8.0) 324 | ransack (~> 4.2) 325 | turbo-rails (~> 2.0) 326 | web-console 327 | 328 | RUBY VERSION 329 | ruby 3.3.5p100 330 | 331 | BUNDLED WITH 332 | 2.5.20 333 | -------------------------------------------------------------------------------- /config/initializers/devise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Assuming you have not yet modified this file, each configuration option below 4 | # is set to its default value. Note that some are commented out while others 5 | # are not: uncommented lines are intended to protect your configuration from 6 | # breaking changes in upgrades (i.e., in the event that future versions of 7 | # Devise change the default values for those options). 8 | # 9 | # Use this hook to configure devise mailer, warden hooks and so forth. 10 | # Many of these configuration options can be set straight in your model. 11 | Devise.setup do |config| 12 | # The secret key used by Devise. Devise uses this key to generate 13 | # random tokens. Changing this key will render invalid all existing 14 | # confirmation, reset password and unlock tokens in the database. 15 | # Devise will use the `secret_key_base` as its `secret_key` 16 | # by default. You can change it below and use your own secret key. 17 | # config.secret_key = '6a79f69214018eba845c16fc7413df7428bb9fe9d07a579b26050f85e110825cf10cf45b91f65c1e5c394753ebf8813f0323cfcf4e26f7cd55133ee149af81a2' 18 | 19 | # ==> Controller configuration 20 | # Configure the parent class to the devise controllers. 21 | # config.parent_controller = 'DeviseController' 22 | 23 | # ==> Mailer Configuration 24 | # Configure the e-mail address which will be shown in Devise::Mailer, 25 | # note that it will be overwritten if you use your own mailer class 26 | # with default "from" parameter. 27 | # config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com' 28 | 29 | # Configure the class responsible to send e-mails. 30 | # config.mailer = 'Devise::Mailer' 31 | 32 | # Configure the parent class responsible to send e-mails. 33 | config.parent_mailer = 'ApplicationMailer' 34 | 35 | # ==> ORM configuration 36 | # Load and configure the ORM. Supports :active_record (default) and 37 | # :mongoid (bson_ext recommended) by default. Other ORMs may be 38 | # available as additional gems. 39 | require 'devise/orm/active_record' 40 | 41 | # ==> Configuration for any authentication mechanism 42 | # Configure which keys are used when authenticating a user. The default is 43 | # just :email. You can configure it to use [:username, :subdomain], so for 44 | # authenticating a user, both parameters are required. Remember that those 45 | # parameters are used only when authenticating and not when retrieving from 46 | # session. If you need permissions, you should implement that in a before filter. 47 | # You can also supply a hash where the value is a boolean determining whether 48 | # or not authentication should be aborted when the value is not present. 49 | # config.authentication_keys = [:email] 50 | 51 | # Configure parameters from the request object used for authentication. Each entry 52 | # given should be a request method and it will automatically be passed to the 53 | # find_for_authentication method and considered in your model lookup. For instance, 54 | # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. 55 | # The same considerations mentioned for authentication_keys also apply to request_keys. 56 | # config.request_keys = [] 57 | 58 | # Configure which authentication keys should be case-insensitive. 59 | # These keys will be downcased upon creating or modifying a user and when used 60 | # to authenticate or find a user. Default is :email. 61 | config.case_insensitive_keys = [:email] 62 | 63 | # Configure which authentication keys should have whitespace stripped. 64 | # These keys will have whitespace before and after removed upon creating or 65 | # modifying a user and when used to authenticate or find a user. Default is :email. 66 | config.strip_whitespace_keys = [:email] 67 | 68 | # Tell if authentication through request.params is enabled. True by default. 69 | # It can be set to an array that will enable params authentication only for the 70 | # given strategies, for example, `config.params_authenticatable = [:database]` will 71 | # enable it only for database (email + password) authentication. 72 | # config.params_authenticatable = true 73 | 74 | # Tell if authentication through HTTP Auth is enabled. False by default. 75 | # It can be set to an array that will enable http authentication only for the 76 | # given strategies, for example, `config.http_authenticatable = [:database]` will 77 | # enable it only for database authentication. 78 | # For API-only applications to support authentication "out-of-the-box", you will likely want to 79 | # enable this with :database unless you are using a custom strategy. 80 | # The supported strategies are: 81 | # :database = Support basic authentication with authentication key + password 82 | # config.http_authenticatable = false 83 | 84 | # If 401 status code should be returned for AJAX requests. True by default. 85 | # config.http_authenticatable_on_xhr = true 86 | 87 | # The realm used in Http Basic Authentication. 'Application' by default. 88 | # config.http_authentication_realm = 'Application' 89 | 90 | # It will change confirmation, password recovery and other workflows 91 | # to behave the same regardless if the e-mail provided was right or wrong. 92 | # Does not affect registerable. 93 | config.paranoid = true 94 | 95 | # By default Devise will store the user in session. You can skip storage for 96 | # particular strategies by setting this option. 97 | # Notice that if you are skipping storage for all authentication paths, you 98 | # may want to disable generating routes to Devise's sessions controller by 99 | # passing skip: :sessions to `devise_for` in your config/routes.rb 100 | config.skip_session_storage = [:http_auth] 101 | 102 | # By default, Devise cleans up the CSRF token on authentication to 103 | # avoid CSRF token fixation attacks. This means that, when using AJAX 104 | # requests for sign in and sign up, you need to get a new CSRF token 105 | # from the server. You can disable this option at your own risk. 106 | # config.clean_up_csrf_token_on_authentication = true 107 | 108 | # When false, Devise will not attempt to reload routes on eager load. 109 | # This can reduce the time taken to boot the app but if your application 110 | # requires the Devise mappings to be loaded during boot time the application 111 | # won't boot properly. 112 | # config.reload_routes = true 113 | 114 | # ==> Configuration for :database_authenticatable 115 | # For bcrypt, this is the cost for hashing the password and defaults to 12. If 116 | # using other algorithms, it sets how many times you want the password to be hashed. 117 | # The number of stretches used for generating the hashed password are stored 118 | # with the hashed password. This allows you to change the stretches without 119 | # invalidating existing passwords. 120 | # 121 | # Limiting the stretches to just one in testing will increase the performance of 122 | # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use 123 | # a value less than 10 in other environments. Note that, for bcrypt (the default 124 | # algorithm), the cost increases exponentially with the number of stretches (e.g. 125 | # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation). 126 | config.stretches = Rails.env.test? ? 1 : 12 127 | 128 | # Set up a pepper to generate the hashed password. 129 | # config.pepper = '7867dd16f8db2c36d1edfe0d8b3996b8c4af1b24e3b257bf5c14e5318434e819c51e9b2119a594f8ac531a2ef5edb45e445f8e1b8758c05d5bf4baa6a90e47a4' 130 | 131 | # Send a notification to the original email when the user's email is changed. 132 | # config.send_email_changed_notification = false 133 | 134 | # Send a notification email when the user's password is changed. 135 | # config.send_password_change_notification = false 136 | 137 | # ==> Configuration for :confirmable 138 | # A period that the user is allowed to access the website even without 139 | # confirming their account. For instance, if set to 2.days, the user will be 140 | # able to access the website for two days without confirming their account, 141 | # access will be blocked just in the third day. 142 | # You can also set it to nil, which will allow the user to access the website 143 | # without confirming their account. 144 | # Default is 0.days, meaning the user cannot access the website without 145 | # confirming their account. 146 | # config.allow_unconfirmed_access_for = 2.days 147 | 148 | # A period that the user is allowed to confirm their account before their 149 | # token becomes invalid. For example, if set to 3.days, the user can confirm 150 | # their account within 3 days after the mail was sent, but on the fourth day 151 | # their account can't be confirmed with the token any more. 152 | # Default is nil, meaning there is no restriction on how long a user can take 153 | # before confirming their account. 154 | # config.confirm_within = 3.days 155 | 156 | # If true, requires any email changes to be confirmed (exactly the same way as 157 | # initial account confirmation) to be applied. Requires additional unconfirmed_email 158 | # db field (see migrations). Until confirmed, new email is stored in 159 | # unconfirmed_email column, and copied to email column on successful confirmation. 160 | config.reconfirmable = true 161 | 162 | # Defines which key will be used when confirming an account 163 | # config.confirmation_keys = [:email] 164 | 165 | # ==> Configuration for :rememberable 166 | # The time the user will be remembered without asking for credentials again. 167 | config.remember_for = 1.week 168 | 169 | # Invalidates all the remember me tokens when the user signs out. 170 | config.expire_all_remember_me_on_sign_out = true 171 | 172 | # If true, extends the user's remember period when remembered via cookie. 173 | # config.extend_remember_period = false 174 | 175 | # Options to be passed to the created cookie. For instance, you can set 176 | # secure: true in order to force SSL only cookies. 177 | # config.rememberable_options = {} 178 | 179 | # ==> Configuration for :validatable 180 | # Range for password length. 181 | config.password_length = 8..128 182 | 183 | # Email regex used to validate email formats. It simply asserts that 184 | # one (and only one) @ exists in the given string. This is mainly 185 | # to give user feedback and not to assert the e-mail validity. 186 | config.email_regexp = /\A[^@\s]+@[^@\s]+\z/ 187 | 188 | # ==> Configuration for :timeoutable 189 | # The time you want to timeout the user session without activity. After this 190 | # time the user will be asked for credentials again. Default is 30 minutes. 191 | # config.timeout_in = 30.minutes 192 | 193 | # ==> Configuration for :lockable 194 | # Defines which strategy will be used to lock an account. 195 | # :failed_attempts = Locks an account after a number of failed attempts to sign in. 196 | # :none = No lock strategy. You should handle locking by yourself. 197 | # config.lock_strategy = :failed_attempts 198 | 199 | # Defines which key will be used when locking and unlocking an account 200 | # config.unlock_keys = [:email] 201 | 202 | # Defines which strategy will be used to unlock an account. 203 | # :email = Sends an unlock link to the user email 204 | # :time = Re-enables login after a certain amount of time (see :unlock_in below) 205 | # :both = Enables both strategies 206 | # :none = No unlock strategy. You should handle unlocking by yourself. 207 | # config.unlock_strategy = :both 208 | 209 | # Number of authentication tries before locking an account if lock_strategy 210 | # is failed attempts. 211 | # config.maximum_attempts = 20 212 | 213 | # Time interval to unlock the account if :time is enabled as unlock_strategy. 214 | # config.unlock_in = 1.hour 215 | 216 | # Warn on the last attempt before the account is locked. 217 | # config.last_attempt_warning = true 218 | 219 | # ==> Configuration for :recoverable 220 | # 221 | # Defines which key will be used when recovering the password for an account 222 | # config.reset_password_keys = [:email] 223 | 224 | # Time interval you can reset your password with a reset password key. 225 | # Don't put a too small interval or your users won't have the time to 226 | # change their passwords. 227 | config.reset_password_within = 6.hours 228 | 229 | # When set to false, does not sign a user in automatically after their password is 230 | # reset. Defaults to true, so a user is signed in automatically after a reset. 231 | # config.sign_in_after_reset_password = true 232 | 233 | # ==> Configuration for :encryptable 234 | # Allow you to use another hashing or encryption algorithm besides bcrypt (default). 235 | # You can use :sha1, :sha512 or algorithms from others authentication tools as 236 | # :clearance_sha1, :authlogic_sha512 (then you should set stretches above to 20 237 | # for default behavior) and :restful_authentication_sha1 (then you should set 238 | # stretches to 10, and copy REST_AUTH_SITE_KEY to pepper). 239 | # 240 | # Require the `devise-encryptable` gem when using anything other than bcrypt 241 | # config.encryptor = :sha512 242 | 243 | # ==> Scopes configuration 244 | # Turn scoped views on. Before rendering "sessions/new", it will first check for 245 | # "users/sessions/new". It's turned off by default because it's slower if you 246 | # are using only default views. 247 | # config.scoped_views = false 248 | 249 | # Configure the default scope given to Warden. By default it's the first 250 | # devise role declared in your routes (usually :user). 251 | # config.default_scope = :user 252 | 253 | # Set this configuration to false if you want /users/sign_out to sign out 254 | # only the current scope. By default, Devise signs out all scopes. 255 | # config.sign_out_all_scopes = true 256 | 257 | # ==> Navigation configuration 258 | # Lists the formats that should be treated as navigational. Formats like 259 | # :html, should redirect to the sign in page when the user does not have 260 | # access, but formats like :xml or :json, should return 401. 261 | # 262 | # If you have any extra navigational formats, like :iphone or :mobile, you 263 | # should add them to the navigational formats lists. 264 | # 265 | # The "*/*" below is required to match Internet Explorer requests. 266 | # config.navigational_formats = ['*/*', :html] 267 | 268 | # The default HTTP method used to sign out a resource. Default is :delete. 269 | config.sign_out_via = :delete 270 | 271 | # ==> OmniAuth 272 | # Add a new OmniAuth provider. Check the wiki for more information on setting 273 | # up on your models and hooks. 274 | config.omniauth :facebook, ENV['FACEBOOK_CLIENT_ID'], ENV['FACEBOOK_CLIENT_SECRET'] 275 | config.omniauth :github, ENV['GITHUB_CLIENT_ID'], ENV['GITHUB_CLIENT_SECRET'] 276 | config.omniauth :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'] 277 | 278 | # ==> Warden configuration 279 | # If you want to use other strategies, that are not supported by Devise, or 280 | # change the failure app, you can configure them inside the config.warden block. 281 | # 282 | # config.warden do |manager| 283 | # manager.intercept_401 = false 284 | # manager.default_strategies(scope: :user).unshift :some_external_strategy 285 | # end 286 | 287 | # ==> Mountable engine configurations 288 | # When using Devise inside an engine, let's call it `MyEngine`, and this engine 289 | # is mountable, there are some extra configurations to be taken into account. 290 | # The following options are available, assuming the engine is mounted as: 291 | # 292 | # mount MyEngine, at: '/my_engine' 293 | # 294 | # The router that invoked `devise_for`, in the example above, would be: 295 | # config.router_name = :my_engine 296 | # 297 | # When using OmniAuth, Devise cannot automatically set OmniAuth path, 298 | # so you need to do it manually. For the users scope, it would be: 299 | # config.omniauth_path_prefix = '/my_engine/users/auth' 300 | 301 | # ==> Turbolinks configuration 302 | # If your app is using Turbolinks, Turbolinks::Controller needs to be included to make redirection work correctly: 303 | # 304 | # ActiveSupport.on_load(:devise_failure_app) do 305 | # include Turbolinks::Controller 306 | # end 307 | 308 | # ==> Configuration for :registerable 309 | 310 | # When set to false, does not sign a user in automatically after their password is 311 | # changed. Defaults to true, so a user is signed in automatically after changing a password. 312 | # config.sign_in_after_change_password = true 313 | end 314 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@ampproject/remapping@^2.3.0": 6 | version "2.3.0" 7 | resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" 8 | integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== 9 | dependencies: 10 | "@jridgewell/gen-mapping" "^0.3.5" 11 | "@jridgewell/trace-mapping" "^0.3.24" 12 | 13 | "@emnapi/core@^1.4.3": 14 | version "1.4.5" 15 | resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.4.5.tgz#bfbb0cbbbb9f96ec4e2c4fd917b7bbe5495ceccb" 16 | integrity sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q== 17 | dependencies: 18 | "@emnapi/wasi-threads" "1.0.4" 19 | tslib "^2.4.0" 20 | 21 | "@emnapi/runtime@^1.4.3": 22 | version "1.4.5" 23 | resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.5.tgz#c67710d0661070f38418b6474584f159de38aba9" 24 | integrity sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg== 25 | dependencies: 26 | tslib "^2.4.0" 27 | 28 | "@emnapi/wasi-threads@1.0.4", "@emnapi/wasi-threads@^1.0.2": 29 | version "1.0.4" 30 | resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz#703fc094d969e273b1b71c292523b2f792862bf4" 31 | integrity sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g== 32 | dependencies: 33 | tslib "^2.4.0" 34 | 35 | "@esbuild/aix-ppc64@0.25.8": 36 | version "0.25.8" 37 | resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz#a1414903bb38027382f85f03dda6065056757727" 38 | integrity sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA== 39 | 40 | "@esbuild/android-arm64@0.25.8": 41 | version "0.25.8" 42 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz#c859994089e9767224269884061f89dae6fb51c6" 43 | integrity sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w== 44 | 45 | "@esbuild/android-arm@0.25.8": 46 | version "0.25.8" 47 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.8.tgz#96a8f2ca91c6cd29ea90b1af79d83761c8ba0059" 48 | integrity sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw== 49 | 50 | "@esbuild/android-x64@0.25.8": 51 | version "0.25.8" 52 | resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.8.tgz#a3a626c4fec4a024a9fa8c7679c39996e92916f0" 53 | integrity sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA== 54 | 55 | "@esbuild/darwin-arm64@0.25.8": 56 | version "0.25.8" 57 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz#a5e1252ca2983d566af1c0ea39aded65736fc66d" 58 | integrity sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw== 59 | 60 | "@esbuild/darwin-x64@0.25.8": 61 | version "0.25.8" 62 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz#5271b0df2bb12ce8df886704bfdd1c7cc01385d2" 63 | integrity sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg== 64 | 65 | "@esbuild/freebsd-arm64@0.25.8": 66 | version "0.25.8" 67 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz#d0a0e7fdf19733b8bb1566b81df1aa0bb7e46ada" 68 | integrity sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA== 69 | 70 | "@esbuild/freebsd-x64@0.25.8": 71 | version "0.25.8" 72 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz#2de8b2e0899d08f1cb1ef3128e159616e7e85343" 73 | integrity sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw== 74 | 75 | "@esbuild/linux-arm64@0.25.8": 76 | version "0.25.8" 77 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz#a4209efadc0c2975716458484a4e90c237c48ae9" 78 | integrity sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w== 79 | 80 | "@esbuild/linux-arm@0.25.8": 81 | version "0.25.8" 82 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz#ccd9e291c24cd8d9142d819d463e2e7200d25b19" 83 | integrity sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg== 84 | 85 | "@esbuild/linux-ia32@0.25.8": 86 | version "0.25.8" 87 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz#006ad1536d0c2b28fb3a1cf0b53bcb85aaf92c4d" 88 | integrity sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg== 89 | 90 | "@esbuild/linux-loong64@0.25.8": 91 | version "0.25.8" 92 | resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz#127b3fbfb2c2e08b1397e985932f718f09a8f5c4" 93 | integrity sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ== 94 | 95 | "@esbuild/linux-mips64el@0.25.8": 96 | version "0.25.8" 97 | resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz#837d1449517791e3fa7d82675a2d06d9f56cb340" 98 | integrity sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw== 99 | 100 | "@esbuild/linux-ppc64@0.25.8": 101 | version "0.25.8" 102 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz#aa2e3bd93ab8df084212f1895ca4b03c42d9e0fe" 103 | integrity sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ== 104 | 105 | "@esbuild/linux-riscv64@0.25.8": 106 | version "0.25.8" 107 | resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz#a340620e31093fef72767dd28ab04214b3442083" 108 | integrity sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg== 109 | 110 | "@esbuild/linux-s390x@0.25.8": 111 | version "0.25.8" 112 | resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz#ddfed266c8c13f5efb3105a0cd47f6dcd0e79e71" 113 | integrity sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg== 114 | 115 | "@esbuild/linux-x64@0.25.8": 116 | version "0.25.8" 117 | resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz#9a4f78c75c051e8c060183ebb39a269ba936a2ac" 118 | integrity sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ== 119 | 120 | "@esbuild/netbsd-arm64@0.25.8": 121 | version "0.25.8" 122 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz#902c80e1d678047926387230bc037e63e00697d0" 123 | integrity sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw== 124 | 125 | "@esbuild/netbsd-x64@0.25.8": 126 | version "0.25.8" 127 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz#2d9eb4692add2681ff05a14ce99de54fbed7079c" 128 | integrity sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg== 129 | 130 | "@esbuild/openbsd-arm64@0.25.8": 131 | version "0.25.8" 132 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz#89c3b998c6de739db38ab7fb71a8a76b3fa84a45" 133 | integrity sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ== 134 | 135 | "@esbuild/openbsd-x64@0.25.8": 136 | version "0.25.8" 137 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz#2f01615cf472b0e48c077045cfd96b5c149365cc" 138 | integrity sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ== 139 | 140 | "@esbuild/openharmony-arm64@0.25.8": 141 | version "0.25.8" 142 | resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz#a201f720cd2c3ebf9a6033fcc3feb069a54b509a" 143 | integrity sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg== 144 | 145 | "@esbuild/sunos-x64@0.25.8": 146 | version "0.25.8" 147 | resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz#07046c977985a3334667f19e6ab3a01a80862afb" 148 | integrity sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w== 149 | 150 | "@esbuild/win32-arm64@0.25.8": 151 | version "0.25.8" 152 | resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz#4a5470caf0d16127c05d4833d4934213c69392d1" 153 | integrity sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ== 154 | 155 | "@esbuild/win32-ia32@0.25.8": 156 | version "0.25.8" 157 | resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz#3de3e8470b7b328d99dbc3e9ec1eace207e5bbc4" 158 | integrity sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg== 159 | 160 | "@esbuild/win32-x64@0.25.8": 161 | version "0.25.8" 162 | resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz#610d7ea539d2fcdbe39237b5cc175eb2c4451f9c" 163 | integrity sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw== 164 | 165 | "@hotwired/turbo-rails@^8.0.0": 166 | version "8.0.16" 167 | resolved "https://registry.yarnpkg.com/@hotwired/turbo-rails/-/turbo-rails-8.0.16.tgz#096f3bec8c3c04d4aac4dd0f75305c67b3db3501" 168 | integrity sha512-Yxiy2x+N3eOIEDokvLzSrd08aI5RDKnFYDQFl2J/LuMEWTtPdY7oNP0F/gv/sSe5AV23Lwz4FitG/uNFXNM5tA== 169 | dependencies: 170 | "@hotwired/turbo" "^8.0.13" 171 | "@rails/actioncable" ">=7.0" 172 | 173 | "@hotwired/turbo@^8.0.13": 174 | version "8.0.13" 175 | resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-8.0.13.tgz#ab35fda9d358432c8a872a833844b38cccb8c25b" 176 | integrity sha512-M7qXUqcGab6G5PKOiwhgbByTtrPgKPFCTMNQ52QhzUEXEqmp0/ApEguUesh/FPiUjrmFec+3lq98KsWnYY2C7g== 177 | 178 | "@isaacs/fs-minipass@^4.0.0": 179 | version "4.0.1" 180 | resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" 181 | integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== 182 | dependencies: 183 | minipass "^7.0.4" 184 | 185 | "@jridgewell/gen-mapping@^0.3.5": 186 | version "0.3.12" 187 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz#2234ce26c62889f03db3d7fea43c1932ab3e927b" 188 | integrity sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg== 189 | dependencies: 190 | "@jridgewell/sourcemap-codec" "^1.5.0" 191 | "@jridgewell/trace-mapping" "^0.3.24" 192 | 193 | "@jridgewell/resolve-uri@^3.1.0": 194 | version "3.1.2" 195 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" 196 | integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== 197 | 198 | "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": 199 | version "1.5.4" 200 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz#7358043433b2e5da569aa02cbc4c121da3af27d7" 201 | integrity sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw== 202 | 203 | "@jridgewell/trace-mapping@^0.3.24": 204 | version "0.3.29" 205 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz#a58d31eaadaf92c6695680b2e1d464a9b8fbf7fc" 206 | integrity sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ== 207 | dependencies: 208 | "@jridgewell/resolve-uri" "^3.1.0" 209 | "@jridgewell/sourcemap-codec" "^1.4.14" 210 | 211 | "@napi-rs/wasm-runtime@^0.2.11": 212 | version "0.2.12" 213 | resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" 214 | integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== 215 | dependencies: 216 | "@emnapi/core" "^1.4.3" 217 | "@emnapi/runtime" "^1.4.3" 218 | "@tybys/wasm-util" "^0.10.0" 219 | 220 | "@parcel/watcher-android-arm64@2.5.1": 221 | version "2.5.1" 222 | resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz#507f836d7e2042f798c7d07ad19c3546f9848ac1" 223 | integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA== 224 | 225 | "@parcel/watcher-darwin-arm64@2.5.1": 226 | version "2.5.1" 227 | resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz#3d26dce38de6590ef79c47ec2c55793c06ad4f67" 228 | integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw== 229 | 230 | "@parcel/watcher-darwin-x64@2.5.1": 231 | version "2.5.1" 232 | resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz#99f3af3869069ccf774e4ddfccf7e64fd2311ef8" 233 | integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg== 234 | 235 | "@parcel/watcher-freebsd-x64@2.5.1": 236 | version "2.5.1" 237 | resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz#14d6857741a9f51dfe51d5b08b7c8afdbc73ad9b" 238 | integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ== 239 | 240 | "@parcel/watcher-linux-arm-glibc@2.5.1": 241 | version "2.5.1" 242 | resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz#43c3246d6892381db473bb4f663229ad20b609a1" 243 | integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA== 244 | 245 | "@parcel/watcher-linux-arm-musl@2.5.1": 246 | version "2.5.1" 247 | resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz#663750f7090bb6278d2210de643eb8a3f780d08e" 248 | integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q== 249 | 250 | "@parcel/watcher-linux-arm64-glibc@2.5.1": 251 | version "2.5.1" 252 | resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz#ba60e1f56977f7e47cd7e31ad65d15fdcbd07e30" 253 | integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w== 254 | 255 | "@parcel/watcher-linux-arm64-musl@2.5.1": 256 | version "2.5.1" 257 | resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz#f7fbcdff2f04c526f96eac01f97419a6a99855d2" 258 | integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg== 259 | 260 | "@parcel/watcher-linux-x64-glibc@2.5.1": 261 | version "2.5.1" 262 | resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz#4d2ea0f633eb1917d83d483392ce6181b6a92e4e" 263 | integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A== 264 | 265 | "@parcel/watcher-linux-x64-musl@2.5.1": 266 | version "2.5.1" 267 | resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz#277b346b05db54f55657301dd77bdf99d63606ee" 268 | integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg== 269 | 270 | "@parcel/watcher-win32-arm64@2.5.1": 271 | version "2.5.1" 272 | resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz#7e9e02a26784d47503de1d10e8eab6cceb524243" 273 | integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw== 274 | 275 | "@parcel/watcher-win32-ia32@2.5.1": 276 | version "2.5.1" 277 | resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz#2d0f94fa59a873cdc584bf7f6b1dc628ddf976e6" 278 | integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ== 279 | 280 | "@parcel/watcher-win32-x64@2.5.1": 281 | version "2.5.1" 282 | resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz#ae52693259664ba6f2228fa61d7ee44b64ea0947" 283 | integrity sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA== 284 | 285 | "@parcel/watcher@^2.5.1": 286 | version "2.5.1" 287 | resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.1.tgz#342507a9cfaaf172479a882309def1e991fb1200" 288 | integrity sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg== 289 | dependencies: 290 | detect-libc "^1.0.3" 291 | is-glob "^4.0.3" 292 | micromatch "^4.0.5" 293 | node-addon-api "^7.0.0" 294 | optionalDependencies: 295 | "@parcel/watcher-android-arm64" "2.5.1" 296 | "@parcel/watcher-darwin-arm64" "2.5.1" 297 | "@parcel/watcher-darwin-x64" "2.5.1" 298 | "@parcel/watcher-freebsd-x64" "2.5.1" 299 | "@parcel/watcher-linux-arm-glibc" "2.5.1" 300 | "@parcel/watcher-linux-arm-musl" "2.5.1" 301 | "@parcel/watcher-linux-arm64-glibc" "2.5.1" 302 | "@parcel/watcher-linux-arm64-musl" "2.5.1" 303 | "@parcel/watcher-linux-x64-glibc" "2.5.1" 304 | "@parcel/watcher-linux-x64-musl" "2.5.1" 305 | "@parcel/watcher-win32-arm64" "2.5.1" 306 | "@parcel/watcher-win32-ia32" "2.5.1" 307 | "@parcel/watcher-win32-x64" "2.5.1" 308 | 309 | "@popperjs/core@^2.9.0": 310 | version "2.11.8" 311 | resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" 312 | integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== 313 | 314 | "@rails/actioncable@>=7.0": 315 | version "8.0.200" 316 | resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-8.0.200.tgz#1d27d9d55e45266e061190db045925e0b4d53d6b" 317 | integrity sha512-EDqWyxck22BHmv1e+mD8Kl6GmtNkhEPdRfGFT7kvsv1yoXd9iYrqHDVAaR8bKmU/syC5eEZ2I5aWWxtB73ukMw== 318 | 319 | "@rails/actiontext@^8.0.0": 320 | version "8.0.200" 321 | resolved "https://registry.yarnpkg.com/@rails/actiontext/-/actiontext-8.0.200.tgz#b0ed8ba50ec31dd8fcc7a8885403c58b2b4f378d" 322 | integrity sha512-p9SVulDmWKMChQpNYFrRBGa2aIfMSw8vyCRW9bwHzihFB8eAZ1NE6ak88nr037gwurbCBv4UVdnwndtuh2piAA== 323 | dependencies: 324 | "@rails/activestorage" ">= 8.0.0-alpha" 325 | 326 | "@rails/activestorage@>= 8.0.0-alpha": 327 | version "8.0.200" 328 | resolved "https://registry.yarnpkg.com/@rails/activestorage/-/activestorage-8.0.200.tgz#147c088e2b4167d6d49292431bdbdf10b118d5bd" 329 | integrity sha512-V7GnZXsAMPDWVOBv4/XpHwj5sOw5bWjidWCuUbK3Zx1xt2pOfFaeJDUG7fEWb1MwP4aW1oVVlGkJBdXVyvru0A== 330 | dependencies: 331 | spark-md5 "^3.0.1" 332 | 333 | "@tailwindcss/cli@^4.1.11": 334 | version "4.1.11" 335 | resolved "https://registry.yarnpkg.com/@tailwindcss/cli/-/cli-4.1.11.tgz#edeb8c241815188beb823460f9008c197d097ff0" 336 | integrity sha512-7RAFOrVaXCFz5ooEG36Kbh+sMJiI2j4+Ozp71smgjnLfBRu7DTfoq8DsTvzse2/6nDeo2M3vS/FGaxfDgr3rtQ== 337 | dependencies: 338 | "@parcel/watcher" "^2.5.1" 339 | "@tailwindcss/node" "4.1.11" 340 | "@tailwindcss/oxide" "4.1.11" 341 | enhanced-resolve "^5.18.1" 342 | mri "^1.2.0" 343 | picocolors "^1.1.1" 344 | tailwindcss "4.1.11" 345 | 346 | "@tailwindcss/forms@^0.5.9": 347 | version "0.5.10" 348 | resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.10.tgz#0a1cd67b6933402f1985a04595bd24f9785aa302" 349 | integrity sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw== 350 | dependencies: 351 | mini-svg-data-uri "^1.2.3" 352 | 353 | "@tailwindcss/node@4.1.11": 354 | version "4.1.11" 355 | resolved "https://registry.yarnpkg.com/@tailwindcss/node/-/node-4.1.11.tgz#d626af65fc9872e5e9d8884791d7e3856e945359" 356 | integrity sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q== 357 | dependencies: 358 | "@ampproject/remapping" "^2.3.0" 359 | enhanced-resolve "^5.18.1" 360 | jiti "^2.4.2" 361 | lightningcss "1.30.1" 362 | magic-string "^0.30.17" 363 | source-map-js "^1.2.1" 364 | tailwindcss "4.1.11" 365 | 366 | "@tailwindcss/oxide-android-arm64@4.1.11": 367 | version "4.1.11" 368 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.11.tgz#1f387d8302f011b61c226deb0c3a1d2bd79c6915" 369 | integrity sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg== 370 | 371 | "@tailwindcss/oxide-darwin-arm64@4.1.11": 372 | version "4.1.11" 373 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.11.tgz#acd35ffb7e4eae83d0a3fe2f8ea36cfcc9b21f7e" 374 | integrity sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ== 375 | 376 | "@tailwindcss/oxide-darwin-x64@4.1.11": 377 | version "4.1.11" 378 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.11.tgz#a0022312993a3893d6ff0312d6e3c83c4636fef4" 379 | integrity sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw== 380 | 381 | "@tailwindcss/oxide-freebsd-x64@4.1.11": 382 | version "4.1.11" 383 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.11.tgz#dd8e55eb0b88fe7995b8148c0e0ae5fa27092d22" 384 | integrity sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA== 385 | 386 | "@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11": 387 | version "4.1.11" 388 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.11.tgz#02ee99090988847d3f13d277679012cbffcdde37" 389 | integrity sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg== 390 | 391 | "@tailwindcss/oxide-linux-arm64-gnu@4.1.11": 392 | version "4.1.11" 393 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.11.tgz#4837559c102bebe65089879f6a0278ed473b4813" 394 | integrity sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ== 395 | 396 | "@tailwindcss/oxide-linux-arm64-musl@4.1.11": 397 | version "4.1.11" 398 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.11.tgz#bec465112a13a1383558ff36afdf28b8a8cb9021" 399 | integrity sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ== 400 | 401 | "@tailwindcss/oxide-linux-x64-gnu@4.1.11": 402 | version "4.1.11" 403 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.11.tgz#f9e47e6aa67ff77f32f7412bc9698d4278e101bf" 404 | integrity sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg== 405 | 406 | "@tailwindcss/oxide-linux-x64-musl@4.1.11": 407 | version "4.1.11" 408 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.11.tgz#7d6e8adcfb9bc84d8e2e2e8781d661edb9e41ba8" 409 | integrity sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q== 410 | 411 | "@tailwindcss/oxide-wasm32-wasi@4.1.11": 412 | version "4.1.11" 413 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.11.tgz#a1762f4939c6ebaa824696fda2fd7db1b85fbed2" 414 | integrity sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g== 415 | dependencies: 416 | "@emnapi/core" "^1.4.3" 417 | "@emnapi/runtime" "^1.4.3" 418 | "@emnapi/wasi-threads" "^1.0.2" 419 | "@napi-rs/wasm-runtime" "^0.2.11" 420 | "@tybys/wasm-util" "^0.9.0" 421 | tslib "^2.8.0" 422 | 423 | "@tailwindcss/oxide-win32-arm64-msvc@4.1.11": 424 | version "4.1.11" 425 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz#70ba392dca0fa3707ebe27d2bd6ac3e69d35e3b7" 426 | integrity sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w== 427 | 428 | "@tailwindcss/oxide-win32-x64-msvc@4.1.11": 429 | version "4.1.11" 430 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.11.tgz#cdcb9eea9225a346c0695f67f621990b0534763f" 431 | integrity sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg== 432 | 433 | "@tailwindcss/oxide@4.1.11": 434 | version "4.1.11" 435 | resolved "https://registry.yarnpkg.com/@tailwindcss/oxide/-/oxide-4.1.11.tgz#569b668c99c337b7b8204bc5b6a833429755a05b" 436 | integrity sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg== 437 | dependencies: 438 | detect-libc "^2.0.4" 439 | tar "^7.4.3" 440 | optionalDependencies: 441 | "@tailwindcss/oxide-android-arm64" "4.1.11" 442 | "@tailwindcss/oxide-darwin-arm64" "4.1.11" 443 | "@tailwindcss/oxide-darwin-x64" "4.1.11" 444 | "@tailwindcss/oxide-freebsd-x64" "4.1.11" 445 | "@tailwindcss/oxide-linux-arm-gnueabihf" "4.1.11" 446 | "@tailwindcss/oxide-linux-arm64-gnu" "4.1.11" 447 | "@tailwindcss/oxide-linux-arm64-musl" "4.1.11" 448 | "@tailwindcss/oxide-linux-x64-gnu" "4.1.11" 449 | "@tailwindcss/oxide-linux-x64-musl" "4.1.11" 450 | "@tailwindcss/oxide-wasm32-wasi" "4.1.11" 451 | "@tailwindcss/oxide-win32-arm64-msvc" "4.1.11" 452 | "@tailwindcss/oxide-win32-x64-msvc" "4.1.11" 453 | 454 | "@tybys/wasm-util@^0.10.0": 455 | version "0.10.0" 456 | resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.0.tgz#2fd3cd754b94b378734ce17058d0507c45c88369" 457 | integrity sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ== 458 | dependencies: 459 | tslib "^2.4.0" 460 | 461 | "@tybys/wasm-util@^0.9.0": 462 | version "0.9.0" 463 | resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.9.0.tgz#3e75eb00604c8d6db470bf18c37b7d984a0e3355" 464 | integrity sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw== 465 | dependencies: 466 | tslib "^2.4.0" 467 | 468 | "@types/trusted-types@^2.0.7": 469 | version "2.0.7" 470 | resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" 471 | integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== 472 | 473 | braces@^3.0.3: 474 | version "3.0.3" 475 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" 476 | integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== 477 | dependencies: 478 | fill-range "^7.1.1" 479 | 480 | chownr@^3.0.0: 481 | version "3.0.0" 482 | resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" 483 | integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== 484 | 485 | detect-libc@^1.0.3: 486 | version "1.0.3" 487 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 488 | integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== 489 | 490 | detect-libc@^2.0.3, detect-libc@^2.0.4: 491 | version "2.0.4" 492 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" 493 | integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== 494 | 495 | dompurify@^3.2.5, dompurify@^3.2.6: 496 | version "3.2.6" 497 | resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.2.6.tgz#ca040a6ad2b88e2a92dc45f38c79f84a714a1cad" 498 | integrity sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ== 499 | optionalDependencies: 500 | "@types/trusted-types" "^2.0.7" 501 | 502 | enhanced-resolve@^5.18.1: 503 | version "5.18.2" 504 | resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz#7903c5b32ffd4b2143eeb4b92472bd68effd5464" 505 | integrity sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ== 506 | dependencies: 507 | graceful-fs "^4.2.4" 508 | tapable "^2.2.0" 509 | 510 | esbuild@^0.25.0: 511 | version "0.25.8" 512 | resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.8.tgz#482d42198b427c9c2f3a81b63d7663aecb1dda07" 513 | integrity sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q== 514 | optionalDependencies: 515 | "@esbuild/aix-ppc64" "0.25.8" 516 | "@esbuild/android-arm" "0.25.8" 517 | "@esbuild/android-arm64" "0.25.8" 518 | "@esbuild/android-x64" "0.25.8" 519 | "@esbuild/darwin-arm64" "0.25.8" 520 | "@esbuild/darwin-x64" "0.25.8" 521 | "@esbuild/freebsd-arm64" "0.25.8" 522 | "@esbuild/freebsd-x64" "0.25.8" 523 | "@esbuild/linux-arm" "0.25.8" 524 | "@esbuild/linux-arm64" "0.25.8" 525 | "@esbuild/linux-ia32" "0.25.8" 526 | "@esbuild/linux-loong64" "0.25.8" 527 | "@esbuild/linux-mips64el" "0.25.8" 528 | "@esbuild/linux-ppc64" "0.25.8" 529 | "@esbuild/linux-riscv64" "0.25.8" 530 | "@esbuild/linux-s390x" "0.25.8" 531 | "@esbuild/linux-x64" "0.25.8" 532 | "@esbuild/netbsd-arm64" "0.25.8" 533 | "@esbuild/netbsd-x64" "0.25.8" 534 | "@esbuild/openbsd-arm64" "0.25.8" 535 | "@esbuild/openbsd-x64" "0.25.8" 536 | "@esbuild/openharmony-arm64" "0.25.8" 537 | "@esbuild/sunos-x64" "0.25.8" 538 | "@esbuild/win32-arm64" "0.25.8" 539 | "@esbuild/win32-ia32" "0.25.8" 540 | "@esbuild/win32-x64" "0.25.8" 541 | 542 | fill-range@^7.1.1: 543 | version "7.1.1" 544 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" 545 | integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== 546 | dependencies: 547 | to-regex-range "^5.0.1" 548 | 549 | graceful-fs@^4.2.4: 550 | version "4.2.11" 551 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" 552 | integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== 553 | 554 | is-extglob@^2.1.1: 555 | version "2.1.1" 556 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 557 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 558 | 559 | is-glob@^4.0.3: 560 | version "4.0.3" 561 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 562 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 563 | dependencies: 564 | is-extglob "^2.1.1" 565 | 566 | is-number@^7.0.0: 567 | version "7.0.0" 568 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 569 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 570 | 571 | jiti@^2.4.2: 572 | version "2.5.1" 573 | resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.5.1.tgz#bd099c1c2be1c59bbea4e5adcd127363446759d0" 574 | integrity sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w== 575 | 576 | lightningcss-darwin-arm64@1.30.1: 577 | version "1.30.1" 578 | resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz#3d47ce5e221b9567c703950edf2529ca4a3700ae" 579 | integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ== 580 | 581 | lightningcss-darwin-x64@1.30.1: 582 | version "1.30.1" 583 | resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz#e81105d3fd6330860c15fe860f64d39cff5fbd22" 584 | integrity sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA== 585 | 586 | lightningcss-freebsd-x64@1.30.1: 587 | version "1.30.1" 588 | resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz#a0e732031083ff9d625c5db021d09eb085af8be4" 589 | integrity sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig== 590 | 591 | lightningcss-linux-arm-gnueabihf@1.30.1: 592 | version "1.30.1" 593 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz#1f5ecca6095528ddb649f9304ba2560c72474908" 594 | integrity sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q== 595 | 596 | lightningcss-linux-arm64-gnu@1.30.1: 597 | version "1.30.1" 598 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz#eee7799726103bffff1e88993df726f6911ec009" 599 | integrity sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw== 600 | 601 | lightningcss-linux-arm64-musl@1.30.1: 602 | version "1.30.1" 603 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz#f2e4b53f42892feeef8f620cbb889f7c064a7dfe" 604 | integrity sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ== 605 | 606 | lightningcss-linux-x64-gnu@1.30.1: 607 | version "1.30.1" 608 | resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz#2fc7096224bc000ebb97eea94aea248c5b0eb157" 609 | integrity sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw== 610 | 611 | lightningcss-linux-x64-musl@1.30.1: 612 | version "1.30.1" 613 | resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz#66dca2b159fd819ea832c44895d07e5b31d75f26" 614 | integrity sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ== 615 | 616 | lightningcss-win32-arm64-msvc@1.30.1: 617 | version "1.30.1" 618 | resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz#7d8110a19d7c2d22bfdf2f2bb8be68e7d1b69039" 619 | integrity sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA== 620 | 621 | lightningcss-win32-x64-msvc@1.30.1: 622 | version "1.30.1" 623 | resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz#fd7dd008ea98494b85d24b4bea016793f2e0e352" 624 | integrity sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg== 625 | 626 | lightningcss@1.30.1: 627 | version "1.30.1" 628 | resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.30.1.tgz#78e979c2d595bfcb90d2a8c0eb632fe6c5bfed5d" 629 | integrity sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg== 630 | dependencies: 631 | detect-libc "^2.0.3" 632 | optionalDependencies: 633 | lightningcss-darwin-arm64 "1.30.1" 634 | lightningcss-darwin-x64 "1.30.1" 635 | lightningcss-freebsd-x64 "1.30.1" 636 | lightningcss-linux-arm-gnueabihf "1.30.1" 637 | lightningcss-linux-arm64-gnu "1.30.1" 638 | lightningcss-linux-arm64-musl "1.30.1" 639 | lightningcss-linux-x64-gnu "1.30.1" 640 | lightningcss-linux-x64-musl "1.30.1" 641 | lightningcss-win32-arm64-msvc "1.30.1" 642 | lightningcss-win32-x64-msvc "1.30.1" 643 | 644 | magic-string@^0.30.17: 645 | version "0.30.17" 646 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" 647 | integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== 648 | dependencies: 649 | "@jridgewell/sourcemap-codec" "^1.5.0" 650 | 651 | micromatch@^4.0.5: 652 | version "4.0.8" 653 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" 654 | integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== 655 | dependencies: 656 | braces "^3.0.3" 657 | picomatch "^2.3.1" 658 | 659 | micromodal@^0.6.1: 660 | version "0.6.1" 661 | resolved "https://registry.yarnpkg.com/micromodal/-/micromodal-0.6.1.tgz#2558c1802317a53e89f7913652a1eb8b91454738" 662 | integrity sha512-rw1fOptxQe3XGDm9xil9hBC2ylPb1kKZyYv4FlK54R/7L+KG+D8SQxPL5L8OlEXAhBDHckeoULYxWSYU9rg/RA== 663 | 664 | mini-svg-data-uri@^1.2.3: 665 | version "1.4.4" 666 | resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" 667 | integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== 668 | 669 | minipass@^7.0.4, minipass@^7.1.2: 670 | version "7.1.2" 671 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" 672 | integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== 673 | 674 | minizlib@^3.0.1: 675 | version "3.0.2" 676 | resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.2.tgz#f33d638eb279f664439aa38dc5f91607468cb574" 677 | integrity sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA== 678 | dependencies: 679 | minipass "^7.1.2" 680 | 681 | mkdirp@^3.0.1: 682 | version "3.0.1" 683 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" 684 | integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== 685 | 686 | mri@^1.2.0: 687 | version "1.2.0" 688 | resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" 689 | integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== 690 | 691 | node-addon-api@^7.0.0: 692 | version "7.1.1" 693 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" 694 | integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== 695 | 696 | picocolors@^1.1.1: 697 | version "1.1.1" 698 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" 699 | integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== 700 | 701 | picomatch@^2.3.1: 702 | version "2.3.1" 703 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 704 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 705 | 706 | ralix@^1.8.0: 707 | version "1.8.0" 708 | resolved "https://registry.yarnpkg.com/ralix/-/ralix-1.8.0.tgz#724555d8ae42cc6c2e69aa80449b4ac5715a82e6" 709 | integrity sha512-G+jaGI6YrSugylQGPK7EL5S9mHpJ4wyHiJUv+uszIBlYDKbwauJbn5Pgtu/pBZYmTuMcFEB4C7jlq4jXLYjenQ== 710 | dependencies: 711 | dompurify "^3.2.6" 712 | 713 | source-map-js@^1.2.1: 714 | version "1.2.1" 715 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" 716 | integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== 717 | 718 | spark-md5@^3.0.1: 719 | version "3.0.2" 720 | resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc" 721 | integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== 722 | 723 | tailwindcss@4.1.11, tailwindcss@^4.1.11: 724 | version "4.1.11" 725 | resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-4.1.11.tgz#799af3e98c19c5baaefafc6e0c16304a0e684854" 726 | integrity sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA== 727 | 728 | tapable@^2.2.0: 729 | version "2.2.2" 730 | resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.2.tgz#ab4984340d30cb9989a490032f086dbb8b56d872" 731 | integrity sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg== 732 | 733 | tar@^7.4.3: 734 | version "7.4.3" 735 | resolved "https://registry.yarnpkg.com/tar/-/tar-7.4.3.tgz#88bbe9286a3fcd900e94592cda7a22b192e80571" 736 | integrity sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== 737 | dependencies: 738 | "@isaacs/fs-minipass" "^4.0.0" 739 | chownr "^3.0.0" 740 | minipass "^7.1.2" 741 | minizlib "^3.0.1" 742 | mkdirp "^3.0.1" 743 | yallist "^5.0.0" 744 | 745 | tippy.js@^6.3.7: 746 | version "6.3.7" 747 | resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c" 748 | integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ== 749 | dependencies: 750 | "@popperjs/core" "^2.9.0" 751 | 752 | to-regex-range@^5.0.1: 753 | version "5.0.1" 754 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 755 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 756 | dependencies: 757 | is-number "^7.0.0" 758 | 759 | trix@^2.1.15: 760 | version "2.1.15" 761 | resolved "https://registry.yarnpkg.com/trix/-/trix-2.1.15.tgz#fabad796ea779a8ae96522402fbc214cbfc4015f" 762 | integrity sha512-LoaXWczdTUV8+3Box92B9b1iaDVbxD14dYemZRxi3PwY+AuDm97BUJV2aHLBUFPuDABhxp0wzcbf0CxHCVmXiw== 763 | dependencies: 764 | dompurify "^3.2.5" 765 | 766 | tslib@^2.4.0, tslib@^2.8.0: 767 | version "2.8.1" 768 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" 769 | integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== 770 | 771 | yallist@^5.0.0: 772 | version "5.0.0" 773 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" 774 | integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== 775 | --------------------------------------------------------------------------------