decidim-core 0.29.0.rc3 → 0.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/address/online.erb +2 -2
  3. data/app/cells/decidim/address_cell.rb +4 -0
  4. data/app/cells/decidim/card_g/show.erb +1 -1
  5. data/app/cells/decidim/card_g_cell.rb +5 -2
  6. data/app/cells/decidim/card_l/image.erb +2 -2
  7. data/app/cells/decidim/card_l_cell.rb +5 -2
  8. data/app/cells/decidim/content_blocks/hero_cell.rb +1 -1
  9. data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +1 -1
  10. data/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb +2 -2
  11. data/app/cells/decidim/nav_links/show.erb +3 -3
  12. data/app/cells/decidim/resource_types_filter/show.erb +11 -12
  13. data/app/commands/decidim/create_omniauth_registration.rb +10 -4
  14. data/app/controllers/concerns/decidim/devise_controllers.rb +1 -0
  15. data/app/controllers/concerns/decidim/paginable.rb +1 -1
  16. data/app/controllers/decidim/application_controller.rb +1 -0
  17. data/app/helpers/decidim/menu_helper.rb +1 -1
  18. data/app/helpers/decidim/paginate_helper.rb +3 -5
  19. data/app/models/decidim/attachment.rb +8 -7
  20. data/app/models/decidim/component.rb +4 -1
  21. data/app/models/decidim/content_block.rb +2 -2
  22. data/app/models/decidim/user.rb +12 -12
  23. data/app/packs/src/decidim/a11y.js +11 -15
  24. data/app/packs/src/decidim/attachments/file_or_link_tabs.js +7 -3
  25. data/app/packs/src/decidim/input_character_counter.js +1 -1
  26. data/app/packs/stylesheets/decidim/_dropdown.scss +9 -9
  27. data/app/packs/stylesheets/decidim/_filters.scss +3 -1
  28. data/app/packs/stylesheets/decidim/_footer.scss +1 -1
  29. data/app/packs/stylesheets/decidim/_forms.scss +4 -4
  30. data/app/packs/stylesheets/decidim/_tooltip.scss +10 -10
  31. data/app/packs/stylesheets/decidim/editor.scss +1 -1
  32. data/app/presenters/decidim/menu_item_presenter.rb +1 -1
  33. data/app/services/decidim/open_data_exporter.rb +8 -7
  34. data/app/views/decidim/manifests/show.json.erb +4 -4
  35. data/app/views/decidim/pages/_tabbed.html.erb +3 -3
  36. data/app/views/decidim/shared/_filters.html.erb +5 -5
  37. data/app/views/decidim/shared/_orders.html.erb +3 -2
  38. data/app/views/decidim/shared/filters/_check_boxes_tree.html.erb +1 -1
  39. data/app/views/decidim/shared/filters/_collection.html.erb +1 -1
  40. data/app/views/layouts/decidim/_logo.html.erb +1 -1
  41. data/app/views/layouts/decidim/footer/_main.html.erb +1 -1
  42. data/app/views/layouts/decidim/footer/_main_intro.html.erb +1 -1
  43. data/app/views/layouts/decidim/header/_main_links_desktop.html.erb +1 -1
  44. data/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb +1 -1
  45. data/app/views/layouts/decidim/header/_main_links_mobile_item_account.html.erb +1 -1
  46. data/app/views/layouts/decidim/shared/_layout_user_profile.html.erb +2 -2
  47. data/config/locales/ca.yml +3 -3
  48. data/config/locales/cs.yml +14 -0
  49. data/config/locales/fi-plain.yml +3 -3
  50. data/config/locales/fi.yml +28 -28
  51. data/config/locales/sv.yml +72 -64
  52. data/db/migrate/20181025082245_add_timestamps_to_components.rb +5 -1
  53. data/lib/decidim/asset_router/storage.rb +216 -13
  54. data/lib/decidim/core/test/shared_examples/attachable_interface_examples.rb +1 -1
  55. data/lib/decidim/core/test/shared_examples/follows_examples.rb +8 -3
  56. data/lib/decidim/core/test/shared_examples/paginated_resource_examples.rb +5 -5
  57. data/lib/decidim/core/version.rb +1 -1
  58. data/lib/tasks/upgrade/decidim_fix_categorization.rake +100 -0
  59. metadata +8 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d58ac45e047a62b04a7625b6da1c4ee92c2a62d9bf4e1969cdfb324257e5ef9
