Files
fizzy/app/assets/stylesheets/trays.css
T

578 lines
13 KiB
CSS

@layer components {
/* Container
/* ------------------------------------------------------------------------ */
.tray {
--tray-duration: 350ms;
--tray-margin: 0.5rem;
--tray-radius: 0.25rem;
--tray-item-height: 76px; /* FIXME: Magic number */
align-items: end;
block-size: var(--footer-height);
display: grid;
inset-block: auto env(safe-area-inset-bottom);
inline-size: var(--tray-size);
position: fixed;
transition: inset var(--tray-duration) var(--ease-out-overshoot-subtle);
z-index: var(--z-tray);
/* Make the dialog, expander, and actions inhabit the same space */
> * {
grid-column-start: 1;
grid-row-start: 1;
}
@media (max-width: 799px) {
&:has(.tray__dialog[open]) {
background-color: var(--color-terminal-bg);
inline-size: calc(100% - var(--tray-margin) * 2);
inset-inline-start: var(--tray-margin);
z-index: calc(var(--z-tray) + 2);
}
}
}
/* Dialog
/* ------------------------------------------------------------------------ */
.tray__dialog {
background-color: transparent;
display: flex;
flex-direction: column-reverse;
inline-size: auto;
inset: auto 0 0 0;
position: absolute;
transition: var(--tray-duration) var(--ease-out-overshoot-subtle);
transition-property: background-color, box-shadow, inset-block-end;
&[open] {
border-radius: var(--tray-radius);
box-shadow:
0 0 0 1px var(--color-ink-lighter),
0 0 16px oklch(var(--lch-black) / 33%);
inset-block-end: calc(var(--footer-height) - 0.75ch);
}
&:not([open]) {
block-size: var(--footer-height);
pointer-events: none;
/* On desktop, when there aren't items, tweak the hat so it doesn't look
like it's coming from the bottom of the viewport */
@media (min-width: 800px) {
&:not(:has(.tray__item--notification)) {
.tray__item--hat {
margin-block-end: 0;
opacity: 0;
}
}
}
}
}
/* Expander
/* ------------------------------------------------------------------------ */
.tray__toggle {
align-self: stretch;
background: none;
border: 0;
display: block;
padding: 0;
transition: opacity 100ms ease-out;
.icon {
color: var(--color-ink);
display: none;
}
.tray__toggle-text {
display: contents;
}
@media (max-width: 799px) {
/* When collapsed on mobile, make it small */
.tray__dialog:not([open]) ~ & {
inline-size: var(--footer-height);
.tray__toggle-btn {
border: 0;
}
.icon {
display: block;
}
.tray__toggle-text {
display: none;
}
}
/* Show a red dot if there are items to show */
.tray__dialog:not([open]):has(.tray__item--notification) ~ &:after {
background: oklch(var(--lch-red-medium));
block-size: 1ch;
border-radius: 50%;
content: "";
inline-size: 1ch;
inset: 25% 25% auto auto;
position: absolute;
}
}
/* On desktop… */
@media (min-width: 800px) {
.tray__dialog:not([open]):has(.tray__item:not(.tray__item--hat)) ~ & {
block-size: var(--tray-item-height);
translate: 0 -1.85rem;
}
/* Hide the UI when collapsed, but only if there are items */
.tray__dialog:not([open]):has(.tray__item--notification) ~ & {
opacity: 0;
}
}
}
.tray__toggle-btn {
--btn-background: transparent;
--btn-border-size: 0;
--btn-color: var(--color-ink);
inline-size: 100%;
opacity: 0.66;
}
/* Item
/* ------------------------------------------------------------------------ */
.tray__item {
--tray-item-delay: calc((var(--tray-item-index) - 1) * 20ms);
--tray-item-index: 1;
--tray-item-margin: calc(-1 * var(--tray-item-height) + var(--tray-item-offset));
--tray-item-offset: var(--block-space-half); /* The amount they overlap */
--tray-item-scale: calc(1 - (var(--tray-item-index) - 1) / 30);
--tray-item-z: calc(6 - var(--tray-item-index));
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;
&:not(.tray__item--hat) {
z-index: var(--tray-item-z);
}
&:has(*:focus-visible) {
z-index: calc(var(--tray-item-z) + 1);
}
&:first-child {
--tray-item-margin: var(--tray-margin);
}
&:not(:first-child) {
scale: var(--tray-item-scale);
}
&:nth-child(1) { --tray-item-index: 1; }
&:nth-child(2) { --tray-item-index: 2; }
&:nth-child(3) { --tray-item-index: 3; }
&:nth-child(4) { --tray-item-index: 4; }
&:nth-child(5) { --tray-item-index: 5; }
&:nth-child(6) { --tray-item-index: 6; }
&:nth-child(7) { --tray-item-index: 7; }
&:nth-child(8) { --tray-item-index: 8; }
&:nth-child(9) { --tray-item-index: 9; }
&:nth-child(10) { --tray-item-index: 10; }
}
.tray__dialog[open] & {
--tray-item-margin: 0;
--tray-item-scale: 1;
}
.tray__dialog:not([open]) & {
@media (max-width: 799px) {
opacity: 0;
}
}
.bubble {
display: none;
}
}
.tray__item--hat {
--tray-hat-bg: var(--color-canvas);
--tray-item-scale: 1;
background-color: var(--tray-hat-bg);
border-block-end: 1px solid var(--color-ink-lighter);
border-radius: var(--tray-radius) var(--tray-radius) 0 0;
block-size: var(--tray-item-height);
display: flex;
opacity: 0;
padding: 0.5ch;
.btn {
--btn-background: var(--tray-hat-bg);
--btn-border-radius: 0.5ch;
--btn-padding: 1.25ch 0.5ch 1ch;
block-size: 100%;
display: flex;
flex-direction: column;
font-weight: normal;
gap: 0.25ch;
inline-size: 100%;
&:focus-visible {
z-index: 1;
}
@media (max-width: 1060px) {
> span:not(.icon) {
font-size: 12px;
}
}
.tray__dialog:not([open]) & {
pointer-events: none;
}
}
> *:is(:first-child, :last-child) {
inline-size: 128px;
}
.tray__dialog[open] & {
opacity: 1;
}
.tray__new-notifications {
display: none;
position: relative;
}
.tray__dialog:has(.tray__item:nth-child(1n + 7)) & {
.tray__old-notifications { display: none; }
.tray__new-notifications { display: flex; }
.btn:has(.tray__new-notifications) { /* Red dot */
&:after {
background-color: oklch(var(--lch-red-medium));
block-size: 1ch;
border-radius: 50%;
box-shadow: 0 0 0 1px var(--tray-hat-bg);
content: "";
inline-size: 1ch;
inset: 25% auto auto 50%;
position: absolute;
translate: 25% -75%;
}
}
}
}
/* Tray cards
/* ------------------------------------------------------------------------ */
.tray {
.card {
--card-padding-block: 1.5ch;
--card-padding-inline: 1.5ch;
--text-xx-large: 2em;
block-size: var(--tray-item-height);
view-transition-name: unset !important;
[open] & {
box-shadow: 0 0 0 1px var(--color-ink-lighter);
border: 0;
border-radius: 0;
}
html[data-theme="dark"] & {
box-shadow: 0 0 0 1px var(--color-ink-lighter);
}
@media (prefers-color-scheme: dark) {
html:not([data-theme]) & {
box-shadow: 0 0 0 1px var(--color-ink-lighter);
}
}
}
.card__background {
display: none;
}
.card__body {
margin-block-start: 0.2em;
padding-block-end: 0;
}
.card__board {
padding-block: 0.25ch;
}
.card__title {
--lines: 1;
font-size: var(--text-small);
font-weight: bold;
min-block-size: 0;
}
}
/* Pin-specific styles
/* ------------------------------------------------------------------------ */
.tray--pins {
inset-inline: var(--tray-margin) auto;
view-transition-name: tray-pins;
#footer:has(.bar__placeholder[hidden]) & {
inset-inline-start: -100%;
}
.tray__item {
--tray-item-z: calc(10 - var(--tray-item-index));
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;
}
}
/* 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 {
--btn-icon-size: 1.25em;
--btn-size: 2em;
background-color: var(--card-bg-color);
inset: 0 0 auto auto;
opacity: 0;
pointer-events: none;
position: absolute;
z-index: 1;
.tray__dialog[open] & {
opacity: 0.66;
pointer-events: unset;
&:hover {
opacity: 1;
}
}
[aria-busy] & {
position: absolute !important;
}
}
.avatar,
.card__tags,
.card__meta .btn,
.card__meta-text:not(.card__meta-text--updated),
.card__stages,
.card__steps,
.card__closed {
display: none;
}
.card__header {
margin-block-start: calc(var(--card-padding-block) * -1.1);
margin-inline: calc(-1 * var(--card-padding-inline));
max-inline-size: unset;
}
.card__body {
display: block;
margin-block-start: 0.3em;
}
.card__column-name--current {
--btn-padding: 0.1em 0.5em;
background: none !important;
border: 1px solid currentColor;
color: var(--color-ink);
display: inline-flex;
flex: 0 1 auto;
inline-size: fit-content;
margin: 0 0 0 auto;
transition: translate 150ms ease-out;
[open] & {
translate: -2em;
}
}
.card__link {
z-index: 1;
}
.card__footer {
margin-block: -0.2em 2em;
.icon { display: none; }
}
.card__meta {
grid-template-areas: "text-updated";
grid-template-columns: 1fr;
}
.card__meta-text {
line-height: 1.5;
}
.card__meta-text--updated {
border: 0;
font-size: var(--text-x-small);
opacity: 0.66;
padding: 0;
text-transform: none;
.local-time-value {
font-weight: inherit;
}
}
.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) {
z-index: 100;
}
/* Notification-specific styles
/* ------------------------------------------------------------------------ */
.tray--notifications {
inset-inline: auto var(--tray-margin);
view-transition-name: tray-notifications;
#footer:has(.bar__placeholder[hidden]) & {
inset-inline-end: -100%;
}
.tray__item,
[data-navigable-list-target~=item] {
[open] &[aria-selected] {
outline: 0;
z-index: calc(var(--tray-item-z) + 2);
.card,
.tray__item--hat & .btn {
border-radius: 0.25ch;
outline: var(--focus-ring-size) solid var(--focus-ring-color);
outline-offset: var(--focus-ring-offset);
}
}
&:nth-child(1n + 7) {
display: none;
pointer-events: none;
visibility: hidden;
}
&:not([aria-selected]) .card:focus-visible,
.tray__dialog:not([open]) & .card:focus-visible {
--focus-ring-size: 0;
}
.btn:focus-visible {
outline: 0;
}
}
&:not(:has(.card--notification)) {
.tray__notification-read-action {
visibility: hidden;
}
}
/* On mobile… */
@media (max-width: 799px) {
/* …add a border */
.tray__dialog:not([open]) ~ .tray__toggle {
border-inline-start: 1px dashed var(--color-ink-light);
translate: var(--tray-margin) 0;
}
}
}
::view-transition-group(tray-notifications) {
z-index: 100;
}
}