-
-
Notifications
You must be signed in to change notification settings - Fork 341
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature #1826 Introduce cookbook documentation (WebMamba)
This PR was squashed before being merged into the 2.x branch. Discussion ---------- Introduce cookbook documentation | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | Issues | | License | MIT This PR introduces a new section for the UX website: cookbook. This section aims to give more concrete documentation, show examples of common things implemented with UX components, and go deeper into some concepts that we do in the documentation. The goal is not to replace the documentation but to illustrate the documentation with concrete examples. <img width="724" alt="Capture d’écran 2024-05-04 à 17 14 24" src="https://github.com/symfony/ux/assets/32077734/25e5279e-c4d3-4f80-9534-2bbbcc91ee8a"> <img width="1438" alt="Capture d’écran 2024-05-04 à 17 15 38" src="https://github.com/symfony/ux/assets/32077734/28bd2569-2dde-4bbc-9a2e-3905a1b9ad90"> ## How it's implemented? Simply by creating a .md file in the recipes directory at the route of the project, then everything is generated automatically. There are cookbook pages that show all the recipes available, then you can click on the recipe to read it. ## Who can add recipes to the cookbook? Anyone! If you thing you implemented something a bit complex but common, just show you did it! Thank you! Tell me what you think 😁 Commits ------- 6bfa523 Introduce cookbook documentation
- Loading branch information
Showing
17 changed files
with
607 additions
and
2 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
.Cookbook { | ||
h1 { | ||
margin-top: 3rem; | ||
margin-bottom: 1rem; | ||
text-align: center; | ||
font-size: 52px; | ||
font-weight: 700; | ||
line-height: 60px; | ||
} | ||
|
||
.description { | ||
text-align: center; | ||
font-size: 24px; | ||
font-weight: 600; | ||
margin-top: 1.5rem; | ||
} | ||
|
||
.tags { | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
width: 100%; | ||
gap: 1rem; | ||
text-decoration: none; | ||
list-style: none; | ||
margin-bottom: 3rem; | ||
|
||
li { | ||
background-color: rgb(74 29 150); | ||
color: rgb(202 191 253); | ||
font-weight: 500; | ||
font-size: 0.75rem; | ||
line-height: 1rem; | ||
padding: .125rem .625rem; | ||
border-radius: 0.25rem; | ||
} | ||
} | ||
|
||
.image-title { | ||
width: 100%; | ||
max-height: 40vh; | ||
overflow: hidden; | ||
border-radius: 4px; | ||
margin-bottom: 3rem; | ||
|
||
img { | ||
display: block; | ||
object-fit: contain; | ||
width: 100%; | ||
} | ||
} | ||
|
||
.content { | ||
h2 { | ||
margin-top: 3rem; | ||
margin-bottom: 1rem; | ||
font-size: 32px; | ||
font-weight: 700; | ||
line-height: 40px; | ||
} | ||
|
||
h3 { | ||
margin-top: 3rem; | ||
margin-bottom: 1rem; | ||
font-size: 24px; | ||
font-weight: 700; | ||
line-height: 32px; | ||
color: #FFFFFF; | ||
} | ||
} | ||
|
||
pre { | ||
margin-top: 4rem; | ||
margin-bottom: 2rem; | ||
border-radius: 4px; | ||
background-color: #0A0A0A; | ||
padding: 2rem; | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
--- | ||
title: Architecture component | ||
description: Rules and pattern to work with components | ||
image: images/cookbook/component_architecture.png | ||
tags: | ||
- javascript | ||
- symfony | ||
--- | ||
|
||
## Introduction | ||
|
||
In SymfonyUX exist two packages: [TwigComponents](https://symfony.com/bundles/ux-twig-component/current/index.html) and [LiveComponent](https://symfony.com/bundles/ux-live-component/current/index.html). | ||
Those two packages allow you to create reusable components in your Symfony application. | ||
But the component architecture is not exclusive to Symfony, it is a design pattern that can be applied to any programming language or framework. | ||
And the js world already implement this architecture for long time, on many different frameworks like React, Vue, or Svelte. | ||
So, a set of rules and pattern has already be defined to work with components. This is why SymfonyUX try to be as close as possible to those rules. | ||
So let's see what are those rules! | ||
|
||
## 4 Rules | ||
|
||
### Composition | ||
|
||
A page is no longer just a page, but rather a collection of small, reusable components. | ||
These components can be assembled to form a page. For example, there could be a component for the title and another for the training list. | ||
The training list component could even be composed of smaller components, such as a training card component. | ||
The goal is to create the most atomic, and reusable components possible. | ||
|
||
#### How does it work into Symfony? | ||
|
||
In Symfony you can have a component Alert for example with the following template: | ||
|
||
```twig | ||
<div class="alert alert-{{ type }}"> | ||
<twig:Icon name="{{ icon }}" /> | ||
{{ message }} | ||
</div> | ||
``` | ||
|
||
So here you can see we have an alert component that his himself use an Icon component. | ||
Or you can make composition with the following syntax: | ||
|
||
```twig | ||
<twig:Card> | ||
<twig:CardHeader> | ||
<h2>My Card</h2> | ||
</twig:CardHeader> | ||
<twig:CardBody> | ||
<p>This is the content of my card.</p> | ||
</twig:CardBody> | ||
</twig:Card> | ||
``` | ||
|
||
So here we Card component, and we give to the content of this component mutliple other components. | ||
|
||
### Independence | ||
|
||
This is a really important rule, and not obvious. But your component should leave on his own context, | ||
he should not be aware of the rest of the page. You should to talk one component into a page, to another and it should work exactly the same. | ||
This rule make your component trully reusable. | ||
|
||
***How does it work into Symfony?*** | ||
|
||
Symfony keep the context of the page into the context of your component. So this your own responsability to follow this rules. | ||
But notice that if there are conflic between a variable from the context page and your component, your component context override the page context. | ||
|
||
### Props | ||
|
||
Our component must remain independent, but we can customize it props. | ||
Let's take the example of a button component. You have your component that look on every page the same, | ||
the only change is the label. What you can do is to declare a prop `label` into your button component. | ||
And so now when you want to use your button component, you can pass the label you want as props. The component gonna take | ||
this props at his initialization and keep it all his life long. | ||
|
||
***How does it work into Symfony?*** | ||
|
||
Let's take the example of the Alert component an [anonymous component](https://symfony.com/bundles/ux-twig-component/current/index.html#anonymous-components). | ||
We have the following template: | ||
|
||
```twig | ||
{% props type, icon, message %} | ||
<div class="alert alert-{{ type }}"> | ||
<twig:Icon name="{{ icon }}" /> | ||
{{ message }} | ||
</div> | ||
``` | ||
|
||
Just like that we define three props for our Alert component. And know we can use like this: | ||
|
||
```twig | ||
<twig:Alert type="success" icon="check" message="Your account has been created." /> | ||
``` | ||
|
||
If your component anonymous but a class component, you can simply define props | ||
by adding property to your class. | ||
|
||
```php | ||
class Alert | ||
{ | ||
public string $type; | ||
public string $icon; | ||
public string $message; | ||
} | ||
``` | ||
|
||
There are something really important to notice with props. It's your props | ||
should only go into one direction from the parent to child. But your props should never | ||
go up. **If your child need to change something in the parent, you should use events**. | ||
|
||
### State | ||
|
||
A state is pretty much like a prop but the main difference is a state can | ||
change during the life of the component. Let's take the example of a button component. | ||
You can have a state `loading` that can be `true` or `false`. When the button is clicked | ||
the state `loading` can be set to `true` and the button can display a loader instead of the label. | ||
And when the loading is done, the state `loading` can be set to `false` and the button can display the label again. | ||
|
||
***How does it work into Symfony?*** | ||
|
||
In symfony you 2 different approach to handle state. The first one is to use stimulus directly | ||
in to your component. What we recommend to do is to set a controller stimulus at the root of your component. | ||
|
||
```twig | ||
{% props label %} | ||
<button data-controller="button" data-button-label="{{ label }}"> | ||
{{ label }} | ||
</button> | ||
``` | ||
|
||
And then you can define your controller like this: | ||
|
||
```js | ||
import { Controller } from 'stimulus'; | ||
|
||
export default class extends Controller { | ||
static values = { label: String }; | ||
|
||
connect() { | ||
this.element.textContent = this.labelValue; | ||
} | ||
|
||
loading() { | ||
this.element.textContent = 'Loading...'; | ||
} | ||
} | ||
``` | ||
|
||
The second approach is to use the [LiveComponent](https://symfony.com/bundles/ux-live-component/current/index.html) package. | ||
How to choose between the two? If your component don't need any backend logic | ||
for his state keep it simple and use stimulus approach. But if you need to handle | ||
backend logic for your state, use LiveComponent. | ||
With live component a live prop is a state. So if you want store the number of click on a button you can do | ||
the following component: | ||
|
||
```php | ||
<?php | ||
|
||
#[AsLiveComponent] | ||
class Button | ||
{ | ||
#[LiveProp] | ||
public int $clicks = 0; | ||
|
||
public function increment() | ||
{ | ||
$this->clicks++; | ||
|
||
$this->save(); | ||
} | ||
} | ||
``` | ||
|
||
## Conclusion | ||
|
||
Even in Symfony, you can use the component architecture. | ||
Follow those rules help your front developpers working on codebase | ||
their are familiar with since those rules are already used in the js world. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace App\Controller; | ||
|
||
use App\Service\CookbookFactory; | ||
use App\Service\CookbookRepository; | ||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Symfony\Component\Routing\Attribute\Route; | ||
|
||
class CookbookController extends AbstractController | ||
{ | ||
public function __construct( | ||
private CookbookRepository $cookbookRepository, | ||
private CookbookFactory $cookbookFactory, | ||
) { | ||
} | ||
|
||
#[Route('/cookbook', name: 'app_cookbook_index')] | ||
public function index(): Response | ||
{ | ||
$cookbooks = $this->cookbookRepository->findAll(); | ||
|
||
return $this->render('cookbook/index.html.twig', [ | ||
'cookbooks' => $cookbooks, | ||
]); | ||
} | ||
|
||
#[Route('/cookbook/{slug}', name: 'app_cookbook_show')] | ||
public function show(string $slug): Response | ||
{ | ||
$cookbook = $this->cookbookRepository->findOneByName($slug); | ||
|
||
return $this->render('cookbook/show.html.twig', [ | ||
'slug' => $slug, | ||
'cookbook' => $cookbook, | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace App\Model; | ||
|
||
class Cookbook | ||
{ | ||
public function __construct( | ||
public string $title, | ||
public string $description, | ||
public string $route, | ||
public string $image, | ||
public string $content, | ||
/** | ||
* @var string[] | ||
*/ | ||
public array $tags = [], | ||
) { | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.