Seems working
M Gemfile +1 -0
@@ 2,6 2,7 @@ source "https://rubygems.org"
 
 gem "rails", "~> 6.0.0"
 gem "sass-rails"
+gem "autoprefixer-rails"
 gem "webpacker"
 
 # Bundle edge Rails instead:

          
M Gemfile.lock +4 -0
@@ 61,10 61,13 @@ GEM
       minitest (~> 5.1)
       tzinfo (~> 1.1)
       zeitwerk (~> 2.2)
+    autoprefixer-rails (9.7.4)
+      execjs
     builder (3.2.4)
     concurrent-ruby (1.1.6)
     crass (1.0.6)
     erubi (1.9.0)
+    execjs (2.7.0)
     ffi (1.12.2)
     ffi (1.12.2-java)
     globalid (0.4.2)

          
@@ 171,6 174,7 @@ PLATFORMS
 
 DEPENDENCIES
   activerecord-jdbcpostgresql-adapter
+  autoprefixer-rails
   jruby-openssl
   newrelic_rpm
   pg

          
R app/assets/stylesheets/_bootstrap-zp.scss =>  +0 -58
@@ 1,58 0,0 @@ 
-/*!
- * Bootstrap v3.3.5 (http://getbootstrap.com)
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- *
- * Modified for Zeropaste
- */
-
-// Core variables and mixins
-@import "bootstrap-sass/assets/stylesheets/bootstrap/variables";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/mixins";
-
-// Reset and dependencies
-@import "bootstrap-sass/assets/stylesheets/bootstrap/normalize";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/print";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/glyphicons";
-
-// Core CSS
-@import "bootstrap-sass/assets/stylesheets/bootstrap/scaffolding";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/type";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/code";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/grid";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/tables";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/forms";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/buttons";
-
-// Components
-@import "bootstrap-sass/assets/stylesheets/bootstrap/component-animations";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/dropdowns";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/button-groups";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/input-groups";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/navs";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/navbar";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/breadcrumbs";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/pagination";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/pager";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/labels";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/badges";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/jumbotron";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/thumbnails";
-@import "bootstrap-sass/assets/stylesheets/bootstrap/alerts";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/progress-bars";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/media";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/list-group";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/panels";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/responsive-embed";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/wells";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/close";
-
-// Components w/ JavaScript
-@import "bootstrap-sass/assets/stylesheets/bootstrap/modals";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/tooltip";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/popovers";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/carousel";
-
-// Utility classes
-@import "bootstrap-sass/assets/stylesheets/bootstrap/utilities";
-// @import "bootstrap-sass/assets/stylesheets/bootstrap/responsive-utilities";

          
M app/assets/stylesheets/application.scss +11 -32
@@ 1,20 1,19 @@ 
-@import "bootstrap-zp";
+@import "bootstrap/scss/bootstrap";
 @import "highlight.js/scss/default";
 
 .input-url1 { display: none !important; }
 
-// overrides bootstrap
-.form-control {
-  font-size: 16px;
-}
-
-.form-group--narrow {
-  max-width: 300px;
-}
-
 .paste-paste {
   resize: vertical;
   font-family: $font-family-monospace;
+  max-height: 100vh;
+}
+
+.paste-content {
+  border: none;
+  background-color: #fff;
+  padding: 0px;
+  margin: 0px;
 }
 
 .paste-show {

          
@@ 23,31 22,11 @@ 
 
   border-width: 0px 1px 1px 1px;
   border-style: solid;
-  border-color: $nav-tabs-active-link-hover-border-color;
-  border-radius: 0px 0px $border-radius-base $border-radius-base;
-
-  &__content {
-    border: none;
-    background-color: #fff;
-    padding: 0px;
-    margin: 0px;
-  }
-
-  &__footer {
-    padding-bottom: $grid-gutter-width/2;
-  }
-}
-
-.radio-container {
-  margin-top: -10px;
+  border-color: $nav-tabs-border-color;
+  border-radius: 0px 0px $border-radius $border-radius;
 }
 
 .zp-hl {
   background-color: #fff;
   padding: 0px;
 }
