Split out components, link byline
This commit is contained in:
@@ -263,7 +263,6 @@ export const Button = forwardRef<View, ButtonProps>(
|
|||||||
baseStyles.push(t.atoms.bg_contrast_50)
|
baseStyles.push(t.atoms.bg_contrast_50)
|
||||||
}
|
}
|
||||||
} else if (color === 'secondary_inverted') {
|
} else if (color === 'secondary_inverted') {
|
||||||
console.log(t)
|
|
||||||
if (!disabled) {
|
if (!disabled) {
|
||||||
baseStyles.push({
|
baseStyles.push({
|
||||||
backgroundColor: t.palette.contrast_900,
|
backgroundColor: t.palette.contrast_900,
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import {Fragment, type ReactNode, useMemo} from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||||
|
import {Trans, useLingui} from '@lingui/react/macro'
|
||||||
|
|
||||||
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
|
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
||||||
|
import {useProfileQuery} from '#/state/queries/profile'
|
||||||
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {InlineLinkText} from '#/components/Link'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
|
export function PublicationMetaRow({
|
||||||
|
view,
|
||||||
|
author,
|
||||||
|
}: {
|
||||||
|
view: AppBskyEmbedExternal.ViewExternal
|
||||||
|
author: {did: string | null | undefined}
|
||||||
|
}) {
|
||||||
|
const t = useTheme()
|
||||||
|
const {t: l} = useLingui()
|
||||||
|
const profileQuery = useProfileQuery({did: author.did ?? undefined})
|
||||||
|
const handle = author.did ? profileQuery.data?.handle : undefined
|
||||||
|
const highlightedPublisher = useMemo(() => {
|
||||||
|
try {
|
||||||
|
const u = new URL(view.source?.uri || '')
|
||||||
|
return (
|
||||||
|
u.host.endsWith('leaflet.pub') ||
|
||||||
|
u.host.endsWith('pckt.blog') ||
|
||||||
|
u.host.endsWith('offprint.app')
|
||||||
|
)
|
||||||
|
} catch (e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}, [view])
|
||||||
|
|
||||||
|
const metaTextStyle = [
|
||||||
|
a.text_xs,
|
||||||
|
a.leading_snug,
|
||||||
|
t.atoms.text_contrast_medium,
|
||||||
|
]
|
||||||
|
|
||||||
|
const items: {key: string; node: ReactNode}[] = []
|
||||||
|
|
||||||
|
if (!highlightedPublisher && view.source?.uri) {
|
||||||
|
items.push({
|
||||||
|
key: 'domain',
|
||||||
|
node: (
|
||||||
|
<Text numberOfLines={1} style={metaTextStyle}>
|
||||||
|
{toNiceDomain(view.source.uri)}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (author.did && handle) {
|
||||||
|
items.push({
|
||||||
|
key: 'author',
|
||||||
|
node: (
|
||||||
|
<Text numberOfLines={1} style={metaTextStyle}>
|
||||||
|
<Trans>
|
||||||
|
by{' '}
|
||||||
|
<InlineLinkText
|
||||||
|
label={l`View @${handle}'s profile`}
|
||||||
|
to={makeProfileLink({did: author.did, handle})}
|
||||||
|
style={metaTextStyle}>
|
||||||
|
@{handle}
|
||||||
|
</InlineLinkText>
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items.length === 0) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={[a.flex_row, a.align_center, a.gap_xs]}>
|
||||||
|
{items.map((item, i) => (
|
||||||
|
<Fragment key={item.key}>
|
||||||
|
{i > 0 && <Text style={metaTextStyle}>•</Text>}
|
||||||
|
{item.node}
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import {useMemo} from 'react'
|
||||||
|
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||||
|
|
||||||
|
import {ThemeProvider, useAlf, utils} from '#/alf'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides only the values needed for `secondary_inverted` buttons atm.
|
||||||
|
*/
|
||||||
|
export function StandardSiteThemeProvider({
|
||||||
|
view,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
view: AppBskyEmbedExternal.ViewExternal
|
||||||
|
children: React.ReactNode
|
||||||
|
}) {
|
||||||
|
const alf = useAlf()
|
||||||
|
const themesOverride = useMemo(() => {
|
||||||
|
const {accentRGB, accentForegroundRGB} = view.source?.theme || {}
|
||||||
|
if (!accentRGB || !accentForegroundRGB) return alf.themes
|
||||||
|
|
||||||
|
const accent = utils.rgbToHex(accentRGB.r, accentRGB.g, accentRGB.b)
|
||||||
|
const accentForeground = utils.rgbToHex(
|
||||||
|
accentForegroundRGB.r,
|
||||||
|
accentForegroundRGB.g,
|
||||||
|
accentForegroundRGB.b,
|
||||||
|
)
|
||||||
|
const atoms = {
|
||||||
|
text_inverted: {color: accentForeground},
|
||||||
|
}
|
||||||
|
const palette = {
|
||||||
|
contrast_975: utils.darken(accent, 5), // hover
|
||||||
|
contrast_900: accent, // bg
|
||||||
|
contrast_600: utils.lighten(accent, 5), // disabled bg
|
||||||
|
contrast_300: accentForeground, // disabled text
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
lightPalette: {
|
||||||
|
...alf.themes.lightPalette,
|
||||||
|
...palette,
|
||||||
|
},
|
||||||
|
darkPalette: {
|
||||||
|
...alf.themes.darkPalette,
|
||||||
|
...palette,
|
||||||
|
},
|
||||||
|
dimPalette: {
|
||||||
|
...alf.themes.dimPalette,
|
||||||
|
...palette,
|
||||||
|
},
|
||||||
|
light: {
|
||||||
|
...alf.themes.light,
|
||||||
|
atoms: {
|
||||||
|
...alf.themes.light.atoms,
|
||||||
|
...atoms,
|
||||||
|
},
|
||||||
|
palette: {
|
||||||
|
...alf.themes.light.palette,
|
||||||
|
...palette,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
...alf.themes.dark,
|
||||||
|
atoms: {
|
||||||
|
...alf.themes.dark.atoms,
|
||||||
|
...atoms,
|
||||||
|
},
|
||||||
|
palette: {
|
||||||
|
...alf.themes.dark.palette,
|
||||||
|
...palette,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dim: {
|
||||||
|
...alf.themes.dim,
|
||||||
|
atoms: {
|
||||||
|
...alf.themes.dim.atoms,
|
||||||
|
...atoms,
|
||||||
|
},
|
||||||
|
palette: {
|
||||||
|
...alf.themes.dim.palette,
|
||||||
|
...palette,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, [alf, view])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeProvider theme={alf.themeName} themesOverride={themesOverride}>
|
||||||
|
{children}
|
||||||
|
</ThemeProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -14,16 +14,8 @@ import {
|
|||||||
import {niceDate} from '#/lib/strings/time'
|
import {niceDate} from '#/lib/strings/time'
|
||||||
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
||||||
import {useExternalEmbedsPrefs} from '#/state/preferences'
|
import {useExternalEmbedsPrefs} from '#/state/preferences'
|
||||||
import {useProfileQuery} from '#/state/queries/profile'
|
|
||||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
import {
|
import {atoms as a, useBreakpoints, useTheme, utils} from '#/alf'
|
||||||
atoms as a,
|
|
||||||
ThemeProvider,
|
|
||||||
useAlf,
|
|
||||||
useBreakpoints,
|
|
||||||
useTheme,
|
|
||||||
utils,
|
|
||||||
} from '#/alf'
|
|
||||||
import {ButtonIcon, ButtonText} from '#/components/Button'
|
import {ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
import {Divider} from '#/components/Divider'
|
import {Divider} from '#/components/Divider'
|
||||||
import {Clock_Stroke2_Corner0_Rounded as Clock} from '#/components/icons/Clock'
|
import {Clock_Stroke2_Corner0_Rounded as Clock} from '#/components/icons/Clock'
|
||||||
@@ -34,6 +26,8 @@ import {StandardSite} from '#/components/icons/community/StandardSite'
|
|||||||
import {Earth_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
|
import {Earth_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
|
||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||||
|
import {PublicationMetaRow} from '#/components/Post/Embed/StandardSiteEmbed/PublicationMetaRow'
|
||||||
|
import {StandardSiteThemeProvider} from '#/components/Post/Embed/StandardSiteEmbed/StandardSiteThemeProvider'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
|
|
||||||
@@ -350,9 +344,6 @@ export function PublicationCard({
|
|||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const {gtPhone} = useBreakpoints()
|
const {gtPhone} = useBreakpoints()
|
||||||
const profileQuery = useProfileQuery({did: author.did ?? undefined})
|
|
||||||
const handle = author.did ? profileQuery.data?.handle : undefined
|
|
||||||
const highlightedPublisher = useStandardSitePublisherConfig(view)
|
|
||||||
|
|
||||||
if (!view.source) return null
|
if (!view.source) return null
|
||||||
|
|
||||||
@@ -410,49 +401,7 @@ export function PublicationCard({
|
|||||||
]}>
|
]}>
|
||||||
{view.source?.title}
|
{view.source?.title}
|
||||||
</Text>
|
</Text>
|
||||||
<View style={[a.flex_row, a.align_center, a.gap_xs]}>
|
<PublicationMetaRow view={view} author={author} />
|
||||||
{[
|
|
||||||
{
|
|
||||||
type: 'domain',
|
|
||||||
enabled: !highlightedPublisher,
|
|
||||||
value: toNiceDomain(view.source?.uri || ''),
|
|
||||||
hasPrev: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'author',
|
|
||||||
enabled: true,
|
|
||||||
value: handle ? l`by @${handle}` : undefined,
|
|
||||||
hasPrev:
|
|
||||||
!highlightedPublisher && Boolean(view.source?.uri),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.filter(item => item.enabled && item.value)
|
|
||||||
.map(item => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{item.hasPrev && (
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
a.text_xs,
|
|
||||||
a.leading_snug,
|
|
||||||
t.atoms.text_contrast_medium,
|
|
||||||
]}>
|
|
||||||
•
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
<Text
|
|
||||||
numberOfLines={1}
|
|
||||||
style={[
|
|
||||||
a.text_xs,
|
|
||||||
a.leading_snug,
|
|
||||||
t.atoms.text_contrast_medium,
|
|
||||||
]}>
|
|
||||||
{item.value}
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
</View>
|
</View>
|
||||||
@@ -463,7 +412,6 @@ export function PublicationCard({
|
|||||||
style={[!gtPhone && [a.w_full, a.justify_center]]}
|
style={[!gtPhone && [a.w_full, a.justify_center]]}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPress}
|
||||||
themeColors={themeColors}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
@@ -485,83 +433,21 @@ export function SubscribeButton({
|
|||||||
view,
|
view,
|
||||||
onPress,
|
onPress,
|
||||||
onLongPress,
|
onLongPress,
|
||||||
themeColors,
|
|
||||||
style,
|
style,
|
||||||
}: {
|
}: {
|
||||||
view: AppBskyEmbedExternal.ViewExternal
|
view: AppBskyEmbedExternal.ViewExternal
|
||||||
onPress?: () => void
|
onPress?: () => void
|
||||||
onLongPress?: () => void
|
onLongPress?: () => void
|
||||||
themeColors: ThemeColors
|
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
}) {
|
}) {
|
||||||
const alf = useAlf()
|
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const highlightedPublisher = useStandardSitePublisherConfig(view)
|
const highlightedPublisher = useStandardSitePublisherConfig(view)
|
||||||
const cta = highlightedPublisher
|
const cta = highlightedPublisher
|
||||||
? l`Subscribe on ${highlightedPublisher.name}`
|
? l`Subscribe on ${highlightedPublisher.name}`
|
||||||
: l`View publication`
|
: l`View publication`
|
||||||
const themesOverride = useMemo(() => {
|
|
||||||
if (!themeColors.custom) return alf.themes
|
|
||||||
const atoms = {
|
|
||||||
text_inverted: {color: themeColors.accentForeground}, // text
|
|
||||||
}
|
|
||||||
const palette = {
|
|
||||||
contrast_975: utils.darken(themeColors.accent, 5), // hover
|
|
||||||
contrast_900: themeColors.accent, // bg
|
|
||||||
contrast_600: utils.lighten(themeColors.accent, 5), // disabled bg
|
|
||||||
contrast_300: themeColors.accentForeground, // disabled text
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
lightPalette: {
|
|
||||||
...alf.themes.lightPalette,
|
|
||||||
...palette,
|
|
||||||
},
|
|
||||||
darkPalette: {
|
|
||||||
...alf.themes.darkPalette,
|
|
||||||
...palette,
|
|
||||||
},
|
|
||||||
dimPalette: {
|
|
||||||
...alf.themes.dimPalette,
|
|
||||||
...palette,
|
|
||||||
},
|
|
||||||
light: {
|
|
||||||
...alf.themes.light,
|
|
||||||
atoms: {
|
|
||||||
...alf.themes.light.atoms,
|
|
||||||
...atoms,
|
|
||||||
},
|
|
||||||
palette: {
|
|
||||||
...alf.themes.light.palette,
|
|
||||||
...palette,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dark: {
|
|
||||||
...alf.themes.dark,
|
|
||||||
atoms: {
|
|
||||||
...alf.themes.dark.atoms,
|
|
||||||
...atoms,
|
|
||||||
},
|
|
||||||
palette: {
|
|
||||||
...alf.themes.dark.palette,
|
|
||||||
...palette,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dim: {
|
|
||||||
...alf.themes.dim,
|
|
||||||
atoms: {
|
|
||||||
...alf.themes.dim.atoms,
|
|
||||||
...atoms,
|
|
||||||
},
|
|
||||||
palette: {
|
|
||||||
...alf.themes.dim.palette,
|
|
||||||
...palette,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}, [alf, themeColors])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={alf.themeName} themesOverride={themesOverride}>
|
<StandardSiteThemeProvider view={view}>
|
||||||
<Link
|
<Link
|
||||||
shouldProxy
|
shouldProxy
|
||||||
to={view.source!.uri}
|
to={view.source!.uri}
|
||||||
@@ -583,7 +469,7 @@ export function SubscribeButton({
|
|||||||
<ButtonText>{cta}</ButtonText>
|
<ButtonText>{cta}</ButtonText>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
</ThemeProvider>
|
</StandardSiteThemeProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,23 +548,6 @@ export function PublicationFooter({
|
|||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const {gtPhone} = useBreakpoints()
|
const {gtPhone} = useBreakpoints()
|
||||||
const profileQuery = useProfileQuery({did: author.did ?? undefined})
|
|
||||||
const handle = author.did ? profileQuery.data?.handle : undefined
|
|
||||||
const highlightedPublisher = useMemo(() => {
|
|
||||||
try {
|
|
||||||
const u = new URL(view.source?.uri || '')
|
|
||||||
if (u.host.endsWith('leaflet.pub')) {
|
|
||||||
return 'Leaflet'
|
|
||||||
} else if (u.host.endsWith('pckt.blog')) {
|
|
||||||
return 'pckt'
|
|
||||||
} else if (u.host.endsWith('offprint.app')) {
|
|
||||||
return 'Offprint'
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
} catch (e) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}, [view])
|
|
||||||
|
|
||||||
if (!view.source) return null
|
if (!view.source) return null
|
||||||
|
|
||||||
@@ -725,48 +594,7 @@ export function PublicationFooter({
|
|||||||
]}>
|
]}>
|
||||||
{view.source?.title}
|
{view.source?.title}
|
||||||
</Text>
|
</Text>
|
||||||
<View style={[a.flex_row, a.align_center, a.gap_xs]}>
|
<PublicationMetaRow view={view} author={author} />
|
||||||
{[
|
|
||||||
{
|
|
||||||
type: 'domain',
|
|
||||||
enabled: !highlightedPublisher,
|
|
||||||
value: toNiceDomain(view.source?.uri || ''),
|
|
||||||
hasPrev: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'author',
|
|
||||||
enabled: true,
|
|
||||||
value: handle ? l`by @${handle}` : undefined,
|
|
||||||
hasPrev: !highlightedPublisher && Boolean(view.source?.uri),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.filter(item => item.enabled && item.value)
|
|
||||||
.map(item => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{item.hasPrev && (
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
a.text_xs,
|
|
||||||
a.leading_snug,
|
|
||||||
t.atoms.text_contrast_medium,
|
|
||||||
]}>
|
|
||||||
•
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
<Text
|
|
||||||
numberOfLines={1}
|
|
||||||
style={[
|
|
||||||
a.text_xs,
|
|
||||||
a.leading_snug,
|
|
||||||
t.atoms.text_contrast_medium,
|
|
||||||
]}>
|
|
||||||
{item.value}
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -778,7 +606,6 @@ export function PublicationFooter({
|
|||||||
style={[!gtPhone && [a.w_full, a.justify_center]]}
|
style={[!gtPhone && [a.w_full, a.justify_center]]}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPress}
|
||||||
themeColors={themeColors}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
Reference in New Issue
Block a user