diff --git a/app/assets/stylesheets/animation.css b/app/assets/stylesheets/animation.css index c99081856..656f1ae76 100644 --- a/app/assets/stylesheets/animation.css +++ b/app/assets/stylesheets/animation.css @@ -26,4 +26,13 @@ 50% { transform: translateX(-1rem); } 75% { transform: translateX(1rem); } } + + @keyframes wobble { + 0% { transform: rotate(calc(var(--bubble-rotate) + 30deg)); } + 15% { border-radius: 66% 34% 72% 28% / 39% 63% 37% 61%; } + 25% { border-radius: 55% 47% 62% 40% / 58% 50% 52% 44%; } + 33% { border-radius: 46% 54% 61% 39% / 50% 51% 49% 50%; } + 50% { border-radius: 54% 46% 61% 39% / 57% 49% 51% 43%; } + 75% { border-radius: 53% 45% 60% 38% / 56% 48% 50% 42%; } + } } diff --git a/app/assets/stylesheets/cards.css b/app/assets/stylesheets/cards.css index 0e3e4a1ff..a8068226e 100644 --- a/app/assets/stylesheets/cards.css +++ b/app/assets/stylesheets/cards.css @@ -59,7 +59,7 @@ transition: opacity 0.2s ease-in-out; } - @media (hover: hover) { + @media (any-hover: hover) { .card:hover & { img:not([src=""]) { opacity: 1; @@ -286,4 +286,61 @@ -2px 2px 0 var(--card-color), 2px 2px 0 var(--card-color); } + + .card__bubble { + --bubble-color: radial-gradient(oklch(var(--lch-blue-medium) / 10%) 50%, oklch(var(--lch-blue-medium) / 50%) 100%); + --bubble-shape: 54% 46% 61% 39% / 57% 49% 51% 43%; + --bubble-rotate: 0deg; + --size: 5cqi; + + block-size: var(--size); + container-type: inline-size; + font-size: 1.75rem; + font-weight: bold; + inline-size: var(--size); + inset: 50% auto auto -0.5ch; + padding: 0.5cqi; + position: absolute; + translate: -100% -50%; + + &:before { + background: var(--bubble-color); + border-radius: var(--bubble-shape); + content: ""; + inset: 0; + position: absolute; + transform: rotate(var(--bubble-rotate)); + } + + @media (any-hover: hover) { + &:hover:before { + animation: wobble 1200ms; + } + } + + span { + display: grid; + font-size: 40cqi; + font-weight: 900; + inset: 0; + place-content: center; + position: absolute; + text-align: center; + } + + svg { + display: block; + letter-spacing: 0.125ch; + text-transform: uppercase; + } + + .card:nth-child(2n+1) & { --bubble-rotate: -90deg; } + .card:nth-child(3n+1) & { --bubble-rotate: 45deg; } + } + + .card__bubble--today { + span { + font-size: 30cqi; + } + } } diff --git a/app/assets/stylesheets/pins.css b/app/assets/stylesheets/pins.css index 8756e2391..46e50414a 100644 --- a/app/assets/stylesheets/pins.css +++ b/app/assets/stylesheets/pins.css @@ -79,5 +79,9 @@ inset: 0 0 auto auto; position: absolute; } + + .card__bubble { + display: none; + } } } diff --git a/app/models/card/closeable.rb b/app/models/card/closeable.rb index e0d15831b..8f69a7098 100644 --- a/app/models/card/closeable.rb +++ b/app/models/card/closeable.rb @@ -1,6 +1,9 @@ module Card::Closeable extend ActiveSupport::Concern + AUTO_CLOSE_AFTER = 30.days + AUTO_CLOSE_REMINDER_BEFORE = 30.days + included do has_one :closure, dependent: :destroy @@ -26,6 +29,14 @@ module Card::Closeable last_active_at + auto_close_period if auto_closing? && last_active_at end + def days_until_close + (auto_close_at.to_date - Date.current).to_i if auto_close_at + end + + def closing_soon? + considering? && Time.current >= auto_close_at - AUTO_CLOSE_REMINDER_BEFORE + end + def closed? closure.present? end diff --git a/app/views/cards/display/_preview.html.erb b/app/views/cards/display/_preview.html.erb index 32b3d38da..d6b35c135 100644 --- a/app/views/cards/display/_preview.html.erb +++ b/app/views/cards/display/_preview.html.erb @@ -28,5 +28,9 @@ <%= render "cards/display/common/background", card: card %> + + <% if card.closing_soon? %> + <%= render "cards/display/preview/bubble", label: "Closes in", days: card.days_until_close %> + <% end %> <% end %> <% end %> diff --git a/app/views/cards/display/preview/_bubble.html.erb b/app/views/cards/display/preview/_bubble.html.erb new file mode 100644 index 000000000..1b90ae83c --- /dev/null +++ b/app/views/cards/display/preview/_bubble.html.erb @@ -0,0 +1,23 @@ +
+ + + + + <%= label %> + + + + + + <%= days %> + + + + + + + <%= "Day".pluralize(days) %> + + + +