Merge branch 'main' into mobile/bridge-components
* main: Create popup initial alignment classes Fix class typo Hide the board selector button if card is closed Align board and tag picker dialogs without using math Add dialog manager to card perma Fix "M" hotkey using stale user from fragment cache Add Enable all/Disable all buttons to webhook event selection Remove whitespace Remove hover styles from disabled menu items # Conflicts: # app/views/cards/_container.html.erb
This commit is contained in:
@@ -378,6 +378,7 @@
|
||||
}
|
||||
|
||||
.cards__menu {
|
||||
position: relative;
|
||||
z-index: var(--z-popup);
|
||||
}
|
||||
|
||||
|
||||
@@ -119,17 +119,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.board-picker__button {
|
||||
--btn-border-size: 0;
|
||||
|
||||
font-size: 0.5em;
|
||||
margin-inline-start: 1ch;
|
||||
|
||||
+ .panel {
|
||||
--panel-size: 18ch;
|
||||
}
|
||||
}
|
||||
|
||||
.bubble {
|
||||
--bubble-number-max: 42px;
|
||||
--bubble-size: 6rem;
|
||||
|
||||
@@ -71,21 +71,19 @@
|
||||
min-inline-size: 0;
|
||||
padding-block: 0.25lh;
|
||||
padding-inline: var(--card-padding-inline) 1ch;
|
||||
|
||||
&:has(.board-picker__button) {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: background-color 100ms ease-out;
|
||||
|
||||
&:has(.btn) {
|
||||
@media (any-hover: hover) {
|
||||
&:hover {
|
||||
background-color: color-mix(in srgb, var(--card-color) 90%, var(--color-ink));
|
||||
}
|
||||
}
|
||||
|
||||
&:has(.btn:focus-visible) {
|
||||
outline: var(--focus-ring-size) solid var(--focus-ring-color);
|
||||
outline-offset: var(--focus-ring-offset);
|
||||
}
|
||||
|
||||
dialog {
|
||||
inset-block-start: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,9 +97,11 @@
|
||||
}
|
||||
|
||||
.card__board-name {
|
||||
align-items: center;
|
||||
border-inline-start: 1px solid color-mix(in hsl, transparent 75%, currentColor);
|
||||
color: currentColor;
|
||||
display: flex;
|
||||
gap: 0.25ch;
|
||||
margin-inline-start: var(--card-header-space);
|
||||
max-inline-size: 100%;
|
||||
min-inline-size: 0;
|
||||
@@ -109,14 +109,59 @@
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.card__board-picker-button {
|
||||
inset: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.card__tags {
|
||||
--btn-color: var(--card-color);
|
||||
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
color: var(--card-text-color);
|
||||
display: flex;
|
||||
gap: var(--card-header-space);
|
||||
gap: 0.5ch;
|
||||
min-inline-size: 0;
|
||||
|
||||
[data-controller="dialog"] {
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.popup {
|
||||
--panel-size: 18ch;
|
||||
|
||||
inset-block-start: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.card__tag-picker {
|
||||
--panel-border-radius: 2em;
|
||||
--panel-padding: 0.5em 0.7em;
|
||||
--panel-size: max-content;
|
||||
|
||||
inline-size: auto !important;
|
||||
inset: 0 auto auto 0;
|
||||
max-inline-size: var(--panel-size) !important;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
|
||||
&[open] {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.input {
|
||||
--input-padding: 0.2em 0.5em;
|
||||
|
||||
inline-size: 18ch;
|
||||
}
|
||||
}
|
||||
|
||||
.card__tag-picker-button {
|
||||
font-size: 0.6em;
|
||||
}
|
||||
|
||||
.card__tag {
|
||||
|
||||
@@ -21,11 +21,16 @@
|
||||
display: var(--popup-display);
|
||||
}
|
||||
|
||||
/* The .pop-up--align-<drection> classes are used for initial alignment.
|
||||
* The orient JS helper layers on the .orient-<direction> to avoid running
|
||||
* off the edge of the screen and will override .popup--align */
|
||||
&:where(.popup--align-left),
|
||||
&.orient-left {
|
||||
inset-inline: auto 0;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
&:where(.popup--align-right),
|
||||
&.orient-right {
|
||||
inset-inline: 0 auto;
|
||||
transform: translateX(0);
|
||||
@@ -127,6 +132,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
&:has(.popup__btn[disabled]) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.checked {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -164,8 +164,8 @@
|
||||
.comments__subscribers,
|
||||
.card__meta-avatars--assignees > div > div:last-child,
|
||||
.steps > .step:last-child,
|
||||
div:has(> .tag-picker__button),
|
||||
div:has(> .board-picker__button),
|
||||
.card__board-name .icon,
|
||||
div:has(> .card__tag-picker-button),
|
||||
.delete-card,
|
||||
.header--card .header__title {
|
||||
display: none;
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
@layer components {
|
||||
.tag-picker {
|
||||
--panel-border-radius: 2em;
|
||||
--panel-padding: 0.5em 0.7em;
|
||||
--panel-size: max-content;
|
||||
|
||||
inline-size: auto !important;
|
||||
inset: 0 auto auto 0;
|
||||
max-inline-size: var(--panel-size) !important;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
|
||||
&[open] {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.input {
|
||||
--input-padding: 0.2em 0.5em;
|
||||
|
||||
inline-size: 18ch;
|
||||
}
|
||||
}
|
||||
|
||||
.tag-picker__button {
|
||||
font-size: 0.6em;
|
||||
margin-block-start: 0.1em;
|
||||
margin-inline-start: 0.2em;
|
||||
|
||||
+ .panel {
|
||||
--panel-size: 18ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
class Cards::SelfAssignmentsController < ApplicationController
|
||||
include CardScoped
|
||||
|
||||
def create
|
||||
if @card.toggle_assignment(Current.user)
|
||||
respond_to do |format|
|
||||
format.turbo_stream { render "cards/assignments/create" }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
format.turbo_stream { render "cards/assignments/create" }
|
||||
format.json { head :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -79,7 +79,7 @@ export default class extends Controller {
|
||||
const selection = this.#selectedCard
|
||||
if (!selection) return
|
||||
|
||||
const url = selection.card.dataset.cardAssignToMeUrl
|
||||
const url = selection.card.dataset.cardAssignToSelfUrl
|
||||
if (url) {
|
||||
event.preventDefault()
|
||||
await post(url, { responseKind: "turbo-stream" })
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<%= icon_tag "menu-dots-horizontal", class: "translucent" %>
|
||||
<span class="for-screen-reader">Column options</span>
|
||||
</button>
|
||||
<dialog class="popup panel flex-column gap fill-white shadow txt-small margin-block-double" data-dialog-target="dialog">
|
||||
<dialog class="popup popup--align-right panel flex-column gap fill-white shadow txt-small margin-block-double" data-dialog-target="dialog">
|
||||
<ul class="popup__list">
|
||||
<li class="popup__item">
|
||||
<button class="popup__btn btn" data-action="click->clicker#click">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<section id="<%= dom_id(card, :card_container) %>" class="card-perma" style="--card-color: <%= card.color %>;" data-controller="bridge--form">
|
||||
<section id="<%= dom_id(card, :card_container) %>" class="card-perma" style="--card-color: <%= card.color %>;" data-controller="dialog-manager bridge--form">
|
||||
<% cache card do %>
|
||||
<div class="card-perma__actions card-perma__actions--left">
|
||||
<%= render "cards/container/gild", card: card if card.published? && !card.closed? %>
|
||||
|
||||
@@ -11,9 +11,7 @@
|
||||
<% card_data[:card_not_now_url] = card_not_now_path(card) %>
|
||||
<% card_data[:card_closure_url] = card_closure_path(card) %>
|
||||
<% card_data[:action] = "mouseenter->navigable-list#hoverSelect" %>
|
||||
<% if Current.user %>
|
||||
<% card_data[:card_assign_to_me_url] = card_assignments_path(card, params: { assignee_id: Current.user.id }) %>
|
||||
<% end %>
|
||||
<% card_data[:card_assign_to_self_url] = card_self_assignment_path(card) %>
|
||||
<% end %>
|
||||
|
||||
<%= card_article_tag card, class: "card", draggable: draggable, data: card_data, tabindex: 0 do %>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<label class="card__board">
|
||||
<span class="card__id">
|
||||
<div class="card__id">
|
||||
<span class="for-screen-reader">Card number</span>
|
||||
<%= card.number %>
|
||||
</span>
|
||||
<span class="card__board-name">
|
||||
</div>
|
||||
<div class="card__board-name">
|
||||
<span class="overflow-ellipsis"><%= card.board.name %></span>
|
||||
</span>
|
||||
<%= yield %>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
<%= render "cards/display/common/board", card: card do %>
|
||||
<div class="align-self-center position-relative txt-small"
|
||||
data-controller="dialog"
|
||||
data-action="keydown.esc->dialog#close:stop click@document->dialog#closeOnClickOutside mouseenter->dialog#loadLazyFrames" <%= "hidden" if card.closed? %>>
|
||||
<button class="board-picker__button btn btn--reversed card__hide-on-index fill-transparent" data-action="click->dialog#open:stop">
|
||||
<%= icon_tag "caret-down" %>
|
||||
<span class="for-screen-reader">Choose a board for this card</span>
|
||||
</button>
|
||||
|
||||
<dialog class="popup panel flex-column align-start gap-half fill-white shadow margin-block-double" data-dialog-target="dialog" data-action="turbo:before-morph-attribute->dialog#preventCloseOnMorphing turbo:submit-end->dialog#close">
|
||||
<div class="card__board" data-controller="dialog" data-action="keydown.esc->dialog#close:stop click@document->dialog#closeOnClickOutside mouseenter->dialog#loadLazyFrames">
|
||||
<%= render "cards/display/common/board", card: card do %>
|
||||
<%= icon_tag "caret-down", class: "txt-xx-small", hidden: card.closed? %>
|
||||
<% end %>
|
||||
<button class="card__board-picker-button btn btn--plain" data-action="click->dialog#open:stop" aria-label="Choose a board for this card" <%= "hidden" if card.closed? %>></button>
|
||||
<dialog class="popup popup--align-right panel flex-column align-start gap-half fill-white shadow" data-dialog-target="dialog" data-action="turbo:before-morph-attribute->dialog#preventCloseOnMorphing turbo:submit-end->dialog#close">
|
||||
<%= turbo_frame_tag "board_picker", src: edit_card_board_path(card), target: "_top", loading: :lazy, refresh: "morph" %>
|
||||
</dialog>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div id="<%= dom_id(card, :tags) %>" class="card__tags">
|
||||
<div class="position-relative" data-controller="dialog"
|
||||
<div data-controller="dialog"
|
||||
data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside mouseenter->dialog#loadLazyFrames" <%= "hidden" if card.closed? %>>
|
||||
<button class="tag-picker__button btn card__hide-on-index" style="--btn-background: var(--card-bg-color);"
|
||||
<button class="card__tag-picker-button btn card__hide-on-index" style="--btn-background: var(--card-bg-color);"
|
||||
data-controller="tooltip hotkey" data-action="click->dialog#open:stop keydown.t@document->hotkey#click">
|
||||
<%= icon_tag "tag" %>
|
||||
<span class="for-screen-reader">Add a tag</span>
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
<%= render "cards/display/common/board", card: card %>
|
||||
<div class="card__board">
|
||||
<%= render "cards/display/common/board", card: card %>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<ul class="flex flex-column align-start gap-half margin-none unpad">
|
||||
<div data-controller="toggle-class">
|
||||
<div class="flex align-center gap-half margin-block-end-half">
|
||||
<%= button_tag "Enable all", type: "button", class: "btn btn--plain txt-x-small txt-link font-weight-normal", data: { action: "click->toggle-class#checkAll" } %>
|
||||
<span class="txt-subtle">·</span>
|
||||
<%= button_tag "Disable all", type: "button", class: "btn btn--plain txt-x-small txt-link font-weight-normal", data: { action: "click->toggle-class#checkNone" } %>
|
||||
</div>
|
||||
<ul class="flex flex-column align-start gap-half margin-none unpad">
|
||||
<%= form.collection_check_boxes \
|
||||
:subscribed_actions,
|
||||
webhook_action_options,
|
||||
@@ -7,11 +13,12 @@
|
||||
<li class="list-style-none margin-none">
|
||||
<label class="toggler__visible-when-off flex align-center gap cursor-pointer">
|
||||
<span class="switch txt-x-small flex-item-no-shrink">
|
||||
<%= item.check_box(class: "switch__input") %>
|
||||
<%= item.check_box(class: "switch__input", data: { toggle_class_target: "checkbox" }) %>
|
||||
<span class="switch__btn round"></span>
|
||||
</span>
|
||||
<span class="min-width"><%= item.text %></span>
|
||||
</label>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -87,6 +87,7 @@ Rails.application.routes.draw do
|
||||
resource :reading
|
||||
|
||||
resources :assignments
|
||||
resource :self_assignment, only: :create
|
||||
resources :steps
|
||||
resources :taggings
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
require "test_helper"
|
||||
|
||||
class Cards::SelfAssignmentsControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in_as :kevin
|
||||
end
|
||||
|
||||
test "create assigns to current user" do
|
||||
card = cards(:layout)
|
||||
|
||||
assert_not card.assigned_to?(users(:kevin))
|
||||
|
||||
post card_self_assignment_path(card), as: :turbo_stream
|
||||
assert_response :success
|
||||
assert_meta_replaced(card)
|
||||
assert card.reload.assigned_to?(users(:kevin))
|
||||
end
|
||||
|
||||
test "create toggles off when already assigned" do
|
||||
card = cards(:logo)
|
||||
|
||||
assert card.assigned_to?(users(:kevin))
|
||||
|
||||
post card_self_assignment_path(card), as: :turbo_stream
|
||||
assert_response :success
|
||||
assert_meta_replaced(card)
|
||||
assert_not card.reload.assigned_to?(users(:kevin))
|
||||
end
|
||||
|
||||
test "create as JSON" do
|
||||
card = cards(:layout)
|
||||
|
||||
assert_not card.assigned_to?(users(:kevin))
|
||||
|
||||
post card_self_assignment_path(card), as: :json
|
||||
assert_response :no_content
|
||||
assert card.reload.assigned_to?(users(:kevin))
|
||||
end
|
||||
|
||||
private
|
||||
def assert_meta_replaced(card)
|
||||
assert_turbo_stream action: :replace, target: dom_id(card, :meta)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user