From 607203134e886f436f41d3e559042b70fec82a38 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Wed, 28 Dec 2022 19:20:02 -0600 Subject: [PATCH] Update posts in feed to use the theming system --- src/view/com/posts/FeedItem.tsx | 69 ++++++++++++++++------------- src/view/com/util/PostEmbeds.tsx | 31 ++++++------- src/view/com/util/PostMeta.tsx | 16 +++++-- src/view/com/util/UserInfoText.tsx | 13 +++++- src/view/com/util/text/RichText.tsx | 21 +++++---- src/view/lib/ThemeContext.tsx | 7 ++- src/view/lib/hooks/usePalette.ts | 4 -- src/view/lib/styles.ts | 13 +++++- src/view/lib/themes.ts | 41 ++++++++++++----- 9 files changed, 133 insertions(+), 82 deletions(-) diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index f456fbab..6cd374d8 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -16,8 +16,10 @@ import {PostEmbeds} from '../util/PostEmbeds' import {RichText} from '../util/text/RichText' import * as Toast from '../util/Toast' import {UserAvatar} from '../util/UserAvatar' -import {s, colors} from '../../lib/styles' +import {s, colors, lh} from '../../lib/styles' import {useStores} from '../../../state' +import {useTheme} from '../../lib/ThemeContext' +import {usePalette} from '../../lib/hooks/usePalette' export const FeedItem = observer(function ({ item, @@ -27,6 +29,8 @@ export const FeedItem = observer(function ({ showReplyLine?: boolean }) { const store = useStores() + const theme = useTheme() + const pal = usePalette('default') const [deleted, setDeleted] = useState(false) const record = item.post.record as unknown as AppBskyFeedPost.Record const itemHref = useMemo(() => { @@ -96,6 +100,8 @@ export const FeedItem = observer(function ({ const isNoTop = isChild && !item._isThreadChild const outerStyles = [ styles.outer, + pal.view, + {borderTopColor: pal.colors.border}, isSmallTop ? styles.outerSmallTop : undefined, isNoTop ? styles.outerNoTop : undefined, item._isThreadParent ? styles.outerNoBottom : undefined, @@ -106,10 +112,21 @@ export const FeedItem = observer(function ({ ) : undefined} - {item._isThreadChild && } + {item._isThreadChild && ( + + )} {(showReplyLine || item._isThreadParent) && ( )} {item.reasonRepost && ( @@ -120,7 +137,7 @@ export const FeedItem = observer(function ({ item.reasonRepost.by.displayName || item.reasonRepost.by.handle }> - + Reposted by{' '} {item.reasonRepost.by.displayName || item.reasonRepost.by.handle} @@ -137,7 +154,7 @@ export const FeedItem = observer(function ({ icon="arrow-trend-up" style={styles.includeReasonIcon} /> - + Trending with{' '} {item.reasonTrend.by.displayName || item.reasonTrend.by.handle} @@ -171,13 +188,16 @@ export const FeedItem = observer(function ({ - Reply to + + Reply to + @@ -186,9 +206,9 @@ export const FeedItem = observer(function ({ {record.text ? ( ) : ( @@ -210,7 +230,7 @@ export const FeedItem = observer(function ({ {item._isThreadChildElided ? ( @@ -221,15 +241,17 @@ export const FeedItem = observer(function ({ y1="0" x2="2" y2="5" - stroke={colors.gray2} + stroke={pal.colors.replyLine} strokeWidth="2" /> - - - + + + - View full thread + + View full thread + ) : undefined} @@ -239,15 +261,11 @@ export const FeedItem = observer(function ({ const styles = StyleSheet.create({ outer: { borderTopWidth: 1, - borderTopColor: colors.gray2, - backgroundColor: colors.white, padding: 10, }, outerNoTop: { borderTopWidth: 0, paddingTop: 0, - borderTopLeftRadius: 0, - borderTopRightRadius: 0, }, outerSmallTop: { borderTopWidth: 0, @@ -262,7 +280,6 @@ const styles = StyleSheet.create({ top: 0, height: 6, borderLeftWidth: 2, - borderLeftColor: colors.gray2, }, bottomReplyLine: { position: 'absolute', @@ -270,7 +287,6 @@ const styles = StyleSheet.create({ top: 72, bottom: 0, borderLeftWidth: 2, - borderLeftColor: colors.gray2, }, includeReason: { flexDirection: 'row', @@ -296,17 +312,10 @@ const styles = StyleSheet.create({ flexWrap: 'wrap', paddingBottom: 8, }, - postText: { - fontFamily: 'System', - fontSize: 16, - lineHeight: 20.8, // 1.3 of 16px - color: colors.black, - }, postEmbeds: { marginBottom: 10, }, viewFullThread: { - backgroundColor: colors.white, paddingTop: 12, paddingBottom: 2, paddingLeft: 70, @@ -316,8 +325,4 @@ const styles = StyleSheet.create({ left: 33, top: 0, }, - viewFullThreadText: { - color: colors.blue3, - fontSize: 16, - }, }) diff --git a/src/view/com/util/PostEmbeds.tsx b/src/view/com/util/PostEmbeds.tsx index 839110a2..ce93ac61 100644 --- a/src/view/com/util/PostEmbeds.tsx +++ b/src/view/com/util/PostEmbeds.tsx @@ -7,6 +7,8 @@ import {colors} from '../../lib/styles' import {AutoSizedImage} from './images/AutoSizedImage' import {ImagesLightbox} from '../../../state/models/shell-ui' import {useStores} from '../../../state' +import {useTheme} from '../../lib/ThemeContext' +import {usePalette} from '../../lib/hooks/usePalette' type Embed = | AppBskyEmbedImages.Presented @@ -20,6 +22,8 @@ export function PostEmbeds({ embed?: Embed style?: StyleProp }) { + const theme = useTheme() + const pal = usePalette('default') const store = useStores() if (embed?.$type === 'app.bsky.embed.images#presented') { const imgEmbed = embed as AppBskyEmbedImages.Presented @@ -90,18 +94,24 @@ export function PostEmbeds({ const externalEmbed = embed as AppBskyEmbedExternal.Presented const link = externalEmbed.external return ( - + {link.thumb ? ( ) : undefined} - + {link.title || link.uri} - + {link.uri} {link.description ? ( - + {link.description} ) : undefined} @@ -140,23 +150,10 @@ const styles = StyleSheet.create({ }, extOuter: { - borderWidth: 1, - borderColor: colors.gray2, borderRadius: 8, padding: 10, }, - extImage: {}, - extTitle: { - fontSize: 16, - fontWeight: 'bold', - color: colors.black, - }, extDescription: { marginTop: 4, - fontSize: 15, - color: colors.black, - }, - extUrl: { - color: colors.gray4, }, }) diff --git a/src/view/com/util/PostMeta.tsx b/src/view/com/util/PostMeta.tsx index a9ffd688..4dcd7435 100644 --- a/src/view/com/util/PostMeta.tsx +++ b/src/view/com/util/PostMeta.tsx @@ -6,6 +6,8 @@ import {Text} from './text/Text' import {PostDropdownBtn} from './forms/DropdownButton' import {s} from '../../lib/styles' import {ago} from '../../../lib/strings' +import {useTheme} from '../../lib/ThemeContext' +import {usePalette} from '../../lib/hooks/usePalette' interface PostMetaOpts { itemHref: string @@ -20,6 +22,8 @@ interface PostMetaOpts { } export function PostMeta(opts: PostMetaOpts) { + const theme = useTheme() + const pal = usePalette('default') let displayName = opts.authorDisplayName || opts.authorHandle let handle = opts.authorHandle @@ -44,16 +48,16 @@ export function PostMeta(opts: PostMetaOpts) { style={styles.metaItem} href={opts.authorHref} title={opts.authorHandle}> - + {displayName} {handle ? ( - +  {handle} ) : undefined} - + · {ago(opts.timestamp)} @@ -64,7 +68,11 @@ export function PostMeta(opts: PostMetaOpts) { isAuthor={opts.isAuthor} onCopyPostText={opts.onCopyPostText} onDeletePost={opts.onDeletePost}> - + ) diff --git a/src/view/com/util/UserInfoText.tsx b/src/view/com/util/UserInfoText.tsx index f5ed07d6..38d6d3d3 100644 --- a/src/view/com/util/UserInfoText.tsx +++ b/src/view/com/util/UserInfoText.tsx @@ -5,8 +5,10 @@ import {Link} from './Link' import {Text} from './text/Text' import {LoadingPlaceholder} from './LoadingPlaceholder' import {useStores} from '../../../state' +import {TypographyVariant} from '../../lib/ThemeContext' export function UserInfoText({ + type = 'body1', did, attr, loading, @@ -15,6 +17,7 @@ export function UserInfoText({ style, asLink, }: { + type?: TypographyVariant did: string attr?: keyof GetProfile.OutputSchema loading?: string @@ -52,9 +55,15 @@ export function UserInfoText({ let inner if (didFail) { - inner = {failed} + inner = ( + + {failed} + + ) } else if (profile) { - inner = {`${prefix || ''}${profile[attr]}`} + inner = ( + {`${prefix || ''}${profile[attr]}`} + ) } else { inner = ( numberOfLines?: number }) { + const theme = useTheme() const pal = usePalette('default') + const lineHeightStyle = lh(theme, 'body1', 1.2) if (!entities?.length) { if (/^\p{Extended_Pictographic}+$/u.test(text) && text.length <= 5) { style = { fontSize: 26, lineHeight: 30, } - return {text} + return {text} } - return {text} + return {text} } if (!style) style = [] else if (!Array.isArray(style)) style = [style] @@ -55,7 +57,7 @@ export function RichText({ type={type} text={segment.text} href={`/profile/${segment.entity.value}`} - style={[style, pal.link]} + style={[style, lineHeightStyle, pal.link]} />, ) } else if (segment.entity.type === 'link') { @@ -65,7 +67,7 @@ export function RichText({ type={type} text={toShortUrl(segment.text)} href={segment.entity.value} - style={[style, pal.link]} + style={[style, lineHeightStyle, pal.link]} />, ) } @@ -73,7 +75,10 @@ export function RichText({ key++ } return ( - + {els} ) diff --git a/src/view/lib/ThemeContext.tsx b/src/view/lib/ThemeContext.tsx index 57f758c5..f51983cb 100644 --- a/src/view/lib/ThemeContext.tsx +++ b/src/view/lib/ThemeContext.tsx @@ -11,7 +11,6 @@ export type PaletteColorName = | 'inverted' | 'error' export type PaletteColor = { - isLowContrast: boolean background: string backgroundLight: string text: string @@ -20,6 +19,7 @@ export type PaletteColor = { link: string border: string icon: string + [k: string]: string } export type Palette = Record @@ -31,13 +31,16 @@ export type TypographyVariant = | 'h2' | 'h3' | 'h4' + | 'h5' + | 'h6' | 'subtitle1' | 'subtitle2' | 'body1' | 'body2' | 'button' | 'caption' - | 'overline' + | 'overline1' + | 'overline2' export type Typography = Record export interface Theme { diff --git a/src/view/lib/hooks/usePalette.ts b/src/view/lib/hooks/usePalette.ts index e9af4ae1..698b7fba 100644 --- a/src/view/lib/hooks/usePalette.ts +++ b/src/view/lib/hooks/usePalette.ts @@ -23,19 +23,15 @@ export function usePalette(color: PaletteColorName): UsePaletteValue { }, text: { color: palette.text, - fontWeight: palette.isLowContrast ? '500' : undefined, }, textLight: { color: palette.textLight, - fontWeight: palette.isLowContrast ? '500' : undefined, }, textInverted: { color: palette.textInverted, - fontWeight: palette.isLowContrast ? '500' : undefined, }, link: { color: palette.link, - fontWeight: palette.isLowContrast ? '500' : undefined, }, } } diff --git a/src/view/lib/styles.ts b/src/view/lib/styles.ts index 26d33f6c..8933a8d8 100644 --- a/src/view/lib/styles.ts +++ b/src/view/lib/styles.ts @@ -1,4 +1,5 @@ -import {StyleSheet} from 'react-native' +import {StyleSheet, TextStyle} from 'react-native' +import {Theme, TypographyVariant} from './ThemeContext' // 1 is lightest, 2 is light, 3 is mid, 4 is dark, 5 is darkest export const colors = { @@ -191,3 +192,13 @@ export const s = StyleSheet.create({ green4: {color: colors.green4}, green5: {color: colors.green5}, }) + +export function lh( + theme: Theme, + type: TypographyVariant, + height: number, +): TextStyle { + return { + lineHeight: (theme.typography[type].lineHeight || 16) * height, + } +} diff --git a/src/view/lib/themes.ts b/src/view/lib/themes.ts index 722c79df..1dedd049 100644 --- a/src/view/lib/themes.ts +++ b/src/view/lib/themes.ts @@ -5,18 +5,21 @@ export const defaultTheme: Theme = { colorScheme: 'light', palette: { default: { - isLowContrast: false, background: colors.white, backgroundLight: colors.gray2, text: colors.black, textLight: colors.gray5, textInverted: colors.white, link: colors.blue3, - border: colors.gray3, + border: colors.gray2, icon: colors.gray2, + + // non-standard + actionLabel: colors.gray4, + replyLine: colors.gray2, + replyLineDot: colors.gray3, }, primary: { - isLowContrast: true, background: colors.blue3, backgroundLight: colors.blue2, text: colors.white, @@ -27,7 +30,6 @@ export const defaultTheme: Theme = { icon: colors.blue4, }, secondary: { - isLowContrast: true, background: colors.green3, backgroundLight: colors.green2, text: colors.white, @@ -38,7 +40,6 @@ export const defaultTheme: Theme = { icon: colors.green4, }, inverted: { - isLowContrast: true, background: colors.black, backgroundLight: colors.gray6, text: colors.white, @@ -49,7 +50,6 @@ export const defaultTheme: Theme = { icon: colors.gray5, }, error: { - isLowContrast: true, background: colors.red3, backgroundLight: colors.red2, text: colors.white, @@ -90,6 +90,16 @@ export const defaultTheme: Theme = { fontSize: 20, letterSpacing: 0.15, }, + h5: { + fontWeight: 'bold', + fontSize: 17, + letterSpacing: 0.15, + }, + h6: { + fontWeight: '400', + fontSize: 15, + letterSpacing: 0.15, + }, subtitle1: { fontSize: 16, letterSpacing: 0.15, @@ -116,11 +126,15 @@ export const defaultTheme: Theme = { fontSize: 12, letterSpacing: 0.4, }, - overline: { + overline1: { fontSize: 10, letterSpacing: 1.5, textTransform: 'uppercase', }, + overline2: { + fontSize: 14, + fontWeight: '600', + }, }, } @@ -130,15 +144,19 @@ export const darkTheme: Theme = { palette: { ...defaultTheme.palette, default: { - isLowContrast: true, - background: colors.black, + background: colors.gray8, backgroundLight: colors.gray6, text: colors.white, textLight: colors.gray3, textInverted: colors.black, - link: colors.blue2, - border: colors.gray3, + link: colors.blue3, + border: colors.gray6, icon: colors.gray5, + + // non-standard + actionLabel: colors.gray3, + replyLine: colors.gray5, + replyLineDot: colors.gray6, }, primary: { ...defaultTheme.palette.primary, @@ -149,7 +167,6 @@ export const darkTheme: Theme = { textInverted: colors.green2, }, inverted: { - isLowContrast: false, background: colors.white, backgroundLight: colors.gray2, text: colors.black,