mirror of
https://github.com/screentinker/screentinker.git
synced 2026-06-14 18:22:46 -06:00
Merge pull request #56 from screentinker/fix/branding-fouc
fix(branding): no default-brand flash on load/switch (#38)
This commit is contained in:
commit
bcdffd4f56
|
|
@ -29,8 +29,10 @@
|
|||
<line x1="8" y1="21" x2="16" y2="21"/>
|
||||
<line x1="12" y1="17" x2="12" y2="21"/>
|
||||
</svg>
|
||||
<span>ScreenTinker</span>
|
||||
<span id="brandName">ScreenTinker</span>
|
||||
</div>
|
||||
<!-- #38: apply cached white-label before first paint (no ScreenTinker flash) -->
|
||||
<script src="/js/brand-prime.js"></script>
|
||||
<div class="workspace-switcher" id="workspaceSwitcher"></div>
|
||||
</div>
|
||||
<ul class="nav-links">
|
||||
|
|
|
|||
44
frontend/js/brand-prime.js
Normal file
44
frontend/js/brand-prime.js
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// Render-blocking branding primer (#38). Loaded as a synchronous same-origin
|
||||
// <script> right after the sidebar logo, so it runs DURING parse, before first
|
||||
// paint — applying the current workspace's CACHED white-label so the page paints
|
||||
// branded instead of flashing the "ScreenTinker" default. branding.js then
|
||||
// refreshes it from the server and re-writes the cache. Plain script (not a
|
||||
// module) so it's not deferred; keyed by workspace so a switch shows the right
|
||||
// brand (or the neutral default for a workspace we haven't cached yet).
|
||||
(function () {
|
||||
try {
|
||||
var token = localStorage.getItem('token');
|
||||
if (!token) return;
|
||||
var ws = 'none';
|
||||
try {
|
||||
var seg = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/');
|
||||
ws = (JSON.parse(atob(seg)) || {}).current_workspace_id || 'none';
|
||||
} catch (e) { /* malformed token -> treat as no workspace */ }
|
||||
|
||||
var wl = JSON.parse(localStorage.getItem('rd_branding_' + ws) || 'null');
|
||||
if (!wl) return;
|
||||
|
||||
var root = document.documentElement;
|
||||
if (wl.primary_color) root.style.setProperty('--accent', wl.primary_color);
|
||||
if (wl.bg_color) {
|
||||
root.style.setProperty('--bg-primary', wl.bg_color);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', wl.bg_color);
|
||||
}
|
||||
if (wl.brand_name) {
|
||||
document.title = wl.brand_name;
|
||||
var span = document.getElementById('brandName');
|
||||
if (span) span.textContent = wl.brand_name;
|
||||
}
|
||||
if (wl.favicon_url) {
|
||||
var links = document.querySelectorAll('link[rel="icon"], link[rel="apple-touch-icon"]');
|
||||
for (var i = 0; i < links.length; i++) links[i].setAttribute('href', wl.favicon_url);
|
||||
}
|
||||
if (wl.custom_css) {
|
||||
var s = document.createElement('style');
|
||||
s.id = 'wl-custom-css';
|
||||
s.textContent = wl.custom_css;
|
||||
document.head.appendChild(s);
|
||||
}
|
||||
} catch (e) { /* never let branding break boot */ }
|
||||
})();
|
||||
|
|
@ -6,6 +6,15 @@
|
|||
|
||||
let applied = false;
|
||||
|
||||
// Current workspace id from the JWT, so the branding cache (read render-blocking by
|
||||
// brand-prime.js) is keyed per workspace — a switch shows the right brand. (#38)
|
||||
function currentWorkspaceId() {
|
||||
try {
|
||||
const seg = localStorage.getItem('token').split('.')[1].replace(/-/g, '+').replace(/_/g, '/');
|
||||
return (JSON.parse(atob(seg)) || {}).current_workspace_id || 'none';
|
||||
} catch { return 'none'; }
|
||||
}
|
||||
|
||||
export async function applyBranding() {
|
||||
if (applied) return;
|
||||
applied = true;
|
||||
|
|
@ -21,6 +30,9 @@ export async function applyBranding() {
|
|||
} catch { return; }
|
||||
if (!wl) return;
|
||||
|
||||
// Cache for the next load/switch so brand-prime.js can apply it before paint.
|
||||
try { localStorage.setItem('rd_branding_' + currentWorkspaceId(), JSON.stringify(wl)); } catch {}
|
||||
|
||||
const root = document.documentElement;
|
||||
if (wl.primary_color) root.style.setProperty('--accent', wl.primary_color);
|
||||
if (wl.bg_color) {
|
||||
|
|
@ -31,7 +43,7 @@ export async function applyBranding() {
|
|||
|
||||
if (wl.brand_name) {
|
||||
document.title = wl.brand_name;
|
||||
const span = document.querySelector('.sidebar-header .logo span');
|
||||
const span = document.getElementById('brandName');
|
||||
if (span) span.textContent = wl.brand_name;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue