Merge pull request #379 from basecamp/btn-dropdown

Btn dropdown
This commit is contained in:
Andy Smith
2025-04-09 14:23:52 -05:00
committed by GitHub
9 changed files with 139 additions and 23 deletions
+1
View File
@@ -0,0 +1 @@
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M4 8l8 8 8-8" stroke="#000" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>

After

Width:  |  Height:  |  Size: 183 B

+1
View File
@@ -21,6 +21,7 @@
background: var(--color-bg);
color: var(--color-ink);
font-family: var(--font-sans);
interpolate-size: allow-keywords;
line-height: 1.375;
overflow: unset;
scroll-behavior: auto;
+1
View File
@@ -193,3 +193,4 @@
}
}
}
+1 -1
View File
@@ -121,7 +121,7 @@
position: relative;
z-index: 0;
&:has(dialog[open]) {
&:has([open]) {
z-index: 1;
}
+112
View File
@@ -0,0 +1,112 @@
/* https://nerdy.dev/open-and-close-transitions-for-the-details-element */
.expander {
--expander-height: calc(1em + 1lh);
--expander-width: 11ch;
--expander-radius: calc(var(--expander-height) / 2);
--expander-duration: 150ms;
interpolate-size: allow-keywords;
position: relative;
z-index: 1;
}
.expander__button {
--btn-border-radius: var(--expander-radius);
align-items: center;
block-size: var(--expander-height);
cursor: pointer;
display: flex;
inline-size: var(--expander-width);
justify-content: flex-start;
padding-inline: 1.5ch;
position: relative;
white-space: nowrap;
z-index: 1;
&::-webkit-details-marker {
display: none;
}
[open] & {
box-shadow: none;
}
.icon {
font-size: 1ch;
}
}
.expander__content {
--btn-border-radius: var(--expander-radius);
align-items: stretch;
border-radius: var(--expander-radius);
flex-direction: column;
gap: 0;
padding-block-start: var(--expander-height);
&:hover {
box-shadow: none;
}
}
/* For browsers that support animation */
@supports selector(details::details-content) {
.expander::details-content {
--btn-border-radius: var(--expander-radius);
block-size: var(--expander-height);
border-radius: var(--expander-radius);
inset: 0 auto auto 0;
inline-size: var(--expander-width);
overflow: clip;
position: absolute;
transition: content-visibility var(--expander-duration) allow-discrete, block-size var(--expander-duration), inline-size var(--expander-duration);
}
.expander[open]::details-content {
block-size: auto;
inline-size: auto;
}
.expander__content {
min-inline-size: var(--expander-width);
}
}
/* Fallback for browsers that don't support animation */
@supports not selector(details::details-content) {
.expander__content {
border-radius: var(--expander-radius);
inset: 0 auto auto 0;
min-inline-size: var(--expander-width);
position: absolute;
[open] & {
block-size: auto;
inline-size: auto;
}
}
}
.expander__item {
--btn-background: transparent;
--btn-border-radius: 0.3em;
--btn-border-size: 0;
--btn-font-weight: 500;
--btn-padding: var(--inline-space-half) var(--inline-space);
--hover-size: 0;
--outline-color: transparent;
inline-size: calc(100% + var(--inline-space-double));
margin-inline-start: calc(-1 * var(--inline-space));
justify-content: flex-start;
white-space: nowrap;
&:hover,
&:focus-visible {
background-color: oklch(var(--lch-white) / 15%);
}
}
+1
View File
@@ -35,6 +35,7 @@
.icon--calendar-add { --svg: url("calendar-add.svg "); }
.icon--calendar { --svg: url("calendar.svg "); }
.icon--camera { --svg: url("camera.svg "); }
.icon--caret-down { --svg: url("caret-down.svg "); }
.icon--chart { --svg: url("chart.svg "); }
.icon--check { --svg: url("check.svg "); }
.icon--close { --svg: url("close.svg "); }
@@ -0,0 +1,13 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = [ "details" ]
close() {
this.detailsTarget.removeAttribute("open")
}
closeOnClickOutside({ target }) {
if (!this.element.contains(target)) this.close()
}
}
@@ -1,9 +0,0 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
closeOnFocusOutside(event) {
if (!this.element.contains(event.relatedTarget)) {
this.element.removeAttribute("open")
}
}
}
+9 -13
View File
@@ -5,23 +5,19 @@
<span>Un-do</span>
<% end %>
<% else %>
<div class="flex-inline center position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<button class="btn borderless" data-action="click->dialog#open:stop">
<span>Close as…</span>
</button>
<dialog class="popup panel flex-column align-start gap-half fill-white shadow" style="--row-gap: 0.2em;"
aria-label="Close as…" aria-description="Close this card and select a reason.."
data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
<strong class="popup__title margin-block-start-half pad-inline-half">Close as…</strong>
<details class="expander" data-controller="details" data-details-target="details" data-action="keydown.esc->details#close click@document->details#closeOnClickOutside">
<summary class="expander__button btn borderless">
Close as
<%= icon_tag "caret-down" %>
</summary>
<div class="expander__content btn borderless">
<% Current.account.closure_reasons.labels.each do |label| %>
<%= button_to card_closure_path(card, reason: label), class: "btn popup__item full-width", form_class: "full-width" do %>
<%= button_to card_closure_path(card, reason: label), class: "expander__item btn" do %>
<span class="overflow-ellipsis"><%= label %></span>
<% end %>
<% end %>
</dialog>
</div>
</div>
</details>
<span class="card__closure-message">
<% if card.doing? %>