-
-.zp-header {
-  margin-top: 0px;
-}
-

          
M app/helpers/application_helper.rb +1 -1
@@ 9,7 9,7 @@ module ApplicationHelper
   end
 
   def error_class(object, attribute)
-    "has-error" if object.errors.include? attribute
+    "is-invalid" if object.errors.include? attribute
   end
 
   def with_host(url)

          
M app/javascript/src/main.coffee +1 -4
@@ 1,7 1,4 @@ 
-import 'bootstrap/js/transition'
-import 'bootstrap/js/collapse'
-import 'bootstrap/js/modal'
-import 'bootstrap/js/tab'
+import 'bootstrap'
 import hljs from 'highlight.js'
 import * as commonmark from 'commonmark'
 

          
M app/views/layouts/_alerts.html.erb +2 -2
@@ 1,12 1,12 @@ 
 <% if notice %>
-  <div class="alert alert-info">
+  <div class="alert alert-info" role="alert">
     <strong><%= t(".info") %>:</strong>
     <%= notice %>
   </div>
 <% end %>
 
 <% if alert %>
-  <div class="alert alert-danger">
+  <div class="alert alert-danger" role="alert">
     <strong><%= t(".error") %>:</strong>
     <%= alert %>
   </div>

          
M app/views/layouts/application.html.erb +32 -23
@@ 7,32 7,41 @@ 
     <%= stylesheet_link_tag "application", :media => "all" %>
   </head>
   <body>
-    <nav class="navbar navbar-default navbar-static-top">
+    <nav class="navbar navbar-expand-lg navbar-light bg-light">
       <div class="container">
-        <div class="navbar-header">
-          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-menu">
-            <span class="sr-only">Toggle navigation</span>
-            <span class="icon-bar"></span>
-            <span class="icon-bar"></span>
-            <span class="icon-bar"></span>
-          </button>
-          <%= link_to "Zeropaste", root_path, :class => "navbar-brand" %>
-        </div>
+        <%= link_to "Zeropaste", root_path, :class => "navbar-brand" %>
+
+        <button
+          type="button"
+          class="navbar-toggler"
+          data-toggle="collapse"
+          data-target="#navbar-menu"
+          aria-controls="navbar-menu"
+          aria-expanded="false"
+          aria-label="<%= t('.toggle_nav') %>"
+        >
+          <span class="navbar-toggler-icon"></span>
+        </button>
 
         <div class="collapse navbar-collapse" id="navbar-menu">
-          <ul class="nav navbar-nav navbar-right">
-            <li>
-              <%= link_to t(".about"), "#",
-                  :data => { :toggle => "modal",
-                  :target => "#modal-about" }
+          <ul class="navbar-nav ml-auto">
+            <li class="nav-item">
+              <%= link_to t(".about"), "#", {
+                    data: {
+                      toggle: "modal",
+                      target: "#modal-about",
+                    },
+                    class: 'nav-link',
+                  }
               %>
             </li>
-            <li>
-              <a href="https://bitbucket.org/nanayapro/zeropaste"><%= t(".source") %></a>
+            <li class="nav-item">
+              <a class="nav-link" href="https://hg.sr.ht/~nanaya/zeropaste"><%= t(".source") %></a>
             </li>
-            <li>
+            <li class="nav-item">
               <%= link_to t(".donate"),
-                  "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=GV9AHVHQAHXLJ"
+                  "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=GV9AHVHQAHXLJ",
+                  class: 'nav-link'
               %>
             </li>
           </ul>

          
@@ 41,8 50,8 @@ 
     </nav>
 
     <div class="container">
-      <div class="row"><div class="col-xs-12">
-        <h1 class="h2 zp-header page-header"><%= content_for :title %></h1>
+      <div class="row"><div class="col-12">
+        <h1 class="h2 pt-3 pb-1"><%= content_for :title %></h1>
       </div></div>
 
       <%= render "layouts/alerts" %>

          
