u
This commit is contained in:
1 parent
0ab2796dd4
commit
f7b0c6ad2f
26 files changed
+1893
-354
No files matched your search
@@ -0,0 +1,58 @@
|
||||
import type { AFormRef } from '@/components/common/ao'
|
||||
import { useRef, useState } from 'react'
|
||||
import { Text, View } from 'react-native'
|
||||
import { AButton, ADivider, AForm, AFormItem, AInput } from '@/components/common/ao'
|
||||
import { Link, LinkText } from '@/components/ui/link'
|
||||
|
||||
interface JoinSpaceProps {
|
||||
onBack?: () => void
|
||||
}
|
||||
|
||||
export default function JoinSpace({
|
||||
onBack,
|
||||
}: JoinSpaceProps) {
|
||||
const formRef = useRef<AFormRef>(null)
|
||||
const [form, setForm] = useState({
|
||||
code: '',
|
||||
})
|
||||
return (
|
||||
<View className="px-4 items-center">
|
||||
<AForm ref={formRef} form={form}>
|
||||
<AFormItem
|
||||
name="username"
|
||||
label="邀请码"
|
||||
>
|
||||
<AInput placeholder="请输入邀请码"></AInput>
|
||||
</AFormItem>
|
||||
</AForm>
|
||||
|
||||
<AButton className="w-full">加入空间</AButton>
|
||||
<View
|
||||
className="flex-row items-center w-full"
|
||||
style={{
|
||||
marginTop: 16,
|
||||
marginBottom: 16,
|
||||
}}
|
||||
>
|
||||
<View className="flex-1">
|
||||
<ADivider />
|
||||
</View>
|
||||
<Text className="mx-3 text-gray-500 text-sm">或</Text>
|
||||
<View className="flex-1">
|
||||
<ADivider />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<AButton variant="outline" className="w-full">扫码加入</AButton>
|
||||
|
||||
<Link
|
||||
className="mt-4"
|
||||
onPress={() => {
|
||||
onBack?.()
|
||||
}}
|
||||
>
|
||||
<LinkText>返回</LinkText>
|
||||
</Link>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Text, View } from 'react-native'
|
||||
import { AButton, ADivider, LucideIcon } from '@/components/common/ao'
|
||||
|
||||
interface SpaceHomeProps {
|
||||
onCreate?: () => void
|
||||
onJoin?: () => void
|
||||
}
|
||||
|
||||
export default function SpaceHome({
|
||||
onCreate,
|
||||
onJoin,
|
||||
}: SpaceHomeProps) {
|
||||
return (
|
||||
<View className="p-4">
|
||||
<View className="flex-col gap-4 justify-center items-center">
|
||||
<LucideIcon icon="Earth" size={48} strokeWidth={1.5} />
|
||||
<Text className="font-semibold text-xl">创建共享空间</Text>
|
||||
<Text className="text-base text-center">创建一个专属空间,邀请朋友加入,共享文件、聊天和协作</Text>
|
||||
<AButton
|
||||
className="w-full"
|
||||
onPress={() => onCreate?.()}
|
||||
>
|
||||
创建我的空间
|
||||
</AButton>
|
||||
</View>
|
||||
|
||||
<ADivider text="或" />
|
||||
|
||||
<AButton
|
||||
variant="outline"
|
||||
onPress={() => onJoin?.()}
|
||||
>
|
||||
加入已有空间
|
||||
</AButton>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
import * as Clipboard from 'expo-clipboard'
|
||||
import { useState } from 'react'
|
||||
import { FlatList, Pressable, TouchableOpacity, View } from 'react-native'
|
||||
import QRCode from 'react-native-qrcode-svg'
|
||||
import { AButton, ADivider, LucideIcon } from '@/components/common/ao'
|
||||
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionHeader,
|
||||
AccordionIcon,
|
||||
AccordionItem,
|
||||
AccordionTitleText,
|
||||
AccordionTrigger,
|
||||
} from '@/components/ui/accordion'
|
||||
import {
|
||||
Avatar,
|
||||
AvatarBadge,
|
||||
AvatarFallbackText,
|
||||
} from '@/components/ui/avatar'
|
||||
import { Badge, BadgeText } from '@/components/ui/badge'
|
||||
import { Heading } from '@/components/ui/heading'
|
||||
import { HStack } from '@/components/ui/hstack'
|
||||
import { ChevronDownIcon, ChevronUpIcon } from '@/components/ui/icon'
|
||||
import { Menu, MenuItem, MenuItemLabel } from '@/components/ui/menu'
|
||||
import { Text } from '@/components/ui/text'
|
||||
import { VStack } from '@/components/ui/vstack'
|
||||
import { toast } from '@/utils/toast'
|
||||
|
||||
export default function SpaceInviteAndMembers() {
|
||||
const [accordion, setAccordion] = useState(['a'])
|
||||
|
||||
const members = [
|
||||
{ id: 1, name: '张三' },
|
||||
{ id: 2, name: '李四' },
|
||||
{ id: 3, name: '王五' },
|
||||
]
|
||||
|
||||
async function copyInviteCode() {
|
||||
await Clipboard.setStringAsync('hello world')
|
||||
|
||||
toast.show({
|
||||
title: '复制成功',
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<View className="px-4 flex-1">
|
||||
<Accordion
|
||||
size="md"
|
||||
variant="unfilled"
|
||||
type="multiple"
|
||||
isCollapsible={true}
|
||||
isDisabled={false}
|
||||
value={accordion}
|
||||
onValueChange={(value) => {
|
||||
setAccordion(value)
|
||||
}}
|
||||
>
|
||||
<AccordionItem value="a">
|
||||
<AccordionHeader>
|
||||
<AccordionTrigger
|
||||
style={{
|
||||
paddingLeft: 0,
|
||||
paddingRight: 0,
|
||||
}}
|
||||
>
|
||||
{({ isExpanded }: { isExpanded: boolean }) => {
|
||||
return (
|
||||
<>
|
||||
<AccordionTitleText className="font-semibold text-lg">
|
||||
我的邀请码
|
||||
</AccordionTitleText>
|
||||
{isExpanded
|
||||
? (
|
||||
<AccordionIcon as={ChevronUpIcon} className="ml-3" />
|
||||
)
|
||||
: (
|
||||
<AccordionIcon as={ChevronDownIcon} className="ml-3" />
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}}
|
||||
</AccordionTrigger>
|
||||
</AccordionHeader>
|
||||
<AccordionContent style={{
|
||||
marginBottom: 0,
|
||||
paddingBottom: 0,
|
||||
}}
|
||||
>
|
||||
<TouchableOpacity
|
||||
className="flex-row items-center justify-center"
|
||||
onPress={() => {
|
||||
copyInviteCode()
|
||||
}}
|
||||
>
|
||||
<Text className="font-bold text-3xl tracking-[4px] mr-3">123456</Text>
|
||||
<LucideIcon icon="Copy" size={16} color="blue" clickable={false} />
|
||||
</TouchableOpacity>
|
||||
|
||||
<View className="items-center justify-center">
|
||||
<ADivider direction="horizontal" text="扫描二维码" />
|
||||
<QRCode
|
||||
size={120}
|
||||
value="http://awesome.link.qr"
|
||||
/>
|
||||
</View>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
<View className="mt-4 flex-1">
|
||||
<View className="flex flex-row items-center justify-between">
|
||||
<Text className="font-semibold text-lg">空间成员</Text>
|
||||
<Badge size="lg" variant="solid" action="muted">
|
||||
<BadgeText>3 人</BadgeText>
|
||||
</Badge>
|
||||
</View>
|
||||
|
||||
<View>
|
||||
<FlatList
|
||||
data={members}
|
||||
keyExtractor={item => item.id.toString()}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity>
|
||||
<HStack space="md" className="my-2 items-center">
|
||||
<Avatar className="bg-indigo-600">
|
||||
<AvatarFallbackText className="text-white text-lg">
|
||||
{item.name}
|
||||
</AvatarFallbackText>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
<VStack>
|
||||
<HStack space="sm">
|
||||
<Heading size="sm">{item.name}</Heading>
|
||||
<Badge size="sm" variant="solid" action="muted">
|
||||
<BadgeText>管理员</BadgeText>
|
||||
</Badge>
|
||||
</HStack>
|
||||
<Text size="sm">Marketing Coordinator</Text>
|
||||
</VStack>
|
||||
|
||||
<View className="ml-auto">
|
||||
<Menu
|
||||
placement="top"
|
||||
offset={5}
|
||||
trigger={triggerProps => (
|
||||
<Pressable
|
||||
{...triggerProps}
|
||||
style={{
|
||||
padding: 8,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<LucideIcon icon="EllipsisVertical" size={20} clickable={false} />
|
||||
</Pressable>
|
||||
)}
|
||||
>
|
||||
<MenuItem key="Add account" textValue="Add account">
|
||||
<MenuItemLabel size="sm">添加为管理员</MenuItemLabel>
|
||||
</MenuItem>
|
||||
<MenuItem key="Community" textValue="Community">
|
||||
<MenuItemLabel size="sm">移出空间</MenuItemLabel>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</View>
|
||||
</HStack>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
<AButton size="sm" className="mb-8 mt-4">退出该空间</AButton>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'
|
||||
|
||||
interface StepFadeProps {
|
||||
visible: boolean
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export default function StepFade({ visible, children }: StepFadeProps) {
|
||||
if (!visible)
|
||||
return null
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
entering={FadeIn.duration(200)}
|
||||
exiting={FadeOut.duration(200)}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
{children}
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
@@ -1,241 +1,41 @@
|
||||
import type { AFormRef } from '@/components/common/ao'
|
||||
import * as React from 'react'
|
||||
import { useRef, useState } from 'react'
|
||||
import { FlatList, Pressable, TouchableOpacity, View } from 'react-native'
|
||||
import QRCode from 'react-native-qrcode-svg'
|
||||
import { AButton, ADivider, AForm, AFormItem, AInput, LucideIcon } from '@/components/common/ao'
|
||||
import { useState } from 'react'
|
||||
import { View } from 'react-native'
|
||||
import CustomHeader from '@/components/custom/Header'
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionHeader,
|
||||
AccordionIcon,
|
||||
AccordionItem,
|
||||
AccordionTitleText,
|
||||
AccordionTrigger,
|
||||
} from '@/components/ui/accordion'
|
||||
import {
|
||||
Avatar,
|
||||
AvatarBadge,
|
||||
AvatarFallbackText,
|
||||
AvatarImage,
|
||||
} from '@/components/ui/avatar'
|
||||
import { Badge, BadgeText } from '@/components/ui/badge'
|
||||
|
||||
import { Heading } from '@/components/ui/heading'
|
||||
import { HStack } from '@/components/ui/hstack'
|
||||
import { ChevronDownIcon, ChevronUpIcon } from '@/components/ui/icon'
|
||||
import { Link, LinkText } from '@/components/ui/link'
|
||||
import { Menu, MenuItem, MenuItemLabel } from '@/components/ui/menu'
|
||||
import { Text } from '@/components/ui/text'
|
||||
import { VStack } from '@/components/ui/vstack'
|
||||
import JoinSpace from './components/JoinSpace'
|
||||
import SpaceHome from './components/SpaceHome'
|
||||
import SpaceInviteAndMembers from './components/SpaceInviteAndMembers'
|
||||
import StepFade from './components/StepFade'
|
||||
|
||||
export default function PagerWithTab() {
|
||||
const formRef = useRef<AFormRef>(null)
|
||||
const [form, setForm] = useState({
|
||||
code: '',
|
||||
})
|
||||
|
||||
const [accordion, setAccordion] = useState(['a'])
|
||||
|
||||
function EnterSapce() {
|
||||
return (
|
||||
<View className="px-4 items-center">
|
||||
<AForm ref={formRef} form={form}>
|
||||
<AFormItem
|
||||
name="username"
|
||||
label="邀请码"
|
||||
>
|
||||
<AInput placeholder="请输入邀请码"></AInput>
|
||||
</AFormItem>
|
||||
</AForm>
|
||||
|
||||
<AButton className="w-full">加入空间</AButton>
|
||||
<View
|
||||
className="flex-row items-center w-full"
|
||||
style={{
|
||||
marginTop: 16,
|
||||
marginBottom: 16,
|
||||
}}
|
||||
>
|
||||
<View className="flex-1">
|
||||
<ADivider />
|
||||
</View>
|
||||
<Text className="mx-3 text-gray-500 text-sm">或</Text>
|
||||
<View className="flex-1">
|
||||
<ADivider />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<AButton variant="outline" className="w-full">扫码加入</AButton>
|
||||
|
||||
<Link className="mt-4">
|
||||
<LinkText>返回</LinkText>
|
||||
</Link>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
const members = [
|
||||
{ id: 1, name: '张三' },
|
||||
{ id: 2, name: '李四' },
|
||||
{ id: 3, name: '王五' },
|
||||
]
|
||||
const [step, setStep] = useState<'join' | 'invite' | 'home'>('home')
|
||||
|
||||
return (
|
||||
<View className="flex-1">
|
||||
<CustomHeader title="共享空间" />
|
||||
<View className="flex-1">
|
||||
{/* <View className="p-4">
|
||||
<View className="flex-col gap-4 justify-center items-center">
|
||||
<LucideIcon icon="Earth" size={48} strokeWidth={1.5} />
|
||||
<Text className="font-semibold text-xl">创建共享空间</Text>
|
||||
<Text className="text-base text-center">创建一个专属空间,邀请朋友加入,共享文件、聊天和协作</Text>
|
||||
<AButton className="w-full">创建我的空间</AButton>
|
||||
</View>
|
||||
<View
|
||||
className="flex-row items-center w-full"
|
||||
style={{
|
||||
marginTop: 16,
|
||||
marginBottom: 16,
|
||||
<StepFade visible={step === 'home'}>
|
||||
<SpaceHome
|
||||
onCreate={() => {
|
||||
setStep('invite')
|
||||
}}
|
||||
>
|
||||
<View className="flex-1">
|
||||
<Divider />
|
||||
</View>
|
||||
<Text className="mx-3 text-gray-500 text-sm">或</Text>
|
||||
<View className="flex-1">
|
||||
<Divider />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<AButton variant="outline">加入已有空间</AButton>
|
||||
</View> */}
|
||||
|
||||
{/* <View className="px-4 flex-1">
|
||||
<Accordion
|
||||
size="md"
|
||||
variant="unfilled"
|
||||
type="multiple"
|
||||
isCollapsible={true}
|
||||
isDisabled={false}
|
||||
value={accordion}
|
||||
onValueChange={(value) => {
|
||||
setAccordion(value)
|
||||
onJoin={() => {
|
||||
setStep('join')
|
||||
}}
|
||||
>
|
||||
<AccordionItem value="a">
|
||||
<AccordionHeader>
|
||||
<AccordionTrigger
|
||||
style={{
|
||||
paddingLeft: 0,
|
||||
paddingRight: 0,
|
||||
}}
|
||||
>
|
||||
{({ isExpanded }: { isExpanded: boolean }) => {
|
||||
return (
|
||||
<>
|
||||
<AccordionTitleText className="font-semibold text-lg">
|
||||
我的邀请码
|
||||
</AccordionTitleText>
|
||||
{isExpanded
|
||||
? (
|
||||
<AccordionIcon as={ChevronUpIcon} className="ml-3" />
|
||||
)
|
||||
: (
|
||||
<AccordionIcon as={ChevronDownIcon} className="ml-3" />
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}}
|
||||
</AccordionTrigger>
|
||||
</AccordionHeader>
|
||||
<AccordionContent style={{
|
||||
marginBottom: 0,
|
||||
paddingBottom: 0,
|
||||
}}
|
||||
>
|
||||
<TouchableOpacity className="flex-row items-center justify-center ">
|
||||
<Text className="font-bold text-3xl tracking-[4px] mr-3">123456</Text>
|
||||
<LucideIcon icon="Copy" size={16} color="blue" clickable={false} />
|
||||
</TouchableOpacity>
|
||||
/>
|
||||
</StepFade>
|
||||
|
||||
<View className="items-center justify-center">
|
||||
<ADivider direction="horizontal" text="扫描二维码" />
|
||||
<QRCode
|
||||
size={120}
|
||||
value="http://awesome.link.qr"
|
||||
/>
|
||||
</View>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
<View className="mt-4 flex-1">
|
||||
<View className="flex flex-row items-center justify-between">
|
||||
<Text className="font-semibold text-lg">空间成员</Text>
|
||||
<Badge size="lg" variant="solid" action="muted">
|
||||
<BadgeText>3 人</BadgeText>
|
||||
</Badge>
|
||||
</View>
|
||||
<StepFade visible={step === 'join'}>
|
||||
<JoinSpace
|
||||
onBack={() => {
|
||||
setStep('home')
|
||||
}}
|
||||
/>
|
||||
</StepFade>
|
||||
|
||||
<View>
|
||||
<FlatList
|
||||
data={members}
|
||||
keyExtractor={item => item.id.toString()}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity>
|
||||
<HStack space="md" className="my-2 items-center">
|
||||
<Avatar className="bg-indigo-600">
|
||||
<AvatarFallbackText className="text-white text-lg">
|
||||
{item.name}
|
||||
</AvatarFallbackText>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
<VStack>
|
||||
<HStack space="sm">
|
||||
<Heading size="sm">{item.name}</Heading>
|
||||
<Badge size="sm" variant="solid" action="muted">
|
||||
<BadgeText>管理员</BadgeText>
|
||||
</Badge>
|
||||
</HStack>
|
||||
<Text size="sm">Marketing Coordinator</Text>
|
||||
</VStack>
|
||||
|
||||
<View className="ml-auto">
|
||||
<Menu
|
||||
placement="top"
|
||||
offset={5}
|
||||
trigger={triggerProps => (
|
||||
<Pressable
|
||||
{...triggerProps}
|
||||
style={{
|
||||
padding: 8,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<LucideIcon icon="EllipsisVertical" size={20} clickable={false} />
|
||||
</Pressable>
|
||||
)}
|
||||
>
|
||||
<MenuItem key="Add account" textValue="Add account">
|
||||
<MenuItemLabel size="sm">添加为管理员</MenuItemLabel>
|
||||
</MenuItem>
|
||||
<MenuItem key="Community" textValue="Community">
|
||||
<MenuItemLabel size="sm">移出空间</MenuItemLabel>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</View>
|
||||
</HStack>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
<AButton size="sm" className="mb-8 mt-4">退出该空间</AButton>
|
||||
</View>
|
||||
|
||||
</View> */}
|
||||
|
||||
<EnterSapce />
|
||||
<StepFade visible={step === 'invite'}>
|
||||
<SpaceInviteAndMembers />
|
||||
</StepFade>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -32,8 +32,8 @@ function isWhiteListed(url: string) {
|
||||
}
|
||||
|
||||
const alovaInstance = createAlova({
|
||||
baseURL: 'http://192.168.5.6:8086/app',
|
||||
// baseURL: 'http://192.168.1.136:8086/app',
|
||||
// baseURL: 'http://192.168.5.6:8086/app',
|
||||
baseURL: 'http://192.168.1.136:8086/app',
|
||||
requestAdapter: axiosRequestAdapter(),
|
||||
timeout: 5000,
|
||||
cacheFor: null,
|
||||
|
||||
Reference in new issue
Block a user