4
- data.tar.gz: 94a06bf8519d6234945a39dc86cc9794149fa3dc09c89273dcd475a64a3ad78b
3
+ metadata.gz: 37f39b870aa9a840fbf4c415858b3210d520511f8efb0327bb90e8aa0126f243
4
+ data.tar.gz: 16fa93602fc35d288ddeef831f50f3e3878714ea4fae6547064c9be0a148fad0
5
5
  SHA512:
6
- metadata.gz: 6e90186e86e894822888b13cbaabe6c8c2a752d73a477cb13b39be5fd785d9b92082e5e403de91790f43c19a78f83bb85253e4fa0475f086f64e90258b2593b3
7
- data.tar.gz: f297c4b6a5fad64c57984fc063778cddda2404f3861e75b8a16c4fff83986caedc44354bba11a58551c5815dae0c9785b5f8d159a9a7e0930d2f080341b69579
6
+ metadata.gz: 0ae69c163d580612c4a8f4f4cf8d9c460aebc24270a67f4a245d25f4fceb2988075664aab8f97977ae19b75d90c42e1cdb03ad2591bd546c5acf9f8562d5852f
7
+ data.tar.gz: 23132fff12f59d0bb72b073e6729ccb5f439f5c59493d8a3f8f7026dbb45cf20e56f1cac34b07bc8a2d10e757b4cd6efe60bc93180f22d2a4764db597913a1b6
@@ -5,8 +5,8 @@
5
5
  <div class="address">
6
6
  <div class="address__location"><%= t(model.type_of_meeting, scope: "decidim.meetings.meetings.filters.type_values") %></div>
7
7
  <% if display_online_meeting_url? %>
8
- <a href="<%= model.online_meeting_url %>" target="_blank" rel="noopener noreferrer" class="address__hints underline break-all">
9
- <%= model.online_meeting_url %>
8
+ <a href="<%= online_meeting_url %>" target="_blank" rel="noopener noreferrer" class="address__hints underline break-all">
9
+ <%= online_meeting_url %>
10
10
  <% end %>
11
11
  </a>
12
12
  </div>
@@ -43,6 +43,10 @@ module Decidim
43
43
  HTML
44
44
  end
45
45
 
46
+ def online_meeting_url
47
+ URI::Parser.new.escape(model.online_meeting_url)
48
+ end
49
+
46
50
  def display_online_meeting_url?
47
51
  return true unless model.respond_to?(:online?)
48
52
  return true unless model.respond_to?(:iframe_access_level_allowed_for_user?)
@@ -1,7 +1,7 @@
1
1
  <%= link_to resource_path, class: classes[:default], id: resource_id do %>
2
2
  <div class="<%= classes[:img] %>">
3
3
  <% if has_image? %>
4
- <%= image_tag resource_image_path, alt: alt_title %>
4
+ <%= image_tag resource_image_url, alt: alt_title %>
5
5
  <% else %>
6
6
  <%= external_icon "media/images/placeholder-card-g.svg", class: "card__placeholder-g" %>
7
7
  <% end %>
@@ -52,12 +52,15 @@ module Decidim
52
52
  @id_base_name ||= resource.class.name.gsub(/\ADecidim::/, "").underscore.split("/").join("__")
53
53
  end
54
54
 
55
- def resource_image_path
55
+ def resource_image_url
56
+ # Backwards compatibility.
57
+ return resource_image_path if respond_to?(:resource_image_path)
58
+
56
59
  nil
57
60
  end
58
61
 
59
62
  def has_image?
60
- resource_image_path.present?
63
+ resource_image_url.present?
61
64
  end
62
65
 
63
66
  def show_description?
@@ -1,6 +1,6 @@
1
1
  <div class="card__list-image">
2
- <% if resource_image_path.present? %>
3
- <%= image_tag resource_image_path, class: "w-full h-full object-cover" %>
2
+ <% if has_image? %>
3
+ <%= image_tag resource_image_url, class: "w-full h-full object-cover" %>
4
4
  <% else %>
5
5
  <div class="w-full h-full relative">
