Skip to content

Commit 6eb2069

Browse files
authored
Merge pull request #25 from eurosky-social/eurosky/fork
deploy
2 parents 2d0f776 + f117d77 commit 6eb2069

12 files changed

Lines changed: 693 additions & 426 deletions

File tree

src/alf/atoms.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {type StyleProp, type ViewStyle} from 'react-native'
22
import {atoms as baseAtoms} from '@bsky.app/alf'
33

44
import {CARD_ASPECT_RATIO} from '#/lib/constants'
5+
import * as tokens from '#/alf/tokens'
56
import {native, platform, web} from '#/alf/util/platform'
67
import * as Layout from '#/components/Layout'
78

@@ -10,6 +11,14 @@ const EXP_CURVE = 'cubic-bezier(0.16, 1, 0.3, 1)'
1011
export const atoms = {
1112
...baseAtoms,
1213

14+
// Eurosky fork: text size for inputs
15+
// A 16px minimum keeps mobile browsers from
16+
// auto-zooming when an input is focused.
17+
text_input: {
18+
fontSize: tokens.inputMinFontSize,
19+
letterSpacing: tokens.TRACKING,
20+
},
21+
1322
h_full_vh: web({
1423
height: '100vh',
1524
}),

src/alf/tokens.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import {EUROSKY_GRADIENTS} from '#/config/eurosky-theme'
55

66
export * from '@bsky.app/alf/dist/tokens'
77

8+
// Eurosky fork: minimum font size for text inputs.
9+
// Mobile browsers auto-zoom when a focused input renders below 16px,
10+
// so inputs never go under this size.
11+
export const inputMinFontSize = 16
12+
813
export const color = {
914
temp_purple: tokens.labelerColor.purple,
1015
temp_purple_dark: tokens.labelerColor.purple_dark,

src/components/ProgressGuide/FollowDialog.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ function SearchInput({
710710
onChangeText={onChangeText}
711711
onFocus={onFocus}
712712
onBlur={onBlur}
713-
style={[a.flex_1, a.py_md, a.text_md, t.atoms.text]}
713+
style={[a.flex_1, a.py_md, a.text_input, t.atoms.text]}
714714
placeholderTextColor={t.palette.contrast_500}
715715
keyboardAppearance={t.name === 'light' ? 'light' : 'dark'}
716716
returnKeyType="search"

src/components/dialogs/SearchablePeopleList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ function SearchInput({
674674
onChangeText={onChangeText}
675675
onFocus={onFocus}
676676
onBlur={onBlur}
677-
style={[a.flex_1, a.py_md, a.text_md, t.atoms.text]}
677+
style={[a.flex_1, a.py_md, a.text_input, t.atoms.text]}
678678
placeholderTextColor={t.palette.contrast_500}
679679
keyboardAppearance={t.name === 'light' ? 'light' : 'dark'}
680680
returnKeyType="search"

src/components/dms/components/UserSearchInput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export function UserSearchInput({
4545
onChangeText={onChangeText}
4646
onFocus={onFocus}
4747
onBlur={onBlur}
48-
style={[a.flex_1, a.py_md, a.text_md, t.atoms.text]}
48+
style={[a.flex_1, a.py_md, a.text_input, t.atoms.text]}
4949
placeholderTextColor={t.palette.contrast_500}
5050
keyboardAppearance={t.name === 'light' ? 'light' : 'dark'}
5151
returnKeyType="search"

src/components/forms/AutosizedTextarea.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export function AutosizedTextarea({
3535
const {style, minInputHeight, maxInputHeight, verticalContentPadding} =
3636
useMemo(() => {
3737
const normalizedStyles = normalizeTextStyles(
38-
[a.text_md, a.leading_snug, t.atoms.text, outerStyle],
38+
[a.text_input, a.leading_snug, t.atoms.text, outerStyle],
3939
{
4040
fontScale: fonts.scaleMultiplier,
4141
fontFamily: fonts.family,

src/components/forms/TextField.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,12 @@ export function createInput(Component: typeof TextInput) {
207207
a.relative,
208208
a.z_20,
209209
a.flex_1,
210-
a.text_md,
210+
a.text_input,
211211
t.atoms.text,
212212
a.px_xs,
213213
{
214214
// paddingVertical doesn't work w/multiline - esb
215-
lineHeight: a.text_md.fontSize * 1.2,
215+
lineHeight: a.text_input.fontSize * 1.2,
216216
textAlignVertical: rest.multiline ? 'top' : undefined,
217217
minHeight: rest.multiline ? 80 : undefined,
218218
minWidth: 0,
@@ -436,17 +436,17 @@ export function GhostText({
436436
<Text
437437
style={[
438438
{color: 'transparent'},
439-
a.text_md,
440-
{lineHeight: a.text_md.fontSize * 1.1875},
439+
a.text_input,
440+
{lineHeight: a.text_input.fontSize * 1.1875},
441441
a.w_full,
442442
]}
443443
numberOfLines={1}>
444444
{children}
445445
<Text
446446
style={[
447447
t.atoms.text_contrast_low,
448-
a.text_md,
449-
{lineHeight: a.text_md.fontSize * 1.1875},
448+
a.text_input,
449+
{lineHeight: a.text_input.fontSize * 1.1875},
450450
]}>
451451
{value}
452452
</Text>

src/config/eurosky.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,17 @@ export const EUROSKY = {
1919
/** Display name used in page/tab titles and in-app brand text. */
2020
name: 'Eurosky',
2121
},
22+
web: {
23+
/**
24+
* Web hostnames this app serves its own UI on. A link pasted to one of
25+
* these hosts (in the composer or a DM) is detected as a first-party
26+
* record - quote post, feed, list, or starter pack - and rendered as a
27+
* rich embed, exactly like a bsky.app link, instead of a plain link card.
28+
*
29+
* Bare hostnames only: no scheme, no trailing slash, no subdomain wildcard
30+
* (matching is exact). bsky.app is always treated as first-party in
31+
* addition to these.
32+
*/
33+
hosts: ['mu.social'],
34+
},
2235
} as const

src/lib/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ export const TRUSTED_VERIFIER_DIDS = [
242242
'did:plc:durcipmx2rwgzzagbiumobs5', // france-atmosphe.re
243243
'did:plc:ooensn4mr5mhznzypvxelfa3', // eurosky.social
244244
'did:plc:u5zp7npt5kpueado77kuihyz', // npmx.dev
245+
'did:plc:hd564mpf6bekrwzyhvujs54b', // medsky.network
245246
]
246247

247248
/**

src/lib/strings/url-helpers.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,27 @@ import {BSKY_SERVICE} from '#/lib/constants'
66
import {isInvalidHandle} from '#/lib/strings/handles'
77
import {startUriToStarterPackUri} from '#/lib/strings/starter-pack'
88
import {logger} from '#/logger'
9+
import {EUROSKY} from '#/config/eurosky'
910

1011
export const BSKY_APP_HOST = 'https://bsky.app'
12+
13+
/**
14+
* Hostnames whose web URLs we treat as first-party app links. Pasting one of
15+
* these into the composer or a DM resolves it to an in-app record embed (quote
16+
* post, feed, list, starter pack) instead of a plain external link card.
17+
* Upstream only knows about bsky.app; the fork adds its own web host(s) via
18+
* EUROSKY.web.hosts. See isBskyAppUrl().
19+
*/
20+
const APP_URL_HOSTS = ['bsky.app', ...EUROSKY.web.hosts]
21+
1122
const BSKY_TRUSTED_HOSTS = [
1223
'bsky\\.app',
1324
'bsky\\.social',
1425
'blueskyweb\\.xyz',
1526
'blueskyweb\\.zendesk\\.com',
27+
// Fork web host(s) are first-party too, so links to them are not treated as
28+
// untrusted/external (e.g. no phishing warning interstitial).
29+
...EUROSKY.web.hosts.map(host => host.replace(/\./g, '\\.')),
1630
...(__DEV__ ? ['localhost:19006', 'localhost:8100'] : []),
1731
]
1832

@@ -121,18 +135,22 @@ export function toBskyAppUrl(url: string): string {
121135
}
122136

123137
export function isBskyAppUrl(url: string): boolean {
124-
return url.startsWith('https://bsky.app/')
138+
// Match by parsed hostname rather than a string prefix so that fork hosts are
139+
// supported and look-alike hosts (e.g. https://bsky.app.evil.com/) are not.
140+
try {
141+
const urlp = new URL(url)
142+
return urlp.protocol === 'https:' && APP_URL_HOSTS.includes(urlp.hostname)
143+
} catch {
144+
return false
145+
}
125146
}
126147

127148
export function isRelativeUrl(url: string): boolean {
128149
return /^\/[^/]/.test(url)
129150
}
130151

131152
export function isBskyRSSUrl(url: string): boolean {
132-
return (
133-
(url.startsWith('https://bsky.app/') || isRelativeUrl(url)) &&
134-
/\/rss\/?$/.test(url)
135-
)
153+
return (isBskyAppUrl(url) || isRelativeUrl(url)) && /\/rss\/?$/.test(url)
136154
}
137155

138156
export function isExternalUrl(url: string): boolean {

0 commit comments

Comments
 (0)