mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-25 12:52:47 -07:00
docs: refine UI (#466)
This commit is contained in:
@@ -1,17 +1,71 @@
|
|||||||
import type { ElementType, JSX, ReactNode } from 'react'
|
import type { ElementType, JSX, MouseEventHandler, ReactNode } from 'react'
|
||||||
import { Title, type TitleProps } from '@mantine/core'
|
import { useCallback } from 'react'
|
||||||
|
import { Title, Anchor, Box } from '@mantine/core'
|
||||||
|
import type { TitleProps } from '@mantine/core'
|
||||||
|
import { IconLink } from '@tabler/icons-react'
|
||||||
|
import { useHover } from '@mantine/hooks'
|
||||||
|
|
||||||
export default function MdxTitle(props: TitleProps): JSX.Element {
|
export default function MdxTitle({
|
||||||
const headingId = getIdFrom(props.children)
|
children,
|
||||||
|
order,
|
||||||
|
...rest
|
||||||
|
}: TitleProps): JSX.Element {
|
||||||
|
const headingId = getIdFrom(children)
|
||||||
|
const { hovered, ref } = useHover<HTMLHeadingElement>()
|
||||||
|
|
||||||
|
const handleAnchorClick: MouseEventHandler<HTMLAnchorElement> = useCallback(
|
||||||
|
(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
if (ref.current) {
|
||||||
|
history.pushState(
|
||||||
|
null,
|
||||||
|
'',
|
||||||
|
`#${(ref.current.firstChild as HTMLHeadingElement).id} `,
|
||||||
|
)
|
||||||
|
ref.current.scrollIntoView({
|
||||||
|
behavior: 'instant',
|
||||||
|
block: 'start',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[ref],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Title
|
<Box
|
||||||
data-heading={headingId}
|
ref={ref}
|
||||||
data-order={props.order}
|
data-order={order}
|
||||||
style={{ scrollMargin: 70 }}
|
style={{
|
||||||
{...props}
|
scrollMargin: 80,
|
||||||
id={headingId}
|
marginTop: order === 1 ? 0 : 20,
|
||||||
/>
|
}}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
<Title
|
||||||
|
data-heading={headingId}
|
||||||
|
id={headingId}
|
||||||
|
data-order={order}
|
||||||
|
display="inline"
|
||||||
|
style={{
|
||||||
|
scrollMargin: 80,
|
||||||
|
marginTop: order === 1 ? 0 : 20,
|
||||||
|
}}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{hovered && order !== 1 && (
|
||||||
|
<Anchor
|
||||||
|
onClick={handleAnchorClick}
|
||||||
|
display="inline-flex"
|
||||||
|
ml={8}
|
||||||
|
mb={2}
|
||||||
|
style={{ alignItems: 'center', verticalAlign: 'middle' }}
|
||||||
|
>
|
||||||
|
<IconLink width={20} height={20} />
|
||||||
|
</Anchor>
|
||||||
|
)}
|
||||||
|
</Title>
|
||||||
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ export function MdxWrapper({ children }: MdxWrapperProps): JSX.Element {
|
|||||||
id="mdx-root"
|
id="mdx-root"
|
||||||
component="article"
|
component="article"
|
||||||
mt="xl"
|
mt="xl"
|
||||||
px={16}
|
|
||||||
py={36}
|
py={36}
|
||||||
className={classes.wrapper}
|
className={classes.wrapper}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ export const sidebarElements: Array<SidebarElement> = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
type: 'element',
|
type: 'element',
|
||||||
label: 'Defining routes',
|
label: 'Pages and layout',
|
||||||
href: '/documentation/routing/defining-routes',
|
href: '/documentation/routing/defining-routes',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -121,26 +121,6 @@ export const sidebarElements: Array<SidebarElement> = [
|
|||||||
label: 'Link and navigation',
|
label: 'Link and navigation',
|
||||||
href: '/documentation/routing/link-and-navigation',
|
href: '/documentation/routing/link-and-navigation',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
type: 'element',
|
|
||||||
label: 'Pages',
|
|
||||||
href: '/documentation/routing/pages',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'element',
|
|
||||||
label: 'Loading state',
|
|
||||||
href: '/documentation/routing/loading-state',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'element',
|
|
||||||
label: 'Layouts',
|
|
||||||
href: '/documentation/routing/layouts',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'element',
|
|
||||||
label: 'Redirecting',
|
|
||||||
href: '/documentation/routing/redirecting',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ export function TableOfContents(): JSX.Element | null {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const element = document.getElementById(id)
|
const element = document.getElementById(id)
|
||||||
if (element) {
|
if (element) {
|
||||||
|
history.pushState(null, '', `#${element.id} `)
|
||||||
|
|
||||||
element.scrollIntoView({
|
element.scrollIntoView({
|
||||||
behavior: 'instant',
|
behavior: 'instant',
|
||||||
block: 'start',
|
block: 'start',
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Application state
|
# Application state
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
The main reason Tuono is fast is that it loads just the features that are needed for the project.
|
The main reason Tuono is fast is that it loads just the features that are needed for the project.
|
||||||
|
|
||||||
To define them, you need to fill the `ApplicationState` struct in the `./src/app.rs` file, and
|
To define them, you need to fill the `ApplicationState` struct in the `./src/app.rs` file, and
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# CLI
|
# CLI
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
Tuono is the CLI that provides all the needed commands to handle the full-stack project.
|
Tuono is the CLI that provides all the needed commands to handle the full-stack project.
|
||||||
|
|
||||||
> ☝️ Check the [installation](/documentation/installation) page if you haven't installed the
|
> ☝️ Check the [installation](/documentation/installation) page if you haven't installed the
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Link
|
# Link
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
Tuono provides a `Link` component for clientside navigation between pages of your app. `Link` prefetches pages from any links above the fold, allowing for faster navigations without a full reload.
|
Tuono provides a `Link` component for clientside navigation between pages of your app. `Link` prefetches pages from any links above the fold, allowing for faster navigations without a full reload.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
Tuono can be configured using the `tuono.config.ts` file,
|
Tuono can be configured using the `tuono.config.ts` file,
|
||||||
which allows you to customize various aspects of the build process and development environment.
|
which allows you to customize various aspects of the build process and development environment.
|
||||||
|
|
||||||
@@ -34,7 +36,7 @@ Tuono leverages Vite, a modern and fast build tool and development server for we
|
|||||||
|
|
||||||
As a result, **some** Vite configuration properties can be set in the `tuono.config.ts` file under the `vite` property.
|
As a result, **some** Vite configuration properties can be set in the `tuono.config.ts` file under the `vite` property.
|
||||||
|
|
||||||
### vite.alias
|
### `vite.alias`
|
||||||
|
|
||||||
Useful for configuring custom source alias paths during imports
|
Useful for configuring custom source alias paths during imports
|
||||||
|
|
||||||
@@ -43,13 +45,13 @@ Useful for configuring custom source alias paths during imports
|
|||||||
- `Array<{ find: string | RegExp, replacement: string, customResolver?: ResolverFunction | ResolverObject }>`
|
- `Array<{ find: string | RegExp, replacement: string, customResolver?: ResolverFunction | ResolverObject }>`
|
||||||
- [Vite documentation: resolve.alias](https://vite.dev/config/shared-options#resolve-alias)
|
- [Vite documentation: resolve.alias](https://vite.dev/config/shared-options#resolve-alias)
|
||||||
|
|
||||||
### vite.optimizeDeps
|
### `vite.optimizeDeps`
|
||||||
|
|
||||||
Vite's dependency optimizer used only during dev
|
Vite's dependency optimizer used only during dev
|
||||||
|
|
||||||
- [Vite documentation: Dep Optimization Options](https://vite.dev/config/dep-optimization-options)
|
- [Vite documentation: Dep Optimization Options](https://vite.dev/config/dep-optimization-options)
|
||||||
|
|
||||||
### vite.plugins
|
### `vite.plugins`
|
||||||
|
|
||||||
Useful for extending vite's functionality
|
Useful for extending vite's functionality
|
||||||
|
|
||||||
@@ -60,7 +62,7 @@ Useful for extending vite's functionality
|
|||||||
|
|
||||||
The following options configure the server.
|
The following options configure the server.
|
||||||
|
|
||||||
## server.host
|
### server.host
|
||||||
|
|
||||||
- Type: `string`
|
- Type: `string`
|
||||||
- Default: `'localhost'`
|
- Default: `'localhost'`
|
||||||
@@ -68,7 +70,7 @@ The following options configure the server.
|
|||||||
The hostname or IP address of the server.
|
The hostname or IP address of the server.
|
||||||
It can be a domain name (e.g., `"example.com"`) or an IP address (e.g., `"127.0.0.1"`)
|
It can be a domain name (e.g., `"example.com"`) or an IP address (e.g., `"127.0.0.1"`)
|
||||||
|
|
||||||
## server.port
|
### `server.port`
|
||||||
|
|
||||||
- Type: `number`
|
- Type: `number`
|
||||||
- Default: `3000`
|
- Default: `3000`
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Pull Requests
|
# Pull Requests
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
Once your changes are ready, you can create a PR!
|
Once your changes are ready, you can create a PR!
|
||||||
|
|
||||||
If you are not familiar with GitHub pull requests,
|
If you are not familiar with GitHub pull requests,
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# useRouter
|
# useRouter
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
The `useRouter` hook provides access to various data about the current route, as well as methods to navigate between pages, as seen in the below example:
|
The `useRouter` hook provides access to various data about the current route, as well as methods to navigate between pages, as seen in the below example:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ languages. Since then, you need the following tools installed on your computer t
|
|||||||
|
|
||||||
> Node.js is needed just for the development environment. The final output will run on a Rust server.
|
> Node.js is needed just for the development environment. The final output will run on a Rust server.
|
||||||
|
|
||||||
## Installation
|
## How to install
|
||||||
|
|
||||||
The tuono `CLI` is hosted on [crates.io](https://crates.io/crates/tuono) to download and install it, just run it on a terminal:
|
The tuono `CLI` is hosted on [crates.io](https://crates.io/crates/tuono) to download and install it, just run it on a terminal:
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
<Breadcrumbs breadcrumbs={[{ label: 'Defining routes' }]} />
|
<Breadcrumbs breadcrumbs={[{ label: 'Defining routes' }]} />
|
||||||
|
|
||||||
# Defining routes
|
# Pages and layouts
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
Tuono has a file-system based router built on the concept of routes.
|
Tuono has a file-system based router built on the concept of routes.
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import MetaTags from '@/components/MetaTags'
|
|
||||||
|
|
||||||
<MetaTags
|
|
||||||
title="Tuono - Routing"
|
|
||||||
canonical="https://tuono.dev/documentation/routing/layouts"
|
|
||||||
/>
|
|
||||||
|
|
||||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
|
||||||
|
|
||||||
<Breadcrumbs breadcrumbs={[{ label: 'Layouts' }]} />
|
|
||||||
|
|
||||||
# Layouts
|
|
||||||
|
|
||||||
Todo
|
|
||||||
@@ -11,6 +11,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Link and navigation
|
# Link and navigation
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
The Tuono router facilitates client-side route transitions between pages, enhancing the user experience by:
|
The Tuono router facilitates client-side route transitions between pages, enhancing the user experience by:
|
||||||
|
|
||||||
- Enabling smooth navigation in single-page applications (SPAs)
|
- Enabling smooth navigation in single-page applications (SPAs)
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import MetaTags from '@/components/MetaTags'
|
|
||||||
|
|
||||||
<MetaTags
|
|
||||||
title="Tuono - Routing"
|
|
||||||
canonical="https://tuono.dev/documentation/routing/loading-state"
|
|
||||||
/>
|
|
||||||
|
|
||||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
|
||||||
|
|
||||||
<Breadcrumbs breadcrumbs={[{ label: 'Loading state' }]} />
|
|
||||||
|
|
||||||
# Loading state
|
|
||||||
|
|
||||||
Todo
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import MetaTags from '@/components/MetaTags'
|
|
||||||
|
|
||||||
<MetaTags
|
|
||||||
title="Tuono - Routing"
|
|
||||||
canonical="https://tuono.dev/documentation/routing/pages"
|
|
||||||
/>
|
|
||||||
|
|
||||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
|
||||||
|
|
||||||
<Breadcrumbs breadcrumbs={[{ label: 'Pages' }]} />
|
|
||||||
|
|
||||||
# Pages
|
|
||||||
|
|
||||||
Todo
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import MetaTags from '@/components/MetaTags'
|
|
||||||
|
|
||||||
<MetaTags
|
|
||||||
title="Tuono - Routing"
|
|
||||||
canonical="https://tuono.dev/documentation/routing/redirecting"
|
|
||||||
/>
|
|
||||||
|
|
||||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
|
||||||
|
|
||||||
<Breadcrumbs breadcrumbs={[{ label: 'Redirecting' }]} />
|
|
||||||
|
|
||||||
# Redirecting
|
|
||||||
|
|
||||||
Todo
|
|
||||||
@@ -11,6 +11,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Tailwind CSS
|
# Tailwind CSS
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
[Tailwind CSS](https://tailwindcss.com) is a popular utility-first CSS framework.
|
[Tailwind CSS](https://tailwindcss.com) is a popular utility-first CSS framework.
|
||||||
Tuono support begins with Tailwind CSS v4.
|
Tuono support begins with Tailwind CSS v4.
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ Now that the link is done, let’s import it into the `index.tsx` file
|
|||||||
Now the links work. Clicking on any of them, we get redirected to the 404 page because we haven’t yet implemented the `pokemons/[pokemon]` page.
|
Now the links work. Clicking on any of them, we get redirected to the 404 page because we haven’t yet implemented the `pokemons/[pokemon]` page.
|
||||||
As previously said, CSS modules are enabled out of the box, so let’s make those links a little bit nicer.
|
As previously said, CSS modules are enabled out of the box, so let’s make those links a little bit nicer.
|
||||||
|
|
||||||
|
## Styling the component
|
||||||
|
|
||||||
Create alongside the `PokemonLink.tsx` component the CSS module `PokemonLink.module.css` and copy the following content into it:
|
Create alongside the `PokemonLink.tsx` component the CSS module `PokemonLink.module.css` and copy the following content into it:
|
||||||
|
|
||||||
```css
|
```css
|
||||||
|
|||||||
@@ -17,13 +17,16 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Conclusion
|
# Conclusion
|
||||||
|
|
||||||
|
## What a tutorial :)
|
||||||
|
|
||||||
That’s it! You just created a multi thread full stack application with Rust and React.
|
That’s it! You just created a multi thread full stack application with Rust and React.
|
||||||
|
|
||||||
The project is still under heavy development and many features are not ready yet, but
|
The project is still under heavy development and many features are not ready yet, but
|
||||||
I hope you got the taste of what is like working with rust and react in the same stack.
|
I hope you got the taste of what is like working with rust and react in the same stack.
|
||||||
|
|
||||||
As I mentioned in the introduction, I'd love to hear what you thought about the framework and the tutorial - feel free to reach me
|
As I mentioned in the introduction, I'd love to hear what you thought about the
|
||||||
at [valerioageno@yahoo.it](mailto:valerioageno@yahoo.it) or in Twitter (X) DMs [@valerioageno](https://twitter.com/valerioageno).
|
framework and the tutorial - feel free to join the [official discord server](https://discord.com/invite/khQzPa654B)
|
||||||
|
or to reach me on Twitter (X) [@valerioageno](https://twitter.com/valerioageno).
|
||||||
|
|
||||||
Ciao
|
Ciao
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Error handling
|
# Error handling
|
||||||
|
|
||||||
|
## Return a 404 Error
|
||||||
|
|
||||||
With the current setup, all the routes always return a `200 Success` HTTP status, no matter the response type.
|
With the current setup, all the routes always return a `200 Success` HTTP status, no matter the response type.
|
||||||
|
|
||||||
In order to return a more meaningful status code to the browser, the `Props` struct can also be initialized with the
|
In order to return a more meaningful status code to the browser, the `Props` struct can also be initialized with the
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Tutorial
|
# Tutorial
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
This tutorial is meant to give you a sneak peek at the framework and is intended to evolve during the
|
This tutorial is meant to give you a sneak peek at the framework and is intended to evolve during the
|
||||||
development - be sure to have [installed](/documentation/installation) the [latest version](https://crates.io/crates/tuono).
|
development - be sure to have [installed](/documentation/installation) the [latest version](https://crates.io/crates/tuono).
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Production build
|
# Production build
|
||||||
|
|
||||||
|
## Building the production assets
|
||||||
|
|
||||||
The source is now ready to be released. Both server and client have been managed in an unoptimized way
|
The source is now ready to be released. Both server and client have been managed in an unoptimized way
|
||||||
to ease the development experience. To build the project to the production state, just run:
|
to ease the development experience. To build the project to the production state, just run:
|
||||||
|
|
||||||
@@ -24,7 +26,9 @@ to ease the development experience. To build the project to the production state
|
|||||||
tuono build
|
tuono build
|
||||||
```
|
```
|
||||||
|
|
||||||
This command just created the final assets within the `out` directory. To run the production server,
|
## Running the production server
|
||||||
|
|
||||||
|
The above command just created the final assets within the `out` directory. To run the production server,
|
||||||
run:
|
run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Redirections
|
# Redirections
|
||||||
|
|
||||||
|
## Redirecting to a different page
|
||||||
|
|
||||||
What if there is a Pokémon among all of them that should be considered the GOAT? What
|
What if there is a Pokémon among all of them that should be considered the GOAT? What
|
||||||
we are going to do right now is creating a new route `/pokemons/GOAT` that points to the best
|
we are going to do right now is creating a new route `/pokemons/GOAT` that points to the best
|
||||||
Pokémon of the first generation.
|
Pokémon of the first generation.
|
||||||
|
|||||||
@@ -17,12 +17,13 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# SEO and meta tags
|
# SEO and meta tags
|
||||||
|
|
||||||
|
## Adding the page title
|
||||||
|
|
||||||
The website now works and the HTTP errors are meaningful, but we should also take care to be meaningful
|
The website now works and the HTTP errors are meaningful, but we should also take care to be meaningful
|
||||||
for the web crawlers. The best way to do it is to enrich the meta tags like the `<title>` and the
|
for the web crawlers. The best way to do it is to enrich the meta tags like the `<title>` and the
|
||||||
`<description>`.
|
`<description>`.
|
||||||
|
|
||||||
To do so `tuono` fully supports [React19
|
To do so `tuono` fully supports the [React19 components](https://react.dev/reference/react-dom/components/title). Let's update the `/` and the
|
||||||
tags](https://react.dev/reference/react-dom/components/title). Let's update the `/` and the
|
|
||||||
`/pokemons/[pokemon]` routes with this.
|
`/pokemons/[pokemon]` routes with this.
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import Breadcrumbs from '@/components/Breadcrumbs'
|
|||||||
|
|
||||||
# Tuono
|
# Tuono
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
Tuono is a full-stack web framework for building React applications using Rust as the
|
Tuono is a full-stack web framework for building React applications using Rust as the
|
||||||
backend with a strong focus on usability and performance.
|
backend with a strong focus on usability and performance.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user