feat(rn): impl list setting pages
Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
0d124ffd6b
commit
c18da69de1
|
|
@ -23,6 +23,7 @@
|
|||
"@follow/models": "workspace:*",
|
||||
"@follow/shared": "workspace:*",
|
||||
"@follow/utils": "workspace:*",
|
||||
"@formatjs/intl-numberformat": "8.15.2",
|
||||
"@gorhom/portal": "1.0.14",
|
||||
"@hookform/resolvers": "3.9.1",
|
||||
"@infinite-list/data-model": "2.2.10",
|
||||
|
|
@ -36,6 +37,7 @@
|
|||
"better-auth": "1.1.9-beta.1",
|
||||
"cookie-es": "^1.2.2",
|
||||
"dayjs": "1.11.13",
|
||||
"dnum": "^2.14.0",
|
||||
"es-toolkit": "1.29.0",
|
||||
"expo": "52.0.18",
|
||||
"expo-apple-authentication": "~7.1.2",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
import { cn, toScientificNotation } from "@follow/utils"
|
||||
import { Text } from "react-native"
|
||||
|
||||
export const Balance = ({
|
||||
children,
|
||||
|
||||
className,
|
||||
precision = 2,
|
||||
}: {
|
||||
/** The token balance in wei. */
|
||||
children: bigint
|
||||
|
||||
className?: string
|
||||
precision?: number
|
||||
}) => {
|
||||
const n = BigInt(children || 0n)
|
||||
const formatted = format(n, { digits: precision, trailingZeros: true })
|
||||
|
||||
return <Text className={cn("tabular-nums", className)}>{formatted}</Text>
|
||||
}
|
||||
|
||||
function format(
|
||||
value: bigint,
|
||||
options:
|
||||
| number
|
||||
| {
|
||||
digits?: number
|
||||
compact?: boolean
|
||||
trailingZeros?: boolean
|
||||
locale?: string
|
||||
decimalsRounding?: "ROUND_HALF" | "ROUND_UP" | "ROUND_DOWN"
|
||||
signDisplay?: "auto" | "always" | "exceptZero" | "negative" | "never"
|
||||
} = {},
|
||||
): string {
|
||||
// Normalize options
|
||||
const opts = typeof options === "number" ? { digits: options } : options
|
||||
const {
|
||||
digits,
|
||||
compact = false,
|
||||
trailingZeros = false,
|
||||
locale = "en-US",
|
||||
|
||||
signDisplay = "auto",
|
||||
} = opts
|
||||
|
||||
// Convert bigint to number for formatting
|
||||
const num = Number(value) / 1e18 // Assuming 18 decimals (wei to ether conversion)
|
||||
|
||||
if (compact) {
|
||||
return new Intl.NumberFormat(locale, {
|
||||
notation: "compact",
|
||||
maximumFractionDigits: digits,
|
||||
minimumFractionDigits: trailingZeros ? digits : 0,
|
||||
signDisplay,
|
||||
}).format(num)
|
||||
}
|
||||
|
||||
// For very large or small numbers, use scientific notation
|
||||
if (Math.abs(num) > 1e9 || (Math.abs(num) < 1e-9 && num !== 0)) {
|
||||
return toScientificNotation(num.toString(), 10)
|
||||
}
|
||||
|
||||
return new Intl.NumberFormat(locale, {
|
||||
maximumFractionDigits: digits,
|
||||
minimumFractionDigits: trailingZeros ? digits : 0,
|
||||
signDisplay,
|
||||
useGrouping: true,
|
||||
}).format(num)
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import { Fragment } from "react"
|
|||
import type { ViewProps } from "react-native"
|
||||
import { Pressable, StyleSheet, Text, View } from "react-native"
|
||||
|
||||
import { MingcuteRightLine } from "@/src/icons/mingcute_right_line"
|
||||
import { RightCuteReIcon } from "@/src/icons/right_cute_re"
|
||||
import { useColor } from "@/src/theme/colors"
|
||||
|
||||
|
|
@ -91,7 +92,7 @@ export const GroupedInsetListNavigationLink: FC<{
|
|||
<Text className={"text-label text-[16px]"}>{label}</Text>
|
||||
</View>
|
||||
<View className="-mr-2 ml-4">
|
||||
<RightCuteReIcon height={18} width={18} color={rightIconColor} />
|
||||
<MingcuteRightLine height={18} width={18} color={rightIconColor} />
|
||||
</View>
|
||||
</View>
|
||||
</GroupedInsetListBaseCell>
|
||||
|
|
@ -160,3 +161,29 @@ export const GroupedInsetListActionCell: FC<{
|
|||
</Pressable>
|
||||
)
|
||||
}
|
||||
|
||||
export const GroupedInformationCell: FC<{
|
||||
title: string
|
||||
description?: string
|
||||
icon?: React.ReactNode
|
||||
iconBackgroundColor?: string
|
||||
}> = ({ title, description, icon, iconBackgroundColor }) => {
|
||||
return (
|
||||
<GroupedInsetListBaseCell className="flex-1 flex-col items-center justify-center rounded-[16px] p-6">
|
||||
{icon && (
|
||||
<View
|
||||
className="mb-3 size-[64px] items-center justify-center rounded-xl p-1"
|
||||
style={{ backgroundColor: iconBackgroundColor }}
|
||||
>
|
||||
{icon}
|
||||
</View>
|
||||
)}
|
||||
<Text className="text-3xl font-bold">{title}</Text>
|
||||
{!!description && (
|
||||
<Text className="text-label mt-3 text-balance text-center text-base leading-tight">
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
</GroupedInsetListBaseCell>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export const LoadingIndicator: FC<
|
|||
color?: string
|
||||
className?: string
|
||||
} & PropsWithChildren
|
||||
> = ({ size = 60, color, children, className }) => {
|
||||
> = ({ size = 36, color, children, className }) => {
|
||||
const rotateValue = useSharedValue(0)
|
||||
|
||||
const rotation = useDerivedValue(() => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import * as React from "react"
|
||||
import Svg, { Path } from "react-native-svg"
|
||||
|
||||
interface UserAdd2CuteFiIconProps {
|
||||
width?: number
|
||||
height?: number
|
||||
color?: string
|
||||
}
|
||||
|
||||
export const UserAdd2CuteFiIcon = ({
|
||||
width = 24,
|
||||
height = 24,
|
||||
color = "#10161F",
|
||||
}: UserAdd2CuteFiIconProps) => {
|
||||
return (
|
||||
<Svg width={width} height={height} fill="none" viewBox="0 0 24 24">
|
||||
<Path fill="#fff" fillOpacity={0.01} d="M24 0v24H0V0z" />
|
||||
<Path
|
||||
fill={color}
|
||||
d="M6 7a5 5 0 1 1 10 0A5 5 0 0 1 6 7M4.822 14.672C6.425 13.694 8.605 13 11 13c.447 0 .887.024 1.316.07a1 1 0 0 1 .72 1.557A5.968 5.968 0 0 0 12 18c0 .92.207 1.79.575 2.567a1 1 0 0 1-.89 1.428c-.226.003-.455.005-.685.005-2.229 0-4.335-.14-5.913-.558-.785-.208-1.524-.506-2.084-.956C2.41 20.01 2 19.345 2 18.5c0-.787.358-1.523.844-2.139.494-.625 1.177-1.2 1.978-1.69M18 14a1 1 0 0 1 1 1v2h2a1 1 0 1 1 0 2h-2v2a1 1 0 1 1-2 0v-2h-2a1 1 0 1 1 0-2h2v-2a1 1 0 0 1 1-1"
|
||||
/>
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import * as React from "react"
|
||||
import Svg, { Path } from "react-native-svg"
|
||||
|
||||
interface Wallet2CuteFiIconProps {
|
||||
width?: number
|
||||
height?: number
|
||||
color?: string
|
||||
}
|
||||
|
||||
export const Wallet2CuteFiIcon = ({
|
||||
width = 24,
|
||||
height = 24,
|
||||
color = "#10161F",
|
||||
}: Wallet2CuteFiIconProps) => {
|
||||
return (
|
||||
<Svg width={width} height={height} fill="none" viewBox="0 0 24 24">
|
||||
<Path fill="#fff" fillOpacity={0.01} d="M24 0v24H0V0z" />
|
||||
<Path
|
||||
fill={color}
|
||||
fillRule="evenodd"
|
||||
d="M9.06 4.647a.31.31 0 0 0-.06.069c0 .01.008.086.137.231.14.157.375.335.702.504.66.342 1.503.549 2.161.549.658 0 1.502-.207 2.161-.549.327-.169.561-.347.702-.504.129-.145.136-.22.137-.231a.309.309 0 0 0-.06-.069c-.106-.094-.31-.213-.639-.325C13.647 4.102 12.765 4 12 4c-.765 0-1.647.101-2.301.322-.33.112-.533.23-.638.325m6.63 2.214c.242-.17.469-.363.663-.58.353-.395.647-.925.647-1.567 0-.666-.317-1.188-.723-1.553-.386-.348-.872-.577-1.336-.733C14.01 2.113 12.892 2 12 2c-.892 0-2.01.113-2.941.428-.464.156-.95.385-1.336.733C7.317 3.526 7 4.048 7 4.714c0 .642.294 1.172.647 1.566.194.218.42.411.663.581C5.325 8.284 3 11.335 3 15c0 2.556 1.02 4.386 2.766 5.525C7.441 21.617 9.67 22 12 22s4.56-.383 6.234-1.475C19.98 19.386 21 17.555 21 15c0-3.665-2.325-6.716-5.31-8.139m-4.296 4.192a1 1 0 1 0-1.788.894L10.132 13H10a1 1 0 1 0 0 2h1v.5h-1a1 1 0 1 0 0 2h1v.5a1 1 0 1 0 2 0v-.5h1a1 1 0 1 0 0-2h-1V15h1a1 1 0 1 0 0-2h-.132l.526-1.053a1 1 0 1 0-1.788-.894L12 12.263z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ export const useDataSkeleton = (isLoading: boolean, data: any) => {
|
|||
return (
|
||||
<BaseSearchPageRootView className="items-center justify-center">
|
||||
<View className="-mt-72" />
|
||||
<LoadingIndicator color={withOpacity(textColor, 0.7)} size={32} />
|
||||
<LoadingIndicator color={withOpacity(textColor, 0.7)} />
|
||||
</BaseSearchPageRootView>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ const SubscriptionItem = memo(({ id, className }: { id: string; className?: stri
|
|||
if (isLoading) {
|
||||
return (
|
||||
<View className="mt-24 flex-1 flex-row items-start justify-center">
|
||||
<LoadingIndicator size={36} />
|
||||
<LoadingIndicator />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export function FollowFeed(props: { id: string }) {
|
|||
if (isLoading) {
|
||||
return (
|
||||
<View className="mt-24 flex-1 flex-row items-start justify-center">
|
||||
<LoadingIndicator size={36} />
|
||||
<LoadingIndicator />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export const FollowList = (props: { id: string }) => {
|
|||
if (isLoading) {
|
||||
return (
|
||||
<View className="mt-24 flex-1 flex-row items-start justify-center">
|
||||
<LoadingIndicator size={36} />
|
||||
<LoadingIndicator />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ const UserGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
navigation.navigate("Achievement")
|
||||
},
|
||||
iconBackgroundColor: "#6366F1",
|
||||
todo: true,
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -107,6 +108,7 @@ const DataGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
navigation.navigate("Actions")
|
||||
},
|
||||
iconBackgroundColor: "#059669",
|
||||
todo: true,
|
||||
},
|
||||
|
||||
{
|
||||
|
|
@ -116,6 +118,7 @@ const DataGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
navigation.navigate("Feeds")
|
||||
},
|
||||
iconBackgroundColor: "#10B981",
|
||||
todo: true,
|
||||
},
|
||||
{
|
||||
label: "Lists",
|
||||
|
|
@ -124,6 +127,7 @@ const DataGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
navigation.navigate("Lists")
|
||||
},
|
||||
iconBackgroundColor: "#34D399",
|
||||
// todo: true,
|
||||
},
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,168 @@
|
|||
import { Text, View } from "react-native"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { createElement, useCallback } from "react"
|
||||
import type { ListRenderItem } from "react-native"
|
||||
import { Image, StyleSheet, Text, TouchableOpacity, View } from "react-native"
|
||||
import Animated, { LinearTransition } from "react-native-reanimated"
|
||||
import { useColor } from "react-native-uikit-colors"
|
||||
|
||||
import { Balance } from "@/src/components/common/Balance"
|
||||
import {
|
||||
NavigationBlurEffectHeader,
|
||||
SafeNavigationScrollView,
|
||||
} from "@/src/components/common/SafeNavigationScrollView"
|
||||
import {
|
||||
GroupedInformationCell,
|
||||
GroupedInsetListCard,
|
||||
} from "@/src/components/ui/grouped/GroupedList"
|
||||
import { FallbackIcon } from "@/src/components/ui/icon/fallback-icon"
|
||||
import { LoadingIndicator } from "@/src/components/ui/loading"
|
||||
import { views } from "@/src/constants/views"
|
||||
import { AddCuteReIcon } from "@/src/icons/add_cute_re"
|
||||
import { PowerIcon } from "@/src/icons/power"
|
||||
import { RadaCuteFiIcon } from "@/src/icons/rada_cute_fi"
|
||||
import { UserAdd2CuteFiIcon } from "@/src/icons/user_add_2_cute_fi"
|
||||
import { Wallet2CuteFiIcon } from "@/src/icons/wallet_2_cute_fi"
|
||||
import type { HonoApiClient } from "@/src/morph/types"
|
||||
import { listSyncServices } from "@/src/store/list/store"
|
||||
import { accentColor } from "@/src/theme/colors"
|
||||
|
||||
export const ListsScreen = () => {
|
||||
const { isLoading, data } = useQuery({
|
||||
queryKey: ["owned", "lists"],
|
||||
queryFn: () => listSyncServices.fetchOwnedLists(),
|
||||
})
|
||||
|
||||
return (
|
||||
<View className="flex-1 items-center justify-center">
|
||||
<Text>Lists Settings</Text>
|
||||
<SafeNavigationScrollView nestedScrollEnabled className="bg-system-grouped-background">
|
||||
<NavigationBlurEffectHeader
|
||||
title="Lists"
|
||||
headerRight={useCallback(
|
||||
() => (
|
||||
<AddListButton />
|
||||
),
|
||||
[],
|
||||
)}
|
||||
/>
|
||||
|
||||
<View className="mt-6">
|
||||
<GroupedInsetListCard>
|
||||
<GroupedInformationCell
|
||||
title="Lists"
|
||||
description="Lists are collections of feeds that you can share or sell for others to subscribe to. Subscribers will synchronize and access all feeds in the list."
|
||||
icon={<RadaCuteFiIcon height={40} width={40} color="#fff" />}
|
||||
iconBackgroundColor="#34D399"
|
||||
/>
|
||||
</GroupedInsetListCard>
|
||||
</View>
|
||||
|
||||
<View className="mt-6">
|
||||
{data && (
|
||||
<GroupedInsetListCard>
|
||||
<Animated.FlatList
|
||||
keyExtractor={keyExtractor}
|
||||
itemLayoutAnimation={LinearTransition}
|
||||
scrollEnabled={false}
|
||||
data={data}
|
||||
renderItem={ListItemCell}
|
||||
ItemSeparatorComponent={ItemSeparatorComponent}
|
||||
/>
|
||||
</GroupedInsetListCard>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{isLoading && (
|
||||
<View className="flex-1 items-center justify-center">
|
||||
<LoadingIndicator />
|
||||
</View>
|
||||
)}
|
||||
</SafeNavigationScrollView>
|
||||
)
|
||||
}
|
||||
|
||||
const AddListButton = () => {
|
||||
const labelColor = useColor("label")
|
||||
return (
|
||||
<TouchableOpacity hitSlop={10}>
|
||||
<AddCuteReIcon height={20} width={20} color={labelColor} />
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
const ItemSeparatorComponent = () => {
|
||||
return (
|
||||
<View
|
||||
className="bg-opaque-separator ml-24 flex-1"
|
||||
style={{ height: StyleSheet.hairlineWidth }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const keyExtractor = (item: HonoApiClient.List_List_Get) => item.id
|
||||
|
||||
const ListItemCell: ListRenderItem<HonoApiClient.List_List_Get> = ({ item: list }) => {
|
||||
const { title, description } = list
|
||||
return (
|
||||
<View className="flex-row p-4">
|
||||
<View className="size-16 overflow-hidden rounded-lg">
|
||||
{list.image ? (
|
||||
<Image source={{ uri: list.image }} resizeMode="cover" className="size-full" />
|
||||
) : (
|
||||
<FallbackIcon title={list.title || ""} size="100%" textStyle={styles.title} />
|
||||
)}
|
||||
</View>
|
||||
<View className="ml-4 flex-1">
|
||||
<Text
|
||||
className="text-label text-lg font-semibold leading-tight"
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="middle"
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
<Text className="text-secondary-label text-base" numberOfLines={4}>
|
||||
{description}
|
||||
</Text>
|
||||
<View className="flex-row items-center gap-1">
|
||||
{!!views[list.view]?.icon &&
|
||||
createElement(views[list.view]!.icon, {
|
||||
color: views[list.view]!.activeColor,
|
||||
height: 16,
|
||||
width: 16,
|
||||
})}
|
||||
<Text className="text-secondary-label text-base">{views[list.view]?.name}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View
|
||||
className="bg-opaque-separator mx-4 h-full"
|
||||
style={{ width: StyleSheet.hairlineWidth }}
|
||||
/>
|
||||
<View className="w-16 gap-1">
|
||||
<View className="flex-row items-center gap-1">
|
||||
<PowerIcon height={16} width={16} color={accentColor} />
|
||||
<Text className="text-secondary-label text-sm">{list.fee}</Text>
|
||||
</View>
|
||||
|
||||
<View className="flex-row items-center gap-1">
|
||||
<UserAdd2CuteFiIcon height={16} width={16} color={accentColor} />
|
||||
<Text className="text-secondary-label text-sm">{list.subscriptionCount || 0}</Text>
|
||||
</View>
|
||||
|
||||
{!!list.purchaseAmount && (
|
||||
<View className="flex-row items-center gap-1">
|
||||
<Wallet2CuteFiIcon height={16} width={16} color={accentColor} />
|
||||
<Balance className="text-secondary-label text-sm">
|
||||
{BigInt(list.purchaseAmount)}
|
||||
</Balance>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
title: {
|
||||
fontSize: 20,
|
||||
fontWeight: "semibold",
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { UnGroupedList } from "./UnGroupedList"
|
|||
// })
|
||||
// }
|
||||
export const CategoryGrouped = memo(
|
||||
// eslint-disable-next-line @eslint-react/no-unstable-context-value
|
||||
({ category, subscriptionIds }: { category: string; subscriptionIds: string[] }) => {
|
||||
const unreadCounts = useUnreadCounts(subscriptionIds)
|
||||
const [expanded, setExpanded] = useState(false)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export const SubscriptionItem = memo(({ id, className }: { id: string; className
|
|||
if (isLoading) {
|
||||
return (
|
||||
<View className="mt-24 flex-1 flex-row items-start justify-center">
|
||||
<LoadingIndicator size={36} />
|
||||
<LoadingIndicator />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ class Morph {
|
|||
return { subscriptions, ...collections }
|
||||
}
|
||||
|
||||
toList({ list: data }: HonoApiClient.List_Get): ListModel {
|
||||
toList(data: HonoApiClient.List_Get["list"] | HonoApiClient.List_List_Get): ListModel {
|
||||
return {
|
||||
id: data.id,
|
||||
title: data.title!,
|
||||
|
|
|
|||
|
|
@ -10,4 +10,5 @@ export namespace HonoApiClient {
|
|||
export type List_Get = ExtractData<typeof apiClient.lists.$get>
|
||||
export type Entry_Post = ExtractData<typeof apiClient.entries.$post>
|
||||
export type Entry_Get = ExtractData<typeof apiClient.entries.$get>
|
||||
export type List_List_Get = ExtractData<typeof apiClient.lists.list.$get>[number]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,10 +84,17 @@ class ListSyncServices {
|
|||
async fetchListById(params: { id: string }) {
|
||||
const list = await apiClient.lists.$get({ query: { listId: params.id } })
|
||||
|
||||
listActions.upsertMany([honoMorph.toList(list.data)])
|
||||
listActions.upsertMany([honoMorph.toList(list.data.list)])
|
||||
|
||||
return list.data
|
||||
}
|
||||
|
||||
async fetchOwnedLists() {
|
||||
const res = await apiClient.lists.list.$get()
|
||||
listActions.upsertMany(res.data.map((list) => honoMorph.toList(list)))
|
||||
|
||||
return res.data
|
||||
}
|
||||
}
|
||||
|
||||
export const listSyncServices = new ListSyncServices()
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none"><path fill="#fff" fill-opacity=".01" d="M24 0v24H0V0z"/><path fill="#10161F" d="M6 7a5 5 0 1 1 10 0A5 5 0 0 1 6 7M4.822 14.672C6.425 13.694 8.605 13 11 13c.447 0 .887.024 1.316.07a1 1 0 0 1 .72 1.557A5.968 5.968 0 0 0 12 18c0 .92.207 1.79.575 2.567a1 1 0 0 1-.89 1.428c-.226.003-.455.005-.685.005-2.229 0-4.335-.14-5.913-.558-.785-.208-1.524-.506-2.084-.956C2.41 20.01 2 19.345 2 18.5c0-.787.358-1.523.844-2.139.494-.625 1.177-1.2 1.978-1.69M18 14a1 1 0 0 1 1 1v2h2a1 1 0 1 1 0 2h-2v2a1 1 0 1 1-2 0v-2h-2a1 1 0 1 1 0-2h2v-2a1 1 0 0 1 1-1"/></svg>
|
||||
|
After Width: | Height: | Size: 621 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none"><path fill="#fff" fill-opacity=".01" d="M24 0v24H0V0z"/><path fill="#10161F" fill-rule="evenodd" d="M9.06 4.647a.31.31 0 0 0-.06.069c0 .01.008.086.137.231.14.157.375.335.702.504.66.342 1.503.549 2.161.549.658 0 1.502-.207 2.161-.549.327-.169.561-.347.702-.504.129-.145.136-.22.137-.231a.309.309 0 0 0-.06-.069c-.106-.094-.31-.213-.639-.325C13.647 4.102 12.765 4 12 4c-.765 0-1.647.101-2.301.322-.33.112-.533.23-.638.325m6.63 2.214c.242-.17.469-.363.663-.58.353-.395.647-.925.647-1.567 0-.666-.317-1.188-.723-1.553-.386-.348-.872-.577-1.336-.733C14.01 2.113 12.892 2 12 2c-.892 0-2.01.113-2.941.428-.464.156-.95.385-1.336.733C7.317 3.526 7 4.048 7 4.714c0 .642.294 1.172.647 1.566.194.218.42.411.663.581C5.325 8.284 3 11.335 3 15c0 2.556 1.02 4.386 2.766 5.525C7.441 21.617 9.67 22 12 22s4.56-.383 6.234-1.475C19.98 19.386 21 17.555 21 15c0-3.665-2.325-6.716-5.31-8.139m-4.296 4.192a1 1 0 1 0-1.788.894L10.132 13H10a1 1 0 1 0 0 2h1v.5h-1a1 1 0 1 0 0 2h1v.5a1 1 0 1 0 2 0v-.5h1a1 1 0 1 0 0-2h-1V15h1a1 1 0 1 0 0-2h-.132l.526-1.053a1 1 0 1 0-1.788-.894L12 12.263z" clip-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -436,6 +436,9 @@ importers:
|
|||
'@follow/utils':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/utils
|
||||
'@formatjs/intl-numberformat':
|
||||
specifier: 8.15.2
|
||||
version: 8.15.2
|
||||
'@gorhom/portal':
|
||||
specifier: 1.0.14
|
||||
version: 1.0.14(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)
|
||||
|
|
@ -475,6 +478,9 @@ importers:
|
|||
dayjs:
|
||||
specifier: 1.11.13
|
||||
version: 1.11.13
|
||||
dnum:
|
||||
specifier: ^2.14.0
|
||||
version: 2.14.0
|
||||
es-toolkit:
|
||||
specifier: 1.29.0
|
||||
version: 1.29.0
|
||||
|
|
@ -3777,6 +3783,18 @@ packages:
|
|||
'@fontsource/sn-pro@5.1.0':
|
||||
resolution: {integrity: sha512-k7cdU1hftD/pyrnrmQg+egKAssbuPORbtgQM/9JG5b76EchEKZdl/juO8xBjN3O/H5BQ16iu8/9vNPgzyExZeg==}
|
||||
|
||||
'@formatjs/ecma402-abstract@2.3.2':
|
||||
resolution: {integrity: sha512-6sE5nyvDloULiyOMbOTJEEgWL32w+VHkZQs8S02Lnn8Y/O5aQhjOEXwWzvR7SsBE/exxlSpY2EsWZgqHbtLatg==}
|
||||
|
||||
'@formatjs/fast-memoize@2.2.6':
|
||||
resolution: {integrity: sha512-luIXeE2LJbQnnzotY1f2U2m7xuQNj2DA8Vq4ce1BY9ebRZaoPB1+8eZ6nXpLzsxuW5spQxr7LdCg+CApZwkqkw==}
|
||||
|
||||
'@formatjs/intl-localematcher@0.5.10':
|
||||
resolution: {integrity: sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==}
|
||||
|
||||
'@formatjs/intl-numberformat@8.15.2':
|
||||
resolution: {integrity: sha512-8rdXSBKXb0nyfEX98/Sh3+ML4JXK2vm7Slnrjikx1svXoBKhiw8kZKwQMpAcGIKtEiQA0conUW3LMPXzv/YlSg==}
|
||||
|
||||
'@freakycoder/react-native-bounceable@1.0.3':
|
||||
resolution: {integrity: sha512-+iMq2tnqxCwFjitbPUz9nZ+VfJ8OU9waIlDJAAsoq1229QEwCmERCNy5zVtDsz75q3i4FLXX/n7fimdMzmP21A==}
|
||||
|
||||
|
|
@ -18338,6 +18356,28 @@ snapshots:
|
|||
|
||||
'@fontsource/sn-pro@5.1.0': {}
|
||||
|
||||
'@formatjs/ecma402-abstract@2.3.2':
|
||||
dependencies:
|
||||
'@formatjs/fast-memoize': 2.2.6
|
||||
'@formatjs/intl-localematcher': 0.5.10
|
||||
decimal.js: 10.4.3
|
||||
tslib: 2.8.1
|
||||
|
||||
'@formatjs/fast-memoize@2.2.6':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@formatjs/intl-localematcher@0.5.10':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@formatjs/intl-numberformat@8.15.2':
|
||||
dependencies:
|
||||
'@formatjs/ecma402-abstract': 2.3.2
|
||||
'@formatjs/intl-localematcher': 0.5.10
|
||||
decimal.js: 10.4.3
|
||||
tslib: 2.8.1
|
||||
|
||||
'@freakycoder/react-native-bounceable@1.0.3': {}
|
||||
|
||||
'@gar/promisify@1.1.3': {}
|
||||
|
|
@ -23274,8 +23314,7 @@ snapshots:
|
|||
optionalDependencies:
|
||||
supports-color: 8.1.1
|
||||
|
||||
decimal.js@10.4.3:
|
||||
optional: true
|
||||
decimal.js@10.4.3: {}
|
||||
|
||||
decode-bmp@0.2.1:
|
||||
dependencies:
|
||||
|
|
|
|||
Loading…
Reference in New Issue