├── .gitignore ├── .rubocop.yml ├── .tool-versions ├── CHANGELOG.md ├── Gemfile ├── Gemfile.lock ├── MIT-LICENSE ├── Procfile.dev ├── README.md ├── Rakefile ├── app ├── assets │ ├── config │ │ └── deployed_manifest.js │ ├── images │ │ └── deployed │ │ │ └── .keep │ ├── javascripts │ │ └── deployed │ │ │ └── application.js │ └── stylesheets │ │ └── deployed │ │ ├── deployed.css │ │ └── src │ │ └── input.css ├── controllers │ ├── concerns │ │ └── .keep │ └── deployed │ │ ├── application_controller.rb │ │ ├── config_controller.rb │ │ ├── git_controller.rb │ │ ├── log_output_controller.rb │ │ ├── run_controller.rb │ │ ├── setup_controller.rb │ │ └── welcome_controller.rb ├── helpers │ └── deployed │ │ ├── application_helper.rb │ │ └── log_output_helper.rb ├── models │ ├── concerns │ │ └── .keep │ └── deployed │ │ ├── config.rb │ │ └── current_execution.rb └── views │ ├── deployed │ ├── git │ │ └── uncommitted_check.html.erb │ ├── setup │ │ └── new.html.erb │ └── welcome │ │ └── index.html.erb │ └── layouts │ └── deployed │ └── application.html.erb ├── bin ├── dev ├── rails └── setup ├── config └── routes.rb ├── deployed.gemspec ├── lib ├── deployed.rb ├── deployed │ ├── engine.rb │ └── version.rb └── tasks │ └── deployed_tasks.rake ├── package-lock.json ├── package.json ├── tailwind.config.js └── test ├── controllers └── .keep ├── dummy ├── Rakefile ├── app │ ├── assets │ │ ├── config │ │ │ └── manifest.js │ │ ├── images │ │ │ └── .keep │ │ └── stylesheets │ │ │ └── application.css │ ├── channels │ │ └── application_cable │ │ │ ├── channel.rb │ │ │ └── connection.rb │ ├── controllers │ │ ├── application_controller.rb │ │ └── concerns │ │ │ └── .keep │ ├── helpers │ │ └── application_helper.rb │ ├── jobs │ │ └── application_job.rb │ ├── mailers │ │ └── application_mailer.rb │ ├── models │ │ ├── application_record.rb │ │ └── concerns │ │ │ └── .keep │ └── views │ │ └── layouts │ │ ├── application.html.erb │ │ ├── mailer.html.erb │ │ └── mailer.text.erb ├── bin │ ├── rails │ ├── rake │ └── setup ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── cable.yml │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── assets.rb │ │ ├── content_security_policy.rb │ │ ├── filter_parameter_logging.rb │ │ ├── inflections.rb │ │ └── permissions_policy.rb │ ├── locales │ │ └── en.yml │ ├── puma.rb │ ├── routes.rb │ ├── storage.yml │ └── tailwind.config.js ├── lib │ └── assets │ │ └── .keep ├── log │ └── .keep └── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ ├── apple-touch-icon-precomposed.png │ ├── apple-touch-icon.png │ └── favicon.ico ├── fixtures └── files │ └── .keep ├── helpers └── .keep ├── integration ├── .keep └── navigation_test.rb ├── kamal_rails_test.rb ├── mailers └── .keep ├── models └── .keep └── test_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /doc/ 3 | /log/*.log 4 | /pkg/ 5 | /tmp/ 6 | /test/dummy/db/*.sqlite3 7 | /test/dummy/db/*.sqlite3-* 8 | /test/dummy/log/*.log 9 | /test/dummy/storage/ 10 | /test/dummy/tmp/ 11 | /test/dummy/.env 12 | /test/dummy/.deployed 13 | /test/dummy/config/deploy.yml 14 | /node_modules/**/* 15 | .DS_Store 16 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/.rubocop.yml -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs 18.18.2 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## [0.1.3] October 26, 2023 8 | 9 | ### Changed 10 | - The way log output is generated and piped to the browser 11 | - Log persists if the user reloads the dashboard while process is still running 12 | 13 | ## [0.1.0 to 0.1.2] 14 | 15 | Initial release(s) 16 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 5 | 6 | # Specify your gem's dependencies in deployed.gemspec. 7 | gemspec 8 | 9 | gem 'turbo-rails', '~> 1.5' 10 | gem 'puma' 11 | gem 'rubocop' 12 | gem 'sprockets-rails' 13 | gem 'sqlite3' 14 | gem 'kamal' 15 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | deployed (0.1.2) 5 | kamal (~> 1.0) 6 | rails (>= 7.1.1) 7 | turbo-rails (~> 1.5) 8 | 9 | GEM 10 | remote: https://rubygems.org/ 11 | specs: 12 | actioncable (7.1.1) 13 | actionpack (= 7.1.1) 14 | activesupport (= 7.1.1) 15 | nio4r (~> 2.0) 16 | websocket-driver (>= 0.6.1) 17 | zeitwerk (~> 2.6) 18 | actionmailbox (7.1.1) 19 | actionpack (= 7.1.1) 20 | activejob (= 7.1.1) 21 | activerecord (= 7.1.1) 22 | activestorage (= 7.1.1) 23 | activesupport (= 7.1.1) 24 | mail (>= 2.7.1) 25 | net-imap 26 | net-pop 27 | net-smtp 28 | actionmailer (7.1.1) 29 | actionpack (= 7.1.1) 30 | actionview (= 7.1.1) 31 | activejob (= 7.1.1) 32 | activesupport (= 7.1.1) 33 | mail (~> 2.5, >= 2.5.4) 34 | net-imap 35 | net-pop 36 | net-smtp 37 | rails-dom-testing (~> 2.2) 38 | actionpack (7.1.1) 39 | actionview (= 7.1.1) 40 | activesupport (= 7.1.1) 41 | nokogiri (>= 1.8.5) 42 | rack (>= 2.2.4) 43 | rack-session (>= 1.0.1) 44 | rack-test (>= 0.6.3) 45 | rails-dom-testing (~> 2.2) 46 | rails-html-sanitizer (~> 1.6) 47 | actiontext (7.1.1) 48 | actionpack (= 7.1.1) 49 | activerecord (= 7.1.1) 50 | activestorage (= 7.1.1) 51 | activesupport (= 7.1.1) 52 | globalid (>= 0.6.0) 53 | nokogiri (>= 1.8.5) 54 | actionview (7.1.1) 55 | activesupport (= 7.1.1) 56 | builder (~> 3.1) 57 | erubi (~> 1.11) 58 | rails-dom-testing (~> 2.2) 59 | rails-html-sanitizer (~> 1.6) 60 | activejob (7.1.1) 61 | activesupport (= 7.1.1) 62 | globalid (>= 0.3.6) 63 | activemodel (7.1.1) 64 | activesupport (= 7.1.1) 65 | activerecord (7.1.1) 66 | activemodel (= 7.1.1) 67 | activesupport (= 7.1.1) 68 | timeout (>= 0.4.0) 69 | activestorage (7.1.1) 70 | actionpack (= 7.1.1) 71 | activejob (= 7.1.1) 72 | activerecord (= 7.1.1) 73 | activesupport (= 7.1.1) 74 | marcel (~> 1.0) 75 | activesupport (7.1.1) 76 | base64 77 | bigdecimal 78 | concurrent-ruby (~> 1.0, >= 1.0.2) 79 | connection_pool (>= 2.2.5) 80 | drb 81 | i18n (>= 1.6, < 2) 82 | minitest (>= 5.1) 83 | mutex_m 84 | tzinfo (~> 2.0) 85 | ast (2.4.2) 86 | base64 (0.1.1) 87 | bcrypt_pbkdf (1.1.0) 88 | bigdecimal (3.1.4) 89 | builder (3.2.4) 90 | concurrent-ruby (1.2.2) 91 | connection_pool (2.4.1) 92 | crass (1.0.6) 93 | date (3.3.3) 94 | dotenv (2.8.1) 95 | drb (2.1.1) 96 | ruby2_keywords 97 | ed25519 (1.3.0) 98 | erubi (1.12.0) 99 | globalid (1.2.1) 100 | activesupport (>= 6.1) 101 | i18n (1.14.1) 102 | concurrent-ruby (~> 1.0) 103 | io-console (0.6.0) 104 | irb (1.8.3) 105 | rdoc 106 | reline (>= 0.3.8) 107 | json (2.6.3) 108 | kamal (1.0.0) 109 | activesupport (>= 7.0) 110 | bcrypt_pbkdf (~> 1.0) 111 | concurrent-ruby (~> 1.2) 112 | dotenv (~> 2.8) 113 | ed25519 (~> 1.2) 114 | net-ssh (~> 7.0) 115 | sshkit (~> 1.21) 116 | thor (~> 1.2) 117 | zeitwerk (~> 2.5) 118 | language_server-protocol (3.17.0.3) 119 | loofah (2.21.4) 120 | crass (~> 1.0.2) 121 | nokogiri (>= 1.12.0) 122 | mail (2.8.1) 123 | mini_mime (>= 0.1.1) 124 | net-imap 125 | net-pop 126 | net-smtp 127 | marcel (1.0.2) 128 | mini_mime (1.1.5) 129 | minitest (5.20.0) 130 | mutex_m (0.1.2) 131 | net-imap (0.4.1) 132 | date 133 | net-protocol 134 | net-pop (0.1.2) 135 | net-protocol 136 | net-protocol (0.2.1) 137 | timeout 138 | net-scp (4.0.0) 139 | net-ssh (>= 2.6.5, < 8.0.0) 140 | net-smtp (0.4.0) 141 | net-protocol 142 | net-ssh (7.2.0) 143 | nio4r (2.5.9) 144 | nokogiri (1.15.4-arm64-darwin) 145 | racc (~> 1.4) 146 | nokogiri (1.15.4-x86_64-linux) 147 | racc (~> 1.4) 148 | parallel (1.23.0) 149 | parser (3.2.2.4) 150 | ast (~> 2.4.1) 151 | racc 152 | psych (5.1.1.1) 153 | stringio 154 | puma (6.4.0) 155 | nio4r (~> 2.0) 156 | racc (1.7.1) 157 | rack (3.0.8) 158 | rack-session (2.0.0) 159 | rack (>= 3.0.0) 160 | rack-test (2.1.0) 161 | rack (>= 1.3) 162 | rackup (2.1.0) 163 | rack (>= 3) 164 | webrick (~> 1.8) 165 | rails (7.1.1) 166 | actioncable (= 7.1.1) 167 | actionmailbox (= 7.1.1) 168 | actionmailer (= 7.1.1) 169 | actionpack (= 7.1.1) 170 | actiontext (= 7.1.1) 171 | actionview (= 7.1.1) 172 | activejob (= 7.1.1) 173 | activemodel (= 7.1.1) 174 | activerecord (= 7.1.1) 175 | activestorage (= 7.1.1) 176 | activesupport (= 7.1.1) 177 | bundler (>= 1.15.0) 178 | railties (= 7.1.1) 179 | rails-dom-testing (2.2.0) 180 | activesupport (>= 5.0.0) 181 | minitest 182 | nokogiri (>= 1.6) 183 | rails-html-sanitizer (1.6.0) 184 | loofah (~> 2.21) 185 | nokogiri (~> 1.14) 186 | railties (7.1.1) 187 | actionpack (= 7.1.1) 188 | activesupport (= 7.1.1) 189 | irb 190 | rackup (>= 1.0.0) 191 | rake (>= 12.2) 192 | thor (~> 1.0, >= 1.2.2) 193 | zeitwerk (~> 2.6) 194 | rainbow (3.1.1) 195 | rake (13.0.6) 196 | rdoc (6.5.0) 197 | psych (>= 4.0.0) 198 | regexp_parser (2.8.2) 199 | reline (0.3.9) 200 | io-console (~> 0.5) 201 | rexml (3.2.6) 202 | rubocop (1.57.1) 203 | base64 (~> 0.1.1) 204 | json (~> 2.3) 205 | language_server-protocol (>= 3.17.0) 206 | parallel (~> 1.10) 207 | parser (>= 3.2.2.4) 208 | rainbow (>= 2.2.2, < 4.0) 209 | regexp_parser (>= 1.8, < 3.0) 210 | rexml (>= 3.2.5, < 4.0) 211 | rubocop-ast (>= 1.28.1, < 2.0) 212 | ruby-progressbar (~> 1.7) 213 | unicode-display_width (>= 2.4.0, < 3.0) 214 | rubocop-ast (1.29.0) 215 | parser (>= 3.2.1.0) 216 | ruby-progressbar (1.13.0) 217 | ruby2_keywords (0.0.5) 218 | sprockets (4.2.1) 219 | concurrent-ruby (~> 1.0) 220 | rack (>= 2.2.4, < 4) 221 | sprockets-rails (3.4.2) 222 | actionpack (>= 5.2) 223 | activesupport (>= 5.2) 224 | sprockets (>= 3.0.0) 225 | sqlite3 (1.6.7-arm64-darwin) 226 | sqlite3 (1.6.7-x86_64-linux) 227 | sshkit (1.21.5) 228 | net-scp (>= 1.1.2) 229 | net-ssh (>= 2.8.0) 230 | stringio (3.0.8) 231 | thor (1.3.0) 232 | timeout (0.4.0) 233 | turbo-rails (1.5.0) 234 | actionpack (>= 6.0.0) 235 | activejob (>= 6.0.0) 236 | railties (>= 6.0.0) 237 | tzinfo (2.0.6) 238 | concurrent-ruby (~> 1.0) 239 | unicode-display_width (2.5.0) 240 | webrick (1.8.1) 241 | websocket-driver (0.7.6) 242 | websocket-extensions (>= 0.1.0) 243 | websocket-extensions (0.1.5) 244 | zeitwerk (2.6.12) 245 | 246 | PLATFORMS 247 | arm64-darwin-23 248 | x86_64-linux 249 | 250 | DEPENDENCIES 251 | deployed! 252 | kamal 253 | puma 254 | rubocop 255 | sprockets-rails 256 | sqlite3 257 | turbo-rails (~> 1.5) 258 | 259 | BUNDLED WITH 260 | 2.4.20 261 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | 2023 Copyright Simon Chiu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Procfile.dev: -------------------------------------------------------------------------------- 1 | tailwind: npx tailwindcss -i ./app/assets/stylesheets/deployed/src/input.css -o ./app/assets/stylesheets/deployed/deployed.css --watch 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deployed 2 | 3 | [![Gem Version](https://badge.fury.io/rb/deployed.svg)](https://badge.fury.io/rb/deployed) 4 | 5 | Deployed is a web interface for the deployment library, [Kamal](https://kamal-deploy.org). 6 | 7 | Here is a quick video demo: https://x.com/geetfun/status/1716109581619744781?s=20 8 | 9 | ## Requirements 10 | 11 | Ruby on Rails 12 | 13 | ## Installation 14 | Add this line to your application's Gemfile: 15 | 16 | ```ruby 17 | group :development do 18 | gem 'kamal' 19 | gem 'deployed' 20 | end 21 | ``` 22 | 23 | ## Usage 24 | 25 | Add the following to your app's routes file: 26 | 27 | ```ruby 28 | Rails.application.routes.draw do 29 | if Rails.env.development? && defined?(Deployed) 30 | mount(Deployed::Engine => '/deployed') 31 | end 32 | 33 | # Your other routes... 34 | end 35 | ``` 36 | 37 | Next, head to `http://localhost:3000/deployed` 38 | 39 | ## Development 40 | 41 | Run `bin/setup` to bootstrap the development environment. 42 | 43 | To run tests: `bundle exec rake app:test`. Currently there are no tests, but some will be added soon. 44 | 45 | ## License 46 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 47 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/setup" 2 | 3 | APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__) 4 | load "rails/tasks/engine.rake" 5 | 6 | load "rails/tasks/statistics.rake" 7 | 8 | require "bundler/gem_tasks" 9 | -------------------------------------------------------------------------------- /app/assets/config/deployed_manifest.js: -------------------------------------------------------------------------------- 1 | //= link_directory ../stylesheets/deployed .css 2 | -------------------------------------------------------------------------------- /app/assets/images/deployed/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/app/assets/images/deployed/.keep -------------------------------------------------------------------------------- /app/assets/javascripts/deployed/application.js: -------------------------------------------------------------------------------- 1 | import 'https://cdn.skypack.dev/@hotwired/turbo-rails' 2 | import 'https://cdn.skypack.dev/alpine-turbo-drive-adapter' 3 | import Alpine from 'https://cdn.skypack.dev/alpinejs' 4 | window.Alpine = Alpine 5 | Alpine.start() 6 | 7 | const endMarker = '[Deployed Rails] End' 8 | const outputContainerEl = document.getElementById('deploy-output') 9 | const spinnerEl = document.getElementById('spinner') 10 | 11 | window.pipeLogs = () => { 12 | spinnerEl.classList.remove('hidden') 13 | window.logEventSource = new EventSource(`/deployed/log_output`) 14 | 15 | window.logEventSource.onmessage = (event) => { 16 | if (!Alpine.store('process').running) { 17 | window.logEventSource.close() 18 | } else { 19 | if (event.data.includes("[Deployed] End")) { 20 | window.stopPipeLogs() 21 | } else { 22 | outputContainerEl.innerHTML += event.data 23 | } 24 | } 25 | 26 | outputContainerEl.scrollIntoView({ behavior: "smooth", block: "end" }) 27 | spinnerEl.scrollIntoView({ behavior: "smooth", block: "end" }) 28 | } 29 | } 30 | 31 | window.stopPipeLogs = () => { 32 | if (typeof(window.logEventSource) !== 'undefined') { 33 | window.logEventSource.close() 34 | } 35 | spinnerEl.classList.add('hidden') 36 | Alpine.store('process').stop() 37 | } 38 | 39 | window.execDeployed = (commandToRun) => { 40 | Alpine.store('process').start() 41 | 42 | let endpoint = `/deployed/execute` 43 | 44 | // Create a data object with your payload (in this case, a command) 45 | const data = { command: commandToRun } 46 | 47 | // Define the fetch options for the POST request 48 | const options = { 49 | method: 'POST', 50 | headers: { 'Content-Type': 'application/json' }, 51 | body: JSON.stringify(data) 52 | } 53 | 54 | // Perform the POST request using the fetch API 55 | fetch(endpoint, options) 56 | .then(response => { 57 | if (response.ok) { 58 | outputContainerEl.innerHTML += "
" 59 | outputContainerEl.innerHTML += `
[Deployed] Command Received: kamal ${commandToRun}
` 60 | window.pipeLogs() 61 | return response.json(); // Parse the JSON response if needed 62 | } else { 63 | throw new Error('Network response was not ok'); 64 | } 65 | }) 66 | .catch(error => { 67 | console.error('Fetch error:', error) 68 | }) 69 | } 70 | 71 | window.abortDeployed = () => { 72 | // Let the frontend know we're starting 73 | Alpine.store('process').startAbort() 74 | 75 | let outputContainerEl = document.getElementById('deploy-output') 76 | let spinnerEl = document.getElementById('spinner') 77 | 78 | outputContainerEl.innerHTML += `
Aborting...
` 79 | 80 | let endpoint = `/deployed/cancel` 81 | 82 | const options = { 83 | method: 'POST', 84 | headers: { 'Content-Type': 'application/json' } 85 | } 86 | 87 | // Perform the POST request using the fetch API 88 | fetch(endpoint, options) 89 | .then(response => { 90 | if (response.ok) { 91 | window.stopPipeLogs() 92 | Alpine.store('process').stop() 93 | Alpine.store('process').resetAbort() 94 | return response.json(); // Parse the JSON response if needed 95 | } else { 96 | throw new Error('Network response was not ok'); 97 | } 98 | }) 99 | .then(data => { 100 | console.log(data) 101 | outputContainerEl.innerHTML += `
Aborted process with PID ${data.message}
` 102 | }) 103 | .catch(error => { 104 | console.error('Fetch error:', error) 105 | }) 106 | } 107 | 108 | // Some other JS that probably should be refactored at some point... 109 | document.addEventListener('DOMContentLoaded', (event) => { 110 | // Hackish way to refresh git status with turbo frames 111 | // setInterval(() => { 112 | // document.getElementById('git-status').reload() 113 | // }, 2500) 114 | 115 | // Resizing functionality 116 | let isResizing = false 117 | let initialY 118 | let initialHeight 119 | 120 | const deployOutputContainer = document.getElementById('deploy-output-container') 121 | const resizeHandle = document.getElementById('resize-handle') 122 | 123 | const startResize = (e) => { 124 | isResizing = true 125 | initialY = e.clientY 126 | initialHeight = deployOutputContainer.clientHeight 127 | } 128 | 129 | const stopResize = () => { isResizing = false } 130 | 131 | const resize = (e) => { 132 | if (isResizing) { 133 | const deltaY = initialY - e.clientY 134 | deployOutputContainer.style.height = initialHeight + deltaY + 'px' 135 | } 136 | } 137 | 138 | resizeHandle.addEventListener('mousedown', startResize) 139 | document.addEventListener('mousemove', resize) 140 | document.addEventListener('mouseup', stopResize) 141 | }) 142 | -------------------------------------------------------------------------------- /app/assets/stylesheets/deployed/deployed.css: -------------------------------------------------------------------------------- 1 | /* 2 | ! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com 3 | */ 4 | 5 | /* 6 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 7 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) 8 | */ 9 | 10 | *, 11 | ::before, 12 | ::after { 13 | box-sizing: border-box; 14 | /* 1 */ 15 | border-width: 0; 16 | /* 2 */ 17 | border-style: solid; 18 | /* 2 */ 19 | border-color: #e5e7eb; 20 | /* 2 */ 21 | } 22 | 23 | ::before, 24 | ::after { 25 | --tw-content: ''; 26 | } 27 | 28 | /* 29 | 1. Use a consistent sensible line-height in all browsers. 30 | 2. Prevent adjustments of font size after orientation changes in iOS. 31 | 3. Use a more readable tab size. 32 | 4. Use the user's configured `sans` font-family by default. 33 | 5. Use the user's configured `sans` font-feature-settings by default. 34 | 6. Use the user's configured `sans` font-variation-settings by default. 35 | */ 36 | 37 | html { 38 | line-height: 1.5; 39 | /* 1 */ 40 | -webkit-text-size-adjust: 100%; 41 | /* 2 */ 42 | -moz-tab-size: 4; 43 | /* 3 */ 44 | -o-tab-size: 4; 45 | tab-size: 4; 46 | /* 3 */ 47 | font-family: Inter var, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 48 | /* 4 */ 49 | font-feature-settings: normal; 50 | /* 5 */ 51 | font-variation-settings: normal; 52 | /* 6 */ 53 | } 54 | 55 | /* 56 | 1. Remove the margin in all browsers. 57 | 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. 58 | */ 59 | 60 | body { 61 | margin: 0; 62 | /* 1 */ 63 | line-height: inherit; 64 | /* 2 */ 65 | } 66 | 67 | /* 68 | 1. Add the correct height in Firefox. 69 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 70 | 3. Ensure horizontal rules are visible by default. 71 | */ 72 | 73 | hr { 74 | height: 0; 75 | /* 1 */ 76 | color: inherit; 77 | /* 2 */ 78 | border-top-width: 1px; 79 | /* 3 */ 80 | } 81 | 82 | /* 83 | Add the correct text decoration in Chrome, Edge, and Safari. 84 | */ 85 | 86 | abbr:where([title]) { 87 | -webkit-text-decoration: underline dotted; 88 | text-decoration: underline dotted; 89 | } 90 | 91 | /* 92 | Remove the default font size and weight for headings. 93 | */ 94 | 95 | h1, 96 | h2, 97 | h3, 98 | h4, 99 | h5, 100 | h6 { 101 | font-size: inherit; 102 | font-weight: inherit; 103 | } 104 | 105 | /* 106 | Reset links to optimize for opt-in styling instead of opt-out. 107 | */ 108 | 109 | a { 110 | color: inherit; 111 | text-decoration: inherit; 112 | } 113 | 114 | /* 115 | Add the correct font weight in Edge and Safari. 116 | */ 117 | 118 | b, 119 | strong { 120 | font-weight: bolder; 121 | } 122 | 123 | /* 124 | 1. Use the user's configured `mono` font family by default. 125 | 2. Correct the odd `em` font sizing in all browsers. 126 | */ 127 | 128 | code, 129 | kbd, 130 | samp, 131 | pre { 132 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 133 | /* 1 */ 134 | font-size: 1em; 135 | /* 2 */ 136 | } 137 | 138 | /* 139 | Add the correct font size in all browsers. 140 | */ 141 | 142 | small { 143 | font-size: 80%; 144 | } 145 | 146 | /* 147 | Prevent `sub` and `sup` elements from affecting the line height in all browsers. 148 | */ 149 | 150 | sub, 151 | sup { 152 | font-size: 75%; 153 | line-height: 0; 154 | position: relative; 155 | vertical-align: baseline; 156 | } 157 | 158 | sub { 159 | bottom: -0.25em; 160 | } 161 | 162 | sup { 163 | top: -0.5em; 164 | } 165 | 166 | /* 167 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 168 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 169 | 3. Remove gaps between table borders by default. 170 | */ 171 | 172 | table { 173 | text-indent: 0; 174 | /* 1 */ 175 | border-color: inherit; 176 | /* 2 */ 177 | border-collapse: collapse; 178 | /* 3 */ 179 | } 180 | 181 | /* 182 | 1. Change the font styles in all browsers. 183 | 2. Remove the margin in Firefox and Safari. 184 | 3. Remove default padding in all browsers. 185 | */ 186 | 187 | button, 188 | input, 189 | optgroup, 190 | select, 191 | textarea { 192 | font-family: inherit; 193 | /* 1 */ 194 | font-feature-settings: inherit; 195 | /* 1 */ 196 | font-variation-settings: inherit; 197 | /* 1 */ 198 | font-size: 100%; 199 | /* 1 */ 200 | font-weight: inherit; 201 | /* 1 */ 202 | line-height: inherit; 203 | /* 1 */ 204 | color: inherit; 205 | /* 1 */ 206 | margin: 0; 207 | /* 2 */ 208 | padding: 0; 209 | /* 3 */ 210 | } 211 | 212 | /* 213 | Remove the inheritance of text transform in Edge and Firefox. 214 | */ 215 | 216 | button, 217 | select { 218 | text-transform: none; 219 | } 220 | 221 | /* 222 | 1. Correct the inability to style clickable types in iOS and Safari. 223 | 2. Remove default button styles. 224 | */ 225 | 226 | button, 227 | [type='button'], 228 | [type='reset'], 229 | [type='submit'] { 230 | -webkit-appearance: button; 231 | /* 1 */ 232 | background-color: transparent; 233 | /* 2 */ 234 | background-image: none; 235 | /* 2 */ 236 | } 237 | 238 | /* 239 | Use the modern Firefox focus style for all focusable elements. 240 | */ 241 | 242 | :-moz-focusring { 243 | outline: auto; 244 | } 245 | 246 | /* 247 | Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) 248 | */ 249 | 250 | :-moz-ui-invalid { 251 | box-shadow: none; 252 | } 253 | 254 | /* 255 | Add the correct vertical alignment in Chrome and Firefox. 256 | */ 257 | 258 | progress { 259 | vertical-align: baseline; 260 | } 261 | 262 | /* 263 | Correct the cursor style of increment and decrement buttons in Safari. 264 | */ 265 | 266 | ::-webkit-inner-spin-button, 267 | ::-webkit-outer-spin-button { 268 | height: auto; 269 | } 270 | 271 | /* 272 | 1. Correct the odd appearance in Chrome and Safari. 273 | 2. Correct the outline style in Safari. 274 | */ 275 | 276 | [type='search'] { 277 | -webkit-appearance: textfield; 278 | /* 1 */ 279 | outline-offset: -2px; 280 | /* 2 */ 281 | } 282 | 283 | /* 284 | Remove the inner padding in Chrome and Safari on macOS. 285 | */ 286 | 287 | ::-webkit-search-decoration { 288 | -webkit-appearance: none; 289 | } 290 | 291 | /* 292 | 1. Correct the inability to style clickable types in iOS and Safari. 293 | 2. Change font properties to `inherit` in Safari. 294 | */ 295 | 296 | ::-webkit-file-upload-button { 297 | -webkit-appearance: button; 298 | /* 1 */ 299 | font: inherit; 300 | /* 2 */ 301 | } 302 | 303 | /* 304 | Add the correct display in Chrome and Safari. 305 | */ 306 | 307 | summary { 308 | display: list-item; 309 | } 310 | 311 | /* 312 | Removes the default spacing and border for appropriate elements. 313 | */ 314 | 315 | blockquote, 316 | dl, 317 | dd, 318 | h1, 319 | h2, 320 | h3, 321 | h4, 322 | h5, 323 | h6, 324 | hr, 325 | figure, 326 | p, 327 | pre { 328 | margin: 0; 329 | } 330 | 331 | fieldset { 332 | margin: 0; 333 | padding: 0; 334 | } 335 | 336 | legend { 337 | padding: 0; 338 | } 339 | 340 | ol, 341 | ul, 342 | menu { 343 | list-style: none; 344 | margin: 0; 345 | padding: 0; 346 | } 347 | 348 | /* 349 | Reset default styling for dialogs. 350 | */ 351 | 352 | dialog { 353 | padding: 0; 354 | } 355 | 356 | /* 357 | Prevent resizing textareas horizontally by default. 358 | */ 359 | 360 | textarea { 361 | resize: vertical; 362 | } 363 | 364 | /* 365 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) 366 | 2. Set the default placeholder color to the user's configured gray 400 color. 367 | */ 368 | 369 | input::-moz-placeholder, textarea::-moz-placeholder { 370 | opacity: 1; 371 | /* 1 */ 372 | color: #9ca3af; 373 | /* 2 */ 374 | } 375 | 376 | input::placeholder, 377 | textarea::placeholder { 378 | opacity: 1; 379 | /* 1 */ 380 | color: #9ca3af; 381 | /* 2 */ 382 | } 383 | 384 | /* 385 | Set the default cursor for buttons. 386 | */ 387 | 388 | button, 389 | [role="button"] { 390 | cursor: pointer; 391 | } 392 | 393 | /* 394 | Make sure disabled buttons don't get the pointer cursor. 395 | */ 396 | 397 | :disabled { 398 | cursor: default; 399 | } 400 | 401 | /* 402 | 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) 403 | 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) 404 | This can trigger a poorly considered lint error in some tools but is included by design. 405 | */ 406 | 407 | img, 408 | svg, 409 | video, 410 | canvas, 411 | audio, 412 | iframe, 413 | embed, 414 | object { 415 | display: block; 416 | /* 1 */ 417 | vertical-align: middle; 418 | /* 2 */ 419 | } 420 | 421 | /* 422 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) 423 | */ 424 | 425 | img, 426 | video { 427 | max-width: 100%; 428 | height: auto; 429 | } 430 | 431 | /* Make elements with the HTML hidden attribute stay hidden by default */ 432 | 433 | [hidden] { 434 | display: none; 435 | } 436 | 437 | [type='text'],input:where(:not([type])),[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select { 438 | -webkit-appearance: none; 439 | -moz-appearance: none; 440 | appearance: none; 441 | background-color: #fff; 442 | border-color: #6b7280; 443 | border-width: 1px; 444 | border-radius: 0px; 445 | padding-top: 0.5rem; 446 | padding-right: 0.75rem; 447 | padding-bottom: 0.5rem; 448 | padding-left: 0.75rem; 449 | font-size: 1rem; 450 | line-height: 1.5rem; 451 | --tw-shadow: 0 0 #0000; 452 | } 453 | 454 | [type='text']:focus, input:where(:not([type])):focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus { 455 | outline: 2px solid transparent; 456 | outline-offset: 2px; 457 | --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); 458 | --tw-ring-offset-width: 0px; 459 | --tw-ring-offset-color: #fff; 460 | --tw-ring-color: #2563eb; 461 | --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); 462 | --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); 463 | box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); 464 | border-color: #2563eb; 465 | } 466 | 467 | input::-moz-placeholder, textarea::-moz-placeholder { 468 | color: #6b7280; 469 | opacity: 1; 470 | } 471 | 472 | input::placeholder,textarea::placeholder { 473 | color: #6b7280; 474 | opacity: 1; 475 | } 476 | 477 | ::-webkit-datetime-edit-fields-wrapper { 478 | padding: 0; 479 | } 480 | 481 | ::-webkit-date-and-time-value { 482 | min-height: 1.5em; 483 | text-align: inherit; 484 | } 485 | 486 | ::-webkit-datetime-edit { 487 | display: inline-flex; 488 | } 489 | 490 | ::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field { 491 | padding-top: 0; 492 | padding-bottom: 0; 493 | } 494 | 495 | select { 496 | background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); 497 | background-position: right 0.5rem center; 498 | background-repeat: no-repeat; 499 | background-size: 1.5em 1.5em; 500 | padding-right: 2.5rem; 501 | -webkit-print-color-adjust: exact; 502 | print-color-adjust: exact; 503 | } 504 | 505 | [multiple],[size]:where(select:not([size="1"])) { 506 | background-image: initial; 507 | background-position: initial; 508 | background-repeat: unset; 509 | background-size: initial; 510 | padding-right: 0.75rem; 511 | -webkit-print-color-adjust: unset; 512 | print-color-adjust: unset; 513 | } 514 | 515 | [type='checkbox'],[type='radio'] { 516 | -webkit-appearance: none; 517 | -moz-appearance: none; 518 | appearance: none; 519 | padding: 0; 520 | -webkit-print-color-adjust: exact; 521 | print-color-adjust: exact; 522 | display: inline-block; 523 | vertical-align: middle; 524 | background-origin: border-box; 525 | -webkit-user-select: none; 526 | -moz-user-select: none; 527 | user-select: none; 528 | flex-shrink: 0; 529 | height: 1rem; 530 | width: 1rem; 531 | color: #2563eb; 532 | background-color: #fff; 533 | border-color: #6b7280; 534 | border-width: 1px; 535 | --tw-shadow: 0 0 #0000; 536 | } 537 | 538 | [type='checkbox'] { 539 | border-radius: 0px; 540 | } 541 | 542 | [type='radio'] { 543 | border-radius: 100%; 544 | } 545 | 546 | [type='checkbox']:focus,[type='radio']:focus { 547 | outline: 2px solid transparent; 548 | outline-offset: 2px; 549 | --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); 550 | --tw-ring-offset-width: 2px; 551 | --tw-ring-offset-color: #fff; 552 | --tw-ring-color: #2563eb; 553 | --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); 554 | --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); 555 | box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); 556 | } 557 | 558 | [type='checkbox']:checked,[type='radio']:checked { 559 | border-color: transparent; 560 | background-color: currentColor; 561 | background-size: 100% 100%; 562 | background-position: center; 563 | background-repeat: no-repeat; 564 | } 565 | 566 | [type='checkbox']:checked { 567 | background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); 568 | } 569 | 570 | [type='radio']:checked { 571 | background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); 572 | } 573 | 574 | [type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus { 575 | border-color: transparent; 576 | background-color: currentColor; 577 | } 578 | 579 | [type='checkbox']:indeterminate { 580 | background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); 581 | border-color: transparent; 582 | background-color: currentColor; 583 | background-size: 100% 100%; 584 | background-position: center; 585 | background-repeat: no-repeat; 586 | } 587 | 588 | [type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus { 589 | border-color: transparent; 590 | background-color: currentColor; 591 | } 592 | 593 | [type='file'] { 594 | background: unset; 595 | border-color: inherit; 596 | border-width: 0; 597 | border-radius: 0; 598 | padding: 0; 599 | font-size: unset; 600 | line-height: inherit; 601 | } 602 | 603 | [type='file']:focus { 604 | outline: 1px solid ButtonText; 605 | outline: 1px auto -webkit-focus-ring-color; 606 | } 607 | 608 | *, ::before, ::after { 609 | --tw-border-spacing-x: 0; 610 | --tw-border-spacing-y: 0; 611 | --tw-translate-x: 0; 612 | --tw-translate-y: 0; 613 | --tw-rotate: 0; 614 | --tw-skew-x: 0; 615 | --tw-skew-y: 0; 616 | --tw-scale-x: 1; 617 | --tw-scale-y: 1; 618 | --tw-pan-x: ; 619 | --tw-pan-y: ; 620 | --tw-pinch-zoom: ; 621 | --tw-scroll-snap-strictness: proximity; 622 | --tw-gradient-from-position: ; 623 | --tw-gradient-via-position: ; 624 | --tw-gradient-to-position: ; 625 | --tw-ordinal: ; 626 | --tw-slashed-zero: ; 627 | --tw-numeric-figure: ; 628 | --tw-numeric-spacing: ; 629 | --tw-numeric-fraction: ; 630 | --tw-ring-inset: ; 631 | --tw-ring-offset-width: 0px; 632 | --tw-ring-offset-color: #fff; 633 | --tw-ring-color: rgb(59 130 246 / 0.5); 634 | --tw-ring-offset-shadow: 0 0 #0000; 635 | --tw-ring-shadow: 0 0 #0000; 636 | --tw-shadow: 0 0 #0000; 637 | --tw-shadow-colored: 0 0 #0000; 638 | --tw-blur: ; 639 | --tw-brightness: ; 640 | --tw-contrast: ; 641 | --tw-grayscale: ; 642 | --tw-hue-rotate: ; 643 | --tw-invert: ; 644 | --tw-saturate: ; 645 | --tw-sepia: ; 646 | --tw-drop-shadow: ; 647 | --tw-backdrop-blur: ; 648 | --tw-backdrop-brightness: ; 649 | --tw-backdrop-contrast: ; 650 | --tw-backdrop-grayscale: ; 651 | --tw-backdrop-hue-rotate: ; 652 | --tw-backdrop-invert: ; 653 | --tw-backdrop-opacity: ; 654 | --tw-backdrop-saturate: ; 655 | --tw-backdrop-sepia: ; 656 | } 657 | 658 | ::backdrop { 659 | --tw-border-spacing-x: 0; 660 | --tw-border-spacing-y: 0; 661 | --tw-translate-x: 0; 662 | --tw-translate-y: 0; 663 | --tw-rotate: 0; 664 | --tw-skew-x: 0; 665 | --tw-skew-y: 0; 666 | --tw-scale-x: 1; 667 | --tw-scale-y: 1; 668 | --tw-pan-x: ; 669 | --tw-pan-y: ; 670 | --tw-pinch-zoom: ; 671 | --tw-scroll-snap-strictness: proximity; 672 | --tw-gradient-from-position: ; 673 | --tw-gradient-via-position: ; 674 | --tw-gradient-to-position: ; 675 | --tw-ordinal: ; 676 | --tw-slashed-zero: ; 677 | --tw-numeric-figure: ; 678 | --tw-numeric-spacing: ; 679 | --tw-numeric-fraction: ; 680 | --tw-ring-inset: ; 681 | --tw-ring-offset-width: 0px; 682 | --tw-ring-offset-color: #fff; 683 | --tw-ring-color: rgb(59 130 246 / 0.5); 684 | --tw-ring-offset-shadow: 0 0 #0000; 685 | --tw-ring-shadow: 0 0 #0000; 686 | --tw-shadow: 0 0 #0000; 687 | --tw-shadow-colored: 0 0 #0000; 688 | --tw-blur: ; 689 | --tw-brightness: ; 690 | --tw-contrast: ; 691 | --tw-grayscale: ; 692 | --tw-hue-rotate: ; 693 | --tw-invert: ; 694 | --tw-saturate: ; 695 | --tw-sepia: ; 696 | --tw-drop-shadow: ; 697 | --tw-backdrop-blur: ; 698 | --tw-backdrop-brightness: ; 699 | --tw-backdrop-contrast: ; 700 | --tw-backdrop-grayscale: ; 701 | --tw-backdrop-hue-rotate: ; 702 | --tw-backdrop-invert: ; 703 | --tw-backdrop-opacity: ; 704 | --tw-backdrop-saturate: ; 705 | --tw-backdrop-sepia: ; 706 | } 707 | 708 | .fixed { 709 | position: fixed; 710 | } 711 | 712 | .absolute { 713 | position: absolute; 714 | } 715 | 716 | .relative { 717 | position: relative; 718 | } 719 | 720 | .inset-0 { 721 | inset: 0px; 722 | } 723 | 724 | .left-0 { 725 | left: 0px; 726 | } 727 | 728 | .right-0 { 729 | right: 0px; 730 | } 731 | 732 | .right-5 { 733 | right: 1.25rem; 734 | } 735 | 736 | .right-\[40px\] { 737 | right: 40px; 738 | } 739 | 740 | .top-0 { 741 | top: 0px; 742 | } 743 | 744 | .top-16 { 745 | top: 4rem; 746 | } 747 | 748 | .top-\[-6px\] { 749 | top: -6px; 750 | } 751 | 752 | .top-\[50px\] { 753 | top: 50px; 754 | } 755 | 756 | .z-10 { 757 | z-index: 10; 758 | } 759 | 760 | .mx-auto { 761 | margin-left: auto; 762 | margin-right: auto; 763 | } 764 | 765 | .my-8 { 766 | margin-top: 2rem; 767 | margin-bottom: 2rem; 768 | } 769 | 770 | .-ml-1 { 771 | margin-left: -0.25rem; 772 | } 773 | 774 | .mb-5 { 775 | margin-bottom: 1.25rem; 776 | } 777 | 778 | .mr-2 { 779 | margin-right: 0.5rem; 780 | } 781 | 782 | .mt-1 { 783 | margin-top: 0.25rem; 784 | } 785 | 786 | .mt-2 { 787 | margin-top: 0.5rem; 788 | } 789 | 790 | .mt-4 { 791 | margin-top: 1rem; 792 | } 793 | 794 | .mt-5 { 795 | margin-top: 1.25rem; 796 | } 797 | 798 | .block { 799 | display: block; 800 | } 801 | 802 | .flex { 803 | display: flex; 804 | } 805 | 806 | .inline-flex { 807 | display: inline-flex; 808 | } 809 | 810 | .grid { 811 | display: grid; 812 | } 813 | 814 | .hidden { 815 | display: none; 816 | } 817 | 818 | .h-5 { 819 | height: 1.25rem; 820 | } 821 | 822 | .h-6 { 823 | height: 1.5rem; 824 | } 825 | 826 | .h-\[12px\] { 827 | height: 12px; 828 | } 829 | 830 | .h-\[200px\] { 831 | height: 200px; 832 | } 833 | 834 | .h-screen { 835 | height: 100vh; 836 | } 837 | 838 | .min-h-full { 839 | min-height: 100%; 840 | } 841 | 842 | .w-5 { 843 | width: 1.25rem; 844 | } 845 | 846 | .w-6 { 847 | width: 1.5rem; 848 | } 849 | 850 | .w-full { 851 | width: 100%; 852 | } 853 | 854 | .w-screen { 855 | width: 100vw; 856 | } 857 | 858 | .max-w-5xl { 859 | max-width: 64rem; 860 | } 861 | 862 | .max-w-lg { 863 | max-width: 32rem; 864 | } 865 | 866 | .flex-1 { 867 | flex: 1 1 0%; 868 | } 869 | 870 | .translate-y-0 { 871 | --tw-translate-y: 0px; 872 | transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 873 | } 874 | 875 | .translate-y-4 { 876 | --tw-translate-y: 1rem; 877 | transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 878 | } 879 | 880 | .transform { 881 | transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 882 | } 883 | 884 | @keyframes pulse { 885 | 50% { 886 | opacity: .5; 887 | } 888 | } 889 | 890 | .animate-pulse { 891 | animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; 892 | } 893 | 894 | @keyframes spin { 895 | to { 896 | transform: rotate(360deg); 897 | } 898 | } 899 | 900 | .animate-spin { 901 | animation: spin 1s linear infinite; 902 | } 903 | 904 | .resize { 905 | resize: both; 906 | } 907 | 908 | .grid-cols-1 { 909 | grid-template-columns: repeat(1, minmax(0, 1fr)); 910 | } 911 | 912 | .flex-col { 913 | flex-direction: column; 914 | } 915 | 916 | .items-center { 917 | align-items: center; 918 | } 919 | 920 | .justify-start { 921 | justify-content: flex-start; 922 | } 923 | 924 | .justify-center { 925 | justify-content: center; 926 | } 927 | 928 | .gap-x-8 { 929 | -moz-column-gap: 2rem; 930 | column-gap: 2rem; 931 | } 932 | 933 | .gap-y-4 { 934 | row-gap: 1rem; 935 | } 936 | 937 | .space-x-1 > :not([hidden]) ~ :not([hidden]) { 938 | --tw-space-x-reverse: 0; 939 | margin-right: calc(0.25rem * var(--tw-space-x-reverse)); 940 | margin-left: calc(0.25rem * calc(1 - var(--tw-space-x-reverse))); 941 | } 942 | 943 | .space-x-2 > :not([hidden]) ~ :not([hidden]) { 944 | --tw-space-x-reverse: 0; 945 | margin-right: calc(0.5rem * var(--tw-space-x-reverse)); 946 | margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); 947 | } 948 | 949 | .space-y-10 > :not([hidden]) ~ :not([hidden]) { 950 | --tw-space-y-reverse: 0; 951 | margin-top: calc(2.5rem * calc(1 - var(--tw-space-y-reverse))); 952 | margin-bottom: calc(2.5rem * var(--tw-space-y-reverse)); 953 | } 954 | 955 | .space-y-4 > :not([hidden]) ~ :not([hidden]) { 956 | --tw-space-y-reverse: 0; 957 | margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); 958 | margin-bottom: calc(1rem * var(--tw-space-y-reverse)); 959 | } 960 | 961 | .divide-y > :not([hidden]) ~ :not([hidden]) { 962 | --tw-divide-y-reverse: 0; 963 | border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); 964 | border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); 965 | } 966 | 967 | .divide-gray-100 > :not([hidden]) ~ :not([hidden]) { 968 | --tw-divide-opacity: 1; 969 | border-color: rgb(243 244 246 / var(--tw-divide-opacity)); 970 | } 971 | 972 | .divide-gray-900\/10 > :not([hidden]) ~ :not([hidden]) { 973 | border-color: rgb(17 24 39 / 0.1); 974 | } 975 | 976 | .overflow-hidden { 977 | overflow: hidden; 978 | } 979 | 980 | .overflow-scroll { 981 | overflow: scroll; 982 | } 983 | 984 | .overflow-y-auto { 985 | overflow-y: auto; 986 | } 987 | 988 | .rounded-full { 989 | border-radius: 9999px; 990 | } 991 | 992 | .rounded-lg { 993 | border-radius: 0.5rem; 994 | } 995 | 996 | .rounded-md { 997 | border-radius: 0.375rem; 998 | } 999 | 1000 | .rounded-xl { 1001 | border-radius: 0.75rem; 1002 | } 1003 | 1004 | .border { 1005 | border-width: 1px; 1006 | } 1007 | 1008 | .border-b-4 { 1009 | border-bottom-width: 4px; 1010 | } 1011 | 1012 | .border-t { 1013 | border-top-width: 1px; 1014 | } 1015 | 1016 | .border-slate-200 { 1017 | --tw-border-opacity: 1; 1018 | border-color: rgb(226 232 240 / var(--tw-border-opacity)); 1019 | } 1020 | 1021 | .border-slate-300 { 1022 | --tw-border-opacity: 1; 1023 | border-color: rgb(203 213 225 / var(--tw-border-opacity)); 1024 | } 1025 | 1026 | .bg-gray-500 { 1027 | --tw-bg-opacity: 1; 1028 | background-color: rgb(107 114 128 / var(--tw-bg-opacity)); 1029 | } 1030 | 1031 | .bg-red-400 { 1032 | --tw-bg-opacity: 1; 1033 | background-color: rgb(248 113 113 / var(--tw-bg-opacity)); 1034 | } 1035 | 1036 | .bg-red-600 { 1037 | --tw-bg-opacity: 1; 1038 | background-color: rgb(220 38 38 / var(--tw-bg-opacity)); 1039 | } 1040 | 1041 | .bg-sky-600 { 1042 | --tw-bg-opacity: 1; 1043 | background-color: rgb(2 132 199 / var(--tw-bg-opacity)); 1044 | } 1045 | 1046 | .bg-slate-100 { 1047 | --tw-bg-opacity: 1; 1048 | background-color: rgb(241 245 249 / var(--tw-bg-opacity)); 1049 | } 1050 | 1051 | .bg-slate-200 { 1052 | --tw-bg-opacity: 1; 1053 | background-color: rgb(226 232 240 / var(--tw-bg-opacity)); 1054 | } 1055 | 1056 | .bg-slate-700 { 1057 | --tw-bg-opacity: 1; 1058 | background-color: rgb(51 65 85 / var(--tw-bg-opacity)); 1059 | } 1060 | 1061 | .bg-slate-900 { 1062 | --tw-bg-opacity: 1; 1063 | background-color: rgb(15 23 42 / var(--tw-bg-opacity)); 1064 | } 1065 | 1066 | .bg-white { 1067 | --tw-bg-opacity: 1; 1068 | background-color: rgb(255 255 255 / var(--tw-bg-opacity)); 1069 | } 1070 | 1071 | .bg-yellow-400 { 1072 | --tw-bg-opacity: 1; 1073 | background-color: rgb(250 204 21 / var(--tw-bg-opacity)); 1074 | } 1075 | 1076 | .bg-opacity-75 { 1077 | --tw-bg-opacity: 0.75; 1078 | } 1079 | 1080 | .p-4 { 1081 | padding: 1rem; 1082 | } 1083 | 1084 | .p-6 { 1085 | padding: 1.5rem; 1086 | } 1087 | 1088 | .p-8 { 1089 | padding: 2rem; 1090 | } 1091 | 1092 | .px-0 { 1093 | padding-left: 0px; 1094 | padding-right: 0px; 1095 | } 1096 | 1097 | .px-2 { 1098 | padding-left: 0.5rem; 1099 | padding-right: 0.5rem; 1100 | } 1101 | 1102 | .px-3 { 1103 | padding-left: 0.75rem; 1104 | padding-right: 0.75rem; 1105 | } 1106 | 1107 | .px-3\.5 { 1108 | padding-left: 0.875rem; 1109 | padding-right: 0.875rem; 1110 | } 1111 | 1112 | .px-4 { 1113 | padding-left: 1rem; 1114 | padding-right: 1rem; 1115 | } 1116 | 1117 | .px-6 { 1118 | padding-left: 1.5rem; 1119 | padding-right: 1.5rem; 1120 | } 1121 | 1122 | .px-8 { 1123 | padding-left: 2rem; 1124 | padding-right: 2rem; 1125 | } 1126 | 1127 | .py-0 { 1128 | padding-top: 0px; 1129 | padding-bottom: 0px; 1130 | } 1131 | 1132 | .py-0\.5 { 1133 | padding-top: 0.125rem; 1134 | padding-bottom: 0.125rem; 1135 | } 1136 | 1137 | .py-1 { 1138 | padding-top: 0.25rem; 1139 | padding-bottom: 0.25rem; 1140 | } 1141 | 1142 | .py-1\.5 { 1143 | padding-top: 0.375rem; 1144 | padding-bottom: 0.375rem; 1145 | } 1146 | 1147 | .py-2 { 1148 | padding-top: 0.5rem; 1149 | padding-bottom: 0.5rem; 1150 | } 1151 | 1152 | .py-2\.5 { 1153 | padding-top: 0.625rem; 1154 | padding-bottom: 0.625rem; 1155 | } 1156 | 1157 | .py-3 { 1158 | padding-top: 0.75rem; 1159 | padding-bottom: 0.75rem; 1160 | } 1161 | 1162 | .py-4 { 1163 | padding-top: 1rem; 1164 | padding-bottom: 1rem; 1165 | } 1166 | 1167 | .py-6 { 1168 | padding-top: 1.5rem; 1169 | padding-bottom: 1.5rem; 1170 | } 1171 | 1172 | .py-8 { 1173 | padding-top: 2rem; 1174 | padding-bottom: 2rem; 1175 | } 1176 | 1177 | .\!pb-0 { 1178 | padding-bottom: 0px !important; 1179 | } 1180 | 1181 | .\!pt-0 { 1182 | padding-top: 0px !important; 1183 | } 1184 | 1185 | .pb-4 { 1186 | padding-bottom: 1rem; 1187 | } 1188 | 1189 | .pt-10 { 1190 | padding-top: 2.5rem; 1191 | } 1192 | 1193 | .pt-\[56px\] { 1194 | padding-top: 56px; 1195 | } 1196 | 1197 | .text-left { 1198 | text-align: left; 1199 | } 1200 | 1201 | .text-center { 1202 | text-align: center; 1203 | } 1204 | 1205 | .font-mono { 1206 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 1207 | } 1208 | 1209 | .text-3xl { 1210 | font-size: 1.875rem; 1211 | line-height: 2.25rem; 1212 | } 1213 | 1214 | .text-base { 1215 | font-size: 1rem; 1216 | line-height: 1.5rem; 1217 | } 1218 | 1219 | .text-sm { 1220 | font-size: 0.875rem; 1221 | line-height: 1.25rem; 1222 | } 1223 | 1224 | .text-xl { 1225 | font-size: 1.25rem; 1226 | line-height: 1.75rem; 1227 | } 1228 | 1229 | .font-bold { 1230 | font-weight: 700; 1231 | } 1232 | 1233 | .font-medium { 1234 | font-weight: 500; 1235 | } 1236 | 1237 | .font-semibold { 1238 | font-weight: 600; 1239 | } 1240 | 1241 | .italic { 1242 | font-style: italic; 1243 | } 1244 | 1245 | .leading-6 { 1246 | line-height: 1.5rem; 1247 | } 1248 | 1249 | .leading-7 { 1250 | line-height: 1.75rem; 1251 | } 1252 | 1253 | .text-gray-500 { 1254 | --tw-text-opacity: 1; 1255 | color: rgb(107 114 128 / var(--tw-text-opacity)); 1256 | } 1257 | 1258 | .text-gray-700 { 1259 | --tw-text-opacity: 1; 1260 | color: rgb(55 65 81 / var(--tw-text-opacity)); 1261 | } 1262 | 1263 | .text-gray-900 { 1264 | --tw-text-opacity: 1; 1265 | color: rgb(17 24 39 / var(--tw-text-opacity)); 1266 | } 1267 | 1268 | .text-green-400 { 1269 | --tw-text-opacity: 1; 1270 | color: rgb(74 222 128 / var(--tw-text-opacity)); 1271 | } 1272 | 1273 | .text-red-400 { 1274 | --tw-text-opacity: 1; 1275 | color: rgb(248 113 113 / var(--tw-text-opacity)); 1276 | } 1277 | 1278 | .text-red-500 { 1279 | --tw-text-opacity: 1; 1280 | color: rgb(239 68 68 / var(--tw-text-opacity)); 1281 | } 1282 | 1283 | .text-red-900 { 1284 | --tw-text-opacity: 1; 1285 | color: rgb(127 29 29 / var(--tw-text-opacity)); 1286 | } 1287 | 1288 | .text-slate-200 { 1289 | --tw-text-opacity: 1; 1290 | color: rgb(226 232 240 / var(--tw-text-opacity)); 1291 | } 1292 | 1293 | .text-slate-300 { 1294 | --tw-text-opacity: 1; 1295 | color: rgb(203 213 225 / var(--tw-text-opacity)); 1296 | } 1297 | 1298 | .text-slate-400 { 1299 | --tw-text-opacity: 1; 1300 | color: rgb(148 163 184 / var(--tw-text-opacity)); 1301 | } 1302 | 1303 | .text-slate-700 { 1304 | --tw-text-opacity: 1; 1305 | color: rgb(51 65 85 / var(--tw-text-opacity)); 1306 | } 1307 | 1308 | .text-white { 1309 | --tw-text-opacity: 1; 1310 | color: rgb(255 255 255 / var(--tw-text-opacity)); 1311 | } 1312 | 1313 | .text-yellow-400 { 1314 | --tw-text-opacity: 1; 1315 | color: rgb(250 204 21 / var(--tw-text-opacity)); 1316 | } 1317 | 1318 | .text-yellow-900 { 1319 | --tw-text-opacity: 1; 1320 | color: rgb(113 63 18 / var(--tw-text-opacity)); 1321 | } 1322 | 1323 | .opacity-0 { 1324 | opacity: 0; 1325 | } 1326 | 1327 | .opacity-100 { 1328 | opacity: 1; 1329 | } 1330 | 1331 | .opacity-25 { 1332 | opacity: 0.25; 1333 | } 1334 | 1335 | .opacity-50 { 1336 | opacity: 0.5; 1337 | } 1338 | 1339 | .opacity-75 { 1340 | opacity: 0.75; 1341 | } 1342 | 1343 | .shadow-md { 1344 | --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); 1345 | --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); 1346 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 1347 | } 1348 | 1349 | .shadow-sm { 1350 | --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); 1351 | --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); 1352 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 1353 | } 1354 | 1355 | .shadow-xl { 1356 | --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); 1357 | --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color); 1358 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 1359 | } 1360 | 1361 | .ring-1 { 1362 | --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); 1363 | --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); 1364 | box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); 1365 | } 1366 | 1367 | .ring-inset { 1368 | --tw-ring-inset: inset; 1369 | } 1370 | 1371 | .ring-gray-300 { 1372 | --tw-ring-opacity: 1; 1373 | --tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity)); 1374 | } 1375 | 1376 | .ring-gray-900\/5 { 1377 | --tw-ring-color: rgb(17 24 39 / 0.05); 1378 | } 1379 | 1380 | .transition-all { 1381 | transition-property: all; 1382 | transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 1383 | transition-duration: 150ms; 1384 | } 1385 | 1386 | .transition-opacity { 1387 | transition-property: opacity; 1388 | transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 1389 | transition-duration: 150ms; 1390 | } 1391 | 1392 | .duration-200 { 1393 | transition-duration: 200ms; 1394 | } 1395 | 1396 | .duration-300 { 1397 | transition-duration: 300ms; 1398 | } 1399 | 1400 | .ease-in { 1401 | transition-timing-function: cubic-bezier(0.4, 0, 1, 1); 1402 | } 1403 | 1404 | .ease-out { 1405 | transition-timing-function: cubic-bezier(0, 0, 0.2, 1); 1406 | } 1407 | 1408 | [x-cloak] { 1409 | display: none !important; 1410 | } 1411 | 1412 | /* Style for scrollable-div to fill the available vertical space */ 1413 | 1414 | #scrollable-div { 1415 | flex: 1; 1416 | /* Grow to fill available vertical space */ 1417 | } 1418 | 1419 | #resize-handle { 1420 | cursor: ns-resize; 1421 | /* Change cursor to indicate vertical resizing */ 1422 | } 1423 | 1424 | /* Style for deploy-output-container */ 1425 | 1426 | #deploy-output-container { 1427 | min-height: 150px; 1428 | } 1429 | 1430 | .hover\:bg-gray-50:hover { 1431 | --tw-bg-opacity: 1; 1432 | background-color: rgb(249 250 251 / var(--tw-bg-opacity)); 1433 | } 1434 | 1435 | .hover\:bg-red-500:hover { 1436 | --tw-bg-opacity: 1; 1437 | background-color: rgb(239 68 68 / var(--tw-bg-opacity)); 1438 | } 1439 | 1440 | .hover\:bg-sky-500:hover { 1441 | --tw-bg-opacity: 1; 1442 | background-color: rgb(14 165 233 / var(--tw-bg-opacity)); 1443 | } 1444 | 1445 | .hover\:bg-slate-300:hover { 1446 | --tw-bg-opacity: 1; 1447 | background-color: rgb(203 213 225 / var(--tw-bg-opacity)); 1448 | } 1449 | 1450 | .focus-visible\:outline:focus-visible { 1451 | outline-style: solid; 1452 | } 1453 | 1454 | .focus-visible\:outline-2:focus-visible { 1455 | outline-width: 2px; 1456 | } 1457 | 1458 | .focus-visible\:outline-offset-2:focus-visible { 1459 | outline-offset: 2px; 1460 | } 1461 | 1462 | .focus-visible\:outline-red-600:focus-visible { 1463 | outline-color: #dc2626; 1464 | } 1465 | 1466 | .focus-visible\:outline-sky-600:focus-visible { 1467 | outline-color: #0284c7; 1468 | } 1469 | 1470 | @media (min-width: 640px) { 1471 | .sm\:col-span-2 { 1472 | grid-column: span 2 / span 2; 1473 | } 1474 | 1475 | .sm\:col-start-2 { 1476 | grid-column-start: 2; 1477 | } 1478 | 1479 | .sm\:mt-0 { 1480 | margin-top: 0px; 1481 | } 1482 | 1483 | .sm\:translate-y-0 { 1484 | --tw-translate-y: 0px; 1485 | transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 1486 | } 1487 | 1488 | .sm\:scale-100 { 1489 | --tw-scale-x: 1; 1490 | --tw-scale-y: 1; 1491 | transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 1492 | } 1493 | 1494 | .sm\:scale-95 { 1495 | --tw-scale-x: .95; 1496 | --tw-scale-y: .95; 1497 | transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 1498 | } 1499 | 1500 | .sm\:p-8 { 1501 | padding: 2rem; 1502 | } 1503 | } 1504 | 1505 | @media (min-width: 768px) { 1506 | .md\:col-span-2 { 1507 | grid-column: span 2 / span 2; 1508 | } 1509 | 1510 | .md\:grid-cols-3 { 1511 | grid-template-columns: repeat(3, minmax(0, 1fr)); 1512 | } 1513 | } 1514 | -------------------------------------------------------------------------------- /app/assets/stylesheets/deployed/src/input.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | [x-cloak] { display: none !important; } 6 | 7 | /* Style for scrollable-div to fill the available vertical space */ 8 | #scrollable-div { 9 | flex: 1; /* Grow to fill available vertical space */ 10 | } 11 | 12 | #resize-handle { 13 | cursor: ns-resize; /* Change cursor to indicate vertical resizing */ 14 | } 15 | 16 | /* Style for deploy-output-container */ 17 | #deploy-output-container { 18 | min-height: 150px; 19 | } 20 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/deployed/application_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Deployed 4 | class ApplicationController < ActionController::Base 5 | layout 'deployed/application' 6 | 7 | helper Deployed::Engine.helpers 8 | 9 | before_action :initialize_deployed 10 | 11 | private 12 | 13 | # A bunch of housekeeping stuff to make things run 14 | def initialize_deployed 15 | Deployed.setup! 16 | end 17 | 18 | def lock_file_path 19 | Rails.root.join(Deployed::DIRECTORY, 'process.lock') 20 | end 21 | 22 | def lock_process 23 | File.open(lock_file_path, 'a') do |file| 24 | file.puts(Deployed::CurrentExecution.child_pid) 25 | end 26 | end 27 | 28 | def release_process 29 | return unless File.exist?(lock_file_path) 30 | 31 | File.delete(lock_file_path) 32 | end 33 | 34 | def stored_pid 35 | return false unless File.exist?(lock_file_path) 36 | 37 | value = File.read(lock_file_path).to_i 38 | 39 | if value.is_a?(Integer) 40 | value 41 | else 42 | false 43 | end 44 | end 45 | 46 | def process_running? 47 | return false unless stored_pid 48 | 49 | begin 50 | # Send signal 0 to the process to check if it exists 51 | Process.kill(0, stored_pid) 52 | true 53 | rescue Errno::ESRCH 54 | false 55 | end 56 | end 57 | helper_method :process_running? 58 | 59 | def current_log_file 60 | Rails.root.join(Deployed::DIRECTORY, 'deployments/current.log') 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /app/controllers/deployed/config_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Deployed 4 | # Provides information on the current ./config/deploy.yml 5 | class ConfigController < ApplicationController 6 | def show 7 | respond_to(&:html) 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/controllers/deployed/git_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Deployed 4 | # Provides a git status check to see if we are deploying uncommitted changes 5 | class GitController < ApplicationController 6 | def uncommitted_check 7 | @git_status = `git status --porcelain` 8 | respond_to(&:html) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/controllers/deployed/log_output_controller.rb: -------------------------------------------------------------------------------- 1 | module Deployed 2 | class LogOutputController < ApplicationController 3 | include ActionController::Live 4 | 5 | before_action :set_headers 6 | 7 | def index 8 | thread_exit_flag = false 9 | 10 | thread = Thread.new do 11 | File.open(current_log_file, 'r') do |file| 12 | while true 13 | IO.select([file]) 14 | 15 | found_deployed = false 16 | 17 | file.each_line do |line| 18 | # Check the exit flag 19 | if thread_exit_flag 20 | break 21 | end 22 | 23 | css_class = if line.include?('[Deployed]') 24 | 'text-slate-400' 25 | else 26 | 'text-green-400' 27 | end 28 | sse.write("
#{line.strip}
", event: 'message') 29 | 30 | if line.include?("[Deployed Rails] End") 31 | found_deployed = true 32 | break 33 | end 34 | end 35 | 36 | if found_deployed || thread_exit_flag 37 | break 38 | end 39 | end 40 | end 41 | end 42 | 43 | begin 44 | thread.join 45 | rescue ActionController::Live::ClientDisconnected 46 | logger.info 'Client Disconnected' 47 | ensure 48 | # Set the exit flag to true to signal the thread to exit 49 | thread_exit_flag = true 50 | sse.close 51 | response.stream.close 52 | end 53 | end 54 | 55 | 56 | private 57 | 58 | def set_headers 59 | response.headers['Content-Type'] = 'text/event-stream' 60 | response.headers['Last-Modified'] = Time.now.httpdate 61 | end 62 | 63 | def sse 64 | @sse ||= SSE.new(response.stream, event: 'Stream Started') 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /app/controllers/deployed/run_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Deployed 4 | # Provides a centralized way to run all `kamal [command]` executions and streams to the browser 5 | class RunController < ApplicationController 6 | class ConcurrentProcessRunning < StandardError; end 7 | skip_forgery_protection 8 | 9 | # Endpoint to execute the kamal command 10 | def execute 11 | raise(ConcurrentProcessRunning) if process_running? 12 | release_process if stored_pid 13 | File.write(current_log_file, '') 14 | 15 | # Fork a child process 16 | Deployed::CurrentExecution.child_pid = fork do 17 | exec("bundle exec rake deployed:execute_and_log['#{command}']") 18 | end 19 | 20 | lock_process 21 | render json: { message: 'OK' } 22 | rescue ConcurrentProcessRunning 23 | render json: { message: 'EXISTING PROCESS' } 24 | end 25 | 26 | # Endpoint to cancel currently running process 27 | def cancel 28 | pid = stored_pid 29 | if process_running? 30 | # If a process is running, get the PID and attempt to kill it 31 | begin 32 | Process.kill('TERM', stored_pid) 33 | rescue Errno::ESRCH 34 | ensure 35 | release_process 36 | end 37 | end 38 | render json: { message: pid } 39 | end 40 | 41 | private 42 | 43 | def command 44 | params[:command] 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /app/controllers/deployed/setup_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Deployed 4 | # Provides a way to setup ./config/deploy.yml 5 | class SetupController < ApplicationController 6 | def new 7 | respond_to do |format| 8 | format.html 9 | end 10 | end 11 | 12 | def create 13 | `kamal init` 14 | 15 | respond_to do |format| 16 | format.html { redirect_to root_path } 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/controllers/deployed/welcome_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Deployed 4 | # Provides the main entry point for the app 5 | class WelcomeController < ApplicationController 6 | def index 7 | respond_to(&:html) 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/helpers/deployed/application_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Deployed 4 | module ApplicationHelper 5 | def rocket_icon 6 | output = <<~ICON 7 | 8 | 9 | 10 | ICON 11 | 12 | output.html_safe 13 | end 14 | 15 | def config_icon 16 | output = <<~ICON 17 | 18 | 19 | 20 | ICON 21 | 22 | output.html_safe 23 | end 24 | 25 | def tools_icon 26 | output = <<~ICON 27 | 28 | 29 | 30 | 31 | ICON 32 | 33 | output.html_safe 34 | end 35 | 36 | def right_arrow 37 | output = <<~ICON 38 | 39 | 40 | 41 | ICON 42 | 43 | output.html_safe 44 | end 45 | 46 | def kamal_exec_button(label:, command:) 47 | button_tag( 48 | label, 49 | type: 'button', 50 | onclick: "execDeployed('#{command}')", 51 | class: 'rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50', 52 | 'x-bind:disabled' => '$store.process.running', 53 | 'x-bind:class' => "{'opacity-50': $store.process.running}", 54 | 'x-data' => '' 55 | ) 56 | end 57 | 58 | def kamal_abort_button 59 | button_tag( 60 | 'Abort', 61 | type: 'button', 62 | onclick: "abortDeployed()", 63 | class: 'rounded-md bg-red-600 px-3 py-1.5 text-sm text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600', 64 | 'x-bind:disabled' => '$store.process.abortInProgress', 65 | 'x-bind:class' => "{'opacity-50': $store.process.abortInProgress}", 66 | 'x-text' => "$store.process.abortInProgress ? 'Aborting' : 'Abort'", 67 | 'x-data' => '' 68 | ) 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /app/helpers/deployed/log_output_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Deployed 4 | module LogOutputHelper 5 | def deploy_output_intro 6 | output = <<~HTML 7 |
Ready... Set... Deploy!
8 | HTML 9 | 10 | output.html_safe 11 | end 12 | 13 | def deploy_output_kamal_version 14 | output = <<~HTML 15 |
16 | Using kamal #{::Kamal::VERSION} 17 |
18 | HTML 19 | 20 | output.html_safe 21 | end 22 | 23 | def deploy_output_missing_config 24 | return unless Deployed::Config.requires_init 25 | 26 | output = <<~HTML 27 |
WARNING: ./config/deploy.yml file not detected
28 | HTML 29 | 30 | output.html_safe 31 | end 32 | 33 | def deploy_output_spinner 34 | output = <<~HTML 35 | 41 | HTML 42 | 43 | output.html_safe 44 | end 45 | 46 | def deploy_output_resize_handler 47 | output = <<~ICON 48 | 49 | 50 | 51 | ICON 52 | 53 | output.html_safe 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/deployed/config.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'yaml' 4 | 5 | module Deployed 6 | # Provides a model to track the current values in ./config/deploy.yml 7 | class Config < ActiveSupport::CurrentAttributes 8 | attribute :service, :image, :servers, :ssh, :volumes, :registry, :env, :traefik, :requires_init, :env_values 9 | 10 | def self.init!(yaml_file = './config/deploy.yml', dot_env_file = '.env') 11 | self.requires_init = File.exist?(yaml_file) ? false : true 12 | 13 | unless requires_init 14 | yaml_data = YAML.load_file(yaml_file) 15 | self.service = yaml_data['service'] 16 | self.image = yaml_data['image'] 17 | self.servers = yaml_data['servers'] 18 | self.ssh = yaml_data['ssh'] 19 | self.volumes = yaml_data['volumes'] 20 | self.registry = yaml_data['registry'] 21 | self.env = yaml_data['env'] || {} 22 | self.traefik = yaml_data['traefik'] 23 | end 24 | 25 | if File.exist?(dot_env_file) 26 | self.env_values = {} 27 | 28 | File.open(dot_env_file, 'r') do |file| 29 | file.each_line do |line| 30 | key, value = line.strip.split('=') 31 | self.env_values[key] = value 32 | end 33 | end 34 | end 35 | 36 | requires_init 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /app/models/deployed/current_execution.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Deployed 4 | # Provides a way to track the current child_pid 5 | class CurrentExecution < ActiveSupport::CurrentAttributes 6 | attribute :child_pid 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/views/deployed/git/uncommitted_check.html.erb: -------------------------------------------------------------------------------- 1 | <%= turbo_frame_tag 'git-status' do %> 2 | <% unless @git_status.empty? %> 3 |
You have uncommitted files!
4 | <% end %> 5 | <% end %> 6 | -------------------------------------------------------------------------------- /app/views/deployed/setup/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= turbo_frame_tag 'deployed-init', target: '_top' do %> 2 | 47 | <% end %> 48 | -------------------------------------------------------------------------------- /app/views/deployed/welcome/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

5 | <%= rocket_icon %> 6 | Deployment 7 |

8 |
9 | 10 |
11 |
12 |
13 |
14 | <%= kamal_exec_button(label: 'Deploy', command: 'deploy') %> 15 | 16 | <%= turbo_frame_tag 'git-status', src: git_uncommitted_check_url %> 17 |
18 |
19 | <%= kamal_exec_button(label: 'App Details', command: 'app details') %> 20 | <%= kamal_exec_button(label: 'App Containers', command: 'app containers') %> 21 |
22 |
23 | <%= kamal_exec_button(label: 'App Boot', command: 'app boot') %> 24 | <%= kamal_exec_button(label: 'App Start', command: 'app start') %> 25 | <%= kamal_exec_button(label: 'App Stop', command: 'app stop') %> 26 |
27 |
28 |
29 |
30 |
31 | 32 |
33 |
34 |

35 | <%= config_icon %> 36 | Configuration 37 |

38 |
39 | 40 |
41 |
42 | <% if Deployed::Config.requires_init %> 43 |

Your ./config/deploy.yml file does not exist. You will need to create it.

44 | <% else %> 45 |
46 |
47 |
App
48 |
49 | <%= Deployed::Config.service %> 50 |
51 |
52 |
53 |
Image
54 |
55 | <%= Deployed::Config.image %> 56 |
57 |
58 |
59 |
Environment variables
60 |
61 | <% if !Deployed::Config.env.dig('secret').present? && !Deployed::Config.env.dig('clear').present? %> 62 |

You have not specified any environment variables in your configuration file. This is likely an error. Please check your ./config/deploy.yml file.

63 | <% end %> 64 | 65 | <% if Deployed::Config.env.dig('secret').present? %> 66 |
Secret
67 |
    68 | <% Deployed::Config.env.dig('secret').each do |secret_env| %> 69 |
  • 70 | <%= secret_env %> 71 | <%= right_arrow %> 72 | <% if Deployed::Config.env_values[secret_env].present? %> 73 | 74 | <%= redacted_string = '*' * (Deployed::Config.env_values[secret_env].length - 6) + Deployed::Config.env_values[secret_env][-6..-1] %> 75 | 76 | <% else %> 77 | Not found 78 | <% end %> 79 |
  • 80 | <% end %> 81 |
82 | <% end %> 83 | 84 | <% if Deployed::Config.env['clear'].present? %> 85 |
Secret
86 |
    87 | <% Deployed::Config.env['clear'].each do |secret_env| %> 88 |
  • 89 | <%= secret_env %> 90 | <%= right_arrow %> 91 | <% if Deployed::Config.env_values[secret_env].present? %> 92 | 93 | <%= Deployed::Config.env_values[secret_env] %> 94 | 95 | <% else %> 96 | Not found 97 | <% end %> 98 |
  • 99 | <% end %> 100 |
101 | <% end %> 102 |
103 |
104 |
105 | <% end %> 106 |
107 |
108 |
109 | 110 |
111 |
112 |

113 | <%= tools_icon %> 114 | Utilities 115 |

116 |
117 | 118 |
119 |
120 |
<%= kamal_exec_button(label: 'Perform Healthcheck', command: 'healthcheck --verbose') %>
121 |
122 | <%= kamal_exec_button(label: 'Check Lock Status', command: 'lock status') %> 123 | <%= kamal_exec_button(label: 'Release Lock', command: 'lock release') %> 124 |
125 |
126 |
127 |
128 |
129 | -------------------------------------------------------------------------------- /app/views/layouts/deployed/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Deployed: The Deployment Rails Engine 5 | <%= csrf_meta_tags %> 6 | <%= csp_meta_tag %> 7 | 8 | <%= stylesheet_link_tag "deployed/deployed", 'data-turbo-track': 'reload' %> 9 | <%= javascript_include_tag "deployed/application", type: "module" %> 10 | 32 | 33 | 34 |
35 | Process Running 36 |
37 |
38 | Configuration Required 39 |
40 |
41 |
42 |
43 |

44 |
45 |
46 |
47 | DEPLOYED 48 |
49 |
50 |
51 | v<%= Deployed::VERSION %> 52 |
53 |
54 |

55 |
56 |
57 |
58 |
59 |
60 |
61 | <%= yield %> 62 |
63 |
64 | 65 |
66 |
67 |
68 | <%= deploy_output_resize_handler %> 69 |
70 |
71 |
72 |
73 | <%= deploy_output_intro %> 74 | <%= deploy_output_kamal_version %> 75 | <%= deploy_output_missing_config %> 76 | 77 |
78 | <%= kamal_abort_button %> 79 |
80 |
81 | <%= deploy_output_spinner %> 82 |
83 |
84 |
85 | 86 | <%= turbo_frame_tag('deployed-init', src: setup_path, target: '_top') if Deployed::Config.requires_init %> 87 | 88 | 89 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /bin/dev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | if ! gem list foreman -i --silent; then 4 | echo "Installing foreman..." 5 | gem install foreman 6 | fi 7 | 8 | exec foreman start -f Procfile.dev "$@" 9 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails gems 3 | # installed from the root of your application. 4 | 5 | ENGINE_ROOT = File.expand_path("..", __dir__) 6 | ENGINE_PATH = File.expand_path("../lib/deployed/engine", __dir__) 7 | APP_PATH = File.expand_path("../test/dummy/config/application", __dir__) 8 | 9 | # Set up gems listed in the Gemfile. 10 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 11 | require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"]) 12 | 13 | require "rails/all" 14 | require "rails/engine/commands" 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | npm install -D tailwindcss 4 | npm install -D @tailwindcss/aspect-ratio 5 | npm install -D @tailwindcss/typography 6 | npm install -D @tailwindcss/container-queries 7 | 8 | bundle 9 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Deployed::Engine.routes.draw do 2 | get 'setup', to: 'setup#new' 3 | post 'setup', to: 'setup#create' 4 | get 'config', to: 'config#show' 5 | get 'git/uncommitted_check', to: 'git#uncommitted_check' 6 | post 'execute', to: 'run#execute' 7 | post 'cancel', to: 'run#cancel' 8 | get 'log_output', to: 'log_output#index' 9 | root to: 'welcome#index' 10 | end 11 | -------------------------------------------------------------------------------- /deployed.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'lib/deployed/version' 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = 'deployed' 7 | spec.version = Deployed::VERSION 8 | spec.authors = ['Simon Chiu'] 9 | spec.email = ['simon@furvur.com'] 10 | spec.homepage = 'https://github.com/geetfun/deployed' 11 | spec.summary = 'Mountable Rails engine to manage Kamal commands' 12 | spec.description = 'Mountable Rails engine to manage Kamal commands' 13 | spec.license = 'MIT' 14 | 15 | # Prevent pushing this gem to RubyGems.org. To allow pushes either set the "allowed_push_host" 16 | # to allow pushing to a single host or delete this section to allow pushing to any host. 17 | spec.metadata['allowed_push_host'] = 'https://rubygems.org' 18 | 19 | spec.metadata['homepage_uri'] = spec.homepage 20 | spec.metadata['source_code_uri'] = 'https://github.com/geetfun/deployed' 21 | spec.metadata['changelog_uri'] = 'https://github.com/geetfun/deployed/blob/main/CHANGELOG.md' 22 | 23 | spec.files = Dir.chdir(File.expand_path(__dir__)) do 24 | Dir['{app,config,db,lib}/**/*', 'MIT-LICENSE', 'Rakefile', 'README.md'] 25 | end 26 | 27 | spec.add_dependency 'kamal', '~> 1.0' 28 | spec.add_dependency 'turbo-rails', '~> 1.5' 29 | spec.add_dependency 'rails', '>= 7.1.1' 30 | end 31 | -------------------------------------------------------------------------------- /lib/deployed.rb: -------------------------------------------------------------------------------- 1 | require 'deployed/version' 2 | require 'deployed/engine' 3 | 4 | module Deployed 5 | DIRECTORY = '.deployed' 6 | 7 | def self.setup! 8 | # Ensure directory is set up 9 | directory_path = Rails.root.join(DIRECTORY) 10 | 11 | unless File.directory?(directory_path) 12 | Dir.mkdir(directory_path) 13 | end 14 | 15 | # Ensure we read the config 16 | Deployed::Config.init! 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/deployed/engine.rb: -------------------------------------------------------------------------------- 1 | module Deployed 2 | class Engine < ::Rails::Engine 3 | isolate_namespace Deployed 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/deployed/version.rb: -------------------------------------------------------------------------------- 1 | module Deployed 2 | VERSION = "0.1.3" 3 | end 4 | -------------------------------------------------------------------------------- /lib/tasks/deployed_tasks.rake: -------------------------------------------------------------------------------- 1 | # lib/tasks/deployed.rake 2 | 3 | namespace :deployed do 4 | desc "Execute a Kamal command and log its output" 5 | task :execute_and_log, [:command] => :environment do |task, args| 6 | command = args[:command] 7 | 8 | unless command 9 | puts "Please provide a Kamal command. Usage: rake deployed:execute_and_log[command]" 10 | next 11 | end 12 | 13 | log_file = Rails.root.join(Deployed::DIRECTORY, 'deployments/current.log') 14 | 15 | File.open(log_file, 'a') do |file| 16 | IO.popen("kamal #{command}") do |io| 17 | start_time = Time.now 18 | 19 | file.puts("[Deployed] > kamal #{command}") 20 | file.fsync 21 | 22 | io.each_line do |line| 23 | file.puts line 24 | file.fsync # Force data to be written to disk immediately 25 | end 26 | end_time = Time.now 27 | file.puts("[Deployed] Finished in #{end_time - start_time} seconds") 28 | file.puts("[Deployed] End") 29 | file.fsync 30 | 31 | # Delete lockfile 32 | File.delete(Rails.root.join(Deployed::DIRECTORY, 'process.lock')) 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deployed", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "devDependencies": { 8 | "@tailwindcss/aspect-ratio": "^0.4.2", 9 | "@tailwindcss/container-queries": "^0.1.1", 10 | "@tailwindcss/forms": "^0.5.6", 11 | "@tailwindcss/typography": "^0.5.10", 12 | "tailwindcss": "^3.3.3" 13 | } 14 | }, 15 | "node_modules/@alloc/quick-lru": { 16 | "version": "5.2.0", 17 | "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", 18 | "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", 19 | "dev": true, 20 | "engines": { 21 | "node": ">=10" 22 | }, 23 | "funding": { 24 | "url": "https://github.com/sponsors/sindresorhus" 25 | } 26 | }, 27 | "node_modules/@jridgewell/gen-mapping": { 28 | "version": "0.3.3", 29 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 30 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 31 | "dev": true, 32 | "dependencies": { 33 | "@jridgewell/set-array": "^1.0.1", 34 | "@jridgewell/sourcemap-codec": "^1.4.10", 35 | "@jridgewell/trace-mapping": "^0.3.9" 36 | }, 37 | "engines": { 38 | "node": ">=6.0.0" 39 | } 40 | }, 41 | "node_modules/@jridgewell/resolve-uri": { 42 | "version": "3.1.1", 43 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 44 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 45 | "dev": true, 46 | "engines": { 47 | "node": ">=6.0.0" 48 | } 49 | }, 50 | "node_modules/@jridgewell/set-array": { 51 | "version": "1.1.2", 52 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 53 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 54 | "dev": true, 55 | "engines": { 56 | "node": ">=6.0.0" 57 | } 58 | }, 59 | "node_modules/@jridgewell/sourcemap-codec": { 60 | "version": "1.4.15", 61 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 62 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 63 | "dev": true 64 | }, 65 | "node_modules/@jridgewell/trace-mapping": { 66 | "version": "0.3.20", 67 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", 68 | "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", 69 | "dev": true, 70 | "dependencies": { 71 | "@jridgewell/resolve-uri": "^3.1.0", 72 | "@jridgewell/sourcemap-codec": "^1.4.14" 73 | } 74 | }, 75 | "node_modules/@nodelib/fs.scandir": { 76 | "version": "2.1.5", 77 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 78 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 79 | "dev": true, 80 | "dependencies": { 81 | "@nodelib/fs.stat": "2.0.5", 82 | "run-parallel": "^1.1.9" 83 | }, 84 | "engines": { 85 | "node": ">= 8" 86 | } 87 | }, 88 | "node_modules/@nodelib/fs.stat": { 89 | "version": "2.0.5", 90 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 91 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 92 | "dev": true, 93 | "engines": { 94 | "node": ">= 8" 95 | } 96 | }, 97 | "node_modules/@nodelib/fs.walk": { 98 | "version": "1.2.8", 99 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 100 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 101 | "dev": true, 102 | "dependencies": { 103 | "@nodelib/fs.scandir": "2.1.5", 104 | "fastq": "^1.6.0" 105 | }, 106 | "engines": { 107 | "node": ">= 8" 108 | } 109 | }, 110 | "node_modules/@tailwindcss/aspect-ratio": { 111 | "version": "0.4.2", 112 | "resolved": "https://registry.npmjs.org/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz", 113 | "integrity": "sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==", 114 | "dev": true, 115 | "peerDependencies": { 116 | "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" 117 | } 118 | }, 119 | "node_modules/@tailwindcss/container-queries": { 120 | "version": "0.1.1", 121 | "resolved": "https://registry.npmjs.org/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz", 122 | "integrity": "sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==", 123 | "dev": true, 124 | "peerDependencies": { 125 | "tailwindcss": ">=3.2.0" 126 | } 127 | }, 128 | "node_modules/@tailwindcss/forms": { 129 | "version": "0.5.6", 130 | "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.6.tgz", 131 | "integrity": "sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA==", 132 | "dev": true, 133 | "dependencies": { 134 | "mini-svg-data-uri": "^1.2.3" 135 | }, 136 | "peerDependencies": { 137 | "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" 138 | } 139 | }, 140 | "node_modules/@tailwindcss/typography": { 141 | "version": "0.5.10", 142 | "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz", 143 | "integrity": "sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==", 144 | "dev": true, 145 | "dependencies": { 146 | "lodash.castarray": "^4.4.0", 147 | "lodash.isplainobject": "^4.0.6", 148 | "lodash.merge": "^4.6.2", 149 | "postcss-selector-parser": "6.0.10" 150 | }, 151 | "peerDependencies": { 152 | "tailwindcss": ">=3.0.0 || insiders" 153 | } 154 | }, 155 | "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { 156 | "version": "6.0.10", 157 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", 158 | "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", 159 | "dev": true, 160 | "dependencies": { 161 | "cssesc": "^3.0.0", 162 | "util-deprecate": "^1.0.2" 163 | }, 164 | "engines": { 165 | "node": ">=4" 166 | } 167 | }, 168 | "node_modules/any-promise": { 169 | "version": "1.3.0", 170 | "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", 171 | "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", 172 | "dev": true 173 | }, 174 | "node_modules/anymatch": { 175 | "version": "3.1.3", 176 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 177 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 178 | "dev": true, 179 | "dependencies": { 180 | "normalize-path": "^3.0.0", 181 | "picomatch": "^2.0.4" 182 | }, 183 | "engines": { 184 | "node": ">= 8" 185 | } 186 | }, 187 | "node_modules/arg": { 188 | "version": "5.0.2", 189 | "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", 190 | "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", 191 | "dev": true 192 | }, 193 | "node_modules/balanced-match": { 194 | "version": "1.0.2", 195 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 196 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 197 | "dev": true 198 | }, 199 | "node_modules/binary-extensions": { 200 | "version": "2.2.0", 201 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 202 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 203 | "dev": true, 204 | "engines": { 205 | "node": ">=8" 206 | } 207 | }, 208 | "node_modules/brace-expansion": { 209 | "version": "1.1.11", 210 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 211 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 212 | "dev": true, 213 | "dependencies": { 214 | "balanced-match": "^1.0.0", 215 | "concat-map": "0.0.1" 216 | } 217 | }, 218 | "node_modules/braces": { 219 | "version": "3.0.2", 220 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 221 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 222 | "dev": true, 223 | "dependencies": { 224 | "fill-range": "^7.0.1" 225 | }, 226 | "engines": { 227 | "node": ">=8" 228 | } 229 | }, 230 | "node_modules/camelcase-css": { 231 | "version": "2.0.1", 232 | "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", 233 | "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", 234 | "dev": true, 235 | "engines": { 236 | "node": ">= 6" 237 | } 238 | }, 239 | "node_modules/chokidar": { 240 | "version": "3.5.3", 241 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 242 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 243 | "dev": true, 244 | "funding": [ 245 | { 246 | "type": "individual", 247 | "url": "https://paulmillr.com/funding/" 248 | } 249 | ], 250 | "dependencies": { 251 | "anymatch": "~3.1.2", 252 | "braces": "~3.0.2", 253 | "glob-parent": "~5.1.2", 254 | "is-binary-path": "~2.1.0", 255 | "is-glob": "~4.0.1", 256 | "normalize-path": "~3.0.0", 257 | "readdirp": "~3.6.0" 258 | }, 259 | "engines": { 260 | "node": ">= 8.10.0" 261 | }, 262 | "optionalDependencies": { 263 | "fsevents": "~2.3.2" 264 | } 265 | }, 266 | "node_modules/chokidar/node_modules/glob-parent": { 267 | "version": "5.1.2", 268 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 269 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 270 | "dev": true, 271 | "dependencies": { 272 | "is-glob": "^4.0.1" 273 | }, 274 | "engines": { 275 | "node": ">= 6" 276 | } 277 | }, 278 | "node_modules/commander": { 279 | "version": "4.1.1", 280 | "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", 281 | "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", 282 | "dev": true, 283 | "engines": { 284 | "node": ">= 6" 285 | } 286 | }, 287 | "node_modules/concat-map": { 288 | "version": "0.0.1", 289 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 290 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 291 | "dev": true 292 | }, 293 | "node_modules/cssesc": { 294 | "version": "3.0.0", 295 | "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", 296 | "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", 297 | "dev": true, 298 | "bin": { 299 | "cssesc": "bin/cssesc" 300 | }, 301 | "engines": { 302 | "node": ">=4" 303 | } 304 | }, 305 | "node_modules/didyoumean": { 306 | "version": "1.2.2", 307 | "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", 308 | "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", 309 | "dev": true 310 | }, 311 | "node_modules/dlv": { 312 | "version": "1.1.3", 313 | "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", 314 | "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", 315 | "dev": true 316 | }, 317 | "node_modules/fast-glob": { 318 | "version": "3.3.1", 319 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", 320 | "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", 321 | "dev": true, 322 | "dependencies": { 323 | "@nodelib/fs.stat": "^2.0.2", 324 | "@nodelib/fs.walk": "^1.2.3", 325 | "glob-parent": "^5.1.2", 326 | "merge2": "^1.3.0", 327 | "micromatch": "^4.0.4" 328 | }, 329 | "engines": { 330 | "node": ">=8.6.0" 331 | } 332 | }, 333 | "node_modules/fast-glob/node_modules/glob-parent": { 334 | "version": "5.1.2", 335 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 336 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 337 | "dev": true, 338 | "dependencies": { 339 | "is-glob": "^4.0.1" 340 | }, 341 | "engines": { 342 | "node": ">= 6" 343 | } 344 | }, 345 | "node_modules/fastq": { 346 | "version": "1.15.0", 347 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 348 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 349 | "dev": true, 350 | "dependencies": { 351 | "reusify": "^1.0.4" 352 | } 353 | }, 354 | "node_modules/fill-range": { 355 | "version": "7.0.1", 356 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 357 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 358 | "dev": true, 359 | "dependencies": { 360 | "to-regex-range": "^5.0.1" 361 | }, 362 | "engines": { 363 | "node": ">=8" 364 | } 365 | }, 366 | "node_modules/fs.realpath": { 367 | "version": "1.0.0", 368 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 369 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 370 | "dev": true 371 | }, 372 | "node_modules/fsevents": { 373 | "version": "2.3.3", 374 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 375 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 376 | "dev": true, 377 | "hasInstallScript": true, 378 | "optional": true, 379 | "os": [ 380 | "darwin" 381 | ], 382 | "engines": { 383 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 384 | } 385 | }, 386 | "node_modules/glob": { 387 | "version": "7.1.6", 388 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 389 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 390 | "dev": true, 391 | "dependencies": { 392 | "fs.realpath": "^1.0.0", 393 | "inflight": "^1.0.4", 394 | "inherits": "2", 395 | "minimatch": "^3.0.4", 396 | "once": "^1.3.0", 397 | "path-is-absolute": "^1.0.0" 398 | }, 399 | "engines": { 400 | "node": "*" 401 | }, 402 | "funding": { 403 | "url": "https://github.com/sponsors/isaacs" 404 | } 405 | }, 406 | "node_modules/glob-parent": { 407 | "version": "6.0.2", 408 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 409 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 410 | "dev": true, 411 | "dependencies": { 412 | "is-glob": "^4.0.3" 413 | }, 414 | "engines": { 415 | "node": ">=10.13.0" 416 | } 417 | }, 418 | "node_modules/has": { 419 | "version": "1.0.4", 420 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", 421 | "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", 422 | "dev": true, 423 | "engines": { 424 | "node": ">= 0.4.0" 425 | } 426 | }, 427 | "node_modules/inflight": { 428 | "version": "1.0.6", 429 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 430 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 431 | "dev": true, 432 | "dependencies": { 433 | "once": "^1.3.0", 434 | "wrappy": "1" 435 | } 436 | }, 437 | "node_modules/inherits": { 438 | "version": "2.0.4", 439 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 440 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 441 | "dev": true 442 | }, 443 | "node_modules/is-binary-path": { 444 | "version": "2.1.0", 445 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 446 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 447 | "dev": true, 448 | "dependencies": { 449 | "binary-extensions": "^2.0.0" 450 | }, 451 | "engines": { 452 | "node": ">=8" 453 | } 454 | }, 455 | "node_modules/is-core-module": { 456 | "version": "2.13.0", 457 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", 458 | "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", 459 | "dev": true, 460 | "dependencies": { 461 | "has": "^1.0.3" 462 | }, 463 | "funding": { 464 | "url": "https://github.com/sponsors/ljharb" 465 | } 466 | }, 467 | "node_modules/is-extglob": { 468 | "version": "2.1.1", 469 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 470 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 471 | "dev": true, 472 | "engines": { 473 | "node": ">=0.10.0" 474 | } 475 | }, 476 | "node_modules/is-glob": { 477 | "version": "4.0.3", 478 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 479 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 480 | "dev": true, 481 | "dependencies": { 482 | "is-extglob": "^2.1.1" 483 | }, 484 | "engines": { 485 | "node": ">=0.10.0" 486 | } 487 | }, 488 | "node_modules/is-number": { 489 | "version": "7.0.0", 490 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 491 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 492 | "dev": true, 493 | "engines": { 494 | "node": ">=0.12.0" 495 | } 496 | }, 497 | "node_modules/jiti": { 498 | "version": "1.20.0", 499 | "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz", 500 | "integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==", 501 | "dev": true, 502 | "bin": { 503 | "jiti": "bin/jiti.js" 504 | } 505 | }, 506 | "node_modules/lilconfig": { 507 | "version": "2.1.0", 508 | "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", 509 | "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", 510 | "dev": true, 511 | "engines": { 512 | "node": ">=10" 513 | } 514 | }, 515 | "node_modules/lines-and-columns": { 516 | "version": "1.2.4", 517 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", 518 | "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", 519 | "dev": true 520 | }, 521 | "node_modules/lodash.castarray": { 522 | "version": "4.4.0", 523 | "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", 524 | "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", 525 | "dev": true 526 | }, 527 | "node_modules/lodash.isplainobject": { 528 | "version": "4.0.6", 529 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 530 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", 531 | "dev": true 532 | }, 533 | "node_modules/lodash.merge": { 534 | "version": "4.6.2", 535 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 536 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 537 | "dev": true 538 | }, 539 | "node_modules/merge2": { 540 | "version": "1.4.1", 541 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 542 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 543 | "dev": true, 544 | "engines": { 545 | "node": ">= 8" 546 | } 547 | }, 548 | "node_modules/micromatch": { 549 | "version": "4.0.5", 550 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 551 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 552 | "dev": true, 553 | "dependencies": { 554 | "braces": "^3.0.2", 555 | "picomatch": "^2.3.1" 556 | }, 557 | "engines": { 558 | "node": ">=8.6" 559 | } 560 | }, 561 | "node_modules/mini-svg-data-uri": { 562 | "version": "1.4.4", 563 | "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", 564 | "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", 565 | "dev": true, 566 | "bin": { 567 | "mini-svg-data-uri": "cli.js" 568 | } 569 | }, 570 | "node_modules/minimatch": { 571 | "version": "3.1.2", 572 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 573 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 574 | "dev": true, 575 | "dependencies": { 576 | "brace-expansion": "^1.1.7" 577 | }, 578 | "engines": { 579 | "node": "*" 580 | } 581 | }, 582 | "node_modules/mz": { 583 | "version": "2.7.0", 584 | "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", 585 | "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", 586 | "dev": true, 587 | "dependencies": { 588 | "any-promise": "^1.0.0", 589 | "object-assign": "^4.0.1", 590 | "thenify-all": "^1.0.0" 591 | } 592 | }, 593 | "node_modules/nanoid": { 594 | "version": "3.3.6", 595 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 596 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", 597 | "dev": true, 598 | "funding": [ 599 | { 600 | "type": "github", 601 | "url": "https://github.com/sponsors/ai" 602 | } 603 | ], 604 | "bin": { 605 | "nanoid": "bin/nanoid.cjs" 606 | }, 607 | "engines": { 608 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 609 | } 610 | }, 611 | "node_modules/normalize-path": { 612 | "version": "3.0.0", 613 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 614 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 615 | "dev": true, 616 | "engines": { 617 | "node": ">=0.10.0" 618 | } 619 | }, 620 | "node_modules/object-assign": { 621 | "version": "4.1.1", 622 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 623 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 624 | "dev": true, 625 | "engines": { 626 | "node": ">=0.10.0" 627 | } 628 | }, 629 | "node_modules/object-hash": { 630 | "version": "3.0.0", 631 | "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", 632 | "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", 633 | "dev": true, 634 | "engines": { 635 | "node": ">= 6" 636 | } 637 | }, 638 | "node_modules/once": { 639 | "version": "1.4.0", 640 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 641 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 642 | "dev": true, 643 | "dependencies": { 644 | "wrappy": "1" 645 | } 646 | }, 647 | "node_modules/path-is-absolute": { 648 | "version": "1.0.1", 649 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 650 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 651 | "dev": true, 652 | "engines": { 653 | "node": ">=0.10.0" 654 | } 655 | }, 656 | "node_modules/path-parse": { 657 | "version": "1.0.7", 658 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 659 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 660 | "dev": true 661 | }, 662 | "node_modules/picocolors": { 663 | "version": "1.0.0", 664 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 665 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 666 | "dev": true 667 | }, 668 | "node_modules/picomatch": { 669 | "version": "2.3.1", 670 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 671 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 672 | "dev": true, 673 | "engines": { 674 | "node": ">=8.6" 675 | }, 676 | "funding": { 677 | "url": "https://github.com/sponsors/jonschlinkert" 678 | } 679 | }, 680 | "node_modules/pify": { 681 | "version": "2.3.0", 682 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 683 | "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", 684 | "dev": true, 685 | "engines": { 686 | "node": ">=0.10.0" 687 | } 688 | }, 689 | "node_modules/pirates": { 690 | "version": "4.0.6", 691 | "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", 692 | "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", 693 | "dev": true, 694 | "engines": { 695 | "node": ">= 6" 696 | } 697 | }, 698 | "node_modules/postcss": { 699 | "version": "8.4.31", 700 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", 701 | "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", 702 | "dev": true, 703 | "funding": [ 704 | { 705 | "type": "opencollective", 706 | "url": "https://opencollective.com/postcss/" 707 | }, 708 | { 709 | "type": "tidelift", 710 | "url": "https://tidelift.com/funding/github/npm/postcss" 711 | }, 712 | { 713 | "type": "github", 714 | "url": "https://github.com/sponsors/ai" 715 | } 716 | ], 717 | "dependencies": { 718 | "nanoid": "^3.3.6", 719 | "picocolors": "^1.0.0", 720 | "source-map-js": "^1.0.2" 721 | }, 722 | "engines": { 723 | "node": "^10 || ^12 || >=14" 724 | } 725 | }, 726 | "node_modules/postcss-import": { 727 | "version": "15.1.0", 728 | "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", 729 | "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", 730 | "dev": true, 731 | "dependencies": { 732 | "postcss-value-parser": "^4.0.0", 733 | "read-cache": "^1.0.0", 734 | "resolve": "^1.1.7" 735 | }, 736 | "engines": { 737 | "node": ">=14.0.0" 738 | }, 739 | "peerDependencies": { 740 | "postcss": "^8.0.0" 741 | } 742 | }, 743 | "node_modules/postcss-js": { 744 | "version": "4.0.1", 745 | "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", 746 | "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", 747 | "dev": true, 748 | "dependencies": { 749 | "camelcase-css": "^2.0.1" 750 | }, 751 | "engines": { 752 | "node": "^12 || ^14 || >= 16" 753 | }, 754 | "funding": { 755 | "type": "opencollective", 756 | "url": "https://opencollective.com/postcss/" 757 | }, 758 | "peerDependencies": { 759 | "postcss": "^8.4.21" 760 | } 761 | }, 762 | "node_modules/postcss-load-config": { 763 | "version": "4.0.1", 764 | "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", 765 | "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", 766 | "dev": true, 767 | "dependencies": { 768 | "lilconfig": "^2.0.5", 769 | "yaml": "^2.1.1" 770 | }, 771 | "engines": { 772 | "node": ">= 14" 773 | }, 774 | "funding": { 775 | "type": "opencollective", 776 | "url": "https://opencollective.com/postcss/" 777 | }, 778 | "peerDependencies": { 779 | "postcss": ">=8.0.9", 780 | "ts-node": ">=9.0.0" 781 | }, 782 | "peerDependenciesMeta": { 783 | "postcss": { 784 | "optional": true 785 | }, 786 | "ts-node": { 787 | "optional": true 788 | } 789 | } 790 | }, 791 | "node_modules/postcss-nested": { 792 | "version": "6.0.1", 793 | "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", 794 | "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", 795 | "dev": true, 796 | "dependencies": { 797 | "postcss-selector-parser": "^6.0.11" 798 | }, 799 | "engines": { 800 | "node": ">=12.0" 801 | }, 802 | "funding": { 803 | "type": "opencollective", 804 | "url": "https://opencollective.com/postcss/" 805 | }, 806 | "peerDependencies": { 807 | "postcss": "^8.2.14" 808 | } 809 | }, 810 | "node_modules/postcss-selector-parser": { 811 | "version": "6.0.13", 812 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", 813 | "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", 814 | "dev": true, 815 | "dependencies": { 816 | "cssesc": "^3.0.0", 817 | "util-deprecate": "^1.0.2" 818 | }, 819 | "engines": { 820 | "node": ">=4" 821 | } 822 | }, 823 | "node_modules/postcss-value-parser": { 824 | "version": "4.2.0", 825 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 826 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 827 | "dev": true 828 | }, 829 | "node_modules/queue-microtask": { 830 | "version": "1.2.3", 831 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 832 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 833 | "dev": true, 834 | "funding": [ 835 | { 836 | "type": "github", 837 | "url": "https://github.com/sponsors/feross" 838 | }, 839 | { 840 | "type": "patreon", 841 | "url": "https://www.patreon.com/feross" 842 | }, 843 | { 844 | "type": "consulting", 845 | "url": "https://feross.org/support" 846 | } 847 | ] 848 | }, 849 | "node_modules/read-cache": { 850 | "version": "1.0.0", 851 | "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", 852 | "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", 853 | "dev": true, 854 | "dependencies": { 855 | "pify": "^2.3.0" 856 | } 857 | }, 858 | "node_modules/readdirp": { 859 | "version": "3.6.0", 860 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 861 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 862 | "dev": true, 863 | "dependencies": { 864 | "picomatch": "^2.2.1" 865 | }, 866 | "engines": { 867 | "node": ">=8.10.0" 868 | } 869 | }, 870 | "node_modules/resolve": { 871 | "version": "1.22.8", 872 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", 873 | "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", 874 | "dev": true, 875 | "dependencies": { 876 | "is-core-module": "^2.13.0", 877 | "path-parse": "^1.0.7", 878 | "supports-preserve-symlinks-flag": "^1.0.0" 879 | }, 880 | "bin": { 881 | "resolve": "bin/resolve" 882 | }, 883 | "funding": { 884 | "url": "https://github.com/sponsors/ljharb" 885 | } 886 | }, 887 | "node_modules/reusify": { 888 | "version": "1.0.4", 889 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 890 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 891 | "dev": true, 892 | "engines": { 893 | "iojs": ">=1.0.0", 894 | "node": ">=0.10.0" 895 | } 896 | }, 897 | "node_modules/run-parallel": { 898 | "version": "1.2.0", 899 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 900 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 901 | "dev": true, 902 | "funding": [ 903 | { 904 | "type": "github", 905 | "url": "https://github.com/sponsors/feross" 906 | }, 907 | { 908 | "type": "patreon", 909 | "url": "https://www.patreon.com/feross" 910 | }, 911 | { 912 | "type": "consulting", 913 | "url": "https://feross.org/support" 914 | } 915 | ], 916 | "dependencies": { 917 | "queue-microtask": "^1.2.2" 918 | } 919 | }, 920 | "node_modules/source-map-js": { 921 | "version": "1.0.2", 922 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 923 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 924 | "dev": true, 925 | "engines": { 926 | "node": ">=0.10.0" 927 | } 928 | }, 929 | "node_modules/sucrase": { 930 | "version": "3.34.0", 931 | "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", 932 | "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", 933 | "dev": true, 934 | "dependencies": { 935 | "@jridgewell/gen-mapping": "^0.3.2", 936 | "commander": "^4.0.0", 937 | "glob": "7.1.6", 938 | "lines-and-columns": "^1.1.6", 939 | "mz": "^2.7.0", 940 | "pirates": "^4.0.1", 941 | "ts-interface-checker": "^0.1.9" 942 | }, 943 | "bin": { 944 | "sucrase": "bin/sucrase", 945 | "sucrase-node": "bin/sucrase-node" 946 | }, 947 | "engines": { 948 | "node": ">=8" 949 | } 950 | }, 951 | "node_modules/supports-preserve-symlinks-flag": { 952 | "version": "1.0.0", 953 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 954 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 955 | "dev": true, 956 | "engines": { 957 | "node": ">= 0.4" 958 | }, 959 | "funding": { 960 | "url": "https://github.com/sponsors/ljharb" 961 | } 962 | }, 963 | "node_modules/tailwindcss": { 964 | "version": "3.3.3", 965 | "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", 966 | "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==", 967 | "dev": true, 968 | "dependencies": { 969 | "@alloc/quick-lru": "^5.2.0", 970 | "arg": "^5.0.2", 971 | "chokidar": "^3.5.3", 972 | "didyoumean": "^1.2.2", 973 | "dlv": "^1.1.3", 974 | "fast-glob": "^3.2.12", 975 | "glob-parent": "^6.0.2", 976 | "is-glob": "^4.0.3", 977 | "jiti": "^1.18.2", 978 | "lilconfig": "^2.1.0", 979 | "micromatch": "^4.0.5", 980 | "normalize-path": "^3.0.0", 981 | "object-hash": "^3.0.0", 982 | "picocolors": "^1.0.0", 983 | "postcss": "^8.4.23", 984 | "postcss-import": "^15.1.0", 985 | "postcss-js": "^4.0.1", 986 | "postcss-load-config": "^4.0.1", 987 | "postcss-nested": "^6.0.1", 988 | "postcss-selector-parser": "^6.0.11", 989 | "resolve": "^1.22.2", 990 | "sucrase": "^3.32.0" 991 | }, 992 | "bin": { 993 | "tailwind": "lib/cli.js", 994 | "tailwindcss": "lib/cli.js" 995 | }, 996 | "engines": { 997 | "node": ">=14.0.0" 998 | } 999 | }, 1000 | "node_modules/thenify": { 1001 | "version": "3.3.1", 1002 | "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", 1003 | "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", 1004 | "dev": true, 1005 | "dependencies": { 1006 | "any-promise": "^1.0.0" 1007 | } 1008 | }, 1009 | "node_modules/thenify-all": { 1010 | "version": "1.6.0", 1011 | "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", 1012 | "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", 1013 | "dev": true, 1014 | "dependencies": { 1015 | "thenify": ">= 3.1.0 < 4" 1016 | }, 1017 | "engines": { 1018 | "node": ">=0.8" 1019 | } 1020 | }, 1021 | "node_modules/to-regex-range": { 1022 | "version": "5.0.1", 1023 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1024 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1025 | "dev": true, 1026 | "dependencies": { 1027 | "is-number": "^7.0.0" 1028 | }, 1029 | "engines": { 1030 | "node": ">=8.0" 1031 | } 1032 | }, 1033 | "node_modules/ts-interface-checker": { 1034 | "version": "0.1.13", 1035 | "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", 1036 | "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", 1037 | "dev": true 1038 | }, 1039 | "node_modules/util-deprecate": { 1040 | "version": "1.0.2", 1041 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1042 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 1043 | "dev": true 1044 | }, 1045 | "node_modules/wrappy": { 1046 | "version": "1.0.2", 1047 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1048 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1049 | "dev": true 1050 | }, 1051 | "node_modules/yaml": { 1052 | "version": "2.3.3", 1053 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", 1054 | "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", 1055 | "dev": true, 1056 | "engines": { 1057 | "node": ">= 14" 1058 | } 1059 | } 1060 | } 1061 | } 1062 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@tailwindcss/aspect-ratio": "^0.4.2", 4 | "@tailwindcss/container-queries": "^0.1.1", 5 | "@tailwindcss/forms": "^0.5.6", 6 | "@tailwindcss/typography": "^0.5.10", 7 | "tailwindcss": "^3.3.3" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | const defaultTheme = require('tailwindcss/defaultTheme') 3 | 4 | module.exports = { 5 | content: [ 6 | './app/**/*.{erb,html,rb,js}' 7 | ], 8 | theme: { 9 | extend: { 10 | fontFamily: { 11 | sans: ['Inter var', ...defaultTheme.fontFamily.sans], 12 | }, 13 | }, 14 | }, 15 | plugins: [ 16 | require('@tailwindcss/forms'), 17 | require('@tailwindcss/aspect-ratio'), 18 | require('@tailwindcss/typography'), 19 | require('@tailwindcss/container-queries'), 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/controllers/.keep -------------------------------------------------------------------------------- /test/dummy/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 | -------------------------------------------------------------------------------- /test/dummy/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../stylesheets .css 3 | -------------------------------------------------------------------------------- /test/dummy/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/dummy/app/assets/images/.keep -------------------------------------------------------------------------------- /test/dummy/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /test/dummy/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | end 3 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/dummy/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /test/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /test/dummy/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | # Automatically retry jobs that encountered a deadlock 3 | # retry_on ActiveRecord::Deadlocked 4 | 5 | # Most jobs are safe to ignore if the underlying records are no longer available 6 | # discard_on ActiveJob::DeserializationError 7 | end 8 | -------------------------------------------------------------------------------- /test/dummy/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: "from@example.com" 3 | layout "mailer" 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | primary_abstract_class 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/dummy/app/models/concerns/.keep -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | 6 | <%= csrf_meta_tags %> 7 | <%= csp_meta_tag %> 8 | 9 | <%= stylesheet_link_tag "application" %> 10 | 11 | 12 | 13 | <%= yield %> 14 | 15 | 16 | -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /test/dummy/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path("../config/application", __dir__) 3 | require_relative "../config/boot" 4 | require "rails/commands" 5 | -------------------------------------------------------------------------------- /test/dummy/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative "../config/boot" 3 | require "rake" 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /test/dummy/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "fileutils" 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path("..", __dir__) 6 | 7 | def system!(*args) 8 | system(*args, exception: true) 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to set up or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts "== Installing dependencies ==" 17 | system! "gem install bundler --conservative" 18 | system("bundle check") || system!("bundle install") 19 | 20 | # puts "\n== Copying sample files ==" 21 | # unless File.exist?("config/database.yml") 22 | # FileUtils.cp "config/database.yml.sample", "config/database.yml" 23 | # end 24 | 25 | puts "\n== Preparing database ==" 26 | system! "bin/rails db:prepare" 27 | 28 | puts "\n== Removing old logs and tempfiles ==" 29 | system! "bin/rails log:clear tmp:clear" 30 | 31 | puts "\n== Restarting application server ==" 32 | system! "bin/rails restart" 33 | end 34 | -------------------------------------------------------------------------------- /test/dummy/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 | -------------------------------------------------------------------------------- /test/dummy/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 Dummy 10 | class Application < Rails::Application 11 | config.load_defaults Rails::VERSION::STRING.to_f 12 | 13 | # For compatibility with applications that use this config 14 | config.action_controller.include_all_helpers = false 15 | 16 | # Please, add to the `ignore` list any other `lib` subdirectories that do 17 | # not contain `.rb` files, or that should not be reloaded or eager loaded. 18 | # Common ones are `templates`, `generators`, or `middleware`, for example. 19 | config.autoload_lib(ignore: %w(assets tasks)) 20 | 21 | # Configuration for the application, engines, and railties goes here. 22 | # 23 | # These settings can be overridden in specific environments using the files 24 | # in config/environments, which are processed later. 25 | # 26 | # config.time_zone = "Central Time (US & Canada)" 27 | # config.eager_load_paths << Rails.root.join("extras") 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /test/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile", __dir__) 3 | 4 | require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"]) 5 | $LOAD_PATH.unshift File.expand_path("../../../lib", __dir__) 6 | -------------------------------------------------------------------------------- /test/dummy/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: test 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: dummy_production 11 | -------------------------------------------------------------------------------- /test/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite. Versions 3.8.0 and up are supported. 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem "sqlite3" 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: storage/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: storage/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: storage/production.sqlite3 26 | -------------------------------------------------------------------------------- /test/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /test/dummy/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 = { 28 | "Cache-Control" => "public, max-age=#{2.days.to_i}" 29 | } 30 | else 31 | config.action_controller.perform_caching = false 32 | 33 | config.cache_store = :null_store 34 | end 35 | 36 | # Store uploaded files on the local file system (see config/storage.yml for options). 37 | config.active_storage.service = :local 38 | 39 | # Don't care if the mailer can't send. 40 | config.action_mailer.raise_delivery_errors = false 41 | 42 | config.action_mailer.perform_caching = false 43 | 44 | # Print deprecation notices to the Rails logger. 45 | config.active_support.deprecation = :log 46 | 47 | # Raise exceptions for disallowed deprecations. 48 | config.active_support.disallowed_deprecation = :raise 49 | 50 | # Tell Active Support which deprecation messages to disallow. 51 | config.active_support.disallowed_deprecation_warnings = [] 52 | 53 | # Raise an error on page load if there are pending migrations. 54 | config.active_record.migration_error = :page_load 55 | 56 | # Highlight code that triggered database queries in logs. 57 | config.active_record.verbose_query_logs = true 58 | 59 | # Highlight code that enqueued background job in logs. 60 | config.active_job.verbose_enqueue_logs = true 61 | 62 | # Suppress logger output for asset requests. 63 | config.assets.quiet = true 64 | config.assets.check_precompiled_asset = false 65 | 66 | # Raises error for missing translations. 67 | # config.i18n.raise_on_missing_translations = true 68 | 69 | # Annotate rendered view with file names. 70 | # config.action_view.annotate_rendered_view_with_filenames = true 71 | 72 | # Uncomment if you wish to allow Action Cable access from any origin. 73 | # config.action_cable.disable_request_forgery_protection = true 74 | 75 | # Raise error when a before_action's only/except options reference missing actions 76 | config.action_controller.raise_on_missing_callback_actions = true 77 | end 78 | -------------------------------------------------------------------------------- /test/dummy/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 | # Enable static file serving from the `/public` folder (turn off if using NGINX/Apache for it). 24 | config.public_file_server.enabled = true 25 | 26 | # Compress CSS using a preprocessor. 27 | # config.assets.css_compressor = :sass 28 | 29 | # Do not fallback to assets pipeline if a precompiled asset is missed. 30 | config.assets.compile = false 31 | 32 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 33 | # config.asset_host = "http://assets.example.com" 34 | 35 | # Specifies the header that your server uses for sending files. 36 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache 37 | # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX 38 | 39 | # Store uploaded files on the local file system (see config/storage.yml for options). 40 | config.active_storage.service = :local 41 | 42 | # Mount Action Cable outside main process or domain. 43 | # config.action_cable.mount_path = nil 44 | # config.action_cable.url = "wss://example.com/cable" 45 | # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] 46 | 47 | # Assume all access to the app is happening through a SSL-terminating reverse proxy. 48 | # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. 49 | # config.assume_ssl = true 50 | 51 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 52 | config.force_ssl = true 53 | 54 | # Log to STDOUT by default 55 | config.logger = ActiveSupport::Logger.new(STDOUT) 56 | .tap { |logger| logger.formatter = ::Logger::Formatter.new } 57 | .then { |logger| ActiveSupport::TaggedLogging.new(logger) } 58 | 59 | # Prepend all log lines with the following tags. 60 | config.log_tags = [ :request_id ] 61 | 62 | # Info include generic and useful information about system operation, but avoids logging too much 63 | # information to avoid inadvertent exposure of personally identifiable information (PII). If you 64 | # want to log everything, set the level to "debug". 65 | config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") 66 | 67 | # Use a different cache store in production. 68 | # config.cache_store = :mem_cache_store 69 | 70 | # Use a real queuing backend for Active Job (and separate queues per environment). 71 | # config.active_job.queue_adapter = :resque 72 | # config.active_job.queue_name_prefix = "dummy_production" 73 | 74 | config.action_mailer.perform_caching = false 75 | 76 | # Ignore bad email addresses and do not raise email delivery errors. 77 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 78 | # config.action_mailer.raise_delivery_errors = false 79 | 80 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 81 | # the I18n.default_locale when a translation cannot be found). 82 | config.i18n.fallbacks = true 83 | 84 | # Don't log any deprecations. 85 | config.active_support.report_deprecations = false 86 | 87 | # Do not dump schema after migrations. 88 | config.active_record.dump_schema_after_migration = false 89 | 90 | # Enable DNS rebinding protection and other `Host` header attacks. 91 | # config.hosts = [ 92 | # "example.com", # Allow requests from example.com 93 | # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` 94 | # ] 95 | # Skip DNS rebinding protection for the default health check endpoint. 96 | # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } 97 | end 98 | -------------------------------------------------------------------------------- /test/dummy/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.enabled = true 22 | config.public_file_server.headers = { 23 | "Cache-Control" => "public, max-age=#{1.hour.to_i}" 24 | } 25 | 26 | # Show full error reports and disable caching. 27 | config.consider_all_requests_local = true 28 | config.action_controller.perform_caching = false 29 | config.cache_store = :null_store 30 | 31 | # Raise exceptions instead of rendering exception templates. 32 | config.action_dispatch.show_exceptions = :rescuable 33 | 34 | # Disable request forgery protection in test environment. 35 | config.action_controller.allow_forgery_protection = false 36 | 37 | # Store uploaded files on the local file system in a temporary directory. 38 | config.active_storage.service = :test 39 | 40 | config.action_mailer.perform_caching = false 41 | 42 | # Tell Action Mailer not to deliver emails to the real world. 43 | # The :test delivery method accumulates sent emails in the 44 | # ActionMailer::Base.deliveries array. 45 | config.action_mailer.delivery_method = :test 46 | 47 | # Print deprecation notices to the stderr. 48 | config.active_support.deprecation = :stderr 49 | 50 | # Raise exceptions for disallowed deprecations. 51 | config.active_support.disallowed_deprecation = :raise 52 | 53 | # Tell Active Support which deprecation messages to disallow. 54 | config.active_support.disallowed_deprecation_warnings = [] 55 | 56 | # Raises error for missing translations. 57 | # config.i18n.raise_on_missing_translations = true 58 | 59 | # Annotate rendered view with file names. 60 | # config.action_view.annotate_rendered_view_with_filenames = true 61 | 62 | # Raise error when a before_action's only/except options reference missing actions 63 | config.action_controller.raise_on_missing_callback_actions = true 64 | end 65 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = "1.0" 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in the app/assets 11 | # folder are already added. 12 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 13 | -------------------------------------------------------------------------------- /test/dummy/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 | -------------------------------------------------------------------------------- /test/dummy/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, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn 8 | ] 9 | -------------------------------------------------------------------------------- /test/dummy/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 | -------------------------------------------------------------------------------- /test/dummy/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 | -------------------------------------------------------------------------------- /test/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization and 2 | # are automatically loaded by Rails. If you want to use locales other than 3 | # 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 | # To learn more about the API, please read the Rails Internationalization guide 20 | # at https://guides.rubyonrails.org/i18n.html. 21 | # 22 | # Be aware that YAML interprets the following case-insensitive strings as 23 | # booleans: `true`, `false`, `on`, `off`, `yes`, `no`. Therefore, these strings 24 | # must be quoted to be interpreted as strings. For example: 25 | # 26 | # en: 27 | # "yes": yup 28 | # enabled: "ON" 29 | 30 | en: 31 | hello: "Hello world" 32 | -------------------------------------------------------------------------------- /test/dummy/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 can serve each request in a thread from an internal thread pool. 6 | # The `threads` method setting takes two numbers: a minimum and maximum. 7 | # Any libraries that use thread pools should be configured to match 8 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 9 | # and maximum; this matches the default thread size of Active Record. 10 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 11 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 12 | threads min_threads_count, max_threads_count 13 | 14 | # Specifies that the worker count should equal the number of processors in production. 15 | if ENV["RAILS_ENV"] == "production" 16 | require "concurrent-ruby" 17 | worker_count = Integer(ENV.fetch("WEB_CONCURRENCY") { Concurrent.physical_processor_count }) 18 | workers worker_count if worker_count > 1 19 | end 20 | 21 | # Specifies the `worker_timeout` threshold that Puma will use to wait before 22 | # terminating a worker in development environments. 23 | worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" 24 | 25 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 26 | port ENV.fetch("PORT") { 3000 } 27 | 28 | # Specifies the `environment` that Puma will run in. 29 | environment ENV.fetch("RAILS_ENV") { "development" } 30 | 31 | # Specifies the `pidfile` that Puma will use. 32 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 33 | 34 | # Allow puma to be restarted by `bin/rails restart` command. 35 | plugin :tmp_restart 36 | -------------------------------------------------------------------------------- /test/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | mount Deployed::Engine => "/deployed" 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/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 | 9 | # Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket-<%= Rails.env %> 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket-<%= Rails.env %> 23 | 24 | # Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name-<%= Rails.env %> 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /test/dummy/config/tailwind.config.js: -------------------------------------------------------------------------------- 1 | const defaultTheme = require('tailwindcss/defaultTheme') 2 | 3 | module.exports = { 4 | content: [ 5 | '../public/*.html', 6 | '../app/helpers/**/*.rb', 7 | '../app/javascript/**/*.js', 8 | '../app/views/**/*.{erb,haml,html,slim}' 9 | ], 10 | theme: { 11 | extend: { 12 | fontFamily: { 13 | sans: ['Inter var', ...defaultTheme.fontFamily.sans], 14 | }, 15 | }, 16 | }, 17 | plugins: [ 18 | require('@tailwindcss/forms'), 19 | require('@tailwindcss/aspect-ratio'), 20 | require('@tailwindcss/typography'), 21 | require('@tailwindcss/container-queries'), 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /test/dummy/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/dummy/lib/assets/.keep -------------------------------------------------------------------------------- /test/dummy/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/dummy/log/.keep -------------------------------------------------------------------------------- /test/dummy/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /test/dummy/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /test/dummy/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /test/dummy/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/dummy/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /test/dummy/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/dummy/public/apple-touch-icon.png -------------------------------------------------------------------------------- /test/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/dummy/public/favicon.ico -------------------------------------------------------------------------------- /test/fixtures/files/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/fixtures/files/.keep -------------------------------------------------------------------------------- /test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/helpers/.keep -------------------------------------------------------------------------------- /test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/integration/.keep -------------------------------------------------------------------------------- /test/integration/navigation_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class NavigationTest < ActionDispatch::IntegrationTest 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/kamal_rails_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class DeployedTest < ActiveSupport::TestCase 4 | test "it has a version number" do 5 | assert Deployed::VERSION 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/mailers/.keep -------------------------------------------------------------------------------- /test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geetfun/deployed/e88439b8822b70d54f4035e8d0feba805d4e4a8c/test/models/.keep -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # Configure Rails Environment 2 | ENV["RAILS_ENV"] = "test" 3 | 4 | require_relative "../test/dummy/config/environment" 5 | ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)] 6 | ActiveRecord::Migrator.migrations_paths << File.expand_path("../db/migrate", __dir__) 7 | require "rails/test_help" 8 | 9 | # Load fixtures from the engine 10 | if ActiveSupport::TestCase.respond_to?(:fixture_paths=) 11 | ActiveSupport::TestCase.fixture_paths = [File.expand_path("fixtures", __dir__)] 12 | ActionDispatch::IntegrationTest.fixture_paths = ActiveSupport::TestCase.fixture_paths 13 | ActiveSupport::TestCase.file_fixture_path = File.expand_path("fixtures", __dir__) + "/files" 14 | ActiveSupport::TestCase.fixtures :all 15 | end 16 | --------------------------------------------------------------------------------