6
6
  <div class="w-full h-full bg-primary opacity-10 absolute top-0 left-0 z-10">
@@ -66,12 +66,15 @@ module Decidim
66
66
  "#{class_base_name}__#{class_name}"
67
67
  end
68
68
 
69
- def resource_image_path
69
+ def resource_image_url
70
+ # Backwards compatibility.
71
+ return resource_image_path if respond_to?(:resource_image_path)
72
+
70
73
  nil
71
74
  end
72
75
 
73
76
  def has_image?
74
- resource_image_path.present?
77
+ resource_image_url.present?
75
78
  end
76
79
 
77
80
  def has_link_to_resource?
@@ -15,7 +15,7 @@ module Decidim
15
15
  end
16
16
 
17
17
  def background_image
18
- model.images_container.attached_uploader(:background_image).path(variant: :big)
18
+ model.images_container.attached_uploader(:background_image).variant_url(:big)
19
19
  end
20
20
 
21
21
  private
@@ -1,4 +1,4 @@
1
- <section id="highlighted_content_banner" class="home__section-image" style="--hero-image:url('<%= current_organization.attached_uploader(:highlighted_content_banner_image).path %>');">
1
+ <section id="highlighted_content_banner" class="home__section-image" style="--hero-image:url('<%= current_organization.attached_uploader(:highlighted_content_banner_image).url %>');">
2
2
  <div class="home__section-content-banner home__section">
3
3
  <div>
4
4
  <h2 class="home__section-content-banner__title">
@@ -32,9 +32,9 @@ module Decidim
32
32
  # If it is called from the landing page content block, use the background image defined there
33
33
  # Else, use the banner image defined in the space (for assemblies)
34
34
  def image_path
35
- return model.images_container.attached_uploader(:background_image).path if model.respond_to?(:images_container)
35
+ return model.images_container.attached_uploader(:background_image).url if model.respond_to?(:images_container)
36
36
 
37
- attached_uploader(:banner_image).path
37
+ attached_uploader(:banner_image).url
38
38
  end
39
39
 
40
40
  def has_hashtag?
@@ -1,12 +1,12 @@
1
1
  <div class="participatory-space__nav-container">
2
- <button id="dropdown-trigger-participatory-space" data-component="dropdown" data-target="dropdown-menu-participatory-space" data-auto-close="true" data-scroll-to-menu="true">
2
+ <button id="dropdown-trigger-participatory-space" data-component="dropdown" data-target="dropdown-menu-participatory-space" data-auto-close="true" data-scroll-to-menu="true" data-open-md="true">
3
3
  <span><%= t("decidim.searches.filters.jump_to") %></span>
4
4
  <%= icon "arrow-down-s-line" %>
5
5
  <%= icon "arrow-up-s-line" %>
6
6
  </button>
7
- <ul id="dropdown-menu-participatory-space" class="participatory-space__nav" aria-hidden="true">
7
+ <ul id="dropdown-menu-participatory-space" class="participatory-space__nav">
8
8
  <% model.each do |item| %>
9
- <li>
9
+ <li role="menuitem">
10
10
  <%= link_to item[:url], class: "participatory-space__nav-item" do %>
11
11
  <%= item[:name] %>
12
12
  <%= icon "arrow-right-line" %>
@@ -1,5 +1,5 @@
1
1
  <div id="<%= id %>" class="filter-container">
2
- <button id="dropdown-trigger-resource" data-component="dropdown" data-target="dropdown-menu-resource" data-auto-close="true">
2
+ <button id="dropdown-trigger-resource" data-component="dropdown" data-target="dropdown-menu-resource" data-open-md="true">
3
3
  <% resource_types.each do |resource_type| %>
4
4
  <span data-value="<%= resource_type[0] %>" class="<%= "is-active" if filter_param == resource_type[0] %>">
5
5
  <%= text_with_resource_icon(*resource_type) %>
@@ -8,15 +8,14 @@
8
8
  <%= icon "arrow-down-s-line" %>
9
9
  <%= icon "arrow-up-s-line" %>
10
10
  </button>
11
- <%= filter_form_for filter, form_path, :class => "new_filter", :id => "dropdown-menu-resource", "aria-hidden" => true do |form| %>
12
- <%= form.collection_radio_buttons(
13
- filter_param_key,
14
- resource_types,
15
- :first,
16
- :last,
17
- { checked: filter_param }
18
- ) do |builder|
19
- builder.label { builder.radio_button(class: "reset-defaults", hidden: true) + content_tag(:span, text_with_resource_icon(builder.value, builder.text), class: "filter") }
20
- end %>
21
- <% end %>
11
+ <ul id="dropdown-menu-resource">
12
+ <% resource_types.each do |resource_type| %>
13
+ <li role="menuitem">
14
+ <%= link_to decidim.last_activities_path(filter: { with_resource_type: resource_type[0] } ), class: "filter#{" is-active" if filter_param == resource_type[0]}" do %>
15
+ <span class="sr-only"><%= resource_type[1] %></span>
16
+ <%= text_with_resource_icon(*resource_type) %>
17
+ <% end %>
18
+ </li>
19
+ <% end %>
20
+ </ul>
22
21
  </div>
@@ -55,7 +55,12 @@ module Decidim
55
55
  # If user has left the account unconfirmed and later on decides to sign
56
56
  # in with omniauth with an already verified account, the account needs
57
57
  # to be marked confirmed.
58
- @user.skip_confirmation! if !@user.confirmed? && @user.email == verified_email
58
+ if !@user.confirmed? && @user.email == verified_email
59
+ @user.skip_confirmation!
60
+ @user.after_confirmation
61
+ end
62
+ @user.tos_agreement = "1"
63
+ @user.save!
59
64
  else
60
65
  @user.email = (verified_email || form.email)
61
66
  @user.name = form.name
@@ -69,10 +74,11 @@ module Decidim
69
74
  @user.avatar.attach(io: file, filename:)
70
75
  end
71
76
  @user.skip_confirmation! if verified_email
72
- end
77
+ @user.tos_agreement = "1"
78
+ @user.save!
73
79
 
74
- @user.tos_agreement = "1"
75
- @user.save!
80
+ @user.after_confirmation if verified_email
81
+ end
76
82
  end
77
83
 
78
84
  def create_identity
@@ -21,6 +21,7 @@ module Decidim
21
21
  include Decidim::SafeRedirect
22
22
  include NeedsSnippets
23
23
  include UserBlockedChecker
24
+ include ActiveStorage::SetCurrent
24
25
 
25
26
  helper Decidim::TranslationsHelper
26
27
  helper Decidim::MetaTagsHelper
@@ -7,7 +7,7 @@ module Decidim
7
7
  module Paginable
8
8
  extend ActiveSupport::Concern
9
9
 
10
- OPTIONS = [10, 20, 50, 100].freeze
10
+ OPTIONS = [25, 50, 100].freeze
11
11
 
12
12
  included do
13
13
  helper_method :per_page, :page_offset
@@ -24,6 +24,7 @@ module Decidim
24
24
  include DisableRedirectionToExternalHost
25
25
  include NeedsPasswordChange
26
26
  include LinkedResourceReference
27
+ include ActiveStorage::SetCurrent
27
28
 
28
29
  helper Decidim::MetaTagsHelper
29
30
  helper Decidim::DecidimFormHelper
@@ -57,7 +57,7 @@ module Decidim
57
57
  self,
58
58
  element_class: "font-semibold underline",
59
59
  active_class: "is-active",
60
- container_options: { class: "space-y-4 break-inside-avoid" },
60
+ container_options: { class: "space-y-4 break-inside-avoid", role: :menu },
61
61
  label: t("layouts.decidim.footer.decidim_title")
62
62
  )
63
63
  end
@@ -11,16 +11,14 @@ module Decidim
11
11
  def decidim_paginate(collection, paginate_params = {})
12
12
  return if collection.total_pages <= 1
13
13
 
14
+ per_page = (params[:per_page] || paginate_params[:per_page] || Decidim::Paginable::OPTIONS.first).to_i
15
+
14
16
  content_tag :div, class: "flex flex-col-reverse md:flex-row items-center justify-between gap-1 py-8 md:py-16", data: { pagination: "" } do
15
17
  template = ""
