diff --git a/app/assets/images/check-circle.svg b/app/assets/images/check-circle.svg new file mode 100644 index 000000000..7e22d1cef --- /dev/null +++ b/app/assets/images/check-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/close-circle.svg b/app/assets/images/close-circle.svg new file mode 100644 index 000000000..cb0894a34 --- /dev/null +++ b/app/assets/images/close-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/reaction.svg b/app/assets/images/reaction.svg index b6b18b6f2..4f68fcfcb 100644 --- a/app/assets/images/reaction.svg +++ b/app/assets/images/reaction.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/images/remove-med.svg b/app/assets/images/remove-med.svg deleted file mode 100644 index c15d589ec..000000000 --- a/app/assets/images/remove-med.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/assets/stylesheets/comments.css b/app/assets/stylesheets/comments.css index 0a42d1f3e..33aacc74a 100644 --- a/app/assets/stylesheets/comments.css +++ b/app/assets/stylesheets/comments.css @@ -4,7 +4,7 @@ --comment-padding-block: var(--block-space-half); --comment-padding-inline: var(--inline-space-double); --comment-max: 70ch; - --reaction-size: 2rem; + --reaction-size: 1.6875rem; display: flex; flex-direction: column; @@ -37,8 +37,6 @@ } .comment__author { - margin-inline-end: calc(var(--comment-padding-inline) * -0.66); - .btn { font-weight: inherit; } @@ -54,6 +52,7 @@ } .comment__body { + padding-inline-end: var(--reaction-size); text-align: start; :first-child { @@ -75,7 +74,7 @@ border-radius: 0.2em; padding: var(--comment-padding-block) - var(--comment-padding-inline) + calc(var(--comment-padding-inline) / 2) calc(var(--comment-padding-block) * 1.5) var(--comment-padding-inline); word-wrap: break-word; @@ -89,17 +88,8 @@ } } - .comment__reaction { - background-color: var(--color-ink-lightest); - opacity: 0.66; - - @media (any-hover: hover) { - .comment:not(:hover) & { - opacity: 0; - } - } - - .comment--mine & { + .comment--mine { + .comment__reaction { display: none; } } @@ -147,8 +137,7 @@ ); } - .reactions, - .quick-reaction { + .reactions { display: none !important; } } diff --git a/app/assets/stylesheets/icons.css b/app/assets/stylesheets/icons.css index 61e140007..c53d9ce5f 100644 --- a/app/assets/stylesheets/icons.css +++ b/app/assets/stylesheets/icons.css @@ -36,9 +36,11 @@ .icon--camera { --svg: url("camera.svg "); } .icon--caret-down { --svg: url("caret-down.svg "); } .icon--check { --svg: url("check.svg "); } + .icon--check-circle { --svg: url("check-circle.svg "); } .icon--check-all { --svg: url("check-all.svg "); } .icon--clipboard { --svg: url("clipboard.svg "); } .icon--close { --svg: url("close.svg "); } + .icon--close-circle { --svg: url("close-circle.svg "); } .icon--collection { --svg: url("collection.svg "); } .icon--collection-add { --svg: url("collection-add.svg "); } .icon--comment { --svg: url("comment.svg "); } @@ -81,7 +83,6 @@ .icon--reaction { --svg: url("reaction.svg "); } .icon--refresh { --svg: url("refresh.svg "); } .icon--refresh--meta { --svg: url("refresh--meta.svg "); } - .icon--remove-med { --svg: url("remove-med.svg "); } .icon--remove { --svg: url("remove.svg "); } .icon--rename { --svg: url("rename.svg "); } .icon--search { --svg: url("search.svg "); } diff --git a/app/assets/stylesheets/reactions.css b/app/assets/stylesheets/reactions.css index 6b49cf4c5..664aa7941 100644 --- a/app/assets/stylesheets/reactions.css +++ b/app/assets/stylesheets/reactions.css @@ -12,18 +12,41 @@ inline-size: 100%; margin-block-start: calc(var(--block-space-half) / 2); margin-inline: calc(var(--column-gap) / -1); + + &:has([open]) { + z-index: var(--z-popup); + } + + &:not(:has(.reaction)) { + inline-size: auto; + inset-block-end: var(--comment-padding-block); + inset-inline-end: calc(var(--comment-padding-inline) / 2); + margin: 0; + position: absolute; + + .reactions__list { + display: none; + } + + .reactions__trigger { + background-color: var(--color-ink-lightest); + + &:not(:hover) { + opacity: 0.66; + } + } + } } .reactions__list { display: inline-flex; flex-wrap: wrap; - gap: var(--column-gap); - - &:not(:has(.reaction)) { - display: none; - } + gap: var(--inline-space-half); } + /* Single reaction + /* -------------------------------------------------------------------------- */ + .reaction { --btn-size: 100%; --reaction-hover-brightness: 0.9; @@ -34,10 +57,10 @@ border: 1px solid var(--reaction-border-color); border-radius: 4rem; display: inline-flex; - gap: var(--column-gap); + gap: 0.25ch; max-inline-size: 100%; opacity: 1; - padding: 0.1em 0.25em 0.1em 0.12em; + padding: 0.1em 0.12em; postion: relative; transition: opacity 100ms ease-in-out, transform 150ms ease-in-out; @@ -51,7 +74,7 @@ cursor: pointer; @media (any-hover: hover) { - &:not(:active):hover { + &:not(.expanded):hover { filter: brightness(var(--reaction-hover-brightness)); @media (prefers-color-scheme: dark) { @@ -70,7 +93,6 @@ .reaction__delete { display: none; - translate: 0.25em; .expanded & { display: grid; @@ -88,7 +110,7 @@ &:has(.input:focus) { outline: var(--focus-ring-size) solid var(--focus-ring-color); - outline-offset: var(--focus-ring-offset); + outline-offset: -1px; } .reaction__form-label:focus { @@ -112,25 +134,30 @@ animation: scale-fade-out 0.2s both; } - .reaction__action { - --btn-border-color: var(--reaction-border-color); - --btn-size: var(--reaction-size); - - font-size: 0.75em; - - .reactions:not(:has(.reaction)) & { - display: none; - } + .reaction__menu-btn, + .reaction__submit-btn, + .reaction__cancel-btn { + --btn-size: 1.25rem; + --icon-size: var(--btn-size); } - /* Quick reactions + .reaction__submit-btn { + color: oklch(var(--lch-green-dark)); + } + + .reaction__cancel-btn { + color: oklch(var(--lch-red-dark)); + } + + + /* Menu /* ------------------------------------------------------------------------ */ - .quick-reaction { + .reaction__menu { position: relative; } - .quick-reaction__popup { + .reaction__popup { --panel-border-radius: 1.2em; --panel-padding: 0.5ch; --offset: calc(-1 * var(--panel-padding)); @@ -140,22 +167,26 @@ transform: none; } - .quick-reaction__emojis { + .reaction__emoji-list { display: grid; - grid-template-columns: repeat(3, 1fr); + grid-template-columns: repeat(10, 1fr); .btn { - --btn-icon-size: 1.5ch; - --btn-size: var(--reaction-size); - --btn-border-color: var(--color-canvas); + --btn-size: 1.5rem; + font-size: 1rem; position: relative; - /* Make sure the selection ring sits on top of adjacent buttons on hover */ + /* Make sure the focus ring sits on top of adjacent buttons */ &:hover, &:focus-visible { + filter: none; z-index: 1; } + + &:hover { + scale: 1.5; + } } } } diff --git a/app/helpers/emoji_helper.rb b/app/helpers/emoji_helper.rb index fd959ce8a..5746071e6 100644 --- a/app/helpers/emoji_helper.rb +++ b/app/helpers/emoji_helper.rb @@ -1,12 +1,54 @@ module EmojiHelper REACTIONS = { - "👍" => "Thumbs up", "👏" => "Clapping", - "👋" => "Waving hand", - "💪" => "Muscle", + "👍" => "Thumbs up", + "🙌" => "Hands raised in celebration", + "💪" => "Flexed bicep", + "🤘" => "Sign of the horns", + "✊" => "Raised fist", + "✨" => "Sparkles", "❤️" => "Red heart", - "😂" => "Face with tears of joy", + "💯" => "100 points", "🎉" => "Party popper", - "🔥" => "Fire" + "🤩" => "Face with starry eyes", + "🥳" => "Partying face", + "😊" => "Smiling face with flush cheeks", + "😀" => "Grinning face", + "😂" => "Face with tears of joy", + "😅" => "Grinning face with sweat drop", + "😎" => "Smiling face with sunglasses", + "😉" => "Winking face", + "😜" => "Winking face with stuck out tongue", + "😬" => "Grimacing face", + "😮" => "Surprised face with open mouth", + "😳" => "Flushed face", + "🤔" => "Thinking face", + "😒" => "Unamused face", + "😢" => "Crying face", + "😭" => "Loudly crying face", + "😱" => "Face screaming in fear", + "👀" => "Eyes", + "🙏" => "Hands pressed together", + "💩" => "Pile of poop", + "👎" => "Thumbs down", + "✌️" => "Peace", + "👈" => "Finger pointing left", + "👆" => "Finger pointing Up", + "✋" => "Raised hand", + "👋" => "Waving hand", + "☀️" => "Sun", + "🌙" => "Moon", + "💥" => "Collision", + "🔥" => "Fire", + "🎂" => "Birthday cake", + "🍴" => "Fork and knife", + "💰" => "Money bag", + "🥇" => "Gold medal", + "🚨" => "Red flashing light", + "💡" => "Light bulb", + "🛠" => "Hammer and wrench", + "📈" => "Chart with upward trend", + "✅" => "Check mark", + "📢" => "Public address loudspeaker" } end diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 5dfad5225..c557624be 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -48,7 +48,7 @@ module NotificationsHelper title: "Mark as read", data: { action: "form#submit:stop badge#update:stop", form_target: "submit" }, form: { data: { controller: "form" } } do - concat(icon_tag("remove-med")) + concat(icon_tag("remove")) concat(tag.span("Mark as read", class: "for-screen-reader")) end end diff --git a/app/javascript/controllers/reaction_emoji_controller.js b/app/javascript/controllers/reaction_emoji_controller.js new file mode 100644 index 000000000..e3e61ca58 --- /dev/null +++ b/app/javascript/controllers/reaction_emoji_controller.js @@ -0,0 +1,11 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "input" ] + + insertEmoji(event) { + const emojiChar = event.target.getAttribute("data-emoji") + const value = this.inputTarget.value + this.inputTarget.value = `${value}${emojiChar}` + } +} diff --git a/app/views/cards/comments/_comment.html.erb b/app/views/cards/comments/_comment.html.erb index dafdb1c4e..f0cd8c642 100644 --- a/app/views/cards/comments/_comment.html.erb +++ b/app/views/cards/comments/_comment.html.erb @@ -24,13 +24,6 @@ <%= icon_tag "menu-dots-horizontal" %> Edit this comment <% end %> - - <%= render "cards/comments/reactions/quick_reaction", comment: comment do %> - - <% end %>
diff --git a/app/views/cards/comments/reactions/_menu.html.erb b/app/views/cards/comments/reactions/_menu.html.erb new file mode 100644 index 000000000..698ba4ad7 --- /dev/null +++ b/app/views/cards/comments/reactions/_menu.html.erb @@ -0,0 +1,13 @@ +
+ + + +
+ <% EmojiHelper::REACTIONS.each do |character, title| %> + <%= tag.button character, title: title, class: "reaction__emoji-btn btn btn--circle borderless", type: "button", data: { action: "reaction-emoji#insertEmoji dialog#close", emoji: character } %> + <% end %> +
+
+
diff --git a/app/views/cards/comments/reactions/_quick_reaction.html.erb b/app/views/cards/comments/reactions/_quick_reaction.html.erb deleted file mode 100644 index 7b4054bd7..000000000 --- a/app/views/cards/comments/reactions/_quick_reaction.html.erb +++ /dev/null @@ -1,25 +0,0 @@ -
- <%= yield %> - - -
- <% EmojiHelper::REACTIONS.each do |character, title| %> - <%= form_with model: [ comment.card, comment, Reaction.new ], data: { turbo_frame: dom_id(comment, :new_reaction), action: "dialog#close"} do |form| %> - <%= hidden_field_tag "reaction[content]", character %> - <%= form.button type: "submit", title: title, class: "reaction__quick-emoji-btn btn btn--circle", data: { emoji: character } do %> - <%= character %> - <% end %> - <% end %> - <% end %> - -
- <%= link_to new_card_comment_reaction_path(comment.card, comment), role: "button", - class: "btn btn--circle", action: "soft-keyboard#open", - data: { turbo_frame: dom_id(comment, :new_reaction), action: "dialog#close" } do %> - <%= icon_tag "reaction" %> - Add your own reaction - <% end %> -
-
-
-
diff --git a/app/views/cards/comments/reactions/_reaction.html.erb b/app/views/cards/comments/reactions/_reaction.html.erb index 621b8406a..2c9dfc01b 100644 --- a/app/views/cards/comments/reactions/_reaction.html.erb +++ b/app/views/cards/comments/reactions/_reaction.html.erb @@ -19,7 +19,7 @@ method: :delete, class: "reaction__delete btn btn--negative flex-item-justify-end", data: { action: "reaction-delete#perform", reaction_delete_target: "button" } do %> - <%= icon_tag "minus" %> + <%= icon_tag "trash" %> Delete this reaction <% end %>
diff --git a/app/views/cards/comments/reactions/_reactions.html.erb b/app/views/cards/comments/reactions/_reactions.html.erb index 73a79812b..dde2d18fd 100644 --- a/app/views/cards/comments/reactions/_reactions.html.erb +++ b/app/views/cards/comments/reactions/_reactions.html.erb @@ -5,10 +5,11 @@ <%= turbo_frame_tag comment, :new_reaction do %> - <%= render "cards/comments/reactions/quick_reaction", comment: comment do %> - + <%= link_to new_card_comment_reaction_path(comment.card, comment), role: "button", + class: "reactions__trigger btn btn--circle borderless", action: "soft-keyboard#open", + data: { turbo_frame: dom_id(comment, :new_reaction), action: "dialog#close" } do %> + <%= icon_tag "reaction" %> + Add your own reaction <% end %> <% end %> diff --git a/app/views/cards/comments/reactions/new.html.erb b/app/views/cards/comments/reactions/new.html.erb index 5f6f57b03..38c6daf98 100644 --- a/app/views/cards/comments/reactions/new.html.erb +++ b/app/views/cards/comments/reactions/new.html.erb @@ -2,23 +2,25 @@ <%= form_with model: [ @comment.card, @comment, Reaction.new ], class: "reaction reaction__form expanded", html: { aria: { label: "New reaction" } }, - data: { controller: "form", turbo_frame: dom_id(@comment, :reacting), action: "keydown.esc->form#cancel" } do |form| %> + data: { controller: "form reaction-emoji", turbo_frame: dom_id(@comment, :reacting), action: "keydown.esc->form#cancel submit->form#preventEmptySubmit" } do |form| %> - <%= form.button class: "btn btn--circle borderless btn--reversed", type: "submit" do %> - <%= icon_tag "check" %> Submit + <%= render "cards/comments/reactions/menu", comment: @comment %> + + <%= form.button class: "reaction__submit-btn btn btn--circle borderless", type: "submit", data: { form_target: "submit" } do %> + <%= icon_tag "check-circle" %> Submit <% end %> <%= link_to card_comment_reactions_path(@comment.card, @comment), role: "button", - data: { turbo_frame: dom_id(@comment, :reacting), form_target: "cancel" }, class: "btn btn--circle borderless btn--negative" do %> - <%= icon_tag "minus" %> Cancel + data: { turbo_frame: dom_id(@comment, :reacting), form_target: "cancel" }, class: "reaction__cancel-btn btn btn--circle borderless" do %> + <%= icon_tag "close-circle" %> Cancel <% end %> <% end %> <% end %> diff --git a/app/views/searches/_results.html.erb b/app/views/searches/_results.html.erb index 38364b547..7cdd92df9 100644 --- a/app/views/searches/_results.html.erb +++ b/app/views/searches/_results.html.erb @@ -1,6 +1,6 @@