mirror of
https://github.com/johndoe6345789/AutoMetabuilder.git
synced 2026-04-24 13:54:59 +00:00
Enhance UI components and add Theme/Navigation Managers:
- Refactor `app_context.js` for async context loading and translation handling. - Introduce `ThemeManager` for dynamic theme control. - Add `NavigationManager` for improved section navigation. - Expose new `/api/ui-context` endpoint for UI context data.
This commit is contained in:
@@ -369,6 +369,11 @@ async def update_settings(request: Request, username: str = Depends(get_current_
|
||||
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
|
||||
@app.get("/api/ui-context", response_class=JSONResponse)
|
||||
async def get_ui_context(username: str = Depends(get_current_user)):
|
||||
ui_messages, ui_lang = get_ui_messages()
|
||||
return {"lang": ui_lang, "messages": ui_messages}
|
||||
|
||||
@app.get("/api/status")
|
||||
async def get_status(username: str = Depends(get_current_user)):
|
||||
return {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* AutoMetabuilder - Shared Context
|
||||
*/
|
||||
(() => {
|
||||
const translations = window.AMB_I18N || {};
|
||||
let translations = {};
|
||||
const t = (key, fallback = '') => translations[key] || fallback || key;
|
||||
const format = (text, values = {}) => text.replace(/\{(\w+)\}/g, (_, name) => values[name] ?? '');
|
||||
const authHeaders = (() => {
|
||||
@@ -13,9 +13,31 @@
|
||||
return { Authorization: `Basic ${token}` };
|
||||
})();
|
||||
|
||||
window.AMBContext = {
|
||||
const context = {
|
||||
t,
|
||||
format,
|
||||
authHeaders
|
||||
authHeaders,
|
||||
lang: 'en',
|
||||
ready: null
|
||||
};
|
||||
|
||||
const loadContext = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/ui-context', {
|
||||
credentials: 'include',
|
||||
headers: authHeaders || {}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`UI context fetch failed: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
translations = data.messages || {};
|
||||
context.lang = data.lang || 'en';
|
||||
} catch (error) {
|
||||
console.error('Failed to load UI context', error);
|
||||
}
|
||||
};
|
||||
|
||||
context.ready = loadContext();
|
||||
window.AMBContext = context;
|
||||
})();
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
};
|
||||
|
||||
const initAll = async () => {
|
||||
if (window.AMBContext?.ready) {
|
||||
await window.AMBContext.ready;
|
||||
}
|
||||
for (const plugin of plugins) {
|
||||
try {
|
||||
await plugin.init();
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* AutoMetabuilder - Navigation Manager
|
||||
*/
|
||||
(() => {
|
||||
const NavigationManager = {
|
||||
_popstateBound: false,
|
||||
|
||||
init() {
|
||||
this.bindLinks();
|
||||
this.activateFromHash(false);
|
||||
if (!this._popstateBound) {
|
||||
window.addEventListener('popstate', () => {
|
||||
this.activateFromHash(false);
|
||||
});
|
||||
this._popstateBound = true;
|
||||
}
|
||||
},
|
||||
|
||||
bindLinks() {
|
||||
document.querySelectorAll('[data-section]').forEach(link => {
|
||||
if (link.dataset.navBound === 'true') return;
|
||||
link.dataset.navBound = 'true';
|
||||
link.addEventListener('click', event => {
|
||||
event.preventDefault();
|
||||
this.showSection(link.dataset.section);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
refresh() {
|
||||
this.bindLinks();
|
||||
if (!this.activateFromHash(false)) {
|
||||
const firstLink = document.querySelector('[data-section]');
|
||||
if (firstLink) {
|
||||
this.showSection(firstLink.dataset.section, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
activateFromHash(updateHistory) {
|
||||
const hash = window.location.hash.slice(1);
|
||||
if (!hash || !document.querySelector(`#${hash}`)) return false;
|
||||
this.showSection(hash, updateHistory);
|
||||
return true;
|
||||
},
|
||||
|
||||
showSection(sectionId, updateHistory = true) {
|
||||
document.querySelectorAll('.amb-section').forEach(section => {
|
||||
section.classList.remove('active');
|
||||
});
|
||||
|
||||
const targetSection = document.querySelector(`#${sectionId}`);
|
||||
if (targetSection) {
|
||||
targetSection.classList.add('active');
|
||||
}
|
||||
|
||||
document.querySelectorAll('.amb-nav-link').forEach(link => {
|
||||
link.classList.remove('active');
|
||||
});
|
||||
const activeLink = document.querySelector(`[data-section="${sectionId}"]`);
|
||||
if (activeLink) {
|
||||
activeLink.classList.add('active');
|
||||
}
|
||||
|
||||
if (updateHistory) {
|
||||
history.pushState(null, '', `#${sectionId}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.NavigationManager = NavigationManager;
|
||||
window.AMBPlugins?.register('navigation_manager', async () => NavigationManager.init());
|
||||
})();
|
||||
45
src/autometabuilder/web/static/js/plugins/theme_manager.js
Normal file
45
src/autometabuilder/web/static/js/plugins/theme_manager.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* AutoMetabuilder - Theme Manager
|
||||
*/
|
||||
(() => {
|
||||
const ThemeManager = {
|
||||
STORAGE_KEY: 'amb-theme',
|
||||
|
||||
init() {
|
||||
const saved = localStorage.getItem(this.STORAGE_KEY);
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const theme = saved || (prefersDark ? 'dark' : 'light');
|
||||
this.setTheme(theme);
|
||||
|
||||
document.querySelectorAll('[data-theme-toggle]').forEach(btn => {
|
||||
btn.addEventListener('click', () => this.toggle());
|
||||
});
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
|
||||
if (!localStorage.getItem(this.STORAGE_KEY)) {
|
||||
this.setTheme(e.matches ? 'dark' : 'light');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setTheme(theme) {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
localStorage.setItem(this.STORAGE_KEY, theme);
|
||||
this.updateToggleIcon(theme);
|
||||
},
|
||||
|
||||
toggle() {
|
||||
const current = document.documentElement.getAttribute('data-theme');
|
||||
this.setTheme(current === 'dark' ? 'light' : 'dark');
|
||||
},
|
||||
|
||||
updateToggleIcon(theme) {
|
||||
document.querySelectorAll('[data-theme-toggle] i').forEach(icon => {
|
||||
icon.className = theme === 'dark' ? 'bi bi-moon-fill' : 'bi bi-sun-fill';
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.ThemeManager = ThemeManager;
|
||||
window.AMBPlugins?.register('theme_manager', async () => ThemeManager.init());
|
||||
})();
|
||||
Reference in New Issue
Block a user