diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index 2b38b4b8101..c0134c6bbde 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -1,4 +1,5 @@ //= link application.css +//= link hammy.css //= link_tree ../../../vendor/assets/images //= link_tree ../builds //= link_tree ../../javascript .js diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css index f575b6d8902..9a9e22c1a76 100644 --- a/app/assets/stylesheets/application.tailwind.css +++ b/app/assets/stylesheets/application.tailwind.css @@ -1,7 +1,5 @@ @config "../../../config/tailwind.config.js"; @tailwind base; -@tailwind components; -@tailwind utilities; @layer base { @font-face { @@ -9,6 +7,9 @@ font-style: normal; font-weight: 400; font-display: swap; - src: url(/fonts/Roboto.woff2) format('woff2'); } + } + +@tailwind components; +@tailwind utilities; diff --git a/app/assets/stylesheets/hammy.css b/app/assets/stylesheets/hammy.css new file mode 100644 index 00000000000..e54d84913b6 --- /dev/null +++ b/app/assets/stylesheets/hammy.css @@ -0,0 +1,11 @@ +/* + * This is a manifest file that'll automatically include all the stylesheets available in this directory + * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at + * the top of the compiled file, but it's generally better to create a new file per style scope. + *= require_self +*/ + +/* Default browser style adds a max width that is hard to override with tailwind directly */ +dialog:modal { + max-width: 100vw; +} diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d017ae5a988..65861579447 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -62,6 +62,15 @@ def self.http_basic_authenticate_with(**options) super end + def breadcrumbs + @breadcrumbs ||= [] + end + helper_method :breadcrumbs + + def add_breadcrumb(name, link = nil) + breadcrumbs << [name, link] + end + protected def http_basic_authentication_options_valid?(**options) diff --git a/app/controllers/dashboards_controller.rb b/app/controllers/dashboards_controller.rb index 79e8b999ce6..b4da09e50a0 100644 --- a/app/controllers/dashboards_controller.rb +++ b/app/controllers/dashboards_controller.rb @@ -5,6 +5,8 @@ class DashboardsController < ApplicationController before_action :redirect_to_settings_strong_mfa_required, if: :mfa_required_weak_level_enabled? def show + add_breadcrumb t("breadcrumbs.dashboard"), dashboard_path + respond_to do |format| format.html do @my_gems = current_user.rubygems.with_versions.by_name.preload(:most_recent_version) diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index 767ce234925..c47d16291c4 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -1,7 +1,10 @@ class PagesController < ApplicationController before_action :find_page + layout "hammy" + def show + add_breadcrumb t("pages.#{@page}.title") render @page end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c2dac569d41..46f44560c59 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -75,7 +75,7 @@ def flash_message(name, msg) msg end - def rubygem_search_field(home: false) + def rubygem_search_field(home: false, **kwargs) data = { autocomplete_target: "query", action: %w[ @@ -89,17 +89,21 @@ def rubygem_search_field(home: false) blur->autocomplete#hide ].join(" ") } - data[:nav_target] = "search" unless home + aria = { autocomplete: "list" } + + data.merge!(kwargs.delete(:data)) if kwargs[:data] + aria.merge!(kwargs.delete(:aria)) if kwargs[:aria] search_field_tag( :query, params[:query], placeholder: t("layouts.application.header.search_gem_html"), autofocus: current_page?(root_url), - class: home ? "home__search" : "header__search", + class: kwargs[:class], autocomplete: "off", - aria: { autocomplete: "list" }, - data: data + aria:, + data:, + **kwargs ) end end diff --git a/app/helpers/prose_helper.rb b/app/helpers/prose_helper.rb new file mode 100644 index 00000000000..50dda78bec9 --- /dev/null +++ b/app/helpers/prose_helper.rb @@ -0,0 +1,9 @@ +module ProseHelper + + def prose(&) + base = "prose prose-neutral dark:prose-invert prose-lg lg:prose-xl max-w-prose mx-auto" + styles = "prose-headings:font-semibold" + tag.div class: "#{base} #{styles}", & + end + +end diff --git a/app/javascript/controllers/autocomplete_controller.js b/app/javascript/controllers/autocomplete_controller.js index a840f4eb1d1..c933cd6df2b 100644 --- a/app/javascript/controllers/autocomplete_controller.js +++ b/app/javascript/controllers/autocomplete_controller.js @@ -14,6 +14,7 @@ export default class extends Controller { disconnect() { clear() } clear() { + this.suggestionsTarget.classList.add('hidden'); this.suggestionsTarget.innerHTML = "" this.suggestionsTarget.removeAttribute('tabindex'); this.suggestionsTarget.removeAttribute('aria-activedescendant'); @@ -25,12 +26,14 @@ export default class extends Controller { } next() { + if (this.suggestLength === 0) return; this.indexNumber++; if (this.indexNumber >= this.suggestLength) this.indexNumber = 0; this.focusItem(this.itemTargets[this.indexNumber]); } prev() { + if (this.suggestLength === 0) return; this.indexNumber--; if (this.indexNumber < 0) this.indexNumber = this.suggestLength - 1; this.focusItem(this.itemTargets[this.indexNumber]); @@ -78,6 +81,7 @@ export default class extends Controller { items.forEach((item, idx) => this.appendItem(item, idx)); this.suggestionsTarget.setAttribute('tabindex', 0); this.suggestionsTarget.setAttribute('role', 'listbox'); + this.suggestionsTarget.classList.remove('hidden'); this.suggestLength = items.length; this.indexNumber = -1; @@ -92,8 +96,9 @@ export default class extends Controller { } focusItem(el, change = true) { - this.itemTargets.forEach(el => el.classList.remove(this.selectedClass)) - el.classList.add(this.selectedClass); + if (!el) { return; } + this.itemTargets.forEach(el => el.classList.remove(...this.selectedClasses)) + el.classList.add(...this.selectedClasses); this.suggestionsTarget.setAttribute('aria-activedescendant', el.id); if (change) { this.queryTarget.value = el.textContent; diff --git a/app/javascript/controllers/dialog_controller.js b/app/javascript/controllers/dialog_controller.js new file mode 100644 index 00000000000..4ae72c551d9 --- /dev/null +++ b/app/javascript/controllers/dialog_controller.js @@ -0,0 +1,23 @@ +import Dialog from '@stimulus-components/dialog' + +export default class extends Dialog { + static targets = ["dialog", "button"] + + connect() { + super.connect() + } + + open() { + super.open() + if (this.hasButtonTarget) { + this.buttonTarget.ariaExpanded = true + } + } + + close() { + if (this.hasButtonTarget) { + this.buttonTarget.ariaExpanded = false + } + super.close() + } +} diff --git a/app/javascript/controllers/reveal_controller.js b/app/javascript/controllers/reveal_controller.js new file mode 100644 index 00000000000..8f32bfea4c4 --- /dev/null +++ b/app/javascript/controllers/reveal_controller.js @@ -0,0 +1,44 @@ +import Reveal from '@stimulus-components/reveal' + +export default class extends Reveal { + static targets = ["item", "toggle", "button"] + static classes = ["hidden", "toggle"] + + connect() { + super.connect() + if (this.hasButtonTarget) { + this.buttonTarget.ariaExpanded = false + } + } + toggle() { + super.toggle() + if (this.hasButtonTarget) { + this.buttonTarget.ariaExpanded = this.buttonTarget.ariaExpanded !== "true" + } + if (this.hasToggleTarget && this.hasToggleClass) { + this.toggleClasses.forEach((className) => { + this.toggleTarget.classList.toggle(className) + }) + } + } + + show() { + super.show() + if (this.hasButtonTarget) { + this.buttonTarget.ariaExpanded = true + } + if (this.hasToggleTarget && this.hasToggleClass) { + this.toggleTarget.classList.add(...this.toggleClasses) + } + } + + hide() { + super.hide() + if (this.hasToggleTarget) { + this.buttonTarget.ariaExpanded = false + } + if (this.hasToggleTarget && this.hasToggleClass) { + this.toggleTarget.classList.add(...this.toggleClasses) + } + } +} diff --git a/app/javascript/controllers/reveal_search_controller.js b/app/javascript/controllers/reveal_search_controller.js new file mode 100644 index 00000000000..683c1a73cdb --- /dev/null +++ b/app/javascript/controllers/reveal_search_controller.js @@ -0,0 +1,19 @@ +import Reveal from './reveal_controller' + +export default class extends Reveal { + static targets = ["item", "toggle", "button", "input"] + + // There's nothing here because this is just a copy of the reveal controller + // with a different name. This saves us from a name conflict in the header. + toggle() { + super.toggle() + if (!this.itemTarget.classList.contains("hidden")) { + this.inputTarget.focus() // Auto focus the input when revealed + } + } + + open() { + super.open() + this.inputTarget.focus() + } +} diff --git a/app/views/components/button_component.rb b/app/views/components/button_component.rb new file mode 100644 index 00000000000..0dec3ec2ee6 --- /dev/null +++ b/app/views/components/button_component.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +class ButtonComponent < ApplicationComponent + include Phlex::Rails::Helpers::LinkTo + include Phlex::Rails::Helpers::ButtonTo + + attr_reader :text, :href, :type, :options, :color_css, :size_css + + def initialize(text=nil, href: nil, type: :button, color: :primary, outline: false, size: :large, **options) + @text = text + @href = href + @type = type + @options = options + @options[:name] ||= nil + @color_css = button_color(color, outline) + @size_css = button_size(size) + end + + def view_template(&) + css = "text-nowrap font-semibold no-underline " \ + "rounded inline-flex border-box " \ + "justify-content-center items-center hover:shadow-md " \ + "transition duration-200 ease-in-out focus:outline-none " \ + "#{color_css} #{size_css} #{options.delete(:class)}" + + if type == :link + link_to text, href, class: css, **options, & + elsif href + button_to text, href, class: css, **options, & + else + button(class: css, type:, **options, &) + end + end + + private + + def button_color(color, outline) + color = color.to_sym + color = :orange if color == :primary + color = :orange2 if color == :secondary + @color_css = outline ? OUTLINE_BUTTON_COLOR[color] : FILL_BUTTON_COLOR[color] + end + + def button_size(size) + case size + when :small # 36px height + "px-4 py-3 h-9 min-h-9 text-b3" + else # :large, 44px height + "px-4 py-3 h-12 min-h-12 text-b2" \ + end + end + + FILL_BUTTON_COLOR = { + orange: "text-white bg-orange-500 dark:bg-orange-500 hover:bg-orange-600 dark:hover:bg-orange-700 active:bg-orange-600 dark:active:bg-orange-700", + orange2: "text-neutral-800 dark:text-white bg-orange-200 dark:bg-orange-800 hover:bg-orange-300 dark:hover:bg-orange-900 active:bg-orange-300 dark:active:bg-orange-900", + yellow: "text-neutral-800 dark:text-white bg-yellow-500 dark:bg-yellow-500 hover:bg-yellow-600 dark:hover:bg-yellow-900 active:bg-yellow-600 dark:active:bg-yellow-900", + blue: "text-white bg-blue-500 dark:bg-blue-500 hover:bg-blue-600 dark:hover:bg-blue-700 active:bg-blue-600 dark:active:bg-blue-700", + green: "text-white bg-green-500 dark:bg-green-500 hover:bg-green-600 dark:hover:bg-green-700 active:bg-green-600 dark:active:bg-green-700", + red: "text-white bg-red-500 dark:bg-red-500 hover:bg-red-600 dark:hover:bg-red-700 active:bg-red-600 dark:active:bg-red-700", + neutral: "text-white bg-neutral-700 dark:bg-neutral-700 hover:bg-neutral-600 dark:hover:bg-neutral-700 active:bg-neutral-600 dark:active:bg-neutral-700", + }.freeze + + OUTLINE_BUTTON_COLOR = { + orange: "border-2 border-orange-500 text-orange-500 dark:border-orange-500 dark:text-orange-500 hover:border-orange-600 hover:text-orange-600 active:border-orange-600 active:text-orange-600 dark:hover:border-orange-700 dark:hover:text-orange-700 dark:active:border-orange-700 dark:active:text-orange-700", + orange2: "border-2 border-orange-200 text-orange-200 dark:border-orange-800 dark:text-orange-800 hover:border-orange-300 hover:text-orange-300 active:border-orange-300 active:text-orange-300 dark:hover:border-orange-900 dark:hover:text-orange-900 dark:active:border-orange-900 dark:active:text-orange-900", + yellow: "border-2 border-yellow-500 text-yellow-500 dark:border-yellow-500 dark:text-yellow-500 hover:border-yellow-600 hover:text-yellow-600 active:border-yellow-600 active:text-yellow-600 dark:hover:border-yellow-900 dark:hover:text-yellow-900 dark:active:border-yellow-900 dark:active:text-yellow-900", + blue: "border-2 border-blue-500 text-blue-500 dark:border-blue-500 dark:text-blue-500 hover:border-blue-600 hover:text-blue-600 active:border-blue-600 active:text-blue-600 dark:hover:border-blue-700 dark:hover:text-blue-700 dark:active:border-blue-700 dark:active:text-blue-700", + green: "border-2 border-green-500 text-green-500 dark:border-green-500 dark:text-green-500 hover:border-green-600 hover:text-green-600 active:border-green-600 active:text-green-600 dark:hover:border-green-700 dark:hover:text-green-700 dark:active:border-green-700 dark:active:text-green-700", + red: "border-2 border-red-500 text-red-500 dark:border-red-500 dark:text-red-500 hover:border-red-600 hover:text-red-600 active:border-red-600 active:text-red-600 dark:hover:border-red-700 dark:hover:text-red-700 dark:active:border-red-700 dark:active:text-red-700", + neutral: "border-2 border-neutral-700 text-neutral-700 dark:border-neutral-700 dark:text-neutral-700 hover:border-neutral-600 hover:text-neutral-600 active:border-neutral-600 active:text-neutral-600 dark:hover:border-neutral-700 dark:hover:text-neutral-700 dark:active:border-neutral-700 dark:active:text-neutral-700", + }.freeze +end diff --git a/app/views/components/card_component.rb b/app/views/components/card_component.rb new file mode 100644 index 00000000000..97a5188d2f5 --- /dev/null +++ b/app/views/components/card_component.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +class CardComponent < ApplicationComponent + def view_template(&) + color = "bg-white dark:bg-black border border-neutral-400 dark:border-neutral-800 rounded-md shadow text-neutral-900 dark:text-neutral-100" + box = "w-full px-4 py-6 md:p-10" + article(**classes(color, box), &) + end + + def head(title, icon: nil, url: nil, count: nil) + div(class: "flex justify-between items-center mb-8") do + h3(class: "flex items-center space-x-2 text-lg") do + render_icon(icon) if icon + span(class: "font-semibold") { title } + span(class: "font-light text-neutral-600") { count } if count + end + + a(href: url, class: "text-sm text-orange-500 hover:underline") { t("view_all") } if url + end + end + + def with_list(items, &) + ul(class: "mx-6 my-8") do + items.each do |item| + li(class: "flex justify-between items-center py-3 px-4 rounded-md border border-white dark:border-neutral-850 hover:border-neutral-700") do + yield(item) + end + end + end + end + + def with_content(&) + div(class: "space-y-4", &) + end + + private + + def render_icon(name, width: 20, height: 20) + svg(class: "fill-orange", width:, height:) do + "".html_safe + end + end +end diff --git a/app/views/layouts/_breadcrumbs.html.erb b/app/views/layouts/_breadcrumbs.html.erb new file mode 100644 index 00000000000..151bafbe074 --- /dev/null +++ b/app/views/layouts/_breadcrumbs.html.erb @@ -0,0 +1,25 @@ +
+
+ +
+
diff --git a/app/views/layouts/_search.html.erb b/app/views/layouts/_search.html.erb index c711f56a75f..b5bf61009f5 100644 --- a/app/views/layouts/_search.html.erb +++ b/app/views/layouts/_search.html.erb @@ -1,7 +1,10 @@ <% home = current_page?(root_path) || current_page?(advanced_search_path) %>
" role="search"> <%= form_tag search_path, method: :get, data: { controller: "autocomplete", autocomplete_selected_class: "selected", } do %> - <%= rubygem_search_field(home: home) %> + <%= rubygem_search_field( + class: (home ? "home__search" : "header__search"), + data: (home ? nil : { nav_target: "search" }), + ) %> diff --git a/app/views/layouts/_session.html.erb b/app/views/layouts/_session.html.erb new file mode 100644 index 00000000000..263acf7ed33 --- /dev/null +++ b/app/views/layouts/_session.html.erb @@ -0,0 +1,51 @@ +
+ <% if signed_in? %> + + <% else %> + + + <%= link_to sign_up_path, class: "-mr-1 p-1 md:hidden" do %> + + <% end %> + <% end %> + + +
+ +
+ +
+

+ + RubyGems +

+ + +

+ + + + <%= link_to t('.header.sign_out'), sign_out_path, method: :delete, class: "w-full my-8 px-4 py-2 text-b2 rounded border border-black dark:border-white bg-white dark:bg-black hover:bg-neutral-100 dark:hover:bg-neutral-800 text-black dark:text-white text-center" %> +
+
+
+
diff --git a/app/views/layouts/hammy.html.erb b/app/views/layouts/hammy.html.erb new file mode 100644 index 00000000000..6ee72cb673a --- /dev/null +++ b/app/views/layouts/hammy.html.erb @@ -0,0 +1,244 @@ + + + + <%= page_title %> + + + + + <% ["57x57", "72x72", "76x76", "114x114","120x120", "144x144", "152x152", "180x180"].each do |size| %> + + <% end %> + + + + + + <%= stylesheet_link_tag("hammy") %> + <%= stylesheet_link_tag("tailwind", "data-turbo-track": "reload") %> + + + <%= render "layouts/feeds" %> + <%= csrf_meta_tag %> + <%= yield :head %> + <%= javascript_importmap_tags %> + + +
+ +
+ +
+
+ +
+ + + + + <%= link_to(root_path, title: "RubyGems", class: "flex h-8 items-center text-orange text-b1") do %> + + + <% end %> + + + + + + +
+ +
+ + + + <%= link_to(root_path, title: "RubyGems", class: "flex h-8 items-center text-orange text-b1") do %> + + RubyGems + <% end %> +
+ + + +
+
+
+ +
+ + + + + <%= render "layouts/session" %> +
+ + + +
+
+ + + <%= render "layouts/breadcrumbs" %> +
+ + +
+
+ +

+ + + + + Design Under Construction! + Learn more + +

+ + <%= yield %> +
+
+ + +
+
+ +
+ +
+ + + + <%# + %> +
+
+
+ +
+ +
+ +

+ <%= t("layouts.application.footer.supported_by_html") %> +

+ + +
+ + + + + + + +
+
+
+
+
+ + diff --git a/app/views/pages/about.html.erb b/app/views/pages/about.html.erb index 115142f8cad..7078e3097d1 100644 --- a/app/views/pages/about.html.erb +++ b/app/views/pages/about.html.erb @@ -1,11 +1,11 @@ <% @title = t('.title') %> -
+<%= prose do %>

<%= t '.purpose.header', :site => t('title') %>

-
    -
  1. <%= t '.purpose.better_api' %>
  2. -
  3. <%= t '.purpose.transparent_pages' %>
  4. -
  5. <%= t '.purpose.enable_community' %>
  6. +
      +
    1. <%= t '.purpose.better_api' %>
    2. +
    3. <%= t '.purpose.transparent_pages' %>
    4. +
    5. <%= t '.purpose.enable_community' %>

    <%= t('.founding_html', :founder => link_to('Nick Quaranto', 'https://twitter.com/qrush'), @@ -28,16 +28,9 @@ ) %>

    -
    -

    <%= t('.logo_header') %>

    -

    <%= t('.logo_details') %>

    - +

    <%= t('.logo_header') %>

    +

    <%= t('.logo_details') %>

    +
    + <%= render ButtonComponent.new t('rubygems.aside.links.download'), type: :link, href: "/logos.zip" %>
    -
    +<% end %> diff --git a/app/views/pages/data.html.erb b/app/views/pages/data.html.erb index 87e7d71e94e..951fd6581be 100644 --- a/app/views/pages/data.html.erb +++ b/app/views/pages/data.html.erb @@ -1,12 +1,19 @@ <% @title = t('.title') %> -
    -

    We provide weekly dumps of the RubyGems.org PostgreSQL data. This dump is sanitized, removing all user information.

    -

    The load-pg-dump script is - available as an example of how to to download and load the most recent weekly dump.

    -
      - -
    +
    + <%= render CardComponent.new do |c| %> + <%= c.head("PostgreSQL Data", icon: :history) %> + <%= c.with_content do |user| %> + <%= prose do %> +

    We provide weekly dumps of the RubyGems.org PostgreSQL data. This dump is sanitized, removing all user information.

    +

    The load-pg-dump script is + available as an example of how to to download and load the most recent weekly dump.

    + <% end %> +
      + +
    + <% end %> + <% end %>
    diff --git a/app/views/pages/download.html.erb b/app/views/pages/download.html.erb index 0cecaa6c9db..23184c1ecd5 100644 --- a/app/views/pages/download.html.erb +++ b/app/views/pages/download.html.erb @@ -1,30 +1,32 @@ <% @title = t('.title') %> <% @subtitle = subtitle %> -
    +<%= prose do %> +

    <%= @title %>

    - RubyGems is a package management framework for Ruby. Download the latest version here: -

    -
    - <%= link_to "tgz", "https://rubygems.org/rubygems/rubygems-#{version_number}.tgz", class: "download__format" %> - <%= link_to "zip", "https://rubygems.org/rubygems/rubygems-#{version_number}.zip", class: "download__format" %> - <%= link_to "gem", "https://rubygems.org/gems/rubygems-update-#{version_number}.gem", class: "download__format" %> - <%= link_to "git", "https://github.com/rubygems/rubygems", class: "download__format" %> -
    -

    - Or, to upgrade to the latest RubyGems: + RubyGems is a package management framework for Ruby. +
    + Upgrade to the latest RubyGems at the command line:

    $ gem update --system

    - You might be running into some bug that prevents you from upgrading rubygems the standard way. In that case, you can try upgrading manually: + If you run into problems that prevent you from upgrading rubygems the standard way, you can try upgrading manually:

      -
    1. <%=link_to "Download from above", "#formats" %>
    2. -
    3. Unpack into a directory and cd there
    4. -
    5. Install with: ruby setup.rb
    6. +
    7. Download the latest version
    8. +
    9. Unpack and cd into the unpacked directory
    10. +
    11. Install with: +
      ruby setup.rb
      +
    12. +
    13. + For more details and other options, run: ruby setup.rb --help +
    -

    - For more details and other options, see: -

    -
    ruby setup.rb --help
    -
    +

    Download the latest version

    +
    + <%= render ButtonComponent.new "tgz", type: :link, href: "https://rubygems.org/rubygems/rubygems-#{version_number}.tgz" %> + <%= render ButtonComponent.new "zip", type: :link, href: "https://rubygems.org/rubygems/rubygems-#{version_number}.zip" %> + <%= render ButtonComponent.new "gem", type: :link, href: "https://rubygems.org/gems/rubygems-update-#{version_number}.gem" %> + <%= render ButtonComponent.new "git", type: :link, href: "https://github.com/rubygems/rubygems" %> +
    +<% end %> diff --git a/app/views/pages/faq.html.erb b/app/views/pages/faq.html.erb deleted file mode 100644 index ab8e903c4df..00000000000 --- a/app/views/pages/faq.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -<% @title = t('.title') %> - -
    -

    - <%= link_to "This page has been moved onto #{t(:title)}’s new support site.", "https://help.rubygems.org/kb/gemcutter/faq" %> -

    -
    diff --git a/app/views/pages/migrate.html.erb b/app/views/pages/migrate.html.erb deleted file mode 100644 index aac2e406081..00000000000 --- a/app/views/pages/migrate.html.erb +++ /dev/null @@ -1,8 +0,0 @@ -<% @title = t('.title') %> - -
    -

    - gem migrate has been deprecated, all of the RubyForge accounts and ownerships have been transferred over to Gemcutter. -

    -

    If you’re having problems with your gems and pushing, <%= mail_to "support@rubygems.org", "please open a support request" %>.

    -
    diff --git a/app/views/pages/security.html.erb b/app/views/pages/security.html.erb index e7731de0096..2955948a383 100644 --- a/app/views/pages/security.html.erb +++ b/app/views/pages/security.html.erb @@ -1,6 +1,6 @@ <% @title = t('.title') %> -
    +<%= prose do %>

    Found a security issue with RubyGems or RubyGems.org? Please follow these steps to report it. @@ -131,4 +131,4 @@ security@rubygems.org or open an issue on GitHub. Thanks!

    -
    +<% end %> diff --git a/app/views/pages/sponsors.html.erb b/app/views/pages/sponsors.html.erb index 7d93b9c5096..05b78bf813e 100644 --- a/app/views/pages/sponsors.html.erb +++ b/app/views/pages/sponsors.html.erb @@ -1,6 +1,6 @@ <% @title = t('.title') %> -
    +<%= prose do %>

    RubyGems.org is made possible by support from the Ruby community. These companies provide the servers and developers that create the public infrastructure of the Ruby programming language.

    @@ -8,10 +8,11 @@

    Ruby Central

    Ruby Central, Inc. is a nonprofit 501(c)3 organization dedicated to the support and advocacy of the worldwide Ruby community. They organize the annual RubyConf and RailsConf as opportunities for Rubyists to collaborate and network. As part of those conferences, Ruby Central also operates the Opportunity Scholarship program to consistently bring new people into the tech community and to provide them with a comfortable, welcoming environment to explore our community and its events. -

    +

    +

    They also fund and operate the Ruby Central Community Grant, underwriting events or open source projects that benefit the Ruby community, and they fund the ongoing server costs associated with running RubyGems.org. - You can support Ruby Central by attending or [sponsoring](sponsors@rubycentral.org) a conference, or by [joining as a supporting member](https://rubycentral.org/#/portal/signup). + You can support Ruby Central by attending or contacting Ruby Central about sponsoring a conference, or by joining as a supporting member.

    Fastly

    @@ -21,16 +22,12 @@ Fastly provides the RubyGems.org content delivery network, allowing Ruby developers all over the world to download gems from nearby servers around the world.

    -
    -

    1Password

    A password manager, digital vault, form filler and secure digital wallet. 1Password remembers all your passwords for you to help keep account information safe.

    -
    -

    Avo

    Avo is a custom Content Management System for Ruby on Rails that saves developers and teams months of development time. It's built on modern technologies and provides all the necessary hooks to ensure developers ship the best experiences to their customers.

    Avo enables the RubyGems.org team to quickly build internal tools with limited resources.

    -
    +<% end %> diff --git a/config/application.rb b/config/application.rb index 340006377d5..bdc1e68bf04 100644 --- a/config/application.rb +++ b/config/application.rb @@ -108,6 +108,6 @@ def self.config ENABLE_DEVELOPMENT_ADMIN_LOG_IN = Rails.env.local? MAIL_SENDER = "RubyGems.org ".freeze PAGES = %w[ - about data download faq migrate security sponsors + about data download security sponsors ].freeze end diff --git a/config/importmap.rb b/config/importmap.rb index 4897472eefb..681e27fe7b1 100644 --- a/config/importmap.rb +++ b/config/importmap.rb @@ -11,6 +11,8 @@ pin "@hotwired/stimulus-loading", to: "stimulus-loading.js" pin_all_from "app/javascript/controllers", under: "controllers" pin "@stimulus-components/clipboard", to: "@stimulus-components--clipboard.js" # @5.0.0 +pin "@stimulus-components/dialog", to: "@stimulus-components--dialog.js" # @1.0.1 +pin "@stimulus-components/reveal", to: "@stimulus-components--reveal.js" # @5.0.0 # vendored and adapted from https://github.com/mdo/github-buttons/blob/master/src/js.js pin "github-buttons" diff --git a/config/locales/de.yml b/config/locales/de.yml index 975b1593aa1..b6320cd83f7 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -243,6 +243,7 @@ de: blog: Blog contribute: Beitragen data: Daten + docs: Dokumentation designed_by: Design von discussion_forum: Diskussion gems_served_by: Gems angeboten von @@ -257,6 +258,9 @@ de: statistics: Statistiken status: Status supported_by: Unterstützt von + supported_by_html: | + RubyGems.org + wird unterstützt von tested_by: tracking_by: Getrackt von uptime: Betriebszeit @@ -272,6 +276,11 @@ de: sign_out: Abmelden sign_up: Registrieren mfa_banner_html: + breadcrumbs: + home: + dashboard: Dashboard + settings: + org_name: 'Organisation: %{name}' mailer: confirm_your_email: Bitte bestätigen Sie Ihre E-Mail-Adresse mit dem Link, der an Ihre E-Mail gesendet wurde. @@ -475,10 +484,6 @@ de: title: RubyGems.org Data Dumps download: title: Download RubyGems - faq: - title: FAQ - migrate: - title: Migrate gems security: title: Security sponsors: diff --git a/config/locales/en.yml b/config/locales/en.yml index 3a05781c196..9f10e4a055a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -229,6 +229,7 @@ en: blog: Blog contribute: Contribute data: Data + docs: Docs designed_by: Designed by discussion_forum: Discuss gems_served_by: Gems served by @@ -243,6 +244,9 @@ en: statistics: Stats status: Status supported_by: Supported by + supported_by_html: | + RubyGems.org + is supported by tested_by: Tested by tracking_by: Tracking by uptime: Uptime @@ -258,6 +262,11 @@ en: sign_out: Sign out sign_up: Sign up mfa_banner_html: 🎉 We now support security devices! Improve your account security by setting up a new device. [Learn more](link to blog post)! + breadcrumbs: + home: Home + dashboard: Dashboard + settings: Settings + org_name: "Org: %{name}" mailer: confirm_your_email: Please confirm your email address with the link sent to your email. confirmation_subject: Please confirm your email address with %{host} @@ -407,10 +416,6 @@ en: title: RubyGems.org Data Dumps download: title: Download RubyGems - faq: - title: FAQ - migrate: - title: Migrate gems security: title: Security sponsors: diff --git a/config/locales/es.yml b/config/locales/es.yml index 4efa807b479..3cb319bcb69 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -242,6 +242,7 @@ es: blog: Blog contribute: Contribuye data: Datos + docs: Documentación designed_by: Diseñado por discussion_forum: Foro de Discusión gems_served_by: Distribuida por @@ -256,6 +257,9 @@ es: statistics: Estadísticas status: Estado supported_by: Con el apoyo de + supported_by_html: | + RubyGems.org + es respaldado por tested_by: Probado por tracking_by: Seguimiento con uptime: Uptime @@ -271,6 +275,11 @@ es: sign_out: Salir sign_up: Registro mfa_banner_html: + breadcrumbs: + home: + dashboard: Dashboard + settings: Configuración + org_name: 'Org: %{name}' mailer: confirm_your_email: Por favor confirma tu dirección de correo con el enlace enviado. confirmation_subject: Por favor confirma tu dirección de correo con %{host} @@ -463,10 +472,6 @@ es: title: Volcado de datos de RubyGems.org download: title: Descargar RubyGems - faq: - title: Preguntas Frecuentes - migrate: - title: Migrar Gemas security: title: Seguridad sponsors: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index fcd1c729046..56ce112f954 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -234,6 +234,7 @@ fr: blog: Blog contribute: Contribuer data: Données + docs: Documentation designed_by: Design par discussion_forum: Discussions gems_served_by: Gems mis à disposition par @@ -248,6 +249,9 @@ fr: statistics: Stats status: Statut supported_by: Soutenu par + supported_by_html: | + RubyGems.org + est soutenu par tested_by: Testé par tracking_by: Tracking par uptime: Uptime @@ -263,6 +267,11 @@ fr: sign_out: Déconnexion sign_up: Inscription mfa_banner_html: + breadcrumbs: + home: + dashboard: Dashboard + settings: Paramètres + org_name: 'Org: %{name}' mailer: confirm_your_email: Veuillez confirmer votre adresse email avec le lien qui vous a été envoyé par email. @@ -428,10 +437,6 @@ fr: title: download: title: - faq: - title: - migrate: - title: security: title: sponsors: diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 1ea681dfbf4..4e722acdb0e 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -223,6 +223,7 @@ ja: blog: ブログ contribute: 貢献 data: データ + docs: ドキュメント designed_by: 設計 discussion_forum: 議論 gems_served_by: gemの提供 @@ -237,6 +238,9 @@ ja: statistics: 統計 status: 状態 supported_by: 協賛 + supported_by_html: | + RubyGems.org + は以下から支援を受けています tested_by: テスト tracking_by: 追跡 uptime: 稼働時間 @@ -253,6 +257,11 @@ ja: sign_up: 新規登録 mfa_banner_html: "\U0001F389 セキュリティ機器に対応しました!新しい機器を設定してアカウントのセキュリティを向上しましょう。[詳細はこちら](link to blog post)!" + breadcrumbs: + home: + dashboard: ダッシュボード + settings: 設定 + org_name: 組織:%{name} mailer: confirm_your_email: Eメールに送信されたリンクからEメールアドレスを確認してください。 confirmation_subject: "%{host}に登録されたメールアドレスを確認してください" @@ -408,10 +417,6 @@ ja: title: RubyGems.orgのデータのダンプ download: title: RubyGemsをダウンロード - faq: - title: FAQ - migrate: - title: gemを移行する security: title: セキュリティ sponsors: diff --git a/config/locales/nl.yml b/config/locales/nl.yml index cf043b2b4a4..140f732287f 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -226,6 +226,7 @@ nl: blog: Blog contribute: Bijdragen data: Data + docs: Documentatie designed_by: Ontwerp discussion_forum: Forum gems_served_by: @@ -240,6 +241,9 @@ nl: statistics: Statistieken status: Status supported_by: Ondersteuning + supported_by_html: | + RubyGems.org + wordt ondersteund door tested_by: Getest door tracking_by: Tracking uptime: Uptime @@ -255,6 +259,11 @@ nl: sign_out: Uitloggen sign_up: Registreren mfa_banner_html: + breadcrumbs: + home: + dashboard: Dashboard + settings: + org_name: 'Organisatie: %{name}' mailer: confirm_your_email: confirmation_subject: @@ -414,10 +423,6 @@ nl: title: download: title: - faq: - title: - migrate: - title: security: title: sponsors: diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 0918fae12c5..95efe9ebcb7 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -231,6 +231,7 @@ pt-BR: blog: Blog contribute: Como Contribuir data: Dump de Dados + docs: Documentação designed_by: Design discussion_forum: Fóruns gems_served_by: Provisionamento @@ -245,6 +246,9 @@ pt-BR: statistics: Estatísticas status: Status supported_by: Patrocínio + supported_by_html: | + RubyGems.org + é apoiado por tested_by: Testado por tracking_by: Coleta de Dados uptime: Uptime @@ -260,6 +264,11 @@ pt-BR: sign_out: Sair sign_up: Cadastrar mfa_banner_html: + breadcrumbs: + home: + dashboard: Painel de Controle + settings: Configurações da Conta + org_name: 'Org: %{name}' mailer: confirm_your_email: Por favor, confirme seu endereço de email através do link que enviamos para o seu endereço de email. @@ -425,10 +434,6 @@ pt-BR: title: download: title: - faq: - title: - migrate: - title: security: title: sponsors: diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 6421206df98..2b24b842791 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -225,6 +225,7 @@ zh-CN: blog: 博客 contribute: 贡献 data: 数据 + docs: 文档 designed_by: 设计 discussion_forum: 讨论 gems_served_by: 服务 @@ -239,6 +240,9 @@ zh-CN: statistics: 统计 status: 状态 supported_by: 支持 + supported_by_html: | + RubyGems.org + 由以下支持 tested_by: 测试 tracking_by: 追踪 uptime: 服务运行时间 @@ -254,6 +258,11 @@ zh-CN: sign_out: 退出 sign_up: 注册 mfa_banner_html: + breadcrumbs: + home: + dashboard: 仪表盘 + settings: 设置 + org_name: 组织:%{name} mailer: confirm_your_email: 请在发送到您的邮件中点击链接,确认您的邮箱地址。 confirmation_subject: 请确认您的邮箱地址 @@ -416,10 +425,6 @@ zh-CN: title: RubyGems.org 数据转储 download: title: 下载 RubyGems - faq: - title: 常问问题 - migrate: - title: 迁移 Gem security: title: 安全 sponsors: diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index a2f84c0ded2..52da59cf777 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -224,6 +224,7 @@ zh-TW: blog: 部落格 contribute: 貢獻 data: 資料 + docs: 文件 designed_by: 設計 discussion_forum: 討論群組 gems_served_by: 服務 @@ -238,6 +239,9 @@ zh-TW: statistics: 統計 status: 狀態 supported_by: 支持 + supported_by_html: | + RubyGems.org + 由以下支持 tested_by: 測試 tracking_by: 追蹤 uptime: 上線時間 @@ -253,6 +257,11 @@ zh-TW: sign_out: 登出 sign_up: 註冊 mfa_banner_html: "\U0001F389 我們現在支援安全裝置了!設定新的裝置來提升您的帳號安全。[了解詳情](部落格文章連結)!" + breadcrumbs: + home: + dashboard: + settings: + org_name: 組織:%{name} mailer: confirm_your_email: 已寄送連結,請點擊連結來確認您的電子郵件地址。 confirmation_subject: "%{host} 電子郵件地址確認" @@ -410,10 +419,6 @@ zh-TW: title: download: title: 下載 RubyGems - faq: - title: 常見問題 - migrate: - title: 轉移 Gems security: title: 安全性 sponsors: diff --git a/config/tailwind.config.js b/config/tailwind.config.js index 664dbdb8c31..b0ee5019caf 100644 --- a/config/tailwind.config.js +++ b/config/tailwind.config.js @@ -13,37 +13,41 @@ module.exports = { ], theme: { extend: { + screens: { + 'sm': '480px' // Below this is a phone in portrait mode + }, fontFamily: { sans: ['"Titillium Web"', ...defaultTheme.fontFamily.sans], mono: ['"Fira Code"', ...defaultTheme.fontFamily.mono], }, fontSize: { - lg: ['1.4375rem', '2.156rem'], /* Base/01 23px, 34.5px */ - base: ['1.1875rem', '1.781rem'], /* Base/02 19px, 28.5px */ - sm: ['1.0000rem', '1.500rem'], /* Base/03 16px, 24px */ - xs: ['0.8750rem', '1.313rem'], /* Base/04 14px, 21px */ + lg: ['1.4375rem', '2.156rem'], // Base/01 23px, 34.5px + base: ['1.1875rem', '1.781rem'], // Base/02 19px, 28.5px + sm: ['1.0000rem', '1.500rem'], // Base/03 16px, 24px + xs: ['0.8750rem', '1.313rem'], // Base/04 14px, 21px - d1: ['3.1875rem', '3.825rem'], /* Display/01 51px, 61.2px */ - d2: ['2.9375rem', '3.525rem'], /* Display/02 47px, 56.4px */ - d3: ['2.6875rem', '3.225rem'], /* Display/03 43px, 51.6px */ - h1: ['2.4375rem', '2.925rem'], /* Header/01 39px, 46.8px */ - h2: ['2.1875rem', '2.625rem'], /* Header/02 35px, 42px */ - h3: ['1.9375rem', '2.325rem'], /* Header/03 31px, 37.2px */ - h4: ['1.6875rem', '2.025rem'], /* Header/04 27px, 32.4px */ - b1: ['1.4375rem', '2.156rem'], /* Base/01 23px, 34.5px */ - b2: ['1.1875rem', '1.781rem'], /* Base/02 19px, 28.5px */ - b3: ['1.0000rem', '1.500rem'], /* Base/03 16px, 24px */ - b4: ['0.8750rem', '1.313rem'], /* Base/04 14px, 21px */ - c1: ['1.6875rem', '2.025rem'], /* Code/01 27px, 32.4px */ - c2: ['1.4375rem', '1.725rem'], /* Code/02 23px, 27.6px */ - c3: ['1.1250rem', '1.350rem'], /* Code/03 18px, 21.6px */ - c4: ['1.0000rem', '1.200rem'], /* Code/04 16px, 19.2px */ + d1: ['3.1875rem', '3.825rem'], // Display/01 51px, 61.2px + d2: ['2.9375rem', '3.525rem'], // Display/02 47px, 56.4px + d3: ['2.6875rem', '3.225rem'], // Display/03 43px, 51.6px + h1: ['2.4375rem', '2.925rem'], // Header/01 39px, 46.8px + h2: ['2.1875rem', '2.625rem'], // Header/02 35px, 42px + h3: ['1.8750rem', '2.325rem'], // Header/03 31px, 37.2px + h4: ['1.6875rem', '2.025rem'], // Header/04 27px, 32.4px + b1: ['1.4375rem', '2.156rem'], // Base/01 23px, 34.5px + b2: ['1.1875rem', '1.781rem'], // Base/02 19px, 28.5px + b3: ['1.0000rem', '1.500rem'], // Base/03 16px, 24px + b4: ['0.8750rem', '1.313rem'], // Base/04 14px, 21px + c1: ['1.6875rem', '2.025rem'], // Code/01 27px, 32.4px + c2: ['1.4375rem', '1.725rem'], // Code/02 23px, 27.6px + c3: ['1.1250rem', '1.350rem'], // Code/03 18px, 21.6px + c4: ['1.0000rem', '1.200rem'], // Code/04 16px, 19.2px }, colors: { transparent: 'transparent', current: 'currentColor', - 'white': '#ffffff', - 'red': { + 'white': '#FFFFFF', + 'black': '#000000', + 'red': { // Warn / Failure 100: '#FFEEF1', 200: '#FFC4CD', 300: '#FF9CB0', @@ -54,18 +58,20 @@ module.exports = { 800: '#730012', 900: '#58000A', }, - 'orange': { + 'orange': { // Primary 100: '#FFF0EC', - 200: '#FFD0C5', + 200: '#FFC6AD', 300: '#FFA983', 400: '#FF7539', 500: '#F74C27', - 600: '#E54523', + DEFAULT: '#F74C27', // 500 brand primary + 600: '#E04300', 700: '#AD2F14', 800: '#761A05', - 900: '#631200', + 900: '#581A0C', + 950: '#3A1007', }, - 'yellow': { + 'yellow': { // Alert 100: '#FFFBF7', 200: '#FFF4EA', 300: '#FFE4BB', @@ -76,7 +82,7 @@ module.exports = { 800: '#7A4E0C', 900: '#4D2E00', }, - 'green': { + 'green': { // Success 100: '#F1FFFE', 200: '#E1FFFC', 300: '#C9FFF9', @@ -87,7 +93,7 @@ module.exports = { 800: '#004F56', 900: '#00373B', }, - 'blue': { + 'blue': { // Info 100: '#F3F9FF', 200: '#E1F1FF', 300: '#92C0F4', @@ -97,21 +103,149 @@ module.exports = { 700: '#3F699A', 800: '#234C7D', 900: '#113765', + 950: '#06264C', }, 'neutral': { + // WHITE + // Light + // background (general) + // secondary search bar background + // Dark + // primary text + // primary icons '000': '#FFFFFF', + + // neutral-050 + // Light + // work canvas + // form input + // Dark (not used) '050': '#FBFBFB', - '100': '#F6F6F6', - '200': '#EEEEEE', - '300': '#E2E2E2', - '400': '#D5D5D5', - '500': '#C3C5C7', - '600': '#969CA7', - '700': '#636B79', - '800': '#454C59', - '850': '#2F3643', - '900': '#13181F', - '950': '#191E26', + + // neutral-100 + // Light + // primary search bar bg + // Dark (not used) + '100': '#EEF1F3', + + // neutral-200 + // Light + // tab hover + // pagination hover + // neutral toasts + // neutral badges + // neutral labels (dropdown) + // low performance indicators + // Dark + // primary text hover + '200': '#E3E7EA', + + // neutral-300 + // Light + // disabled buttons + // disabled form input + // list dividing line + // tab dividing line + // outside line default + // search bar + // dropdown + // chips + // Dark (not used) + '300': '#D7DEE3', + + // neutral-400 + // Light (not used) + // Dark + // secondary text + // disabled button text + // inactive search bar + // nav breadcrumbs + // secondary icons + '400': '#C6CED5', + + // neutral-500 + // Light + // outside stroke + // general containers + // neutral toasts + // outside stroke active states + // search bar + // drop downs + // chips + // Dark (not used) + '500': '#AEB8C1', + + // neutral-600 + // Light + // secondary text + // disabled button text + // inactive search bar + // nav breadcrumbs + // search result gem description captions + // text counters [ Gems 4 ] + // sort by - not active + // secondary icons + // Dark + // secondary text + // search result gem description captions + // text counters [ Gems 4 ] + // sort by - not active + // + '600': '#6C7583', + + // neutral-700 + // Light (not used) + // Dark + // disabled buttons + // disabled form input + // list dividing line + // tab dividing line + // outside line default + // search bar + // dropdown + // chips + // outside stroke + // general containers + // neutral toasts + // outside stroke active states + // search bar + // drop downs + // chips + '700': '#434B59', + + // neutral-800 + // Light + // primary text + // primary icons + // Dark + // tab hover + // pagination hover + // neutral toasts + // neutral badges + // neutral labels (dropdown) + // low performance indicators + '800': '#333A45', + + // neutral-900 + // Light (not used) + // Dark + // primary search bar background + '900': '#222831', + + // neutral-950 + // Light (not used) + // Dark + // work canvas + // form input + '950': '#16191E', + + // BLACK + // Light + // primary text hover + // Dark + // background (general) + // secondary search bar background + '1000': '#000000', }, }, }, diff --git a/public/images/icons.svg b/public/images/icons.svg new file mode 100644 index 00000000000..321ab50e6af --- /dev/null +++ b/public/images/icons.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/policies/rubygem_policy_test.rb b/test/policies/rubygem_policy_test.rb index c5cefe7a214..ca753f869ad 100644 --- a/test/policies/rubygem_policy_test.rb +++ b/test/policies/rubygem_policy_test.rb @@ -55,10 +55,12 @@ def policy!(user) refute_authorized @user, :request_ownership? end - should "be false if the gem has a version newer than 1 year" do - create(:version, rubygem: @rubygem, created_at: 11.months.ago) + context "when the gem has a version newer than 1 year" do + should "be false" do + create(:version, rubygem: @rubygem, created_at: 11.months.ago) - refute_authorized @user, :request_ownership? + refute_authorized @user, :request_ownership? + end end should "be true if the gem's latest version is older than 1 year and less than 10,000 downloads" do diff --git a/vendor/javascript/@stimulus-components--dialog.js b/vendor/javascript/@stimulus-components--dialog.js new file mode 100644 index 00000000000..6c877875fa9 --- /dev/null +++ b/vendor/javascript/@stimulus-components--dialog.js @@ -0,0 +1,2 @@ +import{Controller as e}from"@hotwired/stimulus";const t=class _Dialog extends e{initialize(){this.forceClose=this.forceClose.bind(this)}connect(){this.openValue&&this.open(),document.addEventListener("turbo:before-render",this.forceClose)}disconnect(){document.removeEventListener("turbo:before-render",this.forceClose)}open(){this.dialogTarget.showModal()}close(){this.dialogTarget.setAttribute("closing",""),Promise.all(this.dialogTarget.getAnimations().map((e=>e.finished))).then((()=>{this.dialogTarget.removeAttribute("closing"),this.dialogTarget.close()}))}backdropClose(e){e.target===this.dialogTarget&&this.close()}forceClose(){this.dialogTarget.close()}};t.targets=["dialog"],t.values={open:{type:Boolean,default:!1}};let o=t;export{o as default}; + diff --git a/vendor/javascript/@stimulus-components--reveal.js b/vendor/javascript/@stimulus-components--reveal.js new file mode 100644 index 00000000000..91615312192 --- /dev/null +++ b/vendor/javascript/@stimulus-components--reveal.js @@ -0,0 +1,2 @@ +import{Controller as s}from"@hotwired/stimulus";const t=class _Reveal extends s{connect(){this.class=this.hasHiddenClass?this.hiddenClass:"hidden"}toggle(){this.itemTargets.forEach((s=>{s.classList.toggle(this.class)}))}show(){this.itemTargets.forEach((s=>{s.classList.remove(this.class)}))}hide(){this.itemTargets.forEach((s=>{s.classList.add(this.class)}))}};t.targets=["item"],t.classes=["hidden"];let e=t;export{e as default}; +