diff --git a/app/assets/stylesheets/buttons.css b/app/assets/stylesheets/buttons.css index 4ee5f199e..64ea77611 100644 --- a/app/assets/stylesheets/buttons.css +++ b/app/assets/stylesheets/buttons.css @@ -107,13 +107,22 @@ > * { grid-area: 1/1; } + + @media (max-width: 639px) { + --btn-size: 3em; + --icon-size: 70%; + } } /* Make a normal button circular on mobile */ @media (max-width: 639px) { .btn--circle-mobile { + --btn-size: 3em; + --btn-padding: 0; + --icon-size: 70%; + aspect-ratio: 1; - padding: 0.5em; + inline-size: var(--btn-size); kbd, span:last-of-type { @@ -270,4 +279,3 @@ } } } - diff --git a/app/assets/stylesheets/card-perma.css b/app/assets/stylesheets/card-perma.css index 59a80a32a..240dadb4b 100644 --- a/app/assets/stylesheets/card-perma.css +++ b/app/assets/stylesheets/card-perma.css @@ -5,6 +5,7 @@ --actions-block-inset: 1.5rem; --actions-inline-inset: 4rem; --color-container: color-mix(in srgb, var(--card-color) 33%, var(--color-canvas)); + --half-btn-height: 1.25rem; --padding-inline: calc(var(--block-space-double) + var(--block-space)); --padding-block: calc(var(--block-space-double) + var(--block-space-half)); @@ -14,7 +15,8 @@ grid-template-areas: "notch-top notch-top notch-top" "actions-left card actions-right" - "notch-bottom notch-bottom notch-bottom"; + "notch-bottom notch-bottom notch-bottom" + "closure-message closure-message closure-message"; grid-template-columns: 48px minmax(0, 1120px) 48px; inline-size: fit-content; margin-block-start: var(--block-space); @@ -47,6 +49,7 @@ .card__body { @media (max-width: 639px) { flex-direction: column; + padding-block-end: calc(var(--card-padding-block) * 1.5); } } @@ -89,15 +92,30 @@ @media (max-width: 639px) { border: 1px solid var(--card-color); border-radius: 0.25em; - overflow: hidden; + flex-direction: row; + gap: 0; + overflow: auto; max-inline-size: 100%; padding: 0; + position: relative; + white-space: nowrap; + + & > form { + flex-grow: 1; + max-inline-size: 25ch; + min-block-size: 2.5em; + } + + & > form + form:not(:has(.card__column-name--current)) { + box-shadow: -1px 0 0 0 var(--color-container); + } } } .card__column-name { @media (max-width: 639px) { --btn-border-radius: 0; + justify-content: center; } } @@ -127,13 +145,15 @@ } @media (max-width: 799px) { + --half-btn-height: 1.5rem; --padding-inline: 1.5ch; column-gap: 0; grid-template-areas: "notch-top notch-top notch-top" "card card card" - "actions-left notch-bottom actions-right"; + "actions-left notch-bottom actions-right" + "closure-message closure-message closure-message"; grid-template-columns: 1fr auto 1fr; inline-size: calc(100% + 2 * var(--padding-inline)); margin-inline: calc(-1 * var(--padding-inline)); @@ -151,7 +171,12 @@ grid-area: card; padding: clamp(2rem, 4vw, var(--padding-block)); - @media (max-width: 799px) { + @media (max-width: 639px) { + padding: clamp(0.25rem, 2vw, var(--padding-block)); + padding-block-end: clamp(2.5rem, 4vw, var(--padding-block)); + } + + @media (min-width: 640px) and (max-width: 799px) { padding-inline: var(--padding-inline); } } @@ -263,13 +288,14 @@ } .card-perma__notch--bottom { - --half-btn-height: 1.25rem; - grid-area: notch-bottom; /* Overlap the card BG by half the button height */ &:has(.btn) { - translate: 0 calc(-1 * var(--half-btn-height)); + &, + ~ .card-perma__closure-message { + translate: 0 calc(-1 * var(--half-btn-height)); + } } form { @@ -314,5 +340,8 @@ .card-perma__closure-message { color: var(--card-color); + grid-area: closure-message; + margin-block-start: 0.5ch; + padding-inline: 1ch; } } diff --git a/app/assets/stylesheets/events.css b/app/assets/stylesheets/events.css index 1dbdf0997..73e446185 100644 --- a/app/assets/stylesheets/events.css +++ b/app/assets/stylesheets/events.css @@ -225,6 +225,11 @@ padding-block: calc(var(--events-gap) * 3) var(--events-gap); position: sticky; z-index: var(--z-events-column-header); + + @media (max-width: 639px) { + margin-inline: calc(var(--main-padding) * -1); + padding-inline: var(--main-padding); + } } .events__column-footer { diff --git a/app/assets/stylesheets/header.css b/app/assets/stylesheets/header.css index c29b21518..5a3c7ee83 100644 --- a/app/assets/stylesheets/header.css +++ b/app/assets/stylesheets/header.css @@ -122,17 +122,15 @@ /* Optional class to stack header actions on small screens /* ------------------------------------------------------------------------ */ - /* .header--mobile-actions-stack { + .header--mobile-actions-stack { @media (max-width: 639px) { - grid-template-columns: 1fr 1fr; grid-template-areas: - "menu menu" - "actions-start actions-end" - "title title"; + "actions-start menu actions-end" + "title title title"; .header__title { margin-block-start: 0.25rem; } } - } */ + } } diff --git a/app/assets/stylesheets/native.css b/app/assets/stylesheets/native.css index f7b059c0c..96df0e00b 100644 --- a/app/assets/stylesheets/native.css +++ b/app/assets/stylesheets/native.css @@ -6,8 +6,40 @@ --custom-safe-inset-bottom: var(--injected-safe-inset-bottom, env(safe-area-inset-bottom, 0px)); --custom-safe-inset-left: var(--injected-safe-inset-left, env(safe-area-inset-left, 0px)); + -webkit-tap-highlight-color: transparent; + .hide-on-native { display: none; } + + /* Header + /* ------------------------------------------------------------------------ */ + + .header:is( + :not(:has(.header__title, .header__actions)), + :not(:has(.header__title, .header__actions--end)):has(.header__actions--start .btn--back:only-child) + ) { + display: none; + } + + .header__actions { + .btn--back { + display: none; + } + } + + /* Card perma + /* ------------------------------------------------------------------------ */ + + .card-perma { + margin-block-start: 0; + } + + /* Search + /* ------------------------------------------------------------------------ */ + + .search__title { + text-decoration: none; + } } } diff --git a/app/assets/stylesheets/notifications.css b/app/assets/stylesheets/notifications.css index 0cf434da8..ada7324d2 100644 --- a/app/assets/stylesheets/notifications.css +++ b/app/assets/stylesheets/notifications.css @@ -108,7 +108,7 @@ } .notifications__status { + --panel-border-radius: 0.5em; --panel-padding: var(--block-space); } } - diff --git a/app/assets/stylesheets/pins.css b/app/assets/stylesheets/pins.css new file mode 100644 index 000000000..fbecaf912 --- /dev/null +++ b/app/assets/stylesheets/pins.css @@ -0,0 +1,5 @@ +@layer components { + .pins-list { + --panel-size: 45ch; + } +} diff --git a/app/assets/stylesheets/print.css b/app/assets/stylesheets/print.css index f700b9332..5ed9c3fdf 100644 --- a/app/assets/stylesheets/print.css +++ b/app/assets/stylesheets/print.css @@ -7,6 +7,7 @@ --color-canvas: white; --border-dark: 1px solid var(--color-ink); --border-light: 1px solid color-mix(in oklch, var(--color-ink), transparent 75%); + --font-sans: "Adwaita Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Hiragino Sans GB", "Hiragino Sans", "Apple SD Gothic Neo", "Microsoft YaHei", "Meiryo", "Malgun Gothic"; } @page { diff --git a/app/assets/stylesheets/search.css b/app/assets/stylesheets/search.css index 96368841e..fcd4563ca 100644 --- a/app/assets/stylesheets/search.css +++ b/app/assets/stylesheets/search.css @@ -26,7 +26,7 @@ summary { max-block-size: 100%; overflow-y: auto; overscroll-behavior: contain; - padding: var(--block-space) calc(var(--block-space-double) + var(--btn-size)); + padding: var(--block-space); } /* Form @@ -34,18 +34,22 @@ summary { .search__input { --clear-icon-size: 1em; - --focus-ring-size: 0; - --input-border-color: var(--color-ink-light); - --input-border-radius: 0; - --input-padding: 0.1em; - border-width: 0 0 1px; max-inline-size: 50ch; position: relative; &::-webkit-search-cancel-button { display: none; } + + .bar__input & { + --focus-ring-size: 0; + --input-border-color: var(--color-ink-light); + --input-border-radius: 0; + --input-padding: 0.1em; + + border-width: 0 0 1px; + } } .search__reset { @@ -107,4 +111,22 @@ summary { .search__title { text-decoration: underline; } + + /* Perma + /* ------------------------------------------------------------------------ */ + + .search-perma { + .search__form > label, + .search__reset { + display: none; + } + + .search__input { + max-inline-size: min(80ch, 100%); + } + + .search { + padding-inline: 0; + } + } } diff --git a/app/assets/stylesheets/trays.css b/app/assets/stylesheets/trays.css index 7cc90f92d..7793b6f2d 100644 --- a/app/assets/stylesheets/trays.css +++ b/app/assets/stylesheets/trays.css @@ -156,11 +156,11 @@ --tray-item-scale: calc(1 - (var(--tray-item-index) - 1) / 30); --tray-item-z: calc(6 - var(--tray-item-index)); + font-size: 10px; + margin-block-end: var(--tray-item-margin); position: relative; .tray__dialog & { - font-size: 10px; - margin-block-end: var(--tray-item-margin); transition: var(--tray-duration) var(--ease-out-overshoot-subtle); transition-delay: var(--tray-item-delay); transition-property: margin, opacity, scale; @@ -285,7 +285,7 @@ /* Tray cards /* ------------------------------------------------------------------------ */ - .tray { + .tray__item { .card { --card-padding-block: 1.5ch; --card-padding-inline: 1.5ch; @@ -345,52 +345,69 @@ inset-inline-start: -100%; } - .tray__item { - --tray-item-z: calc(10 - var(--tray-item-index)); + /* Disable the expander if there aren't items to show */ + .tray__dialog:not(:has(.tray__item)) ~ .tray__toggle { + opacity: 0.5; - position: relative; - - [open] &[aria-selected] { - outline: 0; - z-index: calc(var(--tray-item-z) + 2); - - .card__link { - border-radius: 0.25ch; - outline: var(--focus-ring-size) solid var(--focus-ring-color); - outline-offset: var(--focus-ring-offset); - z-index: 1; - } + &, .tray__toggle-btn { + pointer-events: none; } + } - /* Show 6 max items on smallest devices */ - @media (max-height: 578px) { - &:nth-child(1n + 7) { display: none; } + /* Add a border on mobile */ + @media (max-width: 799px) { + .tray__dialog:not([open]) ~ .tray__toggle { + border-inline-end: 1px dashed var(--color-ink-light); + translate: calc(-1 * var(--tray-margin)) 0; } + } + } - /* 7 max */ - @media (min-height: 578px) and (max-height: 656px) { - &:nth-child(1n + 8) { display: none; } - } + .tray__item--pin { + --tray-item-z: calc(10 - var(--tray-item-index)); - /* 8 max */ - @media (min-height: 656px) and (max-height: 734px) { - &:nth-child(1n + 9) { display: none; } - } + position: relative; - /* 9 max */ - @media (min-height: 734px) and (max-height: 812px) { - &:nth-child(1n + 10) { display: none; } - } + [open] &[aria-selected] { + outline: 0; + z-index: calc(var(--tray-item-z) + 2); - /* 10 max on larger screens */ - @media (min-height: 812px) { - &:nth-child(1n + 11) { display: none; } + .card__link { + border-radius: 0.25ch; + outline: var(--focus-ring-size) solid var(--focus-ring-color); + outline-offset: var(--focus-ring-offset); + z-index: 1; } + } - &:not([aria-selected]) .card__link:focus-visible, - .tray__dialog:not([open]) & .card__link:focus-visible { - --focus-ring-size: 0; - } + /* Show 6 max items on smallest devices */ + @media (max-height: 578px) { + &:nth-child(1n + 7) { display: none; } + } + + /* 7 max */ + @media (min-height: 578px) and (max-height: 656px) { + &:nth-child(1n + 8) { display: none; } + } + + /* 8 max */ + @media (min-height: 656px) and (max-height: 734px) { + &:nth-child(1n + 9) { display: none; } + } + + /* 9 max */ + @media (min-height: 734px) and (max-height: 812px) { + &:nth-child(1n + 10) { display: none; } + } + + /* 10 max on larger screens */ + @media (min-height: 812px) { + &:nth-child(1n + 11) { display: none; } + } + + &:not([aria-selected]) .card__link:focus-visible, + .tray__dialog:not([open]) & .card__link:focus-visible { + --focus-ring-size: 0; } .tray__remove-pin-btn { @@ -399,18 +416,17 @@ background-color: var(--card-bg-color); inset: 0 0 auto auto; - opacity: 0; - pointer-events: none; + opacity: 0.66; position: absolute; z-index: 1; - .tray__dialog[open] & { - opacity: 0.66; - pointer-events: unset; + &:hover { + opacity: 1; + } - &:hover { - opacity: 1; - } + .tray__dialog:not([open]) & { + opacity: 0; + pointer-events: none; } [aria-busy] & { @@ -451,9 +467,10 @@ inline-size: fit-content; margin: 0 0 0 auto; transition: translate 150ms ease-out; + translate: -2em; - [open] & { - translate: -2em; + .tray__dialog:not([open]) & { + translate: 0; } } @@ -491,24 +508,6 @@ .card__bubble { display: none; } - - /* Disable the expander if there aren't items to show */ - .tray__dialog:not(:has(.tray__item)) ~ .tray__toggle { - opacity: 0.5; - - &, .tray__toggle-btn { - pointer-events: none; - } - } - - /* Add a border on mobile */ - @media (max-width: 799px) { - .tray__dialog:not([open]) ~ .tray__toggle { - border-inline-end: 1px dashed var(--color-ink-light); - translate: calc(-1 * var(--tray-margin)) 0; - } - - } } ::view-transition-group(tray-pins) { diff --git a/app/controllers/cards/engagements_controller.rb b/app/controllers/cards/engagements_controller.rb deleted file mode 100644 index 73b8e9c9d..000000000 --- a/app/controllers/cards/engagements_controller.rb +++ /dev/null @@ -1,18 +0,0 @@ -class Cards::EngagementsController < ApplicationController - include CardScoped - - def create - case params[:engagement] - when "doing" - @card.engage - when "on_deck" - @card.move_to_on_deck - end - render_card_replacement - end - - def destroy - @card.reconsider - render_card_replacement - end -end diff --git a/app/controllers/cards_controller.rb b/app/controllers/cards_controller.rb index daf22a5bc..e79eeb22b 100644 --- a/app/controllers/cards_controller.rb +++ b/app/controllers/cards_controller.rb @@ -12,7 +12,7 @@ class CardsController < ApplicationController def create respond_to do |format| format.html do - card = @board.cards.find_or_create_by!(creator: Current.user, status: "drafted") + card = Current.user.draft_new_card_in(@board) redirect_to card end diff --git a/app/controllers/users/roles_controller.rb b/app/controllers/users/roles_controller.rb index b881bdcfc..711308d13 100644 --- a/app/controllers/users/roles_controller.rb +++ b/app/controllers/users/roles_controller.rb @@ -4,7 +4,7 @@ class Users::RolesController < ApplicationController def update @user.update!(role_params) - redirect_to users_path + redirect_to account_settings_path end private diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 74deb686b..54c18704c 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -30,7 +30,7 @@ class UsersController < ApplicationController @user.deactivate respond_to do |format| - format.html { redirect_to users_path } + format.html { redirect_to account_settings_path } format.json { head :no_content } end end diff --git a/app/helpers/columns_helper.rb b/app/helpers/columns_helper.rb index 6b9459c52..a92fb2824 100644 --- a/app/helpers/columns_helper.rb +++ b/app/helpers/columns_helper.rb @@ -6,8 +6,8 @@ module ColumnsHelper method: :post, class: [ "card__column-name btn", { "card__column-name--current": column == card.column && card.open? } ], style: "--column-color: #{column.color}", - form_class: "flex align-center gap-half", - data: { turbo_frame: "_top" } + form_class: "flex gap-half", + data: { turbo_frame: "_top", scroll_to_target: column == card.column && card.open? ? "target" : nil } end def column_tag(id:, name:, drop_url:, collapsed: true, selected: nil, card_color: "var(--color-card-default)", data: {}, **properties, &block) diff --git a/app/javascript/controllers/bar_controller.js b/app/javascript/controllers/bar_controller.js index 5e72e4e07..e83bce9a9 100644 --- a/app/javascript/controllers/bar_controller.js +++ b/app/javascript/controllers/bar_controller.js @@ -34,6 +34,7 @@ export default class extends Controller { showModalAndSubmit(event) { this.showModal() this.formTarget.requestSubmit() + this.#restoreFocusAfterTurboFrameLoads() } showModal() { @@ -51,6 +52,12 @@ export default class extends Controller { } } + #restoreFocusAfterTurboFrameLoads() { + this.turboFrameTarget.addEventListener("turbo:frame-load", () => { + this.searchInputTarget.focus() + }, { once: true }) + } + #loadTurboFrame() { this.turboFrameTarget.src = this.searchUrlValue } diff --git a/app/javascript/controllers/navigable_list_controller.js b/app/javascript/controllers/navigable_list_controller.js index b9eba66ee..0be9bd170 100644 --- a/app/javascript/controllers/navigable_list_controller.js +++ b/app/javascript/controllers/navigable_list_controller.js @@ -1,5 +1,6 @@ import { Controller } from "@hotwired/stimulus" import { nextFrame } from "helpers/timing_helpers" +import { isMobile } from "helpers/platform_helpers" export default class extends Controller { static targets = [ "item", "input" ] @@ -18,6 +19,11 @@ export default class extends Controller { onlyActOnFocusedItems: { type: Boolean, default: false } } + // Don't load for mobile devices + static get shouldLoad() { + return !isMobile() + } + connect() { if (this.autoSelectValue) { this.reset() diff --git a/app/javascript/controllers/scroll_to_controller.js b/app/javascript/controllers/scroll_to_controller.js new file mode 100644 index 000000000..aad761fd8 --- /dev/null +++ b/app/javascript/controllers/scroll_to_controller.js @@ -0,0 +1,19 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "target" ] + + connect() { + this.#scrollTargetIntoView() + } + + #scrollTargetIntoView() { + if(this.hasTargetTarget) { + this.element.scrollTo({ + top: this.targetTarget.offsetTop - this.element.offsetHeight / 2 + this.targetTarget.offsetHeight / 2, + left: this.targetTarget.offsetLeft - this.element.offsetWidth / 2 + this.targetTarget.offsetWidth / 2, + behavior: "instant" + }) + } + } +} diff --git a/app/javascript/controllers/soft_keyboard_controller.js b/app/javascript/controllers/soft_keyboard_controller.js index 75fb4f2ee..25dc15bf7 100644 --- a/app/javascript/controllers/soft_keyboard_controller.js +++ b/app/javascript/controllers/soft_keyboard_controller.js @@ -1,10 +1,11 @@ import { Controller } from "@hotwired/stimulus" import { nextEventNamed } from "helpers/timing_helpers" +import { isTouchDevice } from "helpers/platform_helpers" export default class extends Controller { // Only load for touch devices static get shouldLoad() { - return "ontouchstart" in window && navigator.maxTouchPoints > 0 + return isTouchDevice() } // Use a fake input to trigger the soft keyboard on actions that load async content diff --git a/app/javascript/helpers/platform_helpers.js b/app/javascript/helpers/platform_helpers.js new file mode 100644 index 000000000..636e4b968 --- /dev/null +++ b/app/javascript/helpers/platform_helpers.js @@ -0,0 +1,15 @@ +export function isTouchDevice() { + return "ontouchstart" in window && navigator.maxTouchPoints > 0 +} + +export function isIos() { + return /iPhone|iPad/.test(navigator.userAgent) +} + +export function isAndroid() { + return /Android/.test(navigator.userAgent) +} + +export function isMobile() { + return isIos() || isAndroid() +} diff --git a/app/models/card/closeable.rb b/app/models/card/closeable.rb index e4cea509f..ff947452b 100644 --- a/app/models/card/closeable.rb +++ b/app/models/card/closeable.rb @@ -31,6 +31,7 @@ module Card::Closeable def close(user: Current.user) unless closed? transaction do + not_now&.destroy create_closure! user: user track_event :closed, creator: user end diff --git a/app/models/card/engagement.rb b/app/models/card/engagement.rb deleted file mode 100644 index 2f45543dc..000000000 --- a/app/models/card/engagement.rb +++ /dev/null @@ -1,6 +0,0 @@ -class Card::Engagement < ApplicationRecord - belongs_to :account, default: -> { card.account } - belongs_to :card, class_name: "::Card", touch: true - - validates :status, presence: true, inclusion: { in: %w[doing on_deck] } -end diff --git a/app/models/event/description.rb b/app/models/event/description.rb index f44233011..fd7a66ae1 100644 --- a/app/models/event/description.rb +++ b/app/models/event/description.rb @@ -14,7 +14,7 @@ class Event::Description end def to_plain_text - to_sentence(creator_name, h(card.title)) + to_sentence(creator_name, quoted(card.title)) end private @@ -41,6 +41,10 @@ class Event::Description h(event.creator.name) end + def quoted(text) + %("#{h text}") + end + def card @card ||= event.action.comment_created? ? event.eventable.card : event.eventable end diff --git a/app/models/user/accessor.rb b/app/models/user/accessor.rb index e8a24830f..d383f8929 100644 --- a/app/models/user/accessor.rb +++ b/app/models/user/accessor.rb @@ -11,6 +11,12 @@ module User::Accessor after_create_commit :grant_access_to_boards, unless: :system? end + def draft_new_card_in(board) + board.cards.find_or_initialize_by(creator: self, status: "drafted").tap do |card| + card.update!(created_at: Time.current, updated_at: Time.current, last_active_at: Time.current) + end + end + private def grant_access_to_boards Access.insert_all account.boards.all_access.ids.collect { |board_id| { id: ActiveRecord::Type::Uuid.generate, board_id: board_id, user_id: id, account_id: account.id } } diff --git a/app/models/webhook/delivery.rb b/app/models/webhook/delivery.rb index 3ebe49b06..50a0cd560 100644 --- a/app/models/webhook/delivery.rb +++ b/app/models/webhook/delivery.rb @@ -1,4 +1,6 @@ class Webhook::Delivery < ApplicationRecord + include Rails.application.routes.url_helpers + class ResponseTooLarge < StandardError; end STALE_TRESHOLD = 7.days @@ -130,8 +132,7 @@ class Webhook::Delivery < ApplicationRecord elsif webhook.for_campfire? render_payload(formats: :html) elsif webhook.for_slack? - html = render_payload(formats: :html) - { text: convert_html_to_mrkdwn(html) }.to_json + slack_payload else render_payload(formats: :json) end @@ -158,4 +159,16 @@ class Webhook::Delivery < ApplicationRecord document.text end + + def slack_payload + text = event.description_for(nil).to_plain_text + url = polymorphic_url(event.eventable, base_url_options.merge(script_name: account.slug)) + + { text: "#{text} <#{url}|Open in Fizzy>" }.to_json + end + + def base_url_options + Rails.application.routes.default_url_options.presence || + Rails.application.config.action_mailer.default_url_options + end end diff --git a/app/views/bar/_bar.html.erb b/app/views/bar/_bar.html.erb index 6d2014e12..3eb449598 100644 --- a/app/views/bar/_bar.html.erb +++ b/app/views/bar/_bar.html.erb @@ -8,7 +8,7 @@
<%= tag.dialog id: "bar-modal", class: "bar__modal", data: { diff --git a/app/views/cards/_card.json.jbuilder b/app/views/cards/_card.json.jbuilder index e5792f127..75d3ebcf2 100644 --- a/app/views/cards/_card.json.jbuilder +++ b/app/views/cards/_card.json.jbuilder @@ -16,6 +16,8 @@ json.cache! card do json.board card.board, partial: "boards/board", as: :board json.column card.column, partial: "columns/column", as: :column if card.column json.creator card.creator, partial: "users/user", as: :user + json.assignees card.assignees.limit(5), partial: "users/user", as: :user + json.has_more_assignees card.assignees.size > 5 json.comments_url card_comments_url(card) end diff --git a/app/views/cards/columns/edit.html.erb b/app/views/cards/columns/edit.html.erb index a2ad2c819..586fac20f 100644 --- a/app/views/cards/columns/edit.html.erb +++ b/app/views/cards/columns/edit.html.erb @@ -1,5 +1,5 @@ <%= turbo_frame_tag @card, :columns do %> -