-
Notifications
You must be signed in to change notification settings - Fork 901
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Here's a new template that uses TinyBase (and Expo SQLite) to implement a simple todo app. WYSIWYG! ![image](https://github.com/user-attachments/assets/f643a7c4-833f-4b44-865b-9d32bf08ec1b)
- Loading branch information
1 parent
a3a4bf8
commit 7f52bcc
Showing
4 changed files
with
230 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
import { useState } from 'react'; | ||
import Constants from 'expo-constants'; | ||
import * as SQLite from 'expo-sqlite'; | ||
import { | ||
Platform, | ||
ScrollView, | ||
StyleSheet, | ||
Text, | ||
TextInput, | ||
TouchableOpacity, | ||
View, | ||
} from 'react-native'; | ||
import { createStore } from 'tinybase'; | ||
import { createLocalPersister } from 'tinybase/persisters/persister-browser'; | ||
import { createExpoSqlitePersister } from 'tinybase/persisters/persister-expo-sqlite'; | ||
import { | ||
Provider, | ||
SortedTableView, | ||
useAddRowCallback, | ||
useCreatePersister, | ||
useCreateStore, | ||
useDelTableCallback, | ||
useHasTable, | ||
useRow, | ||
useSetCellCallback, | ||
} from 'tinybase/ui-react'; | ||
|
||
// The TinyBase table contains the todos, with 'text' and 'done' cells. | ||
const TODO_TABLE = 'todo'; | ||
const TEXT_CELL = 'text'; | ||
const DONE_CELL = 'done'; | ||
|
||
// Emojis to decorate each todo. | ||
const NOT_DONE_ICON = String.fromCodePoint('0x1F7E0'); | ||
const DONE_ICON = String.fromCodePoint('0x2705'); | ||
|
||
// The text input component to add a new todo. | ||
const NewTodo = () => { | ||
const [text, setText] = useState(''); | ||
const handleSubmitEditing = useAddRowCallback( | ||
TODO_TABLE, | ||
({ nativeEvent: { text } }) => { | ||
setText(''); | ||
return { [TEXT_CELL]: text, [DONE_CELL]: false }; | ||
} | ||
); | ||
return ( | ||
<TextInput | ||
value={text} | ||
onChangeText={(text) => setText(text)} | ||
onSubmitEditing={handleSubmitEditing} | ||
placeholder='What do you want to do today?' | ||
style={styles.input} | ||
/> | ||
); | ||
}; | ||
|
||
// A single todo component, either 'not done' or 'done': press to toggle. | ||
const Todo = ({ rowId }) => { | ||
const { text, done } = useRow(TODO_TABLE, rowId); | ||
const handlePress = useSetCellCallback( | ||
TODO_TABLE, | ||
rowId, | ||
DONE_CELL, | ||
() => (done) => !done | ||
); | ||
return ( | ||
<TouchableOpacity | ||
key={rowId} | ||
onPress={handlePress} | ||
style={[styles.todo, done ? styles.done : null]} | ||
> | ||
<Text style={styles.todoText}> | ||
{done ? DONE_ICON : NOT_DONE_ICON} {text} | ||
</Text> | ||
</TouchableOpacity> | ||
); | ||
}; | ||
|
||
// A button component to delete all the todos, only shows when there are some. | ||
const ClearTodos = () => { | ||
const handlePress = useDelTableCallback(TODO_TABLE); | ||
return useHasTable(TODO_TABLE) ? ( | ||
<TouchableOpacity onPress={handlePress}> | ||
<Text style={styles.clearTodos}>Clear all</Text> | ||
</TouchableOpacity> | ||
) : null; | ||
}; | ||
|
||
// The main app. | ||
const App = () => { | ||
// Initialize the (memoized) TinyBase store and persist it. | ||
const store = useCreateStore(createStore); | ||
useAndStartPersister(store); | ||
|
||
return ( | ||
// Wrap the app in TinyBase context, so the store is default throughout. | ||
<Provider store={store}> | ||
<View style={styles.container}> | ||
<Text style={styles.heading}>TinyBase Example</Text> | ||
<NewTodo /> | ||
<ScrollView style={styles.todos}> | ||
<SortedTableView | ||
tableId={TODO_TABLE} | ||
rowComponent={Todo} | ||
cellId={DONE_CELL} | ||
/> | ||
<ClearTodos /> | ||
</ScrollView> | ||
</View> | ||
</Provider> | ||
); | ||
}; | ||
|
||
const useAndStartPersister = (store) => | ||
// Persist store to Expo SQLite or local storage; load once, then auto-save. | ||
useCreatePersister( | ||
store, | ||
(store) => | ||
Platform.OS === 'web' | ||
? createLocalPersister(store, 'todos') | ||
: createExpoSqlitePersister(store, SQLite.openDatabaseSync('todos.db')), | ||
[], | ||
(persister) => persister.load().then(persister.startAutoSave) | ||
); | ||
|
||
// Styles for the app. | ||
const styles = StyleSheet.create({ | ||
container: { | ||
backgroundColor: '#fff', | ||
flex: 1, | ||
marginTop: Constants.statusBarHeight, | ||
padding: 16, | ||
}, | ||
heading: { | ||
fontSize: 24, | ||
fontWeight: 'bold', | ||
textAlign: 'center', | ||
}, | ||
input: { | ||
borderColor: '#999', | ||
borderRadius: 8, | ||
borderWidth: 2, | ||
flex: 0, | ||
height: 64, | ||
marginTop: 16, | ||
padding: 16, | ||
fontSize: 20, | ||
}, | ||
todos: { | ||
flex: 1, | ||
marginTop: 16, | ||
}, | ||
todo: { | ||
borderRadius: 8, | ||
marginBottom: 16, | ||
padding: 16, | ||
backgroundColor: '#ffd', | ||
}, | ||
done: { | ||
backgroundColor: '#dfd', | ||
}, | ||
todoText: { | ||
fontSize: 20, | ||
}, | ||
clearTodos: { | ||
margin: 16, | ||
textAlign: 'center', | ||
fontSize: 16, | ||
}, | ||
}); | ||
|
||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# TinyBase Example | ||
|
||
<p> | ||
<!-- iOS --> | ||
<img alt="Supports Expo iOS" longdesc="Supports Expo iOS" src="https://img.shields.io/badge/iOS-4630EB.svg?style=flat-square&logo=APPLE&labelColor=999999&logoColor=fff" /> | ||
<!-- Android --> | ||
<img alt="Supports Expo Android" longdesc="Supports Expo Android" src="https://img.shields.io/badge/Android-4630EB.svg?style=flat-square&logo=ANDROID&labelColor=A4C639&logoColor=fff" /> | ||
<!-- Web --> | ||
<img alt="Supports Expo Web" longdesc="Supports Expo Web" src="https://img.shields.io/badge/web-4630EB.svg?style=flat-square&logo=GOOGLE-CHROME&labelColor=4285F4&logoColor=fff" /> | ||
</p> | ||
|
||
An example demonstrating the use of [TinyBase](https://tinybase.org/) with Expo. | ||
|
||
The app allows adding todo items, marking them as done, and deleting them all, | ||
using a TinyBase store. | ||
|
||
The data is persisted between sessions in Expo SQLite (on iOS and Android) and | ||
local storage (on web). | ||
|
||
![Example in action](https://github.com/user-attachments/assets/f3d95e78-4b9b-488a-af94-2b6e9d67f61a) | ||
|
||
## 🚀 How to use | ||
|
||
- Run `yarn` or `npm install` | ||
- Run `yarn start` or `npm run start` to try it out. | ||
|
||
## 📝 Notes | ||
|
||
- [TinyBase](https://tinybase.org/) | ||
- [Expo SQLite](https://docs.expo.dev/versions/latest/sdk/sqlite/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = function(api) { | ||
api.cache(true); | ||
return { | ||
presets: ['babel-preset-expo'], | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"scripts": { | ||
"start": "expo start", | ||
"android": "expo start --android", | ||
"ios": "expo start --ios", | ||
"web": "expo start --web" | ||
}, | ||
"dependencies": { | ||
"@expo/metro-runtime": "~3.2.1", | ||
"expo": "^51.0.0", | ||
"react": "18.2.0", | ||
"react-dom": "18.2.0", | ||
"react-native": "0.74.1", | ||
"react-native-web": "~0.19.6", | ||
"tinybase": "^5.1.0", | ||
"expo-sqlite": "~14.0.4" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.19.3" | ||
} | ||
} |