BartOtten

BartOtten

Proposal

  • Support DOM patching of the HTML link element for a favicon.
  • Add the special @page_favicon assign mimicking the @page_title assign so each page can have it’s own dynamic favicon; supporting multiple tabs for an application with different ‘statuses’.

Reason
Many modern web applications have dynamic favicons. These dynamic favicons are used to notify browser users of events or statuses. For example: unread messages or a CI build status. As those use cases are quite common, providing such functionality seems to fit the ‘no Javascript’-philosophy. Additionaly it seems to align with the automagic @page_title.

Because the root layout from the Plug pipeline is rendered outside of LiveView, the contents cannot be dynamically changed. The one exception is the <title> of the HTML document. Phoenix LiveView special cases the @page_title assign to allow dynamically updating the title of the page, which is useful when using live navigation, or annotating the browser tab with a notification. For example, to update the user’s notification count in the browser’s title bar, first set the page_title assign on mount
Live layouts — Phoenix LiveView v1.2.5

Current State

  • The HTML link element for favicons is placed in layout/root_live.html.heex. No native logic is in place to update it in the DOM and there is no @page_favicon.
  • The HTML title element is placed in `layout/root_live.html.heex. Native logic is in place to update the element in the DOM when the @page_title assignment is changed.

Todo

  • get approval for feature
  • research possibilities
  • draft design
  • get approval for design
  • implement

I am willing to work on this as contribution to the community.

Links
[LiveView Dynamic Favicon?]
[https://medium.com/@alperen.talaslioglu/building-dynamic-favicon-with-javascript-223ad7999661]

Showing Posts 1 to 10

AndyL

AndyL

Here is a working prototype for Dynamic Favicon. A streamlined solution that follows the style of live_title_tag would be great. I will help. :wink:

AndyL

AndyL

Here’s some rough design ideas:

Let there be a special assign @favicon_href

The live_favicon_tag would go into layout/root_live.html.heex

<%= live_favicon_tag assigns[:favicon_href] || "/images/favicon.ico" %>

The live_favicon_tag function would emit the following HTML

<link id="phx-favicon" rel="icon" type="image/x-icon" href="/images/favicon.ico"/>

Add an event listener to the client javascript

window.addEventListener("phx:change-favicon", (e) => {
  var href = e.detail.href 
  var fabtag = document.getElementById('phx-favicon') 
  fabtag.href = href
})

On the server, when the LiveView process detects that @favicon_href has changed, push an event to the client:

push_event(socket, "change-favicon", %{href: @favicon_href})}

With this approach, add-on packages (like live_dashboard) could add their own favicon images to priv/images, and then use their own favicons in their particular LiveViews.

10
Post #2
josevalim

josevalim

Creator of Elixir

Awesome job @AndyL! I am not sure if this is such a common use case to warrant inclusion on LiveView, but that’s all the pieces needed for anyone who wants to roll with it. :slight_smile:

PJextra

PJextra

It would be a great quick win!

BartOtten

BartOtten OP

Great example!

  • Should it support a size opt (or list of sizes and return multiple elements)?
  • SVG icons can be styled with CSS; removing the need for multiple images (in an ico container). Should it support that use case and if so, how? Blog post: Building an adaptive favicon

The other option is to keep is really simple and let a lib handle more advanced usecases :slight_smile:

AndyL

AndyL

Didn’t know about SVG icons - super nice! Pretty well supported on desktop browsers, less on mobile. Also learned that people sometimes use multiple favicon links, to give browsers an way to fall back to supported types.

I think there are two alternatives to attack this problem: manual coding like I did in the prototype, or editing LiveView itself. I don’t think this can be done with a Library, because there is no way for a Library to inject behavior into the LiveView JS. Is this right?

I looked in the LiveView code to understand live_title_tag - there seems to be three key areas in the code:

The code itself looks pretty straightforward - with a good amount of testing support.

Generating the appropriate favicon mime type could be done by checking the file extension of the href - this could be done in the javascript.

size opt

I’m not sure what the size opt does - I’ve always used ‘auto’ size.

The other option is to keep is really simple

If we could do something simple to streamline the 80% case, people could always fall back to a manual approach if needed.

BartOtten

BartOtten OP

Chose to keep the assign key generic; not sure of we can pass components to it (its too late).

If we can the favicon_tag function can use the (to be updated) DOM diffing too as no attribute is in the name. This allow for the simple approach by default using it as href when assigned a binary. Keeping the advanced usage of favicons to a lib which can simply pass a full icon link element. :slight_smile:

Too be continued….first let’s see if the draft PR survives the public exposure.

https://github.com/phoenixframework/phoenix_live_view/pull/2087

Won’t take long before you can play Doom in the browsers` tab bar…

AndyL

AndyL

PR looks great - beautiful screen shot!

I’m curious - did you intend that it should be possible to update multiple favicon links, or just one? If multiple: would you assign an array of hrefs to @favicon, or use some other convention?

BartOtten

BartOtten OP

Last night I looked at support for multiple icons

Phoenix LiveView is awesome at diffing and sending the least amount of data over the wire. I am trying to keep that in honor. As a result I have chosen to use a simple string replace.

The free schema also makes it easier to use online favicon generators that generate a bunch of PNG files for you. Just unzip and place in a subfolder of a variant. SVG scale so don’t need a subfolder. See pseudo code:

# pseudo code supports multiple schema’s
<.live_favicon href="/images/svg/@dynamic.svg" />
<.live_favicon href="/images/status/@dynamic/favicon-32x32.png" />
<.live_favicon href="/images/status/@dynamic/favicon-16x16.png" />

When a new @dynamic value is assigned, the href is split in 3 parts: prefix, @dynamic and suffix. The dynamic value is replaced with the value assigned.

static: /images/status/
dynamic: “new_message”
static: /favicon-32x32.png

Only the dynamic part is sent over the wire on socket assign updates. Just like…LiveView does already :slight_smile:

{"f": {   "dynamic": "new_message"}}

When href is defined without a dynamic, the helper assumes the user needs full control over the href and just passes it through. Thus supporting base64 encoded data and one-off use cases.

This also allow me to add ‘class’ to support those fancy dynamic SVG’s.

As you like screenshots:

BartOtten

BartOtten OP

Update: the draft PR is rejected

Not sure if the presented solution really covers the use cases as mentioned above. It does cover the simple first case in the draft though, so it’s not a surprise. Will check later.

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
psy-q
I’m trying to set up Emacs with elixir-ls via lsp-mode and credo via Flycheck. This should mostly be preconfigured as Flycheck picks up c...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews