Centralize shell bridge glue
This commit is contained in:
parent
147a09035c
commit
a9976c54ae
4 changed files with 103 additions and 46 deletions
|
|
@ -7777,7 +7777,7 @@
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"></script>
|
||||||
{{ vite_assets('body')|safe }}
|
{{ vite_assets('body')|safe }}
|
||||||
<script src="{{ url_for('static', filename='setup-wizard.js', v=static_v) }}"></script>
|
<script src="{{ url_for('static', filename='setup-wizard.js', v=static_v) }}"></script>
|
||||||
<!-- Split modules (was: script.js) — core.js must load first, init.js last -->
|
<!-- Split modules (was: script.js) — core.js must load first, init.js before shell-bridge.js -->
|
||||||
<script src="{{ url_for('static', filename='core.js', v=static_v) }}"></script>
|
<script src="{{ url_for('static', filename='core.js', v=static_v) }}"></script>
|
||||||
<script src="{{ url_for('static', filename='shared-helpers.js', v=static_v) }}"></script>
|
<script src="{{ url_for('static', filename='shared-helpers.js', v=static_v) }}"></script>
|
||||||
<script src="{{ url_for('static', filename='media-player.js', v=static_v) }}"></script>
|
<script src="{{ url_for('static', filename='media-player.js', v=static_v) }}"></script>
|
||||||
|
|
@ -7796,6 +7796,7 @@
|
||||||
<script src="{{ url_for('static', filename='stats-automations.js', v=static_v) }}"></script>
|
<script src="{{ url_for('static', filename='stats-automations.js', v=static_v) }}"></script>
|
||||||
<script src="{{ url_for('static', filename='pages-extra.js', v=static_v) }}"></script>
|
<script src="{{ url_for('static', filename='pages-extra.js', v=static_v) }}"></script>
|
||||||
<script src="{{ url_for('static', filename='init.js', v=static_v) }}"></script>
|
<script src="{{ url_for('static', filename='init.js', v=static_v) }}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='shell-bridge.js', v=static_v) }}"></script>
|
||||||
<!-- Notification bell + floating helper toggle — always accessible above modals -->
|
<!-- Notification bell + floating helper toggle — always accessible above modals -->
|
||||||
<!-- Ambient glow under the global search bar. Radial gradient, brightest
|
<!-- Ambient glow under the global search bar. Radial gradient, brightest
|
||||||
directly under the bar, tapering out toward the window corners.
|
directly under the bar, tapering out toward the window corners.
|
||||||
|
|
|
||||||
2
webui/src/platform/shell/globals.d.ts
vendored
2
webui/src/platform/shell/globals.d.ts
vendored
|
|
@ -30,7 +30,7 @@ declare global {
|
||||||
};
|
};
|
||||||
SoulSyncWebShellBridge?: {
|
SoulSyncWebShellBridge?: {
|
||||||
getCurrentPageId: () => ShellPageId;
|
getCurrentPageId: () => ShellPageId;
|
||||||
getCurrentProfileContext: () => ShellProfileContext;
|
getCurrentProfileContext: () => ShellProfileContext | null;
|
||||||
isPageAllowed: (pageId: ShellPageId) => boolean;
|
isPageAllowed: (pageId: ShellPageId) => boolean;
|
||||||
getProfileHomePage: () => ShellPageId;
|
getProfileHomePage: () => ShellPageId;
|
||||||
resolveLegacyPath: (pathname: string) => ShellPageId | null;
|
resolveLegacyPath: (pathname: string) => ShellPageId | null;
|
||||||
|
|
|
||||||
|
|
@ -329,50 +329,6 @@ function activatePage(pageId, options = {}) {
|
||||||
loadPageData(pageId);
|
loadPageData(pageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function activateLegacyPath(pathname) {
|
|
||||||
const router = getWebRouter();
|
|
||||||
const targetPage = router?.resolvePageId?.(pathname) || _getPageFromPath(pathname);
|
|
||||||
if (!targetPage) return;
|
|
||||||
|
|
||||||
if (!isPageAllowed(targetPage)) {
|
|
||||||
const home = getProfileHomePage();
|
|
||||||
if (home !== targetPage) {
|
|
||||||
navigateToPage(home, { replace: true });
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
activatePage(targetPage, { forceReload: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
const SHELL_BRIDGE_READY_EVENT = 'ss:webui-shell-bridge-ready';
|
|
||||||
|
|
||||||
window.SoulSyncWebShellBridge = {
|
|
||||||
getCurrentPageId() {
|
|
||||||
return currentPage || getWebRouter()?.resolvePageId?.(window.location.pathname) || _getPageFromPath();
|
|
||||||
},
|
|
||||||
getCurrentProfileContext() {
|
|
||||||
return getCurrentProfileContext();
|
|
||||||
},
|
|
||||||
isPageAllowed(pageId) {
|
|
||||||
return isPageAllowed(pageId);
|
|
||||||
},
|
|
||||||
getProfileHomePage() {
|
|
||||||
return getProfileHomePage();
|
|
||||||
},
|
|
||||||
setActivePageChrome(pageId) {
|
|
||||||
setActivePageChrome(pageId);
|
|
||||||
},
|
|
||||||
activateLegacyPath(pathname) {
|
|
||||||
activateLegacyPath(pathname);
|
|
||||||
},
|
|
||||||
showReactHost(pageId) {
|
|
||||||
showReactHost(pageId);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
window.dispatchEvent(new CustomEvent(SHELL_BRIDGE_READY_EVENT));
|
|
||||||
|
|
||||||
function renderProfileAvatar(el, profile) {
|
function renderProfileAvatar(el, profile) {
|
||||||
// Renders avatar as image (if avatar_url set) or colored initial fallback
|
// Renders avatar as image (if avatar_url set) or colored initial fallback
|
||||||
// Preserves existing classes, ensures 'profile-avatar' is present
|
// Preserves existing classes, ensures 'profile-avatar' is present
|
||||||
|
|
|
||||||
100
webui/static/shell-bridge.js
Normal file
100
webui/static/shell-bridge.js
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
// SoulSync shell bridge glue
|
||||||
|
// Keep this file loaded after init.js so the legacy shell helpers it wraps
|
||||||
|
// have already been defined.
|
||||||
|
|
||||||
|
function getWebRouter() {
|
||||||
|
return window.SoulSyncWebRouter ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLegacyPage(pageId) {
|
||||||
|
document.querySelectorAll('.page').forEach(page => {
|
||||||
|
page.classList.remove('active');
|
||||||
|
});
|
||||||
|
const page = document.getElementById(`${pageId}-page`);
|
||||||
|
if (page) {
|
||||||
|
page.classList.add('active');
|
||||||
|
}
|
||||||
|
const reactHost = document.getElementById('webui-react-root');
|
||||||
|
if (reactHost) {
|
||||||
|
reactHost.classList.remove('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActivePageChrome(pageId) {
|
||||||
|
document.querySelectorAll('.nav-button').forEach(btn => {
|
||||||
|
btn.classList.remove('active');
|
||||||
|
});
|
||||||
|
const navButton = document.querySelector(`[data-page="${pageId}"]`);
|
||||||
|
if (navButton) {
|
||||||
|
navButton.classList.add('active');
|
||||||
|
}
|
||||||
|
currentPage = pageId;
|
||||||
|
if (typeof _gsUpdateVisibility === 'function') _gsUpdateVisibility();
|
||||||
|
if (window.pageParticles && window._particlesEnabled !== false) window.pageParticles.setPage(pageId);
|
||||||
|
if (window.workerOrbs) window.workerOrbs.setPage(pageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showReactHost(pageId) {
|
||||||
|
document.querySelectorAll('.page').forEach(page => {
|
||||||
|
page.classList.remove('active');
|
||||||
|
});
|
||||||
|
const host = document.getElementById('webui-react-root');
|
||||||
|
if (host) {
|
||||||
|
host.classList.add('active');
|
||||||
|
}
|
||||||
|
currentPage = pageId;
|
||||||
|
if (typeof _gsUpdateVisibility === 'function') _gsUpdateVisibility();
|
||||||
|
if (window.pageParticles && window._particlesEnabled !== false) window.pageParticles.setPage(pageId);
|
||||||
|
if (window.workerOrbs) window.workerOrbs.setPage(pageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function activateLegacyPath(pathname) {
|
||||||
|
const router = getWebRouter();
|
||||||
|
const targetPage = router?.resolvePageId?.(pathname) || _getPageFromPath(pathname);
|
||||||
|
if (!targetPage) return;
|
||||||
|
|
||||||
|
if (!isPageAllowed(targetPage)) {
|
||||||
|
const home = getProfileHomePage();
|
||||||
|
if (home !== targetPage) {
|
||||||
|
navigateToPage(home, { replace: true });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
activatePage(targetPage, { forceReload: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const SHELL_BRIDGE_READY_EVENT = 'ss:webui-shell-bridge-ready';
|
||||||
|
|
||||||
|
window.SoulSyncWebShellBridge = {
|
||||||
|
getCurrentPageId() {
|
||||||
|
return currentPage || getWebRouter()?.resolvePageId?.(window.location.pathname) || _getPageFromPath();
|
||||||
|
},
|
||||||
|
getCurrentProfileContext() {
|
||||||
|
if (!currentProfile) return null;
|
||||||
|
return {
|
||||||
|
profileId: currentProfile.id,
|
||||||
|
isAdmin: !!currentProfile.is_admin,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
isPageAllowed(pageId) {
|
||||||
|
return isPageAllowed(pageId);
|
||||||
|
},
|
||||||
|
getProfileHomePage() {
|
||||||
|
return getProfileHomePage();
|
||||||
|
},
|
||||||
|
resolveLegacyPath(pathname) {
|
||||||
|
return getWebRouter()?.resolvePageId?.(pathname) ?? null;
|
||||||
|
},
|
||||||
|
setActivePageChrome(pageId) {
|
||||||
|
setActivePageChrome(pageId);
|
||||||
|
},
|
||||||
|
activateLegacyPath(pathname) {
|
||||||
|
activateLegacyPath(pathname);
|
||||||
|
},
|
||||||
|
showReactHost(pageId) {
|
||||||
|
showReactHost(pageId);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
window.dispatchEvent(new CustomEvent(SHELL_BRIDGE_READY_EVENT));
|
||||||
Loading…
Reference in a new issue