Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trending (Beta) #7144

Merged
merged 47 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
7dd6f6c
Add WIP UIs for trending topics and suggested starterpacks
pfrazee Dec 4, 2024
352302a
Disable SPs for now
estrattonbailey Dec 11, 2024
6287bf6
Improve explore treatment a bit, add some polish to cards
estrattonbailey Dec 11, 2024
0ff6151
Add tiny option in RightNav
estrattonbailey Dec 11, 2024
55b573a
Add persisted option to hide trending from sidebar
estrattonbailey Dec 11, 2024
e3d1102
Add to settings, abstract state, not updating in tab
estrattonbailey Dec 12, 2024
99db939
Fix up hide/show toggle state, WITH broadcast hacK
estrattonbailey Dec 12, 2024
be3c36f
Clean up persisted code, add new setting
estrattonbailey Dec 12, 2024
b03a85a
Add new interstitial to Discover
estrattonbailey Dec 12, 2024
72cf85d
Exploration
estrattonbailey Dec 13, 2024
e920958
First hack at mute words
estrattonbailey Dec 13, 2024
c8a6e3b
Wire up interstitial and Explore page
estrattonbailey Dec 16, 2024
111ca28
Align components
estrattonbailey Dec 16, 2024
9d7ebe3
Some skeleton UI
estrattonbailey Dec 16, 2024
2097b67
Handle service config, enablement, load states, update lex contract
estrattonbailey Dec 16, 2024
2f57c24
Centralize mute word handling
estrattonbailey Dec 16, 2024
e03a52b
Stale time to 30m
estrattonbailey Dec 16, 2024
82a069f
Cache enabled value for reloads, use real data for service config
estrattonbailey Dec 16, 2024
369373d
Remove broadcast hack
estrattonbailey Dec 16, 2024
305a9e6
Remove titleChild
estrattonbailey Dec 16, 2024
57ff6f1
Gate settings too
estrattonbailey Dec 16, 2024
cd52e1b
Update package, rm langs
estrattonbailey Dec 17, 2024
4a8fb82
Add feature gate
estrattonbailey Dec 17, 2024
b269b19
Only english during beta period
estrattonbailey Dec 17, 2024
3bf151d
Hook up real data
estrattonbailey Dec 17, 2024
87e88c3
Tweak config
estrattonbailey Dec 17, 2024
7cb9694
Straight passthrough links
estrattonbailey Dec 17, 2024
eda3c35
Hook up prod agent
estrattonbailey Dec 17, 2024
90ed779
Fix no-show logic
estrattonbailey Dec 17, 2024
b3f253d
Up config query to 5 min
estrattonbailey Dec 17, 2024
d0b6000
Remove old file
estrattonbailey Dec 17, 2024
511a13e
Remove comment
estrattonbailey Dec 17, 2024
3020757
Remove stray flex_1
estrattonbailey Dec 17, 2024
41c74e0
Make trending setting global
estrattonbailey Dec 17, 2024
dbadf04
Quick placeholder state
estrattonbailey Dec 17, 2024
28d8314
Limit # in sidebar, tweak spacing
estrattonbailey Dec 17, 2024
dd6509c
Tweak gaps
estrattonbailey Dec 18, 2024
e9fce7a
Handle hide/show of sidebar
estrattonbailey Dec 18, 2024
34a1575
Simplify messages
gaearon Dec 18, 2024
1358ad4
Remove interstitial
estrattonbailey Dec 18, 2024
9694f81
Revert "Remove interstitial"
estrattonbailey Dec 18, 2024
5990468
Only show interstitial on mobile
estrattonbailey Dec 18, 2024
ad2ab91
Fix gap
estrattonbailey Dec 18, 2024
56f086a
Add explore page recommendations
pfrazee Dec 18, 2024
56db27b
[topics] add topic screen (#7149)
haileyok Dec 18, 2024
8938389
add server route
haileyok Dec 18, 2024
28e3faa
Fix potential bad destructure (undefined)
pfrazee Dec 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bskyweb/cmd/bskyweb/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ func serve(cctx *cli.Context) error {

// generic routes
e.GET("/hashtag/:tag", server.WebGeneric)
e.GET("/topic/:topic", server.WebGeneric)
e.GET("/search", server.WebGeneric)
e.GET("/feeds", server.WebGeneric)
e.GET("/notifications", server.WebGeneric)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"icons:optimize": "svgo -f ./assets/icons"
},
"dependencies": {
"@atproto/api": "^0.13.20",
"@atproto/api": "^0.13.21",
"@bitdrift/react-native": "0.4.0",
"@braintree/sanitize-url": "^6.0.2",
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
Expand Down
15 changes: 9 additions & 6 deletions src/App.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
import {Provider as TrendingConfigProvider} from '#/state/trending-config'
import {TestCtrls} from '#/view/com/testing/TestCtrls'
import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext'
import * as Toast from '#/view/com/util/Toast'
Expand Down Expand Up @@ -143,12 +144,14 @@ function InnerApp() {
<BackgroundNotificationPreferencesProvider>
<MutedThreadsProvider>
<ProgressGuideProvider>
<GestureHandlerRootView
style={s.h100pct}>
<TestCtrls />
<Shell />
<NuxDialogs />
</GestureHandlerRootView>
<TrendingConfigProvider>
<GestureHandlerRootView
style={s.h100pct}>
<TestCtrls />
<Shell />
<NuxDialogs />
</GestureHandlerRootView>
</TrendingConfigProvider>
</ProgressGuideProvider>
</MutedThreadsProvider>
</BackgroundNotificationPreferencesProvider>
Expand Down
7 changes: 5 additions & 2 deletions src/App.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
import {Provider as TrendingConfigProvider} from '#/state/trending-config'
import {Provider as ActiveVideoProvider} from '#/view/com/util/post-embeds/ActiveVideoWebContext'
import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext'
import * as Toast from '#/view/com/util/Toast'
Expand Down Expand Up @@ -127,8 +128,10 @@ function InnerApp() {
<MutedThreadsProvider>
<SafeAreaProvider>
<ProgressGuideProvider>
<Shell />
<NuxDialogs />
<TrendingConfigProvider>
<Shell />
<NuxDialogs />
</TrendingConfigProvider>
</ProgressGuideProvider>
</SafeAreaProvider>
</MutedThreadsProvider>
Expand Down
6 changes: 6 additions & 0 deletions src/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ import {LanguageSettingsScreen} from './screens/Settings/LanguageSettings'
import {PrivacyAndSecuritySettingsScreen} from './screens/Settings/PrivacyAndSecuritySettings'
import {SettingsScreen} from './screens/Settings/Settings'
import {ThreadPreferencesScreen} from './screens/Settings/ThreadPreferences'
import TopicScreen from './screens/Topic'

const navigationRef = createNavigationContainerRef<AllNavigatorParams>()

Expand Down Expand Up @@ -376,6 +377,11 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
getComponent={() => HashtagScreen}
options={{title: title(msg`Hashtag`)}}
/>
<Stack.Screen
name="Topic"
getComponent={() => TopicScreen}
options={{title: title(msg`Topic`)}}
/>
<Stack.Screen
name="MessagesConversation"
getComponent={() => MessagesConversationScreen}
Expand Down
8 changes: 5 additions & 3 deletions src/components/GradientFill.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import {LinearGradient} from 'expo-linear-gradient'

import {atoms as a, tokens} from '#/alf'
import {atoms as a, tokens, ViewStyleProp} from '#/alf'

export function GradientFill({
gradient,
}: {
style,
}: ViewStyleProp & {
gradient:
| typeof tokens.gradients.primary
| typeof tokens.gradients.sky
| typeof tokens.gradients.midnight
| typeof tokens.gradients.sunrise
Expand All @@ -26,7 +28,7 @@ export function GradientFill({
}
start={{x: 0, y: 0}}
end={{x: 1, y: 1}}
style={[a.absolute, a.inset_0]}
style={[a.absolute, a.inset_0, style]}
/>
)
}
223 changes: 223 additions & 0 deletions src/components/TrendingTopics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import React from 'react'
import {View} from 'react-native'
import {AtUri} from '@atproto/api'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'

// import {makeProfileLink} from '#/lib/routes/links'
// import {feedUriToHref} from '#/lib/strings/url-helpers'
// import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Hashtag'
// import {CloseQuote_Filled_Stroke2_Corner0_Rounded as Quote} from '#/components/icons/Quote'
// import {UserAvatar} from '#/view/com/util/UserAvatar'
import type {TrendingTopic} from '#/state/queries/trending/useTrendingTopics'
import {atoms as a, useTheme, ViewStyleProp} from '#/alf'
import {Link as InternalLink, LinkProps} from '#/components/Link'
import {Text} from '#/components/Typography'

export function TrendingTopic({
topic: raw,
size,
style,
}: {topic: TrendingTopic; size?: 'large' | 'small'} & ViewStyleProp) {
const t = useTheme()
const topic = useTopic(raw)

const isSmall = size === 'small'
// const hasAvi = topic.type === 'feed' || topic.type === 'profile'
// const aviSize = isSmall ? 16 : 20
// const iconSize = isSmall ? 16 : 20
estrattonbailey marked this conversation as resolved.
Show resolved Hide resolved

return (
<View
style={[
a.flex_row,
a.align_center,
a.rounded_full,
a.border,
t.atoms.border_contrast_medium,
t.atoms.bg,
isSmall
? [
{
paddingVertical: 5,
paddingHorizontal: 10,
},
]
: [a.py_sm, a.px_md],
style,
/*
{
padding: 6,
gap: hasAvi ? 4 : 2,
},
a.pr_md,
*/
]}>
{/*
<View
style={[
a.align_center,
a.justify_center,
a.rounded_full,
a.overflow_hidden,
{
width: aviSize,
height: aviSize,
},
]}>
{topic.type === 'tag' ? (
<Hashtag width={iconSize} />
) : topic.type === 'topic' ? (
<Quote width={iconSize - 2} />
) : topic.type === 'feed' ? (
<UserAvatar
type="user"
size={aviSize}
avatar=""
/>
) : (
<UserAvatar
type="user"
size={aviSize}
avatar=""
/>
)}
</View>
*/}

<Text
style={[
a.font_bold,
a.leading_tight,
isSmall ? [a.text_sm] : [a.text_md, {paddingBottom: 1}],
]}
numberOfLines={1}>
{topic.displayName}
</Text>
</View>
)
}

export function TrendingTopicSkeleton({
size = 'large',
index = 0,
}: {
size?: 'large' | 'small'
index?: number
}) {
const t = useTheme()
const isSmall = size === 'small'
return (
<View
style={[
a.rounded_full,
a.border,
t.atoms.border_contrast_medium,
t.atoms.bg_contrast_25,
isSmall
? {
width: index % 2 === 0 ? 75 : 90,
height: 27,
}
: {
width: index % 2 === 0 ? 90 : 110,
height: 36,
},
]}
/>
)
}

export function TrendingTopicLink({
topic: raw,
children,
...rest
}: {
topic: TrendingTopic
} & Omit<LinkProps, 'to' | 'label'>) {
const topic = useTopic(raw)

return (
<InternalLink label={topic.label} to={topic.url} {...rest}>
{children}
</InternalLink>
)
}

type ParsedTrendingTopic =
| {
type: 'topic' | 'tag' | 'unknown'
label: string
displayName: string
url: string
uri: undefined
}
| {
type: 'profile' | 'feed'
label: string
displayName: string
url: string
uri: AtUri
}

export function useTopic(raw: TrendingTopic): ParsedTrendingTopic {
const {_} = useLingui()
return React.useMemo(() => {
const {topic: displayName, link} = raw

if (link.startsWith('/search')) {
return {
type: 'topic',
label: _(msg`Browse posts about ${displayName}`),
displayName,
uri: undefined,
url: link,
}
} else if (link.startsWith('/hashtag')) {
return {
type: 'tag',
label: _(msg`Browse posts tagged with ${displayName}`),
displayName,
// displayName: displayName.replace(/^#/, ''),
uri: undefined,
url: link,
}
}

/*
if (!link.startsWith('at://')) {
// above logic
} else {
const urip = new AtUri(link)
switch (urip.collection) {
case 'app.bsky.actor.profile': {
return {
type: 'profile',
label: _(msg`View ${displayName}'s profile`),
displayName,
uri: urip,
url: makeProfileLink({did: urip.host, handle: urip.host}),
}
}
case 'app.bsky.feed.generator': {
return {
type: 'feed',
label: _(msg`Browse the ${displayName} feed`),
displayName,
uri: urip,
url: feedUriToHref(link),
}
}
}
}
*/

return {
type: 'unknown',
label: _(msg`Browse topic ${displayName}`),
displayName,
uri: undefined,
url: link,
}
}, [_, raw])
}
Loading
Loading