Skip to content

Commit da55705

Browse files
committed
[Bug Fix] Add Avatar image fallback handling (#259)
1 parent c13b7e1 commit da55705

7 files changed

Lines changed: 77 additions & 1 deletion

File tree

docs/app/javascript/controllers/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ application.register("ruby-ui--accordion", RubyUi__AccordionController)
1313
import RubyUi__AlertDialogController from "./ruby_ui/alert_dialog_controller"
1414
application.register("ruby-ui--alert-dialog", RubyUi__AlertDialogController)
1515

16+
import RubyUi__AvatarController from "./ruby_ui/avatar_controller"
17+
application.register("ruby-ui--avatar", RubyUi__AvatarController)
18+
1619
import RubyUi__CalendarController from "./ruby_ui/calendar_controller"
1720
application.register("ruby-ui--calendar", RubyUi__CalendarController)
1821

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Controller } from "@hotwired/stimulus";
2+
3+
export default class extends Controller {
4+
static targets = ["image", "fallback"];
5+
6+
connect() {
7+
if (!this.hasImageTarget) return;
8+
9+
if (this.imageTarget.complete && this.imageTarget.naturalWidth > 0) {
10+
this.showImage();
11+
} else {
12+
this.showFallback();
13+
}
14+
}
15+
16+
showImage() {
17+
this.imageTargets.forEach((image) => image.classList.remove("hidden"));
18+
this.fallbackTargets.forEach((fallback) =>
19+
fallback.classList.add("hidden"),
20+
);
21+
}
22+
23+
showFallback() {
24+
this.imageTargets.forEach((image) => image.classList.add("hidden"));
25+
this.fallbackTargets.forEach((fallback) =>
26+
fallback.classList.remove("hidden"),
27+
);
28+
}
29+
}

gem/lib/ruby_ui/avatar/avatar.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ def view_template(&)
2424

2525
def default_attrs
2626
{
27+
data: {
28+
controller: "ruby-ui--avatar"
29+
},
2730
class: ["relative flex shrink-0 overflow-hidden rounded-full", @size_classes]
2831
}
2932
end
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Controller } from "@hotwired/stimulus";
2+
3+
export default class extends Controller {
4+
static targets = ["image", "fallback"];
5+
6+
connect() {
7+
if (!this.hasImageTarget) return;
8+
9+
if (this.imageTarget.complete && this.imageTarget.naturalWidth > 0) {
10+
this.showImage();
11+
} else {
12+
this.showFallback();
13+
}
14+
}
15+
16+
showImage() {
17+
this.imageTargets.forEach((image) => image.classList.remove("hidden"));
18+
this.fallbackTargets.forEach((fallback) =>
19+
fallback.classList.add("hidden"),
20+
);
21+
}
22+
23+
showFallback() {
24+
this.imageTargets.forEach((image) => image.classList.add("hidden"));
25+
this.fallbackTargets.forEach((fallback) =>
26+
fallback.classList.remove("hidden"),
27+
);
28+
}
29+
}

gem/lib/ruby_ui/avatar/avatar_fallback.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ def view_template(&)
1010

1111
def default_attrs
1212
{
13+
data: {
14+
ruby_ui__avatar_target: "fallback"
15+
},
1316
class: "flex h-full w-full items-center justify-center rounded-full bg-muted"
1417
}
1518
end

gem/lib/ruby_ui/avatar/avatar_image.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ def view_template
1717
def default_attrs
1818
{
1919
loading: "lazy",
20-
class: "aspect-square h-full w-full",
20+
data: {
21+
ruby_ui__avatar_target: "image",
22+
action: "load->ruby-ui--avatar#showImage error->ruby-ui--avatar#showFallback"
23+
},
24+
class: "hidden aspect-square h-full w-full",
2125
alt: @alt,
2226
src: @src
2327
}

gem/test/ruby_ui/avatar_test.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,10 @@ def test_render_with_all_items
1212
end
1313

1414
assert_match(/joeldrapper/, output)
15+
assert_match(/data-controller="ruby-ui--avatar"/, output)
16+
assert_match(/data-ruby-ui--avatar-target="image"/, output)
17+
assert_match(/load->ruby-ui--avatar#showImage error->ruby-ui--avatar#showFallback/, output)
18+
assert_match(/data-ruby-ui--avatar-target="fallback"/, output)
19+
assert_match(/hidden aspect-square/, output)
1520
end
1621
end

0 commit comments

Comments
 (0)