+4
-4
.github/workflows/golang-test-lint.yml
+4
-4
.github/workflows/golang-test-lint.yml
···
20
20
uses: actions/setup-go@v3
21
21
with:
22
22
go-version: '1.21'
23
-
- name: Dummy JS File
24
-
run: touch bskyweb/static/js/blah.js
23
+
- name: Dummy Static Files
24
+
run: touch bskyweb/static/js/blah.js && touch bskyweb/static/media/blah.txt
25
25
- name: Check
26
26
run: cd bskyweb/ && make check
27
27
- name: Build (binary)
···
37
37
uses: actions/setup-go@v3
38
38
with:
39
39
go-version: '1.21'
40
-
- name: Dummy JS File
41
-
run: touch bskyweb/static/js/blah.js
40
+
- name: Dummy Static Files
41
+
run: touch bskyweb/static/js/blah.js && touch bskyweb/static/media/blah.txt
42
42
- name: Lint
43
43
run: cd bskyweb/ && make lint
+1
Dockerfile.embedr
+1
Dockerfile.embedr
assets/kawaii.png
assets/kawaii.png
This is a binary file and will not be displayed.
assets/kawaii_smol.png
assets/kawaii_smol.png
This is a binary file and will not be displayed.
+2
bskyweb/.gitignore
+2
bskyweb/.gitignore
+1
-1
bskyweb/cmd/bskyweb/server.go
+1
-1
bskyweb/cmd/bskyweb/server.go
···
158
158
159
159
// Cache javascript and images files for 1 week, which works because
160
160
// they're always versioned (e.g. /static/js/main.64c14927.js)
161
-
if strings.HasPrefix(path, "/static/js/") || strings.HasPrefix(path, "/static/images/") {
161
+
if strings.HasPrefix(path, "/static/js/") || strings.HasPrefix(path, "/static/images/") || strings.HasPrefix(path, "/static/media/") {
162
162
maxAge = 7 * (60 * 60 * 24) // 1 week
163
163
}
164
164
bskyweb/static/media/.gitkeep
bskyweb/static/media/.gitkeep
This is a binary file and will not be displayed.
+1
-1
package.json
+1
-1
package.json
···
15
15
"web": "expo start --web",
16
16
"use-build-number": "./scripts/useBuildNumberEnv.sh",
17
17
"use-build-number-with-bump": "./scripts/useBuildNumberEnvWithBump.sh",
18
-
"build-web": "expo export:web && node ./scripts/post-web-build.js && cp -v ./web-build/static/js/*.* ./bskyweb/static/js/",
18
+
"build-web": "expo export:web && node ./scripts/post-web-build.js && cp -v ./web-build/static/js/*.* ./bskyweb/static/js/ && cp -v ./web-build/static/media/*.png ./bskyweb/static/media/",
19
19
"build-all": "yarn intl:build && yarn use-build-number-with-bump eas build --platform all",
20
20
"build-ios": "yarn use-build-number-with-bump eas build -p ios",
21
21
"build-android": "yarn use-build-number-with-bump eas build -p android",
+4
-4
src/state/persisted/index.ts
+4
-4
src/state/persisted/index.ts
···
1
1
import EventEmitter from 'eventemitter3'
2
+
3
+
import BroadcastChannel from '#/lib/broadcast'
2
4
import {logger} from '#/logger'
3
-
import {defaults, Schema} from '#/state/persisted/schema'
4
5
import {migrate} from '#/state/persisted/legacy'
6
+
import {defaults, Schema} from '#/state/persisted/schema'
5
7
import * as store from '#/state/persisted/store'
6
-
import BroadcastChannel from '#/lib/broadcast'
7
-
8
-
export type {Schema, PersistedAccount} from '#/state/persisted/schema'
8
+
export type {PersistedAccount, Schema} from '#/state/persisted/schema'
9
9
export {defaults} from '#/state/persisted/schema'
10
10
11
11
const broadcast = new BroadcastChannel('BSKY_BROADCAST_CHANNEL')
+2
src/state/persisted/schema.ts
+2
src/state/persisted/schema.ts
···
80
80
pdsAddressHistory: z.array(z.string()).optional(),
81
81
disableHaptics: z.boolean().optional(),
82
82
disableAutoplay: z.boolean().optional(),
83
+
kawaii: z.boolean().optional(),
83
84
})
84
85
export type Schema = z.infer<typeof schema>
85
86
···
117
118
pdsAddressHistory: [],
118
119
disableHaptics: false,
119
120
disableAutoplay: prefersReducedMotion,
121
+
kawaii: false,
120
122
}
+4
-1
src/state/preferences/index.tsx
+4
-1
src/state/preferences/index.tsx
···
7
7
import {Provider as ExternalEmbedsProvider} from './external-embeds-prefs'
8
8
import {Provider as HiddenPostsProvider} from './hidden-posts'
9
9
import {Provider as InAppBrowserProvider} from './in-app-browser'
10
+
import {Provider as KawaiiProvider} from './kawaii'
10
11
import {Provider as LanguagesProvider} from './languages'
11
12
12
13
export {
···
32
33
<InAppBrowserProvider>
33
34
<DisableHapticsProvider>
34
35
<AutoplayProvider>
35
-
<DmServiceUrlProvider>{children}</DmServiceUrlProvider>
36
+
<DmServiceUrlProvider>
37
+
<KawaiiProvider>{children}</KawaiiProvider>
38
+
</DmServiceUrlProvider>
36
39
</AutoplayProvider>
37
40
</DisableHapticsProvider>
38
41
</InAppBrowserProvider>
+50
src/state/preferences/kawaii.tsx
+50
src/state/preferences/kawaii.tsx
···
1
+
import React from 'react'
2
+
3
+
import {isWeb} from '#/platform/detection'
4
+
import * as persisted from '#/state/persisted'
5
+
6
+
type StateContext = persisted.Schema['kawaii']
7
+
8
+
const stateContext = React.createContext<StateContext>(
9
+
persisted.defaults.kawaii,
10
+
)
11
+
12
+
export function Provider({children}: React.PropsWithChildren<{}>) {
13
+
const [state, setState] = React.useState(persisted.get('kawaii'))
14
+
15
+
const setStateWrapped = React.useCallback(
16
+
(kawaii: persisted.Schema['kawaii']) => {
17
+
setState(kawaii)
18
+
persisted.write('kawaii', kawaii)
19
+
},
20
+
[setState],
21
+
)
22
+
23
+
React.useEffect(() => {
24
+
return persisted.onUpdate(() => {
25
+
setState(persisted.get('kawaii'))
26
+
})
27
+
}, [setStateWrapped])
28
+
29
+
React.useEffect(() => {
30
+
// dumb and stupid but it's web only so just refresh the page if you want to change it
31
+
32
+
if (isWeb) {
33
+
const kawaii = new URLSearchParams(window.location.search).get('kawaii')
34
+
switch (kawaii) {
35
+
case 'true':
36
+
setStateWrapped(true)
37
+
break
38
+
case 'false':
39
+
setStateWrapped(false)
40
+
break
41
+
}
42
+
}
43
+
}, [setStateWrapped])
44
+
45
+
return <stateContext.Provider value={state}>{children}</stateContext.Provider>
46
+
}
47
+
48
+
export function useKawaiiMode() {
49
+
return React.useContext(stateContext)
50
+
}
+9
-4
src/view/com/auth/SplashScreen.web.tsx
+9
-4
src/view/com/auth/SplashScreen.web.tsx
···
4
4
import {msg, Trans} from '@lingui/macro'
5
5
import {useLingui} from '@lingui/react'
6
6
7
+
import {useKawaiiMode} from '#/state/preferences/kawaii'
7
8
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
8
9
import {Logo} from '#/view/icons/Logo'
9
10
import {Logotype} from '#/view/icons/Logotype'
···
27
28
const {_} = useLingui()
28
29
const t = useTheme()
29
30
const {isTabletOrMobile: isMobileWeb} = useWebMediaQueries()
31
+
32
+
const kawaii = useKawaiiMode()
30
33
31
34
return (
32
35
<>
···
66
69
]}>
67
70
<ErrorBoundary>
68
71
<View style={[a.justify_center, a.align_center]}>
69
-
<Logo width={92} fill="sky" />
72
+
<Logo width={kawaii ? 300 : 92} fill="sky" />
70
73
71
-
<View style={[a.pb_sm, a.pt_5xl]}>
72
-
<Logotype width={161} fill={t.atoms.text.color} />
73
-
</View>
74
+
{!kawaii && (
75
+
<View style={[a.pb_sm, a.pt_5xl]}>
76
+
<Logotype width={161} fill={t.atoms.text.color} />
77
+
</View>
78
+
)}
74
79
75
80
<Text
76
81
style={[
+12
-2
src/view/com/home/HomeHeaderLayout.web.tsx
+12
-2
src/view/com/home/HomeHeaderLayout.web.tsx
···
15
15
import {usePalette} from 'lib/hooks/usePalette'
16
16
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
17
17
import {Logo} from '#/view/icons/Logo'
18
+
import {useKawaiiMode} from '../../../state/preferences/kawaii'
18
19
import {Link} from '../util/Link'
19
20
import {HomeHeaderLayoutMobile} from './HomeHeaderLayoutMobile'
20
21
···
43
44
const {hasSession} = useSession()
44
45
const {_} = useLingui()
45
46
47
+
const kawaii = useKawaiiMode()
48
+
46
49
return (
47
50
<>
48
51
{hasSession && (
49
-
<View style={[pal.view, pal.border, styles.bar, styles.topBar]}>
52
+
<View
53
+
style={[
54
+
pal.view,
55
+
pal.border,
56
+
styles.bar,
57
+
styles.topBar,
58
+
kawaii && {paddingTop: 4, paddingBottom: 0},
59
+
]}>
50
60
<Link
51
61
href="/settings/following-feed"
52
62
hitSlop={10}
···
58
68
style={pal.textLight as FontAwesomeIconStyle}
59
69
/>
60
70
</Link>
61
-
<Logo width={28} />
71
+
<Logo width={kawaii ? 60 : 28} />
62
72
<Link
63
73
href="/settings/saved-feeds"
64
74
hitSlop={10}
+23
-2
src/view/icons/Logo.tsx
+23
-2
src/view/icons/Logo.tsx
···
1
1
import React from 'react'
2
2
import {StyleSheet, TextProps} from 'react-native'
3
3
import Svg, {
4
-
Path,
5
4
Defs,
6
5
LinearGradient,
6
+
Path,
7
+
PathProps,
7
8
Stop,
8
9
SvgProps,
9
-
PathProps,
10
10
} from 'react-native-svg'
11
+
import {Image} from 'expo-image'
11
12
12
13
import {colors} from '#/lib/styles'
14
+
import {useKawaiiMode} from '#/state/preferences/kawaii'
13
15
14
16
const ratio = 57 / 64
15
17
···
25
27
const _fill = gradient ? 'url(#sky)' : fill || styles?.color || colors.blue3
26
28
// @ts-ignore it's fiiiiine
27
29
const size = parseInt(rest.width || 32)
30
+
31
+
const isKawaii = useKawaiiMode()
32
+
33
+
if (isKawaii) {
34
+
return (
35
+
<Image
36
+
source={
37
+
size > 100
38
+
? require('../../../assets/kawaii.png')
39
+
: require('../../../assets/kawaii_smol.png')
40
+
}
41
+
accessibilityLabel="Bluesky"
42
+
accessibilityHint=""
43
+
accessibilityIgnoresInvertColors
44
+
style={[{height: size, aspectRatio: 1.4}]}
45
+
/>
46
+
)
47
+
}
48
+
28
49
return (
29
50
<Svg
30
51
fill="none"
+13
src/view/shell/Drawer.tsx
+13
src/view/shell/Drawer.tsx
···
18
18
import {StackActions, useNavigation} from '@react-navigation/native'
19
19
20
20
import {emitSoftReset} from '#/state/events'
21
+
import {useKawaiiMode} from '#/state/preferences/kawaii'
21
22
import {useUnreadNotifications} from '#/state/queries/notifications/unread'
22
23
import {useProfileQuery} from '#/state/queries/profile'
23
24
import {SessionAccount, useSession} from '#/state/session'
···
117
118
const {isAtHome, isAtSearch, isAtFeeds, isAtNotifications, isAtMyProfile} =
118
119
useNavigationTabState()
119
120
const {hasSession, currentAccount} = useSession()
121
+
const kawaii = useKawaiiMode()
120
122
121
123
// events
122
124
// =
···
262
264
href="https://bsky.social/about/support/privacy-policy"
263
265
text={_(msg`Privacy Policy`)}
264
266
/>
267
+
{kawaii && (
268
+
<Text type="md" style={pal.textLight}>
269
+
Logo by{' '}
270
+
<TextLink
271
+
type="md"
272
+
href="/profile/sawaratsuki.bsky.social"
273
+
text="@sawaratsuki.bsky.social"
274
+
style={pal.link}
275
+
/>
276
+
</Text>
277
+
)}
265
278
</View>
266
279
267
280
<View style={styles.smallSpacer} />