Skip to content

Commit

Permalink
[docs] First pass at tutorial (#6769)
Browse files Browse the repository at this point in the history
  • Loading branch information
brentvatne authored and EvanBacon committed Feb 13, 2020
1 parent fbbb3fe commit c5ff7e9
Show file tree
Hide file tree
Showing 45 changed files with 2,339 additions and 25 deletions.
1 change: 1 addition & 0 deletions docs/common/navigation-data.js
Expand Up @@ -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',
Expand Down
16 changes: 15 additions & 1 deletion docs/common/navigation.js
Expand Up @@ -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'],
Expand All @@ -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'],
Expand Down Expand Up @@ -235,6 +248,7 @@ const sections = [
const ROOT = [
'Introduction',
'Get Started',
'Tutorial',
'Fundamentals',
'Guides',
'Distributing Your App',
Expand Down
9 changes: 6 additions & 3 deletions 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';
Expand All @@ -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 {
Expand Down Expand Up @@ -129,4 +130,6 @@ export class Code extends React.Component {
}
}

export const InlineCode = ({ children }) => <code className={`${STYLES_INLINE_CODE} inline`}>{children}</code>;
export const InlineCode = ({ children }) => (
<code className={`${STYLES_INLINE_CODE} inline`}>{children}</code>
);
9 changes: 1 addition & 8 deletions docs/components/icons/BrandLogo.js
Expand Up @@ -3,13 +3,6 @@ import * as React from 'react';
// TODO(jim): Figure out why this was wrapped in a span.
export default () => (
<span>
<svg height="16px" viewBox="0 0 29 25" version="1.1" xmlns="http://www.w3.org/2000/svg">
<title>Expo</title>
<g stroke="none" strokeWidth="1" fill="rgba(0, 0, 32, 1)" fillRule="evenodd">
<g transform="translate(-41.000000, -52.000000)">
<path d="M58.7621343,53.7835977 C57.7033988,52.2084242 57.462144,52.0030749 55.3171951,52.0001337 L55.3171951,52 C55.3090975,52 55.3016207,52.0000535 55.2935771,52.0000535 C55.2855335,52.0000535 55.2780567,52 55.2699591,52 L55.2699591,52.0001337 C53.1249832,52.0030749 52.8837284,52.2084242 51.8250199,53.7835977 C50.8346552,55.2570591 41,72.9589169 41,73.4493488 C41,74.1697024 41.1886473,74.8447882 41.867416,75.806347 C42.5569544,76.7829861 43.7434432,77.3194611 44.6087268,76.4585181 C45.1926995,75.8774973 51.5074316,65.2012591 54.5506484,61.1556908 C54.9160935,60.6561947 55.6710337,60.6561947 56.0364788,61.1556908 C59.0796956,65.2012591 65.3944547,75.8774973 65.9784273,76.4585181 C66.8436839,77.3194611 68.0301997,76.7829861 68.7197112,75.806347 C69.3985069,74.8447882 69.5871542,74.1697024 69.5871542,73.4493488 C69.5871542,72.9589169 59.752472,55.2570591 58.7621343,53.7835977" />
</g>
</g>
</svg>
<img src="/static/images/header-logo.png" alt="Expo" style={{ width: 27, height: 29 }} />
</span>
);
11 changes: 11 additions & 0 deletions 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 }) => <span className={`${STYLES_HIGHLIGHT}`}>{children}</span>;

export default Highlight;
10 changes: 7 additions & 3 deletions docs/components/plugins/SnackInline.js
Expand Up @@ -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())}`;
Expand Down Expand Up @@ -99,8 +99,12 @@ export default class SnackInline extends React.Component {
<div ref={this.contentRef}>{this.props.children}</div>

{/* TODO: this should be a POST request, need to change Snack to support it though */}
<form ref={this.formRef} action="https://snack.expo.io" method="GET" target="_blank">
<input type="hidden" name="platform" value={DEFAULT_PLATFORM} />
<form ref={this.formRef} action="https://snack.expo.io" method="POST" target="_blank">
<input
type="hidden"
name="platform"
value={this.props.defaultPlatform || DEFAULT_PLATFORM}
/>
<input type="hidden" name="name" value={this.props.label || 'Example'} />
<input type="hidden" name="dependencies" value={this._getDependencies()} />
<input type="hidden" name="code" value={this._getCode()} />
Expand Down
4 changes: 4 additions & 0 deletions docs/global-styles/tippy.js
Expand Up @@ -21,4 +21,8 @@ export const globalTippy = `
color: ${Constants.colors.white};
font-family: ${Constants.fonts.book};
}
.tippy-content a {
color: #eee;
}
`;
Expand Up @@ -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.
- **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.
4 changes: 1 addition & 3 deletions docs/pages/versions/unversioned/introduction/why-not-expo.md
Expand Up @@ -3,9 +3,7 @@ title: Limitations
sidebar_title: Limitations
---

> *Your success will be limited if you don't know the limitations of your tools.*
>
> &mdash; *Confucius <small>(but not really)</small>*
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

Expand Down
27 changes: 27 additions & 0 deletions docs/pages/versions/unversioned/sdk/sharing.md
Expand Up @@ -15,6 +15,18 @@ import Video from '../../../../components/plugins/Video'
| -------------- | ---------------- | ---------- | ------------- | --- |
||||||

<br />

> 🚨 **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()`.
<br/>

> 💡 **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.
<br/>

> ⚠️ **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 &mdash; 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).
Expand All @@ -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.
Expand Down
126 changes: 126 additions & 0 deletions 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.

<SnackInline label="Simple button">

```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 (
<View style={styles.container}>
<Image source={{ uri: 'https://i.imgur.com/TkIrScD.png' }} style={styles.logo} />
<Text style={styles.instructions}>
To share a photo from your phone with a friend, just press the button below!
</Text>

/* @info onPress takes a function that should be called when the button is pressed */
<TouchableOpacity
onPress={() => alert('Hello, world!')}
style={{ backgroundColor: 'blue' }}>
<Text style={{ fontSize: 20, color: '#fff' }}>Pick a photo</Text>
</TouchableOpacity>/* @end */

</View>
);
}

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,
},
});
```

</SnackInline>

<br />

Give it a try! Notice that when you press on the button it fades a little bit &mdash; 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 &mdash; 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.

<SnackInline label="Simple button">

```jsx
import React from 'react';
import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native';

export default function App() {
return (
<View style={styles.container}>
<Image source={{ uri: 'https://i.imgur.com/TkIrScD.png' }} style={styles.logo} />
<Text style={styles.instructions}>
To share a photo from your phone with a friend, just press the button below!
</Text>

<TouchableOpacity onPress={() => alert('Hello, world!')} /* @info We moved our our style down to the StyleSheet, keep scrolling! */ style={styles.button}/* @end */>
<Text /* @info See StyleSheet */style={styles.buttonText}/* @end */>Pick a photo</Text>
</TouchableOpacity>
</View>
);
}

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 */

});
```

</SnackInline>

<br />

> 📜 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/).
69 changes: 69 additions & 0 deletions 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.

<br />

# 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.

<!-- TODO: replace this recommendation with the react-native tutorial when it's live -->

### 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.

<br />

# 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/).

0 comments on commit c5ff7e9

Please sign in to comment.