Skip to content

Commit 51530c0

Browse files
committed
Make example more LOTR themed
1 parent 0327d68 commit 51530c0

22 files changed

+617
-337
lines changed

cspell.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212
],
1313
"ignoreRegExpList": ["/from\\s+(['\"]).*\\1/", "/(['\"`]).*?\\1/g"],
1414
"dictionaryDefinitions": [],
15-
"words": ["bunx", "weakref", "Lotr"],
15+
"words": ["bunx", "weakref", "Thorin"],
1616
"ignoreWords": []
1717
}

example/app/(tabs)/index.tsx

Lines changed: 69 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,26 @@
11
import * as React from "react"
22
import {StyleSheet, View} from "react-native"
33
import {useSafeAreaInsets} from "react-native-safe-area-context"
4-
import {ListItemDataListRow} from "src/components/features/list-item/list-item-data-list-row"
54

65
import {ReactDataList} from "@attio/react-data-list"
76

7+
import {Box} from "../../src/components/design-system/box"
88
import {Button} from "../../src/components/design-system/button"
99
import {LIST_HORIZONTAL_MARGIN} from "../../src/components/design-system/constants"
10-
import {ColorDataListRow} from "../../src/components/features/color-data-list/color-data-list-row"
10+
import {CharacterListItemDataListRow} from "../../src/components/features/character-list-item/character-list-item-data-list-row"
1111
import {ListHeaderDataListRow} from "../../src/components/features/list-header/list-header-data-list-row"
12-
import LotrPlacesDataList from "../../src/components/features/lotr-places-data-list/lotr-places-data-list"
12+
import {LoadingListItemDataListRow} from "../../src/components/features/loading-list-item/loading-list-item-data-list-row"
13+
import MiddleEarthHobbitCompanyDataListRows from "../../src/components/features/middle-earth-hobbit-company-data-list/middle-earth-hobbit-company-data-list-rows"
14+
import {MiddleEarthPlacesDataListRow} from "../../src/components/features/middle-earth-places-data-list/middle-earth-places-data-list-row"
15+
import {MIDDLE_EARTH_PLACES} from "../../src/data/middle-earth-places"
16+
import {
17+
MIDDLE_EARTH_THE_FELLOWSHIP,
18+
type MiddleEarthCharacter,
19+
} from "../../src/data/middle-earth-the-fellowship"
1320
import {FlashListRenderer} from "../../src/data-list/flashlist-renderer"
1421

15-
const styles = StyleSheet.create({
16-
container: {
17-
flex: 1,
18-
},
19-
contentContainer: {
20-
marginBottom: 64,
21-
},
22-
alert: {
23-
width: "100%",
24-
aspectRatio: 1,
25-
backgroundColor: "red",
26-
},
27-
header: {
28-
flexDirection: "row",
29-
alignItems: "center",
30-
justifyContent: "space-between",
31-
gap: 8,
32-
marginHorizontal: LIST_HORIZONTAL_MARGIN,
33-
marginBottom: 16,
34-
},
35-
})
36-
37-
const PEOPLE_NAMES = [
38-
{name: "Thorin", color: "black"},
39-
{name: "Fíli", color: "blue"},
40-
{name: "Kíli", color: "green"},
41-
{name: "Oín", color: "red"},
42-
{name: "Glóin", color: "orange"},
43-
{name: "Balin", color: "purple"},
44-
{name: "Dwalin", color: "brown"},
45-
{name: "Ori", color: "pink"},
46-
{name: "Dori", color: "yellow"},
47-
{name: "Nori", color: "cyan"},
48-
{name: "Bifur", color: "magenta"},
49-
{name: "Bofur", color: "lime"},
50-
{name: "Bombur", color: "navy"},
51-
{name: "Bilbo", color: "gold"},
52-
{name: "Gandalf", color: "silver"},
53-
]
54-
55-
const WEAPONS = [
56-
"Sting",
57-
"Glamdring",
58-
"Orcrist",
59-
"Andúril",
60-
"Narsil",
61-
"Herugrim",
62-
"Hadhafang",
63-
"Aeglos",
64-
"Gurthang",
65-
"Ringil",
66-
]
67-
68-
const ALL_COLORS = [
69-
"aquamarine",
70-
"coral",
71-
"crimson",
72-
"darkgoldenrod",
73-
"darkolivegreen",
74-
"deeppink",
75-
"deepskyblue",
76-
"dimgray",
77-
"dodgerblue",
78-
"firebrick",
79-
"forestgreen",
80-
"fuchsia",
81-
]
82-
83-
const getJumbledPeople = () => PEOPLE_NAMES.slice().sort(() => Math.random() - 0.5)
22+
const getJumbledFellowship = () =>
23+
MIDDLE_EARTH_THE_FELLOWSHIP.slice().sort(() => Math.random() - 0.5)
8424

