├── .env.example ├── .gitignore ├── .ruby-version ├── Gemfile ├── Gemfile.lock ├── Procfile.dev ├── README.md ├── Rakefile ├── app ├── assets │ ├── builds │ │ └── .keep │ ├── images │ │ └── icons │ │ │ ├── facebook.svg │ │ │ ├── github.svg │ │ │ └── google.svg │ └── stylesheets │ │ ├── application.css │ │ └── components │ │ ├── base.css │ │ ├── buttons.css │ │ ├── cards.css │ │ ├── forms.css │ │ ├── modals.css │ │ ├── overrides.css │ │ ├── pagination.css │ │ └── tables.css ├── controllers │ ├── application_controller.rb │ ├── articles_controller.rb │ ├── errors_controller.rb │ ├── home_controller.rb │ ├── pages_controller.rb │ ├── users │ │ └── omniauth_callbacks_controller.rb │ └── users_controller.rb ├── helpers │ ├── application_helper.rb │ ├── articles_helper.rb │ └── users_helper.rb ├── javascript │ ├── application.js │ ├── components │ │ ├── remote_modal.js │ │ └── tooltip.js │ └── controllers │ │ ├── app.js │ │ └── articles.js ├── mailers │ └── application_mailer.rb ├── models │ ├── ability.rb │ ├── application_record.rb │ ├── article.rb │ └── user.rb └── views │ ├── application │ ├── _error_messages.html.erb │ ├── _flash_messages.html.erb │ ├── _footer.html.erb │ ├── _header.html.erb │ └── _remote_modal.html.erb │ ├── articles │ ├── _form.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── devise │ ├── passwords │ │ ├── edit.html.erb │ │ └── new.html.erb │ ├── registrations │ │ └── new.html.erb │ ├── sessions │ │ └── new.html.erb │ └── shared │ │ ├── _links.html.erb │ │ └── _social_signin.html.erb │ ├── errors │ ├── _error_page.html.erb │ ├── internal_server_error.html.erb │ └── not_found.html.erb │ ├── home │ └── index.html.erb │ ├── layouts │ ├── application.html.erb │ ├── mailer.html.erb │ └── mailer.text.erb │ ├── pages │ ├── about.html.erb │ ├── privacy_policy.html.erb │ └── terms.html.erb │ └── users │ ├── edit.html.erb │ ├── index.html.erb │ └── show.html.erb ├── bin ├── dev ├── rails ├── rake └── setup ├── config.ru ├── config ├── application.rb ├── boot.rb ├── credentials.yml.enc ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── action_text.rb │ ├── content_security_policy.rb │ ├── devise.rb │ ├── filter_parameter_logging.rb │ ├── heroicon.rb │ ├── inflections.rb │ └── permissions_policy.rb ├── locales │ └── en.yml ├── puma.rb ├── routes.rb └── storage.yml ├── db ├── migrate │ ├── 20220831194622_create_articles.rb │ ├── 20220831213127_devise_create_users.rb │ ├── 20220831235947_add_name_to_users.rb │ ├── 20221005175500_create_active_storage_tables.active_storage.rb │ └── 20230525120314_create_action_text_tables.action_text.rb ├── schema.rb └── seeds.rb ├── lib └── tasks │ └── .keep ├── log └── .keep ├── package.json ├── public ├── favicon.ico └── robots.txt ├── storage └── .keep ├── tailwind.config.js ├── tmp └── .keep └── yarn.lock /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.3.5 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | ruby File.read(".ruby-version").strip 4 | 5 | gem "rails", "~> 7.2" 6 | gem "pg", "~> 1.5" 7 | gem "puma", "~> 6.4" 8 | gem "bootsnap", "~> 1.18", require: false 9 | gem "devise", "~> 4.9" 10 | gem "omniauth-facebook", "~> 9.0" 11 | gem "omniauth-github", "~> 2.0" 12 | gem "omniauth-google-oauth2", "~> 1.1" 13 | gem "omniauth-rails_csrf_protection", "~> 1.0" 14 | gem "cancancan", "~> 3.4" 15 | gem "ransack", "~> 4.2" 16 | gem "pagy", "~> 9.0" 17 | gem "image_processing", "~> 1.2" 18 | gem "faker", "~> 3" 19 | 20 | # Front-end 21 | gem "propshaft", "~> 1.1" 22 | gem "jsbundling-rails", "~> 1.0" 23 | gem "cssbundling-rails", "~> 1.1" 24 | gem "turbo-rails", "~> 2.0" 25 | gem "heroicon", "~> 1.0" 26 | 27 | group :development do 28 | gem "web-console" 29 | gem "debug" 30 | gem "dotenv-rails" 31 | end 32 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (7.2.2.1) 5 | actionpack (= 7.2.2.1) 6 | activesupport (= 7.2.2.1) 7 | nio4r (~> 2.0) 8 | websocket-driver (>= 0.6.1) 9 | zeitwerk (~> 2.6) 10 | actionmailbox (7.2.2.1) 11 | actionpack (= 7.2.2.1) 12 | activejob (= 7.2.2.1) 13 | activerecord (= 7.2.2.1) 14 | activestorage (= 7.2.2.1) 15 | activesupport (= 7.2.2.1) 16 | mail (>= 2.8.0) 17 | actionmailer (7.2.2.1) 18 | actionpack (= 7.2.2.1) 19 | actionview (= 7.2.2.1) 20 | activejob (= 7.2.2.1) 21 | activesupport (= 7.2.2.1) 22 | mail (>= 2.8.0) 23 | rails-dom-testing (~> 2.2) 24 | actionpack (7.2.2.1) 25 | actionview (= 7.2.2.1) 26 | activesupport (= 7.2.2.1) 27 | nokogiri (>= 1.8.5) 28 | racc 29 | rack (>= 2.2.4, < 3.2) 30 | rack-session (>= 1.0.1) 31 | rack-test (>= 0.6.3) 32 | rails-dom-testing (~> 2.2) 33 | rails-html-sanitizer (~> 1.6) 34 | useragent (~> 0.16) 35 | actiontext (7.2.2.1) 36 | actionpack (= 7.2.2.1) 37 | activerecord (= 7.2.2.1) 38 | activestorage (= 7.2.2.1) 39 | activesupport (= 7.2.2.1) 40 | globalid (>= 0.6.0) 41 | nokogiri (>= 1.8.5) 42 | actionview (7.2.2.1) 43 | activesupport (= 7.2.2.1) 44 | builder (~> 3.1) 45 | erubi (~> 1.11) 46 | rails-dom-testing (~> 2.2) 47 | rails-html-sanitizer (~> 1.6) 48 | activejob (7.2.2.1) 49 | activesupport (= 7.2.2.1) 50 | globalid (>= 0.3.6) 51 | activemodel (7.2.2.1) 52 | activesupport (= 7.2.2.1) 53 | activerecord (7.2.2.1) 54 | activemodel (= 7.2.2.1) 55 | activesupport (= 7.2.2.1) 56 | timeout (>= 0.4.0) 57 | activestorage (7.2.2.1) 58 | actionpack (= 7.2.2.1) 59 | activejob (= 7.2.2.1) 60 | activerecord (= 7.2.2.1) 61 | activesupport (= 7.2.2.1) 62 | marcel (~> 1.0) 63 | activesupport (7.2.2.1) 64 | base64 65 | benchmark (>= 0.3) 66 | bigdecimal 67 | concurrent-ruby (~> 1.0, >= 1.3.1) 68 | connection_pool (>= 2.2.5) 69 | drb 70 | i18n (>= 1.6, < 2) 71 | logger (>= 1.4.2) 72 | minitest (>= 5.1) 73 | securerandom (>= 0.3) 74 | tzinfo (~> 2.0, >= 2.0.5) 75 | base64 (0.2.0) 76 | bcrypt (3.1.20) 77 | benchmark (0.4.0) 78 | bigdecimal (3.1.8) 79 | bindex (0.8.1) 80 | bootsnap (1.18.4) 81 | msgpack (~> 1.2) 82 | builder (3.3.0) 83 | cancancan (3.6.1) 84 | concurrent-ruby (1.3.4) 85 | connection_pool (2.4.1) 86 | crass (1.0.6) 87 | cssbundling-rails (1.4.1) 88 | railties (>= 6.0.0) 89 | date (3.4.1) 90 | debug (1.9.2) 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.4) 100 | dotenv-rails (3.1.4) 101 | dotenv (= 3.1.4) 102 | railties (>= 6.1) 103 | drb (2.2.1) 104 | erubi (1.13.0) 105 | faker (3.4.2) 106 | i18n (>= 1.8.11, < 2) 107 | faraday (2.12.0) 108 | faraday-net_http (>= 2.0, < 3.4) 109 | json 110 | logger 111 | faraday-net_http (3.3.0) 112 | net-http 113 | ffi (1.17.0-arm64-darwin) 114 | ffi (1.17.0-x86_64-darwin) 115 | ffi (1.17.0-x86_64-linux-gnu) 116 | globalid (1.2.1) 117 | activesupport (>= 6.1) 118 | hashie (5.0.0) 119 | heroicon (1.0.0) 120 | rails (>= 5.2) 121 | i18n (1.14.6) 122 | concurrent-ruby (~> 1.0) 123 | image_processing (1.13.0) 124 | mini_magick (>= 4.9.5, < 5) 125 | ruby-vips (>= 2.0.17, < 3) 126 | io-console (0.7.2) 127 | irb (1.14.1) 128 | rdoc (>= 4.0.0) 129 | reline (>= 0.4.2) 130 | jsbundling-rails (1.3.1) 131 | railties (>= 6.0.0) 132 | json (2.7.2) 133 | jwt (2.9.1) 134 | base64 135 | logger (1.6.2) 136 | loofah (2.23.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 (4.13.2) 146 | mini_mime (1.1.5) 147 | minitest (5.25.4) 148 | msgpack (1.7.2) 149 | multi_xml (0.7.1) 150 | bigdecimal (~> 3.1) 151 | net-http (0.4.1) 152 | uri 153 | net-imap (0.4.20) 154 | date 155 | net-protocol 156 | net-pop (0.1.2) 157 | net-protocol 158 | net-protocol (0.2.2) 159 | timeout 160 | net-smtp (0.5.0) 161 | net-protocol 162 | nio4r (2.7.3) 163 | nokogiri (1.18.8-arm64-darwin) 164 | racc (~> 1.4) 165 | nokogiri (1.18.8-x86_64-darwin) 166 | racc (~> 1.4) 167 | nokogiri (1.18.8-x86_64-linux-gnu) 168 | racc (~> 1.4) 169 | oauth2 (2.0.9) 170 | faraday (>= 0.17.3, < 3.0) 171 | jwt (>= 1.0, < 3.0) 172 | multi_xml (~> 0.5) 173 | rack (>= 1.2, < 4) 174 | snaky_hash (~> 2.0) 175 | version_gem (~> 1.1) 176 | omniauth (2.1.2) 177 | hashie (>= 3.4.6) 178 | rack (>= 2.2.3) 179 | rack-protection 180 | omniauth-facebook (9.0.0) 181 | omniauth-oauth2 (~> 1.2) 182 | omniauth-github (2.0.1) 183 | omniauth (~> 2.0) 184 | omniauth-oauth2 (~> 1.8) 185 | omniauth-google-oauth2 (1.2.0) 186 | jwt (>= 2.9) 187 | oauth2 (~> 2.0) 188 | omniauth (~> 2.0) 189 | omniauth-oauth2 (~> 1.8) 190 | omniauth-oauth2 (1.8.0) 191 | oauth2 (>= 1.4, < 3) 192 | omniauth (~> 2.0) 193 | omniauth-rails_csrf_protection (1.0.2) 194 | actionpack (>= 4.2) 195 | omniauth (~> 2.0) 196 | orm_adapter (0.5.0) 197 | pagy (9.0.9) 198 | pg (1.5.8) 199 | propshaft (1.1.0) 200 | actionpack (>= 7.0.0) 201 | activesupport (>= 7.0.0) 202 | rack 203 | railties (>= 7.0.0) 204 | psych (5.1.2) 205 | stringio 206 | puma (6.4.3) 207 | nio4r (~> 2.0) 208 | racc (1.8.1) 209 | rack (3.1.16) 210 | rack-protection (4.0.0) 211 | base64 (>= 0.1.0) 212 | rack (>= 3.0.0, < 4) 213 | rack-session (2.1.1) 214 | base64 (>= 0.1.0) 215 | rack (>= 3.0.0) 216 | rack-test (2.1.0) 217 | rack (>= 1.3) 218 | rackup (2.1.0) 219 | rack (>= 3) 220 | webrick (~> 1.8) 221 | rails (7.2.2.1) 222 | actioncable (= 7.2.2.1) 223 | actionmailbox (= 7.2.2.1) 224 | actionmailer (= 7.2.2.1) 225 | actionpack (= 7.2.2.1) 226 | actiontext (= 7.2.2.1) 227 | actionview (= 7.2.2.1) 228 | activejob (= 7.2.2.1) 229 | activemodel (= 7.2.2.1) 230 | activerecord (= 7.2.2.1) 231 | activestorage (= 7.2.2.1) 232 | activesupport (= 7.2.2.1) 233 | bundler (>= 1.15.0) 234 | railties (= 7.2.2.1) 235 | rails-dom-testing (2.2.0) 236 | activesupport (>= 5.0.0) 237 | minitest 238 | nokogiri (>= 1.6) 239 | rails-html-sanitizer (1.6.1) 240 | loofah (~> 2.21) 241 | 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) 242 | railties (7.2.2.1) 243 | actionpack (= 7.2.2.1) 244 | activesupport (= 7.2.2.1) 245 | irb (~> 1.13) 246 | rackup (>= 1.0.0) 247 | rake (>= 12.2) 248 | thor (~> 1.0, >= 1.2.2) 249 | zeitwerk (~> 2.6) 250 | rake (13.2.1) 251 | ransack (4.2.1) 252 | activerecord (>= 6.1.5) 253 | activesupport (>= 6.1.5) 254 | i18n 255 | rdoc (6.7.0) 256 | psych (>= 4.0.0) 257 | reline (0.5.10) 258 | io-console (~> 0.5) 259 | responders (3.1.1) 260 | actionpack (>= 5.2) 261 | railties (>= 5.2) 262 | ruby-vips (2.2.2) 263 | ffi (~> 1.12) 264 | logger 265 | securerandom (0.4.0) 266 | snaky_hash (2.0.1) 267 | hashie 268 | version_gem (~> 1.1, >= 1.1.1) 269 | stringio (3.1.1) 270 | thor (1.3.2) 271 | timeout (0.4.3) 272 | turbo-rails (2.0.10) 273 | actionpack (>= 6.0.0) 274 | railties (>= 6.0.0) 275 | tzinfo (2.0.6) 276 | concurrent-ruby (~> 1.0) 277 | uri (0.13.2) 278 | useragent (0.16.11) 279 | version_gem (1.1.4) 280 | warden (1.2.9) 281 | rack (>= 2.0.9) 282 | web-console (4.2.1) 283 | actionview (>= 6.0.0) 284 | activemodel (>= 6.0.0) 285 | bindex (>= 0.4.0) 286 | railties (>= 6.0.0) 287 | webrick (1.8.2) 288 | websocket-driver (0.7.6) 289 | websocket-extensions (>= 0.1.0) 290 | websocket-extensions (0.1.5) 291 | zeitwerk (2.6.18) 292 | 293 | PLATFORMS 294 | arm64-darwin-22 295 | x86_64-darwin-17 296 | x86_64-darwin-22 297 | x86_64-linux 298 | 299 | DEPENDENCIES 300 | bootsnap (~> 1.18) 301 | cancancan (~> 3.4) 302 | cssbundling-rails (~> 1.1) 303 | debug 304 | devise (~> 4.9) 305 | dotenv-rails 306 | faker (~> 3) 307 | heroicon (~> 1.0) 308 | image_processing (~> 1.2) 309 | jsbundling-rails (~> 1.0) 310 | omniauth-facebook (~> 9.0) 311 | omniauth-github (~> 2.0) 312 | omniauth-google-oauth2 (~> 1.1) 313 | omniauth-rails_csrf_protection (~> 1.0) 314 | pagy (~> 9.0) 315 | pg (~> 1.5) 316 | propshaft (~> 1.1) 317 | puma (~> 6.4) 318 | rails (~> 7.2) 319 | ransack (~> 4.2) 320 | turbo-rails (~> 2.0) 321 | web-console 322 | 323 | RUBY VERSION 324 | ruby 3.3.5p100 325 | 326 | BUNDLED WITH 327 | 2.5.20 328 | -------------------------------------------------------------------------------- /Procfile.dev: -------------------------------------------------------------------------------- 1 | web: bin/rails server -p 3000 2 | js: yarn build --watch 3 | css: yarn build:css --watch 4 | -------------------------------------------------------------------------------- /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 v7 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 | -------------------------------------------------------------------------------- /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/assets/builds/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ralixjs/rails-ralix-tailwind/f476049dd9c7ef07868148da8615cba4e463da09/app/assets/builds/.keep -------------------------------------------------------------------------------- /app/assets/images/icons/facebook.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/assets/images/icons/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/assets/images/icons/google.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* Dependencies */ 2 | @import 'tailwindcss/base'; 3 | @import 'tailwindcss/components'; 4 | @import 'tailwindcss/utilities'; 5 | @import 'tippy.js/dist/tippy.css'; 6 | @import "trix/dist/trix"; 7 | 8 | /* Components */ 9 | @import 'components/base.css'; 10 | @import 'components/modals.css'; 11 | @import 'components/tables.css'; 12 | @import 'components/buttons.css'; 13 | @import 'components/forms.css'; 14 | @import 'components/cards.css'; 15 | @import 'components/pagination.css'; 16 | @import 'components/overrides.css'; 17 | -------------------------------------------------------------------------------- /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-none; 23 | } 24 | 25 | img { 26 | display: inline-block; 27 | } 28 | 29 | ul { 30 | @apply list-disc; 31 | } 32 | 33 | ol { 34 | @apply list-decimal; 35 | } 36 | -------------------------------------------------------------------------------- /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 cursor-pointer outline-none; 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 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/cards.css: -------------------------------------------------------------------------------- 1 | .card { 2 | @apply rounded 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/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 focus:border-indigo-600 focus:ring focus:ring-indigo-300 focus:ring-opacity-50; 3 | } 4 | 5 | input[type="file"] { 6 | @apply text-slate-400 bg-white border border-gray-500 cursor-pointer focus:outline-none 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 focus:ring-indigo-300 focus:ring-opacity-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/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 | -------------------------------------------------------------------------------- /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 focus:ring-indigo-300 focus:ring-opacity-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 border-none; 42 | } 43 | -------------------------------------------------------------------------------- /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; 7 | } 8 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | def index 3 | end 4 | end 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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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 | }, 500) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: "from@example.com" 3 | layout "mailer" 4 | end 5 | -------------------------------------------------------------------------------- /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/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | primary_abstract_class 3 | end 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/application/_flash_messages.html.erb: -------------------------------------------------------------------------------- 1 | <% flash.each do |key, msg| %> 2 |
3 | <%= msg %> 4 | 5 |
6 | <% end %> 7 | -------------------------------------------------------------------------------- /app/views/application/_footer.html.erb: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /app/views/application/_header.html.erb: -------------------------------------------------------------------------------- 1 | 63 | -------------------------------------------------------------------------------- /app/views/application/_remote_modal.html.erb: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /app/views/articles/new.html.erb: -------------------------------------------------------------------------------- 1 |

