Skip to content

Commit

Permalink
feat: view selector
Browse files Browse the repository at this point in the history
  • Loading branch information
DIYgod committed Jan 22, 2025
1 parent 1041b9a commit 0c29f27
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 2 deletions.
1 change: 1 addition & 0 deletions apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"react-hook-form": "7.54.0",
"react-native": "0.76.5",
"react-native-bouncy-checkbox": "4.1.2",
"react-native-color-matrix-image-filters": "^7.0.2",
"react-native-context-menu-view": "1.16.0",
"react-native-gesture-handler": "~2.20.2",
"react-native-image-colors": "2.4.0",
Expand Down
9 changes: 8 additions & 1 deletion apps/mobile/src/components/ui/icon/fallback-icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { LinearGradient } from "expo-linear-gradient"
import { useMemo, useState } from "react"
import type { DimensionValue, StyleProp, TextStyle, ViewStyle } from "react-native"
import { StyleSheet, Text, View } from "react-native"
import { useColor } from "react-native-uikit-colors"

export const FallbackIcon = ({
title,
Expand All @@ -13,6 +14,7 @@ export const FallbackIcon = ({
style,
textClassName,
textStyle,
gray,
}: {
title: string
url?: string
Expand All @@ -21,6 +23,7 @@ export const FallbackIcon = ({
style?: StyleProp<ViewStyle>
textClassName?: string
textStyle?: StyleProp<TextStyle>
gray?: boolean
}) => {
const colors = useMemo(() => getBackgroundGradient(title || url || ""), [title, url])
const sizeStyle = useMemo(() => ({ width: size, height: size }), [size])
Expand All @@ -36,10 +39,14 @@ export const FallbackIcon = ({
)
}, [title, textStyle, textClassName])

const grayColor = useColor("gray2")

return (
<LinearGradient
className={className}
colors={[bgAccent!, bgAccentLight!, bgAccentUltraLight!]}
colors={
gray ? [grayColor, grayColor, grayColor] : [bgAccent!, bgAccentLight!, bgAccentUltraLight!]
}
locations={[0, 0.99, 1]}
style={[sizeStyle, styles.container, style]}
>
Expand Down
102 changes: 102 additions & 0 deletions apps/mobile/src/modules/feed-drawer/view-selector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { cn } from "@follow/utils"
import { Image } from "expo-image"
import { Stack } from "expo-router"
import { ScrollView, TouchableOpacity, View } from "react-native"
import { Grayscale } from "react-native-color-matrix-image-filters"

import { BlurEffect } from "@/src/components/common/BlurEffect"
import { FallbackIcon } from "@/src/components/ui/icon/fallback-icon"
import type { ViewDefinition } from "@/src/constants/views"
import { views } from "@/src/constants/views"
import { useList } from "@/src/store/list/hooks"
import { useAllListSubscription } from "@/src/store/subscription/hooks"
import { useColor } from "@/src/theme/colors"

import { LeftAction, RightAction } from "../entry-list/action"
import { selectFeed, useSelectedFeed } from "../feed-drawer/atoms"

export function ViewSelector() {
return (
<Stack.Screen
options={{
headerShown: true,
headerTitle: ViewItems,
headerLeft: LeftAction,
headerRight: RightAction,
headerTransparent: true,
headerBackground: BlurEffect,
}}
/>
)
}

function ViewItems() {
const lists = useAllListSubscription()

return (
<ScrollView horizontal className="mx-7">
{views.map((view) => (
<ViewItem key={view.name} view={view} />
))}
{lists.map((listId) => (
<ListItem key={listId} listId={listId} />
))}
</ScrollView>
)
}

function ViewItem({ view }: { view: ViewDefinition }) {
const selectedFeed = useSelectedFeed()
const isActive = selectedFeed.type === "view" && selectedFeed.viewId === view.view

const bgColor = useColor("gray2")

return (
<TouchableOpacity
className="relative flex aspect-square items-center justify-center"
onPress={() => selectFeed({ type: "view", viewId: view.view })}
>
<View className="flex size-8 items-center justify-center overflow-hidden rounded-full">
<View
className="flex size-full items-center justify-center"
style={{
backgroundColor: isActive ? view.activeColor : bgColor,
}}
>
<view.icon color={"#fff"} height={15} width={15} />
</View>
</View>
</TouchableOpacity>
)
}

function ListItem({ listId }: { listId: string }) {
const list = useList(listId)
const selectedFeed = useSelectedFeed()
const isActive = selectedFeed.type === "list" && selectedFeed.listId === listId

if (!list) return null

return (
<TouchableOpacity
className="relative flex aspect-square items-center justify-center"
onPress={() => selectFeed({ type: "list", listId })}
>
<View className="flex size-8 items-center justify-center overflow-hidden rounded-full">
<View className={cn("flex size-full items-center justify-center")}>
{list.image ? (
isActive ? (
<Image source={list.image} contentFit="cover" style={{ width: 32, height: 32 }} />
) : (
<Grayscale>
<Image source={list.image} contentFit="cover" style={{ width: 32, height: 32 }} />
</Grayscale>
)
) : (
<FallbackIcon title={list.title} size="100%" gray={!isActive} />
)}
</View>
</View>
</TouchableOpacity>
)
}
8 changes: 7 additions & 1 deletion apps/mobile/src/screens/(stack)/(tabs)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { EntryList } from "@/src/modules/entry-list/entry-list"
import { ViewSelector } from "@/src/modules/feed-drawer/view-selector"

export default function Index() {
return <EntryList />
return (
<>
<ViewSelector />
<EntryList />
</>
)
}
44 changes: 44 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0c29f27

Please sign in to comment.