SHA256
460 lines
16 KiB
JavaScript
460 lines
16 KiB
JavaScript
import { parseShineRouteParts } from './services/shine-routes.js';
|
|
|
|
const ROOT_PAGES = ['messages-list', 'channels-list', 'network-view', 'notifications-view', 'profile-view'];
|
|
const SWIPEABLE_ROOT_PAGES = ['messages-list', 'channels-list', 'notifications-view', 'profile-view'];
|
|
const lastVisitedRouteByRoot = new Map();
|
|
let previousTrackedPath = '';
|
|
let currentTrackedPath = String(window.location.pathname || '').trim() || '/';
|
|
const PRETTY_PATHS = new Map([
|
|
['start-view', 'start'],
|
|
['entry-settings-view', 'entry-settings'],
|
|
['register-view', 'register'],
|
|
['registration-faq-view', 'register/faq'],
|
|
['registration-payment-view', 'register/payment'],
|
|
['registration-draft-keys-view', 'register/draft-keys'],
|
|
['registration-keys-view', 'register/keys'],
|
|
['topup-view', 'topup'],
|
|
['devnet-topup-view', 'devnet-topup'],
|
|
['login-view', 'login'],
|
|
['login-camera-view', 'login/camera'],
|
|
['login-other-device-view', 'login/device'],
|
|
['login-password-view', 'login/password'],
|
|
['key-storage-view', 'key-storage'],
|
|
['profile-view', 'profile'],
|
|
['profile-edit-view', 'profile/edit'],
|
|
['messages-list', 'messages'],
|
|
['contact-search-view', 'contacts'],
|
|
['chat-view', 'chat'],
|
|
['channels-list', 'channels'],
|
|
['add-channel-view', 'channels/new'],
|
|
['add-personal-public-chat-view', 'channels/new-public-chat'],
|
|
['channel-view', 'channel'],
|
|
['channel-thread-view', 'thread'],
|
|
['network-view', 'network'],
|
|
['notifications-view', 'notifications'],
|
|
['settings-view', 'settings'],
|
|
['access-servers-view', 'settings/access-servers'],
|
|
['server-settings-view', 'settings/servers'],
|
|
['arweave-uploads-view', 'settings/arweave-uploads'],
|
|
['developer-settings-view', 'settings/developer'],
|
|
['trusted-device-login-settings-view', 'settings/device-login'],
|
|
['language-view', 'settings/language'],
|
|
['app-log-view', 'settings/app-log'],
|
|
['pwa-diagnostics-view', 'settings/pwa-diagnostics'],
|
|
['solana-users-init-view', 'settings/solana-users-init'],
|
|
['solana-rpc-check-view', 'settings/solana-rpc-check'],
|
|
['wallet-view', 'wallet'],
|
|
['queue', 'quene'],
|
|
['device-view', 'devices'],
|
|
['device-session-view', 'devices'],
|
|
['connect-device-view', 'devices/connect'],
|
|
['device-pairing-view', 'devices/pairing'],
|
|
['device-qr-view', 'devices/qr'],
|
|
['device-camera-view', 'devices/camera'],
|
|
['show-keys-view', 'devices/keys'],
|
|
['remote-addblock-session-view', 'remote-addblock-session'],
|
|
]);
|
|
|
|
export const PRE_AUTH_PAGES = [
|
|
'start-view',
|
|
'entry-settings-view',
|
|
'register-view',
|
|
'registration-faq-view',
|
|
'registration-payment-view',
|
|
'registration-draft-keys-view',
|
|
'registration-keys-view',
|
|
'topup-view',
|
|
'devnet-topup-view',
|
|
'login-view',
|
|
'login-camera-view',
|
|
'login-other-device-view',
|
|
'login-password-view',
|
|
'key-storage-view',
|
|
];
|
|
|
|
export function parseRouteFromPath(pathname = '') {
|
|
const currentPath = String(pathname || '').trim();
|
|
const raw = currentPath
|
|
.replace(/^\/+/, '')
|
|
.replace(/^index\.html$/i, '')
|
|
.replace(/^index\.html\//i, '')
|
|
.replace(/\/+$/, '');
|
|
if (!raw) return { pageId: '', params: {} };
|
|
|
|
const segments = raw.split('/').filter(Boolean);
|
|
const pageId = segments[0] || '';
|
|
const dynamicId = segments[1] || '';
|
|
|
|
const decodePart = (value) => {
|
|
try {
|
|
return decodeURIComponent(value || '');
|
|
} catch {
|
|
return value || '';
|
|
}
|
|
};
|
|
const isLikelyBlockNumber = (value) => /^[0-9]+$/.test(String(value || '').trim());
|
|
|
|
const shineRoute = parseShineRouteParts(segments);
|
|
if (shineRoute?.entity) {
|
|
const shineLogin = shineRoute.entity;
|
|
const baseOffset = Number(shineRoute.offset || 0);
|
|
const section = decodePart(segments[baseOffset] || '').toLowerCase();
|
|
if (!section) {
|
|
return { pageId: 'user', params: { login: shineLogin, fromPage: 'messages-list', section: 'profile' } };
|
|
}
|
|
if (section === 'links') {
|
|
return { pageId: 'network-view', params: { mode: 'keep-history', login: shineLogin } };
|
|
}
|
|
if (section === 'channels') {
|
|
const sub = decodePart(segments[baseOffset + 1] || '').toLowerCase();
|
|
if (sub === 'owned') {
|
|
return {
|
|
pageId: 'channels-list',
|
|
params: { mode: 'my', login: shineLogin, scope: 'owned' },
|
|
};
|
|
}
|
|
if (sub === 'following') {
|
|
return {
|
|
pageId: 'channels-list',
|
|
params: { mode: 'feed', login: shineLogin, scope: 'following' },
|
|
};
|
|
}
|
|
return {
|
|
pageId: 'channels-list',
|
|
params: { mode: 'feed', login: shineLogin, scope: 'all' },
|
|
};
|
|
}
|
|
if (segments.length === baseOffset + 1 && isLikelyBlockNumber(segments[baseOffset])) {
|
|
return {
|
|
pageId: 'channel-thread-view',
|
|
params: {
|
|
messageBlockchainName: shineLogin,
|
|
messageBlockNumber: segments[baseOffset] || '',
|
|
messageBlockHash: '',
|
|
channelOwnerBlockchainName: '',
|
|
channelRootBlockNumber: '',
|
|
channelRootBlockHash: '',
|
|
},
|
|
};
|
|
}
|
|
if (segments.length >= baseOffset + 1) {
|
|
const ownerBlockchainName = shineLogin;
|
|
const channelName = decodePart(segments[baseOffset] || '');
|
|
const messageBlockNumber = segments[baseOffset + 1] || '';
|
|
if (ownerBlockchainName && channelName && messageBlockNumber) {
|
|
return {
|
|
pageId: 'channel-thread-view',
|
|
params: {
|
|
ownerBlockchainName,
|
|
channelName,
|
|
messageBlockNumber,
|
|
messageBlockHash: '',
|
|
messageBlockchainName: '',
|
|
channelOwnerBlockchainName: ownerBlockchainName,
|
|
channelRootBlockNumber: '',
|
|
channelRootBlockHash: '',
|
|
},
|
|
};
|
|
}
|
|
if (ownerBlockchainName && channelName) {
|
|
return {
|
|
pageId: 'channel-view',
|
|
params: { ownerBlockchainName, channelName, channelId: '' },
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pageId === 'chat' || pageId === 'chat-view') {
|
|
return { pageId: 'chat-view', params: { chatId: dynamicId ? decodeURIComponent(dynamicId) : '' } };
|
|
}
|
|
|
|
if (pageId === 'start') {
|
|
return { pageId: 'start-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'entry-settings') {
|
|
return { pageId: 'entry-settings-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'register') {
|
|
const sub = decodePart(segments[1] || '').toLowerCase();
|
|
if (sub === 'faq') return { pageId: 'registration-faq-view', params: {} };
|
|
if (sub === 'payment') return { pageId: 'registration-payment-view', params: {} };
|
|
if (sub === 'draft-keys') return { pageId: 'registration-draft-keys-view', params: {} };
|
|
if (sub === 'keys') return { pageId: 'registration-keys-view', params: {} };
|
|
return { pageId: 'register-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'topup') {
|
|
return { pageId: 'topup-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'devnet-topup') {
|
|
return { pageId: 'devnet-topup-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'login') {
|
|
const sub = decodePart(segments[1] || '').toLowerCase();
|
|
if (sub === 'camera') return { pageId: 'login-camera-view', params: {} };
|
|
if (sub === 'device') return { pageId: 'login-other-device-view', params: {} };
|
|
if (sub === 'password') return { pageId: 'login-password-view', params: {} };
|
|
return { pageId: 'login-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'key-storage') {
|
|
return { pageId: 'key-storage-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'profile') {
|
|
const sub = decodePart(segments[1] || '').toLowerCase();
|
|
if (sub === 'edit') return { pageId: 'profile-edit-view', params: {} };
|
|
return { pageId: 'profile-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'messages') {
|
|
return { pageId: 'messages-list', params: {} };
|
|
}
|
|
|
|
if (pageId === 'contacts') {
|
|
return { pageId: 'contact-search-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'channels') {
|
|
const sub = decodePart(segments[1] || '').toLowerCase();
|
|
if (sub === 'new') return { pageId: 'add-channel-view', params: {} };
|
|
if (sub === 'new-public-chat') return { pageId: 'add-personal-public-chat-view', params: {} };
|
|
return { pageId: 'channels-list', params: { mode: segments[1] ? decodePart(segments[1]) : '' } };
|
|
}
|
|
|
|
if (pageId === 'channel') {
|
|
if (segments.length >= 4) {
|
|
return {
|
|
pageId: 'channel-view',
|
|
params: {
|
|
ownerBlockchainName: decodePart(segments[1]),
|
|
channelRootBlockNumber: segments[2] || '',
|
|
channelRootBlockHash: segments[3] || '',
|
|
channelId: '',
|
|
},
|
|
};
|
|
}
|
|
return { pageId: 'channel-view', params: { channelId: dynamicId || '' } };
|
|
}
|
|
|
|
if (pageId === 'thread') {
|
|
return {
|
|
pageId: 'channel-thread-view',
|
|
params: {
|
|
messageBlockchainName: decodePart(segments[1]),
|
|
messageBlockNumber: segments[2] || '',
|
|
messageBlockHash: '',
|
|
channelOwnerBlockchainName: decodePart(segments[3]),
|
|
channelRootBlockNumber: segments[4] || '',
|
|
channelRootBlockHash: segments[5] || '',
|
|
},
|
|
};
|
|
}
|
|
|
|
if (pageId === 'network') {
|
|
return { pageId: 'network-view', params: { mode: segments[1] ? decodePart(segments[1]) : '' } };
|
|
}
|
|
|
|
if (pageId === 'notifications') {
|
|
return { pageId: 'notifications-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'settings') {
|
|
const sub = decodePart(segments[1] || '').toLowerCase();
|
|
if (sub === 'access-servers') return { pageId: 'access-servers-view', params: {} };
|
|
if (sub === 'servers') return { pageId: 'server-settings-view', params: {} };
|
|
if (sub === 'arweave-uploads') return { pageId: 'arweave-uploads-view', params: {} };
|
|
if (sub === 'developer') return { pageId: 'developer-settings-view', params: {} };
|
|
if (sub === 'device-login') return { pageId: 'trusted-device-login-settings-view', params: {} };
|
|
if (sub === 'language') return { pageId: 'language-view', params: {} };
|
|
if (sub === 'app-log') return { pageId: 'app-log-view', params: {} };
|
|
if (sub === 'pwa-diagnostics') return { pageId: 'pwa-diagnostics-view', params: {} };
|
|
if (sub === 'solana-users-init') return { pageId: 'solana-users-init-view', params: {} };
|
|
if (sub === 'solana-rpc-check') return { pageId: 'solana-rpc-check-view', params: {} };
|
|
return { pageId: 'settings-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'wallet') {
|
|
return { pageId: 'wallet-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'quene' || pageId === 'queue') {
|
|
return { pageId: 'queue', params: {} };
|
|
}
|
|
|
|
if (pageId === 'devices') {
|
|
const sub = decodePart(segments[1] || '').toLowerCase();
|
|
if (sub === 'connect') return { pageId: 'connect-device-view', params: {} };
|
|
if (sub === 'pairing') return { pageId: 'device-pairing-view', params: {} };
|
|
if (sub === 'qr') return { pageId: 'device-qr-view', params: {} };
|
|
if (sub === 'camera') return { pageId: 'device-camera-view', params: {} };
|
|
if (sub === 'keys') return { pageId: 'show-keys-view', params: {} };
|
|
if (dynamicId) {
|
|
return { pageId: 'device-session-view', params: { sessionId: decodeURIComponent(dynamicId) } };
|
|
}
|
|
return { pageId: 'device-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'remote-addblock-session') {
|
|
return { pageId: 'remote-addblock-session-view', params: {} };
|
|
}
|
|
|
|
if (pageId === 'channel-view') {
|
|
if (segments.length >= 4) {
|
|
return {
|
|
pageId,
|
|
params: {
|
|
ownerBlockchainName: decodePart(segments[1]),
|
|
channelRootBlockNumber: segments[2] || '',
|
|
channelRootBlockHash: segments[3] || '',
|
|
channelId: '',
|
|
},
|
|
};
|
|
}
|
|
return { pageId, params: { channelId: dynamicId || '' } };
|
|
}
|
|
|
|
if (pageId === 'channel-thread-view') {
|
|
return {
|
|
pageId,
|
|
params: {
|
|
messageBlockchainName: decodePart(segments[1]),
|
|
messageBlockNumber: segments[2] || '',
|
|
messageBlockHash: '',
|
|
channelOwnerBlockchainName: decodePart(segments[3]),
|
|
channelRootBlockNumber: segments[4] || '',
|
|
channelRootBlockHash: segments[5] || '',
|
|
},
|
|
};
|
|
}
|
|
|
|
if (pageId === 'device-session-view') {
|
|
return { pageId, params: { sessionId: dynamicId ? decodeURIComponent(dynamicId) : '' } };
|
|
}
|
|
|
|
if (pageId === 'network-view') {
|
|
return { pageId, params: { mode: segments[1] ? decodePart(segments[1]) : '' } };
|
|
}
|
|
|
|
if (pageId === 'channels-list') {
|
|
return { pageId, params: { mode: segments[1] ? decodePart(segments[1]) : '' } };
|
|
}
|
|
|
|
return { pageId, params: {} };
|
|
}
|
|
|
|
export function getRoute() {
|
|
return parseRouteFromPath(window.location.pathname || '');
|
|
}
|
|
|
|
export function navigate(path) {
|
|
const cleanPath = toPrettyPath(path);
|
|
const nextPath = cleanPath ? `/${cleanPath}` : '/';
|
|
if (window.location.pathname !== nextPath) {
|
|
previousTrackedPath = currentTrackedPath;
|
|
currentTrackedPath = nextPath;
|
|
}
|
|
if (window.location.pathname !== nextPath) {
|
|
window.history.pushState({}, '', nextPath);
|
|
}
|
|
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
}
|
|
|
|
function normalizeCurrentPath() {
|
|
return String(window.location.pathname || '')
|
|
.replace(/^\/+/, '')
|
|
.replace(/\/+$/, '');
|
|
}
|
|
|
|
export function toPrettyPath(path) {
|
|
const raw = String(path || '').replace(/^\/+/, '').replace(/\/+$/, '');
|
|
if (!raw) return '';
|
|
const segments = raw.split('/').filter(Boolean);
|
|
if (!segments.length) return '';
|
|
const [head, ...tail] = segments;
|
|
const prettyHead = PRETTY_PATHS.get(head) || head;
|
|
return [prettyHead, ...tail].join('/');
|
|
}
|
|
|
|
export function navigateBack() {
|
|
if (window.history.length <= 1) return;
|
|
window.history.back();
|
|
}
|
|
|
|
export function resolveToolbarActive(pageId) {
|
|
if (ROOT_PAGES.includes(pageId)) return pageId;
|
|
if (
|
|
pageId === 'profile-edit-view' ||
|
|
pageId === 'wallet-view' ||
|
|
pageId === 'settings-view' ||
|
|
pageId === 'access-servers-view' ||
|
|
pageId === 'developer-settings-view' ||
|
|
pageId === 'server-settings-view' ||
|
|
pageId === 'arweave-uploads-view' ||
|
|
pageId === 'remote-addblock-session-view' ||
|
|
pageId === 'device-view' ||
|
|
pageId === 'connect-device-view' ||
|
|
pageId === 'device-pairing-view' ||
|
|
pageId === 'trusted-device-login-settings-view' ||
|
|
pageId === 'device-qr-view' ||
|
|
pageId === 'device-camera-view' ||
|
|
pageId === 'show-keys-view' ||
|
|
pageId === 'device-session-view' ||
|
|
pageId === 'language-view' ||
|
|
pageId === 'app-log-view' ||
|
|
pageId === 'pwa-diagnostics-view' ||
|
|
pageId === 'solana-users-init-view'
|
|
) return 'profile-view';
|
|
if (pageId === 'chat-view' || pageId === 'contact-search-view') return 'messages-list';
|
|
if (pageId === 'channel-view' || pageId === 'channel-thread-view' || pageId === 'add-channel-view' || pageId === 'add-personal-public-chat-view') return 'channels-list';
|
|
if (pageId === 'user') return 'messages-list';
|
|
return 'profile-view';
|
|
}
|
|
|
|
export function rememberToolbarRoute(pageId, explicitPath = '') {
|
|
const rootPageId = resolveToolbarActive(pageId);
|
|
if (!ROOT_PAGES.includes(rootPageId)) return;
|
|
const cleanPath = String(explicitPath || normalizeCurrentPath()).trim();
|
|
lastVisitedRouteByRoot.set(rootPageId, cleanPath || toPrettyPath(rootPageId) || rootPageId);
|
|
}
|
|
|
|
export function getToolbarNavigationTarget(pageId) {
|
|
const rootPageId = resolveToolbarActive(pageId);
|
|
return lastVisitedRouteByRoot.get(rootPageId) || toPrettyPath(rootPageId) || rootPageId;
|
|
}
|
|
|
|
export function resetRememberedToolbarRoutes() {
|
|
lastVisitedRouteByRoot.clear();
|
|
previousTrackedPath = '';
|
|
currentTrackedPath = String(window.location.pathname || '').trim() || '/';
|
|
}
|
|
|
|
export function getSwipeNavigationTarget(currentPageId, direction) {
|
|
const rootPageId = resolveToolbarActive(currentPageId);
|
|
const index = SWIPEABLE_ROOT_PAGES.indexOf(rootPageId);
|
|
if (index === -1) return '';
|
|
|
|
const step = direction === 'left' ? 1 : direction === 'right' ? -1 : 0;
|
|
if (!step) return '';
|
|
|
|
const nextIndex = index + step;
|
|
if (nextIndex < 0 || nextIndex >= SWIPEABLE_ROOT_PAGES.length) return '';
|
|
return getToolbarNavigationTarget(SWIPEABLE_ROOT_PAGES[nextIndex]);
|
|
}
|
|
|
|
export function syncTrackedRouteHistory(pathname = '') {
|
|
const nextPath = String(pathname || '').trim() || '/';
|
|
if (nextPath === currentTrackedPath) return;
|
|
previousTrackedPath = currentTrackedPath;
|
|
currentTrackedPath = nextPath;
|
|
}
|
|
|
|
export function getPreviousTrackedPath() {
|
|
return previousTrackedPath;
|
|
}
|