refactor: update component exports to named exports and enhance UI structure

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-03-30 19:39:59 -03:00
parent 661b821f37
commit e8cd469ee4
40 changed files with 325 additions and 401 deletions

View file

@ -1,11 +0,0 @@
# Tauri + React + Typescript
This template should help get you started developing with Tauri, React and Typescript in Vite.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
upx --best --lzma /home/rodriguez/Sources/my-tauri-app/src-tauri/target/release/my-tauri-app

View file

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View file

Before

Width:  |  Height:  |  Size: 974 B

After

Width:  |  Height:  |  Size: 974 B

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View file

Before

Width:  |  Height:  |  Size: 903 B

After

Width:  |  Height:  |  Size: 903 B

View file

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View file

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,10 +1,7 @@
import React, { useState } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import DateTimePicker from '@react-native-community/datetimepicker';
import { Picker } from '@react-native-picker/picker';
const accountFormSchema = z.object({
name: z
@ -55,28 +52,23 @@ export function AccountForm() {
};
return (
<View>
<div className="space-y-4">
<Controller
control={control}
name="name"
render={({ field: { onChange, value } }) => (
<View style={{ marginBottom: 16 }}>
<Text style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Name</Text>
<TextInput
style={{
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 4,
padding: 8,
}}
onChangeText={onChange}
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Name</label>
<input
className="w-full p-2 border rounded"
onChange={(e) => onChange(e.target.value)}
value={value}
placeholder="Your name"
/>
<Text style={{ fontSize: 14, color: '#666', marginTop: 4 }}>
<p className="text-sm text-gray-500 mt-1">
This is the name that will be displayed on your profile and in emails.
</Text>
</View>
</p>
</div>
)}
/>
@ -84,36 +76,32 @@ export function AccountForm() {
control={control}
name="dob"
render={({ field: { onChange, value } }) => (
<View style={{ marginBottom: 16 }}>
<Text style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Date of birth</Text>
<TouchableOpacity
style={{
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 4,
padding: 8,
}}
onPress={() => setShowDatePicker(true)}
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Date of birth</label>
<button
type="button"
className="w-full p-2 border rounded text-left"
onClick={() => setShowDatePicker(true)}
>
<Text>{value.toDateString()}</Text>
</TouchableOpacity>
{value.toDateString()}
</button>
{showDatePicker && (
<DateTimePicker
value={value}
mode="date"
display="default"
onChange={(event, selectedDate) => {
<input
type="date"
value={value.toISOString().split('T')[0]}
onChange={(e) => {
setShowDatePicker(false);
if (selectedDate) {
onChange(selectedDate);
if (e.target.value) {
onChange(new Date(e.target.value));
}
}}
className="mt-1 p-1 border rounded"
/>
)}
<Text style={{ fontSize: 14, color: '#666', marginTop: 4 }}>
<p className="text-sm text-gray-500 mt-1">
Your date of birth is used to calculate your age.
</Text>
</View>
</p>
</div>
)}
/>
@ -121,35 +109,32 @@ export function AccountForm() {
control={control}
name="language"
render={({ field: { onChange, value } }) => (
<View style={{ marginBottom: 16 }}>
<Text style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Language</Text>
<Picker
selectedValue={value}
onValueChange={onChange}
style={{ height: 50, width: '100%' }}
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Language</label>
<select
className="w-full p-2 border rounded"
value={value}
onChange={(e) => onChange(e.target.value)}
>
{languages.map((language) => (
<Picker.Item key={language.value} label={language.label} value={language.value} />
<option key={language.value} value={language.value}>
{language.label}
</option>
))}
</Picker>
<Text style={{ fontSize: 14, color: '#666', marginTop: 4 }}>
</select>
<p className="text-sm text-gray-500 mt-1">
This is the language that will be used in the dashboard.
</Text>
</View>
</p>
</div>
)}
/>
<TouchableOpacity
style={{
backgroundColor: '#007AFF',
padding: 12,
borderRadius: 8,
alignItems: 'center',
}}
onPress={handleSubmit(onSubmit)}
<button
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
onClick={handleSubmit(onSubmit)}
>
<Text style={{ color: 'white', fontWeight: '500' }}>Update account</Text>
</TouchableOpacity>
</View>
Update account
</button>
</div>
);
}

View file

@ -1,19 +1,17 @@
import React from 'react';
import { View, Text } from 'react-native';
import { AccountForm } from './account-form';
export default function SettingsAccountPage() {
return (
<View style={{ gap: 24 }}>
<View>
<Text style={{ fontSize: 18, fontWeight: '500' }}>Account</Text>
<Text style={{ fontSize: 14, color: '#666' }}>
Update your account settings. Set your preferred language and
timezone.
</Text>
</View>
<View style={{ height: 1, backgroundColor: '#ccc' }} />
<div className="space-y-6">
<div>
<h2 className="text-lg font-medium">Account</h2>
<p className="text-sm text-gray-500">
Update your account settings. Set your preferred language and timezone.
</p>
</div>
<div className="border-t border-gray-200 my-4" />
<AccountForm />
</View>
</div>
);
}

View file

@ -1,6 +1,4 @@
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { Picker } from '@react-native-picker/picker';
import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
@ -32,75 +30,64 @@ export function AppearanceForm() {
};
return (
<View>
<View style={{ marginBottom: 16 }}>
<Text style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Font</Text>
<div className="space-y-4">
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Font</label>
<Controller
control={control}
name="font"
render={({ field: { onChange, value } }) => (
<Picker
selectedValue={value}
onValueChange={onChange}
style={{ height: 50, width: 200 }}
<select
className="w-full p-2 border rounded"
value={value}
onChange={(e) => onChange(e.target.value)}
>
<Picker.Item label="Inter" value="inter" />
<Picker.Item label="Manrope" value="manrope" />
<Picker.Item label="System" value="system" />
</Picker>
<option value="inter">Inter</option>
<option value="manrope">Manrope</option>
<option value="system">System</option>
</select>
)}
/>
<Text style={{ fontSize: 14, color: '#666' }}>
<p className="text-sm text-gray-500">
Set the font you want to use in the dashboard.
</Text>
</View>
</p>
</div>
<View style={{ marginBottom: 16 }}>
<Text style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Theme</Text>
<Text style={{ fontSize: 14, color: '#666', marginBottom: 8 }}>
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Theme</label>
<p className="text-sm text-gray-500 mb-2">
Select the theme for the dashboard.
</Text>
</p>
<Controller
control={control}
name="theme"
render={({ field: { onChange, value } }) => (
<View style={{ flexDirection: 'row', justifyContent: 'space-around' }}>
<TouchableOpacity
style={{
padding: 12,
backgroundColor: value === 'light' ? '#f0f0f0' : 'transparent',
borderRadius: 8,
}}
onPress={() => onChange('light')}
<div className="flex space-x-4">
<button
type="button"
className={`px-4 py-2 rounded ${value === 'light' ? 'bg-gray-200' : 'bg-white'}`}
onClick={() => onChange('light')}
>
<Text>Light</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
padding: 12,
backgroundColor: value === 'dark' ? '#f0f0f0' : 'transparent',
borderRadius: 8,
}}
onPress={() => onChange('dark')}
Light
</button>
<button
type="button"
className={`px-4 py-2 rounded ${value === 'dark' ? 'bg-gray-200' : 'bg-white'}`}
onClick={() => onChange('dark')}
>
<Text>Dark</Text>
</TouchableOpacity>
</View>
Dark
</button>
</div>
)}
/>
</View>
</div>
<TouchableOpacity
style={{
backgroundColor: '#007AFF',
padding: 12,
borderRadius: 8,
alignItems: 'center',
}}
onPress={handleSubmit(onSubmit)}
<button
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
onClick={handleSubmit(onSubmit)}
>
<Text style={{ color: 'white', fontWeight: '500' }}>Update preferences</Text>
</TouchableOpacity>
</View>
Update preferences
</button>
</div>
);
}

View file

@ -1,19 +1,17 @@
import React from 'react';
import { View, Text } from 'react-native';
import { AppearanceForm } from './appearance-form';
export default function SettingsAppearancePage() {
return (
<View style={{ gap: 24 }}>
<View>
<Text style={{ fontSize: 18, fontWeight: '500' }}>Appearance</Text>
<Text style={{ fontSize: 14, color: '#666' }}>
Customize the appearance of the app. Automatically switch between day
and night themes.
</Text>
</View>
<View style={{ height: 1, backgroundColor: '#ccc' }} />
<div className="space-y-6">
<div>
<h2 className="text-lg font-medium">Appearance</h2>
<p className="text-sm text-gray-500">
Customize the appearance of the app. Automatically switch between day and night themes.
</p>
</div>
<div className="border-t border-gray-200 my-4" />
<AppearanceForm />
</View>
</div>
);
}

View file

@ -1,6 +1,5 @@
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { useNavigation, useRoute } from '@react-navigation/native';
import { useNavigate, useLocation } from 'react-router-dom';
interface SidebarNavProps {
items: {
@ -10,24 +9,22 @@ interface SidebarNavProps {
}
export function SidebarNav({ items }: SidebarNavProps) {
const navigation = useNavigation();
const route = useRoute();
const navigate = useNavigate();
const location = useLocation();
return (
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 8 }}>
<div className="flex flex-wrap gap-2">
{items.map((item) => (
<TouchableOpacity
<button
key={item.href}
onPress={() => navigation.navigate(item.href)}
style={{
padding: 8,
backgroundColor: route.name === item.href ? '#f0f0f0' : 'transparent',
borderRadius: 4,
}}
onClick={() => navigate(item.href)}
className={`px-3 py-2 rounded-md text-sm font-medium ${
location.pathname === item.href ? 'bg-gray-100' : 'hover:bg-gray-50'
}`}
>
<Text>{item.title}</Text>
</TouchableOpacity>
{item.title}
</button>
))}
</View>
</div>
);
}

View file

@ -1,5 +1,4 @@
import React from 'react';
import { View, Text, Switch, TouchableOpacity } from 'react-native';
import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
@ -36,44 +35,43 @@ export function DisplayForm() {
};
return (
<View>
<Text style={{ fontSize: 16, fontWeight: '500', marginBottom: 8 }}>Sidebar</Text>
<Text style={{ fontSize: 14, color: '#666', marginBottom: 16 }}>
<div>
<h3 className="text-sm font-medium mb-2">Sidebar</h3>
<p className="text-sm text-gray-500 mb-4">
Select the items you want to display in the sidebar.
</Text>
</p>
{items.map((item) => (
<Controller
key={item.id}
control={control}
name="items"
render={({ field }) => (
<View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 12 }}>
<Switch
value={field.value?.includes(item.id)}
onValueChange={(checked) => {
const updatedValue = checked
<div className="flex items-center mb-3">
<input
type="checkbox"
id={item.id}
checked={field.value?.includes(item.id)}
onChange={(e) => {
const updatedValue = e.target.checked
? [...field.value, item.id]
: field.value?.filter((value) => value !== item.id);
field.onChange(updatedValue);
}}
className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<Text style={{ marginLeft: 8 }}>{item.label}</Text>
</View>
<label htmlFor={item.id} className="ml-2 text-sm">
{item.label}
</label>
</div>
)}
/>
))}
<TouchableOpacity
style={{
backgroundColor: '#007AFF',
padding: 12,
borderRadius: 8,
alignItems: 'center',
marginTop: 16,
}}
onPress={handleSubmit(onSubmit)}
<button
className="mt-4 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
onClick={handleSubmit(onSubmit)}
>
<Text style={{ color: 'white', fontWeight: '500' }}>Update display</Text>
</TouchableOpacity>
</View>
Update display
</button>
</div>
);
}

View file

@ -1,18 +1,17 @@
import React from 'react';
import { View, Text } from 'react-native';
import { DisplayForm } from './display-form';
export default function SettingsDisplayPage() {
return (
<View style={{ gap: 24 }}>
<View>
<Text style={{ fontSize: 18, fontWeight: '500' }}>Display</Text>
<Text style={{ fontSize: 14, color: '#666' }}>
<div className="space-y-6">
<div>
<h2 className="text-lg font-medium">Display</h2>
<p className="text-sm text-gray-500">
Turn items on or off to control what's displayed in the app.
</Text>
</View>
<View style={{ height: 1, backgroundColor: '#ccc' }} />
</p>
</div>
<div className="border-t border-gray-200 my-4" />
<DisplayForm />
</View>
</div>
);
}

View file

@ -1,18 +1,17 @@
import React from 'react';
import { View, Text } from 'react-native';
import { ProfileForm } from './profile-form';
export default function SettingsProfilePage() {
return (
<View style={{ gap: 24 }}>
<View>
<Text style={{ fontSize: 18, fontWeight: '500' }}>Profile</Text>
<Text style={{ fontSize: 14, color: '#666' }}>
<div className="space-y-6">
<div>
<h2 className="text-lg font-medium">Profile</h2>
<p className="text-sm text-gray-500">
This is how others will see you on the site.
</Text>
</View>
<View style={{ height: 1, backgroundColor: '#ccc' }} />
</p>
</div>
<div className="border-t border-gray-200 my-4" />
<ProfileForm />
</View>
</div>
);
}

View file

@ -1,48 +1,47 @@
import React from 'react';
import { View, Text, ScrollView } from 'react-native';
import { SidebarNav } from './components/sidebar-nav';
const sidebarNavItems = [
{
title: "Profile",
href: "/setttings",
href: "/settings",
},
{
title: "Account",
href: "/setttings/account",
href: "/settings/account",
},
{
title: "Appearance",
href: "/setttings/appearance",
href: "/settings/appearance",
},
{
title: "Notifications",
href: "/setttings/notifications",
href: "/settings/notifications",
},
{
title: "Display",
href: "/setttings/display",
href: "/settings/display",
},
];
export default function SettingsLayout({ children }) {
export default function SettingsLayout({ children }: { children: React.ReactNode }) {
return (
<ScrollView style={{ flex: 1 }}>
<View style={{ padding: 20 }}>
<View style={{ marginBottom: 24 }}>
<Text style={{ fontSize: 24, fontWeight: 'bold' }}>Settings</Text>
<Text style={{ fontSize: 14, color: '#666' }}>
<div className="flex-1 overflow-auto">
<div className="p-5">
<div className="mb-6">
<h1 className="text-2xl font-bold">Settings</h1>
<p className="text-sm text-gray-500">
Manage your account settings and set e-mail preferences.
</Text>
</View>
<View style={{ height: 1, backgroundColor: '#ccc', marginVertical: 24 }} />
<View style={{ flexDirection: 'row' }}>
<View style={{ width: '25%', marginRight: 16 }}>
</p>
</div>
<div className="border-t border-gray-200 my-6" />
<div className="flex flex-col md:flex-row gap-6">
<div className="w-full md:w-1/4">
<SidebarNav items={sidebarNavItems} />
</View>
<View style={{ flex: 1 }}>{children}</View>
</View>
</View>
</ScrollView>
</div>
<div className="flex-1">{children}</div>
</div>
</div>
</div>
);
}

View file

@ -1,5 +1,4 @@
import React from 'react';
import { View, Text, Switch, TouchableOpacity } from 'react-native';
import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
@ -35,145 +34,145 @@ export function NotificationsForm() {
};
return (
<View>
<View style={{ marginBottom: 16 }}>
<Text style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Notify me about...</Text>
<div className="space-y-4">
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Notify me about...</label>
<Controller
control={control}
name="type"
render={({ field: { onChange, value } }) => (
<View>
<TouchableOpacity
style={{
flexDirection: 'row',
alignItems: 'center',
marginBottom: 8,
}}
onPress={() => onChange('all')}
>
<View
style={{
width: 20,
height: 20,
borderRadius: 10,
borderWidth: 2,
borderColor: value === 'all' ? '#007AFF' : '#ccc',
marginRight: 8,
}}
<div className="space-y-2">
<div className="flex items-center">
<input
type="radio"
id="all"
checked={value === 'all'}
onChange={() => onChange('all')}
className="h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<Text>All new messages</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
flexDirection: 'row',
alignItems: 'center',
marginBottom: 8,
}}
onPress={() => onChange('mentions')}
>
<View
style={{
width: 20,
height: 20,
borderRadius: 10,
borderWidth: 2,
borderColor: value === 'mentions' ? '#007AFF' : '#ccc',
marginRight: 8,
}}
<label htmlFor="all" className="ml-2">
All new messages
</label>
</div>
<div className="flex items-center">
<input
type="radio"
id="mentions"
checked={value === 'mentions'}
onChange={() => onChange('mentions')}
className="h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<Text>Direct messages and mentions</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
flexDirection: 'row',
alignItems: 'center',
}}
onPress={() => onChange('none')}
>
<View
style={{
width: 20,
height: 20,
borderRadius: 10,
borderWidth: 2,
borderColor: value === 'none' ? '#007AFF' : '#ccc',
marginRight: 8,
}}
<label htmlFor="mentions" className="ml-2">
Direct messages and mentions
</label>
</div>
<div className="flex items-center">
<input
type="radio"
id="none"
checked={value === 'none'}
onChange={() => onChange('none')}
className="h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<Text>Nothing</Text>
</TouchableOpacity>
</View>
<label htmlFor="none" className="ml-2">
Nothing
</label>
</div>
</div>
)}
/>
</View>
</div>
<View style={{ marginBottom: 16 }}>
<Text style={{ fontSize: 18, fontWeight: '500', marginBottom: 16 }}>Email Notifications</Text>
<div className="mb-4">
<h3 className="text-sm font-medium mb-4">Email Notifications</h3>
<Controller
control={control}
name="communication_emails"
render={ ({ field: { onChange, value } }) => (
<View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
<View>
<Text style={{ fontSize: 16, fontWeight: '500' }}>Communication emails</Text>
<Text style={{ fontSize: 14, color: '#666' }}>Receive emails about your account activity.</Text>
</View>
<Switch value={value} onValueChange={onChange} />
</View>
render={({ field: { onChange, value } }) => (
<div className="flex justify-between items-center mb-3">
<div>
<label className="text-sm font-medium">Communication emails</label>
<p className="text-sm text-gray-500">
Receive emails about your account activity.
</p>
</div>
<input
type="checkbox"
checked={value}
onChange={(e) => onChange(e.target.checked)}
className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
</div>
)}
/>
<Controller
control={control}
name="marketing_emails"
render={({ field: { onChange, value } }) => (
<View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
<View>
<Text style={{ fontSize: 16, fontWeight: '500' }}>Marketing emails</Text>
<Text style={{ fontSize: 14, color: '#666' }}>Receive emails about new products, features, and more.</Text>
</View>
<Switch value={value} onValueChange={onChange} />
</View>
<div className="flex justify-between items-center mb-3">
<div>
<label className="text-sm font-medium">Marketing emails</label>
<p className="text-sm text-gray-500">
Receive emails about new products, features, and more.
</p>
</div>
<input
type="checkbox"
checked={value}
onChange={(e) => onChange(e.target.checked)}
className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
</div>
)}
/>
<Controller
control={control}
name="social_emails"
render={({ field: { onChange, value } }) => (
<View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
<View>
<Text style={{ fontSize: 16, fontWeight: '500' }}>Social emails</Text>
<Text style={{ fontSize: 14, color: '#666' }}>Receive emails for friend requests, follows, and more.</Text>
</View>
<Switch value={value} onValueChange={onChange} />
</View>
<div className="flex justify-between items-center mb-3">
<div>
<label className="text-sm font-medium">Social emails</label>
<p className="text-sm text-gray-500">
Receive emails for friend requests, follows, and more.
</p>
</div>
<input
type="checkbox"
checked={value}
onChange={(e) => onChange(e.target.checked)}
className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
</div>
)}
/>
<Controller
control={control}
name="security_emails"
render={({ field: { value } }) => (
<View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
<View>
<Text style={{ fontSize: 16, fontWeight: '500' }}>Security emails</Text>
<Text style={{ fontSize: 14, color: '#666' }}>Receive emails about your account activity and security.</Text>
</View>
<Switch value={value} disabled />
</View>
<div className="flex justify-between items-center">
<div>
<label className="text-sm font-medium">Security emails</label>
<p className="text-sm text-gray-500">
Receive emails about your account activity and security.
</p>
</div>
<input
type="checkbox"
checked={value}
disabled
className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
</div>
)}
/>
</View>
</div>
<TouchableOpacity
style={{
backgroundColor: '#007AFF',
padding: 12,
borderRadius: 8,
alignItems: 'center',
}}
onPress={handleSubmit(onSubmit)}
<button
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
onClick={handleSubmit(onSubmit)}
>
<Text style={{ color: 'white', fontWeight: '500' }}>Update notifications</Text>
</TouchableOpacity>
</View>
Update notifications
</button>
</div>
);
}

View file

@ -1,18 +1,17 @@
import React from 'react';
import { View, Text } from 'react-native';
import { NotificationsForm } from './notifications-form';
export default function SettingsNotificationsPage() {
return (
<View style={{ gap: 24 }}>
<View>
<Text style={{ fontSize: 18, fontWeight: '500' }}>Notifications</Text>
<Text style={{ fontSize: 14, color: '#666' }}>
<div className="space-y-6">
<div>
<h2 className="text-lg font-medium">Notifications</h2>
<p className="text-sm text-gray-500">
Configure how you receive notifications.
</Text>
</View>
<View style={{ height: 1, backgroundColor: '#ccc' }} />
</p>
</div>
<div className="border-t border-gray-200 my-4" />
<NotificationsForm />
</View>
</div>
);
}

View file

@ -1,5 +1,4 @@
import React from 'react';
import { View, Text, TextInput, TouchableOpacity } from 'react-native';
import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
@ -38,30 +37,25 @@ export function ProfileForm() {
};
return (
<View>
<div className="space-y-4">
<Controller
control={control}
name="username"
render={({ field: { onChange, onBlur, value }, fieldState: { error } }) => (
<View style={{ marginBottom: 16 }}>
<Text style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Username</Text>
<TextInput
style={{
borderWidth: 1,
borderColor: error ? 'red' : '#ccc',
borderRadius: 4,
padding: 8,
}}
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Username</label>
<input
className={`w-full p-2 border rounded ${error ? 'border-red-500' : 'border-gray-300'}`}
onBlur={onBlur}
onChangeText={onChange}
onChange={(e) => onChange(e.target.value)}
value={value}
placeholder="Enter username"
/>
{error && <Text style={{ color: 'red', fontSize: 12 }}>{error.message}</Text>}
<Text style={{ fontSize: 14, color: '#666', marginTop: 4 }}>
{error && <p className="text-red-500 text-xs mt-1">{error.message}</p>}
<p className="text-sm text-gray-500 mt-1">
This is your public display name. It can be your real name or a pseudonym. You can only change this once every 30 days.
</Text>
</View>
</p>
</div>
)}
/>
@ -69,26 +63,21 @@ export function ProfileForm() {
control={control}
name="email"
render={({ field: { onChange, onBlur, value }, fieldState: { error } }) => (
<View style={{ marginBottom: 16 }}>
<Text style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Email</Text>
<TextInput
style={{
borderWidth: 1,
borderColor: error ? 'red' : '#ccc',
borderRadius: 4,
padding: 8,
}}
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Email</label>
<input
className={`w-full p-2 border rounded ${error ? 'border-red-500' : 'border-gray-300'}`}
onBlur={onBlur}
onChangeText={onChange}
onChange={(e) => onChange(e.target.value)}
value={value}
placeholder="Enter email"
keyboardType="email-address"
type="email"
/>
{error && <Text style={{ color: 'red', fontSize: 12 }}>{error.message}</Text>}
<Text style={{ fontSize: 14, color: '#666', marginTop: 4 }}>
{error && <p className="text-red-500 text-xs mt-1">{error.message}</p>}
<p className="text-sm text-gray-500 mt-1">
You can manage verified email addresses in your email settings.
</Text>
</View>
</p>
</div>
)}
/>
@ -96,42 +85,30 @@ export function ProfileForm() {
control={control}
name="bio"
render={({ field: { onChange, onBlur, value }, fieldState: { error } }) => (
<View style={{ marginBottom: 16 }}>
<Text style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Bio</Text>
<TextInput
style={{
borderWidth: 1,
borderColor: error ? 'red' : '#ccc',
borderRadius: 4,
padding: 8,
height: 100,
textAlignVertical: 'top',
}}
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Bio</label>
<textarea
className={`w-full p-2 border rounded ${error ? 'border-red-500' : 'border-gray-300'}`}
onBlur={onBlur}
onChangeText={onChange}
onChange={(e) => onChange(e.target.value)}
value={value}
placeholder="Tell us a little bit about yourself"
multiline
rows={4}
/>
{error && <Text style={{ color: 'red', fontSize: 12 }}>{error.message}</Text>}
<Text style={{ fontSize: 14, color: '#666', marginTop: 4 }}>
{error && <p className="text-red-500 text-xs mt-1">{error.message}</p>}
<p className="text-sm text-gray-500 mt-1">
You can @mention other users and organizations to link to them.
</Text>
</View>
</p>
</div>
)}
/>
<TouchableOpacity
style={{
backgroundColor: '#007AFF',
padding: 12,
borderRadius: 8,
alignItems: 'center',
}}
onPress={handleSubmit(onSubmit)}
<button
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
onClick={handleSubmit(onSubmit)}
>
<Text style={{ color: 'white', fontWeight: '500' }}>Update profile</Text>
</TouchableOpacity>
</View>
Update profile
</button>
</div>
);
}

View file

@ -25,8 +25,8 @@ export default defineConfig(async () => ({
}
: undefined,
watch: {
// 3. tell vite to ignore watching `src-tauri`
ignored: ["**/src-tauri/**"],
// 3. tell vite to ignore watching `src-rust`
ignored: ["**/src-rust/**"],
},
},
}));