forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {type TextStyle} from 'react-native'
2
3import {IS_ANDROID, IS_WEB} from '#/env'
4import {type Device, device} from '#/storage'
5
6const WEB_FONT_FAMILIES = `system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"`
7
8/*
9 * DEBUG: Uncomment to test if fonts are actually being applied on Android.
10 * This will use a distinctive cursive font. Revert when done testing.
11 */
12// const DEBUG_FONT_OVERRIDE = 'cursive'
13const DEBUG_FONT_OVERRIDE = undefined
14
15/*
16 * Google Sans Flex optical size mapping.
17 * Picks the correct optical size based on fontSize.
18 */
19function getGoogleSansFlex(weight: number, fontSize?: number): string {
20 const opticalSize = fontSize
21 ? fontSize < 14
22 ? '9pt'
23 : fontSize < 28
24 ? '24pt'
25 : fontSize < 48
26 ? '36pt'
27 : fontSize < 96
28 ? '72pt'
29 : '120pt'
30 : '24pt' // default to 24pt if no fontSize provided
31
32 const weightName =
33 {
34 100: 'Thin',
35 200: 'ExtraLight',
36 300: 'Light',
37 400: 'Regular',
38 500: 'Medium',
39 600: 'SemiBold',
40 700: 'Bold',
41 800: 'ExtraBold',
42 900: 'Black',
43 }[weight] || 'Regular'
44
45 const name = `GoogleSansFlex_${opticalSize}-${weightName}`
46 return name
47}
48
49const factor = 0.0625 // 1 - (15/16)
50const fontScaleMultipliers: Record<Device['fontScale'], number> = {
51 '-2': 1 - factor * 1, // unused
52 '-1': 1 - factor * 1,
53 '0': 1, // default
54 '1': 1 + factor * 1,
55 '2': 1 + factor * 1, // unused
56}
57
58export function computeFontScaleMultiplier(scale: Device['fontScale']) {
59 return fontScaleMultipliers[scale]
60}
61
62export function getFontScale() {
63 return device.get(['fontScale']) ?? '0'
64}
65
66export function setFontScale(fontScale: Device['fontScale']) {
67 device.set(['fontScale'], fontScale)
68}
69
70export function getFontFamily() {
71 return device.get(['fontFamily']) || 'theme'
72}
73
74export function setFontFamily(fontFamily: Device['fontFamily']) {
75 device.set(['fontFamily'], fontFamily)
76}
77
78/*
79 * Unused fonts are commented out, but the files are there if we need them.
80 */
81export function applyFonts(
82 style: TextStyle,
83 fontFamily: 'material' | 'system' | 'theme',
84) {
85 if (IS_ANDROID && fontFamily === 'material') {
86 const weight = Number(style.fontWeight || 400)
87 style.fontFamily = getGoogleSansFlex(weight, style.fontSize)
88 } else if (fontFamily === 'theme') {
89 if (IS_ANDROID) {
90 style.fontFamily =
91 {
92 400: 'Inter-Regular',
93 500: 'Inter-Medium',
94 600: 'Inter-SemiBold',
95 700: 'Inter-Bold',
96 800: 'Inter-Bold',
97 900: 'Inter-Bold',
98 }[String(style.fontWeight || '400')] || 'Inter-Regular'
99
100 if (style.fontStyle === 'italic') {
101 if (style.fontFamily === 'Inter-Regular') {
102 style.fontFamily = 'Inter-Italic'
103 } else {
104 style.fontFamily += 'Italic'
105 }
106 }
107
108 /*
109 * These are not supported on Android and actually break the styling.
110 */
111 delete style.fontWeight
112 delete style.fontStyle
113 } else {
114 style.fontFamily = 'InterVariable'
115
116 if (style.fontStyle === 'italic') {
117 style.fontFamily += 'Italic'
118 }
119 }
120
121 if (IS_WEB) {
122 // fallback families only supported on web
123 style.fontFamily += `, ${WEB_FONT_FAMILIES}`
124 }
125
126 /**
127 * Disable contextual alternates and emoji overrides in Inter
128 * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant}
129 */
130 if (IS_WEB) {
131 // @ts-expect-error - web supports 'unicode' as a valid value for fontVariant
132 style.fontVariant = (style.fontVariant || []).concat(
133 'no-contextual',
134 'unicode',
135 )
136 } else {
137 style.fontVariant = (style.fontVariant || []).concat('no-contextual')
138 }
139 } else {
140 // DEBUG: Use cursive font for testing by uncommenting DEBUG_FONT_OVERRIDE
141 if (DEBUG_FONT_OVERRIDE) {
142 style.fontFamily = DEBUG_FONT_OVERRIDE
143 } else {
144 // fallback families only supported on web
145 if (IS_WEB) {
146 style.fontFamily = style.fontFamily || WEB_FONT_FAMILIES
147 }
148 }
149 /**
150 * Overridden to previous spacing for the `system` font option.
151 * https://github.com/bluesky-social/social-app/commit/2419096e2409008b7d71fd6b8f8d0dd5b016e267
152 */
153 style.letterSpacing = 0.25
154 }
155}
156
157/**
158 * Here only for bundling purposes, not actually used.
159 */
160export {DO_NOT_USE} from '#/alf/util/unusedUseFonts'