16
- template += render(partial: "decidim/shared/results_per_page", formats: [:html]) if collection.total_pages.positive?
18
+ template += render(partial: "decidim/shared/results_per_page", locals: { per_page: }, formats: [:html]) if collection.total_pages.positive?
17
19
  template += paginate collection, window: 2, outer_window: 1, theme: "decidim", params: paginate_params
18
20
  template.html_safe
19
21
  end
20
22
  end
21
-
22
- def per_page
23
- params[:per_page].to_i || Decidim::Paginable::OPTIONS.first
24
- end
25
23
  end
26
24
  end
@@ -84,11 +84,12 @@ module Decidim
84
84
  #
85
85
  # Returns String.
86
86
  def url
87
- if file?
88
- attached_uploader(:file).path
89
- elsif link?
90
- link
91
- end
87
+ @url ||=
88
+ if file?
89
+ attached_uploader(:file).url
90
+ elsif link?
91
+ link
92
+ end
92
93
  end
93
94
 
94
95
  # The URL to download the thumbnail of the file. Only works with images.
@@ -97,7 +98,7 @@ module Decidim
97
98
  def thumbnail_url
98
99
  return unless photo?
99
100
 
100
- attached_uploader(:file).path(variant: :thumbnail)
101
+ @thumbnail_url ||= attached_uploader(:file).variant_url(:thumbnail)
101
102
  end
102
103
 
103
104
  # The URL to download the a big version of the file. Only works with images.
@@ -106,7 +107,7 @@ module Decidim
106
107
  def big_url
107
108
  return unless photo?
108
109
 
109
- attached_uploader(:file).path(variant: :big)
110
+ @big_url ||= attached_uploader(:file).variant_url(:big)
110
111
  end
111
112
 
112
113
  def set_content_type_and_size
@@ -14,7 +14,10 @@ module Decidim
14
14
 
15
15
  belongs_to :participatory_space, polymorphic: true
16
16
 
17
- default_scope { order(arel_table[:weight].asc, arel_table[:manifest_name].asc) }
17
+ scope :registered_component_manifests, -> { where(manifest_name: Decidim.component_registry.manifests.collect(&:name)) }
18
+ scope :registered_space_manifests, -> { where(participatory_space_type: Decidim.participatory_space_registry.manifests.collect(&:model_class_name)) }
19
+
20
+ default_scope { registered_component_manifests.registered_space_manifests.order(arel_table[:weight].asc, arel_table[:manifest_name].asc) }
18
21
 
19
22
  delegate :organization, :categories, to: :participatory_space
20
23
 
@@ -60,8 +60,8 @@ module Decidim
60
60
  #
61
61
  # # This is how you can access the image data, just like with any other
62
62
  # # uploader field. You can use the uploader variants too.
63
- # content_block.images_container.attached_uploader(:my_image).path
64
- # content_block.images_container.attached_uploader(:my_image).path(variant: :big)
63
+ # content_block.images_container.attached_uploader(:my_image).url
64
+ # content_block.images_container.attached_uploader(:my_image).variant_url(:big)
65
65
  #
66
66
  # # This will delete the attached image
67
67
  # content_block.images_container.my_image = nil
@@ -278,6 +278,18 @@ module Decidim
278
278
  false
279
279
  end
280
280
 
281
+ def after_confirmation
282
+ return unless organization.send_welcome_notification?
283
+
284
+ Decidim::EventsManager.publish(
285
+ event: "decidim.events.core.welcome_notification",
286
+ event_class: WelcomeNotificationEvent,
287
+ resource: self,
288
+ affected_users: [self],
289
+ extra: { force_email: true }
290
+ )
291
+ end
292
+
281
293
  protected
282
294
 
283
295
  # Overrides devise email required validation.
@@ -296,18 +308,6 @@ module Decidim
296
308
  super
297
309
  end
298
310
 
299
- def after_confirmation
300
- return unless organization.send_welcome_notification?
301
-
302
- Decidim::EventsManager.publish(
303
- event: "decidim.events.core.welcome_notification",
304
- event_class: WelcomeNotificationEvent,
305
- resource: self,
306
- affected_users: [self],
307
- extra: { force_email: true }
308
- )
309
- end
310
-
311
311
  private
312
312
 
313
313
  # Changes default Devise behaviour to use ActiveJob to send async emails.
@@ -59,7 +59,6 @@ const createDropdown = (component) => {
59
59
  const dropdownOptions = {};
60
60
  dropdownOptions.dropdown = component.dataset.target;
61
61
  dropdownOptions.hover = component.dataset.hover === "true";
62
- dropdownOptions.isOpen = component.dataset.open === "true";
63
62
  dropdownOptions.autoClose = component.dataset.autoClose === "true";
64
63
 
65
64
  // This snippet allows to disable the dropdown based on the current viewport
@@ -78,6 +77,17 @@ const createDropdown = (component) => {
78
77
  return
79
78
  }
80
79
 
80
+ dropdownOptions.isOpen = component.dataset.open === "true";
81
+
82
+ const isOpen = Object.keys(screens).some((key) => {
83
+ if (!isScreenSize(key)) {
84
+ return false;
85
+ }
86
+ return Boolean(component.dataset[`open-${key}`.replace(/-([a-z])/g, (str) => str[1].toUpperCase())]);
87
+ });
88
+
89
+ dropdownOptions.isOpen = dropdownOptions.isOpen || isOpen;
90
+
81
91
  if (!component.id) {
82
92
  // when component has no id, we enforce to have it one
83
93
  component.id = `dropdown-${Math.random().toString(36).substring(7)}`
@@ -104,20 +114,6 @@ const createDropdown = (component) => {
104
114
  });
105
115
  }
106
116
 
107
- // Disable focus on children elements so we can pass the AXE accessibility tests
108
- const dropdownMenu = document.getElementById(dropdownOptions.dropdown);
109
- if (dropdownMenu.getAttribute("aria-hidden") === "true") {
110
- dropdownMenu.
111
- querySelectorAll("a, input, button").
112
- forEach((element) => { element.tabIndex = -1 })
113
- }
114
-
115
- component.addEventListener("click", () => {
116
- dropdownMenu.
117
- querySelectorAll("a, input, button").
118
- forEach((element) => { element.tabIndex = 0 })
119
- })
120
-
121
117
  Dropdowns.render(component.id, dropdownOptions);
122
118
  }
123
119
 
@@ -36,10 +36,14 @@ const initializeTabs = (container) => {
36
36
  updateTabsState(container);
37
37
  });
38
38
 
