mobile: show login screen for stock browsers when not authenticated
Nightly Build / build (push) Successful in 6m57s
Nightly Build / build (push) Successful in 6m57s
Add an inline auth gate to mobile.html that checks /api/auth/me on load. Skipped when ?native=true (the iOS shell handles auth in background). Includes a vanilla JS login form (no Lit) reusing the existing login styles. Bump version to 0.1.2.
This commit is contained in:
Generated
+1
-1
@@ -4172,7 +4172,7 @@ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "skald"
|
name = "skald"
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ resolver = "2"
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "skald"
|
name = "skald"
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { LitElement, html, nothing } from 'lit';
|
import { LitElement, html, nothing } from 'lit';
|
||||||
import { t } from '../lib/i18n.js';
|
import { t } from '../lib/i18n.js';
|
||||||
|
import { LoginPage } from './login-page.js';
|
||||||
import './shared/inbox-page.js';
|
import './shared/inbox-page.js';
|
||||||
import './shared/chat-page.js';
|
import './shared/chat-page.js';
|
||||||
import './shared/projects-page.js';
|
import './shared/projects-page.js';
|
||||||
@@ -7,6 +8,8 @@ import './shared/settings-page.js';
|
|||||||
import './shared/file-viewer-mobile.js';
|
import './shared/file-viewer-mobile.js';
|
||||||
import './shared/tool-detail-mobile.js';
|
import './shared/tool-detail-mobile.js';
|
||||||
|
|
||||||
|
customElements.define('login-page', LoginPage);
|
||||||
|
|
||||||
// Sections addressable via the URL hash — same routing style as the desktop
|
// Sections addressable via the URL hash — same routing style as the desktop
|
||||||
// sidebar (web/components/sidebar.js). The native iOS shell and mobile browsers
|
// sidebar (web/components/sidebar.js). The native iOS shell and mobile browsers
|
||||||
// share this router so the URL always reflects the active section: native menu
|
// share this router so the URL always reflects the active section: native menu
|
||||||
@@ -176,12 +179,10 @@ class MobileApp extends LitElement {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const s = this._section;
|
const s = this._section;
|
||||||
const item = (id, icon, label, extraClass = '') => html`
|
const item = (id, icon, label) => html`
|
||||||
<div class="mobile-nav-item ${extraClass} ${s === id ? 'active' : ''}"
|
<div class="mobile-nav-item ${s === id ? 'active' : ''}"
|
||||||
@click=${() => this._nav(id)}>
|
@click=${() => this._nav(id)}>
|
||||||
${id === 'chat'
|
<span class="nav-icon"><i class="bi ${icon}"></i></span>
|
||||||
? html`<div class="chat-fab"><i class="bi bi-chat-dots-fill"></i></div>`
|
|
||||||
: html`<span class="nav-icon"><i class="bi ${icon}"></i></span>`}
|
|
||||||
<span>${label}</span>
|
<span>${label}</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -231,7 +232,7 @@ class MobileApp extends LitElement {
|
|||||||
<nav class="mobile-nav">
|
<nav class="mobile-nav">
|
||||||
${item('inbox', 'bi-inbox', t('mobile.nav.inbox'))}
|
${item('inbox', 'bi-inbox', t('mobile.nav.inbox'))}
|
||||||
${item('projects', 'bi-folder2-open', t('mobile.nav.projects'))}
|
${item('projects', 'bi-folder2-open', t('mobile.nav.projects'))}
|
||||||
${item('chat', '', t('mobile.nav.chat'), 'chat-btn')}
|
${item('chat', 'bi-chat-dots-fill', t('mobile.nav.chat'))}
|
||||||
${item('notifications', 'bi-bell', t('mobile.nav.alerts'))}
|
${item('notifications', 'bi-bell', t('mobile.nav.alerts'))}
|
||||||
${item('settings', 'bi-sliders', t('mobile.nav.settings'))}
|
${item('settings', 'bi-sliders', t('mobile.nav.settings'))}
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
+3
-50
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
--mobile-nav-height: 64px;
|
--mobile-nav-height: 64px;
|
||||||
--mobile-chat-size: 58px;
|
|
||||||
|
|
||||||
--mobile-bg: var(--bs-body-bg);
|
--mobile-bg: var(--bs-body-bg);
|
||||||
--mobile-text: var(--sidebar-brand-color);
|
--mobile-text: var(--sidebar-brand-color);
|
||||||
@@ -336,7 +335,7 @@ mobile-app[data-native] .chat-page-input-area { padding-bottom: 10px; }
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--mobile-nav-color);
|
color: var(--mobile-nav-color);
|
||||||
font-size: 0.62rem;
|
font-size: 0.68rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
letter-spacing: 0.01em;
|
letter-spacing: 0.01em;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@@ -348,8 +347,8 @@ mobile-app[data-native] .chat-page-input-area { padding-bottom: 10px; }
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 46px;
|
width: 48px;
|
||||||
height: 28px;
|
height: 30px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
transition: background 0.18s, color 0.18s;
|
transition: background 0.18s, color 0.18s;
|
||||||
}
|
}
|
||||||
@@ -367,52 +366,6 @@ mobile-app[data-native] .chat-page-input-area { padding-bottom: 10px; }
|
|||||||
background: var(--accent-soft);
|
background: var(--accent-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Center chat FAB ──────────────────────────────────────────────────────── */
|
|
||||||
|
|
||||||
.mobile-nav-item.chat-btn {
|
|
||||||
position: relative;
|
|
||||||
top: -18px;
|
|
||||||
flex: 1.15;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-fab {
|
|
||||||
width: var(--mobile-chat-size);
|
|
||||||
height: var(--mobile-chat-size);
|
|
||||||
border-radius: 50%;
|
|
||||||
background: linear-gradient(135deg, var(--accent), var(--accent-hover));
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border: 3px solid var(--mobile-bg);
|
|
||||||
box-shadow: 0 4px 14px rgba(var(--accent-rgb), 0.4);
|
|
||||||
transition: transform 0.15s, box-shadow 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-fab i {
|
|
||||||
font-size: 1.45rem;
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-nav-item.chat-btn .nav-icon {
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
background: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-nav-item.chat-btn.active .chat-fab {
|
|
||||||
transform: scale(1.07);
|
|
||||||
box-shadow: 0 6px 18px rgba(var(--accent-rgb), 0.55);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-nav-item.chat-btn span {
|
|
||||||
margin-top: 4px;
|
|
||||||
color: var(--mobile-nav-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-nav-item.chat-btn.active span {
|
|
||||||
color: var(--mobile-nav-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Chat page ────────────────────────────────────────────────────────────── */
|
/* ── Chat page ────────────────────────────────────────────────────────────── */
|
||||||
|
|
||||||
.chat-page {
|
.chat-page {
|
||||||
|
|||||||
+23
-1
@@ -41,6 +41,7 @@
|
|||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" />
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" />
|
||||||
|
|
||||||
<link rel="stylesheet" href="css/variables.css" />
|
<link rel="stylesheet" href="css/variables.css" />
|
||||||
|
<link rel="stylesheet" href="css/setup-page.css" />
|
||||||
<link rel="stylesheet" href="css/copilot-messages.css" />
|
<link rel="stylesheet" href="css/copilot-messages.css" />
|
||||||
<link rel="stylesheet" href="css/inbox-cards.css" />
|
<link rel="stylesheet" href="css/inbox-cards.css" />
|
||||||
<link rel="stylesheet" href="css/file-viewer.css" />
|
<link rel="stylesheet" href="css/file-viewer.css" />
|
||||||
@@ -65,7 +66,28 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<mobile-app></mobile-app>
|
<mobile-app id="mobile-app"></mobile-app>
|
||||||
|
<login-page id="login-page" style="display:none"></login-page>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
// Native shell handles auth in background — never gate it.
|
||||||
|
if (new URLSearchParams(location.search).get('native') === 'true') return;
|
||||||
|
|
||||||
|
var app = document.getElementById('mobile-app');
|
||||||
|
var login = document.getElementById('login-page');
|
||||||
|
|
||||||
|
fetch('/api/auth/me').then(function (res) {
|
||||||
|
if (res.ok) return; // logged in — show app
|
||||||
|
app.style.display = 'none'; // 401 — show login
|
||||||
|
login.style.display = '';
|
||||||
|
}).catch(function () {
|
||||||
|
app.style.display = 'none'; // network error — show login
|
||||||
|
login.style.display = '';
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
<script type="module" src="components/mobile-app.js"></script>
|
<script type="module" src="components/mobile-app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user