mobile: gateway handoff for Chat and Drive below 1024px; pin Hub theme in the SSO bootstrap
Panel consensus (the branding panel): don't mount full-app iframes on mobile — nested scrolling, keyboard collapse and double chrome break both Element and oCIS under the bottom tab bar. Chat and Drive render a gateway card (same-tab handoff, matrix: deep link, signed-in-as) below 1024px; the iframe stays on desktop. hub-sso.html pins mx_local_settings.theme to custom-OccupyHub Dark once (version-flagged) — a device's earlier picker choice would otherwise beat config.json's default_theme.
This commit is contained in:
parent
3463b0a4f4
commit
c01d121748
3 changed files with 72 additions and 0 deletions
|
|
@ -4,6 +4,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|||
import { EmbeddedApp } from "../../../components/embed/embedded-app";
|
||||
import { api, errorMessage } from "../../../lib/api-client";
|
||||
import { useApiResource } from "../../../lib/use-api";
|
||||
import { useIsMobile } from "../../../hooks/use-is-mobile";
|
||||
|
||||
/**
|
||||
* In-app Chat: Element Web, full height inside the Hub shell, signed in as the
|
||||
|
|
@ -59,6 +60,7 @@ function originOf(url: string): string | null {
|
|||
|
||||
export default function ChatPage(): React.ReactElement {
|
||||
const identity = useApiResource<MatrixIdentity, MatrixIdentity | null>("/matrix/identity", identityView, null);
|
||||
const isMobile = useIsMobile();
|
||||
const frameRef = useRef<HTMLIFrameElement>(null);
|
||||
const mints = useRef(0);
|
||||
const tokenSent = useRef(false);
|
||||
|
|
@ -127,6 +129,39 @@ export default function ChatPage(): React.ReactElement {
|
|||
? ssoUser
|
||||
: undefined;
|
||||
|
||||
if (isMobile) {
|
||||
// Mobile: a framed three-pane Element under the bottom tab bar breaks
|
||||
// (nested scrolling, keyboard collapse, double chrome) — hand off to the
|
||||
// standalone app instead (panel consensus: gateway pattern).
|
||||
return (
|
||||
<div className="flex h-full flex-col justify-center px-6 py-10 text-center">
|
||||
<h1 className="text-lg font-bold">Newsroom chat</h1>
|
||||
<p className="mx-auto mt-2 max-w-xs text-xs leading-relaxed text-text-dim">
|
||||
Chat runs best as its own app on mobile — the full three-pane interface gets cramped inside the Hub frame.
|
||||
</p>
|
||||
<div className="mx-auto mt-8 flex w-full max-w-xs flex-col gap-3">
|
||||
<a
|
||||
href={identity.error === null ? `${elementOrigin}/` : FALLBACK_CHAT_URL}
|
||||
className="flex min-h-12 items-center justify-center rounded-xl bg-accent px-4 text-sm font-semibold text-white transition-opacity hover:opacity-90"
|
||||
>
|
||||
Open chat ↗
|
||||
</a>
|
||||
{ssoUser !== null && (
|
||||
<a
|
||||
href={`matrix:u/${ssoUser.slice(1)}`}
|
||||
className="flex min-h-12 items-center justify-center rounded-xl border border-border bg-surface px-4 text-sm font-medium text-text transition-colors hover:border-accent"
|
||||
>
|
||||
Open in a Matrix app
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<p className="mt-4 text-2xs text-text-faint">
|
||||
{ssoUser !== null ? `Signed in as ${ssoUser}` : "Sign in on desktop to link your account."}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EmbeddedApp
|
||||
title="Chat"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { EmbeddedApp } from "../../../../components/embed/embedded-app";
|
||||
import { useFilesLang } from "../../../../components/files/i18n";
|
||||
import { useApiResource } from "../../../../lib/use-api";
|
||||
import { useIsMobile } from "../../../../hooks/use-is-mobile";
|
||||
|
||||
/**
|
||||
* Drive — the oCIS web UI (personal space, shares, office documents) embedded
|
||||
|
|
@ -29,6 +30,7 @@ const driveView = (session: DriveSession): DriveSession | null => session;
|
|||
export default function DrivePage(): React.ReactElement {
|
||||
const { t } = useFilesLang();
|
||||
const drive = useApiResource<DriveSession, DriveSession | null>("/drive/session", driveView, null);
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const driveUrl = drive.source === "sample" ? FALLBACK_DRIVE_URL : drive.data?.driveUrl ?? null;
|
||||
const notConfigured = drive.source === "live" && drive.error === null && driveUrl === null;
|
||||
|
|
@ -43,6 +45,26 @@ export default function DrivePage(): React.ReactElement {
|
|||
es: "Inicia sesión una vez dentro de la unidad y quedará abierta. Los archivos de los colectivos están en la pestaña Biblioteca.",
|
||||
});
|
||||
|
||||
if (isMobile) {
|
||||
// Mobile: the oCIS file browser under the bottom tab bar breaks (nested
|
||||
// scrolling, double chrome) — hand off to the standalone drive instead
|
||||
// (panel consensus: gateway pattern). The Library tab is fully native.
|
||||
return (
|
||||
<div className="flex h-full flex-col justify-center px-6 py-10 text-center">
|
||||
<h1 className="text-lg font-bold">{t({ en: "Drive", es: "Unidad" })}</h1>
|
||||
<p className="mx-auto mt-2 max-w-xs text-xs leading-relaxed text-text-dim">{error ?? notice}</p>
|
||||
<div className="mx-auto mt-8 w-full max-w-xs">
|
||||
<a
|
||||
href={`${driveUrl ?? FALLBACK_DRIVE_URL}/`}
|
||||
className="flex min-h-12 items-center justify-center rounded-xl bg-accent px-4 text-sm font-semibold text-white transition-opacity hover:opacity-90"
|
||||
>
|
||||
{t({ en: "Open drive ↗", es: "Abrir unidad ↗" })}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EmbeddedApp
|
||||
title={t({ en: "Drive", es: "Unidad" })}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,21 @@
|
|||
// Element and the homeserver share this host (/_matrix is proxied here).
|
||||
var HOMESERVER = location.origin;
|
||||
|
||||
// Pin the Hub theme before any handover. config.json's default_theme only
|
||||
// applies to devices that never picked a theme: Element stores the choice
|
||||
// in mx_local_settings on THIS origin, and this bootstrap page is the one
|
||||
// place the Hub can set it. Version-flagged so a later choice in Element's
|
||||
// theme picker is respected.
|
||||
try {
|
||||
if (localStorage.getItem("tmbh_theme_pin_v1") !== "1") {
|
||||
var raw = localStorage.getItem("mx_local_settings");
|
||||
var settings = raw ? JSON.parse(raw) : {};
|
||||
settings.theme = "custom-OccupyHub Dark";
|
||||
localStorage.setItem("mx_local_settings", JSON.stringify(settings));
|
||||
localStorage.setItem("tmbh_theme_pin_v1", "1");
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
function openElement(query) {
|
||||
location.replace("/" + query);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue