Files
llink/js/desktop/src/lib/platform/web.ts
T
2026-06-01 12:46:14 -07:00

110 lines
3.1 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-empty-function */
import { useAutoplayPayloadStore } from "@/stores/autoplay-payload-store";
import type { AutoplayPayload } from "@/lib/autoplay-ipc";
import { apiClient } from "@/api/client";
import type { Platform } from "./types";
declare const __APP_VERSION__: string;
function detectWebPlatform(): "darwin" | "win32" | "linux" | "web" {
if (typeof navigator === "undefined") return "web";
const ua = navigator.userAgent;
if (/Mac|iPhone|iPad|iPod/i.test(ua)) return "darwin";
if (/Win/i.test(ua)) return "win32";
if (/Linux|X11/i.test(ua)) return "linux";
return "web";
}
function downloadCrossOrigin(url: string, filename?: string) {
const a = document.createElement("a");
a.href = url;
if (filename) a.download = filename;
a.target = "_blank";
a.rel = "noopener noreferrer";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
const baseTitle = typeof document !== "undefined" ? document.title : "llink";
function applyDockBadge(count: number) {
if (typeof document === "undefined") return;
document.title = count > 0 ? `(${count}) ${baseTitle}` : baseTitle;
}
const NOT_SUPPORTED = "Not supported in the web app";
export const webPlatform: Platform = {
kind: "web",
window: {
minimize: () => {},
maximize: () => {},
fullscreen: () => {},
close: () => {},
onMaximizeChange: () => () => {},
platform: detectWebPlatform(),
},
huddle: {
isSupported: false,
open: () => { throw new Error(NOT_SUPPORTED); },
close: () => {},
getScreenSources: async () => { throw new Error(NOT_SUPPORTED); },
},
screenRecord: {
isSupported: false,
start: () => { throw new Error(NOT_SUPPORTED); },
stop: () => {},
cancel: () => {},
onStopRequested: () => () => {},
getScreenSources: async () => { throw new Error(NOT_SUPPORTED); },
},
autoplay: {
play: (payload: AutoplayPayload) => {
useAutoplayPayloadStore.getState().setPayload(payload);
},
dismiss: () => {
useAutoplayPayloadStore.getState().setPayload(null);
},
navigate: (d) => {
useAutoplayPayloadStore.getState().setPayload(null);
useAutoplayPayloadStore.getState().setPendingNav(d);
},
onPlay: (cb) =>
useAutoplayPayloadStore.subscribe((state, prev) => {
if (state.payload && state.payload !== prev.payload) cb(state.payload);
}),
onStop: (cb) =>
useAutoplayPayloadStore.subscribe((state, prev) => {
if (!state.payload && prev.payload) cb();
}),
onNavigate: (cb) =>
useAutoplayPayloadStore.subscribe((state, prev) => {
if (state.pendingNav && state.pendingNav !== prev.pendingNav) {
cb({ networkId: state.pendingNav.networkId, streamId: state.pendingNav.streamId });
}
}),
},
link: {
fetchMetadata: (url) => apiClient.getLinkMetadata(url).catch(() => null),
openExternal: async (url) => {
window.open(url, "_blank", "noopener,noreferrer");
},
},
attachment: {
download: downloadCrossOrigin,
},
app: {
setDockBadge: applyDockBadge,
getVersion: async () => __APP_VERSION__,
},
};