Skip to content

Commit

Permalink
chore: Release v0.3.0-beta.0 (#2411)
Browse files Browse the repository at this point in the history
  • Loading branch information
DIYgod authored Jan 2, 2025
2 parents f9314f4 + 78df5b9 commit 871dbf3
Show file tree
Hide file tree
Showing 154 changed files with 4,910 additions and 1,338 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
},
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"files.associations": {
"*.css": "tailwindcss"
},
"tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"],
Expand Down
46 changes: 45 additions & 1 deletion CHANGELOG.md

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions apps/main/src/lib/router.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { callWindowExpose } from "@follow/shared/bridge"
import { DEEPLINK_SCHEME } from "@follow/shared/constants"
import { extractElectronWindowOptions } from "@follow/shared/electron"
import type { BrowserWindow } from "electron/main"

Expand All @@ -9,7 +8,15 @@ import { createMainWindow, createWindow, getMainWindow } from "~/window"
export const handleUrlRouting = (url: string) => {
const options = extractElectronWindowOptions(url)

const uri = url.replace(DEEPLINK_SCHEME, "/")
// For example, the url is "follow://add?id=123&type=list&url=https://example.com"
const doubleSlash = url.indexOf("://")
if (doubleSlash === -1) {
logger.error("url routing error: no protocol found", url)
return
}
// Remove the protocol
// For example, the uri is "/add?id=123&type=list&url=https://example.com"
const uri = url.slice(doubleSlash + 2)
try {
const { pathname, searchParams } = new URL(uri, "https://follow.dev")

Expand Down
12 changes: 12 additions & 0 deletions apps/mobile/babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,19 @@ module.exports = function (api) {
"module-resolver",
{
alias: {
"es-toolkit/compat": path.resolve(
__dirname,
"../../node_modules/es-toolkit/dist/compat/index.js",
),
"es-toolkit": path.resolve(__dirname, "../../node_modules/es-toolkit/dist/index.js"),
"better-auth/react": path.resolve(
__dirname,
"../../node_modules/better-auth/dist/react.js",
),
"@better-auth/expo/client": path.resolve(
__dirname,
"../../node_modules/@better-auth/expo/dist/client.js",
),
},
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
Expand Down
7 changes: 7 additions & 0 deletions apps/mobile/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { DOMProps } from "expo/dom"
import type { FC } from "react"

declare global {
export type WebComponent<P = object> = FC<P & { dom?: DOMProps }>
}
export {}
12 changes: 9 additions & 3 deletions apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,26 @@
"web": "expo start --web"
},
"dependencies": {
"@better-auth/expo": "1.0.23-beta.2",
"@better-auth/expo": "1.1.9-beta.1",
"@expo/vector-icons": "^14.0.2",
"@follow/components": "workspace:*",
"@follow/constants": "workspace:*",
"@follow/hooks": "workspace:*",
"@follow/models": "workspace:*",
"@follow/shared": "workspace:*",
"@follow/utils": "workspace:*",
"@gorhom/portal": "1.0.14",
"@hookform/resolvers": "3.9.1",
"@react-native-cookies/cookies": "^6.2.1",
"@react-native-picker/picker": "2.9.0",
"@react-navigation/bottom-tabs": "^7.0.0",
"@react-navigation/native": "^7.0.0",
"@shopify/flash-list": "1.7.1",
"@tanstack/react-query": "5.62.3",
"better-auth": "1.1.3",
"better-auth": "1.1.9-beta.1",
"cookie-es": "^1.2.2",
"dayjs": "1.11.13",
"es-toolkit": "1.29.0",
"expo": "52.0.18",
"expo-apple-authentication": "~7.1.2",
"expo-blur": "~14.0.1",
Expand Down Expand Up @@ -71,7 +76,7 @@
"swiftui-react-native": "6.3.3",
"tailwindcss": "3.4.16",
"usehooks-ts": "3.1.0",
"zod": "3.23.8",
"zod": "3.24.1",
"zustand": "5.0.2"
},
"devDependencies": {
Expand All @@ -83,6 +88,7 @@
"drizzle-kit": "0.30.1",
"eas-cli": "14.2.0",
"expo-drizzle-studio-plugin": "0.1.1",
"postcss": "8.4.49",
"react-test-renderer": "18.3.1"
}
}
8 changes: 8 additions & 0 deletions apps/mobile/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
plugins: {
tailwindcss: {
config: "./tailwind.dom.config.ts",
},
autoprefixer: {},
},
}
5 changes: 5 additions & 0 deletions apps/mobile/src/components/common/AnimatedComponents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Animated, FlatList, ScrollView, TouchableOpacity } from "react-native"