New article

2 | 3 | <%= render "form", article: @article %> 4 | -------------------------------------------------------------------------------- /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/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/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/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/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/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 | -------------------------------------------------------------------------------- /app/views/devise/shared/_social_signin.html.erb: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /app/views/pages/about.html.erb: -------------------------------------------------------------------------------- 1 |

About us

2 | 3 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

4 | 5 |

Mission

6 | 7 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

8 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

9 | 10 |

Values

11 | 12 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

13 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

14 | 15 |

Team

16 | 17 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

18 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

19 | -------------------------------------------------------------------------------- /app/views/pages/privacy_policy.html.erb: -------------------------------------------------------------------------------- 1 |

Privacy policy

2 | 3 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

4 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

5 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

6 | -------------------------------------------------------------------------------- /app/views/pages/terms.html.erb: -------------------------------------------------------------------------------- 1 |

Terms

2 | 3 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

4 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

5 |

<%= Faker::Lorem.paragraphs(number: 5).join.html_safe %>

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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require_relative "../config/boot" 4 | require "rake" 5 | Rake.application.run 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 7.2 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/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 | -------------------------------------------------------------------------------- /config/credentials.yml.enc: -------------------------------------------------------------------------------- 1 | qDh808AJiyxRn4Npr9Ux3LXJX3DGlIRpG888RrT3kfsq1j6yJkWOQ3PgMixQeoR61VHMWe3fOl3cyUcx8DDekkqSu568qzCPt+uy2R2tEl6JH7xP9jdvSVdmmEuNvyrVbpxayQlxna+JOqVzISadIFw0L974ZC1fLas5bND8r3mFrfApJrHClikMzV6g8C+FVywB1b4m7z4oQqEcg2A72uBwM67eAPibjXH0kDYc3H5JE4hdtcuWMnGXrQ3nybuZsY4c0BKqv3bq/1sl3OF7rzP+LmeqKCjKwIA3En/u0cvAZa+ToAmFVv435F7+MZfmaKJ15TRKypDxVYGyD3H6aYTzkX6Nu9gn8i+0P0Q9vabQM92Q/dgsztKH+nPX3CdtcI02qwTGKCoVLHlV/+OHDIe1eD3usIgcdFaa--X1OKn58uyWHMGamI--i30CtrHvN2/lDeRlD0OYyQ== -------------------------------------------------------------------------------- /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/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /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 | # In the development environment your application's code is reloaded any time 7 | # it changes. This slows down response time but is perfect for development 8 | # since you don't have to restart the web server when you make code changes. 9 | config.enable_reloading = true 10 | 11 | # Do not eager load code on boot. 12 | config.eager_load = false 13 | 14 | # Show full error reports. 15 | config.consider_all_requests_local = true 16 | 17 | # Enable server timing. 18 | config.server_timing = true 19 | 20 | # Enable/disable caching. By default caching is disabled. 21 | # Run rails dev:cache to toggle caching. 22 | if Rails.root.join("tmp/caching-dev.txt").exist? 23 | config.action_controller.perform_caching = true 24 | config.action_controller.enable_fragment_cache_logging = true 25 | 26 | config.cache_store = :memory_store 27 | config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{2.days.to_i}" } 28 | else 29 | config.action_controller.perform_caching = false 30 | 31 | config.cache_store = :null_store 32 | end 33 | 34 | # Store uploaded files on the local file system (see config/storage.yml for options). 35 | config.active_storage.service = :local 36 | 37 | # Don't care if the mailer can't send. 38 | config.action_mailer.raise_delivery_errors = false 39 | 40 | # Disable caching for Action Mailer templates even if Action Controller 41 | # caching is enabled. 42 | config.action_mailer.perform_caching = false 43 | 44 | config.action_mailer.default_url_options = { host: "localhost", port: 3000 } 45 | 46 | # Print deprecation notices to the Rails logger. 47 | config.active_support.deprecation = :log 48 | 49 | # Raise exceptions for disallowed deprecations. 50 | config.active_support.disallowed_deprecation = :raise 51 | 52 | # Tell Active Support which deprecation messages to disallow. 53 | config.active_support.disallowed_deprecation_warnings = [] 54 | 55 | # Raise an error on page load if there are pending migrations. 56 | config.active_record.migration_error = :page_load 57 | 58 | # Highlight code that triggered database queries in logs. 59 | config.active_record.verbose_query_logs = true 60 | 61 | # Highlight code that enqueued background job in logs. 62 | config.active_job.verbose_enqueue_logs = true 63 | 64 | # Raises error for missing translations. 65 | # config.i18n.raise_on_missing_translations = true 66 | 67 | # Annotate rendered view with file names. 68 | config.action_view.annotate_rendered_view_with_filenames = true 69 | 70 | # Uncomment if you wish to allow Action Cable access from any origin. 71 | # config.action_cable.disable_request_forgery_protection = true 72 | 73 | # Raise error when a before_action's only/except options reference missing actions. 74 | config.action_controller.raise_on_missing_callback_actions = true 75 | end 76 | -------------------------------------------------------------------------------- /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. This eager loads most of Rails and 10 | # your application in memory, allowing both threaded web servers 11 | # and those relying on copy on write to perform better. 12 | # Rake tasks automatically ignore this option for performance. 13 | config.eager_load = true 14 | 15 | # Full error reports are disabled and caching is turned on. 16 | config.consider_all_requests_local = false 17 | config.action_controller.perform_caching = true 18 | 19 | # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment 20 | # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). 21 | # config.require_master_key = true 22 | 23 | # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. 24 | # config.public_file_server.enabled = false 25 | 26 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 27 | # config.asset_host = "http://assets.example.com" 28 | 29 | # Specifies the header that your server uses for sending files. 30 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache 31 | # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX 32 | 33 | # Store uploaded files on the local file system (see config/storage.yml for options). 34 | config.active_storage.service = :local 35 | 36 | # Mount Action Cable outside main process or domain. 37 | # config.action_cable.mount_path = nil 38 | # config.action_cable.url = "wss://example.com/cable" 39 | # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] 40 | 41 | # Assume all access to the app is happening through a SSL-terminating reverse proxy. 42 | # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. 43 | # config.assume_ssl = true 44 | 45 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 46 | config.force_ssl = true 47 | 48 | # Skip http-to-https redirect for the default health check endpoint. 49 | # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } 50 | 51 | # Log to STDOUT by default 52 | config.logger = ActiveSupport::Logger.new(STDOUT) 53 | .tap { |logger| logger.formatter = ::Logger::Formatter.new } 54 | .then { |logger| ActiveSupport::TaggedLogging.new(logger) } 55 | 56 | # Prepend all log lines with the following tags. 57 | config.log_tags = [ :request_id ] 58 | 59 | # "info" includes generic and useful information about system operation, but avoids logging too much 60 | # information to avoid inadvertent exposure of personally identifiable information (PII). If you 61 | # want to log everything, set the level to "debug". 62 | config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") 63 | 64 | # Use a different cache store in production. 65 | # config.cache_store = :mem_cache_store 66 | 67 | # Use a real queuing backend for Active Job (and separate queues per environment). 68 | # config.active_job.queue_adapter = :resque 69 | # config.active_job.queue_name_prefix = "rails_ralix_tailwind_production" 70 | 71 | # Disable caching for Action Mailer templates even if Action Controller 72 | # caching is enabled. 73 | config.action_mailer.perform_caching = false 74 | 75 | # Ignore bad email addresses and do not raise email delivery errors. 76 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 77 | # config.action_mailer.raise_delivery_errors = false 78 | 79 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 80 | # the I18n.default_locale when a translation cannot be found). 81 | config.i18n.fallbacks = true 82 | 83 | # Don't log any deprecations. 84 | config.active_support.report_deprecations = false 85 | 86 | # Do not dump schema after migrations. 87 | config.active_record.dump_schema_after_migration = false 88 | 89 | # Enable DNS rebinding protection and other `Host` header attacks. 90 | # config.hosts = [ 91 | # "example.com", # Allow requests from example.com 92 | # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` 93 | # ] 94 | # Skip DNS rebinding protection for the default health check endpoint. 95 | # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } 96 | end 97 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | # The test environment is used exclusively to run your application's 4 | # test suite. You never need to work with it otherwise. Remember that 5 | # your test database is "scratch space" for the test suite and is wiped 6 | # and recreated between test runs. Don't rely on the data there! 7 | 8 | Rails.application.configure do 9 | # Settings specified here will take precedence over those in config/application.rb. 10 | 11 | # While tests run files are not watched, reloading is not necessary. 12 | config.enable_reloading = false 13 | 14 | # Eager loading loads your entire application. When running a single test locally, 15 | # this is usually not necessary, and can slow down your test suite. However, it's 16 | # recommended that you enable it in continuous integration systems to ensure eager 17 | # loading is working properly before deploying your code. 18 | config.eager_load = ENV["CI"].present? 19 | 20 | # Configure public file server for tests with Cache-Control for performance. 21 | config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{1.hour.to_i}" } 22 | 23 | # Show full error reports and disable caching. 24 | config.consider_all_requests_local = true 25 | config.action_controller.perform_caching = false 26 | config.cache_store = :null_store 27 | 28 | # Render exception templates for rescuable exceptions and raise for other exceptions. 29 | config.action_dispatch.show_exceptions = :rescuable 30 | 31 | # Disable request forgery protection in test environment. 32 | config.action_controller.allow_forgery_protection = false 33 | 34 | # Store uploaded files on the local file system in a temporary directory. 35 | config.active_storage.service = :test 36 | 37 | # Disable caching for Action Mailer templates even if Action Controller 38 | # caching is enabled. 39 | config.action_mailer.perform_caching = false 40 | 41 | # Tell Action Mailer not to deliver emails to the real world. 42 | # The :test delivery method accumulates sent emails in the 43 | # ActionMailer::Base.deliveries array. 44 | config.action_mailer.delivery_method = :test 45 | 46 | # Unlike controllers, the mailer instance doesn't have any context about the 47 | # incoming request so you'll need to provide the :host parameter yourself. 48 | config.action_mailer.default_url_options = { host: "www.example.com" } 49 | 50 | # Print deprecation notices to the stderr. 51 | config.active_support.deprecation = :stderr 52 | 53 | # Raise exceptions for disallowed deprecations. 54 | config.active_support.disallowed_deprecation = :raise 55 | 56 | # Tell Active Support which deprecation messages to disallow. 57 | config.active_support.disallowed_deprecation_warnings = [] 58 | 59 | # Raises error for missing translations. 60 | # config.i18n.raise_on_missing_translations = true 61 | 62 | # Annotate rendered view with file names. 63 | # config.action_view.annotate_rendered_view_with_filenames = true 64 | 65 | # Raise error when a before_action's only/except options reference missing actions. 66 | config.action_controller.raise_on_missing_callback_actions = true 67 | end 68 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 8 | ] 9 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | if User.none? 2 | 10.times do 3 | User.create!( 4 | name: Faker::Name.name, 5 | email: Faker::Internet.email, 6 | password: "1234asdf" 7 | ) 8 | end 9 | end 10 | 11 | if Article.none? 12 | 20.times do 13 | Article.create!( 14 | title: Faker::Commerce.product_name, 15 | body: Faker::Lorem.paragraphs(number: 5).join, 16 | user: User.all.sample 17 | ) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ralixjs/rails-ralix-tailwind/f476049dd9c7ef07868148da8615cba4e463da09/lib/tasks/.keep -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ralixjs/rails-ralix-tailwind/f476049dd9c7ef07868148da8615cba4e463da09/log/.keep -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "private": "true", 4 | "dependencies": { 5 | "@hotwired/turbo-rails": "^8.0.0", 6 | "@rails/actiontext": "^7.2.0", 7 | "@tailwindcss/forms": "^0.5.9", 8 | "esbuild": "^0.25.0", 9 | "micromodal": "^0.4.10", 10 | "ralix": "^1.4.0", 11 | "tailwindcss": "^3.4.13", 12 | "tippy.js": "^6.3.7", 13 | "trix": "^2.1.15" 14 | }, 15 | "scripts": { 16 | "build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets", 17 | "build:css": "tailwindcss -i ./app/assets/stylesheets/application.css -o ./app/assets/builds/application.css --minify" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ralixjs/rails-ralix-tailwind/f476049dd9c7ef07868148da8615cba4e463da09/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ralixjs/rails-ralix-tailwind/f476049dd9c7ef07868148da8615cba4e463da09/storage/.keep -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: [ 3 | './app/views/**/*.html.erb', 4 | './app/helpers/**/*.rb', 5 | './app/assets/stylesheets/**/*.css', 6 | './app/javascript/**/*.js', 7 | './config/initializers/heroicon.rb' 8 | ], 9 | plugins: [ 10 | require('@tailwindcss/forms') 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ralixjs/rails-ralix-tailwind/f476049dd9c7ef07868148da8615cba4e463da09/tmp/.keep -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@alloc/quick-lru@^5.2.0": 6 | version "5.2.0" 7 | resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" 8 | integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== 9 | 10 | "@esbuild/aix-ppc64@0.25.0": 11 | version "0.25.0" 12 | resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz#499600c5e1757a524990d5d92601f0ac3ce87f64" 13 | integrity sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ== 14 | 15 | "@esbuild/android-arm64@0.25.0": 16 | version "0.25.0" 17 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz#b9b8231561a1dfb94eb31f4ee056b92a985c324f" 18 | integrity sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g== 19 | 20 | "@esbuild/android-arm@0.25.0": 21 | version "0.25.0" 22 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.0.tgz#ca6e7888942505f13e88ac9f5f7d2a72f9facd2b" 23 | integrity sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g== 24 | 25 | "@esbuild/android-x64@0.25.0": 26 | version "0.25.0" 27 | resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.0.tgz#e765ea753bac442dfc9cb53652ce8bd39d33e163" 28 | integrity sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg== 29 | 30 | "@esbuild/darwin-arm64@0.25.0": 31 | version "0.25.0" 32 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz#fa394164b0d89d4fdc3a8a21989af70ef579fa2c" 33 | integrity sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw== 34 | 35 | "@esbuild/darwin-x64@0.25.0": 36 | version "0.25.0" 37 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz#91979d98d30ba6e7d69b22c617cc82bdad60e47a" 38 | integrity sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg== 39 | 40 | "@esbuild/freebsd-arm64@0.25.0": 41 | version "0.25.0" 42 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz#b97e97073310736b430a07b099d837084b85e9ce" 43 | integrity sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w== 44 | 45 | "@esbuild/freebsd-x64@0.25.0": 46 | version "0.25.0" 47 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz#f3b694d0da61d9910ec7deff794d444cfbf3b6e7" 48 | integrity sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A== 49 | 50 | "@esbuild/linux-arm64@0.25.0": 51 | version "0.25.0" 52 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz#f921f699f162f332036d5657cad9036f7a993f73" 53 | integrity sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg== 54 | 55 | "@esbuild/linux-arm@0.25.0": 56 | version "0.25.0" 57 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz#cc49305b3c6da317c900688995a4050e6cc91ca3" 58 | integrity sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg== 59 | 60 | "@esbuild/linux-ia32@0.25.0": 61 | version "0.25.0" 62 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz#3e0736fcfab16cff042dec806247e2c76e109e19" 63 | integrity sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg== 64 | 65 | "@esbuild/linux-loong64@0.25.0": 66 | version "0.25.0" 67 | resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz#ea2bf730883cddb9dfb85124232b5a875b8020c7" 68 | integrity sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw== 69 | 70 | "@esbuild/linux-mips64el@0.25.0": 71 | version "0.25.0" 72 | resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz#4cababb14eede09248980a2d2d8b966464294ff1" 73 | integrity sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ== 74 | 75 | "@esbuild/linux-ppc64@0.25.0": 76 | version "0.25.0" 77 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz#8860a4609914c065373a77242e985179658e1951" 78 | integrity sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw== 79 | 80 | "@esbuild/linux-riscv64@0.25.0": 81 | version "0.25.0" 82 | resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz#baf26e20bb2d38cfb86ee282dff840c04f4ed987" 83 | integrity sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA== 84 | 85 | "@esbuild/linux-s390x@0.25.0": 86 | version "0.25.0" 87 | resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz#8323afc0d6cb1b6dc6e9fd21efd9e1542c3640a4" 88 | integrity sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA== 89 | 90 | "@esbuild/linux-x64@0.25.0": 91 | version "0.25.0" 92 | resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz#08fcf60cb400ed2382e9f8e0f5590bac8810469a" 93 | integrity sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw== 94 | 95 | "@esbuild/netbsd-arm64@0.25.0": 96 | version "0.25.0" 97 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz#935c6c74e20f7224918fbe2e6c6fe865b6c6ea5b" 98 | integrity sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw== 99 | 100 | "@esbuild/netbsd-x64@0.25.0": 101 | version "0.25.0" 102 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz#414677cef66d16c5a4d210751eb2881bb9c1b62b" 103 | integrity sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA== 104 | 105 | "@esbuild/openbsd-arm64@0.25.0": 106 | version "0.25.0" 107 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz#8fd55a4d08d25cdc572844f13c88d678c84d13f7" 108 | integrity sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw== 109 | 110 | "@esbuild/openbsd-x64@0.25.0": 111 | version "0.25.0" 112 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz#0c48ddb1494bbc2d6bcbaa1429a7f465fa1dedde" 113 | integrity sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg== 114 | 115 | "@esbuild/sunos-x64@0.25.0": 116 | version "0.25.0" 117 | resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz#86ff9075d77962b60dd26203d7352f92684c8c92" 118 | integrity sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg== 119 | 120 | "@esbuild/win32-arm64@0.25.0": 121 | version "0.25.0" 122 | resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz#849c62327c3229467f5b5cd681bf50588442e96c" 123 | integrity sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw== 124 | 125 | "@esbuild/win32-ia32@0.25.0": 126 | version "0.25.0" 127 | resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz#f62eb480cd7cca088cb65bb46a6db25b725dc079" 128 | integrity sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA== 129 | 130 | "@esbuild/win32-x64@0.25.0": 131 | version "0.25.0" 132 | resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz#c8e119a30a7c8d60b9d2e22d2073722dde3b710b" 133 | integrity sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ== 134 | 135 | "@hotwired/turbo-rails@^8.0.0": 136 | version "8.0.10" 137 | resolved "https://registry.yarnpkg.com/@hotwired/turbo-rails/-/turbo-rails-8.0.10.tgz#28b0c1243868d9efc4a71f4a2ff7d97ee9cefbfa" 138 | integrity sha512-BkERfjTbNwMb9/YQi0RL9+f9zkD+dZH2klEONtGwXrIE3O9BE1937Nn9++koZpDryD4XN3zE5U5ibyWoYJAWBg== 139 | dependencies: 140 | "@hotwired/turbo" "^8.0.6" 141 | "@rails/actioncable" "^7.0" 142 | 143 | "@hotwired/turbo@^8.0.6": 144 | version "8.0.10" 145 | resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-8.0.10.tgz#d95569d259f0daad6e824ee1ada877ff94beb72b" 146 | integrity sha512-xen1YhNQirAHlA8vr/444XsTNITC1Il2l/Vx4w8hAWPpI5nQO78mVHNsmFuayETodzPwh25ob2TgfCEV/Loiog== 147 | 148 | "@isaacs/cliui@^8.0.2": 149 | version "8.0.2" 150 | resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" 151 | integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== 152 | dependencies: 153 | string-width "^5.1.2" 154 | string-width-cjs "npm:string-width@^4.2.0" 155 | strip-ansi "^7.0.1" 156 | strip-ansi-cjs "npm:strip-ansi@^6.0.1" 157 | wrap-ansi "^8.1.0" 158 | wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" 159 | 160 | "@jridgewell/gen-mapping@^0.3.2": 161 | version "0.3.5" 162 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" 163 | integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== 164 | dependencies: 165 | "@jridgewell/set-array" "^1.2.1" 166 | "@jridgewell/sourcemap-codec" "^1.4.10" 167 | "@jridgewell/trace-mapping" "^0.3.24" 168 | 169 | "@jridgewell/resolve-uri@^3.1.0": 170 | version "3.1.2" 171 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" 172 | integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== 173 | 174 | "@jridgewell/set-array@^1.2.1": 175 | version "1.2.1" 176 | resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" 177 | integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== 178 | 179 | "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": 180 | version "1.5.0" 181 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" 182 | integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== 183 | 184 | "@jridgewell/trace-mapping@^0.3.24": 185 | version "0.3.25" 186 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" 187 | integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== 188 | dependencies: 189 | "@jridgewell/resolve-uri" "^3.1.0" 190 | "@jridgewell/sourcemap-codec" "^1.4.14" 191 | 192 | "@nodelib/fs.scandir@2.1.5": 193 | version "2.1.5" 194 | resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" 195 | integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== 196 | dependencies: 197 | "@nodelib/fs.stat" "2.0.5" 198 | run-parallel "^1.1.9" 199 | 200 | "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": 201 | version "2.0.5" 202 | resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" 203 | integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== 204 | 205 | "@nodelib/fs.walk@^1.2.3": 206 | version "1.2.8" 207 | resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" 208 | integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== 209 | dependencies: 210 | "@nodelib/fs.scandir" "2.1.5" 211 | fastq "^1.6.0" 212 | 213 | "@pkgjs/parseargs@^0.11.0": 214 | version "0.11.0" 215 | resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" 216 | integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== 217 | 218 | "@popperjs/core@^2.9.0": 219 | version "2.11.8" 220 | resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" 221 | integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== 222 | 223 | "@rails/actioncable@^7.0": 224 | version "7.2.100" 225 | resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-7.2.100.tgz#86ec1c2e00c357cef1e421fd63863d5c34339ce8" 226 | integrity sha512-7xtIENf0Yw59AFDM3+xqxPCZxev3QVAqjPmUzmgsB9eL8S/zTpB0IU9srNc7XknzJI4e09XKNnCaJRx3gfYzXA== 227 | 228 | "@rails/actiontext@^7.2.0": 229 | version "7.2.100" 230 | resolved "https://registry.yarnpkg.com/@rails/actiontext/-/actiontext-7.2.100.tgz#e235c8150d252490902f8b33026bc0a030cce8e4" 231 | integrity sha512-46oDEZdkxpbM/7+3GwSHTRyIkH3LRZRC9OE35rMIt0FcRbjXW+2Q7RL1YYjoy7megqnoCUDZglFISJQxJ/HBZg== 232 | dependencies: 233 | "@rails/activestorage" ">= 7.2.0-alpha" 234 | 235 | "@rails/activestorage@>= 7.2.0-alpha": 236 | version "7.2.100" 237 | resolved "https://registry.yarnpkg.com/@rails/activestorage/-/activestorage-7.2.100.tgz#c1e643d3c35c62c946e6f7c8d812fa567d2ce915" 238 | integrity sha512-gohCilm1E10W51Hc9iT960xX9TP11L5TJ4W1ufs9f3h5Ncsw01S/eHgVUfcdfszqw3G+28Z0MFu999+iSpgdTg== 239 | dependencies: 240 | spark-md5 "^3.0.1" 241 | 242 | "@tailwindcss/forms@^0.5.9": 243 | version "0.5.9" 244 | resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.9.tgz#b495c12575d6eae5865b2cbd9876b26d89f16f61" 245 | integrity sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg== 246 | dependencies: 247 | mini-svg-data-uri "^1.2.3" 248 | 249 | "@types/trusted-types@^2.0.7": 250 | version "2.0.7" 251 | resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" 252 | integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== 253 | 254 | ansi-regex@^5.0.1: 255 | version "5.0.1" 256 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 257 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 258 | 259 | ansi-regex@^6.0.1: 260 | version "6.1.0" 261 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" 262 | integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== 263 | 264 | ansi-styles@^4.0.0: 265 | version "4.3.0" 266 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 267 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 268 | dependencies: 269 | color-convert "^2.0.1" 270 | 271 | ansi-styles@^6.1.0: 272 | version "6.2.1" 273 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" 274 | integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== 275 | 276 | any-promise@^1.0.0: 277 | version "1.3.0" 278 | resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" 279 | integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== 280 | 281 | anymatch@~3.1.2: 282 | version "3.1.3" 283 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" 284 | integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== 285 | dependencies: 286 | normalize-path "^3.0.0" 287 | picomatch "^2.0.4" 288 | 289 | arg@^5.0.2: 290 | version "5.0.2" 291 | resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" 292 | integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== 293 | 294 | balanced-match@^1.0.0: 295 | version "1.0.2" 296 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 297 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 298 | 299 | binary-extensions@^2.0.0: 300 | version "2.3.0" 301 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" 302 | integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== 303 | 304 | brace-expansion@^2.0.1: 305 | version "2.0.1" 306 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 307 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 308 | dependencies: 309 | balanced-match "^1.0.0" 310 | 311 | braces@^3.0.3, braces@~3.0.2: 312 | version "3.0.3" 313 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" 314 | integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== 315 | dependencies: 316 | fill-range "^7.1.1" 317 | 318 | camelcase-css@^2.0.1: 319 | version "2.0.1" 320 | resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" 321 | integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== 322 | 323 | chokidar@^3.5.3: 324 | version "3.6.0" 325 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" 326 | integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== 327 | dependencies: 328 | anymatch "~3.1.2" 329 | braces "~3.0.2" 330 | glob-parent "~5.1.2" 331 | is-binary-path "~2.1.0" 332 | is-glob "~4.0.1" 333 | normalize-path "~3.0.0" 334 | readdirp "~3.6.0" 335 | optionalDependencies: 336 | fsevents "~2.3.2" 337 | 338 | color-convert@^2.0.1: 339 | version "2.0.1" 340 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 341 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 342 | dependencies: 343 | color-name "~1.1.4" 344 | 345 | color-name@~1.1.4: 346 | version "1.1.4" 347 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 348 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 349 | 350 | commander@^4.0.0: 351 | version "4.1.1" 352 | resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" 353 | integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== 354 | 355 | cross-spawn@^7.0.0: 356 | version "7.0.6" 357 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" 358 | integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== 359 | dependencies: 360 | path-key "^3.1.0" 361 | shebang-command "^2.0.0" 362 | which "^2.0.1" 363 | 364 | cssesc@^3.0.0: 365 | version "3.0.0" 366 | resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" 367 | integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== 368 | 369 | didyoumean@^1.2.2: 370 | version "1.2.2" 371 | resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" 372 | integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== 373 | 374 | dlv@^1.1.3: 375 | version "1.1.3" 376 | resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" 377 | integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== 378 | 379 | dompurify@^3.2.5: 380 | version "3.2.5" 381 | resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.2.5.tgz#11b108656a5fb72b24d916df17a1421663d7129c" 382 | integrity sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ== 383 | optionalDependencies: 384 | "@types/trusted-types" "^2.0.7" 385 | 386 | eastasianwidth@^0.2.0: 387 | version "0.2.0" 388 | resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" 389 | integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== 390 | 391 | emoji-regex@^8.0.0: 392 | version "8.0.0" 393 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 394 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 395 | 396 | emoji-regex@^9.2.2: 397 | version "9.2.2" 398 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" 399 | integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== 400 | 401 | esbuild@^0.25.0: 402 | version "0.25.0" 403 | resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.0.tgz#0de1787a77206c5a79eeb634a623d39b5006ce92" 404 | integrity sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw== 405 | optionalDependencies: 406 | "@esbuild/aix-ppc64" "0.25.0" 407 | "@esbuild/android-arm" "0.25.0" 408 | "@esbuild/android-arm64" "0.25.0" 409 | "@esbuild/android-x64" "0.25.0" 410 | "@esbuild/darwin-arm64" "0.25.0" 411 | "@esbuild/darwin-x64" "0.25.0" 412 | "@esbuild/freebsd-arm64" "0.25.0" 413 | "@esbuild/freebsd-x64" "0.25.0" 414 | "@esbuild/linux-arm" "0.25.0" 415 | "@esbuild/linux-arm64" "0.25.0" 416 | "@esbuild/linux-ia32" "0.25.0" 417 | "@esbuild/linux-loong64" "0.25.0" 418 | "@esbuild/linux-mips64el" "0.25.0" 419 | "@esbuild/linux-ppc64" "0.25.0" 420 | "@esbuild/linux-riscv64" "0.25.0" 421 | "@esbuild/linux-s390x" "0.25.0" 422 | "@esbuild/linux-x64" "0.25.0" 423 | "@esbuild/netbsd-arm64" "0.25.0" 424 | "@esbuild/netbsd-x64" "0.25.0" 425 | "@esbuild/openbsd-arm64" "0.25.0" 426 | "@esbuild/openbsd-x64" "0.25.0" 427 | "@esbuild/sunos-x64" "0.25.0" 428 | "@esbuild/win32-arm64" "0.25.0" 429 | "@esbuild/win32-ia32" "0.25.0" 430 | "@esbuild/win32-x64" "0.25.0" 431 | 432 | fast-glob@^3.3.0: 433 | version "3.3.2" 434 | resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" 435 | integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== 436 | dependencies: 437 | "@nodelib/fs.stat" "^2.0.2" 438 | "@nodelib/fs.walk" "^1.2.3" 439 | glob-parent "^5.1.2" 440 | merge2 "^1.3.0" 441 | micromatch "^4.0.4" 442 | 443 | fastq@^1.6.0: 444 | version "1.17.1" 445 | resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" 446 | integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== 447 | dependencies: 448 | reusify "^1.0.4" 449 | 450 | fill-range@^7.1.1: 451 | version "7.1.1" 452 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" 453 | integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== 454 | dependencies: 455 | to-regex-range "^5.0.1" 456 | 457 | foreground-child@^3.1.0: 458 | version "3.3.0" 459 | resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" 460 | integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== 461 | dependencies: 462 | cross-spawn "^7.0.0" 463 | signal-exit "^4.0.1" 464 | 465 | fsevents@~2.3.2: 466 | version "2.3.3" 467 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" 468 | integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== 469 | 470 | function-bind@^1.1.2: 471 | version "1.1.2" 472 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" 473 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== 474 | 475 | glob-parent@^5.1.2, glob-parent@~5.1.2: 476 | version "5.1.2" 477 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 478 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 479 | dependencies: 480 | is-glob "^4.0.1" 481 | 482 | glob-parent@^6.0.2: 483 | version "6.0.2" 484 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" 485 | integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== 486 | dependencies: 487 | is-glob "^4.0.3" 488 | 489 | glob@^10.3.10: 490 | version "10.4.5" 491 | resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" 492 | integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== 493 | dependencies: 494 | foreground-child "^3.1.0" 495 | jackspeak "^3.1.2" 496 | minimatch "^9.0.4" 497 | minipass "^7.1.2" 498 | package-json-from-dist "^1.0.0" 499 | path-scurry "^1.11.1" 500 | 501 | hasown@^2.0.2: 502 | version "2.0.2" 503 | resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" 504 | integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== 505 | dependencies: 506 | function-bind "^1.1.2" 507 | 508 | is-binary-path@~2.1.0: 509 | version "2.1.0" 510 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 511 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 512 | dependencies: 513 | binary-extensions "^2.0.0" 514 | 515 | is-core-module@^2.13.0: 516 | version "2.15.1" 517 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" 518 | integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== 519 | dependencies: 520 | hasown "^2.0.2" 521 | 522 | is-extglob@^2.1.1: 523 | version "2.1.1" 524 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 525 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 526 | 527 | is-fullwidth-code-point@^3.0.0: 528 | version "3.0.0" 529 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 530 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 531 | 532 | is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: 533 | version "4.0.3" 534 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 535 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 536 | dependencies: 537 | is-extglob "^2.1.1" 538 | 539 | is-number@^7.0.0: 540 | version "7.0.0" 541 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 542 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 543 | 544 | isexe@^2.0.0: 545 | version "2.0.0" 546 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 547 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 548 | 549 | jackspeak@^3.1.2: 550 | version "3.4.3" 551 | resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" 552 | integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== 553 | dependencies: 554 | "@isaacs/cliui" "^8.0.2" 555 | optionalDependencies: 556 | "@pkgjs/parseargs" "^0.11.0" 557 | 558 | jiti@^1.21.0: 559 | version "1.21.6" 560 | resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" 561 | integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== 562 | 563 | lilconfig@^2.1.0: 564 | version "2.1.0" 565 | resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" 566 | integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== 567 | 568 | lilconfig@^3.0.0: 569 | version "3.1.2" 570 | resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb" 571 | integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow== 572 | 573 | lines-and-columns@^1.1.6: 574 | version "1.2.4" 575 | resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" 576 | integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== 577 | 578 | lru-cache@^10.2.0: 579 | version "10.4.3" 580 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" 581 | integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== 582 | 583 | merge2@^1.3.0: 584 | version "1.4.1" 585 | resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" 586 | integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== 587 | 588 | micromatch@^4.0.4, micromatch@^4.0.5: 589 | version "4.0.8" 590 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" 591 | integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== 592 | dependencies: 593 | braces "^3.0.3" 594 | picomatch "^2.3.1" 595 | 596 | micromodal@^0.4.10: 597 | version "0.4.10" 598 | resolved "https://registry.yarnpkg.com/micromodal/-/micromodal-0.4.10.tgz#d6f59c21d2f4a5af480f65909eb9608a1d558c73" 599 | integrity sha512-BUrEnzMPFBwK8nOE4xUDYHLrlGlLULQVjpja99tpJQPSUEWgw3kTLp1n1qv0HmKU29AiHE7Y7sMLiRziDK4ghQ== 600 | 601 | mini-svg-data-uri@^1.2.3: 602 | version "1.4.4" 603 | resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" 604 | integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== 605 | 606 | minimatch@^9.0.4: 607 | version "9.0.5" 608 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" 609 | integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== 610 | dependencies: 611 | brace-expansion "^2.0.1" 612 | 613 | "minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: 614 | version "7.1.2" 615 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" 616 | integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== 617 | 618 | mz@^2.7.0: 619 | version "2.7.0" 620 | resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" 621 | integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== 622 | dependencies: 623 | any-promise "^1.0.0" 624 | object-assign "^4.0.1" 625 | thenify-all "^1.0.0" 626 | 627 | nanoid@^3.3.7: 628 | version "3.3.8" 629 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" 630 | integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== 631 | 632 | normalize-path@^3.0.0, normalize-path@~3.0.0: 633 | version "3.0.0" 634 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 635 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 636 | 637 | object-assign@^4.0.1: 638 | version "4.1.1" 639 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 640 | integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== 641 | 642 | object-hash@^3.0.0: 643 | version "3.0.0" 644 | resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" 645 | integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== 646 | 647 | package-json-from-dist@^1.0.0: 648 | version "1.0.1" 649 | resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" 650 | integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== 651 | 652 | path-key@^3.1.0: 653 | version "3.1.1" 654 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 655 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 656 | 657 | path-parse@^1.0.7: 658 | version "1.0.7" 659 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 660 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 661 | 662 | path-scurry@^1.11.1: 663 | version "1.11.1" 664 | resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" 665 | integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== 666 | dependencies: 667 | lru-cache "^10.2.0" 668 | minipass "^5.0.0 || ^6.0.2 || ^7.0.0" 669 | 670 | picocolors@^1.0.0, picocolors@^1.1.0: 671 | version "1.1.0" 672 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" 673 | integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== 674 | 675 | picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: 676 | version "2.3.1" 677 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 678 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 679 | 680 | pify@^2.3.0: 681 | version "2.3.0" 682 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 683 | integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== 684 | 685 | pirates@^4.0.1: 686 | version "4.0.6" 687 | resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" 688 | integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== 689 | 690 | postcss-import@^15.1.0: 691 | version "15.1.0" 692 | resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" 693 | integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== 694 | dependencies: 695 | postcss-value-parser "^4.0.0" 696 | read-cache "^1.0.0" 697 | resolve "^1.1.7" 698 | 699 | postcss-js@^4.0.1: 700 | version "4.0.1" 701 | resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" 702 | integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== 703 | dependencies: 704 | camelcase-css "^2.0.1" 705 | 706 | postcss-load-config@^4.0.1: 707 | version "4.0.2" 708 | resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" 709 | integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== 710 | dependencies: 711 | lilconfig "^3.0.0" 712 | yaml "^2.3.4" 713 | 714 | postcss-nested@^6.0.1: 715 | version "6.2.0" 716 | resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.2.0.tgz#4c2d22ab5f20b9cb61e2c5c5915950784d068131" 717 | integrity sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ== 718 | dependencies: 719 | postcss-selector-parser "^6.1.1" 720 | 721 | postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.1.1: 722 | version "6.1.2" 723 | resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" 724 | integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== 725 | dependencies: 726 | cssesc "^3.0.0" 727 | util-deprecate "^1.0.2" 728 | 729 | postcss-value-parser@^4.0.0: 730 | version "4.2.0" 731 | resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" 732 | integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== 733 | 734 | postcss@^8.4.23: 735 | version "8.4.47" 736 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" 737 | integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== 738 | dependencies: 739 | nanoid "^3.3.7" 740 | picocolors "^1.1.0" 741 | source-map-js "^1.2.1" 742 | 743 | queue-microtask@^1.2.2: 744 | version "1.2.3" 745 | resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" 746 | integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== 747 | 748 | ralix@^1.4.0: 749 | version "1.4.0" 750 | resolved "https://registry.yarnpkg.com/ralix/-/ralix-1.4.0.tgz#b38c9c23a1fd6d4bcd4d54e1f19d7a09cbb8e426" 751 | integrity sha512-2wCHeDxgvD9S06qRnxJah6b3y4BbHShmzJ0y6/+GhE0kerg54bF/hQglgPxyjpT1o/2slXwBdPeYc4Pjs/SxaA== 752 | 753 | read-cache@^1.0.0: 754 | version "1.0.0" 755 | resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" 756 | integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== 757 | dependencies: 758 | pify "^2.3.0" 759 | 760 | readdirp@~3.6.0: 761 | version "3.6.0" 762 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 763 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 764 | dependencies: 765 | picomatch "^2.2.1" 766 | 767 | resolve@^1.1.7, resolve@^1.22.2: 768 | version "1.22.8" 769 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" 770 | integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== 771 | dependencies: 772 | is-core-module "^2.13.0" 773 | path-parse "^1.0.7" 774 | supports-preserve-symlinks-flag "^1.0.0" 775 | 776 | reusify@^1.0.4: 777 | version "1.0.4" 778 | resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" 779 | integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== 780 | 781 | run-parallel@^1.1.9: 782 | version "1.2.0" 783 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" 784 | integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== 785 | dependencies: 786 | queue-microtask "^1.2.2" 787 | 788 | shebang-command@^2.0.0: 789 | version "2.0.0" 790 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 791 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 792 | dependencies: 793 | shebang-regex "^3.0.0" 794 | 795 | shebang-regex@^3.0.0: 796 | version "3.0.0" 797 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 798 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 799 | 800 | signal-exit@^4.0.1: 801 | version "4.1.0" 802 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" 803 | integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== 804 | 805 | source-map-js@^1.2.1: 806 | version "1.2.1" 807 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" 808 | integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== 809 | 810 | spark-md5@^3.0.1: 811 | version "3.0.2" 812 | resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc" 813 | integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== 814 | 815 | "string-width-cjs@npm:string-width@^4.2.0": 816 | version "4.2.3" 817 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 818 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 819 | dependencies: 820 | emoji-regex "^8.0.0" 821 | is-fullwidth-code-point "^3.0.0" 822 | strip-ansi "^6.0.1" 823 | 824 | string-width@^4.1.0: 825 | version "4.2.3" 826 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 827 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 828 | dependencies: 829 | emoji-regex "^8.0.0" 830 | is-fullwidth-code-point "^3.0.0" 831 | strip-ansi "^6.0.1" 832 | 833 | string-width@^5.0.1, string-width@^5.1.2: 834 | version "5.1.2" 835 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" 836 | integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== 837 | dependencies: 838 | eastasianwidth "^0.2.0" 839 | emoji-regex "^9.2.2" 840 | strip-ansi "^7.0.1" 841 | 842 | "strip-ansi-cjs@npm:strip-ansi@^6.0.1": 843 | version "6.0.1" 844 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 845 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 846 | dependencies: 847 | ansi-regex "^5.0.1" 848 | 849 | strip-ansi@^6.0.0, strip-ansi@^6.0.1: 850 | version "6.0.1" 851 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 852 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 853 | dependencies: 854 | ansi-regex "^5.0.1" 855 | 856 | strip-ansi@^7.0.1: 857 | version "7.1.0" 858 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" 859 | integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== 860 | dependencies: 861 | ansi-regex "^6.0.1" 862 | 863 | sucrase@^3.32.0: 864 | version "3.35.0" 865 | resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" 866 | integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== 867 | dependencies: 868 | "@jridgewell/gen-mapping" "^0.3.2" 869 | commander "^4.0.0" 870 | glob "^10.3.10" 871 | lines-and-columns "^1.1.6" 872 | mz "^2.7.0" 873 | pirates "^4.0.1" 874 | ts-interface-checker "^0.1.9" 875 | 876 | supports-preserve-symlinks-flag@^1.0.0: 877 | version "1.0.0" 878 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 879 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 880 | 881 | tailwindcss@^3.4.13: 882 | version "3.4.13" 883 | resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.13.tgz#3d11e5510660f99df4f1bfb2d78434666cb8f831" 884 | integrity sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw== 885 | dependencies: 886 | "@alloc/quick-lru" "^5.2.0" 887 | arg "^5.0.2" 888 | chokidar "^3.5.3" 889 | didyoumean "^1.2.2" 890 | dlv "^1.1.3" 891 | fast-glob "^3.3.0" 892 | glob-parent "^6.0.2" 893 | is-glob "^4.0.3" 894 | jiti "^1.21.0" 895 | lilconfig "^2.1.0" 896 | micromatch "^4.0.5" 897 | normalize-path "^3.0.0" 898 | object-hash "^3.0.0" 899 | picocolors "^1.0.0" 900 | postcss "^8.4.23" 901 | postcss-import "^15.1.0" 902 | postcss-js "^4.0.1" 903 | postcss-load-config "^4.0.1" 904 | postcss-nested "^6.0.1" 905 | postcss-selector-parser "^6.0.11" 906 | resolve "^1.22.2" 907 | sucrase "^3.32.0" 908 | 909 | thenify-all@^1.0.0: 910 | version "1.6.0" 911 | resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" 912 | integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== 913 | dependencies: 914 | thenify ">= 3.1.0 < 4" 915 | 916 | "thenify@>= 3.1.0 < 4": 917 | version "3.3.1" 918 | resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" 919 | integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== 920 | dependencies: 921 | any-promise "^1.0.0" 922 | 923 | tippy.js@^6.3.7: 924 | version "6.3.7" 925 | resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c" 926 | integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ== 927 | dependencies: 928 | "@popperjs/core" "^2.9.0" 929 | 930 | to-regex-range@^5.0.1: 931 | version "5.0.1" 932 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 933 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 934 | dependencies: 935 | is-number "^7.0.0" 936 | 937 | trix@^2.1.15: 938 | version "2.1.15" 939 | resolved "https://registry.yarnpkg.com/trix/-/trix-2.1.15.tgz#fabad796ea779a8ae96522402fbc214cbfc4015f" 940 | integrity sha512-LoaXWczdTUV8+3Box92B9b1iaDVbxD14dYemZRxi3PwY+AuDm97BUJV2aHLBUFPuDABhxp0wzcbf0CxHCVmXiw== 941 | dependencies: 942 | dompurify "^3.2.5" 943 | 944 | ts-interface-checker@^0.1.9: 945 | version "0.1.13" 946 | resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" 947 | integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== 948 | 949 | util-deprecate@^1.0.2: 950 | version "1.0.2" 951 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 952 | integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== 953 | 954 | which@^2.0.1: 955 | version "2.0.2" 956 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 957 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 958 | dependencies: 959 | isexe "^2.0.0" 960 | 961 | "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": 962 | version "7.0.0" 963 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 964 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 965 | dependencies: 966 | ansi-styles "^4.0.0" 967 | string-width "^4.1.0" 968 | strip-ansi "^6.0.0" 969 | 970 | wrap-ansi@^8.1.0: 971 | version "8.1.0" 972 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" 973 | integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== 974 | dependencies: 975 | ansi-styles "^6.1.0" 976 | string-width "^5.0.1" 977 | strip-ansi "^7.0.1" 978 | 979 | yaml@^2.3.4: 980 | version "2.5.1" 981 | resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130" 982 | integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q== 983 | --------------------------------------------------------------------------------