Merge notification styles into a card variant

This commit is contained in:
Andy Smith
2025-05-20 13:50:53 -05:00
parent 242869166e
commit 04d01d7d10
14 changed files with 220 additions and 240 deletions
+109 -21
View File
@@ -1,4 +1,7 @@
@layer components {
/* Base
/* -------------------------------------------------------------------------- */
.card {
--card-padding-inline: var(--inline-space-double);
--card-padding-block: var(--block-space);
@@ -8,7 +11,7 @@
aspect-ratio: var(--card-aspect-ratio, auto);
background-color: color-mix(in srgb, var(--card-color) 4%, var(--color-canvas));
border-radius: 0.5em;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
color: color-mix(in srgb, var(--card-color) 40%, var(--color-ink));
display: flex;
@@ -24,26 +27,8 @@
}
}
.card--golden.card--doing {
/* --lch-golden: var(--lch-yellow-medium); */
--lch-golden: 89.1% 0.178 95.7;
background-color: var(--color-canvas);
background-image: linear-gradient(60deg,
oklch(var(--lch-golden) / 0.5) 0%,
oklch(var(--lch-golden) / 0.15) 33%,
oklch(var(--lch-golden) / 0.05) 66%,
oklch(var(--lch-golden) / 0.5) 100%
);
box-shadow:
0 0 0 1px oklch(var(--lch-golden) / 75%),
0 0 0.5em 0.2em oklch(var(--lch-golden) / 25%),
0 0 1em 0.8em oklch(var(--lch-golden) / 25%) !important;
@media (prefers-color-scheme: dark) {
--lch-golden: var(--lch-blue-medium);
}
}
/* Children
/* ------------------------------------------------------------------------ */
.card__background {
inset: 0;
@@ -125,6 +110,10 @@
}
.card__body {
display: flex;
flex-grow: 1;
gap: var(--card-padding-inline);
inline-size: 100%;
padding-block: var(--card-padding-block);
}
@@ -251,6 +240,11 @@
}
}
.card__timestamp {
font-size: var(--text-small);
opacity: 0.66;
}
.card__closed {
align-items: center;
aspect-ratio: 8/5;
@@ -353,4 +347,98 @@
font-size: 30cqi;
}
}
/* Variants
/* ------------------------------------------------------------------------ */
.card--golden.card--doing {
--lch-golden: 89.1% 0.178 95.7;
background-color: var(--color-canvas);
background-image: linear-gradient(60deg,
oklch(var(--lch-golden) / 0.5) 0%,
oklch(var(--lch-golden) / 0.15) 33%,
oklch(var(--lch-golden) / 0.05) 66%,
oklch(var(--lch-golden) / 0.5) 100%
);
box-shadow:
0 0 0 1px oklch(var(--lch-golden) / 75%),
0 0 0.5em 0.2em oklch(var(--lch-golden) / 25%),
0 0 1em 0.8em oklch(var(--lch-golden) / 25%) !important;
@media (prefers-color-scheme: dark) {
--lch-golden: var(--lch-blue-medium);
}
}
.card--notification {
--card-color: var(--color-card-default);
--card-padding-inline: 1ch;
--card-padding-block: 1ch;
background-color: var(--color-canvas);
.card__collection {
font-size: var(--text-xx-small);
padding-block: 0.5ch;
}
.card__body {
padding-block-end: 0;
}
.card__title {
font-size: var(--text-small);
font-weight: bold;
min-block-size: 0;
}
.card__notification-meta {
font-size: var(--text-small);
}
}
.card__notification-unread-indicator {
--btn-background: var(--color-canvas);
--btn-border-color: var(--color-canvas);
--btn-icon-size: 0.75em;
--btn-padding: 0;
--btn-size: 1.25em;
--hover-size: 0;
inset: 0 0 auto auto;
position: absolute;
z-index: 1;
&:before,
.icon {
transition: opacity 150ms ease;
}
/* The red dot */
&:before {
aspect-ratio: 1;
background-color: var(--color-marker);
border-radius: 50%;
content: "";
inline-size: 50%;
inset: 50% auto auto 50%;
position: absolute;
translate: -50% -50%;
}
/* The X */
.icon {
opacity: 0;
}
@media (hover: hover) {
&:hover {
--btn-background: transparent;
&:before { opacity: 0; }
.icon { opacity: 1; }
}
}
}
}
+21 -150
View File
@@ -1,163 +1,34 @@
@layer components {
/* Notification
/* Notifications list
/* ------------------------------------------------------------------------ */
.notification {
--avatar-size: 2lh;
--card-color: var(--color-card-default);
--notification-border-color: transparent;
--notification-padding-block: 0.75em;
--notification-padding-inline: 0.5em;
align-items: center;
background-color: var(--color-canvas);
border: 1px solid var(--color-ink-lighter);
border-radius: 0.2em;
box-shadow: var(--shadow);
color: var(--color-ink);
display: block;
font-size: var(--text-normal);
inline-size: 100%;
max-inline-size: 100%;
padding: var(--notification-padding-block) var(--notification-padding-inline);
position: relative;
text-align: start;
.tray & {
border: none;
.notifications-list {
.tray__item {
position: relative;
}
@media (prefers-color-scheme: dark) {
--notification-border-color: var(--color-ink-medium);
}
.notificiations-list--read & {
--notification-border-color: var(--color-ink-lighter);
box-shadow: none !important;
}
}
.notification__header {
align-items: center;
display: flex;
gap: 0.5ch;
margin-block-end: 1ch;
margin-block-start: calc(-1 * var(--notification-padding-block));
margin-inline-start: calc(-1 * var(--notification-padding-inline));
min-inline-size: 0;
}
.notification__collection {
background-color: var(--card-color);
border-radius: 0.2em 0 0.2em 0;
color: var(--color-ink-inverted);
font-size: 0.6em;
font-weight: 800;
inline-size: fit-content;
padding: 0.25ch var(--inline-space) 0.25ch var(--inline-space-double);
text-transform: uppercase;
.tray & {
font-size: 10px;
}
}
.notification__id {
display: inline-flex;
margin-inline-start: calc(var(--inline-space) * -1);
}
.notification__collection-name {
border-inline-start: 1px solid color-mix(in srgb, var(--color-ink-inverted) 33%, var(--card-color));
color: currentcolor;
display: inline-flex;
margin-inline-start: var(--inline-space-half);
padding-inline-start: calc(var(--inline-space) * 0.75);
}
.notification__time {
opacity: 0.66;
.tray & {
display: none;
}
}
.notification__body {
align-items: center;
display: flex;
flex-grow: 1;
gap: var(--inline-space-half);
}
.notification__title {
padding-inline-end: calc(var(--inline-space-half) + 1.2em);
}
.notification__unread_indicator {
--btn-background: var(--color-canvas);
--btn-border-color: var(--color-canvas);
--btn-icon-size: 0.7em;
--btn-padding: 0;
--btn-size: 1.75em;
--hover-size: 0;
inset: 0 0 auto auto;
position: absolute;
&:before,
.icon {
transition: opacity 150ms ease;
}
/* The red dot */
&:before {
aspect-ratio: 1;
background-color: var(--color-marker);
border-radius: 50%;
content: "";
inline-size: 0.55em;
inset: 50% auto auto 50%;
position: absolute;
translate: -50% -50%;
}
.icon {
opacity: 0;
}
@media (hover: hover) {
&:hover {
--btn-background: transparent;
&:before {
opacity: 0;
}
.icon {
opacity: 1;
}
&:has(.card--notification) {
.notifications-list__empty-message {
display: none;
}
}
}
.notificiations-list--read & {
/* Read items
/* ------------------------------------------------------------------------ */
.notifications-list--read {
&:not(:has(.card--notification)) {
display: none;
}
.card {
box-shadow: 0 0 0 1px var(--color-ink-lighter);
}
.card__notification-unread-indicator {
display: none;
}
}
}
.notifications__empty-message {
.notificiations-list:has(.notification) & {
display: none;
}
}
.notificiations-list--read {
display: none;
&:has(.notification) {
display: flex;
}
}
+65 -42
View File
@@ -24,16 +24,18 @@
--z: calc(6 - var(--position));
display: flex;
inset: auto 0 0;
font-size: 10px;
inline-size: var(--tray-size);
inset: auto 0 0;
outline: 0;
pointer-events: none;
position: absolute !important; /* tmp fix; ideally should remove the position-relative class from tray__item */
position: absolute; /* tmp fix; ideally should remove the position-relative class from tray__item */
scale: var(--scale);
transform: translateY(var(--offset));
transform-origin: center;
transition: scale 0.2s ease-out, transform 0.2s ease-out;
z-index: var(--z);
container-type: inline-size;
&:nth-child(1) { --position: 1; }
&:nth-child(2) { --position: 2; }
@@ -56,6 +58,7 @@
}
}
.tray__actions {
--hover-size: 0;
@@ -110,41 +113,47 @@
}
}
.tray__item-meta {
font-size: var(--text-x-small);
font-weight: 500;
opacity: 0.66;
}
.tray__overflow {
--border-radius: 0.2em;
--hover-size: 0;
--offset: calc((var(--position) - 1) * (var(--block-space) * -1));
--position: 7;
--scale: calc(1 - var(--position) / 30);
--z: calc(6 - var(--position));
background-color: var(--color-canvas);
/* background-color: tomato; */
block-size: var(--height);
border-radius: 0.2em;
box-shadow: var(--shadow);
color: var(--color-ink);
display: none;
inset: auto 0.1ch 0 auto;
font-size: var(--text-small);
font-weight: bold;
inline-size: var(--tray-size);
inset: auto 0.1ch 0 auto;
opacity: 0;
place-content: center;
pointer-events: none;
position: absolute;
scale: var(--scale);
transform: translateY(var(--offset));
transform-origin: center;
transition: scale 0.2s ease-out, transform 0.2s ease-out;
transition:
opacity 0.2s ease-out,
scale 0.2s ease-out,
transform 0.2s ease-out;
z-index: var(--z);
.tray:has(.tray__item:nth-child(7)) & {
display: flex;
display: grid;
}
.tray[open] & {
--offset: calc((100% + var(--block-space-half)) * (var(--position) * -1));
--scale: 1;
margin-block-end: calc(var(--block-space-half) * -1);
margin-block-end: calc(var(--block-space-half) * -2);
opacity: 1;
pointer-events: unset;
}
}
@@ -152,6 +161,32 @@
/* Notifications
/* ------------------------------------------------------------------------ */
.tray {
.card {
--card-padding-block: 1.5ch;
--card-padding-inline: 1.5ch;
--text-xx-large: 2em;
view-transition-name: unset !important;
}
.card__collection {
padding-block: 0.25ch;
}
.card__body {
padding-block-end: 0;
}
.card__title {
--lines: 1;
font-size: var(--text-small);
font-weight: bold;
min-block-size: 0;
}
}
.tray--notifications {
inset: auto var(--inline-space) var(--block-space-half) auto;
@@ -164,6 +199,19 @@
visibility: hidden;
}
}
.card__notification-unread-indicator {
--btn-icon-size: 1.25em;
--btn-size: 2em;
}
.card__notification-meta {
font-size: var(--text-x-small);
}
.card__timestamp {
display: none;
}
}
/* Pins
@@ -175,14 +223,10 @@
.tray__item {
--z: calc(10 - var(--position));
container-type: inline-size;
font-size: 10px;
&:nth-child(7) { --position: 7; }
&:nth-child(8) { --position: 8; }
&:nth-child(9) { --position: 9; }
&:nth-child(10) { --position: 10; }
&:nth-child(1n + 11) { display: none; }
}
@@ -195,39 +239,18 @@
display: none;
}
.card__body {
display: block;
}
.card__meta-grid {
margin-inline-start: 0;
}
.card {
--block-space: 1em;
--block-space-half: 0.5em;
--text-xx-large: 2em;
view-transition-name: unset !important;
}
.card__collection {
padding-block: 0.25ch;
}
.card__body {
display: block;
padding-block-end: 0;
}
.card__link {
z-index: 1;
}
.card__title {
--lines: 1;
font-size: var(--text-small);
font-weight: bold;
min-block-size: 0;
}
.card__stages {
padding: 0;
}
+2 -2
View File
@@ -22,7 +22,7 @@ module NotificationsHelper
tag.div id: dom_id(notification), class: "tray__item" do
concat(
link_to(notification,
class: "notification",
class: "card card--notification",
data: { action: "click->dialog#close", turbo_frame: "_top" },
&)
)
@@ -32,7 +32,7 @@ module NotificationsHelper
def notification_mark_read_button(notification)
button_to read_notification_path(notification),
class: "notification__unread_indicator btn btn--circle borderless",
class: "card__notification-unread-indicator btn btn--circle borderless",
title: "Mark as read",
data: { turbo_frame: "_top" } do
concat(icon_tag("remove-med"))
+1 -1
View File
@@ -19,7 +19,7 @@
<%= render "cards/display/perma/tags", card: card %>
</header>
<div class="card__body flex gap full-width flex-item-grow justify-space-between">
<div class="card__body justify-space-between">
<%= render "cards/container/title", card: card %>
<%= render "cards/stagings/stages", card: card if card.doing? %>
</div>
+1 -1
View File
@@ -9,7 +9,7 @@
<%= render "cards/display/preview/tags", card: card %>
</header>
<div class="card__body flex gap full-width flex-item-grow justify-space-between">
<div class="card__body justify-space-between">
<div class="card__content">
<h1 class="card__title overflow-line-clamp">
<%= card.title %>
@@ -5,7 +5,7 @@
<% if collection = filter.single_collection || (Current.user.collections.first if Current.user.collections.one?) %>
<%= button_to collection_cards_path(collection), method: :post, class: "card card--new-card-button btn", form_class: "full-width" do %>
<div class="card__body flex align-center gap-half txt-xx-large margin-block-half">
<div class="card__body align-center txt-xx-large margin-block-half">
<%= icon_tag "add" %>
<span>Add a new card</span>
</div>
@@ -1,18 +1,17 @@
<% cache notification do %>
<%= notification_tag notification do %>
<header class="notification__header">
<header class="card__header">
<%= render "notifications/notification/#{notification.source_type.underscore}/header", notification: notification %>
</header>
<div class="notification__body">
<div class="card__body">
<div class="avatar txt-x-small flex-item-no-shrink">
<%= avatar_image_tag notification.creator %>
</div>
<div class="flex flex-column min-width flex-item-grow">
<%= render "notifications/notification/#{notification.source_type.underscore}/body", notification: notification %>
<div class="notification__time overflow-ellipsis"> <%= local_datetime_tag(notification.created_at, style: :ago) %></div>
</div>
</div>
<% end %>
+2 -6
View File
@@ -5,12 +5,8 @@
data-action="keydown.esc->dialog#close:stop click@document->dialog#closeOnClickOutside">
<%= turbo_frame_tag "notifications", src: tray_notifications_path, refresh: "morph" %>
<%= link_to notifications_path, class: "tray__overflow border-radius txt-normal", data: { action: "click->dialog#close" } do %>
<div class="notification__body border-radius shadow fill-white flex align-center txt-align-center gap full-width border txt-ink txt-small">
<div class="flex flex-column txt-tight-lines min-width flex-item-grow">
<strong>+ More…</strong>
</div>
</div>
<%= link_to notifications_path, class: "tray__overflow", data: { action: "click->dialog#close" } do %>
+ More…
<% end %>
<div class="tray__actions">
+3 -3
View File
@@ -13,7 +13,7 @@
</nav>
<% end %>
<section class="notificiations-list panel center borderless unpad flex flex-column gap-half">
<section class="notifications-list panel center borderless unpad flex flex-column gap-half">
<% if @unread.any? %>
<div class="flex align-center justify-space-between margin-block-start margin-block-end-half">
<h2 class="txt-medium txt-uppercase txt-alert">New for you</h2>
@@ -22,13 +22,13 @@
<%= render partial: "notifications/notification", collection: @unread, cached: true %>
<% else %>
<div class="notifications__empty-message pad border-radius border translucent" style="--border-style: dashed; --border-color: var(--color-ink); --border-radius: 0.2em;">
<div class="notifications-list__empty-message pad border-radius border translucent" style="--border-style: dashed; --border-color: var(--color-ink); --border-radius: 0.2em;">
<strong>Nothing new for you.</strong>
</div>
<% end %>
</section>
<section class="notificiations-list--read panel center borderless unpad flex-column gap-half margin-block-start">
<section class="notifications-list notifications-list--read panel center borderless unpad flex flex-column gap-half margin-block-start">
<h2 class="txt-medium margin-block-start-double margin-block-end-half txt-uppercase translucent">Previously seen</h2>
<div id="notifications_list_read" contents>
@@ -1,6 +1,9 @@
<% event = notification.source %>
<strong class="overflow-ellipsis notification__title txt-small txt-tight-lines"><%= event_notification_title(event) %></strong>
<div class="overflow-ellipsis txt-small txt-tight-lines">
<%= event_notification_body(event) %>
<div class="card__title overflow-ellipsis">
<%= event_notification_title(event) %>
</div>
<div class="card__notification-meta overflow-ellipsis">
<%= event_notification_body(event) %> <span class="card__timestamp">• <%= local_datetime_tag(notification.created_at, style: :ago) %></span>
</div>
@@ -1,6 +1,6 @@
<div class="notification__collection">
<span class="notification__id"><%= notification.source.eventable.id %></span>
<span class="notification__collection-name overflow-ellipsis">
<div class="card__collection">
<span class="card__id"><%= notification.source.eventable.id %></span>
<span class="card__collection-name overflow-ellipsis">
<%= notification.source.collection.name %>
</span>
</div>
@@ -1,6 +1,6 @@
<% mention = notification.source %>
<strong class="overflow-ellipsis notification__title txt-small txt-tight-lines"><%= mention.mentioner.first_name %> mentioned you</strong>
<div class="overflow-ellipsis txt-small txt-tight-lines">
<strong class="card__title overflow-ellipsis"><%= mention.mentioner.first_name %> mentioned you</strong>
<div class="card__notification-meta overflow-ellipsis">
<%= mention.source.mentionable_content.truncate(200) %>
</div>
@@ -1,4 +1,4 @@
<div class="notification__collection">
<span class="notification__id"><%= notification.source.id %></span>
<div class="card__collection">
<span class="card__id"><%= notification.source.id %></span>
</div>