export const AnimatedScrollView = Animated.createAnimatedComponent(ScrollView)
export const AnimatedFlatList = Animated.createAnimatedComponent(FlatList)
export const AnimatedTouchableOpacity = Animated.createAnimatedComponent(TouchableOpacity)
103 changes: 103 additions & 0 deletions apps/mobile/src/components/common/CopyButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { cn } from "@follow/utils/src/utils"
import { useRef } from "react"
import { Pressable } from "react-native"
import Animated, {
interpolateColor,
useAnimatedStyle,
useSharedValue,
withDelay,
withTiming,
} from "react-native-reanimated"
import { useEventCallback } from "usehooks-ts"

import { CheckFilledIcon } from "@/src/icons/check_filled"
import { Copy2CuteReIcon } from "@/src/icons/copy_2_cute_re"
import { useColor } from "@/src/theme/colors"

type Size = "sm" | "md" | "tiny"
interface CopyButtonProps {
onCopy: () => void
className?: string
size?: Size
}

const sizeClassNames = {
tiny: "size-6",
sm: "size-8",
md: "size-10",
}

const sizeIconSize = {
tiny: 14,
sm: 18,
md: 20,
}

const AnimatedPressable = Animated.createAnimatedComponent(Pressable)
export const CopyButton = ({ onCopy, className, size = "sm" }: CopyButtonProps) => {
const initialIconScale = useSharedValue(1)
const pressedIconScale = useSharedValue(0)
const initialStyle = useAnimatedStyle(() => ({
transform: [{ scale: initialIconScale.value }],
}))

const initialBgColor = useColor("gray3")
const pressedBgColor = useColor("green")

const pressedStyle = useAnimatedStyle(() => ({
position: "absolute",
transform: [{ scale: pressedIconScale.value }],
}))

const wrapperStyle = useAnimatedStyle(() => ({
backgroundColor: interpolateColor(
pressedIconScale.value,
[0, 1],
[initialBgColor, pressedBgColor],
),
}))

const animatedProgressingRef = useRef(false)
const handlePress = useEventCallback(() => {
onCopy()

if (animatedProgressingRef.current) return
animatedProgressingRef.current = true
initialIconScale.value = withTiming(0, { duration: 100 }, () => {
pressedIconScale.value = withTiming(1, { duration: 100 }, () => {
pressedIconScale.value = withDelay(
1000,
withTiming(0, { duration: 100 }, () => {
initialIconScale.value = withTiming(1, { duration: 100 })
}),
)
})
})

setTimeout(
() => {
animatedProgressingRef.current = false
},
100 + 100 + 1000 + 100 + 100,
)
})
return (
<AnimatedPressable
hitSlop={10}
style={wrapperStyle}
className={cn(

Check warning on line 88 in apps/mobile/src/components/common/CopyButton.tsx

View workflow job for this annotation

GitHub Actions / Format, Lint and Typecheck (lts/*)

Classname 'bg-gray-4' is not a Tailwind CSS class!
"bg-gray-4 items-center justify-center rounded-lg",
sizeClassNames[size],
className,
)}
onPress={handlePress}
>
<Animated.View style={initialStyle}>
<Copy2CuteReIcon color="#fff" height={sizeIconSize[size]} width={sizeIconSize[size]} />
</Animated.View>
<Animated.View style={pressedStyle}>
<CheckFilledIcon color="#fff" height={sizeIconSize[size]} width={sizeIconSize[size]} />
</Animated.View>
</AnimatedPressable>
)
}
2 changes: 1 addition & 1 deletion apps/mobile/src/components/common/FollowWebView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { WebViewNavigation, WebViewProps } from "react-native-webview"
import { WebView } from "react-native-webview"

import { signOut } from "@/src/lib/auth"
import { useOpenLink } from "@/src/lib/hooks/useOpenLink"
import { useOpenLink } from "@/src/lib/hooks/use-open-link"

const presetUri = Platform.select({
ios: "rn-web/index.html",
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/components/common/HeaderBlur.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ const node = (
}}
/>
)
export const HeaderBlur = () => {
export const BlurEffect = () => {
return node
}
14 changes: 14 additions & 0 deletions apps/mobile/src/components/common/Html.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"use dom"
import "@follow/components/assets/colors-media.css"
import "@follow/components/assets/tailwind.css"

import type { HtmlProps } from "@follow/components"
import { Html } from "@follow/components"

export default function HtmlRender({
content,
dom,
...options
}: { dom?: import("expo/dom").DOMProps } & HtmlProps) {
return <Html content={content} {...options} />
}
18 changes: 18 additions & 0 deletions apps/mobile/src/components/common/ModalSharedComponents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { router } from "expo-router"
import { TouchableOpacity } from "react-native"

import { CloseCuteReIcon } from "@/src/icons/close_cute_re"
import { useColor } from "@/src/theme/colors"

export const ModalHeaderCloseButton = () => {
return <ModalHeaderCloseButtonImpl />
}

const ModalHeaderCloseButtonImpl = () => {
const label = useColor("label")
return (
<TouchableOpacity onPress={() => router.dismiss()}>
<CloseCuteReIcon color={label} />
</TouchableOpacity>
)
}
20 changes: 20 additions & 0 deletions apps/mobile/src/components/common/SafeNavigationScrollView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs"
import { useHeaderHeight } from "@react-navigation/elements"
import type { FC } from "react"
import type { ScrollViewProps } from "react-native"
import { ScrollView, View } from "react-native"
import { useSafeAreaInsets } from "react-native-safe-area-context"

export const SafeNavigationScrollView: FC<ScrollViewProps> = ({ children, ...props }) => {
const headerHeight = useHeaderHeight()
const tabBarHeight = useBottomTabBarHeight()
const insets = useSafeAreaInsets()

return (
<ScrollView contentInsetAdjustmentBehavior="automatic" {...props}>
<View style={{ height: headerHeight - insets.top }} />
<View>{children}</View>
<View style={{ height: tabBarHeight - insets.bottom }} />
</ScrollView>
)
}
20 changes: 20 additions & 0 deletions apps/mobile/src/components/ui/form/Label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { cn } from "@follow/utils/src/utils"
import type { FC, PropsWithChildren } from "react"
import type { StyleProp, ViewStyle } from "react-native"
import { Text, View } from "react-native"

export const FormLabel: FC<
PropsWithChildren<{
label: string
optional?: boolean
className?: string
style?: StyleProp<ViewStyle>
}>
> = ({ label, optional, className, style }) => {
return (
<View className={cn("flex-row", className)} style={style}>
<Text className="text-label font-medium capitalize">{label}</Text>

Check warning on line 16 in apps/mobile/src/components/ui/form/Label.tsx

View workflow job for this annotation

GitHub Actions / Format, Lint and Typecheck (lts/*)

Classname 'text-label' is not a Tailwind CSS class!
{!optional && <Text className="text-red ml-1 align-sub">*</Text>}

Check warning on line 17 in apps/mobile/src/components/ui/form/Label.tsx

View workflow job for this annotation

GitHub Actions / Format, Lint and Typecheck (lts/*)

Classname 'text-red' is not a Tailwind CSS class!
</View>
)
}
Loading

0 comments on commit 871dbf3

Please sign in to comment.