reflex/docs/tutorial/frontend.md
2024-02-26 17:18:28 +01:00

263 lines
7.0 KiB
Markdown

```python exec
import reflex as rx
from pcweb.pages.docs import components
from pcweb.pages.docs import styling
from pcweb.pages.docs import library
import docs.tutorial.tutorial_style as style
```
# Basic Frontend
Let's start with defining the frontend for our chat app. In Reflex, the frontend can be broken down into independent, reusable components. See the [components docs]({components.props.path}) for more information.
## Display A Question And Answer
We will modify the `index` function in `chatapp/chatapp.py` file to return a component that displays a single question and answer.
```python demo box
rx.fragment(
rx.box(
"What is Reflex?",
# The user's question is on the right.
text_align="right",
),
rx.box(
"A way to build web apps in pure Python!",
# The answer is on the left.
text_align="left",
),
)
```
```python
# chatapp.py
import reflex as rx
def index() -> rx.Component:
return rx.container(
rx.box(
"What is Reflex?",
# The user's question is on the right.
text_align="right",
),
rx.box(
"A way to build web apps in pure Python!",
# The answer is on the left.
text_align="left",
),
)
# Add state and page to the app.
app = rx.App()
app.add_page(index)
```
Components can be nested inside each other to create complex layouts. Here we create a parent container that contains two boxes for the question and answer.
We also add some basic styling to the components. Components take in keyword arguments, called [props]({components.style_props.path}), that modify the appearance and functionality of the component. We use the `text_align` prop to align the text to the left and right.
## Reusing Components
Now that we have a component that displays a single question and answer, we can reuse it to display multiple questions and answers. We will move the component to a separate function `question_answer` and call it from the `index` function.
```python exec
def qa(question: str, answer: str) -> rx.Component:
return rx.box(
rx.box(question, text_align="right"),
rx.box(answer, text_align="left"),
margin_y="1em",
)
qa_pairs = [
("What is Reflex?", "A way to build web apps in pure Python!"),
(
"What can I make with it?",
"Anything from a simple website to a complex web app!",
),
]
def chat() -> rx.Component:
qa_pairs = [
("What is Reflex?", "A way to build web apps in pure Python!"),
(
"What can I make with it?",
"Anything from a simple website to a complex web app!",
),
]
return rx.box(*[qa(question, answer) for question, answer in qa_pairs])
```
```python demo box
rx.container(chat())
```
```python
def qa(question: str, answer: str) -> rx.Component:
return rx.box(
rx.box(question, text_align="right"),
rx.box(answer, text_align="left"),
margin_y="1em",
)
def chat() -> rx.Component:
qa_pairs = [
("What is Reflex?", "A way to build web apps in pure Python!"),
("What can I make with it?", "Anything from a simple website to a complex web app!"),
]
return rx.box(*[qa(question, answer) for question, answer in qa_pairs])
def index() -> rx.Component:
return rx.container(chat())
```
## Chat Input
Now we want a way for the user to input a question. For this, we will use the [input]({library.chakra.forms.input.path}) component to have the user add text and a [button]({library.forms.button.path}) component to submit the question.
```python exec
def action_bar() -> rx.Component:
return rx.hstack(
rx.chakra.input(placeholder="Ask a question"),
rx.button("Ask"),
)
```
```python demo box
rx.container(
chat(),
action_bar(),
)
```
```python
def action_bar() -> rx.Component:
return rx.hstack(
rx.chakra.input(placeholder="Ask a question"),
rx.button("Ask"),
)
def index() -> rx.Component:
return rx.container(
chat(),
action_bar(),
)
```
## Styling
Let's add some styling to the app. More information on styling can be found in the [styling docs]({styling.overview.path}). To keep our code clean, we will move the styling to a separate file `chatapp/style.py`.
```python
# style.py
# Common styles for questions and answers.
shadow = "rgba(0, 0, 0, 0.15) 0px 2px 8px"
chat_margin = "20%"
message_style = dict(
padding="1em",
border_radius="5px",
margin_y="0.5em",
box_shadow=shadow,
max_width="30em",
display="inline-block",
)
# Set specific styles for questions and answers.
question_style = message_style | dict(margin_left=chat_margin)
answer_style = message_style | dict(margin_right=chat_margin)
# Styles for the action bar.
input_style = dict(
border_width="1px", padding="1em", box_shadow=shadow
)
button_style = dict(
background_color="#CEFFEE", box_shadow=shadow
)
```
We will import the styles in `chatapp.py` and use them in the components. At this point, the app should look like this:
```python exec
def qa4(question: str, answer: str) -> rx.Component:
return rx.box(
rx.box(rx.text(question, style=style.question_style), background_color="#F5EFFE", text_align="right"),
rx.box(rx.text(answer, style=style.answer_style), background_color="#DEEAFD", text_align="left"),
margin_y="1em",
width="100%",
)
def chat4() -> rx.Component:
qa_pairs = [
("What is Reflex?", "A way to build web apps in pure Python!"),
(
"What can I make with it?",
"Anything from a simple website to a complex web app!",
),
]
return rx.box(*[qa4(question, answer) for question, answer in qa_pairs])
def action_bar4() -> rx.Component:
return rx.hstack(
rx.chakra.input(placeholder="Ask a question", style=style.input_style),
rx.button("Ask", style=style.button_style),
)
```
```python demo box
rx.container(
chat4(),
action_bar4(),
)
```
```python
# chatapp.py
import reflex as rx
from chatapp import style
def qa(question: str, answer: str) -> rx.Component:
return rx.box(
rx.box(rx.text(question, style=style.question_style), text_align="right"),
rx.box(rx.text(answer, style=style.answer_style), text_align="left"),
margin_y="1em",
)
def chat() -> rx.Component:
qa_pairs = [
("What is Reflex?", "A way to build web apps in pure Python!"),
("What can I make with it?", "Anything from a simple website to a complex web app!"),
]
return rx.box(*[qa(question, answer) for question, answer in qa_pairs])
def action_bar() -> rx.Component:
return rx.hstack(
rx.chakra.input(placeholder="Ask a question", style=style.input_style),
rx.button("Ask", style=style.button_style),
)
def index() -> rx.Component:
return rx.container(
chat(),
action_bar(),
)
app = rx.App()
app.add_page(index)
```
The app is looking good, but it's not very useful yet! In the next section, we will add some functionality to the app.