openvibers/openvibe.network Commits

openvibe.my: tiles open the menu at their place, sections scroll into view, history times carry their zone (#867)

OP OpenVibers committed 1 days ago · 5a5ecb6da1 · 3 files, +21 −4

- Notifications, Messages and Ask Vibe open the menu on that place (openvibe-shared 4.223.0
  OpenVibeNavbar.openMenu; the Notifications tile clicked a bar bell that is gone, so it did nothing).
- A section named in the address (/history, /my#history, the menu's Full history) opened but
  the page stayed at the top: it scrolls to the section now, and a later #section does too.
- /api/history returns created_at and updated_at as ISO with Z. The column holds UTC without a
  zone, which browsers read as local time: west of UTC every visit said "just now".

Changes

ddiff --git a/public/js/my/core.js b/public/js/my/core.js
iindex 705d566c..2c591a9d 100644
---- a/public/js/my/core.js
++++ b/public/js/my/core.js
@@@ -170,6 +170,16 @@ function showSection(id, btn) {
if (id === 'apps' && typeof loadConnectApps === 'function') loadConnectApps();
}
++// A later #section (a link on this page, the menu's links) opens that section and scrolls to it.
++if (typeof window !== 'undefined' && window.addEventListener) {
++ window.addEventListener('hashchange', () => {
++ const id = window.location.hash.replace(/^#/, '');
++ if (!id || !document.getElementById('sec-' + id)) return;
++ showSection(id);
++ document.getElementById('sec-' + id)?.scrollIntoView?.({ behavior: 'smooth', block: 'start' });
++ });
++}
++
function openInitialSection() {
const pathSection = { '/themes': 'themes', '/notifications': 'notifications', '/verify-email': 'notifications', '/linked': 'linked', '/security': 'security', '/machines': 'machines', '/profile': 'profile', '/history': 'history' }[window.location.pathname];
// #delete is the re-authentication return target: the delete step lives in the accounts section.
@@@ -193,7 +203,9 @@ function openInitialSection() {
showSection(routeSection);
// On openvibe.network the section sits below the account home, so the page scrolls to it; openvibe.link's hub
// (body.link-hub) is the section alone and stays at the top.
-- if (routeSection === 'machines' && !document.body?.classList?.contains('link-hub')) document.getElementById('sec-machines')?.scrollIntoView?.({ block: 'start' });
++ // A section named in the address (openvibe.my/history, /my#history, the menu's Full history) is where the reader
++ // lands: it sits below the account home, so the page scrolls to it (it opened the section and stayed at the top).
++ if (routeSection !== 'profile' && !document.body?.classList?.contains('link-hub')) document.getElementById('sec-' + routeSection)?.scrollIntoView?.({ block: 'start' });
if (routeSection === 'machines' && hash === 'pair') setTimeout(() => mcPair(), 0);
}
}
ddiff --git a/public/js/my/today.js b/public/js/my/today.js
iindex 191d5463..a17701da 100644
---- a/public/js/my/today.js
++++ b/public/js/my/today.js
@@@ -97,7 +97,8 @@ function renderActions(unread) {
if (hero && color && hero.style && hero.style.setProperty) hero.style.setProperty('--me', color);
const streamer = !!(currentUser && currentUser.role && currentUser.role !== 'user');
const count = unread && Number(unread.count) > 0 ? Number(unread.count) : 0;
-- const dock = (tab) => () => { try { const nb = globalThis.OpenVibeNavbar; if (nb && nb.openDock) { nb.openDock(tab); return true; } } catch (e) { /* the link works */ } return false; };
++ // The menu at a place (openvibe-shared 4.223.0 OpenVibeNavbar.openMenu); before it, the Dock's opener; else the link.
++ const dock = (tab) => () => { try { const nb = globalThis.OpenVibeNavbar; if (nb && nb.openMenu) { nb.openMenu(tab); return true; } if (nb && nb.openDock) { nb.openDock(tab); return true; } } catch (e) { /* the link works */ } return false; };
const acts = [
streamer ? ['Go live', 'fa-tower-broadcast', 'https://openvibe.live/broadcast', 'live'] : ['Watch live', 'fa-circle-play', 'https://openvibe.live/', 'live'],
['Messages', 'fa-comment-dots', 'https://openvibe.chat/messages', 'chat', dock('chats')],
@@@ -105,7 +106,7 @@ function renderActions(unread) {
['Your files', 'fa-folder', 'https://openvibe.download/files', 'files'],
['Codes', 'fa-code', 'https://openvibe.codes/', 'codes'],
['Wallet', 'fa-wallet', '/wallet', 'wallet'],
-- ['Notifications', 'fa-bell', '#notifications', 'bell', () => { const bell = document.querySelector('[data-ov-bell], .openvibe-navbar-bell, #openvibe-notif-btn'); if (bell) { bell.click(); return true; } showSection('notifications'); return true; }, count],
++ ['Notifications', 'fa-bell', '#notifications', 'bell', () => { try { const nb = globalThis.OpenVibeNavbar; if (nb && nb.openMenu) { nb.openMenu('notifications'); return true; } } catch (e) { /* the section below */ } showSection('notifications'); document.getElementById('sec-notifications')?.scrollIntoView?.({ behavior: 'smooth', block: 'start' }); return true; }, count],
['Settings', 'fa-gear', '#settings', 'gear'],
];
nav.replaceChildren(...acts.map(([label, icon, href, tone, open, n]) => {
ddiff --git a/server/history/routes.js b/server/history/routes.js
iindex 4996085f..a86e1419 100644
---- a/server/history/routes.js
++++ b/server/history/routes.js
@@@ -44,13 +44,17 @@ function serviceFromUrl(url) {
} catch { return { service: null, sub: null }; }
}
++// Times leave with their zone (the column holds UTC as "YYYY-MM-DD HH:MM:SS", which a browser reads as its local time:
++// west of UTC every visit looked hours ahead and said "just now", 2026-11-12).
++const isoUtc = (t) => (typeof t === 'string' && /^\d{4}-\d\d-\d\d[ T]\d\d:\d\d(:\d\d(\.\d+)?)?$/.test(t) ? `${t.replace(' ', 'T')}Z` : t);
++
function rowOut(r) {
let meta = null;
try { meta = r.meta ? JSON.parse(r.meta) : null; } catch { meta = null; }
return {
id: r.id, type: r.type, title: r.title, url: r.url, icon: r.icon, image_url: r.image_url || null, service: r.service, sub: r.sub,
service_label: r.sub ? `${r.sub}.${SERVICE_LABELS[r.service] || r.service || ''}` : (SERVICE_LABELS[r.service] || r.service || null),
-- meta, hits: r.hits, created_at: r.created_at, updated_at: r.updated_at,
++ meta, hits: r.hits, created_at: isoUtc(r.created_at), updated_at: isoUtc(r.updated_at),
};
}