@@ 51,7 60,7 @@ 
 
     </div>
 
-    <div class="modal fade" id="modal-about" tabindex="-1" role="dialog" aria-labelledby="about-modal-label">
+    <div class="modal fade" id="modal-about" tabindex="-1" role="dialog" aria-labelledby="about-modal-label" aria-hidden="true">
       <div class="modal-dialog" role="document">
         <div class="modal-content">
           <div class="modal-header">

          
@@ 62,7 71,7 @@ 
             <%= render "layouts/about" %>
           </div>
           <div class="modal-footer">
-            <button type="button" class="btn btn-default" data-dismiss="modal">
+            <button type="button" class="btn btn-secondary" data-dismiss="modal">
               <%= t("buttons.close") %>
             </button>
           </div>

          
M app/views/pastes/new.html.erb +36 -21
@@ 3,41 3,56 @@ 
 <%= form_for @paste do |f| %>
   <%= render "shared/filter_spam" %>
 
-  <div class="form-group <%= error_class f.object, :paste %>">
-    <%= f.text_area :paste, :autofocus => true, :class => "form-control paste-paste js-paste-paste", :rows => 20 %>
+  <div class="form-group">
+    <%= f.text_area :paste,
+      autofocus: true,
+      class: "form-control paste-paste js-paste-paste #{error_class f.object, :paste}",
+      rows: 20
+    %>
   </div>
 
 
-  <div class="row"><div class="col-xs-12">
-      <%= link_to t(".preview_md"), "#",
-          :class => "btn btn-default js-paste-preview-md pull-right"
-      %>
+  <div class="row"><div class="col-12">
+      <button type="button" class="btn btn-secondary ml-auto d-block js-paste-preview-md">
+        <%= t(".preview_md") %>
+      </button>
   </div></div>
 
-  <div class="form-group <%= error_class f.object, :key %> form-group--narrow">
-    <%= f.label :key, t(".deletion_key") %>
-    <%= f.text_field :key, :autocomplete => "off", :class => "form-control" %>
+  <div class="form-group row">
+    <%= f.label :key, t('.deletion_key'), class: 'col-sm-2 col-form-label' %>
+
+    <div class="col-auto">
+      <%= f.text_field :key,
+        autocomplete: 'off',
+        class: "form-control #{error_class f.object, :key}"
+      %>
+    </div>
   </div>
 
-  <div class="form-group">
-    <label><%= t(".privacy.label") %></label>
+  <div class="form-group row">
+    <label class="col-sm-2 col-form-label pt-0">
+      <%= t(".privacy.label") %>
+    </label>
 
-    <div class="radio-container">
+    <div class="col-sm-10">
       <% paste_privacy_options.each do |label, value| %>
-        <div class="radio">
-          <label>
-            <%= f.radio_button :is_private, value %>
+        <label class="custom-control custom-radio mb-0">
+          <%= f.radio_button :is_private, value, class: 'custom-control-input' %>
+
+          <span class="custom-control-label d-inline-block">
             <%= t(".privacy.#{label}") %>
-          </label>
-        </div>
+          </span>
+        </label>
       <% end %>
     </div>
   </div>
 
-  <div class="form-group form-group--narrow">
-    <%= f.label :language %>
+  <div class="form-group row">
+    <%= f.label :language, class: 'col-sm-2 col-form-label' %>
 
-    <%= f.select :language, [], { :prompt => t(".language_none") }, :class => "form-control" %>
+    <div class="col-auto">
+      <%= f.select :language, [], { prompt: t(".language_none") }, class: 'custom-select' %>
+    </div>
   </div>
 
   <div class="form-group">

          
@@ 53,7 68,7 @@ 
       <div class="modal-body js-paste-preview-md-box">
       </div>
       <div class="modal-footer">
-        <button type="button" class="btn btn-default" data-dismiss="modal">
+        <button type="button" class="btn btn-secondary" data-dismiss="modal">
           <%= t("buttons.close") %>
         </button>
       </div>

          
