Hello @jbudd
Thank you for your response.
In the meantime, I made some progress (with the help of Gemini AI)
You asked:
Maybe a screen capture would clarify?

As you can see, I now have a logo after the text "Dashboard"
Maybe it is not that nice, but okay, it is an image.
My first step , was a ui-template node, with the following contents:
<template>
<Teleport v-if="mounted" to="#app-bar-title">
<img height="32px" :src="msg.payload"></img>
</Teleport>
</template>
<script>
export default {
data() {
return {
mounted: false
}
},
mounted() {
this.mounted = true
}
}
</script>
I injected the image, as msg.payload, containing a buffered object in this template node.
Perhaps it should have been "base64" encoded, but I did not test that.
It displayed the icon of a file, instead of the desired logo.
But,
With the help of Gemini AI, I got a new script for the ui-template node:
<template>
<!-- Teleport hooks directly into the existing app bar title element -->
<Teleport v-if="isMounted" to="#app-bar-title">
<img src="/logo.png" class="app-bar-logo" alt="Logo" />
</Teleport>
</template>
<script>
export default {
data() {
return {
isMounted: false
}
},
mounted() {
this.isMounted = true;
this.$nextTick(() => {
const titleEl = document.querySelector('#app-bar-title');
if (titleEl) {
titleEl.style.display = 'inline-flex';
titleEl.style.alignItems = 'center';
titleEl.style.flexDirection = 'row'; // Forces standard left-to-right order
titleEl.style.gap = '12px'; // Spacing between logo and text
}
});
}
}
</script>
<style>
.app-bar-logo {
width: 32px !important;
height: 32px !important;
min-width: 32px !important;
min-height: 32px !important;
object-fit: contain;
/* Force this element to render first in the flex container */
order: -1 !important;
}
</style>
This new script gave the result, as shown above, but the script is supposed the put the image in front of the text "Dashboard¨, which it does not.
Then Gemini suggested a more aggressive script, that should do it. But that does not work, either.
<template>
<!-- Teleport still drops the image safely inside the app bar container -->
<Teleport v-if="isMounted" to="#app-bar-title">
<img id="ff-app-logo" src="/logo.png" class="app-bar-logo" alt="Logo" />
</Teleport>
</template>
<script>
export default {
data() {
return {
isMounted: false
}
},
mounted() {
this.isMounted = true;
// Wait for Vue to fully render the element into the layout
this.$nextTick(() => {
const checkExist = setInterval(() => {
const titleEl = document.querySelector('#app-bar-title');
const logoEl = document.querySelector('#ff-app-logo');
if (titleEl && logoEl) {
clearInterval(checkExist); // Stop searching once found
// FORCE DOM RE-ORDER: Physically moves the logo to the absolute first position
titleEl.insertBefore(logoEl, titleEl.firstChild);
// Apply structural layout adjustments to guarantee alignment
titleEl.style.setProperty('display', 'inline-flex', 'important');
titleEl.style.setProperty('align-items', 'center', 'important');
titleEl.style.setProperty('flex-direction', 'row', 'important');
titleEl.style.setProperty('gap', '12px', 'important');
}
}, 100); // Check every 100ms until the dashboard finishes drawing
});
}
}
</script>
<style>
/* Forces the layout constraints onto the image element */
.app-bar-logo {
width: 32px !important;
height: 32px !important;
min-width: 32px !important;
min-height: 32px !important;
object-fit: contain !important;
margin-right: 4px !important; /* Visual padding cushion */
}
</style>
A file logo.png has been copied into a folder in the .node-red folder.
Also the Settings.js file has been modified.
Perhaps. you see something, that is wrong, in order to get the logo in front of the text,?
If not I'm fine with the current solution.
Regards