diff --git a/app/assets/javascripts/darkswarm/directives/darker_background.js.coffee b/app/assets/javascripts/darkswarm/directives/darker_background.js.coffee
deleted file mode 100644
index b41541fab1..0000000000
--- a/app/assets/javascripts/darkswarm/directives/darker_background.js.coffee
+++ /dev/null
@@ -1,11 +0,0 @@
-angular.module('Darkswarm').directive "darkerBackground", ->
- restrict: "A"
- link: (scope, elm, attr)->
- toggleClass = (value) ->
- elm.closest('.page-view').toggleClass("with-darker-background", value)
-
- toggleClass(true)
-
- # if an OrderCycle is selected, disable darker background
- scope.$watch 'order_cycle.order_cycle_id', (newvalue, oldvalue) ->
- toggleClass(false) if newvalue
diff --git a/app/assets/javascripts/darkswarm/directives/disable_dynamically.js.coffee b/app/assets/javascripts/darkswarm/directives/disable_dynamically.js.coffee
deleted file mode 100644
index 33df890ead..0000000000
--- a/app/assets/javascripts/darkswarm/directives/disable_dynamically.js.coffee
+++ /dev/null
@@ -1,14 +0,0 @@
-# Allows disabling of link buttons via disabled attribute.
-# This is normally ignored, ie the link appears disabled but is still clickable.
-
-angular.module('Darkswarm').directive "disableDynamically", ->
- restrict: 'A'
-
- link: (scope, element, attrs) ->
- element.on 'click', (e) ->
- if attrs.disabled
- e.preventDefault()
- return
-
- scope.$on "$destroy", ->
- element.off("click")
diff --git a/app/assets/javascripts/darkswarm/directives/inline_alert.js.coffee b/app/assets/javascripts/darkswarm/directives/inline_alert.js.coffee
deleted file mode 100644
index 217a82b35b..0000000000
--- a/app/assets/javascripts/darkswarm/directives/inline_alert.js.coffee
+++ /dev/null
@@ -1,7 +0,0 @@
-angular.module('Darkswarm').directive "ofnInlineAlert", ->
- restrict: 'A'
- scope: true
- link: (scope, elem, attrs) ->
- scope.visible = true
- scope.close = ->
- scope.visible = false
diff --git a/app/assets/javascripts/darkswarm/directives/page_alert.js.coffee b/app/assets/javascripts/darkswarm/directives/page_alert.js.coffee
deleted file mode 100644
index d0fadadde7..0000000000
--- a/app/assets/javascripts/darkswarm/directives/page_alert.js.coffee
+++ /dev/null
@@ -1,21 +0,0 @@
-angular.module('Darkswarm').directive "ofnPageAlert", ($timeout) ->
- restrict: 'A'
- scope: true
- link: (scope, elem, attrs) ->
- moveSelectors = [".off-canvas-wrap .inner-wrap",
- ".off-canvas-wrap .inner-wrap .fixed",
- ".off-canvas-fixed .top-bar",
- ".off-canvas-fixed ofn-flash",
- ".off-canvas-fixed nav.tab-bar",
- ".off-canvas-fixed .page-alert"]
-
- container_elems = $(moveSelectors.join(", "))
-
- # Wait a moment after page load before showing the alert. Otherwise we often miss the
- # start of the animation.
- $timeout ->
- container_elems.addClass("move-up")
- , 1000
-
- scope.close = ->
- container_elems.removeClass("move-up")
diff --git a/app/helpers/link_helper.rb b/app/helpers/link_helper.rb
index dde2433446..fced430271 100644
--- a/app/helpers/link_helper.rb
+++ b/app/helpers/link_helper.rb
@@ -1,6 +1,29 @@
# frozen_string_literal: true
module LinkHelper
+ def link_to_or_disabled(name = nil, options = nil, html_options = nil, &block)
+ html_options, options, name = options, name, block if block_given?
+ html_options ||= {}
+
+ if !!html_options.delete(:disabled)
+ # https://www.scottohara.me/blog/2021/05/28/disabled-links.html
+ html_options.merge!(
+ 'aria-disabled': true,
+ class: (html_options[:class].to_s.split + ["disabled"]).uniq.join(" "),
+ role: "link"
+ )
+ if block_given?
+ content_tag("a", name, **html_options, &block)
+ else
+ content_tag("a", name, **html_options)
+ end
+ elsif block_given?
+ link_to options, html_options, &block
+ else
+ link_to name, options, html_options
+ end
+ end
+
def link_to_service(baseurl, name, html_options = {}, &)
return if name.blank?
diff --git a/app/helpers/shop_helper.rb b/app/helpers/shop_helper.rb
index fa248c8047..5fcdedc0d9 100644
--- a/app/helpers/shop_helper.rb
+++ b/app/helpers/shop_helper.rb
@@ -62,6 +62,12 @@ module ShopHelper
true
end
+ def shop_tab_class(tab)
+ return unless (tab == "home" && show_home_tab?) || current_order(false)&.order_cycle.nil?
+
+ "with-darker-background"
+ end
+
private
def show_groups_tabs?
diff --git a/app/views/registration/steps/_about.html.haml b/app/views/registration/steps/_about.html.haml
index 9a18dbd55a..4265fc148f 100644
--- a/app/views/registration/steps/_about.html.haml
+++ b/app/views/registration/steps/_about.html.haml
@@ -13,10 +13,10 @@
%form{ name: 'about', novalidate: true, "ng-controller": "RegistrationFormCtrl", "ng-submit": "selectIfValid('images', about)" }
.row
.small-12.columns
- .alert-box.info{ "ofn-inline-alert": true, "ng-show": "visible" }
+ .alert-box.info{ "data-controller": "toggle-control", "data-toggle-control-target": "content", style: "display: block;" }
%h6{ "ng-bind" => "'registration.steps.about.success' | t:{enterprise: enterprise.name}" }
%span= t(".registration_exit_message")
- %a.close{ "ng-click": "close()" } ×
+ %a.close{ "data-action": "toggle-control#toggleDisplay" } ×
.small-12.large-8.columns
.row
diff --git a/app/views/shared/menu/_alert.html.haml b/app/views/shared/menu/_alert.html.haml
index 787c1258cc..c2bd5e43a5 100644
--- a/app/views/shared/menu/_alert.html.haml
+++ b/app/views/shared/menu/_alert.html.haml
@@ -1,4 +1,4 @@
-.text-center.page-alert.fixed{ "ofn-page-alert" => true }
+.text-center.page-alert.fixed{ "data-controller" => "page-alert" }
.alert-box
= render 'shared/page_alert'
- %a.close{ "ng-click": "close()" } ×
+ %a.close{ "data-action" => "page-alert#close" } ×
diff --git a/app/views/shop/messages/_closed_shop.html.haml b/app/views/shop/messages/_closed_shop.html.haml
index 7c65eeaef4..185306b6b3 100644
--- a/app/views/shop/messages/_closed_shop.html.haml
+++ b/app/views/shop/messages/_closed_shop.html.haml
@@ -1,7 +1,7 @@
.closed-shop-header
.row
.small-12.columns
- .content{ "darker-background" => true }
+ .content
%h4
.warning-sign
.rectangle
diff --git a/app/views/shop/messages/_customer_required.html.haml b/app/views/shop/messages/_customer_required.html.haml
index 844621ce28..9b358f1e6e 100644
--- a/app/views/shop/messages/_customer_required.html.haml
+++ b/app/views/shop/messages/_customer_required.html.haml
@@ -1,4 +1,4 @@
-.content{ "darker-background" => true }
+.content
.row.footer-pad
.small-12.columns{ "data-controller": "login-modal" }
%strong
diff --git a/app/views/shop/messages/_select_oc.html.haml b/app/views/shop/messages/_select_oc.html.haml
index 6256789d32..74376d178e 100644
--- a/app/views/shop/messages/_select_oc.html.haml
+++ b/app/views/shop/messages/_select_oc.html.haml
@@ -1,4 +1,4 @@
-.content.footer-pad{ "darker-background" => true, "ng-show" => "order_cycle.order_cycle_id == null" }
+.content.footer-pad{ "ng-show" => "order_cycle.order_cycle_id == null" }
.row
.small-12.columns
.select-oc-message
diff --git a/app/views/shopping_shared/_tabs.html.haml b/app/views/shopping_shared/_tabs.html.haml
index 92d288a9f9..31870b7b38 100644
--- a/app/views/shopping_shared/_tabs.html.haml
+++ b/app/views/shopping_shared/_tabs.html.haml
@@ -10,8 +10,8 @@
.columns.large-4.show-for-large-up
= render partial: "shopping_shared/order_cycles"
- shop_tabs.each do |tab|
- %div{id: "#{tab[:name]}_panel", "data-tabs-and-panels-target": "panel #{'default' if tab[:default]} #{'shop' if tab[:shop]}" }
- .page-view
+ %div{id: "#{tab[:name]}_panel", "data-tabs-and-panels-target": "panel #{'default' if tab[:default]} #{'shop' if tab[:shop]}" }
+ .page-view{ class: shop_tab_class(tab[:name]) }
- if tab[:custom]
= render "shopping_shared/tabs/custom"
- else
diff --git a/app/views/spree/orders/form/_cart_links.html.haml b/app/views/spree/orders/form/_cart_links.html.haml
index 5eaac48a55..a9b17a2172 100644
--- a/app/views/spree/orders/form/_cart_links.html.haml
+++ b/app/views/spree/orders/form/_cart_links.html.haml
@@ -1,5 +1,3 @@
.row.links
- %a.continue-shopping.button.secondary{href: current_shop_products_path, "ng-disabled" => "#{@insufficient_stock_lines.any?}", "disable-dynamically" => true}
- = t :orders_edit_continue
- %a#checkout-link.button.primary.right{href: main_app.checkout_path, "ng-disabled" => "#{@insufficient_stock_lines.any?}", "disable-dynamically" => true}
- = t :orders_edit_checkout
+ = link_to_or_disabled t(:orders_edit_continue), current_shop_products_path, class: "continue-shopping button secondary", disabled: @insufficient_stock_lines.any?
+ = link_to_or_disabled t(:orders_edit_checkout), main_app.checkout_path, class: "button primary right", disabled: @insufficient_stock_lines.any?, id: "checkout-link"
diff --git a/app/views/spree/shared/_order_details.html.haml b/app/views/spree/shared/_order_details.html.haml
index de68929af7..0038ea7309 100644
--- a/app/views/spree/shared/_order_details.html.haml
+++ b/app/views/spree/shared/_order_details.html.haml
@@ -42,9 +42,9 @@
.row
.columns.large-12
- if order.changes_allowed?
- .alert-box.order-summary{ "ofn-inline-alert" => true, "ng-show" => "visible" }
+ .alert-box.order-summary{ "data-controller": "toggle-control", "data-toggle-control-target": "content", style: "display: block;" }
= t(:orders_changeable_orders_alert_html, oc_close: l(order.order_cycle.orders_close_at, format: "%b %d, %Y %H:%M"))
- %a.close{ "ng-click" => "close()" } ×
+ %a.close{ "data-action": "toggle-control#toggleDisplay" } ×
= form_for order, url: main_app.order_path(order), html: {id: 'update-order', name: 'update_order_form' } do |order_form|
- if order.changes_allowed?
diff --git a/app/webpacker/controllers/page_alert_controller.js b/app/webpacker/controllers/page_alert_controller.js
new file mode 100644
index 0000000000..a7bd46dc03
--- /dev/null
+++ b/app/webpacker/controllers/page_alert_controller.js
@@ -0,0 +1,34 @@
+import { Controller } from "stimulus";
+
+export default class extends Controller {
+ moveSelectors = [".off-canvas-wrap .inner-wrap",
+ ".off-canvas-wrap .inner-wrap .fixed",
+ ".off-canvas-fixed .top-bar",
+ ".off-canvas-fixed ofn-flash",
+ ".off-canvas-fixed nav.tab-bar",
+ ".off-canvas-fixed .page-alert"];
+
+ connect() {
+ // Wait a moment after page load before showing the alert. Otherwise we often miss the
+ // start of the animation.
+ setTimeout(this.#show, 1000);
+ }
+
+ close() {
+ this.#moveElements().forEach((element) => {
+ element.classList.remove("move-up");
+ });
+ }
+
+ // private
+
+ #moveElements() {
+ return document.querySelectorAll(this.moveSelectors.join(","));
+ }
+
+ #show = () => {
+ this.#moveElements().forEach((element) => {
+ element.classList.add("move-up");
+ });
+ };
+}
diff --git a/app/webpacker/css/admin_v3/components/buttons.scss b/app/webpacker/css/admin_v3/components/buttons.scss
index 01ede577d1..7de1a2ab6e 100644
--- a/app/webpacker/css/admin_v3/components/buttons.scss
+++ b/app/webpacker/css/admin_v3/components/buttons.scss
@@ -182,6 +182,10 @@ a.button {
text-decoration: none;
}
+a[aria-disabled] {
+ pointer-events: none;
+}
+
.button.disruptive::before {
margin-right: 3px;
diff --git a/app/webpacker/css/darkswarm/_shop-product-rows.scss b/app/webpacker/css/darkswarm/_shop-product-rows.scss
index ddf25d6d51..edbe9fb00a 100644
--- a/app/webpacker/css/darkswarm/_shop-product-rows.scss
+++ b/app/webpacker/css/darkswarm/_shop-product-rows.scss
@@ -1,5 +1,7 @@
.darkswarm {
products {
+ background-color: white;
+
product {
@import "shop_partials/shop-product-rows";
}
diff --git a/spec/helpers/link_helper_spec.rb b/spec/helpers/link_helper_spec.rb
index 14dc507343..aceeca8cf7 100644
--- a/spec/helpers/link_helper_spec.rb
+++ b/spec/helpers/link_helper_spec.rb
@@ -9,4 +9,25 @@ RSpec.describe LinkHelper do
expect(helper.ext_url("http://example.com/", "bla")).to eq("http://example.com/bla")
end
end
+
+ describe "link_to_or_disabled" do
+ it "behaves like the standard :link_to method e.g. it accepts the same arguments and accepts
+ blocks, etc." do
+ expect(helper.link_to_or_disabled("Go", "http://example.com/")).to eq(
+ "Go"
+ )
+ expect(helper.link_to_or_disabled("Go", "http://example.com/", class: "button")).to eq(
+ "Go"
+ )
+ expect(helper.link_to_or_disabled("http://example.com/") { "Go" }).to eq(
+ "Go"
+ )
+ end
+
+ it "accepts an additional boolean :disabled argument, which if true renders a disabled link" do
+ expect(helper.link_to_or_disabled("Go", "http://example.com/", disabled: true)).to eq(
+ "Go"
+ )
+ end
+ end
end
diff --git a/spec/system/consumer/shopping/cart_spec.rb b/spec/system/consumer/shopping/cart_spec.rb
index ed039bc28d..6026f20d5e 100644
--- a/spec/system/consumer/shopping/cart_spec.rb
+++ b/spec/system/consumer/shopping/cart_spec.rb
@@ -241,8 +241,8 @@ RSpec.describe "full-page cart" do
'Please update the selected quantities.'
# "Continue Shopping" and "Checkout" buttons are disabled
- expect(page).to have_selector "a.continue-shopping[disabled=disabled]"
- expect(page).to have_selector "a#checkout-link[disabled=disabled]"
+ expect(page).to have_selector "a.continue-shopping[aria-disabled=true]"
+ expect(page).to have_selector "a#checkout-link[aria-disabled=true]"
# Quantity field clearly marked as invalid and "Update" button is not highlighted
expect(page).to have_selector "#order_line_items_attributes_0_quantity.ng-invalid-stock"
@@ -260,8 +260,8 @@ RSpec.describe "full-page cart" do
click_button 'Update'
# "Continue Shopping" and "Checkout" buttons are not disabled after cart is updated
- expect(page).not_to have_selector "a.continue-shopping[disabled=disabled]"
- expect(page).not_to have_selector "a#checkout-link[disabled=disabled]"
+ expect(page).not_to have_selector "a.continue-shopping[aria-disabled=true]"
+ expect(page).not_to have_selector "a#checkout-link[aria-disabled=true]"
end
end
end
diff --git a/spec/views/spree/orders/edit.html.haml_spec.rb b/spec/views/spree/orders/edit.html.haml_spec.rb
index 2d1b6b65fd..f6b2988edb 100644
--- a/spec/views/spree/orders/edit.html.haml_spec.rb
+++ b/spec/views/spree/orders/edit.html.haml_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe "spree/orders/edit.html.haml" do
helper ShopHelper
helper ApplicationHelper
helper CheckoutHelper
+ helper LinkHelper
helper SharedHelper
helper FooterLinksHelper
helper MarkdownHelper