Skip to content

Commit f452820

Browse files
authored
chore: extract colors from custom image in example app (#49)
1 parent fc00d04 commit f452820

9 files changed

Lines changed: 683 additions & 237 deletions

File tree

example/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
},
1212
"dependencies": {
1313
"expo": "~54.0.32",
14+
"expo-image-picker": "~17.0.0",
1415
"expo-status-bar": "~3.0.9",
1516
"react": "19.1.0",
1617
"react-native": "0.81.5"

example/src/App.tsx

Lines changed: 33 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,29 @@
11
import { useEffect, useState } from 'react';
22
import {
33
BackHandler,
4-
Image,
54
PlatformColor,
65
Pressable,
76
ScrollView,
87
StatusBar,
98
StyleSheet,
109
Text,
11-
View,
12-
type ImageSourcePropType,
1310
} from 'react-native';
14-
import {
15-
Palette,
16-
type PaletteResult,
17-
type PaletteTarget,
18-
} from 'react-native-material-palette';
19-
import Demo from './Demo';
20-
21-
const PALETTE_TYPES: (keyof PaletteResult)[] = [
22-
'vibrant',
23-
'lightVibrant',
24-
'darkVibrant',
25-
'muted',
26-
'lightMuted',
27-
'darkMuted',
28-
];
29-
30-
const IMAGES = [
31-
{
32-
source: require('../assets/images/ishan-seefromthesky.jpg'),
33-
author: 'Ishan @seefromthesky',
34-
},
35-
{
36-
source: require('../assets/images/mohamed-sameeh.jpg'),
37-
author: 'Mohamed Sameeh',
38-
},
39-
{
40-
source: require('../assets/images/andrew-pons.jpg'),
41-
author: 'Andrew Pons',
42-
},
43-
{
44-
source: require('../assets/images/luke-mummert.jpg'),
45-
author: 'Luke Mummert',
46-
},
47-
{
48-
source: require('../assets/images/paolo-nicolello.jpg'),
49-
author: 'Paolo Nicolello',
50-
},
51-
];
52-
53-
const LIGHT_BACKGROUND_TARGET: PaletteTarget = {
54-
targetLightness: 0.75,
55-
minimumLightness: 0.65,
56-
maximumLightness: 1.0,
57-
targetSaturation: 0.1,
58-
minimumSaturation: 0.0,
59-
maximumSaturation: 0.6,
60-
lightnessWeight: 0.5,
61-
saturationWeight: 0.1,
62-
populationWeight: 0.5,
63-
exclusive: false,
64-
};
11+
import CustomImage from './screens/CustomImage';
12+
import Demo from './screens/Demo';
13+
import { COLORS, SPACING } from './constants';
14+
import { IMAGES } from './data';
15+
import PaletteExampleItem from './components/PaletteExampleItem';
6516

6617
const ROUNDNESS = 10;
67-
const SPACING = 8;
6818

6919
export default function App() {
70-
const [screen, setScreen] = useState<'home' | 'demo'>('home');
20+
const [screen, setScreen] = useState<'home' | 'demo' | 'custom'>('home');
7121

7222
useEffect(() => {
7323
const subscription = BackHandler.addEventListener(
7424
'hardwareBackPress',
7525
() => {
76-
if (screen === 'demo') {
26+
if (screen === 'demo' || screen === 'custom') {
7727
setScreen('home');
7828
return true;
7929
}
@@ -89,78 +39,43 @@ export default function App() {
8939
return <Demo />;
9040
}
9141

42+
if (screen === 'custom') {
43+
return <CustomImage />;
44+
}
45+
9246
return (
9347
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
9448
{IMAGES.map((img, index) => (
95-
<ExampleItem key={index} image={img.source} author={img.author} />
49+
<PaletteExampleItem
50+
key={index}
51+
image={img.source}
52+
author={img.author}
53+
/>
9654
))}
9755
<Pressable style={styles.button} onPress={() => setScreen('demo')}>
9856
<Text style={styles.buttonLabel}>Go to Demo</Text>
9957
</Pressable>
58+
<Pressable style={styles.button} onPress={() => setScreen('custom')}>
59+
<Text style={styles.buttonLabel}>Build Demo from URL / gallery</Text>
60+
</Pressable>
10061
</ScrollView>
10162
);
10263
}
10364

104-
function ExampleItem({
105-
image,
106-
author,
107-
}: {
108-
image: ImageSourcePropType;
109-
author: string;
110-
}) {
111-
return (
112-
<Palette.View
113-
source={image}
114-
type={LIGHT_BACKGROUND_TARGET}
115-
style={styles.item}
116-
>
117-
<View style={styles.underlay} />
118-
<View style={styles.row}>
119-
<Image source={image} style={styles.image} resizeMode="cover" />
120-
<View style={styles.palettes}>
121-
{PALETTE_TYPES.map((type) => (
122-
<View key={type} style={styles.palette}>
123-
<Palette.View
124-
key={type}
125-
source={image}
126-
type={type}
127-
fallback={{
128-
color: '#ffffff',
129-
titleTextColor: '#000000',
130-
bodyTextColor: '#000000',
131-
}}
132-
style={styles.color}
133-
>
134-
<Palette.Text variant="titleTextColor" style={styles.title}>
135-
{type}
136-
</Palette.Text>
137-
<Palette.Text variant="bodyTextColor" style={styles.subtitle}>
138-
subtitle
139-
</Palette.Text>
140-
</Palette.View>
141-
</View>
142-
))}
143-
</View>
144-
</View>
145-
<Palette.Text style={styles.author}>Credits: {author}</Palette.Text>
146-
</Palette.View>
147-
);
148-
}
149-
15065
const styles = StyleSheet.create({
15166
container: {
152-
backgroundColor: '#fff',
67+
backgroundColor: COLORS.background,
15368
},
15469
content: {
155-
padding: SPACING * 2,
156-
paddingTop: SPACING * 2 + (StatusBar.currentHeight ?? 0),
157-
paddingBottom: SPACING * 2 + 10,
158-
gap: SPACING * 2,
70+
padding: SPACING * 4,
71+
paddingTop: SPACING * 4 + (StatusBar.currentHeight ?? 0),
72+
paddingBottom: SPACING * 4 + 10,
73+
gap: SPACING * 4,
15974
},
16075
item: {
16176
width: '100%',
162-
padding: SPACING,
163-
borderRadius: ROUNDNESS + SPACING,
77+
padding: SPACING * 2,
78+
borderRadius: ROUNDNESS + SPACING * 2,
16479
overflow: 'hidden',
16580
},
16681
underlay: {
@@ -176,7 +91,7 @@ const styles = StyleSheet.create({
17691
height: null,
17792
width: null,
17893
borderRadius: ROUNDNESS,
179-
margin: SPACING / 2,
94+
margin: SPACING,
18095
},
18196
palettes: {
18297
flex: 1,
@@ -186,11 +101,11 @@ const styles = StyleSheet.create({
186101
},
187102
palette: {
188103
width: '50%',
189-
padding: SPACING / 2,
104+
padding: SPACING,
190105
},
191106
color: {
192107
alignItems: 'center',
193-
padding: SPACING,
108+
padding: SPACING * 2,
194109
borderRadius: ROUNDNESS,
195110
overflow: 'hidden',
196111
},
@@ -201,15 +116,14 @@ const styles = StyleSheet.create({
201116
fontSize: 14,
202117
},
203118
author: {
204-
margin: SPACING / 2,
119+
margin: SPACING,
205120
fontStyle: 'italic',
206121
},
207122
button: {
208-
marginVertical: SPACING,
209123
backgroundColor: PlatformColor('@android:color/system_accent1_50'),
210-
paddingVertical: SPACING,
211-
paddingHorizontal: SPACING * 2,
212-
borderRadius: ROUNDNESS + SPACING,
124+
paddingVertical: SPACING * 2,
125+
paddingHorizontal: SPACING * 4,
126+
borderRadius: ROUNDNESS + SPACING * 2,
213127
},
214128
buttonLabel: {
215129
textAlign: 'center',
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import {
2+
Image,
3+
StyleSheet,
4+
View,
5+
type ImageSourcePropType,
6+
} from 'react-native';
7+
import { Palette } from 'react-native-material-palette';
8+
import { PALETTE_TYPES, LIGHT_BACKGROUND_TARGET, SPACING } from '../constants';
9+
10+
const ROUNDNESS = 10;
11+
12+
export default function PaleteExampleItem({
13+
image,
14+
author,
15+
}: {
16+
image: ImageSourcePropType;
17+
author?: string;
18+
}) {
19+
return (
20+
<Palette.View
21+
source={image}
22+
type={LIGHT_BACKGROUND_TARGET}
23+
style={styles.item}
24+
>
25+
<View style={styles.underlay} />
26+
<View style={styles.row}>
27+
<Image source={image} style={styles.image} resizeMode="cover" />
28+
<View style={styles.palettes}>
29+
{PALETTE_TYPES.map((type) => (
30+
<View key={type} style={styles.palette}>
31+
<Palette.View
32+
key={type}
33+
source={image}
34+
type={type}
35+
fallback={{
36+
color: '#ffffff',
37+
titleTextColor: '#000000',
38+
bodyTextColor: '#000000',
39+
}}
40+
style={styles.color}
41+
>
42+
<Palette.Text variant="titleTextColor" style={styles.title}>
43+
{type}
44+
</Palette.Text>
45+
<Palette.Text variant="bodyTextColor" style={styles.subtitle}>
46+
subtitle
47+
</Palette.Text>
48+
</Palette.View>
49+
</View>
50+
))}
51+
</View>
52+
</View>
53+
{author ? (
54+
<Palette.Text style={styles.author}>Credits: {author}</Palette.Text>
55+
) : null}
56+
</Palette.View>
57+
);
58+
}
59+
60+
const styles = StyleSheet.create({
61+
item: {
62+
width: '100%',
63+
padding: SPACING * 2,
64+
borderRadius: ROUNDNESS + SPACING * 2,
65+
overflow: 'hidden',
66+
},
67+
underlay: {
68+
...StyleSheet.absoluteFill,
69+
backgroundColor: '#e0e0e0',
70+
mixBlendMode: 'luminosity',
71+
},
72+
row: {
73+
flexDirection: 'row',
74+
},
75+
image: {
76+
flexGrow: 1,
77+
height: null,
78+
width: null,
79+
borderRadius: ROUNDNESS,
80+
margin: SPACING,
81+
},
82+
palettes: {
83+
flex: 1,
84+
minWidth: 100,
85+
flexDirection: 'row',
86+
flexWrap: 'wrap',
87+
},
88+
palette: {
89+
width: '50%',
90+
padding: SPACING,
91+
},
92+
color: {
93+
alignItems: 'center',
94+
padding: SPACING * 2,
95+
borderRadius: ROUNDNESS,
96+
overflow: 'hidden',
97+
},
98+
title: {
99+
fontWeight: 'bold',
100+
},
101+
subtitle: {
102+
fontSize: 14,
103+
},
104+
author: {
105+
margin: SPACING,
106+
fontStyle: 'italic',
107+
},
108+
});

0 commit comments

Comments
 (0)