39
- uploadsContainer.addEventListener("DOMSubtreeModified", () => {
40
- updateTabsState(container);
41
- console.log("DOMSubtreeModified");
39
+ const observer = new MutationObserver((mutationsList) => {
40
+ mutationsList.forEach((mutation) => {
41
+ if (mutation.type === "childList") {
42
+ updateTabsState(container);
43
+ }
44
+ });
42
45
  });
46
+ observer.observe(uploadsContainer, {childList: true, subtree: true});
43
47
 
44
48
  updateTabsState(container);
45
49
  };
@@ -74,7 +74,7 @@ export default class InputCharacterCounter {
74
74
 
75
75
  // If input is a hidden for WYSIWYG editor add it at the end
76
76
  if (this.$input.parent().is(".editor")) {
77
- this.$input.parent().after(this.$target);
77
+ this.$input.parent().append(container);
78
78
  } else {
79
79
  const wrapper = document.createElement("span")
80
80
  wrapper.className = "input-character-counter"
@@ -72,6 +72,15 @@
72
72
  .dropdown {
73
73
  @apply absolute border-2 border-gray-3 rounded min-w-max p-4 drop-shadow-md text-left z-10;
74
74
 
75
+ /*
76
+ NOTE: the calculated value is the sum of the arrow offset position plus the half of the arrow size:
77
+ - offset position: 20%
78
+ - arrow size: 1.5rem
79
+ */
80
+ --arrow-offset: 20%;
81
+ --arrow-size: 1.5rem;
82
+ --arrow-visible-size: var(--arrow-size) * 0.5;
83
+
75
84
  & > * {
76
85
  @apply relative z-10 p-3.5 first:pt-1.5 last:pb-1.5;
77
86
  }
@@ -90,15 +99,6 @@
90
99
  }
91
100
  }
92
101
 
93
- /*
94
- NOTE: the calculated value is the sum of the arrow offset position plus the half of the arrow size:
95
- - offset position: 20%
96
- - arrow size: 1.5rem
97
- */
98
- --arrow-offset: 20%;
99
- --arrow-size: 1.5rem;
100
- --arrow-visible-size: var(--arrow-size) * 0.5;
101
-
102
102
  &__bottom {
103
103
  @apply top-full right-0 mt-3 translate-x-[calc(var(--arrow-offset)-var(--arrow-visible-size))] before:content-[''] before:absolute before:right-[var(--arrow-offset)] before:-top-2 before:w-[var(--arrow-size)] before:h-[var(--arrow-size)] before:rotate-45 before:bg-white before:rounded before:border-2 before:border-gray-3 after:content-[''] after:absolute after:left-0 after:top-0 after:w-full after:h-full after:bg-white;
104
104
  }
@@ -1,6 +1,8 @@
1
1
  .filter {
2
+ @apply flex gap-2 p-1.5 relative;
3
+
2
4
  label {
3
- @apply flex items-center gap-2 p-1.5 rounded cursor-pointer relative;
5
+ @apply flex items-center gap-2 p-1.5 rounded cursor-pointer relative w-full;
4
6
  }
5
7
 
6
8
  &-container {
@@ -3,7 +3,7 @@ footer {
3
3
  @apply bg-gray-4;
4
4
 
5
5
  &__top {
6
- @apply hidden flex flex-col lg:flex-row lg:block gap-8 container py-10;
6
+ @apply hidden lg:flex flex-row gap-8 container py-10;
7
7
  }
8
8
 
9
9
  &__down {
@@ -53,16 +53,16 @@
53
53
  }
54
54
 
55
55
  select {
56
- &:not(.reset-defaults) {
57
- @apply pr-8;
58
- }
59
-
60
56
  @apply appearance-none;
61
57
 
62
58
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 12 8'%3e%3cpath fill='%233E4C5C' d='M5.99962 4.97656L10.1246 0.851562L11.303 2.0299L5.99962 7.33323L0.696289 2.0299L1.87462 0.851562L5.99962 4.97656Z'/%3e%3c/svg%3e");
63
59
  background-position: right 1rem center;
64
60
  background-repeat: no-repeat;
65
61
  background-size: 0.75rem;
62
+
63
+ &:not(.reset-defaults) {
64
+ @apply pr-8;
65
+ }
66
66
  }
67
67
  }
68
68
 
@@ -1,6 +1,16 @@
1
1
  [role="tooltip"] {
2
2
  @apply absolute bg-black z-10 px-4 py-2 w-max max-w-xs rounded text-left text-white;
3
3
 
4
+ /*
5
+ NOTE: the calculated value is the sum of the arrow offset position plus the half of the arrow size:
6
+ - offset position: 20%
7
+ - arrow size: 16px
8
+ */
9
+ --arrow-offset: 20%;
10
+ --arrow-size: 16px;
11
+ --arrow-visible-size: var(--arrow-size) * 0.5;
12
+ --arrow-margin: var(--arrow-visible-size) * 1.4142135623730951; // due to the rotation, the margin is SQRT2 times the visible size
13
+
4
14
  & > * {
5
15
  @apply relative z-20;
6
16
  }
@@ -41,16 +51,6 @@
41
51
  }
42
52
  }
43
53
 
44
- /*
45
- NOTE: the calculated value is the sum of the arrow offset position plus the half of the arrow size:
46
- - offset position: 20%
47
- - arrow size: 16px
48
- */
49
- --arrow-offset: 20%;
50
- --arrow-size: 16px;
51
- --arrow-visible-size: var(--arrow-size) * 0.5;
52
- --arrow-margin: var(--arrow-visible-size) * 1.4142135623730951; // due to the rotation, the margin is SQRT2 times the visible size
53
-
54
54
  &.top {
55
55
  @apply -translate-x-[calc(100%-var(--arrow-offset))] -translate-y-[calc(100%+var(--arrow-margin))] before:content-[''] before:absolute before:-z-10 before:right-[calc(var(--arrow-offset)-var(--arrow-visible-size))] before:-bottom-[var(--arrow-visible-size)] before:w-[var(--arrow-size)] before:h-[var(--arrow-size)] before:rotate-45 before:bg-black before:rounded-br;
56
56
  }
@@ -21,7 +21,7 @@
21
21
  }
22
22
 
23
23
  .editor-container {
24
- @apply editor-props editor-suggestions-props flex flex-col mb-6 border editor-border;
24
+ @apply editor-props editor-suggestions-props flex flex-col mt-4 border editor-border;
25
25
 
26
26
  &.editor-disabled {
27
27
  .editor-input .ProseMirror {
@@ -26,7 +26,7 @@ module Decidim
26
26
  delegate :content_tag, :safe_join, :link_to, :active_link_to_class, :is_active_link?, :icon, to: :@view
27
27
 
28
28
  def render
29
- content_tag :li, class: link_wrapper_classes do
29
+ content_tag :li, role: :menuitem, class: link_wrapper_classes do
30
30
  output = if url == "#"
31
31
  [content_tag(:span, composed_label, class: "sidebar-menu__item-disabled")]
32
32
  else
@@ -51,13 +51,14 @@ module Decidim
51
51
  headers.push(*exporter.headers)
52
52
  exported = exporter.export
53
53
 
54
- tmpfile = Tempfile.new("#{export_manifest.name}-#{component.id}-")
55
- tmpfile.write(exported.read)
56
- # Do not delete the file when the reference is deleted
57
- ObjectSpace.undefine_finalizer(tmpfile)
58
- tmpfile.close
59
-
60
- collection.push(tmpfile.path)
54
+ tmpdir = Dir::Tmpname.create(export_manifest.name.to_s) do
55
+ # just get an empty file name
56
+ end
57
+ filename = File.join(tmpdir, "#{component.id}.csv")
58
+ Dir.mkdir(tmpdir)
59
+ File.write(filename, exported.read)
60
+
61
+ collection.push(filename)
61
62
  end
62
63
  end
63
64
  end
@@ -8,22 +8,22 @@
8
8
  "background_color": "#FFFFFF",
9
9
  "icons": [
10
10
  {
11
- "src": "<%= current_organization.attached_uploader(:favicon).variant_path :small %>",
11
+ "src": "<%= current_organization.attached_uploader(:favicon).variant_url :small %>",
12
12
  "sizes": "32x32",
13
13
  "type": "image/png"
14
14
  },
15
15
  {
16
- "src": "<%= current_organization.attached_uploader(:favicon).variant_path :medium %>",
16
+ "src": "<%= current_organization.attached_uploader(:favicon).variant_url :medium %>",
17
17
  "sizes": "180x180",
18
18
  "type": "image/png"
19
19
  },
20
20
  {
21
- "src": "<%= current_organization.attached_uploader(:favicon).variant_path :big %>",
21
+ "src": "<%= current_organization.attached_uploader(:favicon).variant_url :big %>",
22
22
  "sizes": "192x192",
23
23
  "type": "image/png"
24
24
  },
25
25
  {
26
- "src": "<%= current_organization.attached_uploader(:favicon).variant_path :huge %>",
26
+ "src": "<%= current_organization.attached_uploader(:favicon).variant_url :huge %>",
27
27
  "sizes": "512x512",
28
28
  "type": "image/png"
29
29
  }
@@ -11,16 +11,16 @@
11
11
 
12
12
  <div class="vertical-tabs">
13
13
  <nav>
14
- <button id="dropdown-trigger-pages" data-component="dropdown" data-target="dropdown-menu-pages" data-auto-close="true">
14
+ <button id="dropdown-trigger-pages" data-component="dropdown" data-target="dropdown-menu-pages" data-open-md="true" data-auto-close="true">
15
15
  <span>
16
16
  <%= translated_attribute(page.title) %>
17
17
  </span>
18
18
  <%= icon "arrow-down-s-line" %>
19
19
  <%= icon "arrow-up-s-line" %>
20
20
  </button>
21
- <ul id="dropdown-menu-pages" class="vertical-tabs__list" aria-hidden="true">
21
+ <ul id="dropdown-menu-pages" class="vertical-tabs__list" role="menu">
22
22
  <% pages.each do |sibling| %>
23
- <li class="<%= "is-active" if page == sibling %>">
23
+ <li class="<%= "is-active" if page == sibling %>" role="menuitem">
24
24
  <%= link_to translated_attribute(sibling.title), page_path(sibling.slug) %>
25
25
  </li>
26
26
  <% end %>