Add an index view for all notifications
This commit is contained in:
@@ -2,83 +2,83 @@
|
||||
height: 4rem;
|
||||
inset: auto auto var(--block-space);
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.notification {
|
||||
inset: auto auto 0;
|
||||
position: absolute;
|
||||
transform: translate(var(--offsetX), var(--offsetY));
|
||||
transform-origin: center center;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
z-index: var(--z-index);
|
||||
.notification {
|
||||
inset: auto auto 0;
|
||||
position: absolute;
|
||||
transform: translate(var(--offsetX), var(--offsetY));
|
||||
transform-origin: center center;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
z-index: var(--z-index);
|
||||
|
||||
.notification__content {
|
||||
color: var(--color-ink);
|
||||
inline-size: var(--width);
|
||||
}
|
||||
.notification__content {
|
||||
color: var(--color-ink);
|
||||
inline-size: var(--width);
|
||||
}
|
||||
|
||||
&:nth-child(1) {
|
||||
--offsetX: 0;
|
||||
--offsetY: 0;
|
||||
--width: 40ch;
|
||||
--z-index: 0;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
--offsetX: 0.5ch;
|
||||
--offsetY: calc(var(--block-space-half) * -1);
|
||||
--width: 39ch;
|
||||
--z-index: -1;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
--offsetX: 1ch;
|
||||
--offsetY: calc(var(--block-space) * -1);
|
||||
--width: 38ch;
|
||||
--z-index: -2;
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
--offsetX: 1.5ch;
|
||||
--offsetY: calc(var(--block-space) * -1.5);
|
||||
--width: 37ch;
|
||||
--z-index: -3;
|
||||
}
|
||||
|
||||
&:nth-child(5) {
|
||||
--offsetX: 2ch;
|
||||
--offsetY: calc(var(--block-space) * -2);
|
||||
--width: 36ch;
|
||||
--z-index: -4;
|
||||
}
|
||||
|
||||
&:nth-child(1n + 6) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.notification-tray:hover & {
|
||||
&:nth-child(2) {
|
||||
&:nth-child(1) {
|
||||
--offsetX: 0;
|
||||
--offsetY: calc((100% + var(--block-space-half)) * -1);
|
||||
--offsetY: 0;
|
||||
--width: 40ch;
|
||||
--z-index: 0;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
--offsetX: 0.5ch;
|
||||
--offsetY: calc(var(--block-space-half) * -1);
|
||||
--width: 39ch;
|
||||
--z-index: -1;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
--offsetX: 0;
|
||||
--offsetY: calc((100% + var(--block-space-half)) * -2);
|
||||
--width: 40ch;
|
||||
--offsetX: 1ch;
|
||||
--offsetY: calc(var(--block-space) * -1);
|
||||
--width: 38ch;
|
||||
--z-index: -2;
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
--offsetX: 0;
|
||||
--offsetY: calc((100% + var(--block-space-half)) * -3);
|
||||
--width: 40ch;
|
||||
--offsetX: 1.5ch;
|
||||
--offsetY: calc(var(--block-space) * -1.5);
|
||||
--width: 37ch;
|
||||
--z-index: -3;
|
||||
}
|
||||
|
||||
&:nth-child(5) {
|
||||
--offsetX: 0;
|
||||
--offsetY: calc((100% + var(--block-space-half)) * -4);
|
||||
--width: 40ch;
|
||||
--offsetX: 2ch;
|
||||
--offsetY: calc(var(--block-space) * -2);
|
||||
--width: 36ch;
|
||||
--z-index: -4;
|
||||
}
|
||||
|
||||
&:nth-child(1n + 6) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.notification-tray:hover & {
|
||||
&:nth-child(2) {
|
||||
--offsetX: 0;
|
||||
--offsetY: calc((100% + var(--block-space-half)) * -1);
|
||||
--width: 40ch;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
--offsetX: 0;
|
||||
--offsetY: calc((100% + var(--block-space-half)) * -2);
|
||||
--width: 40ch;
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
--offsetX: 0;
|
||||
--offsetY: calc((100% + var(--block-space-half)) * -3);
|
||||
--width: 40ch;
|
||||
}
|
||||
|
||||
&:nth-child(5) {
|
||||
--offsetX: 0;
|
||||
--offsetY: calc((100% + var(--block-space-half)) * -4);
|
||||
--width: 40ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
class NotificationsController < ApplicationController
|
||||
def index
|
||||
@read = Current.user.notifications.read.ordered
|
||||
@unread = Current.user.notifications.unread.ordered
|
||||
end
|
||||
end
|
||||
@@ -8,6 +8,6 @@ class ReadingsController < ApplicationController
|
||||
|
||||
private
|
||||
def mark_bubble_notifications_read
|
||||
Current.user.notifications.where(bubble: @bubble).update(read: true)
|
||||
Current.user.notifications.where(bubble: @bubble).update(read_at: Time.current)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,10 +4,15 @@ class Notification < ApplicationRecord
|
||||
belongs_to :bubble
|
||||
belongs_to :resource, polymorphic: true
|
||||
|
||||
scope :unread, -> { where(read: false) }
|
||||
scope :ordered, -> { order(read: :desc, created_at: :desc) }
|
||||
scope :unread, -> { where(read_at: nil) }
|
||||
scope :read, -> { where.not(read_at: nil) }
|
||||
scope :ordered, -> { order(read_at: :desc, created_at: :desc) }
|
||||
|
||||
delegate :creator, to: :event
|
||||
|
||||
broadcasts_to ->(notification) { [ notification.user, :notifications ] }, inserts_by: :prepend
|
||||
|
||||
def read?
|
||||
read_at.present?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
<span class="for-screen-reader">Account settings</span>
|
||||
<% end %>
|
||||
|
||||
<%= link_to "All notifications", notifications_path %>
|
||||
|
||||
<%= link_to new_bucket_path, class: "btn flex-item-justify-end", style: "view-transition-name: new-bucket" do %>
|
||||
<%= image_tag "add.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Add a new project</span>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<% @page_title = "Notifications" %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<nav>
|
||||
<%= link_to root_path, class: "btn flex-item-justify-start", data: { controller: "hotkey", action: "keydown.esc@document->hotkey#click" } do %>
|
||||
<%= image_tag "arrow-left.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Go back</span>
|
||||
<% end %>
|
||||
|
||||
<h1>All notifications</h1>
|
||||
|
||||
<%= link_to new_bucket_path, class: "btn flex-item-justify-end", style: "view-transition-name: new-bucket" do %>
|
||||
<%= image_tag "add.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Add a new project</span>
|
||||
<% end %>
|
||||
</nav>
|
||||
<% end %>
|
||||
|
||||
<% if @unread.any? %>
|
||||
<h2>New for you</h2>
|
||||
<%= render @unread %>
|
||||
<% end %>
|
||||
|
||||
<% if @read.any? %>
|
||||
<h2>Previously read</h2>
|
||||
<%= render @read %>
|
||||
<% end %>
|
||||
+2
-1
@@ -18,8 +18,9 @@ Rails.application.routes.draw do
|
||||
end
|
||||
|
||||
resources :bubbles
|
||||
resources :notifications, only: :index
|
||||
namespace :notifications do
|
||||
resource :tray
|
||||
resource :tray, only: :show
|
||||
end
|
||||
|
||||
resources :buckets do
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
class ChangeNotificationReadToReadAt < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
remove_index :notifications, %i[ user_id read created_at ], order: { read: :desc, created_at: :desc }
|
||||
|
||||
change_table :notifications do |t|
|
||||
t.remove :read
|
||||
t.datetime :read_at
|
||||
|
||||
t.index %i[ user_id read_at created_at ], order: { read_at: :desc, created_at: :desc }
|
||||
end
|
||||
end
|
||||
end
|
||||
Generated
+3
-3
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.1].define(version: 2025_01_15_122810) do
|
||||
ActiveRecord::Schema[8.1].define(version: 2025_01_16_163344) do
|
||||
create_table "accesses", force: :cascade do |t|
|
||||
t.integer "bucket_id", null: false
|
||||
t.integer "user_id", null: false
|
||||
@@ -183,13 +183,13 @@ ActiveRecord::Schema[8.1].define(version: 2025_01_15_122810) do
|
||||
t.integer "bubble_id", null: false
|
||||
t.string "resource_type", null: false
|
||||
t.integer "resource_id", null: false
|
||||
t.boolean "read", default: false, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "read_at"
|
||||
t.index ["bubble_id"], name: "index_notifications_on_bubble_id"
|
||||
t.index ["event_id"], name: "index_notifications_on_event_id"
|
||||
t.index ["resource_type", "resource_id"], name: "index_notifications_on_resource"
|
||||
t.index ["user_id", "read", "created_at"], name: "index_notifications_on_user_id_and_read_and_created_at", order: { read: :desc, created_at: :desc }
|
||||
t.index ["user_id", "read_at", "created_at"], name: "index_notifications_on_user_id_and_read_at_and_created_at", order: { read_at: :desc, created_at: :desc }
|
||||
t.index ["user_id"], name: "index_notifications_on_user_id"
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
require "test_helper"
|
||||
|
||||
class NotificationsControllerTest < ActionDispatch::IntegrationTest
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
||||
Vendored
-2
@@ -3,7 +3,6 @@ logo_published_kevin:
|
||||
event: logo_published
|
||||
bubble: logo
|
||||
resource: logo (Bubble)
|
||||
read: false
|
||||
created_at: <%= 1.week.ago %>
|
||||
|
||||
layout_commented_kevin:
|
||||
@@ -11,5 +10,4 @@ layout_commented_kevin:
|
||||
event: layout_commented
|
||||
bubble: layout
|
||||
resource: layout_overflowing_david (Comment)
|
||||
read: false
|
||||
created_at: <%= 1.week.ago %>
|
||||
|
||||
Reference in New Issue
Block a user