From c5ff7e985f63a1eeb629052cc540e8c3b9cf525b Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Thu, 16 Jan 2020 11:27:43 -0800 Subject: [PATCH] [docs] First pass at tutorial (#6769) --- docs/common/navigation-data.js | 1 + docs/common/navigation.js | 16 +- docs/components/base/code.js | 9 +- docs/components/icons/BrandLogo.js | 9 +- docs/components/plugins/Highlight.js | 11 ++ docs/components/plugins/SnackInline.js | 10 +- docs/global-styles/tippy.js | 4 + .../get-started/create-a-new-app.md | 5 +- .../unversioned/introduction/why-not-expo.md | 4 +- .../pages/versions/unversioned/sdk/sharing.md | 27 +++ .../versions/unversioned/tutorial/button.md | 126 ++++++++++++++ .../unversioned/tutorial/follow-up.md | 69 ++++++++ .../unversioned/tutorial/image-picker.md | 159 ++++++++++++++++++ .../versions/unversioned/tutorial/image.md | 143 ++++++++++++++++ .../versions/unversioned/tutorial/planning.md | 17 ++ .../tutorial/platform-differences.md | 79 +++++++++ .../versions/unversioned/tutorial/sharing.md | 110 ++++++++++++ .../versions/unversioned/tutorial/text.md | 88 ++++++++++ .../v36.0.0/get-started/create-a-new-app.md | 5 +- .../v36.0.0/introduction/why-not-expo.md | 4 +- docs/pages/versions/v36.0.0/sdk/sharing.md | 27 +++ .../pages/versions/v36.0.0/tutorial/button.md | 126 ++++++++++++++ .../versions/v36.0.0/tutorial/follow-up.md | 69 ++++++++ .../versions/v36.0.0/tutorial/image-picker.md | 159 ++++++++++++++++++ docs/pages/versions/v36.0.0/tutorial/image.md | 143 ++++++++++++++++ .../versions/v36.0.0/tutorial/planning.md | 17 ++ .../v36.0.0/tutorial/platform-differences.md | 79 +++++++++ .../versions/v36.0.0/tutorial/sharing.md | 110 ++++++++++++ docs/pages/versions/v36.0.0/tutorial/text.md | 88 ++++++++++ .../unversioned/tutorial/image-picker-log.js | 59 +++++++ .../unversioned/tutorial/image-picker-show.js | 78 +++++++++ .../unversioned/tutorial/sharing-simple.js | 91 ++++++++++ .../tutorial/sharing-web-workaround.js | 97 +++++++++++ .../v36.0.0/tutorial/image-picker-log.js | 59 +++++++ .../v36.0.0/tutorial/image-picker-show.js | 78 +++++++++ .../v36.0.0/tutorial/sharing-simple.js | 91 ++++++++++ .../tutorial/sharing-web-workaround.js | 97 +++++++++++ docs/static/images/favicon.ico | Bin 21822 -> 15406 bytes docs/static/images/header-logo.png | Bin 0 -> 14790 bytes docs/static/videos/tutorial/cli-install.mp4 | Bin 0 -> 537793 bytes docs/static/videos/tutorial/cli-logs.mp4 | Bin 0 -> 1166567 bytes docs/static/videos/tutorial/picker-show.mp4 | Bin 0 -> 516011 bytes .../static/videos/tutorial/sharing-native.mp4 | Bin 0 -> 890227 bytes .../tutorial/sharing-web-unavailable.mp4 | Bin 0 -> 645736 bytes docs/static/videos/tutorial/snack-install.mp4 | Bin 0 -> 528685 bytes 45 files changed, 2339 insertions(+), 25 deletions(-) create mode 100644 docs/components/plugins/Highlight.js create mode 100644 docs/pages/versions/unversioned/tutorial/button.md create mode 100644 docs/pages/versions/unversioned/tutorial/follow-up.md create mode 100644 docs/pages/versions/unversioned/tutorial/image-picker.md create mode 100644 docs/pages/versions/unversioned/tutorial/image.md create mode 100644 docs/pages/versions/unversioned/tutorial/planning.md create mode 100644 docs/pages/versions/unversioned/tutorial/platform-differences.md create mode 100644 docs/pages/versions/unversioned/tutorial/sharing.md create mode 100644 docs/pages/versions/unversioned/tutorial/text.md create mode 100644 docs/pages/versions/v36.0.0/tutorial/button.md create mode 100644 docs/pages/versions/v36.0.0/tutorial/follow-up.md create mode 100644 docs/pages/versions/v36.0.0/tutorial/image-picker.md create mode 100644 docs/pages/versions/v36.0.0/tutorial/image.md create mode 100644 docs/pages/versions/v36.0.0/tutorial/planning.md create mode 100644 docs/pages/versions/v36.0.0/tutorial/platform-differences.md create mode 100644 docs/pages/versions/v36.0.0/tutorial/sharing.md create mode 100644 docs/pages/versions/v36.0.0/tutorial/text.md create mode 100644 docs/static/examples/unversioned/tutorial/image-picker-log.js create mode 100644 docs/static/examples/unversioned/tutorial/image-picker-show.js create mode 100644 docs/static/examples/unversioned/tutorial/sharing-simple.js create mode 100644 docs/static/examples/unversioned/tutorial/sharing-web-workaround.js create mode 100644 docs/static/examples/v36.0.0/tutorial/image-picker-log.js create mode 100644 docs/static/examples/v36.0.0/tutorial/image-picker-show.js create mode 100644 docs/static/examples/v36.0.0/tutorial/sharing-simple.js create mode 100644 docs/static/examples/v36.0.0/tutorial/sharing-web-workaround.js create mode 100644 docs/static/images/header-logo.png create mode 100644 docs/static/videos/tutorial/cli-install.mp4 create mode 100644 docs/static/videos/tutorial/cli-logs.mp4 create mode 100644 docs/static/videos/tutorial/picker-show.mp4 create mode 100644 docs/static/videos/tutorial/sharing-native.mp4 create mode 100644 docs/static/videos/tutorial/sharing-web-unavailable.mp4 create mode 100644 docs/static/videos/tutorial/snack-install.mp4 diff --git a/docs/common/navigation-data.js b/docs/common/navigation-data.js index 584ff52dd77a8..0403324c7391d 100644 --- a/docs/common/navigation-data.js +++ b/docs/common/navigation-data.js @@ -15,6 +15,7 @@ const DIR_MAPPING = { sdk: 'Expo SDK', 'react-native': 'React Native', 'get-started': 'Get Started', + tutorial: 'Tutorial', 'next-steps': 'Next Steps', workflow: 'Fundamentals', distribution: 'Distributing Your App', diff --git a/docs/common/navigation.js b/docs/common/navigation.js index 1befbb1104696..25ec209cd4cc9 100644 --- a/docs/common/navigation.js +++ b/docs/common/navigation.js @@ -5,7 +5,7 @@ const packageVersion = require('../package.json').version; // - Each section is a top-level folder within the version directory // - The groups of sections are expressed only below, there is no representation of them in the filesystem const GROUPS = { - 'The Basics': ['Introduction', 'Get Started', 'Next Steps'], + 'The Basics': ['Introduction', 'Get Started', 'Tutorial', 'Next Steps'], 'Managed Workflow': ['Fundamentals', 'Guides', 'Distributing Your App', 'ExpoKit'], 'Bare Workflow': ['Essentials'], 'API Reference': ['Expo SDK', 'React Native'], @@ -28,6 +28,19 @@ const sections = [ name: 'Get Started', reference: ['Installation', 'Create a new app'], }, + { + name: 'Tutorial', + reference: [ + 'Introduction', + 'Styling text', + 'Adding an image', + 'Creating a button', + 'Picking an image', + 'Sharing the image', + 'Handling platform differences', + 'Learning more', + ], + }, { name: 'Next Steps', reference: ['Using the documentation', 'Join the community', 'Additional resources'], @@ -235,6 +248,7 @@ const sections = [ const ROOT = [ 'Introduction', 'Get Started', + 'Tutorial', 'Fundamentals', 'Guides', 'Distributing Your App', diff --git a/docs/components/base/code.js b/docs/components/base/code.js index b1290f74e0621..6204c9ca87984 100644 --- a/docs/components/base/code.js +++ b/docs/components/base/code.js @@ -1,4 +1,4 @@ -import styled, { keyframes, css } from 'react-emotion'; +import { css } from 'react-emotion'; import Prism from 'prismjs'; import * as React from 'react'; @@ -20,7 +20,8 @@ const STYLES_CODE_BLOCK = css` .code-annotation { transition: 200ms ease all; transition-property: text-shadow, opacity; - text-shadow: rgba(255,255,0,1) 0px 0px 10px, rgba(255,255,0,1) 0px 0px 10px, rgba(255,255,0,1) 0px 0px 10px, rgba(255,255,0,1) 0px 0px 10px; + text-shadow: rgba(255, 255, 0, 1) 0px 0px 10px, rgba(255, 255, 0, 1) 0px 0px 10px, + rgba(255, 255, 0, 1) 0px 0px 10px, rgba(255, 255, 0, 1) 0px 0px 10px; } .code-annotation:hover { @@ -129,4 +130,6 @@ export class Code extends React.Component { } } -export const InlineCode = ({ children }) => {children}; +export const InlineCode = ({ children }) => ( + {children} +); diff --git a/docs/components/icons/BrandLogo.js b/docs/components/icons/BrandLogo.js index 15a85a03360c5..d895fcfb61cdf 100644 --- a/docs/components/icons/BrandLogo.js +++ b/docs/components/icons/BrandLogo.js @@ -3,13 +3,6 @@ import * as React from 'react'; // TODO(jim): Figure out why this was wrapped in a span. export default () => ( - - Expo - - - - - - + Expo ); diff --git a/docs/components/plugins/Highlight.js b/docs/components/plugins/Highlight.js new file mode 100644 index 0000000000000..83b20cca290d6 --- /dev/null +++ b/docs/components/plugins/Highlight.js @@ -0,0 +1,11 @@ +import React from 'react'; +import { css } from 'react-emotion'; + +const STYLES_HIGHLIGHT = css` + text-shadow: rgba(255, 255, 0, 1) 0px 0px 10px, rgba(255, 255, 0, 1) 0px 0px 10px, + rgba(255, 255, 0, 1) 0px 0px 10px, rgba(255, 255, 0, 1) 0px 0px 10px; +`; + +const Highlight = ({ children }) => {children}; + +export default Highlight; diff --git a/docs/components/plugins/SnackInline.js b/docs/components/plugins/SnackInline.js index 270a8193b5fd8..2218062ecf474 100644 --- a/docs/components/plugins/SnackInline.js +++ b/docs/components/plugins/SnackInline.js @@ -60,7 +60,7 @@ export default class SnackInline extends React.Component { let templateId = this.props.templateId; let baseUrl = - `https://snack.expo.io?platform=${DEFAULT_PLATFORM}&name=` + + `https://snack.expo.io?platform=${this.props.defaultPlatform || DEFAULT_PLATFORM}&name=` + encodeURIComponent(label) + `&sdkVersion=${this._getSnackSdkVersion()}` + `&dependencies=${encodeURIComponent(this._getDependencies())}`; @@ -99,8 +99,12 @@ export default class SnackInline extends React.Component {
{this.props.children}
{/* TODO: this should be a POST request, need to change Snack to support it though */} -
- + + diff --git a/docs/global-styles/tippy.js b/docs/global-styles/tippy.js index cdc9c4c297750..259cf8bcef1c4 100644 --- a/docs/global-styles/tippy.js +++ b/docs/global-styles/tippy.js @@ -21,4 +21,8 @@ export const globalTippy = ` color: ${Constants.colors.white}; font-family: ${Constants.fonts.book}; } + + .tippy-content a { + color: #eee; + } `; diff --git a/docs/pages/versions/unversioned/get-started/create-a-new-app.md b/docs/pages/versions/unversioned/get-started/create-a-new-app.md index 2434ab44af550..90983e2ef8ac5 100644 --- a/docs/pages/versions/unversioned/get-started/create-a-new-app.md +++ b/docs/pages/versions/unversioned/get-started/create-a-new-app.md @@ -63,6 +63,7 @@ The Expo client is configured by default to automatically reload the app wheneve ## Up next -You are now in a good place to start digging in to the rest of the documentation! +Depending on your experience level with tools similar to Expo, you may now in a good place to start digging in to the rest of the documentation! -[Continue to "Using the documentation"](../../next-steps/using-the-documentation/) for suggestions on how to continue your learning journey. \ No newline at end of file +- **If you are new to React Native**, we suggest [following a tutorial](../../tutorial/planning/) before proceeding to the rest of the documentation. +- **If you have used React Native before**, [continue to "Using the documentation"](../../next-steps/using-the-documentation/) for suggestions on how to continue your learning journey. \ No newline at end of file diff --git a/docs/pages/versions/unversioned/introduction/why-not-expo.md b/docs/pages/versions/unversioned/introduction/why-not-expo.md index c739ee007752c..687cad40ae6bb 100644 --- a/docs/pages/versions/unversioned/introduction/why-not-expo.md +++ b/docs/pages/versions/unversioned/introduction/why-not-expo.md @@ -3,9 +3,7 @@ title: Limitations sidebar_title: Limitations --- -> *Your success will be limited if you don't know the limitations of your tools.* -> -> — *Confucius (but not really)* +Your success will be limited if you don't know the limitations of your tools. A good software engineer strives to understand the tradeoffs in the decisions she makes. ## Limitations of the managed workflow diff --git a/docs/pages/versions/unversioned/sdk/sharing.md b/docs/pages/versions/unversioned/sdk/sharing.md index 9ba313ceb48a3..044fc52f9e195 100644 --- a/docs/pages/versions/unversioned/sdk/sharing.md +++ b/docs/pages/versions/unversioned/sdk/sharing.md @@ -15,6 +15,18 @@ import Video from '../../../../components/plugins/Video' | -------------- | ---------------- | ---------- | ------------- | --- | | ✅ | ✅ | ✅ | ✅ | ✅ | +
+ +> 🚨 **Web browser support**: expo-sharing for web is built on top of the Web Share API, which still has [very limited browser support](https://caniuse.com/#feat=web-share). Be sure to check that the API can be used before calling it by using `Sharing.isAvailableAsync()`. + +
+ +> 💡 **HTTPS required on web**: The Web Share API is only available on web when the page is served over https. Run your app with `expo start --https` to enable it. + +
+ +> ⚠️ **No local file sharing on web**: Sharing local files by URI works on iOS and Android, but not on web. You cannot share local files on web by URI — you will need to upload them somewhere and share that URI. + ## Installation For [managed](../../introduction/managed-vs-bare/#managed-workflow) apps, you'll need to run `expo install expo-sharing`. To use it in a [bare](../../introduction/managed-vs-bare/#bare-workflow) React Native app, follow its [installation instructions](https://github.com/expo/expo/tree/master/packages/expo-sharing). @@ -25,6 +37,21 @@ For [managed](../../introduction/managed-vs-bare/#managed-workflow) apps, you'll import * as Sharing from 'expo-sharing'; ``` +**[Methods](#methods)** + +- [`Sharing.isAvailableAsync()`](#sharingisavailableasync) +- [`Sharing.shareAsync(url, options)`](#sharingshareasyncurl-options) + +## Methods + +### `Sharing.isAvailableAsync()` + +Determine if the sharing API can be used in this app. + +#### Returns + +A promise that resolves to `true` if the sharing API can be used, and `false` otherwise. + ### `Sharing.shareAsync(url, options)` Opens action sheet to share file to different applications which can handle this type of file. diff --git a/docs/pages/versions/unversioned/tutorial/button.md b/docs/pages/versions/unversioned/tutorial/button.md new file mode 100644 index 0000000000000..c402eba50bc7d --- /dev/null +++ b/docs/pages/versions/unversioned/tutorial/button.md @@ -0,0 +1,126 @@ +--- +title: Creating a button +--- + +import SnackInline from '~/components/plugins/SnackInline'; + +We're going to create our own custom button using the `TouchableOpacity` component and some styled `Text` inside of it. + + + +```jsx +import React from 'react'; +import { Image, StyleSheet, Text, /* @info Add the TouchableOpacity component to your list of imports */ TouchableOpacity,/* @end */ View } from 'react-native'; + +export default function App() { + return ( + + + + To share a photo from your phone with a friend, just press the button below! + + + /* @info onPress takes a function that should be called when the button is pressed */ + alert('Hello, world!')} + style={{ backgroundColor: 'blue' }}> + Pick a photo + /* @end */ + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + alignItems: 'center', + justifyContent: 'center', + }, + logo: { + width: 305, + height: 159, + marginBottom: 20, + }, + instructions: { + color: '#888', + fontSize: 18, + marginHorizontal: 15, + marginBottom: 10, + }, +}); +``` + + + +
+ +Give it a try! Notice that when you press on the button it fades a little bit — this is because our background is white and the button becomes slightly translucent. When you release, you will see an alert dialog. You can show this dialog any time in your apps by calling the `alert` function. + +## Making it easier to press the button + +When you are using your finger to tap on a button, you don't want to have to hold your breathe and carefully aim your finger — the button should be big enough that it's easy to press for people with varying levels of dexterity and an assortment of finger sizes, from baby right up to big boy. + +We can make our button bigger by adding some `padding` to our `TouchableOpacity`. We've already seen `width`, `height`, and various `margin` properties on our styles, `padding` is in the same family as those. They all tell React Native's layout system how big components should be and how they should be positioned relative to other components. The layout system is called [flexbox](https://facebook.github.io/react-native/docs/flexbox), but don't worry about that for now, in this tutorial we will tell you exactly what styles to use and you can learn about flexbox later. + + + +```jsx +import React from 'react'; +import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; + +export default function App() { + return ( + + + + To share a photo from your phone with a friend, just press the button below! + + + alert('Hello, world!')} /* @info We moved our our style down to the StyleSheet, keep scrolling! */ style={styles.button}/* @end */> + Pick a photo + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + alignItems: 'center', + justifyContent: 'center', + }, + logo: { + width: 305, + height: 159, + marginBottom: 20, + }, + instructions: { + color: '#888', + fontSize: 18, + marginHorizontal: 15, + marginBottom: 10, + }, + /* @info Our button, now with some padding. Rounded corners are a bonus thanks to borderRadius. */ + button: { + backgroundColor: "blue", + padding: 20, + borderRadius: 5, + }, + buttonText: { + fontSize: 20, + color: '#fff', + }, /* @end */ + +}); +``` + + + +
+ +> 📜 Yikes, these code snippets are getting long. For the rest of the tutorial we'll show only relevant code here, and you can click through to Snack to see the full code. + +- We have a button! We can now make that button do what we want it to do: open an "image picker" - a screen with a gallery of images on your device. [Continue to the next section](../../tutorial/image-picker/). \ No newline at end of file diff --git a/docs/pages/versions/unversioned/tutorial/follow-up.md b/docs/pages/versions/unversioned/tutorial/follow-up.md new file mode 100644 index 0000000000000..dea9a71599430 --- /dev/null +++ b/docs/pages/versions/unversioned/tutorial/follow-up.md @@ -0,0 +1,69 @@ +--- +title: Learning more +--- + +We tried to set expectations early on that this tutorial is more focused towards *doing* than *explaining*. Now that the doing is done, explanations are in order. + +
+ +# Filling in the gaps on concepts that we applied + +## React + +We used React components and APIs here with little explaination. Having a solid understanding of React is essential to using Expo to build your app. We recommend reading the [Main Concepts section](https://reactjs.org/docs/hello-world.html) and the [Hooks section](https://reactjs.org/docs/hooks-intro.html) of the React documentation. + + + +### How to verify your Learning + +- You understand how to use `React.useState`, that it is a *hook*, and what the equivalent for React *class* components is. +- Add a new button to clear the selected image state. +- You can create a reusable `Button` component to clean up duplication of `TouchableOpacity` / `Text`. + +## async/await, import, and other JavaScript features + +Read about [Modern JavaScript on React Native Express](http://www.reactnativeexpress.com/modern_javascript). + +### How to verify your Learning + +- You can move part of the code from our app into a separate file, export it, and import it successfully into App.js. + +## View and Text styles + +Read through the [View API reference](https://facebook.github.io/react-native/docs/view) and [Text API reference](https://facebook.github.io/react-native/docs/text) in the React Native documentation. + +### How to verify your Learning + +- Remove all of the styles from your app and attempt to re-create them from scratch, only referring to the View and Text API reference pages when needed. + +## Flexbox + +This is the way you position and size the components on your screen. Learn more about it in [Height & Width](https://facebook.github.io/react-native/docs/height-and-width) and [Layout with Flexbox](https://facebook.github.io/react-native/docs/flexbox) in the React Native documentation. + +### How to verify your Learning + +- Remove the logo image and re-build it using just `View`, `Text`. Use the "sunrise over mountains" 🌄 emoji where needed. + +
+ +# Topics that we didn't cover and you will soon care about + +## Deployment + +How can you take what you have built and turn it into an app that you ship to the App Store and Play Store. Learn more about [distributing your app to stores](../../distribution/introduction/) and [deploying websites](../../guides/deploying-websites/). + +## Configuration with app.json + +You will want to configure your app icon, splash screen, and other things that are done in `app.json` rather than in your app code. Learn more about [app icons](../../guides/splash-screens/) and [splash screens](../../guides/app-icons/). + +## Navigation + +Most apps have multiple screens, we just have one here! Learn more about how to add navigation to your app by following the [Fundamentals guide](https://reactnavigation.org/docs/en/getting-started.html) in the React Navigation documentation. + +## Debugging + +Sometimes things go wrong, and when they do you need to use debugging tools to figure out where your code is having trouble. [Read more about debugging](../../workflow/debugging/). + +## Using the documentation + +[Read more about how you can navigate this documentation and use it effectively](../../next-steps/using-the-documentation/). \ No newline at end of file diff --git a/docs/pages/versions/unversioned/tutorial/image-picker.md b/docs/pages/versions/unversioned/tutorial/image-picker.md new file mode 100644 index 0000000000000..cb8a29ba32bbe --- /dev/null +++ b/docs/pages/versions/unversioned/tutorial/image-picker.md @@ -0,0 +1,159 @@ +--- +title: Picking an image +--- + +import SnackInline from '~/components/plugins/SnackInline'; +import Video from '../../../../components/plugins/Video' + +So far we have been using code from React and React Native in our app. React gives us a nice way to build components and React Native gives us pre-built components that work on iOS, Android, and web — like `View`, `Text`, `TouchableOpacity`. React Native does *not* provide us with an image picker. For this, we can use an Expo library called [expo-image-picker](../../sdk/imagepicker/): + +> **`expo-image-picker`** provides access to the system's UI for selecting images and videos from the phone's library or taking a photo with the camera. + + + + +## Installing expo-image-picker + +To use expo-image-picker in our project, we first need to install it. + +In your project directory, run `expo install expo-image-picker`. This will tell npm (or yarn) to install the a version of the `expo-image-picker` library that is compatible with your project. That's it! + +