Skip to content

Commit

Permalink
Merge pull request #1403 from Retrospring/feature/avatar-component
Browse files Browse the repository at this point in the history
Install `view_component` and add initial `AvatarComponent`
  • Loading branch information
raccube authored Oct 22, 2023
2 parents 3dbbcd1 + 0e68a67 commit 2432010
Show file tree
Hide file tree
Showing 27 changed files with 108 additions and 20 deletions.
4 changes: 4 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ Lint/NestedMethodDefinition:
Exclude:
- api/sinatra/**/*

Lint/MissingSuper:
Exclude:
- app/components/**/*


### Metrics

Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ gem "fake_email_validator"
# TLD validation
gem "tldv", "~> 0.1.0"

gem "view_component"

gem "jwt", "~> 2.7"

group :development do
Expand Down
5 changes: 5 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@ GEM
unf_ext (0.0.8)
unicode-display_width (2.5.0)
uniform_notifier (1.16.0)
view_component (3.6.0)
activesupport (>= 5.2.0, < 8.0)
concurrent-ruby (~> 1.0)
method_source (~> 1.0)
warden (1.2.9)
rack (>= 2.0.9)
webpush (1.1.0)
Expand Down Expand Up @@ -580,6 +584,7 @@ DEPENDENCIES
tldv (~> 0.1.0)
turbo-rails
twitter-text
view_component

BUNDLED WITH
2.4.21
4 changes: 4 additions & 0 deletions app/components/avatar_component.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
%img{ class: avatar_classes,
alt: alt_text,
src: avatar_image,
loading: :lazy }
30 changes: 30 additions & 0 deletions app/components/avatar_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

class AvatarComponent < ViewComponent::Base
ALLOWED_SIZES = %w[xs sm md lg xl xxl].freeze

def initialize(user:, size:, classes: [])
@user = user
@size = size if ALLOWED_SIZES.include? size
@classes = classes
end

private

def size_to_version(size)
case size
when "xs", "sm"
:small
when "md", "lg"
:medium
when "xl", "xxl"
:large
end
end

def alt_text = "@#{@user.screen_name}"

def avatar_classes = @classes.unshift("avatar-#{@size}")

def avatar_image = @user.profile_picture.url(size_to_version(@size))
end
2 changes: 1 addition & 1 deletion app/views/answerbox/_comments.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
.d-flex
.flex-shrink-0
%a{ href: user_path(comment.user) }
%img.comment__user-avatar.avatar-sm{ src: comment.user.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user: comment.user, size: "sm", classes: ["comment__user-avatar"])
.flex-grow-1
%h6.comment__user
= user_screen_name comment.user
Expand Down
2 changes: 1 addition & 1 deletion app/views/answerbox/_header.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
- unless a.question.author_is_anonymous
.flex-shrink-0
%a{ href: user_path(a.question.user) }
%img.answerbox__question-user-avatar.avatar-md{ src: a.question.user.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user: a.question.user, size: "md", classes: ["answerbox__question-user-avatar"])
.flex-grow-1
%h6.text-muted.answerbox__question-user
- if a.question.author_is_anonymous
Expand Down
2 changes: 1 addition & 1 deletion app/views/answerbox/_smiles.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
%a{ href: user_path(smile.user),
title: user_screen_name(smile.user, url: false),
data: { bs_toggle: :tooltip, bs_placement: :top, smile_id: smile.id } }
%img.avatar-xs{ src: smile.user.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user: smile.user, size: "xs")
2 changes: 1 addition & 1 deletion app/views/application/_answerbox.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
.d-flex
.flex-shrink-0
%a{ href: user_path(a.user) }
%img.answerbox__answer-user-avatar.avatar-sm{ src: a.user.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user: a.user, size: "sm", classes: ["answerbox__answer-user-avatar"])
.flex-grow-1
%h6.answerbox__answer-user
= raw t(".answered", hide: hidespan(t(".hide"), "d-none d-sm-inline"), user: user_screen_name(a.user))
Expand Down
2 changes: 1 addition & 1 deletion app/views/discover/_userbox.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
.d-flex
.flex-shrink-0
%a{ href: user_path(u) }
%img.avatar-md.me-2{ src: u.profile_picture.url(:medium) }
= render AvatarComponent.new(user: u, size: "md", classes: ["me-2"])
.flex-grow-1
%h6.answerbox__question-user
- if u.profile.display_name.blank?
Expand Down
2 changes: 1 addition & 1 deletion app/views/inbox/_entry.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
- unless i.question.author_is_anonymous
.flex-shrink-0
%a.pull-left{ href: user_path(i.question.user) }
%img.answerbox__question-user-avatar.avatar-md{ src: i.question.user.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user: i.question.user, size: "md", classes: ["answerbox__question-user-avatar"])
.flex-grow-1
%h6.text-muted.answerbox__question-user
- if i.question.author_is_anonymous
Expand Down
2 changes: 1 addition & 1 deletion app/views/moderation/_moderationbox.html.haml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.card.moderationbox{ data: { id: report.id } }
.card-header
%img.avatar-sm{ src: report.user.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user: report.user, size: "sm")
= t(".reported_html",
user: user_screen_name(report.user),
content: report.type.sub("Reports::", ""),
Expand Down
2 changes: 1 addition & 1 deletion app/views/moderation/inbox/_header.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
.d-flex
.flex-shrink-0
%a{ href: user_path(user) }
%img.answerbox__question-user-avatar.avatar-md{ src: user.profile_picture.url(:medium) }
= render AvatarComponent.new(user:, size: "md", classes: ["answerbox__question-user-avatar"])
.flex-grow-1
= t(".title_html", screen_name: user.screen_name, user_id: user.id)
2 changes: 1 addition & 1 deletion app/views/navigation/_desktop.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
%i.fa.fa-pencil-square-o
%li.nav-item.dropdown.profile--image-dropdown
%a.nav-link.dropdown-toggle.p-sm-0{ href: "#", data: { bs_toggle: :dropdown } }
%img.avatar-md.d-none.d-sm-inline{ src: current_user.profile_picture.url(:small) }
= render AvatarComponent.new(user: current_user, size: "md", classes: ["d-none", "d-sm-inline"])
%span.d-inline.d-sm-none
= current_user.screen_name
%b.caret
Expand Down
2 changes: 1 addition & 1 deletion app/views/navigation/_mobile.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
badge: notification_count, badge_color: "primary", badge_attr: { id: "notification-mobile-count" }, icon_only: true
%li.nav-item.profile--image-dropdown
%a.nav-link{ href: '#', data: { bs_toggle: 'dropdown', bs_target: '#rs-mobile-nav-profile' }, aria: { controls: 'rs-mobile-nav-profile', expanded: 'false' } }

Check warning on line 14 in app/views/navigation/_mobile.html.haml

View workflow job for this annotation

GitHub Actions / haml-lint

[haml-lint] app/views/navigation/_mobile.html.haml#L14

LineLength: Line is too long. [166/160]
Raw output
app/views/navigation/_mobile.html.haml:14 [W] LineLength: Line is too long. [166/160]
%img.avatar-md.d-inline{ src: current_user.profile_picture.url(:small) }
= render AvatarComponent.new(user: current_user, size: "md", classes: ["d-inline"])
= render 'navigation/dropdown/profile', size: "mobile"
2 changes: 1 addition & 1 deletion app/views/notifications/type/_answer.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
%i.fa.fa-2x.fa-fw.fa-exclamation
.flex-grow-1
.notification__heading
%img.avatar-xs{ src: notification.target.user.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user: notification.target.user, size: "xs")
= t(".heading_html",
user: user_screen_name(notification.target.user),
question: link_to(t(".link_text"), answer_path(username: notification.target.user.screen_name, id: notification.target.id), target: "_top"),
Expand Down
2 changes: 1 addition & 1 deletion app/views/notifications/type/_comment.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
%i.fa.fa-2x.fa-fw.fa-comments
.flex-grow-1
.notification__heading
%img.avatar-xs{ src: notification.target.user.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user: notification.target.user, size: "xs")
- if notification.target.answer.user == current_user
= t(".heading_html",
user: user_screen_name(notification.target.user),
Expand Down
2 changes: 1 addition & 1 deletion app/views/notifications/type/_follow.html.haml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.d-flex.notification
.flex-shrink-0.notification__icon
%img.avatar-sm{ src: notification.target.source.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user: notification.target.source, size: "sm")
.flex-grow-1
%h6.notification__user
= user_screen_name notification.target.source
Expand Down
2 changes: 1 addition & 1 deletion app/views/notifications/type/_reaction.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
%i.fa.fa-2x.fa-fw.fa-smile-o
.flex-grow-1
.notification__heading
%img.avatar-xs{ src: notification.target.user.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user: notification.target.user, size: "xs")
- if notification.target.parent_type == "Answer"
= t(".heading_html",
user: user_screen_name(notification.target.user),
Expand Down
2 changes: 1 addition & 1 deletion app/views/question/_question.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- unless question.author_is_anonymous
.flex-shrink-0
%a{ href: unless hidden then user_path(question.user) end }
%img.answerbox__question-user-avatar.avatar-md{ src: question.user.profile_picture.url(:small) }
= render AvatarComponent.new(user: question.user, size: "md", classes: ["answerbox__question-user-avatar"])
.flex-grow-1
%h6.text-muted.answerbox__question-user
- identifier = question.author_is_anonymous ? question.author_identifier : nil
Expand Down
2 changes: 1 addition & 1 deletion app/views/settings/blocks/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
- @blocks.each do |block|
%li.list-group-item
.d-flex
%img.avatar-md.d-none.d-sm-inline.me-2{ src: block.target.profile_picture.url(:small) }
= render AvatarComponent.new(user: block.target, size: "md", classes: ["d-none", "d-sm-inline", "me-2"])
%div
%p.mb-0= user_screen_name(block.target)
%p.text-muted.mb-0= t(".blocked", time: time_ago_in_words(block.created_at))
Expand Down
2 changes: 1 addition & 1 deletion app/views/settings/mutes/_user.html.haml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.d-flex.mb-2
%img.avatar-md.me-2{ src: user.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user:, size: "md", classes: ["me-2"])
%p.align-self-center.m-0= user_screen_name(user, context_user: current_user)
.ms-auto.d-inline-flex
%button.btn.btn-default.align-self-center{ data: { action: :unmute, target: user.screen_name } }
Expand Down
2 changes: 1 addition & 1 deletion app/views/settings/profile/edit.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
%div{ data: { controller: "cropper", cropper_aspect_ratio_value: "1" } }
.d-flex
.flex-shrink-0
%img.avatar-lg.me-3{ src: current_user.profile_picture.url(:medium) }
= render AvatarComponent.new(user: current_user, size: "lg", classes: ["me-3"])
.flex-grow-1
= f.file_field :profile_picture, accept: APP_CONFIG[:accepted_image_formats].join(","), data: { cropper_target: "input", action: "cropper#change" }

Expand Down
2 changes: 1 addition & 1 deletion app/views/shared/_question.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- if type == "discover"
.flex-shrink-0
%a{ href: user_screen_name(q.user, link_only: true) }
%img.avatar-md.me-2{ src: q.user&.profile_picture&.url(:small), loading: :lazy }
= render AvatarComponent.new(user: q.user, size: "md", classes: ["me-2"])
.flex-grow-1
%h6.text-muted.answerbox__question-user
- if type.nil? && q.direct
Expand Down
2 changes: 1 addition & 1 deletion app/views/tabs/_feed.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
%p.px-4.pb-2
- list.members.each do |member|
%a{ href: user_path(member.user), title: member.user.screen_name, data: { bs_toggle: :tooltip, bs_placement: :top } }
%img.avatar-xs{ src: member.user.profile_picture.url(:small), loading: :lazy }
= render AvatarComponent.new(user: member.user, size: "xs")
- if !list && lists.empty?
.p-3= t(".lists.notice_html")
- lists.each do |list|
Expand Down
39 changes: 39 additions & 0 deletions spec/components/avatar_component_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe AvatarComponent, type: :component do
let(:user) { FactoryBot.create(:user) }

it "renders an avatar" do
expect(
render_inline(described_class.new(user:, size: "sm")).to_html,
).to include(
"no_avatar.png",
)
end

it "gets the medium version of a profile picture if requested" do
expect(
render_inline(described_class.new(user:, size: "md")).to_html,
).to include(
"medium/",
)
end

it "gets the large version of a profile picture if requested" do
expect(
render_inline(described_class.new(user:, size: "xl")).to_html,
).to include(
"large/",
)
end

it "includes additionally passed classes" do
expect(
render_inline(described_class.new(user:, size: "md", classes: %w[first-class second-class])).to_html,
).to include(
'class="avatar-md first-class second-class"',
)
end
end
4 changes: 4 additions & 0 deletions spec/rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
require "rspec/its"
require "devise"
require "rspec-sidekiq"
require "view_component/test_helpers"
require "view_component/system_test_helpers"

# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
Expand Down Expand Up @@ -68,6 +70,8 @@
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :helper
config.include Devise::Test::ControllerHelpers, type: :view
config.include ViewComponent::TestHelpers, type: :component
config.include ViewComponent::SystemTestHelpers, type: :component
end

Shoulda::Matchers.configure do |config|
Expand Down

0 comments on commit 2432010

Please sign in to comment.