Merge pull request #720 from basecamp/notification-links
Notification links
This commit is contained in:
+119
-108
@@ -50,7 +50,7 @@
|
||||
box-shadow:
|
||||
0 0 0 1px var(--color-ink-lighter),
|
||||
0 0 16px oklch(var(--lch-black) / 33%);
|
||||
inset-block-end: var(--footer-height);
|
||||
inset-block-end: calc(var(--footer-height) - 0.75ch);
|
||||
}
|
||||
|
||||
&:not([open]) {
|
||||
@@ -62,13 +62,13 @@
|
||||
/* Expander
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
.tray__expander {
|
||||
.tray__toggle {
|
||||
align-self: stretch;
|
||||
background: transparent;
|
||||
background: none;
|
||||
border: 0;
|
||||
display: grid;
|
||||
margin-block: calc(var(--block-space) * -1) var(--block-space-half);
|
||||
place-content: center;
|
||||
display: block;
|
||||
padding: 0;
|
||||
transition: opacity 100ms ease-out;
|
||||
z-index: calc(var(--z-tray) + 1);
|
||||
|
||||
.icon {
|
||||
@@ -76,21 +76,26 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tray__dialog[open] ~ & {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* On mobile, add an icon to the expander button */
|
||||
@media (max-width: 799px) {
|
||||
inline-size: var(--footer-height);
|
||||
margin: 0;
|
||||
/* When collapsed on mobile, make it small */
|
||||
.tray__dialog:not([open]) ~ & {
|
||||
inline-size: var(--footer-height);
|
||||
|
||||
.icon {
|
||||
display: block;
|
||||
.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:has(.tray__item:not(.tray__item--overflow)) ~ &:after {
|
||||
.tray__dialog:not([open]):has(.tray__item:not(.tray__hat)) ~ &:after {
|
||||
background: oklch(var(--lch-red-medium));
|
||||
block-size: 1ch;
|
||||
border-radius: 50%;
|
||||
@@ -101,66 +106,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* On desktop, hide if there aren't any items to show */
|
||||
/* On desktop… */
|
||||
@media (min-width: 800px) {
|
||||
.tray__dialog:not(:has(.tray__item:not(.tray__item--overflow))) ~ & {
|
||||
display: none
|
||||
/* Hide the UI when collapsed, but only if there are items */
|
||||
.tray__dialog:not([open]):has(.tray__item:not(.tray__hat)) ~ & {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Actions
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
.tray__actions {
|
||||
align-self: center;
|
||||
align-items: stretch;
|
||||
border: 1px dashed oklch(var(--lch-white) / 50%);
|
||||
border-radius: 0.5em;
|
||||
color: var(--color-ink-inverted);
|
||||
display: flex;
|
||||
gap: var(--inline-space-half);
|
||||
opacity: 0;
|
||||
transition: translate var(--tray-duration) var(--tray-timing-function);
|
||||
translate: 0 var(--footer-height);
|
||||
.tray__toggle-btn {
|
||||
--btn-background: transparent;
|
||||
|
||||
/* Get the circle buttons to be full-height without magic numbers */
|
||||
form {
|
||||
aspect-ratio: 1;
|
||||
|
||||
.btn {
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
opacity: 0.66;
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.tray__dialog[open] ~ & {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
}
|
||||
|
||||
/* On desktop, show actions when there aren't items */
|
||||
@media (min-width: 800px) {
|
||||
.tray__dialog:not(:has(.tray__item:not(.tray__item--overflow))) ~ & {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.btn--reversed {
|
||||
color: var(--color-ink);
|
||||
}
|
||||
}
|
||||
border-style: dashed;
|
||||
border-radius: 1ch;
|
||||
inline-size: 100%;
|
||||
opacity: 0.66;
|
||||
}
|
||||
|
||||
/* Item
|
||||
@@ -185,6 +147,10 @@
|
||||
transition-property: margin, scale;
|
||||
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);
|
||||
}
|
||||
@@ -221,31 +187,66 @@
|
||||
}
|
||||
}
|
||||
|
||||
.tray__item--overflow {
|
||||
--tray-item-index: 7 !important;
|
||||
--tray-item-z: 1;
|
||||
.tray__hat {
|
||||
--tray-hat-bg: var(--color-canvas);
|
||||
--tray-item-scale: 1;
|
||||
|
||||
display: none;
|
||||
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;
|
||||
|
||||
.card {
|
||||
align-items: center;
|
||||
background-color: var(--color-canvas);
|
||||
font-size: var(--text-small);
|
||||
font-weight: bold;
|
||||
justify-content: center;
|
||||
.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-size: 12px;
|
||||
font-weight: normal;
|
||||
gap: 0.25ch;
|
||||
inline-size: 100%;
|
||||
|
||||
&:focus-visible {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only show when there are 7+ items */
|
||||
.tray__dialog:has(.tray__item:nth-child(7)) & {
|
||||
display: flex;
|
||||
> *:is(:first-child, :last-child) {
|
||||
inline-size: 128px;
|
||||
}
|
||||
|
||||
.tray__dialog[open] & {
|
||||
--tray-item-scale: 1;
|
||||
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.tray__new-notifications {
|
||||
display: none;
|
||||
position: relative;
|
||||
|
||||
/* 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__dialog:has(.tray__item:nth-child(1n + 7)) & {
|
||||
.tray__old-notifications { display: none; }
|
||||
.tray__new-notifications { display: flex; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Tray cards
|
||||
@@ -302,9 +303,30 @@
|
||||
.tray__item {
|
||||
--tray-item-z: calc(10 - var(--tray-item-index));
|
||||
|
||||
position: relative;
|
||||
|
||||
&:nth-child(1n + 11) { display: none; }
|
||||
}
|
||||
|
||||
.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;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
|
||||
.tray__dialog[open] & {
|
||||
opacity: 0.66;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar,
|
||||
.card__tags,
|
||||
.card__meta .btn,
|
||||
@@ -366,33 +388,22 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* On mobile… */
|
||||
/* 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) {
|
||||
/* …add a border */
|
||||
.tray__expander {
|
||||
.tray__dialog:not([open]) ~ .tray__toggle {
|
||||
border-inline-end: 1px dashed oklch(var(--lch-white) / 50%);
|
||||
translate: calc(-1 * var(--tray-margin)) 0;
|
||||
}
|
||||
|
||||
/* …and disable the expander if there aren't items to show */
|
||||
.tray__dialog:not(:has(.tray__item:not(.tray__item--overflow))) ~ .tray__expander {
|
||||
pointer-events: none;
|
||||
|
||||
.icon {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* On desktop, don't expand if there's only one pin */
|
||||
@media (min-width: 800px) {
|
||||
.tray__dialog:has(.tray__item:only-child) {
|
||||
pointer-events: unset;
|
||||
|
||||
~ .tray__expander {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,13 +431,13 @@
|
||||
/* On mobile… */
|
||||
@media (max-width: 799px) {
|
||||
/* …add a border */
|
||||
.tray__expander {
|
||||
.tray__dialog:not([open]) ~ .tray__toggle {
|
||||
border-inline-start: 1px dashed oklch(var(--lch-white) / 50%);
|
||||
translate: var(--tray-margin) 0;
|
||||
}
|
||||
|
||||
/* …and hide the dialog if there aren't items to show */
|
||||
.tray__dialog:not(:has(.tray__item:not(.tray__item--overflow))) {
|
||||
.tray__dialog:not(:has(.tray__item:not(.tray__hat))) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
<div class="tray__item" id="<%= dom_id pin %>">
|
||||
<%= render "cards/display/preview", card: pin.card %>
|
||||
<%= button_to card_pin_path(pin.card), method: :delete, class: "tray__remove-pin-btn btn btn--circle borderless" do %>
|
||||
<%= icon_tag "remove-med" %> <span class="for-screen-reader">Un-pin this card</span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -6,13 +6,10 @@
|
||||
<%= turbo_frame_tag "pins", src: my_pins_path %>
|
||||
<% end %>
|
||||
|
||||
<div class="tray__actions">
|
||||
<button class="txt-uppercase btn btn--reversed borderless fill-transparent txt-x-small translucent center full-width" data-action="click->dialog#close">
|
||||
Pinned
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button class="tray__expander" data-action="dialog#toggle" aria-label="Expand pins stack" aria-haspopup="true">
|
||||
<%= icon_tag "pinned" %>
|
||||
<button class="tray__toggle" data-action="dialog#toggle" aria-label="Toggle pins stack" aria-haspopup="true">
|
||||
<div class="tray__toggle-btn txt-uppercase btn btn--reversed txt-x-small center full-width">
|
||||
<%= icon_tag "pinned" %>
|
||||
<span class="tray__toggle-text">Pinned</span>
|
||||
</div>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
@@ -6,35 +6,39 @@
|
||||
data-action="keydown.esc->dialog#close:stop click@document->dialog#closeOnClickOutside">
|
||||
<%= turbo_frame_tag "notifications", src: tray_notifications_path, refresh: "morph" %>
|
||||
|
||||
<div class="tray__item tray__item--overflow">
|
||||
<%= link_to notifications_path, class: "card", data: { action: "click->dialog#close" } do %>
|
||||
+ More…
|
||||
<div class="tray__item tray__hat txt-x-small">
|
||||
<%= link_to settings_notifications_path,
|
||||
class: "btn borderless tray__notification-settings",
|
||||
title: "Notification settings",
|
||||
data: { action: "click->dialog#close" } do %>
|
||||
<%= icon_tag "settings" %>
|
||||
<span class="translucent">Settings</span>
|
||||
<% end %>
|
||||
|
||||
<%= link_to notifications_path, class: "tray__new-notifications btn borderless flex-item-grow position-relative overflow-ellipsis", data: { action: "click->dialog#close" } do %>
|
||||
<%= icon_tag "bell" %>
|
||||
<span class="translucent">See more new items</span>
|
||||
<% end %>
|
||||
|
||||
<%= link_to notifications_path, class: "tray__old-notifications btn borderless flex-item-grow position-relative overflow-ellipsis", data: { action: "click->dialog#close" } do %>
|
||||
<%= icon_tag "bell" %>
|
||||
<span class="translucent">See older items</span>
|
||||
<% end %>
|
||||
|
||||
<%= button_to read_all_notifications_path,
|
||||
class: "btn borderless tray__clear-notifications",
|
||||
title: "Mark all notifications as read",
|
||||
data: { action: "click->dialog#close", turbo_frame: "notifications" } do %>
|
||||
<%= icon_tag "check" %>
|
||||
<span class="translucent">Clear all</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<div class="tray__actions">
|
||||
<%= button_to read_all_notifications_path,
|
||||
class: "tray__notification-read-action btn btn--reversed fill-transparent borderless flex-item-justify-start txt-xx-small",
|
||||
title: "Mark all notifications as read",
|
||||
data: { action: "click->dialog#close", turbo_frame: "notifications" } do %>
|
||||
<%= icon_tag "check" %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to tag.span("Notifications"), notifications_path,
|
||||
class: "btn btn--reversed borderless fill-transparent center txt-uppercase txt-x-small full-width",
|
||||
title: "See all notifications",
|
||||
data: { action: "click->dialog#close" } %>
|
||||
|
||||
<%= link_to settings_notifications_path,
|
||||
class: "tray__notification-settings-action btn btn--reversed fill-transparent borderless flex-item-justify-start txt-xx-small",
|
||||
title: "Notification settings",
|
||||
data: { action: "click->dialog#close" } do %>
|
||||
<%= icon_tag "settings" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<button class="tray__expander" data-action="dialog#toggle" aria-label="Expand notifications stack" aria-haspopup="true">
|
||||
<%= icon_tag "bell" %>
|
||||
<button class="tray__toggle" data-action="dialog#toggle" aria-label="Toggle notifications stack" aria-haspopup="true">
|
||||
<div class="tray__toggle-btn txt-uppercase btn btn--reversed txt-x-small center full-width">
|
||||
<%= icon_tag "bell" %>
|
||||
<span class="tray__toggle-text">Notifications</span>
|
||||
</div>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user