Merge branch 'main' into unique-notifications
This commit is contained in:
@@ -45,8 +45,9 @@
|
||||
min-block-size: 20lh;
|
||||
}
|
||||
|
||||
@media (max-width: 639px) {
|
||||
--bubble-size: 3rem;
|
||||
/* Hide on small, fat-finger touch devices */
|
||||
@media (hover: none) and (pointer: coarse) and (max-width: 519px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,4 +731,52 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile columns
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
.mobile-card-columns {
|
||||
--column-gap: 8px;
|
||||
--column-padding-expanded: calc(var(--column-gap) * 2);
|
||||
--column-width-collapsed: 40px;
|
||||
--progress-increment: var(--progress-max-width) / var(--progress-max-cards);
|
||||
--progress-max-cards: 20;
|
||||
--progress-max-width: 100%;
|
||||
|
||||
padding-inline: 3vw;
|
||||
|
||||
/* Hide on larger devices with cursors */
|
||||
@media (hover: hover) and (min-width: 520px) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cards.is-collapsed {
|
||||
inline-size: auto;
|
||||
display: block;
|
||||
padding-block: 0.5ch;
|
||||
|
||||
.cards__expander {
|
||||
flex-direction: row;
|
||||
inline-size: auto;
|
||||
|
||||
&:before {
|
||||
block-size: 1px;
|
||||
inline-size: 100%;
|
||||
inset: 50% 0 auto;
|
||||
translaate: 0 -50%;
|
||||
}
|
||||
|
||||
&:after {
|
||||
block-size: var(--column-width-collapsed);
|
||||
inline-size: calc(var(--column-width-collapsed) + var(--card-count) * var(--progress-increment));
|
||||
margin-inline-start: 0;
|
||||
max-inline-size: var(--progress-max-width);
|
||||
}
|
||||
}
|
||||
|
||||
.cards__expander-title {
|
||||
writing-mode: revert;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,29 +10,16 @@ class Cards::Comments::ReactionsController < ApplicationController
|
||||
end
|
||||
|
||||
def create
|
||||
reaction = @comment.reactions.create!(params.expect(reaction: :content))
|
||||
|
||||
broadcast_create(reaction)
|
||||
redirect_to card_comment_reactions_path(@card, @comment)
|
||||
@reaction = @comment.reactions.create!(params.expect(reaction: :content))
|
||||
end
|
||||
|
||||
def destroy
|
||||
reaction = @comment.reactions.find(params[:id])
|
||||
reaction.destroy
|
||||
|
||||
broadcast_remove(reaction)
|
||||
@reaction = @comment.reactions.find(params[:id])
|
||||
@reaction.destroy
|
||||
end
|
||||
|
||||
private
|
||||
def set_comment
|
||||
@comment = @card.comments.find(params[:comment_id])
|
||||
end
|
||||
|
||||
def broadcast_create(reaction)
|
||||
reaction.broadcast_append_to @card, target: [ @comment, :reactions ], partial: "cards/comments/reactions/reaction"
|
||||
end
|
||||
|
||||
def broadcast_remove(reaction)
|
||||
reaction.broadcast_remove_to @card
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,7 +8,6 @@ class Cards::TaggingsController < ApplicationController
|
||||
|
||||
def create
|
||||
@card.toggle_tag_with sanitized_tag_title_param
|
||||
render_card_replacement
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -5,6 +5,6 @@ class My::MenusController < ApplicationController
|
||||
@tags = Tag.all.alphabetically
|
||||
@users = User.active.alphabetically
|
||||
|
||||
# fresh_when etag: [ @user_filtering, Current.session ]
|
||||
fresh_when etag: [ @filters, @boards, @tags, @users ]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,7 +30,7 @@ module FiltersHelper
|
||||
tag.dialog class: "margin-block-start-half popup panel flex-column align-start gap-half fill-white shadow txt-small", data: {
|
||||
action: "turbo:before-cache@document->dialog#close keydown->navigable-list#navigate filter:changed->navigable-list#reset toggle->filter#filter",
|
||||
aria: { label: label, aria_description: label },
|
||||
controller: "filter navigable-list",
|
||||
controller: "navigable-list",
|
||||
dialog_target: "dialog",
|
||||
navigable_list_focus_on_selection_value: false,
|
||||
navigable_list_actionable_items_value: true
|
||||
|
||||
@@ -5,7 +5,8 @@ import { limitHeightToViewport } from "helpers/sizing_helpers"
|
||||
export default class extends Controller {
|
||||
static targets = [ "dialog" ]
|
||||
static values = {
|
||||
modal: { type: Boolean, default: false }
|
||||
modal: { type: Boolean, default: false },
|
||||
sizing: { type: Boolean, default: true }
|
||||
}
|
||||
|
||||
connect() {
|
||||
@@ -22,7 +23,7 @@ export default class extends Controller {
|
||||
orient(this.dialogTarget)
|
||||
}
|
||||
|
||||
limitHeightToViewport(this.dialogTarget, true)
|
||||
limitHeightToViewport(this.dialogTarget, this.sizingValue)
|
||||
|
||||
this.#loadLazyFrames()
|
||||
this.dialogTarget.setAttribute("aria-hidden", "false")
|
||||
@@ -43,6 +44,7 @@ export default class extends Controller {
|
||||
this.dialogTarget.blur()
|
||||
orient(this.dialogTarget, false)
|
||||
limitHeightToViewport(this.dialogTarget, false)
|
||||
this.dispatch("close")
|
||||
}
|
||||
|
||||
closeOnClickOutside({ target }) {
|
||||
|
||||
@@ -20,4 +20,9 @@ export default class extends Controller {
|
||||
|
||||
this.dispatch("changed")
|
||||
}
|
||||
|
||||
clearInput() {
|
||||
if (!this.hasInputTarget) return
|
||||
this.inputTarget.value = ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,5 +26,6 @@
|
||||
<%= render "boards/show/filtered_cards", page: @page %>
|
||||
<% else %>
|
||||
<%= render "boards/show/columns", page: @page, board: @board %>
|
||||
<%= render "boards/show/mobile_columns", page: @page, board: @board %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -25,4 +25,3 @@
|
||||
<%= render "boards/show/menu/columns", board: board %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<section class="mobile-card-columns">
|
||||
<%= link_to board_columns_not_now_path(board), class: "cards cards--on-deck is-collapsed", style: "--card-color: var(--color-card-complete);", data: { turbo_frame: "_top" } do %>
|
||||
<div class="cards__expander btn btn--plain" style="--card-count: <%= board.cards.postponed.count %>">
|
||||
<span class="cards__expander-count"><%= board.cards.postponed.count %></span>
|
||||
<h2 class="cards__expander-title">
|
||||
Not Now
|
||||
</h2>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= link_to board_columns_stream_path(board), class: "cards cards--considering is-collapsed", data: { turbo_frame: "_top" } do %>
|
||||
<div class="cards__expander btn btn--plain" style="--card-count: <%= board.cards.awaiting_triage.count %>">
|
||||
<span class="cards__expander-count"><%= board.cards.awaiting_triage.count %></span>
|
||||
<h2 class="cards__expander-title">
|
||||
Maybe?
|
||||
</h2>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% board.columns.sorted.each do |column| %>
|
||||
<%= link_to board_column_path(column.board, column), class: "cards cards--doing is-collapsed", style: "--card-color: #{column.color}", data: { turbo_frame: "_top" } do %>
|
||||
<div class="cards__expander btn btn--plain" style="--card-count: <%= column.cards.active.count %>">
|
||||
<span class="cards__expander-count"><%= column.cards.active.count %></span>
|
||||
<h2 class="cards__expander-title">
|
||||
<%= column.name %>
|
||||
</h2>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to board_columns_closed_path(board), class: "cards cards--on-deck is-collapsed", style: "--card-color: var(--color-card-complete);", data: { turbo_frame: "_top" } do %>
|
||||
<div class="cards__expander btn btn--plain" style="--card-count: <%= board.cards.closed.count %>">
|
||||
<span class="cards__expander-count"><%= board.cards.closed.count %></span>
|
||||
<h2 class="cards__expander-title">
|
||||
Done
|
||||
</h2>
|
||||
</div>
|
||||
<% end %>
|
||||
</section>
|
||||
@@ -17,7 +17,7 @@
|
||||
<span class="flex-inline align-center gap">
|
||||
<%= form.button class: "comment__submit btn btn--reversed",
|
||||
data: { form_target: "submit" }, disabled: true do %>
|
||||
<span>Post</span>
|
||||
<span>Post this comment</span>
|
||||
<% end %>
|
||||
<span class="hide-on-touch txt-subtle">
|
||||
<kbd class="txt-x-small"><%= hotkey_label([ "ctrl", "enter" ]) %></kbd>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<%= turbo_stream.replace([ @comment, :reacting ]) do %>
|
||||
<%= render "cards/comments/reactions/reactions", comment: @comment.reload %>
|
||||
<% end %>
|
||||
@@ -0,0 +1 @@
|
||||
<%= turbo_stream.remove @reaction %>
|
||||
@@ -1,13 +1,19 @@
|
||||
<div class="card-perma__notch card-perma__notch--bottom">
|
||||
<%= button_to card_publish_path(card), name: "creation_type", value: "add", class: "btn",
|
||||
form: { data: { controller: "form" } },
|
||||
data: { form_target: "submit", controller: "clicker", action: "keydown.ctrl+enter@document->clicker#click keydown.meta+enter@document->clicker#click" } do %>
|
||||
<span>Create card</span>
|
||||
<% end %>
|
||||
<div class="flex flex-column gap-half">
|
||||
<%= button_to card_publish_path(card), name: "creation_type", value: "add", class: "btn",
|
||||
form: { data: { controller: "form" } },
|
||||
data: { form_target: "submit", controller: "clicker", action: "keydown.ctrl+enter@document->clicker#click keydown.meta+enter@document->clicker#click" } do %>
|
||||
<span>Create card</span>
|
||||
<% end %>
|
||||
<kbd class="txt-x-small txt-subtle center"><%= hotkey_label([ "ctrl", "enter" ]) %></kbd>
|
||||
</div>
|
||||
|
||||
<%= button_to card_publish_path(card), method: :post, class: "btn btn--reversed", name: "creation_type", value: "add_another",
|
||||
title: "Create and add another (ctrl+shift+enter)", form: { data: { controller: "form" } },
|
||||
data: { form_target: "submit", controller: "clicker", action: "keydown.ctrl+shift+enter@document->clicker#click keydown.meta+shift+enter@document->clicker#click" } do %>
|
||||
<span>Create and add another</span>
|
||||
<% end %>
|
||||
<div class="flex flex-column gap-half">
|
||||
<%= button_to card_publish_path(card), method: :post, class: "btn btn--reversed", name: "creation_type", value: "add_another",
|
||||
title: "Create and add another (ctrl+shift+enter)", form: { data: { controller: "form" } },
|
||||
data: { form_target: "submit", controller: "clicker", action: "keydown.ctrl+shift+enter@document->clicker#click keydown.meta+shift+enter@document->clicker#click" } do %>
|
||||
<span>Create and add another</span>
|
||||
<% end %>
|
||||
<kbd class="txt-x-small txt-subtle center"><%= hotkey_label([ "ctrl", "shift", "enter" ]) %></kbd>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<%= turbo_stream.replace([ @card, :tags ], partial: "cards/display/perma/tags", method: "morph", locals: { card: @card.reload }) %>
|
||||
@@ -5,8 +5,8 @@
|
||||
data: { controller: "form", turbo_frame: "cards_container", turbo_action: "advance" } do |form| %>
|
||||
<%= tag.div class: "flex-inline position-relative quick-filter",
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside turbo:morph@window->multi-selection-combobox#refresh",
|
||||
controller: "dialog filter multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside turbo:morph@window->multi-selection-combobox#refresh dialog:close@document->filter#clearInput",
|
||||
filter_show: user_filtering.show_boards?,
|
||||
multi_selection_combobox_no_selection_label_value: user_filtering.selected_boards_label } do %>
|
||||
<button type="button" class="btn borderless btn--plain events__filter-select" data-action="click->dialog#toggle:stop">
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
<%= tag.div class: "quick-filter",
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
controller: "dialog filter multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside dialog:close@document->filter#clearInput",
|
||||
filter_show: user_filtering.show_assignees?,
|
||||
multi_selection_combobox_no_selection_label_value: "Assigned to…",
|
||||
multi_selection_combobox_label_prefix_value: "Assigned to" } do %>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
<%= tag.div class: "quick-filter",
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
controller: "dialog filter multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside dialog:close->filter#clearInput",
|
||||
filter_show: user_filtering.show_boards?,
|
||||
multi_selection_combobox_no_selection_label_value: "Board…",
|
||||
multi_selection_combobox_label_prefix_value: "" } do %>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
<%= tag.div class: "quick-filter",
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
controller: "dialog filter multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside dialog:close@document->filter#clearInput",
|
||||
filter_show: user_filtering.show_closers?,
|
||||
multi_selection_combobox_no_selection_label_value: "Closed by…",
|
||||
multi_selection_combobox_label_prefix_value: "Closed by" } do %>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
<%= tag.div class: "quick-filter",
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
controller: "dialog filter multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside dialog:close@document->filter#clearInput",
|
||||
filter_show: user_filtering.show_creators?,
|
||||
multi_selection_combobox_no_selection_label_value: "Added by…",
|
||||
multi_selection_combobox_label_prefix_value: "Added by" } do %>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
|
||||
<%= tag.div class: class_names("quick-filter"),
|
||||
data: { controller: "dialog combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
data: { controller: "dialog filter combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside dialog:close@document->filter#clearInput",
|
||||
filter_show: user_filtering.show_indexed_by?,
|
||||
combobox_default_value_value: "all",
|
||||
combobox_default_label_value: "Status…",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
<%= tag.div class: class_names("quick-filter"),
|
||||
data: {
|
||||
controller: "dialog combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
controller: "dialog filter combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside dialog:close@document->filter#clearInput",
|
||||
filter_show: user_filtering.show_sorted_by?,
|
||||
combobox_default_value_value: "latest",
|
||||
combobox_with_default_class: "quick-filter--with-default" } do %>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
<%= tag.div class: "quick-filter",
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
controller: "dialog filter multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside dialog:close@document->filter#clearInput",
|
||||
filter_show: user_filtering.show_tags?,
|
||||
multi_selection_combobox_no_selection_label_value: "Tagged…" } do %>
|
||||
<button type="button" class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#toggle:stop">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<%= turbo_stream_from Current.user, :notifications %>
|
||||
|
||||
<section class="tray tray--notifications" data-controller="dialog badge" data-badge-unread-class="unread" data-action="turbo:render#update">
|
||||
<section class="tray tray--notifications" data-controller="dialog badge" data-badge-unread-class="unread" data-action="turbo:render#update" data-dialog-sizing-value="false">
|
||||
<dialog class="tray__dialog"
|
||||
data-controller="navigable-list"
|
||||
data-dialog-target="dialog"
|
||||
|
||||
@@ -8,20 +8,17 @@ class Cards::Comments::ReactionsControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
test "create" do
|
||||
assert_turbo_stream_broadcasts @card, count: 1 do
|
||||
assert_difference -> { @comment.reactions.count }, 1 do
|
||||
post card_comment_reactions_path(@comment.card, @comment, format: :turbo_stream), params: { reaction: { content: "Great work!" } }
|
||||
assert_redirected_to card_comment_reactions_path(@comment.card, @comment)
|
||||
end
|
||||
assert_difference -> { @comment.reactions.count }, 1 do
|
||||
post card_comment_reactions_path(@comment.card, @comment, format: :turbo_stream), params: { reaction: { content: "Great work!" } }
|
||||
assert_turbo_stream action: :replace, target: dom_id(@comment, :reacting)
|
||||
end
|
||||
end
|
||||
|
||||
test "destroy" do
|
||||
assert_turbo_stream_broadcasts @card, count: 1 do
|
||||
assert_difference -> { @comment.reactions.count }, -1 do
|
||||
delete card_comment_reaction_path(@comment.card, @comment, reactions(:kevin), format: :turbo_stream)
|
||||
assert_response :success
|
||||
end
|
||||
reaction = reactions(:kevin)
|
||||
assert_difference -> { @comment.reactions.count }, -1 do
|
||||
delete card_comment_reaction_path(@comment.card, @comment, reaction, format: :turbo_stream)
|
||||
assert_turbo_stream action: :remove, target: dom_id(reaction)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,14 +13,14 @@ class Cards::TaggingsControllerTest < ActionDispatch::IntegrationTest
|
||||
test "toggle tag on" do
|
||||
assert_changes "cards(:logo).tagged_with?(tags(:mobile))", from: false, to: true do
|
||||
post card_taggings_path(cards(:logo)), params: { tag_title: tags(:mobile).title }, as: :turbo_stream
|
||||
assert_card_container_rerendered(cards(:logo))
|
||||
assert_turbo_stream action: :replace, target: dom_id(cards(:logo), :tags)
|
||||
end
|
||||
end
|
||||
|
||||
test "toggle tag off" do
|
||||
assert_changes "cards(:logo).tagged_with?(tags(:web))", from: true, to: false do
|
||||
post card_taggings_path(cards(:logo)), params: { tag_title: tags(:web).title }, as: :turbo_stream
|
||||
assert_card_container_rerendered(cards(:logo))
|
||||
assert_turbo_stream action: :replace, target: dom_id(cards(:logo), :tags)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user