diff --git a/app/assets/stylesheets/embeds.css b/app/assets/stylesheets/embeds.css index bd53ba6..a7db589 100644 --- a/app/assets/stylesheets/embeds.css +++ b/app/assets/stylesheets/embeds.css @@ -15,7 +15,7 @@ flex-direction: row; } - .cf-twitter-avatar & { + &.og-embed--twitter-avatar { flex-direction: row; } } @@ -68,7 +68,7 @@ } } - .cf-twitter-avatar & { + .og-embed--twitter-avatar & { aspect-ratio: 1; border-radius: 50%; inline-size: 2lh; diff --git a/app/helpers/content_filters.rb b/app/helpers/content_filters.rb index ef3b06c..8112891 100644 --- a/app/helpers/content_filters.rb +++ b/app/helpers/content_filters.rb @@ -9,5 +9,5 @@ module ContentFilters EDITOR_FORMATTING_TAGS = %w[ s u mark ] EDITOR_FORMATTING_ATTRIBUTES = %w[ data-language ] - TextMessagePresentationFilters = ActionText::Content::Filters.new(RemoveSoloUnfurledLinkText, StyleUnfurledTwitterAvatars, SanitizeTags) + TextMessagePresentationFilters = ActionText::Content::Filters.new(RemoveSoloUnfurledLinkText, SanitizeTags) end diff --git a/app/helpers/content_filters/style_unfurled_twitter_avatars.rb b/app/helpers/content_filters/style_unfurled_twitter_avatars.rb deleted file mode 100644 index 0ca02cf..0000000 --- a/app/helpers/content_filters/style_unfurled_twitter_avatars.rb +++ /dev/null @@ -1,26 +0,0 @@ -class ContentFilters::StyleUnfurledTwitterAvatars < ActionText::Content::Filter - def applicable? - unfurled_twitter_avatars.present? - end - - def apply - fragment.update do |source| - div = source.at_css("div") - div["class"] = UNFURLED_TWITTER_AVATAR_CSS_CLASS - end - end - - private - UNFURLED_TWITTER_AVATAR_CSS_CLASS = "cf-twitter-avatar" - TWITTER_AVATAR_URL_PREFIX = "https://pbs.twimg.com/profile_images" - - def unfurled_twitter_avatars - fragment.find_all(opengraph_css_selector).select do |node| - ActionText::Attachment::OpengraphEmbed.from_node(node)&.url.to_s.start_with?(TWITTER_AVATAR_URL_PREFIX) - end - end - - def opengraph_css_selector - "action-text-attachment[@content-type='#{ActionText::Attachment::OpengraphEmbed::OPENGRAPH_EMBED_CONTENT_TYPE}']" - end -end diff --git a/app/javascript/controllers/unfurl_controller.js b/app/javascript/controllers/unfurl_controller.js index 40d963b..e1b0809 100644 --- a/app/javascript/controllers/unfurl_controller.js +++ b/app/javascript/controllers/unfurl_controller.js @@ -5,7 +5,7 @@ import { escapeHTML } from "helpers/dom_helpers" const OPENGRAPH_EMBED_CONTENT_TYPE = "application/vnd.actiontext.opengraph-embed" -const UNFURLED_TWITTER_AVATAR_CSS_CLASS = "cf-twitter-avatar" +const UNFURLED_TWITTER_AVATAR_CSS_CLASS = "og-embed--twitter-avatar" const TWITTER_AVATAR_URL_PREFIX = "https://pbs.twimg.com/profile_images" export default class extends Controller { @@ -50,8 +50,8 @@ export default class extends Controller { } #opengraphEmbedHTML({ title, href, image, description }) { - return ` -
+ return ` +
${escapeHTML(truncateString(title, 280))} diff --git a/app/javascript/lib/rich_text/campfire_extension.js b/app/javascript/lib/rich_text/campfire_extension.js index 3ba60e3..3c4e5d4 100644 --- a/app/javascript/lib/rich_text/campfire_extension.js +++ b/app/javascript/lib/rich_text/campfire_extension.js @@ -9,6 +9,7 @@ export default class CampfireRichTextExtension extends Lexxy.Extension { "figcaption", "actiontext-opengraph-embed", { tag: "div", attributes: [ "sgid" ] }, + { tag: "span", attributes: [ "sgid" ] }, { tag: "img", attributes: [ "alt" ] }, { tag: "a", attributes: [ "rel", "target" ] } ] diff --git a/app/views/action_text/attachables/_opengraph_embed.html.erb b/app/views/action_text/attachables/_opengraph_embed.html.erb index 6685176..218315a 100644 --- a/app/views/action_text/attachables/_opengraph_embed.html.erb +++ b/app/views/action_text/attachables/_opengraph_embed.html.erb @@ -1,6 +1,6 @@
-
+
">
<%= link_to truncate(opengraph_embed.filename, length: 280, omission: "…"), opengraph_embed.href, rel: "noreferrer", target: "_blank" %> diff --git a/lib/rails_ext/actiontext_opengraph_embeds.rb b/lib/rails_ext/actiontext_opengraph_embeds.rb index a106d42..2e9f8f5 100644 --- a/lib/rails_ext/actiontext_opengraph_embeds.rb +++ b/lib/rails_ext/actiontext_opengraph_embeds.rb @@ -2,6 +2,7 @@ class ActionText::Attachment::OpengraphEmbed include ActiveModel::Model OPENGRAPH_EMBED_CONTENT_TYPE = "application/vnd.actiontext.opengraph-embed" + TWITTER_AVATAR_URL_PREFIX = "https://pbs.twimg.com/profile_images" class << self def from_node(node) @@ -47,6 +48,10 @@ class ActionText::Attachment::OpengraphEmbed attr_accessor :href, :url, :filename, :description + def twitter_avatar? + url.to_s.start_with?(TWITTER_AVATAR_URL_PREFIX) + end + def attachable_content_type OPENGRAPH_EMBED_CONTENT_TYPE end diff --git a/test/helpers/content_filters_test.rb b/test/helpers/content_filters_test.rb index f06d6fc..a79dd2a 100644 --- a/test/helpers/content_filters_test.rb +++ b/test/helpers/content_filters_test.rb @@ -30,20 +30,26 @@ class ContentFiltersTest < ActionView::TestCase assert_match %r{
Hello https://basecamp\.com/\n
\n
\n
37signals (@37signals)
\n
We're back up on all apps, everyone. Really sorry for the disruption to your day.
\n
\n
\n ""\n
\n
\n \">
" - message = Message.create! room: rooms(:pets), body: unfurled_message_body_for_basecamp(text), client_message_id: "0015", creator: users(:jason) + test "unfurled tweet with an avatar image gets the twitter avatar treatment" do + body = %(
https://twitter.com/37signals/status/1750290547908952568
) + message = Message.create! room: rooms(:pets), body: body, client_message_id: "0015", creator: users(:jason) - filtered = ContentFilters::StyleUnfurledTwitterAvatars.apply(message.body.body) - assert_match %r{
}, filtered.to_html + assert_match /og-embed--twitter-avatar/, message_presentation(message) end - test "unfurled tweet containing an image" do - text = "
https://twitter.com/dhh/status/1748445489648050505\n
\n
\n
DHH (@dhh)
\n
We pay homage to the glorious MIT License with the ONCE license. May all our future legalese be as succinct!
\n
\n
\n ""\n
\n
\n \">
" - message = Message.create! room: rooms(:pets), body: unfurled_message_body_for_basecamp(text), client_message_id: "0015", creator: users(:jason) + test "unfurled tweet with an avatar image in a lexxy body gets the twitter avatar treatment" do + content = %(
desc
) + body = %(

https://twitter.com/x/status/1

) + message = Message.create! room: rooms(:pets), body: body, client_message_id: "0015", creator: users(:jason) - filtered = ContentFilters::StyleUnfurledTwitterAvatars.apply(message.body.body) - assert_no_match %r{
}, filtered.to_html + assert_match /og-embed--twitter-avatar/, message_presentation(message) + end + + test "unfurled tweet with a content image is not styled as an avatar" do + body = %(
https://twitter.com/dhh/status/1748445489648050505
) + message = Message.create! room: rooms(:pets), body: body, client_message_id: "0015", creator: users(:jason) + + assert_no_match /og-embed--twitter-avatar/, message_presentation(message) end test "entire message contains an unfurled URL from x.com but unfurls to twitter.com" do