8525
function ErrorOnRenderCheck() {
8626
return (
@@ -93,16 +33,17 @@ function ErrorOnRenderCheck() {
9333
}
9434

9535
export default function HomeScreen() {
96-
const [people, setPeople] = React.useState<typeof PEOPLE_NAMES>(getJumbledPeople)
97-
const [isShowingPlaces, setIsShowingPlaces] = React.useState(false)
36+
const [fellowship, setFellowship] =
37+
React.useState<ReadonlyArray<MiddleEarthCharacter>>(getJumbledFellowship)
38+
const [isShowingThorinAndCompany, setIsShowingThorinAndCompany] = React.useState(false)
9839

99-
const togglePlaces = () => {
100-
setIsShowingPlaces((s) => !s)
40+
const toggleThorinAndCompany = () => {
41+
setIsShowingThorinAndCompany((s) => !s)
10142
}
10243

103-
const jumblePeople = () => {
104-
console.log("Jumble people to test recreating list.")
105-
setPeople(getJumbledPeople())
44+
// Jumble fellowship to test recreating list.
45+
const jumbleFellowship = () => {
46+
setFellowship(getJumbledFellowship())
10647
}
10748

10849
const insets = useSafeAreaInsets()
@@ -116,13 +57,24 @@ export default function HomeScreen() {
11657
{paddingTop: insets.top, paddingBottom: insets.bottom},
11758
]}
11859
ListHeaderComponent={
119-
<View style={styles.header}>
60+
<Box
61+
flexDirection="row"
62+
gap="4"
63+
marginHorizontal={`${LIST_HORIZONTAL_MARGIN}`}
64+
marginBottom="16"
65+
flexShrink={1}
66+
>
12067
<Button
121-
onPress={togglePlaces}
122-
title={isShowingPlaces ? "Hide Places" : "Show Places"}
68+
onPress={toggleThorinAndCompany}
69+
title={
70+
isShowingThorinAndCompany
71+
? "Hide Thorin and Company"
72+
: "Show Thorin and Company"
73+
}
74+
style={styles.button}
12375
/>
124-
<Button onPress={jumblePeople} title="Jumble People" />
125-
</View>
76+
<Button onPress={jumbleFellowship} title="Jumble Fellowship" />
77+
</Box>
12678
}
12779
/>
12880
}
@@ -133,33 +85,44 @@ export default function HomeScreen() {
13385
)}
13486
>
13587
{/* Supports nested ReactDataList instances */}
136-
<ListHeaderDataListRow title="Colors" />
137-
<ColorDataListRow colors={ALL_COLORS} />
88+
<ListHeaderDataListRow title="Places in Middle Earth" />
89+
<MiddleEarthPlacesDataListRow placeItems={MIDDLE_EARTH_PLACES} />
90+
91+
<ListHeaderDataListRow title="The Fellowship" />
92+
{fellowship.map((character) => (
93+
<CharacterListItemDataListRow
94+
key={character.name}
95+
name={character.name}
96+
race={character.race}
97+
url={character.url}
98+
/>
99+
))}
138100

139-
{isShowingPlaces && (
101+
{isShowingThorinAndCompany && (
140102
<>
141-
<ListHeaderDataListRow title="Places" />
142-
<React.Suspense
143-
fallback={<ListItemDataListRow name="Loading places..." color="black" />}
144-
>
145-
<LotrPlacesDataList />
103+
<ListHeaderDataListRow title="Thorin and Company" />
104+
<React.Suspense fallback={<LoadingListItemDataListRow />}>
105+
<MiddleEarthHobbitCompanyDataListRows />
146106
</React.Suspense>
147107
</>
148108
)}
149-
150-
<ListHeaderDataListRow title="People" />
151-
{people.map((person) => (
152-
<ListItemDataListRow key={person.name} name={person.name} color={person.color} />
153-
))}
154-
155-
<ListHeaderDataListRow title="Weapons" />
156-
{WEAPONS.map((weapon, idx) => (
157-
<ListItemDataListRow
158-
key={weapon}
159-
name={weapon}
160-
color={ALL_COLORS.at(idx % ALL_COLORS.length) ?? "black"}
161-
/>
162-
))}
163109
</ReactDataList>
164110
)
165111
}
112+
113+
const styles = StyleSheet.create({
114+
container: {
115+
flex: 1,
116+
},
117+
button: {
118+
flex: 1,
119+
},
120+
contentContainer: {
121+
marginBottom: 64,
122+
},
123+
alert: {
124+
width: "100%",
125+
aspectRatio: 1,
126+
backgroundColor: "red",
127+
},
128+
})

example/src/components/design-system/button.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@ interface ExampleButtonProps extends Pick<TouchableOpacityProps, "onPress"> {
1111

1212
export function Button({title, onPress, style}: ExampleButtonProps) {
1313
return (
14-
<TouchableOpacity onPress={onPress} activeOpacity={0.8}>
14+
<TouchableOpacity onPress={onPress} activeOpacity={0.8} style={style}>
1515
<Box
1616
minHeight={52}
1717
backgroundColor="accent"
1818
borderRadius="12"
1919
padding="8"
2020
justifyContent="center"
2121
alignItems="center"
22-
style={style}
22+
flex={1}
2323
>
24-
<Text variant="titleLarge" color="textOnAccent" numberOfLines={1}>
24+
<Text variant="medium" color="textOnAccent">
2525
{title}
2626
</Text>
2727
</Box>

example/src/components/features/list-item/list-item-data-list-row.tsx renamed to example/src/components/features/character-list-item/character-list-item-data-list-row.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,44 @@
11
import * as React from "react"
22
import {StyleSheet} from "react-native"
3-
import {LIST_HORIZONTAL_MARGIN} from "src/components/design-system/constants"
43

54
import ReactDataList, {getRelativePositionPerRecyclerType} from "@attio/react-data-list"
65

7-
import {ListItem, type ListItemProps} from "./list-item"
6+
import {LIST_HORIZONTAL_MARGIN} from "../../design-system/constants"
7+
import {CharacterListItem, type CharacterListItemProps} from "./character-list-item"
88

9-
interface ListItemItem extends Omit<ListItemProps, "style" | "isFirst" | "isLast"> {
9+
interface CharacterListItemItem
10+
extends Omit<CharacterListItemProps, "style" | "isFirst" | "isLast"> {
1011
id: string
1112
}
1213

13-
const renderListItem: ReactDataList.RenderListItem<ListItemItem> = (itemInfo) => {
14+
const renderListItem: ReactDataList.RenderListItem<CharacterListItemItem> = (itemInfo) => {
1415
const {itemIndex, totalItems} = getRelativePositionPerRecyclerType(itemInfo)
1516

1617
const item = itemInfo.descriptor.item
1718
const isFirst = itemIndex === 0
1819
const isLast = itemIndex === totalItems - 1
1920

2021
return (
21-
<ListItem
22+
<CharacterListItem
2223
name={item.name}
23-
color={item.color}
24+
race={item.race}
25+
url={item.url}
2426
style={styles.container}
2527
isFirst={isFirst}
2628
isLast={isLast}
2729
/>
2830
)
2931
}
3032

31-
export function ListItemDataListRow({name, color}: Omit<ListItemItem, "id">) {
33+
export function CharacterListItemDataListRow({name, race, url}: Omit<CharacterListItemItem, "id">) {
3234
const id = React.useId()
3335

3436
return (
3537
<ReactDataList.Row
3638
id={id}
37-
item={React.useMemo(() => ({id, name, color}), [name, color])}
39+
item={React.useMemo(() => ({id, name, race, url}), [name, race, url])}
3840
render={renderListItem}
39-
recyclerType="list-item"
41+
recyclerType="character-list-item"
4042
/>
4143
)
4244
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import {Image} from "expo-image"
2+
import {type StyleProp, StyleSheet} from "react-native"
3+
4+
import type {MiddleEarthCharacter} from "../../../data/middle-earth-the-fellowship"
5+
import type {LayoutViewStyle} from "../../../style/layout-view-style"
6+
import {Box} from "../../design-system/box"
7+
import {Text} from "../../design-system/text"
8+
9+
export interface CharacterListItemProps extends MiddleEarthCharacter {
10+
isFirst: boolean
11+
isLast: boolean
12+
style?: StyleProp<LayoutViewStyle>
13+
}
14+
15+
export function CharacterListItem({
16+
name,
17+
race,
18+
url,
19+
isFirst,
20+
isLast,
21+
style,
22+
}: CharacterListItemProps) {
23+
return (
24+
<Box
25+
flexDirection="row"
26+
alignItems="center"
27+
gap="4"
28+
borderColor="strokePrimary"
29+
backgroundColor="bgSecondary"
30+
borderWidth={1}
31+
borderBottomWidth={isLast ? 1 : 0}
32+
padding="6"
33+
paddingHorizontal="8"
34+
alignSelf="stretch"
35+
{...(isFirst && {borderTopLeftRadius: "8", borderTopRightRadius: "8"})}
36+
{...(isLast && {borderBottomLeftRadius: "8", borderBottomRightRadius: "8"})}
37+
style={style}
38+
>
39+
<Image source={{uri: url}} style={styles.avatar} />
40+
41+
<Text variant="body">{name}</Text>
42+
43+
<Text variant="body" color="textQuaternary">
44+
{race}
45+
</Text>
46+
</Box>
47+
)
48+
}
49+
50+
const styles = StyleSheet.create({
51+
avatar: {
52+
width: 32,
53+
height: 32,
54+
borderRadius: "50%",
55+
flexDirection: "row",
56+
alignItems: "center",
57+
},
58+
})

0 commit comments

Comments
 (0)