1# Hello World
2
3Let's work through the prototypical "Build a todo app" example to showcase how we might build a simple component from scratch.
4
5## Setup
6
7We'll create a headline, a list of todo items, and a form to add new items.
8
9~~~rust
10struct TodoList<V: 'static> {
11 headline: SharedString,
12 items: Vec<TodoItem>,
13 submit_form: ClickHandler<V>
14}
15
16struct TodoItem<V: 'static> {
17 text: SharedString,
18 completed: bool,
19 delete: ClickHandler<V>
20}
21
22impl<V: 'static> TodoList<V> {
23 pub fn new(
24 // Here we impl Into<SharedString>
25 headline: impl Into<SharedString>,
26 items: Vec<TodoItem>,
27 submit_form: ClickHandler<V>
28 ) -> Self {
29 Self {
30 // and here we call .into() so we can simply pass a string
31 // when creating the headline. This pattern is used throughout
32 // outr components
33 headline: headline.into(),
34 items: Vec::new(),
35 submit_form,
36 }
37 }
38}
39~~~
40
41All of this is relatively straightforward.
42
43We use [gpui::SharedString] in components instead of [std::string::String]. This allows us to [TODO: someone who actually knows please explain why we use SharedString].
44
45When we want to pass an action we pass a `ClickHandler`. Whenever we want to add an action, the struct it belongs to needs to be generic over the view type `V`.
46
47~~~rust
48use gpui::hsla
49
50impl<V: 'static> TodoList<V> {
51 // ...
52 fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
53 div().size_4().bg(hsla(50.0/360.0, 1.0, 0.5, 1.0))
54 }
55}
56~~~
57
58Every component needs a render method, and it should return `impl Element<V>`. This basic component will render a 16x16px yellow square on the screen.
59
60A couple of questions might come to mind:
61
62**Why is `size_4()` 16px, not 4px?**
63
64gpui's style system is based on conventions created by [Tailwind CSS](https://tailwindcss.com/). Here is an example of the list of sizes for `width`: [Width - TailwindCSS Docs](https://tailwindcss.com/docs/width).
65
66I'll quote from the Tailwind [Core Concepts](https://tailwindcss.com/docs/utility-first) docs here:
67
68> Now I know what you’re thinking, “this is an atrocity, what a horrible mess!”
69> and you’re right, it’s kind of ugly. In fact it’s just about impossible to
70> think this is a good idea the first time you see it —
71> you have to actually try it.
72
73As you start using the Tailwind-style conventions you will be surprised how quick it makes it to build out UIs.
74
75**Why `50.0/360.0` in `hsla()`?**
76
77gpui [gpui::Hsla] use `0.0-1.0` for all its values, but it is common for tools to use `0-360` for hue.
78
79This may change in the future, but this is a little trick that let's you use familiar looking values.
80
81## Building out the container
82
83Let's grab our [theme::colors::ThemeColors] from the theme and start building out a basic container.
84
85We can access the current theme's colors like this:
86
87~~~rust
88impl<V: 'static> TodoList<V> {
89 // ...
90 fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
91 let color = cx.theme().colors()
92
93 div().size_4().hsla(50.0/360.0, 1.0, 0.5, 1.0)
94 }
95}
96~~~
97
98Now we have access to the complete set of colors defined in the theme.
99
100~~~rust
101use gpui::hsla
102
103impl<V: 'static> TodoList<V> {
104 // ...
105 fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
106 let color = cx.theme().colors()
107
108 div().size_4().bg(color.surface)
109 }
110}
111~~~
112
113Let's finish up some basic styles for the container then move on to adding the other elements.
114
115~~~rust
116use gpui::hsla
117
118impl<V: 'static> TodoList<V> {
119 // ...
120 fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
121 let color = cx.theme().colors()
122
123 div()
124 // Flex properties
125 .flex()
126 .flex_col() // Stack elements vertically
127 .gap_2() // Add 8px of space between elements
128 // Size properties
129 .w_96() // Set width to 384px
130 .p_4() // Add 16px of padding on all sides
131 // Color properties
132 .bg(color.surface) // Set background color
133 .text_color(color.text) // Set text color
134 // Border properties
135 .rounded_md() // Add 4px of border radius
136 .border() // Add a 1px border
137 .border_color(color.border)
138 .child(
139 "Hello, world!"
140 )
141 }
142}
143~~~
144
145### Headline
146
147TODO
148
149### List of todo items
150
151TODO
152
153### Input
154
155TODO
156
157
158### End result
159
160TODO