M app/views/pastes/show.html.erb +48 -54
@@ 1,71 1,65 @@ 
 <% provide :title, "Paste ##{@paste.id}" %>
 
-<div class="row"><div class="col-xs-12">
-  <ul class="nav nav-tabs" role="tablist">
-    <% [
-        { :title => t(".plain"), :target => "pl", :active => true },
-        { :title => t(".highlight"), :target => "hl" },
-        { :title => t(".markdown"), :target => "md" }
-    ].each do |el| %>
-      <li role="presentation" class="<%= "active" if el[:active] %>">
-        <%= link_to el[:title], "##{el[:target]}",
-            :data => {
-              :mode => el[:target],
-              :toggle => "tab"
-            },
-            :aria => { :controls => el[:target] },
-            :role => "tab",
-            :class => "js-show-tab"
-        %>
-      </li>
-    <% end %>
-  </ul>
-</div></div>
+<ul class="nav nav-tabs" role="tablist">
+  <% [
+      { title: t(".plain"), target: 'pl', active: true },
+      { title: t(".highlight"), target: 'hl' },
+      { title: t(".markdown"), target: 'md' }
+  ].each do |el| %>
+    <li class="nav-item">
+      <%= link_to el[:title], "##{el[:target]}",
+          data: {
+            mode: el[:target],
+            toggle: 'tab',
+          },
+          aria: { controls: el[:target] },
+          role: 'tab',
+          class: "nav-link #{"active" if el[:active]} js-show-tab"
+      %>
+    </li>
+  <% end %>
+</ul>
 
-<div class="row js-showing-paste"><div class="col-xs-12"><div class="paste-show">
+<div class="js-showing-paste paste-show">
   <div class="tab-content">
     <div role="tabpanel" class="tab-pane active" id="pl">
-      <pre class="paste-show__content"><code class="js-paste-pl"><%= @paste.paste %></code></pre>
+      <pre class="paste-content"><code class="js-paste-pl"><%= @paste.paste %></code></pre>
     </div>
 
     <div role="tabpanel" class="tab-pane" id="hl">
-      <pre class="paste-show__content"><code class="js-paste-hl zp-hl lang-<%= @paste.language.try(:parameterize) %>"></code></pre>
+      <pre class="paste-content"><code class="js-paste-hl zp-hl lang-<%= @paste.language.try(:parameterize) %>"></code></pre>
     </div>
 
     <div role="tabpanel" class="tab-pane" id="md">
       <div class="js-paste-md"></div>
     </div>
   </div>
-</div></div></div>
+</div>
 
-<div class="row"><div class="col-xs-12">
-  <%= form_for @paste, :method => :delete, :authenticity_token => false do |f| %>
-    <div class="form-group form-group--narrow <%= error_class f.object, :key %>">
-      <div class="input-group">
-        <%= f.text_field :key,
-            :value => nil,
-            :placeholder => t("pastes.new.deletion_key"),
-            :autofocus => f.object.errors.any?,
-            :autocomplete => "off",
-            :class => "form-control"
-        %>
+<%= form_for @paste, method: :delete, authenticity_token: false, html: { class: 'form-row' } do |f| %>
+  <div class="col-auto my-1">
+    <%= f.text_field :key,
+        value: nil,
+        placeholder: t('pastes.new.deletion_key'),
+        autofocus: f.object.errors.any?,
+        autocomplete: 'off',
+        class: "form-control w-auto #{error_class f.object, :key}"
+    %>
+  </div>
 
-        <span class="input-group-btn">
-          <%= f.button t(".delete"), :class => "btn btn-danger" %>
-        </span>
-      </div>
-    </div>
-  <% end %>
-</div></div>
+  <div class="col-auto my-1">
+    <%= f.button t(".delete"), class: 'btn btn-danger' %>
+  </div>
+<% end %>
 
-<ul class="nav nav-pills paste-show__footer">
-    <li role="presentation">
-      <%= link_to t(".raw"), paste_path(@paste, :txt) %>
-    </li>
-    <li role="presentation">
-      <%= link_to t(".derive"), root_path(:base => @paste) %>
-    </li>
-    <li role="presentation">
-      <%= link_to t(".more"), root_path %>
-    </li>
-</ul>
+<div class="row mt-4">
+    <% [
+      [t('.raw'), paste_path(@paste, :txt)],
+      [t('.derive'), root_path(:base => @paste)],
+      [t('.more'), root_path],
+    ].each do |label, url| %>
+      <div class="col-auto">
+        <%= link_to label, url %>
+      </div>
+    <% end %>
+</div>

          
M config/locales/en.yml +1 -0
@@ 13,6 13,7 @@ en:
       about: About
       donate: Donate
       source: Source
+      toggle_nav: Toggle navigation
 
   pastes:
     new:

          
M config/webpack/environment.js +0 -2
@@ 5,8 5,6 @@ const webpack = require('webpack')
 environment.plugins.append('Provide',
   new webpack.ProvidePlugin({
     $: 'jquery',
-    jQuery: 'jquery',
-    Popper: ['popper.js', 'default']
   })
 )
 

          
M package.json +4 -4
@@ 3,13 3,13 @@ 
   "private": true,
   "dependencies": {
     "@rails/webpacker": "4.2.2",
-    "bootstrap": "3",
-    "bootstrap-sass": "^3.4.1",
+    "bootstrap": "4.4.1",
     "coffee-loader": "^0.9.0",
-    "coffeescript": "1.12.7",
+    "coffeescript": "2.5.1",
     "commonmark": "^0.29.1",
     "highlight.js": "^9.18.1",
-    "jquery": "^3.4.1"
+    "jquery": "^3.4.1",
+    "popper.js": "^1.16.1"
   },
   "version": "0.1.0",
   "devDependencies": {

          
M yarn.lock +13 -13
@@ 1369,15 1369,10 @@ boolbase@^1.0.0, boolbase@~1.0.0:
   resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
   integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
 
-bootstrap-sass@^3.4.1:
-  version "3.4.1"
-  resolved "https://registry.yarnpkg.com/bootstrap-sass/-/bootstrap-sass-3.4.1.tgz#6843c73b1c258a0ac5cb2cc6f6f5285b664a8e9a"
-  integrity sha512-p5rxsK/IyEDQm2CwiHxxUi0MZZtvVFbhWmyMOt4lLkA4bujDA1TGoKT0i1FKIWiugAdP+kK8T5KMDFIKQCLYIA==
-
-bootstrap@3:
-  version "3.4.1"
-  resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.4.1.tgz#c3a347d419e289ad11f4033e3c4132b87c081d72"
-  integrity sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==
+bootstrap@4.4.1:
+  version "4.4.1"
+  resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.4.1.tgz#8582960eea0c5cd2bede84d8b0baf3789c3e8b01"
+  integrity sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==
 
 brace-expansion@^1.1.7:
   version "1.1.11"

          
@@ 1778,10 1773,10 @@ coffee-loader@^0.9.0:
   dependencies:
     loader-utils "^1.0.2"
 
-coffeescript@1.12.7:
-  version "1.12.7"
-  resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-1.12.7.tgz#e57ee4c4867cf7f606bfc4a0f2d550c0981ddd27"
-  integrity sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA==
+coffeescript@2.5.1:
+  version "2.5.1"
+  resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-2.5.1.tgz#b2442a1f2c806139669534a54adc35010559d16a"
+  integrity sha512-J2jRPX0eeFh5VKyVnoLrfVFgLZtnnmp96WQSLAS8OrLm2wtQLcnikYKe1gViJKDH7vucjuhHvBKKBP3rKcD1tQ==
 
 collection-visit@^1.0.0:
   version "1.0.0"

          
@@ 5076,6 5071,11 @@ pnp-webpack-plugin@^1.5.0:
   dependencies:
     ts-pnp "^1.1.6"
 
+popper.js@^1.16.1:
+  version "1.16.1"
+  resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
+  integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
+
 portfinder@^1.0.25:
   version "1.0.25"
   resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca"