char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Aleksander Grygierui: Stores split refactor (#27240)521a64cd0

char/aliceai-t5-moe
3.4 KiB88 linesraw
1/**
2 * deviceStore - Browser environment signals
3 *
4 * Device capabilities, OS theme and viewport in one class store:
5 * deviceStore.isMobile, deviceStore.isIOSDevice / isIOSSafari / isWKWebView /
6 * isStandalone, deviceStore.systemTheme.isDark.
7 *
8 * UA-derived flags are static for the session; isStandalone and systemTheme
9 * track live media query changes.
10 */
11
12import { browser } from '$app/environment';
13import { DEFAULT_MOBILE_BREAKPOINT, MEDIA_QUERIES } from '$lib/constants';
14import { MediaQuery } from 'svelte/reactivity';
15
16/**
17 * iOS UA token detection.
18 *
19 * iPadOS 13+ ships a desktop macOS UA, so 'iPad' is no longer present in it;
20 * a Macintosh UA combined with touch support is treated as an iPad instead.
21 * Third-party iOS browsers (Chrome, Firefox, Edge) and in-app WKWebViews all
22 * run on WKWebView and emit their own tokens (CriOS/FxiOS/EdgiOS/GSA) instead
23 * of the trailing 'Safari/' the Safari app keeps.
24 */
25const UA_PATTERNS = {
26	IOS_PHONE: /iPhone|iPod/,
27	MACINTOSH: /Macintosh/,
28	SAFARI: /Safari/,
29	WEBVIEW_IOS: /CriOS|FxiOS|EdgiOS|GSA/
30} as const;
31
32class DeviceStore {
33	/** Any iOS/iPadOS device, regardless of which app or browser embeds the page. */
34	readonly isIOSDevice: boolean = false;
35	/** The Safari browser app on iOS, excluding other iOS browsers and WKWebViews. */
36	readonly isIOSSafari: boolean = false;
37	/** PWA standalone mode: the page was launched from the home screen icon. */
38	isStandalone = $state(false);
39	/** Any WKWebView context on iOS: in-app browsers, embedded web views, and the
40	 *  third-party iOS browsers (all of which share the WKWebView engine). */
41	readonly isWKWebView: boolean = false;
42	/** OS color scheme preference; the user override lives in settingsStore. */
43	readonly systemTheme = $state({ isDark: false });
44
45	private mobile = new MediaQuery(`max-width: ${DEFAULT_MOBILE_BREAKPOINT - 1}px`);
46
47	get isMobile(): boolean {
48		return this.mobile.current;
49	}
50
51	constructor() {
52		if (!browser) return;
53
54		const ua = navigator.userAgent;
55		const isTouch = navigator.maxTouchPoints > 0;
56
57		this.isIOSDevice =
58			UA_PATTERNS.IOS_PHONE.test(ua) || (UA_PATTERNS.MACINTOSH.test(ua) && isTouch);
59		// Safari keeps 'Safari/' in the UA; non-Safari iOS browsers emit their own
60		// token instead. WKWebView typically omits 'Safari/' entirely.
61		const hasSafariToken = UA_PATTERNS.SAFARI.test(ua) && !UA_PATTERNS.WEBVIEW_IOS.test(ua);
62
63		this.isIOSSafari = this.isIOSDevice && hasSafariToken;
64		this.isWKWebView = this.isIOSDevice && !hasSafariToken;
65		// navigator.standalone is the legacy iOS-only flag (deprecated but still
66		// present); display-mode: standalone is the modern standard (Safari 16.4+).
67		this.isStandalone =
68			window.matchMedia(MEDIA_QUERIES.DISPLAY_MODE_STANDALONE).matches ||
69			(navigator as Navigator & { standalone?: boolean }).standalone === true;
70		this.systemTheme.isDark = window.matchMedia(MEDIA_QUERIES.PREFERS_DARK).matches;
71
72		// isStandalone and systemTheme can change at runtime (e.g. user installs the
73		// PWA while the tab is open); the UA-derived flags are static for the session
74		const standaloneMql = window.matchMedia(MEDIA_QUERIES.DISPLAY_MODE_STANDALONE);
75
76		standaloneMql.addEventListener('change', (e) => {
77			this.isStandalone = e.matches;
78		});
79
80		const darkMql = window.matchMedia(MEDIA_QUERIES.PREFERS_DARK);
81
82		darkMql.addEventListener('change', (e) => {
83			this.systemTheme.isDark = e.matches;
84		});
85	}
86}
87
88export const deviceStore = new DeviceStore();