diff options
author | Eric Bailey <git@esb.lol> | 2024-09-18 19:35:34 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-18 19:35:34 -0500 |
commit | cbc7cd080889bbb8af052717d2831880ccd10475 (patch) | |
tree | 4dcd92ad101e00701479d31611735214852d32a6 /src/components | |
parent | fb3be7982024aed4cf141fbe3f658d8d6b0f94f5 (diff) | |
download | voidsky-cbc7cd080889bbb8af052717d2831880ccd10475.tar.zst |
[Neue] Base (#5395)
* Add fontScale, gate it, fix some computes * Add inter, integrate * Clean up * Apply to old Text component * Use numeric weight * Cleanup * Clean up appearance settings * Global tracking * Fix regular italic variant * Refactor settings and fontScale values * Remove flags * Get rid of lower weight font usage * Remove gate from settings * Refactor appearance settings for reuse * Add neue type nux * Update defaults * Load fonts, add fallback families * Load fonts via plugin in production * Fixes * Fix for web * Nits --------- Co-authored-by: Hailey <me@haileyok.com>
Diffstat (limited to 'src/components')
-rw-r--r-- | src/components/Button.tsx | 12 | ||||
-rw-r--r-- | src/components/Dialog/index.tsx | 1 | ||||
-rw-r--r-- | src/components/Dialog/index.web.tsx | 1 | ||||
-rw-r--r-- | src/components/Dialog/utils.ts | 18 | ||||
-rw-r--r-- | src/components/Typography.tsx | 26 | ||||
-rw-r--r-- | src/components/dialogs/nuxs/NeueTypography.tsx | 119 | ||||
-rw-r--r-- | src/components/dialogs/nuxs/index.tsx | 80 | ||||
-rw-r--r-- | src/components/icons/TextSize.tsx | 5 | ||||
-rw-r--r-- | src/components/icons/TitleCase.tsx | 5 |
9 files changed, 243 insertions, 24 deletions
diff --git a/src/components/Button.tsx b/src/components/Button.tsx index d65444e1f..704aa9d98 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -7,7 +7,6 @@ import { PressableProps, StyleProp, StyleSheet, - Text, TextProps, TextStyle, View, @@ -17,7 +16,7 @@ import {LinearGradient} from 'expo-linear-gradient' import {android, atoms as a, flatten, select, tokens, useTheme} from '#/alf' import {Props as SVGIconProps} from '#/components/icons/common' -import {normalizeTextStyles} from '#/components/Typography' +import {Text} from '#/components/Typography' export type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'gradient' export type ButtonColor = @@ -635,14 +634,7 @@ export function ButtonText({children, style, ...rest}: ButtonTextProps) { const textStyles = useSharedButtonTextStyles() return ( - <Text - {...rest} - style={normalizeTextStyles([ - a.font_bold, - a.text_center, - textStyles, - style, - ])}> + <Text {...rest} style={[a.font_bold, a.text_center, textStyles, style]}> {children} </Text> ) diff --git a/src/components/Dialog/index.tsx b/src/components/Dialog/index.tsx index cdce3765f..d5d92048a 100644 --- a/src/components/Dialog/index.tsx +++ b/src/components/Dialog/index.tsx @@ -37,6 +37,7 @@ import {Portal} from '#/components/Portal' export {useDialogContext, useDialogControl} from '#/components/Dialog/context' export * from '#/components/Dialog/types' +export * from '#/components/Dialog/utils' // @ts-ignore export const Input = createInput(BottomSheetTextInput) diff --git a/src/components/Dialog/index.web.tsx b/src/components/Dialog/index.web.tsx index aff1842f7..bf20bd295 100644 --- a/src/components/Dialog/index.web.tsx +++ b/src/components/Dialog/index.web.tsx @@ -27,6 +27,7 @@ import {Portal} from '#/components/Portal' export {useDialogContext, useDialogControl} from '#/components/Dialog/context' export * from '#/components/Dialog/types' +export * from '#/components/Dialog/utils' export {Input} from '#/components/forms/TextField' const stopPropagation = (e: any) => e.stopPropagation() diff --git a/src/components/Dialog/utils.ts b/src/components/Dialog/utils.ts new file mode 100644 index 000000000..058d6e804 --- /dev/null +++ b/src/components/Dialog/utils.ts @@ -0,0 +1,18 @@ +import React from 'react' + +import {DialogControlProps} from '#/components/Dialog/types' + +export function useAutoOpen(control: DialogControlProps, showTimeout?: number) { + React.useEffect(() => { + if (showTimeout) { + const timeout = setTimeout(() => { + control.open() + }, showTimeout) + return () => { + clearTimeout(timeout) + } + } else { + control.open() + } + }, [control, showTimeout]) +} diff --git a/src/components/Typography.tsx b/src/components/Typography.tsx index 31dd931c6..15f88468a 100644 --- a/src/components/Typography.tsx +++ b/src/components/Typography.tsx @@ -3,7 +3,7 @@ import {StyleProp, TextProps as RNTextProps, TextStyle} from 'react-native' import {UITextView} from 'react-native-uitextview' import {isNative} from '#/platform/detection' -import {atoms, flatten, useTheme, web} from '#/alf' +import {Alf, applyFonts, atoms, flatten, useAlf, useTheme, web} from '#/alf' export type TextProps = RNTextProps & { /** @@ -34,19 +34,30 @@ export function leading< * If the `lineHeight` value is > 2, we assume it's an absolute value and * returns it as-is. */ -export function normalizeTextStyles(styles: StyleProp<TextStyle>) { +export function normalizeTextStyles( + styles: StyleProp<TextStyle>, + { + fontScale, + fontFamily, + }: { + fontScale: number + fontFamily: Alf['fonts']['family'] + } & Pick<Alf, 'flags'>, +) { const s = flatten(styles) // should always be defined on these components - const fontSize = s.fontSize || atoms.text_md.fontSize + s.fontSize = (s.fontSize || atoms.text_md.fontSize) * fontScale if (s?.lineHeight) { if (s.lineHeight !== 0 && s.lineHeight <= 2) { - s.lineHeight = Math.round(fontSize * s.lineHeight) + s.lineHeight = Math.round(s.fontSize * s.lineHeight) } } else if (!isNative) { s.lineHeight = s.fontSize } + applyFonts(s, fontFamily) + return s } @@ -54,8 +65,13 @@ export function normalizeTextStyles(styles: StyleProp<TextStyle>) { * Our main text component. Use this most of the time. */ export function Text({style, selectable, ...rest}: TextProps) { + const {fonts, flags} = useAlf() const t = useTheme() - const s = normalizeTextStyles([atoms.text_sm, t.atoms.text, flatten(style)]) + const s = normalizeTextStyles([atoms.text_sm, t.atoms.text, flatten(style)], { + fontScale: fonts.scaleMultiplier, + fontFamily: fonts.family, + flags, + }) return <UITextView selectable={selectable} uiTextView style={s} {...rest} /> } diff --git a/src/components/dialogs/nuxs/NeueTypography.tsx b/src/components/dialogs/nuxs/NeueTypography.tsx new file mode 100644 index 000000000..f33cea8e7 --- /dev/null +++ b/src/components/dialogs/nuxs/NeueTypography.tsx @@ -0,0 +1,119 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {AppearanceToggleButtonGroup} from '#/screens/Settings/AppearanceSettings' +import {atoms as a, useAlf, useTheme} from '#/alf' +import * as Dialog from '#/components/Dialog' +import {useNuxDialogContext} from '#/components/dialogs/nuxs' +import {Divider} from '#/components/Divider' +import {TextSize_Stroke2_Corner0_Rounded as TextSize} from '#/components/icons/TextSize' +import {TitleCase_Stroke2_Corner0_Rounded as Aa} from '#/components/icons/TitleCase' +import {Text} from '#/components/Typography' + +export function NeueTypography() { + const t = useTheme() + const {_} = useLingui() + const nuxDialogs = useNuxDialogContext() + const control = Dialog.useDialogControl() + const {fonts} = useAlf() + + Dialog.useAutoOpen(control, 3e3) + + const onClose = React.useCallback(() => { + nuxDialogs.dismissActiveNux() + }, [nuxDialogs]) + + const onChangeFontFamily = React.useCallback( + (values: string[]) => { + const next = values[0] === 'system' ? 'system' : 'theme' + fonts.setFontFamily(next) + }, + [fonts], + ) + + const onChangeFontScale = React.useCallback( + (values: string[]) => { + const next = values[0] || ('0' as any) + fonts.setFontScale(next) + }, + [fonts], + ) + + return ( + <Dialog.Outer control={control} onClose={onClose}> + <Dialog.Handle /> + + <Dialog.ScrollableInner label={_(msg`Introducing new font settings`)}> + <View style={[a.gap_xl]}> + <View style={[a.gap_md]}> + <Text style={[a.text_3xl, {fontWeight: '900'}]}> + <Trans>Introducing new font settings ✨</Trans> + </Text> + <Text style={[a.text_lg, a.leading_snug]}> + <Trans> + To the ensure the best possible experience, we're introducing a + new theme font, along with adjustable font sizing settings. + </Trans> + </Text> + <Text + style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}> + <Trans> + Defaults are shown below. You can edit these in your Appearance + Settings later. + </Trans> + </Text> + </View> + + <Divider /> + + <View style={[a.gap_lg]}> + <AppearanceToggleButtonGroup + title={_(msg`Font`)} + description={_( + msg`For the best experience, we recommend using the theme font.`, + )} + icon={Aa} + items={[ + { + label: _(msg`System`), + name: 'system', + }, + { + label: _(msg`Theme`), + name: 'theme', + }, + ]} + values={[fonts.family]} + onChange={onChangeFontFamily} + /> + + <AppearanceToggleButtonGroup + title={_(msg`Font size`)} + icon={TextSize} + items={[ + { + label: _(msg`Smaller`), + name: '-1', + }, + { + label: _(msg`Default`), + name: '0', + }, + { + label: _(msg`Larger`), + name: '1', + }, + ]} + values={[fonts.scale]} + onChange={onChangeFontScale} + /> + </View> + </View> + + <Dialog.Close /> + </Dialog.ScrollableInner> + </Dialog.Outer> + ) +} diff --git a/src/components/dialogs/nuxs/index.tsx b/src/components/dialogs/nuxs/index.tsx index a38c87b68..b93831ad3 100644 --- a/src/components/dialogs/nuxs/index.tsx +++ b/src/components/dialogs/nuxs/index.tsx @@ -1,4 +1,5 @@ import React from 'react' +import {AppBskyActorDefs} from '@atproto/api' import {useGate} from '#/lib/statsig/statsig' import {logger} from '#/logger' @@ -8,9 +9,16 @@ import { useRemoveNuxsMutation, useUpsertNuxMutation, } from '#/state/queries/nuxs' -import {useSession} from '#/state/session' +import { + usePreferencesQuery, + UsePreferencesQueryResponse, +} from '#/state/queries/preferences' +import {useProfileQuery} from '#/state/queries/profile' +import {SessionAccount, useSession} from '#/state/session' import {useOnboardingState} from '#/state/shell' +import {NeueTypography} from '#/components/dialogs/nuxs/NeueTypography' import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing' +// NUXs import {TenMillion} from '#/components/dialogs/nuxs/TenMillion' import {IS_DEV} from '#/env' @@ -21,11 +29,27 @@ type Context = { const queuedNuxs: { id: Nux - enabled?: (props: {gate: ReturnType<typeof useGate>}) => boolean + enabled?: (props: { + gate: ReturnType<typeof useGate> + currentAccount: SessionAccount + currentProfile: AppBskyActorDefs.ProfileViewDetailed + preferences: UsePreferencesQueryResponse + }) => boolean }[] = [ { id: Nux.TenMillionDialog, }, + { + id: Nux.NeueTypography, + enabled(props) { + if (props.currentProfile.createdAt) { + if (new Date(props.currentProfile.createdAt) < new Date('2024-09-25')) { + return true + } + } + return false + }, + }, ] const Context = React.createContext<Context>({ @@ -38,12 +62,31 @@ export function useNuxDialogContext() { } export function NuxDialogs() { - const {hasSession} = useSession() - const onboardingState = useOnboardingState() - return hasSession && !onboardingState.isActive ? <Inner /> : null + const {currentAccount} = useSession() + const {data: preferences} = usePreferencesQuery() + const {data: profile} = useProfileQuery({did: currentAccount?.did}) + const onboardingActive = useOnboardingState().isActive + + const isLoading = + !currentAccount || !preferences || !profile || onboardingActive + return !isLoading ? ( + <Inner + currentAccount={currentAccount} + currentProfile={profile} + preferences={preferences} + /> + ) : null } -function Inner() { +function Inner({ + currentAccount, + currentProfile, + preferences, +}: { + currentAccount: SessionAccount + currentProfile: AppBskyActorDefs.ProfileViewDetailed + preferences: UsePreferencesQueryResponse +}) { const gate = useGate() const {nuxs} = useNuxs() const [snoozed, setSnoozed] = React.useState(() => { @@ -80,10 +123,19 @@ function Inner() { const nux = nuxs.find(nux => nux.id === id) // check if completed first - if (nux && nux.completed) continue + if (nux && nux.completed) { + continue + } // then check gate (track exposure) - if (enabled && !enabled({gate})) continue + if ( + enabled && + !enabled({gate, currentAccount, currentProfile, preferences}) + ) { + continue + } + + logger.debug(`NUX dialogs: activating '${id}' NUX`) // we have a winner setActiveNux(id) @@ -104,7 +156,16 @@ function Inner() { break } - }, [nuxs, snoozed, snoozeNuxDialog, upsertNux, gate]) + }, [ + nuxs, + snoozed, + snoozeNuxDialog, + upsertNux, + gate, + currentAccount, + currentProfile, + preferences, + ]) const ctx = React.useMemo(() => { return { @@ -116,6 +177,7 @@ function Inner() { return ( <Context.Provider value={ctx}> {activeNux === Nux.TenMillionDialog && <TenMillion />} + {activeNux === Nux.NeueTypography && <NeueTypography />} </Context.Provider> ) } diff --git a/src/components/icons/TextSize.tsx b/src/components/icons/TextSize.tsx new file mode 100644 index 000000000..73a6a085d --- /dev/null +++ b/src/components/icons/TextSize.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const TextSize_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M9 5a1 1 0 0 1 1-1h12a1 1 0 1 1 0 2h-5v14a1 1 0 1 1-2 0V6h-5a1 1 0 0 1-1-1Zm-3.073 7v8a1 1 0 1 0 2 0v-8H12a1 1 0 1 0 0-2H6.971a1.015 1.015 0 0 0-.089 0H2a1 1 0 1 0 0 2h3.927Z', +}) diff --git a/src/components/icons/TitleCase.tsx b/src/components/icons/TitleCase.tsx new file mode 100644 index 000000000..9d040c9e5 --- /dev/null +++ b/src/components/icons/TitleCase.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const TitleCase_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M3.65 17.247c-.242.832-.632 1.178-1.325 1.178-.814 0-1.325-.476-1.325-1.23 0-.216.06-.51.173-.831L4.586 7.07c.364-1.014.979-1.482 1.966-1.482 1.022 0 1.629.45 2.001 1.473l3.43 9.303c.121.337.165.571.165.831 0 .72-.546 1.23-1.308 1.23-.736 0-1.126-.338-1.36-1.152l-.658-1.975H4.309l-.658 1.95ZM6.5 8.152l-1.62 5.12h3.335l-1.654-5.12H6.5Zm13.005 8.688c-.52.988-1.68 1.568-2.84 1.568-1.768 0-3.11-1.144-3.11-2.815 0-1.69 1.299-2.668 3.62-2.807l2.34-.138v-.615c0-.867-.607-1.369-1.56-1.369-.771 0-1.239.251-1.802.979-.277.312-.597.468-1.004.468-.615 0-1.057-.399-1.057-.97 0-.2.043-.382.13-.572.433-1.109 1.923-1.793 3.845-1.793 2.383 0 3.933 1.23 3.933 3.1v5.293c0 .84-.511 1.273-1.23 1.273-.684 0-1.16-.38-1.213-1.126v-.476h-.052Zm-3.43-1.386c0 .693.572 1.126 1.42 1.126 1.11 0 2.02-.719 2.02-1.723v-.676l-1.959.121c-.944.07-1.48.494-1.48 1.152Z', +}) |