Add a Verse admin tab that opens versebyversewithnate.us/admin
build-container / build (push) Successful in 2m36s
build-container / build (push) Successful in 2m36s
The site sends X-Frame-Options: SAMEORIGIN, so it cannot be embedded; the tab and a Home tile open it in its own browser tab. Address is VERSE_URL. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6ec98d2527
commit
bd58fe73cc
4 files changed
+18
-5
No files matched your search
+14
-4
@@ -38,6 +38,7 @@ const ICONS = {
|
||||
more: '<circle cx="5" cy="12" r="1.6" fill="currentColor"/><circle cx="12" cy="12" r="1.6" fill="currentColor"/><circle cx="19" cy="12" r="1.6" fill="currentColor"/>',
|
||||
cal: '<rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 10h18M8 3v4M16 3v4"/>',
|
||||
search: '<circle cx="11" cy="11" r="7"/><path d="M20 20l-4-4"/>',
|
||||
book: '<path d="M4 5a2 2 0 012-2h13v16H6a2 2 0 00-2 2z"/><path d="M19 19v2H6a2 2 0 01-2-2"/><path d="M9 7h6"/>',
|
||||
trash: '<path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13"/>',
|
||||
};
|
||||
const icon = (n, cls = '') => `<svg class="${cls}" viewBox="0 0 24 24">${ICONS[n]}</svg>`;
|
||||
@@ -61,7 +62,7 @@ function mailUrl(m, kind) {
|
||||
return base; // iCloud has no sign-in hint
|
||||
}
|
||||
|
||||
let cfg = { audiobooks: 'https://audiobooks.necloud.us', seafile: 'https://seafile.necloud.us', onlyoffice: 'https://onlyoffice.necloud.us' };
|
||||
let cfg = { verse: 'https://versebyversewithnate.us/admin', audiobooks: 'https://audiobooks.necloud.us', seafile: 'https://seafile.necloud.us', onlyoffice: 'https://onlyoffice.necloud.us' };
|
||||
|
||||
// ---- Seafile client (via same-origin proxy)
|
||||
const sf = {
|
||||
@@ -95,8 +96,8 @@ const fmtSize = b => b < 1024 ? b + ' B' : b < 1048576 ? (b / 1024).toFixed(0) +
|
||||
const fmtDate = s => new Date(s * 1000).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
|
||||
|
||||
// ---- Navigation
|
||||
const TABS = [['home', 'Home'], ['files', 'Files'], ['music', 'Music'], ['mail', 'Mail'], ['calendar', 'Calendar'], ['search', 'Search'], ['office', 'Office'], ['audio', 'Audio'], ['settings', 'Settings']];
|
||||
const TAB_ICON = { home: 'home', mail: 'mail', files: 'files', office: 'doc', audio: 'audio', music: 'music', settings: 'cog', calendar: 'cal', search: 'search' };
|
||||
const TABS = [['home', 'Home'], ['files', 'Files'], ['music', 'Music'], ['mail', 'Mail'], ['calendar', 'Calendar'], ['search', 'Search'], ['office', 'Office'], ['audio', 'Audio'], ['verse', 'Verse admin'], ['settings', 'Settings']];
|
||||
const TAB_ICON = { home: 'home', mail: 'mail', files: 'files', office: 'doc', audio: 'audio', verse: 'book', music: 'music', settings: 'cog', calendar: 'cal', search: 'search' };
|
||||
const PRIMARY = ['home', 'files', 'music', 'mail']; // phone tab bar; the rest sit behind "More"
|
||||
const phone = matchMedia('(max-width: 767px)');
|
||||
let activeTab = 'home';
|
||||
@@ -120,7 +121,7 @@ function openMore() {
|
||||
el.querySelectorAll('a.row').forEach(a => a.addEventListener('click', closeSheet));
|
||||
}
|
||||
|
||||
const routes = { home: viewHome, mail: viewMail, files: viewFiles, office: viewOffice, audio: viewAudio, music: viewMusic, search: viewSearch, calendar: viewCalendar, settings: viewSettings, edit: viewEdit };
|
||||
const routes = { home: viewHome, mail: viewMail, files: viewFiles, office: viewOffice, audio: viewAudio, verse: viewVerse, music: viewMusic, search: viewSearch, calendar: viewCalendar, settings: viewSettings, edit: viewEdit };
|
||||
let editor;
|
||||
function route() {
|
||||
const [, id = 'home', ...rest] = location.hash.split('/');
|
||||
@@ -157,6 +158,7 @@ function viewHome() {
|
||||
${tile('#/calendar', '#d9453a', 'cal', 'Calendar', 'Agenda')}
|
||||
${tile('#/office', '#e0742b', 'doc', 'Office', 'OnlyOffice')}
|
||||
${tile('#/audio', '#8a5cf0', 'audio', 'Audio', 'Audiobooks')}
|
||||
${tile(cfg.verse, '#0f9d9a', 'book', 'Verse admin', 'Opens in a new tab', true)}
|
||||
${tile('#/mail', '#4f7cff', 'mail', 'Mail', '4 accounts')}
|
||||
</div>
|
||||
<h2>Mail</h2><div class="grid">
|
||||
@@ -507,6 +509,14 @@ async function newOfficeDoc(x, label) {
|
||||
// ---- Audiobooks: embedded site. Sign-in details saved in Settings (this browser only) can be copied with one tap,
|
||||
// because a page can't type into another site's login form.
|
||||
const abCreds = () => store.get('ab_creds', { u: '', p: '' });
|
||||
// Verse by Verse admin: the site refuses to be framed (X-Frame-Options), so this is a launcher.
|
||||
function viewVerse() {
|
||||
const url = cfg.verse, host = new URL(url).host;
|
||||
$('#view').innerHTML = `<div class="wrap"><h1>Verse admin</h1><p class="sub">${esc(host + new URL(url).pathname)}</p>
|
||||
<div class="card" style="max-width:none"><p style="margin-top:0">This site doesn't allow being shown inside another app, so it opens in its own tab.</p>
|
||||
<div class="bar"><a class="btn" href="${esc(url)}" target="_blank" rel="noopener">${icon('book')}Open admin</a></div></div></div>`;
|
||||
}
|
||||
|
||||
function viewAudio() {
|
||||
const url = cfg.audiobooks, c = abCreds();
|
||||
$('#view').innerHTML = `<div class="wrap"><h1>Audio</h1>
|
||||
|
||||
Reference in new issue
Block a user