Files
thatguygriffandClaude Opus 5 899b6e38d8
CI / Typecheck, test, build (pull_request) Successful in 26s
No browser chosen, no "Open on" button
The plain address is the one thing that button must not offer -- followed
in the browser the rewrite rules are installed in, it comes straight back
here -- so there is nothing to show until there is a browser to hand it to.
The copy button and the selectable URL were always the part carrying the
weight; the open link now ships hidden and the script reveals it along with
the scheme.

That also settles what the button should say. It went back to "Open on
<platform>": the browser's name was there to explain a tap that went
nowhere, and a button that is not shown until it works needs no such
explanation.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KF5YF3iZVKbezwALap8LYd
2026-08-29 19:40:39 -03:00

65 lines
2.8 KiB
JavaScript

// The rewrite rules that send a shared link here catch the original link on
// the way back out too, so in Safari "Open on <platform>" lands back on this
// page. Handing the address to a different browser is the way out, and the
// only way to do that from a web page is that browser's own URL scheme --
// which every one of them spells differently. Some swap the scheme, some
// prefix it, some take the whole address as a query parameter.
/** http -> googlechrome://, https -> googlechromes:// */
const chrome = (url) => url.replace(/^http(s?):/, 'googlechrome$1:');
// Edge keeps the original scheme either way, but on macOS it stays in the
// address and the scheme is prefixed, while on iOS it is folded into the
// scheme itself.
const edgeMacos = (url) => `microsoft-edge:${url}`;
const edgeIos = (url) => url.replace(/^http(s?):/, 'microsoft-edge-http$1:');
/** Firefox and Orion take the address as a parameter instead. */
const openUrl = (scheme) => (url) => `${scheme}://open-url?url=${encodeURIComponent(url)}`;
// `null` means the browser is there but ships no scheme to reach it on that
// system, so there is nothing to offer beyond the plain link.
export const BROWSERS = [
{ id: 'default', label: 'Default browser', macos: null, ios: null },
{ id: 'chrome', label: 'Chrome', macos: chrome, ios: chrome },
{ id: 'edge', label: 'Edge', macos: edgeMacos, ios: edgeIos },
{ id: 'firefox', label: 'Firefox', macos: null, ios: openUrl('firefox') },
{ id: 'orion', label: 'Orion', macos: openUrl('orion'), ios: openUrl('orion') },
];
/**
* iPadOS calls itself MacIntel, so the platform string alone cannot tell the
* two apart; the touch points can. Everything else gets the desktop table --
* the only desktop this is ever opened on is a Mac.
*
* @param {{ platform?: string, maxTouchPoints?: number }} [nav]
*/
export function detectOs(nav = globalThis.navigator) {
const platform = nav?.platform ?? '';
if (/^iP(hone|ad|od)/.test(platform)) return 'ios';
if (platform === 'MacIntel' && (nav?.maxTouchPoints ?? 0) > 1) return 'ios';
return 'macos';
}
/** The browsers worth offering here: the default, plus the ones this system
* actually has a scheme for. */
export function browsersFor(os) {
return BROWSERS.filter((browser) => browser.id === 'default' || browser[os]);
}
function browserById(id) {
return BROWSERS.find((browser) => browser.id === id);
}
/**
* The address to open. A browser with no scheme on this system, an unknown
* id, or anything that is not an ordinary web link is handed back untouched:
* a dead custom scheme opens nothing at all, which is worse than the plain
* link opening in the wrong browser.
*/
export function openUrlFor(url, browserId, os) {
const rewrite = browserById(browserId)?.[os];
if (!rewrite || !/^https?:\/\//i.test(url)) return url;
return rewrite(url);
}