Skip to content

Commit 1956140

Browse files
committed
feat: Add MarkdownImage component
1 parent 9ed2846 commit 1956140

File tree

5 files changed

+111
-19
lines changed

5 files changed

+111
-19
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import React, { useState, useEffect } from 'react'
2+
import { StyleSheet, View, Dimensions, Image as RNImage, LayoutChangeEvent } from 'react-native'
3+
import { Image } from '../components/Image'
4+
import './markdown.theme.css' // Duplicate of the React-Native styles from this file
5+
import { UniversalImageProps } from '../components/Image.types'
6+
7+
/* --- <MarkdownImage/> --------------------------------------------------------------------------- */
8+
9+
export const MarkdownImage = (props: UniversalImageProps) => {
10+
// Props
11+
const { src, alt } = props
12+
13+
// State
14+
const [imgDimensions, setImgDimensions] = useState({ width: 0, height: 0 })
15+
const [wrapperWidth, setWrapperWidth] = useState(0)
16+
17+
// Flags
18+
const hasWrapperWidth = !!wrapperWidth
19+
20+
// Vars
21+
const imgRatio = imgDimensions.height / imgDimensions.width
22+
const maxWindowWidth = Dimensions.get('window').width
23+
const widthToUse = Math.min(...[imgDimensions.width, wrapperWidth, maxWindowWidth].filter(Boolean))
24+
const heightToUse = widthToUse * imgRatio
25+
const finalDimensions = imgRatio ? { width: widthToUse, height: heightToUse } : imgDimensions
26+
27+
// -- Handlers --
28+
29+
const handleWrapperLayout = (event: LayoutChangeEvent) => {
30+
if (wrapperWidth < 5) setWrapperWidth(event.nativeEvent.layout.width)
31+
}
32+
33+
// -- Effects --
34+
35+
useEffect(() => {
36+
const checkImageDimensions = async () => {
37+
RNImage.getSize(src as string, (width, height) => {
38+
setImgDimensions({ width, height })
39+
})
40+
}
41+
if (typeof src === 'string') checkImageDimensions()
42+
}, [])
43+
44+
// -- Render --
45+
46+
return (
47+
<View
48+
style={{
49+
...styles.imgWrapper,
50+
...(!hasWrapperWidth ? { minWidth: '100%' } : finalDimensions)
51+
}}
52+
onLayout={!hasWrapperWidth ? handleWrapperLayout : undefined}
53+
>
54+
<Image
55+
alt={alt}
56+
src={src}
57+
style={finalDimensions}
58+
contentFit="contain"
59+
/>
60+
</View>
61+
)
62+
}
63+
64+
/* --- Styles ---------------------------------------------------------------------------------- */
65+
// -i- These styles won't work in Next.js for some reason, duplicate them in markdown.theme.css
66+
67+
const styles = StyleSheet.create({
68+
imgWrapper: {
69+
display: 'flex',
70+
position: 'relative',
71+
flexDirection: 'column',
72+
marginTop: 16,
73+
}
74+
})

features/app-core/mdx/MarkdownTheme.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react'
22
import { StyleSheet, View, Text } from 'react-native'
3+
import { MarkdownImage } from './MarkdownImage'
34
import { MDXStyles, MDXComponents } from '@bacons/mdx'
45
import { Link } from '../navigation/Link'
56
import './markdown.theme.css' // Duplicate of the React-Native styles from this file
@@ -14,7 +15,7 @@ type MarkdownScreenProps = {
1415

1516
const MarkdownTheme = ({ children }: MarkdownScreenProps) => {
1617
return (
17-
<View nativeID="markdown-theme">
18+
<View id="markdown-theme">
1819
<MDXStyles
1920
h1={styles.h1}
2021
h2={styles.h2}
@@ -23,6 +24,7 @@ const MarkdownTheme = ({ children }: MarkdownScreenProps) => {
2324
li={styles.li}
2425
blockquote={styles.blockquote}
2526
a={styles.link}
27+
img={styles.img}
2628
>
2729
<MDXComponents
2830
h1={(props) => <Text {...props} style={{ ...styles.h1 }} />}
@@ -32,6 +34,7 @@ const MarkdownTheme = ({ children }: MarkdownScreenProps) => {
3234
li={(props) => <Text {...props} style={{ ...styles.li }} />}
3335
blockquote={(props) => <View {...props} style={{ ...styles.blockquote }} />} // prettier-ignore
3436
a={(props) => <Link {...props} style={{ ...styles.link }} />}
37+
img={(props) => <MarkdownImage {...props} />}
3538
>
3639
{children}
3740
</MDXComponents>
@@ -83,6 +86,10 @@ const styles = StyleSheet.create({
8386
textAlign: 'center',
8487
textDecorationLine: 'underline',
8588
},
89+
img: {
90+
maxWidth: '100%',
91+
marginTop: 16,
92+
}
8693
})
8794

8895
/* --- Exports --------------------------------------------------------------------------------- */

features/app-core/mdx/markdown.theme.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,7 @@ blockquote {
6060
text-align: center;
6161
text-decoration: underline;
6262
}
63+
64+
#markdown-theme img {
65+
max-width: 100%;
66+
}

features/app-core/mdx/readme.mdx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import View from 'react-native'
12
import { Image } from '../components/Image'
23

34
<Image
@@ -18,3 +19,5 @@ It's a good starting point if you want to:
1819
- ✅ leave *all other tech choices* for e.g. styling, dbs, component libs, etc. *up to you*
1920

2021
> Need a more robust, Fully-Stacked, Full-Product, Universal App Setup? Check out **[FullProduct.dev](https://fullproduct.dev) ⚡️**
22+
23+
[![Screenshot of FullProduct.dev](https://github.com/user-attachments/assets/a2eecfd2-7889-4079-944b-1b5af6cf5ddf)](https://fullproduct.dev)

features/app-core/screens/MarkdownScreen.tsx

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,46 @@
11
import React from 'react'
2-
import { StyleSheet, View } from 'react-native'
2+
import { StyleSheet, View, ScrollView, Dimensions } from 'react-native'
33
import { Link } from '../navigation/Link' // @ts-ignore
44
import ReadMe from '../mdx/readme.mdx'
55
import MarkdownTheme from '../mdx/MarkdownTheme'
66

77
/* --- <MarkdownScreen/> --------------------------------------------------------------------------- */
88

9-
const MarkdownScreen = () => {
10-
return (
11-
<View style={styles.container}>
12-
<Link
13-
href="/"
14-
style={{ ...styles.backButton, ...styles.link, textDecorationLine: 'none' }}
15-
>
16-
{`< Back`}
17-
</Link>
18-
<View style={styles.markdownWrapper}>
19-
<MarkdownTheme>
20-
<ReadMe />
21-
</MarkdownTheme>
9+
const MarkdownScreen = () => (
10+
<ScrollView contentContainerStyle={styles.container}>
11+
<View style={styles.mainPage}>
12+
<Link
13+
href="/"
14+
style={{ ...styles.backButton, ...styles.link, textDecorationLine: 'none' }}
15+
>
16+
{`< Back`}
17+
</Link>
18+
<View style={styles.markdownWrapper}>
19+
<MarkdownTheme>
20+
<ReadMe />
21+
</MarkdownTheme>
22+
</View>
2223
</View>
23-
</View>
24-
)
25-
}
24+
</ScrollView>
25+
)
2626

2727
/* --- Styles ---------------------------------------------------------------------------------- */
2828

2929
const styles = StyleSheet.create({
3030
container: {
3131
flex: 1,
32-
justifyContent: 'center',
32+
},
33+
mainPage: {
34+
flex: 1,
3335
alignItems: 'center',
3436
padding: 24,
37+
minWidth: Math.min(600, Dimensions.get('window').width)
3538
},
3639
markdownWrapper: {
3740
width: '100%',
3841
position: 'relative',
3942
alignItems: 'flex-start',
43+
paddingTop: 50,
4044
maxWidth: 600,
4145
},
4246
backButton: {

0 commit comments

Comments
 (0)