diff --git a/app/assets/stylesheets/card-columns.css b/app/assets/stylesheets/card-columns.css index a74e8e3f8..7800826bf 100644 --- a/app/assets/stylesheets/card-columns.css +++ b/app/assets/stylesheets/card-columns.css @@ -63,20 +63,9 @@ .cards { --column-color: color-mix(in srgb, var(--card-color) 15%, var(--color-canvas)); - border-radius: calc(var(--column-width-collapsed) / 2); inline-size: var(--column-width-expanded); position: relative; scroll-snap-align: start; - translate: 0; - transition: translate var(--column-transition-duration) var(--ease-out-overshoot-subtle); - - .no-transitions & { - transition: none; - } - - &:not(.is-collapsed) { - padding-inline: var(--column-padding-expanded); - } &.is-collapsed { inline-size: var(--column-width-collapsed); @@ -85,12 +74,41 @@ .card { display: none; } + } - &:not(.cards--considering) { - translate: 0 var(--column-width-collapsed); + &.drag-and-drop__hover-container { + --dnd-bg-color: transparent; + --dnd-border-color: transparent; + + &.is-off-screen { + &:after { + content: attr(data-column-name); + font-size: var(--text-x-small); + font-weight: 500; + line-height: var(--column-width-collapsed); + padding-inline: 1ch; + position: fixed; + text-transform: uppercase; + top: 0; + translate: -50%; + } + + &.is-collapsed { + &:after { + writing-mode: vertical-rl; + } + } + + &:not(.is-collapsed) { + &:after { + background-color: var(--column-color); + inline-size: calc(var(--column-width-expanded) - 4px); /* make room for the dnd border */ + } + } } } + @media (any-hover: hover) { .card:has(.card__background img:not([src=""])):hover .card__background img:not([src=""]) { filter: blur(3px) brightness(1.2); @@ -99,6 +117,42 @@ } } + .cards__transition-container { + block-size: 100%; + border-radius: calc(var(--column-width-collapsed) / 2); + translate: 0; + transition: translate var(--column-transition-duration) var(--ease-out-overshoot-subtle); + + .is-collapsed:not(.cards--considering) & { + translate: 0 var(--column-width-collapsed); + } + + .cards:not(.is-collapsed) & { + padding-inline: var(--column-padding-expanded); + } + + .drag-and-drop__hover-container & { + --dnd-bg-color: var(--column-color); + --dnd-border-color: var(--card-color); + + background-color: var(--dnd-bg-color); + outline: 2px dashed var(--dnd-border-color); + outline-offset: -2px; + transition: background-color 200ms; + z-index: 1; + } + + .no-transitions & { + transition: none; + } + } + + .cards__header { + .cards.is-collapsed & { + block-size: 100%; + } + } + /* The wrapper around the cards used to clip overflow while transitioning. * Also, don't resize cards while transitioning to avoid reflow. */ .cards__list { @@ -473,11 +527,9 @@ /* ------------------------------------------------------------------------ */ .cards--considering { - position: relative; + --card-color: oklch(var(--lch-blue-medium)); - @media (min-width: 640px) { - padding-inline: var(--cards-gap); - } + position: relative; .card { --avatar-size: 2.75em; diff --git a/app/assets/stylesheets/drag_and_drop.css b/app/assets/stylesheets/drag_and_drop.css index 99b3089eb..2ada036b4 100644 --- a/app/assets/stylesheets/drag_and_drop.css +++ b/app/assets/stylesheets/drag_and_drop.css @@ -7,8 +7,11 @@ } .drag-and-drop__hover-container { - background-color: var(--color-selected-light); - outline: 2px dashed var(--color-selected-dark); + --dnd-bg-color: var(--color-selected-light); + --dnd-border-color: var(--color-selected-dark); + + background-color: var(--dnd-bg-color); + outline: 2px dashed var(--dnd-border-color); outline-offset: -2px; transition: background-color 200ms; z-index: 1; diff --git a/app/javascript/controllers/collapsible_columns_controller.js b/app/javascript/controllers/collapsible_columns_controller.js index 74dd1ff65..b11821f3f 100644 --- a/app/javascript/controllers/collapsible_columns_controller.js +++ b/app/javascript/controllers/collapsible_columns_controller.js @@ -2,8 +2,8 @@ import { Controller } from "@hotwired/stimulus" import { nextFrame, debounce } from "helpers/timing_helpers"; export default class extends Controller { - static classes = [ "collapsed", "noTransitions" ] - static targets = [ "column", "button" ] + static classes = [ "collapsed", "noTransitions", "titleNotVisible" ] + static targets = [ "column", "button", "title" ] static values = { board: String } @@ -14,6 +14,14 @@ export default class extends Controller { async connect() { await this.#restoreColumnsDisablingTransitions() + this.#setupIntersectionObserver() + } + + disconnect() { + if (this._intersectionObserver) { + this._intersectionObserver.disconnect() + this._intersectionObserver = null + } } toggle({ target }) { @@ -106,4 +114,23 @@ export default class extends Controller { #localStorageKeyFor(column) { return `expand-${this.boardValue}-${column.getAttribute("id")}` } + + #setupIntersectionObserver() { + if (typeof IntersectionObserver === "undefined") return + if (this._intersectionObserver) this._intersectionObserver.disconnect() + + this._intersectionObserver = new IntersectionObserver(entries => { + entries.forEach(entry => { + const title = entry.target + const column = title.closest(".cards") + + if (!column) return + + const offscreen = entry.intersectionRatio === 0 + column.classList.toggle(this.titleNotVisibleClass, offscreen) + }) + }, { threshold: [0] }) + + this.titleTargets.forEach(title => this._intersectionObserver.observe(title)) + } } diff --git a/app/views/boards/show/_closed.html.erb b/app/views/boards/show/_closed.html.erb index 0b1d8c863..180832660 100644 --- a/app/views/boards/show/_closed.html.erb +++ b/app/views/boards/show/_closed.html.erb @@ -2,13 +2,16 @@ data-drag-and-drop-target="container" data-drag-and-strum-target="container" data-collapsible-columns-target="column" + data-column-name="Done" data-action="turbo:before-morph-attribute->collapsible-columns#preventToggle" data-drag-and-drop-url="<%= columns_card_drops_closure_path("__id__") %>" > - - <%= render "boards/show/expander", title: "Done", count: board.cards.closed.count, column_id: "closed-cards" do %> - <%= render "boards/show/menu/expand", column_path: board_columns_closed_path(board) %> - <% end %> - - <%= column_frame_tag :closed_column, src: board_columns_closed_path(board) %> +