78794499a2
* fix(dictionary): keep other dictionaries usable when System Dictionary syncs to an unsupported platform `dictionarySettings.providerEnabled` is whole-field synced across devices, so enabling System Dictionary on macOS/iOS sets the flag on web/Linux/Windows too. There the row is hidden and the feature is a no-op, but the settings UI read the raw flag and locked every other dictionary's toggle read-only. Gate the lock on `isSystemDictionaryEnabled(settings)` — the same platform-aware check the annotator uses — so it matches real lookup behavior and never triggers where the system dictionary can't run. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(dictionary): dispatch system dictionary handoff by native OS (fixes iPad) iPadOS sends a desktop "Macintosh" user agent, so the UA-based `getOSPlatform()` reported iPad as 'macos' and the handoff invoked the macOS-only `show_lookup_popover` Rust command that iOS never registers ("Command show_lookup_popover not found"). Derive the OS from the app service's `is*App` capability flags (sourced from the Tauri OS plugin, correct on iPad) via a new synchronous `getInitializedAppService()` accessor, so iPad routes to the iOS plugin command path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ui): constrain reader View Options dropdown to h-8 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(agent): note System Dictionary platform-detection and synced-flag patterns Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
82 lines
2.9 KiB
TypeScript
82 lines
2.9 KiB
TypeScript
import { AppService } from '@/types/system';
|
|
import { READEST_NODE_BASE_URL, READEST_WEB_BASE_URL } from './constants';
|
|
import { getRuntimeConfig } from './runtimeConfig';
|
|
|
|
declare global {
|
|
interface Window {
|
|
__READEST_CLI_ACCESS?: boolean;
|
|
}
|
|
}
|
|
|
|
export const isTauriAppPlatform = () => process.env['NEXT_PUBLIC_APP_PLATFORM'] === 'tauri';
|
|
export const isWebAppPlatform = () => process.env['NEXT_PUBLIC_APP_PLATFORM'] === 'web';
|
|
export const hasCli = () => window.__READEST_CLI_ACCESS === true;
|
|
export const isPWA = () => window.matchMedia('(display-mode: standalone)').matches;
|
|
export const getBaseUrl = () =>
|
|
getRuntimeConfig()?.apiBaseUrl ??
|
|
process.env['API_BASE_URL'] ??
|
|
process.env['NEXT_PUBLIC_API_BASE_URL'] ??
|
|
READEST_WEB_BASE_URL;
|
|
export const getNodeBaseUrl = () =>
|
|
process.env['NEXT_PUBLIC_NODE_BASE_URL'] ?? READEST_NODE_BASE_URL;
|
|
|
|
export const isMacPlatform = () =>
|
|
typeof window !== 'undefined' && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
|
|
|
|
export const getCommandPaletteShortcut = () => (isMacPlatform() ? '⌘⇧P' : 'Ctrl+Shift+P');
|
|
|
|
const isWebDevMode = () => process.env['NODE_ENV'] === 'development' && isWebAppPlatform();
|
|
|
|
// Dev API only in development mode and web platform
|
|
// with command `pnpm dev-web`
|
|
// for production build or tauri app use the production Web API
|
|
export const getAPIBaseUrl = () => (isWebDevMode() ? '/api' : `${getBaseUrl()}/api`);
|
|
|
|
// For Node.js API that currently not supported in some edge runtimes
|
|
export const getNodeAPIBaseUrl = () => (isWebDevMode() ? '/api' : `${getNodeBaseUrl()}/api`);
|
|
|
|
export interface EnvConfigType {
|
|
getAppService: () => Promise<AppService>;
|
|
}
|
|
|
|
let nativeAppService: AppService | null = null;
|
|
const getNativeAppService = async () => {
|
|
if (!nativeAppService) {
|
|
const { NativeAppService } = await import('@/services/nativeAppService');
|
|
nativeAppService = new NativeAppService();
|
|
await nativeAppService.init();
|
|
}
|
|
return nativeAppService;
|
|
};
|
|
|
|
let webAppService: AppService | null = null;
|
|
const getWebAppService = async () => {
|
|
if (!webAppService) {
|
|
const { WebAppService } = await import('@/services/webAppService');
|
|
webAppService = new WebAppService();
|
|
await webAppService.init();
|
|
}
|
|
return webAppService;
|
|
};
|
|
|
|
const environmentConfig: EnvConfigType = {
|
|
getAppService: async () => {
|
|
if (isTauriAppPlatform()) {
|
|
return getNativeAppService();
|
|
} else {
|
|
return getWebAppService();
|
|
}
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Synchronously returns the app service if it has already been created by
|
|
* {@link environmentConfig.getAppService}; null before first init. The async
|
|
* getter is preferred everywhere — use this only from synchronous code paths
|
|
* that run well after startup (e.g. capability checks during reader render),
|
|
* where the singleton is guaranteed to exist.
|
|
*/
|
|
export const getInitializedAppService = (): AppService | null => nativeAppService ?? webAppService;
|
|
|
|
export default environmentConfig;
|