-
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
445 additions
and
7 deletions.
There are no files selected for viewing
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 was deleted.
Oops, something went wrong.
110 changes: 110 additions & 0 deletions
110
docs/02-building-your-application/01-routing/01-pages-and-layouts.md
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,110 @@ | ||
--- | ||
title: Pages and Layouts | ||
description: Create your first page and shared layout with the Pages Router. | ||
--- | ||
|
||
The Pages Router has a file-system based router built on the concept of pages (like Next.js pages folder). | ||
|
||
When a file is added to the `pages` directory, it's automatically available as a route. | ||
|
||
In Brisa framework, a **page** is a [Brisa Component](/docs/components-details) exported from a `.js`, `.jsx`, `.ts`, or `.tsx` file in the `pages` directory. Each page is associated with a route based on its file name. | ||
|
||
**Example**: If you create `pages/about.js` that exports a Brisa component like below, it will be accessible at `/about`. | ||
|
||
```jsx | ||
export default function About() { | ||
return <div>About</div> | ||
} | ||
``` | ||
|
||
See the difference between React Components and Brisa Components [here](/docs/components-details). | ||
|
||
## Index routes | ||
|
||
The router will automatically route files named `index` to the root of the directory. | ||
|
||
- `pages/index.js` → `/` | ||
- `pages/blog/index.js` → `/blog` | ||
|
||
## Nested routes | ||
|
||
The router supports nested files. If you create a nested folder structure, files will automatically be routed in the same way still. | ||
|
||
- `pages/blog/first-post.js` → `/blog/first-post` | ||
- `pages/dashboard/settings/username.js` → `/dashboard/settings/username` | ||
|
||
## Pages with Dynamic Routes | ||
|
||
Brisa supports pages with dynamic routes. For example, if you create a file called `pages/posts/[id].js`, then it will be accessible at `posts/1`, `posts/2`, etc. | ||
|
||
> To learn more about dynamic routing, check the [Dynamic Routing documentation](/docs/building-your-application/routing/dynamic-routes). | ||
## Layout | ||
|
||
The global layout is defined inside `/src/layout/index`. By default Brisa supports a default layout, but you can modify it here. | ||
|
||
|
||
```jsx filename="src/layout/index.js" | ||
import { RequestContext } from "brisa"; | ||
|
||
export default function Layout({ children }: { children: JSX.Element }, { route }: RequestContext) { | ||
return ( | ||
<html> | ||
<head> | ||
<title id="title">My layout</title> | ||
<link rel="icon" href="favicon.ico" /> | ||
</head> | ||
<body> | ||
{children} | ||
</body> | ||
</html> | ||
) | ||
} | ||
``` | ||
|
||
It must have the same structure: `html`, `head` and `body`. If for example you forget to put the `head`, you may have issues and you will be alerted with an error during development. | ||
|
||
All the components of Brisa (pages and layouts included), apart from the props, receive a second argument which is the **context of the request**, apart from having access to the request, you have access to a series of extra information such as the **route** of the page. In the layouts, having access to the page route is very useful to **create different layouts**. | ||
|
||
### Example of multi-layouts | ||
|
||
```tsx filename="src/layout/index.js" | ||
import { type RequestContext } from "brisa"; | ||
import UserLayout from './user-layout' | ||
import GlobalLayout from './global-layout' | ||
|
||
export default function Layout({ children }: { children: JSX.Element }, { route }: RequestContext) { | ||
// pathname: /en/user/aralroca/settings or /es/usuario/pepe | ||
if(route.name.startsWith('/user/[username]')) { | ||
return <UserLayout>{children}<UserLayout> | ||
} | ||
|
||
return <GlobalLayout>{children}</GlobalLayout> | ||
} | ||
``` | ||
|
||
## Data Fetching | ||
|
||
Inside your layout, you can fetch data directly with `fetch`, in the same way that you can do it in pages: | ||
|
||
```jsx filename="src/layout/index.js" | ||
import { RequestContext } from "brisa"; | ||
|
||
export default async function Layout({ children }: { children: JSX.Element }, { route }: RequestContext) { | ||
const data = await fetch(/* data url */).then(r => r.json()); | ||
|
||
return ( | ||
<html> | ||
<head> | ||
<title id="title">My layout</title> | ||
<link rel="icon" href="favicon.ico" /> | ||
</head> | ||
<body> | ||
{children} | ||
</body> | ||
</html> | ||
) | ||
} | ||
``` | ||
|
||
The `fetch` is directly native and has no wrapper to control the cache. We recommend that you do not do the same `fetch` in several places, but use the [`context`](/docs/building-your-application/data-fetching/request-context) to store the data and consume it from any component. |
57 changes: 57 additions & 0 deletions
57
docs/02-building-your-application/01-routing/02-dynamic-routes.md
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,57 @@ | ||
--- | ||
title: Dynamic Routes | ||
description: Dynamic Routes are pages that allow you to add custom params to your URLs. Start creating Dynamic Routes and learn more here. | ||
--- | ||
|
||
When you don't know the exact segment names ahead of time and want to create routes from dynamic data, you can use Dynamic Segments that are filled in at request time. | ||
|
||
## Convention | ||
|
||
A Dynamic Segment can be created by wrapping a folder's name in square brackets: `[folderName]`. For example, `[id]` or `[slug]`. | ||
|
||
Dynamic Segments can be accessed from [`request context`](/docs/building-your-application/data-fetching/request-context). | ||
|
||
## Example | ||
|
||
For example, a blog could include the following route `src/pages/blog/[slug].js` where `[slug]` is the Dynamic Segment for blog posts. | ||
|
||
```jsx | ||
export default function Page(props, { route }) { | ||
return <p>Post: {route.query.slug}</p> | ||
} | ||
``` | ||
|
||
All components can access `route.query` in the same way, not just pages. | ||
|
||
| Route | Example URL | `params` | | ||
| ---------------------- | ----------- | --------------- | | ||
| `pages/blog/[slug].js` | `/blog/a` | `{ slug: 'a' }` | | ||
| `pages/blog/[slug].js` | `/blog/b` | `{ slug: 'b' }` | | ||
| `pages/blog/[slug].js` | `/blog/c` | `{ slug: 'c' }` | | ||
|
||
## Catch-all Segments | ||
|
||
Dynamic Segments can be extended to **catch-all** subsequent segments by adding an ellipsis inside the brackets `[...folderName]`. | ||
|
||
For example, `pages/shop/[...slug].js` will match `/shop/clothes`, but also `/shop/clothes/tops`, `/shop/clothes/tops/t-shirts`, and so on. | ||
|
||
| Route | Example URL | `params` | | ||
| ------------------------- | ------------- | --------------------------- | | ||
| `pages/shop/[...slug].js` | `/shop/a` | `{ slug: ['a'] }` | | ||
| `pages/shop/[...slug].js` | `/shop/a/b` | `{ slug: ['a', 'b'] }` | | ||
| `pages/shop/[...slug].js` | `/shop/a/b/c` | `{ slug: ['a', 'b', 'c'] }` | | ||
|
||
## Optional Catch-all Segments | ||
|
||
Catch-all Segments can be made **optional** by including the parameter in double square brackets: `[[...folderName]]`. | ||
|
||
For example, `pages/shop/[[...slug]].js` will **also** match `/shop`, in addition to `/shop/clothes`, `/shop/clothes/tops`, `/shop/clothes/tops/t-shirts`. | ||
|
||
The difference between **catch-all** and **optional catch-all** segments is that with optional, the route without the parameter is also matched (`/shop` in the example above). | ||
|
||
| Route | Example URL | `params` | | ||
| --------------------------- | ------------- | --------------------------- | | ||
| `pages/shop/[[...slug]].js` | `/shop` | `{}` | | ||
| `pages/shop/[[...slug]].js` | `/shop/a` | `{ slug: ['a'] }` | | ||
| `pages/shop/[[...slug]].js` | `/shop/a/b` | `{ slug: ['a', 'b'] }` | | ||
| `pages/shop/[[...slug]].js` | `/shop/a/b/c` | `{ slug: ['a', 'b', 'c'] }` | |
86 changes: 86 additions & 0 deletions
86
docs/02-building-your-application/01-routing/03-linking-and-navigating.md
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,86 @@ | ||
--- | ||
title: Linking and Navigating | ||
description: Learn how navigation works in Brisa. | ||
--- | ||
|
||
Brisa works with MPA, so we will use the native HTML navigation and you can use the `a` tag directly: | ||
|
||
```jsx | ||
export default function Home() { | ||
return ( | ||
<ul> | ||
<li> | ||
<a href="/">Home</a> | ||
</li> | ||
<li> | ||
<a href="/about">About Us</a> | ||
</li> | ||
<li> | ||
<a href="/blog/hello-world">Blog Post</a> | ||
</li> | ||
</ul> | ||
) | ||
} | ||
``` | ||
|
||
The example above uses multiple `a` tags. Each one maps a path (`href`) to a known page: | ||
|
||
- `/` → `src/pages/index.js` | ||
- `/about` → `src/pages/about.js` | ||
- `/blog/hello-world` → `src/pages/blog/[slug].js` | ||
|
||
|
||
## Navigation to dynamic paths | ||
|
||
You can also use interpolation to create the path, which comes in handy for [dynamic route segments](/docs/building-your-application/routing/dynamic-routes). For example, to show a list of posts which have been passed to the component as a prop: | ||
|
||
```jsx | ||
export default function Posts({ posts }) { | ||
return ( | ||
<ul> | ||
{posts.map((post) => ( | ||
<li> | ||
<a href={`/blog/${encodeURIComponent(post.slug)}`}> | ||
{post.title} | ||
</a> | ||
</li> | ||
))} | ||
</ul> | ||
) | ||
} | ||
``` | ||
|
||
> [`encodeURIComponent`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) is used in the example to keep the path utf-8 compatible. | ||
|
||
## I18n navigation | ||
|
||
If you have [i18n routing](/docs/routing/internationalization) enabled, during navigation you always have to forget about route translations and during the render of the page will be translated to correct translated page. | ||
|
||
```jsx | ||
export default function Home() { | ||
return <a href="/about">About Us</a> | ||
} | ||
``` | ||
|
||
In English: | ||
|
||
- `/about` → `/en/about` → `src/pages/about.js` | ||
|
||
In Spanish: | ||
|
||
- `/about` → `/es/sobre-nosotros` → `src/pages/about.js` | ||
|
||
### Navigate to another locale | ||
|
||
It is always possible to force a specific route in case you want to change the locale to another one: | ||
|
||
```jsx | ||
export default function Home() { | ||
return <a href="/es/sobre-nosotros">About Us in Spanish</a> | ||
} | ||
``` | ||
|
||
## Imperative navigation | ||
|
||
TODO |
44 changes: 44 additions & 0 deletions
44
docs/02-building-your-application/01-routing/04-custom-error.md
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,44 @@ | ||
--- | ||
title: Custom Errors | ||
description: Override and extend the built-in Error page to handle custom errors. | ||
--- | ||
|
||
## 404 Page | ||
|
||
To create a custom 404 page you can create a `src/pages/_404.js` file. | ||
|
||
```jsx filename="src/pages/_404.js" | ||
export default function Custom404() { | ||
return <h1>404 - Page Not Found</h1> | ||
} | ||
``` | ||
|
||
> **Good to know**: In this page you can access to the `request context`, `fetch` data, change the `head` content (meta tags, etc), and change the `response headers`, in the same way of the rest of pages. | ||
|
||
## 500 Page | ||
|
||
To customize the 500 page you can create a `src/pages/_500.js` file. | ||
|
||
```jsx filename="src/pages/_500.js" | ||
export default function Custom500({ error }, requestContext) { | ||
return <h1>500 - {error.message}</h1> | ||
} | ||
``` | ||
|
||
> **Good to know**: In this page you can access to the `request context`, `fetch` data, change the `head` content (meta tags, etc), and change the `response headers`, in the same way of the rest of pages. | ||
|
||
### Errors in component-level | ||
|
||
If you want to control errors at the component level instead of displaying a whole new page with the error, you can make the components have the error extension by adding the `ComponentName.error`: | ||
|
||
```jsx | ||
export default function SomeComponent() { | ||
return /* some JSX */ | ||
} | ||
|
||
SomeComponent.error = ({ error }, requestContext) => { | ||
return <p>Oops! {error.message}</p> | ||
} | ||
``` |
Oops, something went wrong.