Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .cursor/mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"mcpServers": {
"RadonAi": {
"url": "http://127.0.0.1:60544/mcp",
"type": "http",
"headers": {
"nonce": "20f25da4-4227-4b6e-8cf1-9f26afcf7289"
}
}
}
}
Binary file added example/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_benchmark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_benchmark@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_benchmark@3x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_chat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_chat@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_chat@3x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_models.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_models@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_models@3x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_sources.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_sources@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_sources@3x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_voice.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_voice@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/onboarding/step_voice@3x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions example/metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,18 @@ const config = withMetroConfig(getDefaultConfig(__dirname), {

config.resolver.unstable_enablePackageExports = true;

// Add watchFolders to include the parent directory for asset resolution
config.watchFolders = [root];

// Configure asset extensions
config.resolver.assetExts = [
...config.resolver.assetExts,
'png',
'jpg',
'jpeg',
'gif',
'webp',
'svg',
];

module.exports = config;
11 changes: 10 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,21 @@
},
"dependencies": {
"@expo/metro-runtime": "~6.1.2",
"@react-native-async-storage/async-storage": "^2.2.0",
"@react-navigation/native": "^7.1.17",
"@react-navigation/native-stack": "^7.3.26",
"expo": "~54.0.7",
"expo-image": "^3.0.8",
"expo-linear-gradient": "~14.0.1",
"expo-status-bar": "~3.0.8",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-native": "0.81.4",
"react-native-web": "~0.21.0"
"react-native-reanimated": "^4.1.2",
"react-native-safe-area-context": "^5.6.1",
"react-native-screens": "^4.16.0",
"react-native-web": "~0.21.0",
"react-native-worklets": "0.5.0"
},
"private": true,
"devDependencies": {
Expand Down
69 changes: 55 additions & 14 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,61 @@
import { Text, View, StyleSheet } from 'react-native';
import { multiply } from 'react-native-onboarding';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { enableScreens } from 'react-native-screens';
import Home from './screens/Home';
import OnboardingDefault from './screens/OnboardingDefault';
import OnboardingCustomIntro from './screens/OnboardingCustomIntro';
import OnboardingCustomSteps from './screens/OnboardingCustomSteps';
import OnboardingCustomTheme from './screens/OnboardingCustomTheme';
import OnboardingGradient from './screens/OnboardingGradient';

const result = multiply(3, 7);
enableScreens(true);

export type RootStackParamList = {
Home: undefined;
OnboardingDefault: undefined;
OnboardingCustomIntro: undefined;
OnboardingCustomSteps: undefined;
OnboardingCustomTheme: undefined;
OnboardingGradient: undefined;
};

const Stack = createNativeStackNavigator<RootStackParamList>();

export default function App() {
return (
<View style={styles.container}>
<Text>Result: {result}</Text>
</View>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ title: 'Example App' }}
/>
<Stack.Screen
name="OnboardingDefault"
component={OnboardingDefault}
options={{ headerShown: false }}
/>
<Stack.Screen
name="OnboardingCustomIntro"
component={OnboardingCustomIntro}
options={{ headerShown: false }}
/>
<Stack.Screen
name="OnboardingCustomSteps"
component={OnboardingCustomSteps}
options={{ headerShown: false }}
/>
<Stack.Screen
name="OnboardingCustomTheme"
component={OnboardingCustomTheme}
options={{ headerShown: false }}
/>
<Stack.Screen
name="OnboardingGradient"
component={OnboardingGradient}
options={{ headerShown: false }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
103 changes: 103 additions & 0 deletions example/src/screens/Home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { useCallback, useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
import type { RootStackParamList } from '../App';
import { useFocusEffect } from '@react-navigation/native';

type Props = NativeStackScreenProps<RootStackParamList, 'Home'>;

const STORAGE_KEY = 'onboarding_finished';

export default function Home({ navigation }: Props) {
const [finished, setFinished] = useState<boolean | null>(null);

const load = useCallback(async () => {
try {
const value = await AsyncStorage.getItem(STORAGE_KEY);
setFinished(value === 'true');
} catch {
setFinished(false);
}
}, []);

useFocusEffect(
useCallback(() => {
load();
}, [load])
);

return (
<View style={styles.container}>
<Text style={styles.title}>React Native Onboarding - Example</Text>
<Text style={styles.subtitle}>
Finished: {finished === null ? 'loading...' : finished ? 'Yes' : 'No'}
</Text>

<View style={styles.actions}>
<Button
title="Open Default Onboarding"
onPress={() => navigation.navigate('OnboardingDefault')}
/>
<View style={styles.spacer} />
<Button
title="Custom Intro"
onPress={() => navigation.navigate('OnboardingCustomIntro')}
/>
<View style={styles.spacer} />
<Button
title="Custom Steps"
onPress={() => navigation.navigate('OnboardingCustomSteps')}
/>
<View style={styles.spacer} />
<Button
title="Custom Theme"
onPress={() => navigation.navigate('OnboardingCustomTheme')}
/>
<View style={styles.spacer} />
<Button
title="Gradient Background"
onPress={() => navigation.navigate('OnboardingGradient')}
/>
</View>

<View style={styles.footer}>
<Button
title="Reset Finished Flag"
onPress={async () => {
await AsyncStorage.removeItem(STORAGE_KEY);
load();
}}
/>
{/* eslint-disable-next-line react-native/no-inline-styles */}
<View style={{ height: 12 }} />
<Button title="Refresh Status" onPress={load} />
</View>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
alignItems: 'stretch',
justifyContent: 'center',
gap: 16,
},
title: {
fontSize: 20,
fontWeight: '700',
textAlign: 'center',
},
subtitle: {
fontSize: 16,
textAlign: 'center',
opacity: 0.8,
},
actions: {
marginTop: 24,
},
spacer: { height: 12 },
footer: { marginTop: 24 },
});
94 changes: 94 additions & 0 deletions example/src/screens/OnboardingCustomIntro.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native';
import Onboarding from 'react-native-onboarding';
import AsyncStorage from '@react-native-async-storage/async-storage';
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
import type { RootStackParamList } from '../App';

type Props = NativeStackScreenProps<
RootStackParamList,
'OnboardingCustomIntro'
>;

const STORAGE_KEY = 'onboarding_finished';

function CustomIntro({ onPressStart }: { onPressStart: () => void }) {
return (
<View style={styles.introContainer}>
<Image source={require('../../assets/logo.png')} style={styles.logo} />
<Text style={styles.h1}>Private AI, Personalized</Text>
<Text style={styles.h2}>Tap to begin your journey</Text>
<TouchableOpacity onPress={onPressStart} style={styles.cta}>
<Text style={styles.ctaText}>Dive In</Text>
</TouchableOpacity>
</View>
);
}

export default function OnboardingCustomIntro({ navigation }: Props) {
return (
<Onboarding
colors={{
background: {
primary: '#0EA5E9',
secondary: '#0B1220',
label: '#111827',
accent: '#0EA5E9',
},
text: {
primary: '#E5E7EB',
secondary: 'rgba(229,231,235,0.7)',
contrast: 'white',
},
}}
fonts="System"
introPanel={CustomIntro}
steps={[
{
title: 'Your data stays with you',
description: 'We never send your prompts to external servers.',
buttonLabel: 'Next',
image: require('../../assets/onboarding/step_chat.png'),
position: 'top',
},
{
title: 'Optimized for device',
description: 'Experience low-latency responses on-device.',
buttonLabel: 'Next',
image: require('../../assets/onboarding/step_benchmark.png'),
position: 'bottom',
},
{
title: 'You decide how it works',
description: 'Customize models and knowledge sources freely.',
buttonLabel: 'Let’s go',
image: require('../../assets/onboarding/step_sources.png'),
position: 'bottom',
},
]}
onComplete={async () => {
await AsyncStorage.setItem(STORAGE_KEY, 'true');
navigation.goBack();
}}
onSkip={() => navigation.goBack()}
onStepChange={() => {}}
showCloseButton
showBackButton={false}
/>
);
}

const styles = StyleSheet.create({
introContainer: { gap: 12, marginTop: 16 },
logo: { alignSelf: 'flex-start' },
h1: { fontSize: 24, fontWeight: '800', color: '#E5E7EB' },
h2: { fontSize: 16, color: 'rgba(229,231,235,0.7)' },
cta: {
marginTop: 12,
backgroundColor: '#0EA5E9',
paddingVertical: 10,
paddingHorizontal: 14,
borderRadius: 10,
alignSelf: 'flex-start',
},
ctaText: { color: '#0B1220', fontWeight: '700' },
});
Loading
Loading