mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-27 13:52:47 -07:00
Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d33c211a01 | |||
| 21ee89ada4 | |||
| dcedb1c6c0 | |||
| d5cc65983e | |||
| 3cb150b090 | |||
| 305ae59086 | |||
| 8fe8930def | |||
| 8730bdbfb9 | |||
| 3ee47e9481 | |||
| 4e649acd60 | |||
| 4768d70a8a | |||
| c7bff7ed09 | |||
| 3035d2a645 | |||
| 0750037385 | |||
| 8c4d61ee65 | |||
| 1a3ccb112e | |||
| 118172d27f | |||
| 69f1d85360 | |||
| f0d042c85b | |||
| 550830c232 | |||
| 6be12b4e58 | |||
| 33aa37ed7d | |||
| 43910fd75d | |||
| 5efcc86a63 | |||
| 17b61a5a41 | |||
| 5dae5c31b7 | |||
| 96deea7f31 | |||
| 7632e6a464 | |||
| 23e2a2e3ff | |||
| b19512dffc | |||
| 11c6fc820b | |||
| 1a8231851d | |||
| 1dfb83b1aa | |||
| 93cb1ae8ba | |||
| 631b168e05 | |||
| af8a43c93a | |||
| 875d12f514 | |||
| a9a2ef67ea | |||
| 5caf3ed6e7 | |||
| 580ec704f2 | |||
| a9918ae555 | |||
| 4b3f4bfab8 | |||
| fed3b1581b | |||
| 9b2f0aab32 | |||
| 818a6bd2ff | |||
| 94a43347a1 | |||
| 16d793c588 | |||
| 0322e5bd8d | |||
| cfe76a9ab3 | |||
| ff6014317b | |||
| 64220f2e27 | |||
| e75414abfc | |||
| d6fae42dc3 | |||
| 0db1245a6b | |||
| 91c0a9ec31 | |||
| 7670c37685 | |||
| ae41c5629c | |||
| 3e7fa05fce | |||
| 6833640c47 | |||
| 18541c45de | |||
| 45bb0dd0d2 | |||
| db0aad2c37 | |||
| d55ca12125 | |||
| ad2cada94b | |||
| f9545f513b | |||
| c75d83dc7c | |||
| 91236e5533 | |||
| 1356be248e | |||
| 7e8be92cd5 | |||
| c3fda4a3a5 | |||
| dfc66cfd50 | |||
| 0ef1252e1f | |||
| cf56b3a53e | |||
| 592f402ffd | |||
| 1dc77fc473 | |||
| 09cd772d74 | |||
| 1c69e10e6a | |||
| 1af18e4c91 | |||
| a3709609c5 | |||
| 70a79faee0 | |||
| 07cb7dae9d | |||
| 9a1fb9c4a1 | |||
| a3f7ed7f61 | |||
| 5302fd2779 | |||
| ccd4e02b6a | |||
| f6593097b6 | |||
| 230cd22bff | |||
| f4367f1755 | |||
| 7b7447f9a0 | |||
| d12d8404ec | |||
| d1b12173d5 | |||
| f3bf13da59 | |||
| f236b75f55 | |||
| 2434231f9b | |||
| b8b39e69a1 | |||
| f8158dfd8e | |||
| f1ab7df5ce | |||
| 986de49052 | |||
| d09ca5548a | |||
| 77e22c40b6 | |||
| de74647c43 | |||
| 498601c21a | |||
| e99f06ddf5 | |||
| f06af59168 | |||
| d50e3a7fc0 | |||
| 3e4e7ff1ab | |||
| 21ff3c8655 | |||
| 166e61bab4 | |||
| 93cd8bd8da | |||
| f5c1641af2 | |||
| 62ffed0624 | |||
| 8d0a4a7417 | |||
| b1b274ea12 | |||
| fc38865965 | |||
| 911adaaecb | |||
| 7626ed8d1d | |||
| 6135fd7e1b | |||
| 14bea36356 |
@@ -0,0 +1,7 @@
|
||||
[*]
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
max_line_length = 80
|
||||
@@ -32,55 +32,24 @@ body:
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: tuono-version
|
||||
- type: textarea
|
||||
id: system-info
|
||||
attributes:
|
||||
label: Tuono version
|
||||
placeholder: '[e.g. 0.4.0]'
|
||||
label: System Info
|
||||
description: Output of `npx envinfo --system --npmPackages 'tuono' --binaries --browsers`
|
||||
render: shell
|
||||
placeholder: System, Binaries, Browsers
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: os-version
|
||||
required: true
|
||||
- type: textarea
|
||||
id: system-info-rust
|
||||
attributes:
|
||||
label: OS
|
||||
placeholder: '[e.g. MacOS, Windows]'
|
||||
label: System info (Rust)
|
||||
description: Output of `rustc --version && cargo --version && tuono --version`
|
||||
render: shell
|
||||
placeholder: 'rustc, cargo and tuono binary version'
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: browser-version
|
||||
attributes:
|
||||
label: Browser
|
||||
placeholder: '[e.g. chrome, safari]'
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: node-version
|
||||
attributes:
|
||||
label: Node version
|
||||
placeholder: '[e.g. 20.0.0]'
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: rust-version
|
||||
attributes:
|
||||
label: Rust version
|
||||
placeholder: '[e.g. 1.79.0]'
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: create-version
|
||||
attributes:
|
||||
label: Crate version
|
||||
placeholder: '[e.g. 1.78.0]'
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: node-package-manager-version
|
||||
attributes:
|
||||
label: Node Package Manger version
|
||||
placeholder: '[e.g. pnpm: 9.5.0] '
|
||||
validations:
|
||||
required: false
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# @see https://github.com/actions/labeler
|
||||
|
||||
rust:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['crates/**', 'Cargo.toml']
|
||||
|
||||
typescript:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
[
|
||||
'packages/**',
|
||||
'package.json',
|
||||
'pnpm-*.yaml',
|
||||
'eslint.config.js',
|
||||
'tsconfig.json',
|
||||
]
|
||||
|
||||
documentation:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['apps/documentation/**']
|
||||
|
||||
'CI/CD':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['.github/**']
|
||||
|
||||
'repo maintenance':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
[
|
||||
'.npmrc',
|
||||
'.nvmrc',
|
||||
'.prettierrc',
|
||||
'.prettierignore',
|
||||
'renovate.json',
|
||||
'turbo.json',
|
||||
]
|
||||
@@ -3,11 +3,12 @@
|
||||
<!--
|
||||
Thank you for your Pull Request.
|
||||
|
||||
Explain the context and why you're making that change. What is the problem
|
||||
you're trying to solve? If a new feature is being added, describe the intended
|
||||
use case that feature fulfills.
|
||||
Explain the context and why you're making that change.
|
||||
What is the problem you're trying to solve?
|
||||
If a new feature is being added,
|
||||
describe the intended use case that feature fulfills.
|
||||
|
||||
Bug fixes and new features should include tests.
|
||||
|
||||
Contributors guide: https://github.com/Valerioageno/tuono/blob/main/CONTRIBUTING.md
|
||||
PR guide: https://tuono.dev/documentation/contributing/pull-requests
|
||||
-->
|
||||
|
||||
@@ -4,20 +4,20 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
# match
|
||||
# - all files inside `apps/documentation` and `.github`
|
||||
# - all files in the root expect `Cargo.toml`
|
||||
paths:
|
||||
# ⬇ Keep paths in sync with `typescript.yml`
|
||||
- '.github/**'
|
||||
- '*'
|
||||
- '!Cargo.toml'
|
||||
# ⬆ Keep paths in sync with `typescript.yml`
|
||||
- 'apps/documentation/**'
|
||||
pull_request:
|
||||
# same as `on.push.paths`
|
||||
paths:
|
||||
# ⬇ Keep paths in sync with `typescript.yml`
|
||||
- '.github/**'
|
||||
- '*'
|
||||
- '!Cargo.toml'
|
||||
# ⬆ Keep paths in sync with `typescript.yml`
|
||||
- 'apps/documentation/**'
|
||||
|
||||
jobs:
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- name: Install tuono
|
||||
run: cargo install tuono@0.15.0
|
||||
run: cargo install tuono@0.17.3
|
||||
|
||||
- name: Build project
|
||||
working-directory: ./apps/documentation
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- name: Install tuono
|
||||
run: cargo install tuono@0.16.0
|
||||
run: cargo install tuono@0.17.3
|
||||
|
||||
- name: Build project
|
||||
working-directory: ./apps/documentation
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
name: 'PR Labeler'
|
||||
|
||||
# @see https://github.com/actions/labeler
|
||||
# @see .github/labeler.yml
|
||||
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
name: 'Manage labels'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
# Add checkout step to load labeler.yml locally,
|
||||
# rather than from an API request
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
sync-labels: true
|
||||
@@ -0,0 +1,61 @@
|
||||
name: 'PR Title Checker'
|
||||
|
||||
# This workflow ensures that PR titles adhere to a pattern
|
||||
# similar to conventional commits standard
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
- labeled
|
||||
- unlabeled
|
||||
|
||||
env:
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
|
||||
jobs:
|
||||
check_pr_title:
|
||||
name: 'PR Title Checker'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check type
|
||||
id: type
|
||||
# @warning Keep in sync with apps/documentation/src/routes/documentation/contributing/pull-requests.mdx
|
||||
run: |
|
||||
VALID_COMMIT_TYPES="chore|ci|docs|feat|fix|refactor|test"
|
||||
REGEX="^${VALID_COMMIT_TYPES})(\(.*\))?!?: .*"
|
||||
|
||||
if ! [[ $PR_TITLE =~ $REGEX ]]; then
|
||||
echo "::error title=Type::The title has an incorrect type. Valid types are ${VALID_COMMIT_TYPES}"
|
||||
echo "result=fail" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "::notice title=Type::The title is using a valid type"
|
||||
echo "result=ok" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Check length
|
||||
id: length
|
||||
run: |
|
||||
MAX_LENGTH=100
|
||||
LENGTH=${#PR_TITLE}
|
||||
|
||||
if [ $LENGTH -gt $MAX_LENGTH ]; then
|
||||
echo "::error title=Length::The title is longer than $MAX_LENGTH characters"
|
||||
echo "result=fail" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "::notice title=Length::The title length is within the maximum value of $MAX_LENGTH characters"
|
||||
echo "result=ok" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Check result
|
||||
env:
|
||||
FAILURE: ${{ contains(join(steps.*.outputs.result, ','), 'fail') }}
|
||||
run: |
|
||||
echo "Failure: $FAILURE"
|
||||
if [ "$FAILURE" = "false" ]; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
@@ -8,16 +8,10 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
paths:
|
||||
- '.github/**'
|
||||
- '*'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/**'
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
format:
|
||||
name: Check format
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
@@ -31,3 +25,23 @@ jobs:
|
||||
|
||||
- name: Test project
|
||||
run: pnpm repo:root:format:check
|
||||
|
||||
ci_ok:
|
||||
name: Repo root CI OK
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 1
|
||||
if: always()
|
||||
needs: [format]
|
||||
env:
|
||||
FAILURE: ${{ contains(join(needs.*.result, ','), 'failure') }}
|
||||
CANCELLED: ${{ contains(join(needs.*.result, ','), 'cancelled') }}
|
||||
steps:
|
||||
- name: Check for failure or cancelled jobs result
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Failure: $FAILURE - Cancelled: $CANCELLED"
|
||||
if [ "$FAILURE" = "false" ] && [ "$CANCELLED" = "false" ]; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -4,15 +4,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
paths:
|
||||
- '.github/**'
|
||||
- 'Cargo.toml'
|
||||
- 'crates/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/**'
|
||||
- 'Cargo.toml'
|
||||
- 'crates/**'
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -40,6 +32,7 @@ jobs:
|
||||
os: 'ubuntu-latest'
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -56,6 +49,7 @@ jobs:
|
||||
lint_and_fmt:
|
||||
name: Check format and lint rust crates
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -66,3 +60,23 @@ jobs:
|
||||
|
||||
- run: cargo fmt --all -- --check
|
||||
- run: cargo clippy -- -D warnings
|
||||
|
||||
ci_ok:
|
||||
name: Rust CI OK
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 1
|
||||
if: always()
|
||||
needs: [build_and_test, lint_and_fmt]
|
||||
env:
|
||||
FAILURE: ${{ contains(join(needs.*.result, ','), 'failure') }}
|
||||
CANCELLED: ${{ contains(join(needs.*.result, ','), 'cancelled') }}
|
||||
steps:
|
||||
- name: Check for failure or cancelled jobs result
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Failure: $FAILURE - Cancelled: $CANCELLED"
|
||||
if [ "$FAILURE" = "false" ] && [ "$CANCELLED" = "false" ]; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -4,26 +4,11 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
paths:
|
||||
# ⬇ Keep paths in sync with `ci-documentation.yml`
|
||||
- '.github/**'
|
||||
- '*'
|
||||
- '!Cargo.toml'
|
||||
# ⬆ Keep paths in sync with `ci-documentation.yml`
|
||||
- 'packages/**'
|
||||
pull_request:
|
||||
paths:
|
||||
# ⬇ Keep paths in sync with `ci-documentation.yml`
|
||||
- '.github/**'
|
||||
- '*'
|
||||
- '!Cargo.toml'
|
||||
# ⬆ Keep paths in sync with `ci-documentation.yml`
|
||||
- 'packages/**'
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
name: Check build and test
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
@@ -34,6 +19,7 @@ jobs:
|
||||
- 'windows-latest'
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -68,3 +54,23 @@ jobs:
|
||||
|
||||
- name: Types
|
||||
run: pnpm types
|
||||
|
||||
ci_ok:
|
||||
name: Typescript CI OK
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 1
|
||||
if: always()
|
||||
needs: [build_and_test, lint_and_fmt]
|
||||
env:
|
||||
FAILURE: ${{ contains(join(needs.*.result, ','), 'failure') }}
|
||||
CANCELLED: ${{ contains(join(needs.*.result, ','), 'cancelled') }}
|
||||
steps:
|
||||
- name: Check for failure or cancelled jobs result
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Failure: $FAILURE - Cancelled: $CANCELLED"
|
||||
if [ "$FAILURE" = "false" ] && [ "$CANCELLED" = "false" ]; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -8,6 +8,8 @@ dist/
|
||||
|
||||
examples/*/pnpm-lock.yaml
|
||||
|
||||
vite.config.ts.timestamp*
|
||||
|
||||
## Rust related ignores
|
||||
|
||||
# Generated by Cargo
|
||||
|
||||
+8
-1
@@ -1 +1,8 @@
|
||||
pnpm-lock.yaml
|
||||
pnpm-lock.yaml
|
||||
|
||||
dist
|
||||
.tuono
|
||||
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
packages/tuono-lazy-fn-vite-plugin/tests/sources/*
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
* @Valerioageno @marcalexiei
|
||||
|
||||
# Rust
|
||||
/crates/ @Valerioageno
|
||||
/Cargo.toml @Valerioageno
|
||||
|
||||
# Misc
|
||||
/.github/ @marcalexiei
|
||||
|
||||
+1
-3
@@ -23,6 +23,4 @@ Consider [opening a new issue](https://github.com/tuono-labs/tuono/issues/new/ch
|
||||
|
||||
**Did you write a patch that fixes a bug?**
|
||||
|
||||
- Open a new GitHub pull request with the patch.
|
||||
- Ensure the PR description clearly describes the problem and solution. Include the relevant issue number, if applicable.
|
||||
- The pull requests must pass all the CI pipelines
|
||||
[Visit the documentation to learn how to open a pull request](https://tuono.dev/documentation/contributing/pull-requests)
|
||||
|
||||
+9
-8
@@ -1,14 +1,15 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"crates/tuono",
|
||||
"crates/tuono_lib",
|
||||
"crates/tuono_lib_macros",
|
||||
"crates/tuono",
|
||||
"crates/tuono_internal",
|
||||
"crates/tuono_lib",
|
||||
"crates/tuono_lib_macros"
|
||||
]
|
||||
exclude = [
|
||||
"apps/documentation",
|
||||
"examples/with-mdx",
|
||||
"examples/tuono-app",
|
||||
"examples/tuono-tutorial",
|
||||
"benches/tuono"
|
||||
"apps/documentation",
|
||||
"examples/with-mdx",
|
||||
"examples/tuono-app",
|
||||
"examples/tuono-tutorial",
|
||||
"examples/with-tailwind",
|
||||
]
|
||||
|
||||
@@ -24,51 +24,34 @@ Some of its features are:
|
||||
- 🧬 Server Side Rendering
|
||||
- 🔥 Hot Module Reload
|
||||
|
||||
## 📖 Documentation
|
||||
## Documentation
|
||||
|
||||
The [documentation](https://tuono.dev/documentation) is available on
|
||||
The [documentation](https://tuono.dev/) is available on
|
||||
[tuono.dev](https://tuono.dev/).
|
||||
|
||||
## Introduction
|
||||
## Installation
|
||||
|
||||
**NodeJs/Deno/Bun are the only runtimes that allow a React app to be full-stack right? (no)**
|
||||
Available on MacOS, Linux and Windows.
|
||||
|
||||
Tuono is a full-stack React framework with the server side written in Rust.
|
||||
Because of this, Tuono is extremely fast, and the requests are handled by a multithreaded Rust server.
|
||||
React is still React - it is just superpowered.
|
||||
|
||||
**Rust is a hard language, then writing server-side code is hard as well, right? (no again)**
|
||||
|
||||
Tuono provides a collection of utilities to handle the server side code seamlessly with the React code.
|
||||
Each server-side route is managed in a separate file alongside the React route. The routing is handled
|
||||
by Tuono based on the files defined within the `./src/routes` directory.
|
||||
|
||||
**How is Tuono different from Next.js?**
|
||||
|
||||
The Tuono API tries to stick as much as possible to the Next.js one (or at least takes a huge inspiration
|
||||
from it). The major difference is the backend system. While Next.js relies entirely on Node/Deno/Bun,
|
||||
Tuono runs the server without any intermediary runtime. This enables impressive performance improvements
|
||||
(check the benchmarks [here](https://github.com/tuono-labs/tuono/tree/main/benches)).
|
||||
```sh
|
||||
cargo install tuono
|
||||
```
|
||||
|
||||
## Getting started
|
||||
|
||||
Tuono is the CLI that provides all the needed commands to handle the full-stack project.
|
||||
To download it is required [cargo](https://doc.rust-lang.org/cargo/), which is the [rust](https://www.rust-lang.org/)
|
||||
package manager.
|
||||
Create a new project with:
|
||||
|
||||
Then run `cargo install tuono`.
|
||||
```sh
|
||||
tuono new [PROJECT_NAME]
|
||||
```
|
||||
|
||||
To list all the available commands, run `tuono -h`
|
||||
> You can optionally pass the --template (or -t) flag to directly start from a [template](https://github.com/tuono-labs/tuono/tree/main/examples)
|
||||
|
||||
To create a new project, run `tuono new [NAME]` (optionally, you can pass the `--template` (or `-t`) flag - check the
|
||||
[examples](https://github.com/tuono-labs/tuono/tree/main/examples) folder).
|
||||
Now just install the dependencies with you favourite JS package manager (i.e. `npm install`) and start the development environment
|
||||
|
||||
Then, to run the local development environment, install the JS dependencies (`npm install`) and run inside the project folder `tuono dev`
|
||||
|
||||
Finally, when the project is ready to be deployed, just run `tuono build` to create the final React assets
|
||||
and to set the server project in `production` mode.
|
||||
|
||||
Now to execute it just run `cargo run --release`.
|
||||
```sh
|
||||
tuono dev
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Documentation Contributing
|
||||
|
||||
## Update `tuono` version in `apps/documentation`
|
||||
|
||||
Update `tuono` version in the following files
|
||||
|
||||
- `.github/workflows/ci-documentation.yml`
|
||||
- `.github/workflows/deploy-documentation.yml`
|
||||
- `apps/documentation/Cargo.toml`
|
||||
- `apps/documentation/package.json`
|
||||
|
||||
[Refer to this PR for additional information](https://github.com/tuono-labs/tuono/pull/236/files)
|
||||
|
||||
In the future we might:
|
||||
|
||||
- move the documentation in a separate repo
|
||||
- make a script to perform this operation
|
||||
@@ -8,8 +8,7 @@ name = "tuono"
|
||||
path = ".tuono/main.rs"
|
||||
|
||||
[dependencies]
|
||||
tuono_lib = "0.15.0"
|
||||
tuono_lib = "0.17.3"
|
||||
glob = "0.3.1"
|
||||
time = { version = "0.3", features = ["macros"] }
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
|
||||
|
||||
@@ -6,26 +6,27 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"format": "prettier -u --write --ignore-unknown .",
|
||||
"format": "prettier --write --ignore-unknown .",
|
||||
"format:check": "prettier --check --ignore-unknown .",
|
||||
"types": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mantine/code-highlight": "7.14.2",
|
||||
"@mantine/core": "7.14.2",
|
||||
"@mantine/hooks": "7.14.2",
|
||||
"@mantine/code-highlight": "7.16.1",
|
||||
"@mantine/core": "7.16.1",
|
||||
"@mantine/hooks": "7.16.1",
|
||||
"@mdx-js/react": "3.1.0",
|
||||
"@tabler/icons-react": "3.22.0",
|
||||
"@tabler/icons-react": "3.28.1",
|
||||
"clsx": "2.1.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"tuono": "npm:tuono@0.16.0"
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"remark-gfm": "4.0.0",
|
||||
"tuono": "npm:tuono@0.17.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mdx-js/rollup": "3.1.0",
|
||||
"@types/react": "18.3.13",
|
||||
"@types/react-dom": "18.3.0",
|
||||
"postcss": "8.4.49",
|
||||
"@types/react": "19.0.7",
|
||||
"@types/react-dom": "19.0.3",
|
||||
"postcss": "8.5.1",
|
||||
"postcss-preset-mantine": "1.17.0",
|
||||
"postcss-simple-vars": "7.0.1"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import { useMemo, type JSX } from 'react'
|
||||
import { Breadcrumbs as MantineBreadcrumbs, Button } from '@mantine/core'
|
||||
import { Link } from 'tuono'
|
||||
|
||||
import { IconChevronRight, IconBolt } from '@tabler/icons-react'
|
||||
|
||||
interface BreadcrumbData {
|
||||
href?: string
|
||||
label: string
|
||||
}
|
||||
interface BreadcrumbsProps {
|
||||
breadcrumbs: Array<BreadcrumbData>
|
||||
}
|
||||
|
||||
export default function Breadcrumbs({
|
||||
breadcrumbs = [],
|
||||
}: BreadcrumbsProps): JSX.Element {
|
||||
const ldJson = useMemo(() => {
|
||||
const _ldJson = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'BreadcrumbList',
|
||||
itemListElement: [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 1,
|
||||
name: 'Tuono - The React/Rust fullstack framework',
|
||||
item: 'https://tuono.dev' as string | undefined,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
_ldJson.itemListElement.push(
|
||||
...breadcrumbs.map((br, i) => ({
|
||||
'@type': 'ListItem' as const,
|
||||
position: i + 3,
|
||||
name: br.label,
|
||||
item: br.href ? `https://tuono.dev${br.href}` : undefined,
|
||||
})),
|
||||
)
|
||||
|
||||
return _ldJson
|
||||
}, [breadcrumbs])
|
||||
|
||||
return (
|
||||
<>
|
||||
<script type="application/ld+json">
|
||||
{JSON.stringify(ldJson, null, 2)}
|
||||
</script>
|
||||
<MantineBreadcrumbs
|
||||
separator={<IconChevronRight size="1.1rem" stroke={1.5} />}
|
||||
mb="md"
|
||||
mt="md"
|
||||
>
|
||||
<Button href="/" component={Link} variant="subtle" radius="xl" p={5}>
|
||||
<IconBolt />
|
||||
</Button>
|
||||
{breadcrumbs.map((br) => (
|
||||
<BreadcrumbElement href={br.href} label={br.label} key={br.label} />
|
||||
))}
|
||||
</MantineBreadcrumbs>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
interface BreadcrumbElementProps {
|
||||
href?: string
|
||||
label: string
|
||||
}
|
||||
|
||||
export function BreadcrumbElement({
|
||||
href,
|
||||
label,
|
||||
}: BreadcrumbElementProps): JSX.Element {
|
||||
if (href) {
|
||||
return (
|
||||
<Button component={Link} href={href} variant="subtle" radius="xl" px={10}>
|
||||
{label}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Button component="span" variant="light" radius="xl">
|
||||
{label}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import Breadcrumbs from './Breadcrumbs'
|
||||
|
||||
export default Breadcrumbs
|
||||
@@ -0,0 +1,3 @@
|
||||
import EditPage from './EditPage'
|
||||
|
||||
export default EditPage
|
||||
@@ -0,0 +1,3 @@
|
||||
import Hero from './Hero'
|
||||
|
||||
export default Hero
|
||||
+1
-1
@@ -2,5 +2,5 @@ import type { JSX } from 'react'
|
||||
import { Text, type TextProps } from '@mantine/core'
|
||||
|
||||
export default function MdxBold(props: TextProps): JSX.Element {
|
||||
return <Text fw={700} {...props} />
|
||||
return <Text component="span" fw={700} {...props} />
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import MdxBold from './MdxBold'
|
||||
|
||||
export default MdxBold
|
||||
@@ -0,0 +1,3 @@
|
||||
import MdxCode from './MdxCode'
|
||||
|
||||
export default MdxCode
|
||||
@@ -0,0 +1,3 @@
|
||||
import MdxLink from './MdxLink'
|
||||
|
||||
export default MdxLink
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import type { JSX } from 'react'
|
||||
import { CodeHighlight } from '@mantine/code-highlight'
|
||||
|
||||
import styles from './mdx-pre.module.css'
|
||||
import styles from './MdxPre.module.css'
|
||||
|
||||
interface PreProps {
|
||||
children: {
|
||||
@@ -0,0 +1,3 @@
|
||||
import MdxPre from './MdxPre'
|
||||
|
||||
export default MdxPre
|
||||
+13
-7
@@ -1,12 +1,13 @@
|
||||
import type { JSX, ReactNode } from 'react'
|
||||
import { MDXProvider } from '@mdx-js/react'
|
||||
|
||||
import MdxLink from './mdx-link'
|
||||
import MdxPre from './mdx-pre'
|
||||
import MdxQuote from './mdx-quote'
|
||||
import MdxCode from './mdx-code'
|
||||
import { h } from './mdx-title'
|
||||
import MdxBold from './mdx-bold/mdx-bold'
|
||||
import MdxLink from './MdxLink'
|
||||
import MdxPre from './MdxPre'
|
||||
import MdxQuote from './MdxQuote'
|
||||
import MdxCode from './MdxCode'
|
||||
import { h } from './MdxTitle'
|
||||
import MdxBold from './MdxBold'
|
||||
import MdxTable from './MdxTable'
|
||||
|
||||
interface MdxProviderProps {
|
||||
children: ReactNode
|
||||
@@ -19,7 +20,6 @@ export default function MdxProvider({
|
||||
<MDXProvider
|
||||
components={{
|
||||
a: MdxLink,
|
||||
// @ts-expect-error: useless finding the correct props types
|
||||
pre: MdxPre,
|
||||
blockquote: MdxQuote,
|
||||
code: MdxCode,
|
||||
@@ -30,6 +30,12 @@ export default function MdxProvider({
|
||||
h5: h(5),
|
||||
h6: h(6),
|
||||
strong: MdxBold,
|
||||
table: MdxTable,
|
||||
thead: MdxTable.Thead,
|
||||
tbody: MdxTable.Tbody,
|
||||
tr: MdxTable.Tr,
|
||||
th: MdxTable.Th,
|
||||
td: MdxTable.Td,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
@@ -0,0 +1,3 @@
|
||||
import MdxQuote from './MdxQuote'
|
||||
|
||||
export default MdxQuote
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { DetailedHTMLProps, TableHTMLAttributes, JSX } from 'react'
|
||||
import { Table, ScrollArea } from '@mantine/core'
|
||||
|
||||
type MdxTableProps = DetailedHTMLProps<
|
||||
TableHTMLAttributes<HTMLTableElement>,
|
||||
HTMLTableElement
|
||||
>
|
||||
|
||||
function MdxTable(props: MdxTableProps): JSX.Element {
|
||||
const { children, ...rest } = props
|
||||
return (
|
||||
<ScrollArea type="auto">
|
||||
<Table highlightOnHover {...rest}>
|
||||
{children}
|
||||
</Table>
|
||||
</ScrollArea>
|
||||
)
|
||||
}
|
||||
|
||||
MdxTable.Thead = Table.Thead
|
||||
MdxTable.Tbody = Table.Tbody
|
||||
MdxTable.Tr = Table.Tr
|
||||
MdxTable.Th = Table.Th
|
||||
MdxTable.Td = Table.Td
|
||||
MdxTable.Caption = Table.Caption
|
||||
|
||||
export default MdxTable
|
||||
@@ -0,0 +1,3 @@
|
||||
import MdxTable from './MdxTable'
|
||||
|
||||
export default MdxTable
|
||||
+9
-3
@@ -16,6 +16,12 @@ export default function MdxTitle(props: TitleProps): JSX.Element {
|
||||
)
|
||||
}
|
||||
|
||||
export const h =
|
||||
(order: 1 | 2 | 3 | 4 | 5 | 6) =>
|
||||
(props: TitleProps): JSX.Element => <MdxTitle order={order} {...props} />
|
||||
export const h = (
|
||||
order: 1 | 2 | 3 | 4 | 5 | 6,
|
||||
): React.ElementType<TitleProps> => {
|
||||
function render(props: TitleProps): JSX.Element {
|
||||
return <MdxTitle order={order} {...props} />
|
||||
}
|
||||
render.displayName = 'H'
|
||||
return render
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import MdxTitle, { h } from './MdxTitle'
|
||||
|
||||
export default MdxTitle
|
||||
|
||||
export { h }
|
||||
@@ -0,0 +1,3 @@
|
||||
import MdxProvider from './MdxProvider'
|
||||
|
||||
export default MdxProvider
|
||||
+2
-3
@@ -1,5 +1,4 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { Head } from 'tuono'
|
||||
|
||||
interface MetaTagsProps {
|
||||
title: string
|
||||
@@ -15,7 +14,7 @@ export default function MetaTags({
|
||||
canonical,
|
||||
}: MetaTagsProps): ReactNode {
|
||||
return (
|
||||
<Head>
|
||||
<>
|
||||
<title>{title}</title>
|
||||
<link rel="canonical" href={canonical} />
|
||||
<meta
|
||||
@@ -41,6 +40,6 @@ export default function MetaTags({
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta name="twitter:image" content="https://tuono.dev/og-cover.png" />
|
||||
</Head>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import MetaTags from './MetaTags'
|
||||
|
||||
export default MetaTags
|
||||
+2
-2
@@ -2,7 +2,7 @@ import type { JSX } from 'react'
|
||||
import { AppShell, Box, Burger, Button, Flex } from '@mantine/core'
|
||||
import { Link } from 'tuono'
|
||||
|
||||
import Actions from './actions'
|
||||
import NavbarActions from './NavbarActions'
|
||||
|
||||
interface NavbarProps {
|
||||
toggle: () => void
|
||||
@@ -24,7 +24,7 @@ export default function Navbar({ toggle }: NavbarProps): JSX.Element {
|
||||
</Button>
|
||||
<Box />
|
||||
<Flex align="center" gap={8}>
|
||||
<Actions />
|
||||
<NavbarActions />
|
||||
<Burger onClick={toggle} hiddenFrom="sm" size="sm" />
|
||||
</Flex>
|
||||
</Flex>
|
||||
+2
-2
@@ -2,9 +2,9 @@ import type { JSX } from 'react'
|
||||
import { Flex, ActionIcon, Group } from '@mantine/core'
|
||||
import { IconBrandGithub, IconBrandDiscord } from '@tabler/icons-react'
|
||||
|
||||
import ThemeBtn from '../theme-btn'
|
||||
import ThemeBtn from '../ThemeBtn'
|
||||
|
||||
export default function Actions(): JSX.Element {
|
||||
export default function NavbarActions(): JSX.Element {
|
||||
return (
|
||||
<Flex gap={8}>
|
||||
<Group gap={8}>
|
||||
@@ -0,0 +1,3 @@
|
||||
import Navbar from './Navbar'
|
||||
|
||||
export default Navbar
|
||||
+6
-6
@@ -1,16 +1,16 @@
|
||||
import type { JSX } from 'react'
|
||||
import { Box, Button, Text, Title, Flex } from '@mantine/core'
|
||||
import { Link } from 'tuono'
|
||||
import { IconArrowRight, IconArrowLeft } from '@tabler/icons-react'
|
||||
import { Link } from 'tuono'
|
||||
|
||||
interface NavigationButton {
|
||||
interface NavigationButtonData {
|
||||
href: string
|
||||
title: string
|
||||
}
|
||||
|
||||
interface NavigationButtonsProps {
|
||||
prev?: NavigationButton
|
||||
next?: NavigationButton
|
||||
prev?: NavigationButtonData
|
||||
next?: NavigationButtonData
|
||||
}
|
||||
|
||||
export default function NavigationButtons({
|
||||
@@ -25,7 +25,7 @@ export default function NavigationButtons({
|
||||
)
|
||||
}
|
||||
|
||||
interface NavigationButtonProps extends NavigationButton {
|
||||
interface NavigationBtnProps extends NavigationButtonData {
|
||||
type: 'next' | 'prev'
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ const NavigationBtn = ({
|
||||
type,
|
||||
title,
|
||||
href,
|
||||
}: NavigationButtonProps): JSX.Element => {
|
||||
}: NavigationBtnProps): JSX.Element => {
|
||||
const heading = type === 'next' ? 'Next' : 'Previous'
|
||||
const textAlign = type === 'next' ? 'left' : 'right'
|
||||
const variant = type === 'next' ? 'filled' : 'outline'
|
||||
@@ -0,0 +1,3 @@
|
||||
import NavigationButtons from './NavigationButtons'
|
||||
|
||||
export default NavigationButtons
|
||||
+12
-7
@@ -14,8 +14,8 @@ import {
|
||||
import { IconX } from '@tabler/icons-react'
|
||||
import { useMediaQuery } from '@mantine/hooks'
|
||||
|
||||
import { sidebarElements } from './config'
|
||||
import SidebarLink from './sidebar-link'
|
||||
import { sidebarElements } from './sidebarElements'
|
||||
import SidebarLink from './SidebarLink'
|
||||
|
||||
interface SidebarProps {
|
||||
close: () => void
|
||||
@@ -50,26 +50,30 @@ function SidebarElements({ close }: SidebarProps): JSX.Element {
|
||||
<AppShell.Section component={ScrollArea}>
|
||||
{sidebarElements.map((el, i) => {
|
||||
if (el.type === 'divider') {
|
||||
return <Divider my="md" mx={10} />
|
||||
return <Divider key={`${el.type}-${i}`} my="md" mx={10} />
|
||||
}
|
||||
|
||||
if (el.type === 'title') {
|
||||
return (
|
||||
<Text
|
||||
key={`${el.type}-${i}`}
|
||||
size="xs"
|
||||
fw={700}
|
||||
fz={12}
|
||||
pl={12}
|
||||
py={5}
|
||||
children={el.label}
|
||||
/>
|
||||
>
|
||||
{el.label}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
if (el.children?.length) {
|
||||
return (
|
||||
<SidebarLink
|
||||
key={`${el.type}-${i}`}
|
||||
href={el.href}
|
||||
label={el.label}
|
||||
key={i}
|
||||
leftSection={el.leftIcon}
|
||||
>
|
||||
{el.children.map((child, index) => (
|
||||
@@ -83,12 +87,13 @@ function SidebarElements({ close }: SidebarProps): JSX.Element {
|
||||
</SidebarLink>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarLink
|
||||
key={`${el.type}-${i}`}
|
||||
href={el.href}
|
||||
label={el.label}
|
||||
onClick={close}
|
||||
key={i}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
+1
-1
@@ -4,7 +4,7 @@ import clsx from 'clsx'
|
||||
import { Link, useRouter } from 'tuono'
|
||||
import { IconChevronRight } from '@tabler/icons-react'
|
||||
|
||||
import styles from './sidebar-link.module.css'
|
||||
import styles from './SidebarLink.module.css'
|
||||
|
||||
interface SidebarLinkProps {
|
||||
label: string
|
||||
@@ -0,0 +1,3 @@
|
||||
import Sidebar from './Sidebar'
|
||||
|
||||
export default Sidebar
|
||||
+16
-11
@@ -111,6 +111,11 @@ export const sidebarElements: Array<SidebarElement> = [
|
||||
label: 'Defining routes',
|
||||
href: '/documentation/routing/defining-routes',
|
||||
},
|
||||
{
|
||||
type: 'element',
|
||||
label: 'Dynamic routes',
|
||||
href: '/documentation/routing/dynamic-routes',
|
||||
},
|
||||
{
|
||||
type: 'element',
|
||||
label: 'Link and navigation',
|
||||
@@ -126,11 +131,6 @@ export const sidebarElements: Array<SidebarElement> = [
|
||||
label: 'Loading state',
|
||||
href: '/documentation/routing/loading-state',
|
||||
},
|
||||
{
|
||||
type: 'element',
|
||||
label: 'Dynamic routes',
|
||||
href: '/documentation/routing/dynamic-routes',
|
||||
},
|
||||
{
|
||||
type: 'element',
|
||||
label: 'Layouts',
|
||||
@@ -170,6 +170,11 @@ export const sidebarElements: Array<SidebarElement> = [
|
||||
label: 'CSS modules',
|
||||
href: '/documentation/styles/css-modules',
|
||||
},
|
||||
{
|
||||
type: 'element',
|
||||
label: 'Tailwind CSS',
|
||||
href: '/documentation/styles/tailwind-css',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -203,11 +208,6 @@ export const sidebarElements: Array<SidebarElement> = [
|
||||
label: 'Components',
|
||||
href: '#focus',
|
||||
children: [
|
||||
{
|
||||
type: 'element',
|
||||
label: 'Head',
|
||||
href: '/documentation/components/head',
|
||||
},
|
||||
{
|
||||
type: 'element',
|
||||
label: 'Link',
|
||||
@@ -239,7 +239,7 @@ export const sidebarElements: Array<SidebarElement> = [
|
||||
},
|
||||
{
|
||||
type: 'element',
|
||||
label: 'tuono.config.ts',
|
||||
label: 'Configuration',
|
||||
href: '/documentation/configuration',
|
||||
},
|
||||
|
||||
@@ -260,6 +260,11 @@ export const sidebarElements: Array<SidebarElement> = [
|
||||
label: 'Local development',
|
||||
href: '/documentation/contributing/local-development',
|
||||
},
|
||||
{
|
||||
type: 'element',
|
||||
label: 'Pull requests',
|
||||
href: '/documentation/contributing/pull-requests',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
+9
-7
@@ -7,12 +7,8 @@ import { useRouter, Link } from 'tuono'
|
||||
import { IconList } from '@tabler/icons-react'
|
||||
import { Box, rem, ScrollArea, Text } from '@mantine/core'
|
||||
|
||||
import { getHeadings, type Heading } from './get-headings'
|
||||
import classes from './table-of-content.module.css'
|
||||
|
||||
interface TableOfContentsProps {
|
||||
withTabs: boolean
|
||||
}
|
||||
import { getHeadings, type Heading } from './getHeadings'
|
||||
import classes from './TableOfContents.module.css'
|
||||
|
||||
function getActiveElement(rects: Array<DOMRect>): number {
|
||||
if (rects.length === 0) {
|
||||
@@ -36,6 +32,10 @@ function getActiveElement(rects: Array<DOMRect>): number {
|
||||
return closest.index
|
||||
}
|
||||
|
||||
interface TableOfContentsProps {
|
||||
withTabs: boolean
|
||||
}
|
||||
|
||||
export function TableOfContents({
|
||||
withTabs,
|
||||
}: TableOfContentsProps): JSX.Element | null {
|
||||
@@ -64,7 +64,9 @@ export function TableOfContents({
|
||||
),
|
||||
)
|
||||
window.addEventListener('scroll', handleScroll)
|
||||
return (): void => window.removeEventListener('scroll', handleScroll)
|
||||
return (): void => {
|
||||
window.removeEventListener('scroll', handleScroll)
|
||||
}
|
||||
}, [router.pathname])
|
||||
|
||||
if (filteredHeadings.length === 0) {
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Component inspired by: https://github.com/mantinedev/mantine/tree/master/apps/mantine.dev/src/components/TableOfContents
|
||||
*/
|
||||
import { TableOfContents } from './table-of-content'
|
||||
import { TableOfContents } from './TableOfContents'
|
||||
|
||||
export default TableOfContents
|
||||
+3
-3
@@ -7,7 +7,7 @@ import {
|
||||
import { IconSun, IconMoon } from '@tabler/icons-react'
|
||||
import cx from 'clsx'
|
||||
|
||||
import classes from './theme-btn.module.css'
|
||||
import classes from './ThemeBtn.module.css'
|
||||
|
||||
export default function ThemeBtn(): JSX.Element {
|
||||
const { setColorScheme } = useMantineColorScheme()
|
||||
@@ -17,9 +17,9 @@ export default function ThemeBtn(): JSX.Element {
|
||||
|
||||
return (
|
||||
<ActionIcon
|
||||
onClick={() =>
|
||||
onClick={() => {
|
||||
setColorScheme(computedColorScheme === 'light' ? 'dark' : 'light')
|
||||
}
|
||||
}}
|
||||
variant="default"
|
||||
size="lg"
|
||||
aria-label="Toggle color scheme"
|
||||
@@ -0,0 +1,3 @@
|
||||
import ThemeBtn from './ThemeBtn'
|
||||
|
||||
export default ThemeBtn
|
||||
@@ -1,84 +0,0 @@
|
||||
import type { JSX } from 'react'
|
||||
import { Breadcrumbs, Button } from '@mantine/core'
|
||||
import { Link, Head } from 'tuono'
|
||||
|
||||
import { IconChevronRight, IconBolt } from '@tabler/icons-react'
|
||||
|
||||
interface Breadcrumb {
|
||||
href?: string
|
||||
label: string
|
||||
}
|
||||
interface BreadcrumbsProps {
|
||||
breadcrumbs: Array<Breadcrumb>
|
||||
}
|
||||
|
||||
export default function TuonoBreadcrumbs({
|
||||
breadcrumbs = [],
|
||||
}: BreadcrumbsProps): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<script type="application/ld+json">
|
||||
{`{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 1,
|
||||
"name": "Tuono - The React/Rust fullstack framework",
|
||||
"item": "https://tuono.dev"
|
||||
}${breadcrumbs.length > 0 ? ',' : ''}
|
||||
${breadcrumbs
|
||||
.map((br, i) =>
|
||||
JSON.stringify({
|
||||
'@type': 'ListItem',
|
||||
position: i + 3,
|
||||
name: br.label,
|
||||
item: br.href ? `https://tuono.dev${br.href}` : undefined,
|
||||
}),
|
||||
)
|
||||
.join(',')}]
|
||||
}
|
||||
`}
|
||||
</script>
|
||||
</Head>
|
||||
<Breadcrumbs
|
||||
separator={<IconChevronRight size="1.1rem" stroke={1.5} />}
|
||||
mb="md"
|
||||
mt="md"
|
||||
>
|
||||
<Button href="/" component={Link} variant="subtle" radius="xl" p={5}>
|
||||
<IconBolt />
|
||||
</Button>
|
||||
{breadcrumbs.map((br) => (
|
||||
<BreadcrumbElement href={br.href} label={br.label} key={br.label} />
|
||||
))}
|
||||
</Breadcrumbs>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
interface BreadcrumbElementProps {
|
||||
href?: string
|
||||
label: string
|
||||
}
|
||||
|
||||
export function BreadcrumbElement({
|
||||
href,
|
||||
label,
|
||||
}: BreadcrumbElementProps): JSX.Element {
|
||||
if (href) {
|
||||
return (
|
||||
<Button component={Link} href={href} variant="subtle" radius="xl" px={10}>
|
||||
{label}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Button component="span" variant="light" radius="xl">
|
||||
{label}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import Breadcrumbs, { BreadcrumbElement } from './breadcrumbs'
|
||||
|
||||
export default Breadcrumbs
|
||||
|
||||
export { BreadcrumbElement as Element }
|
||||
@@ -1,3 +0,0 @@
|
||||
import EditPage from './edit-page'
|
||||
|
||||
export default EditPage
|
||||
@@ -1,3 +0,0 @@
|
||||
import Hero from './hero'
|
||||
|
||||
export default Hero
|
||||
@@ -1,3 +0,0 @@
|
||||
import MdxProvider from './mdx-provider'
|
||||
|
||||
export default MdxProvider
|
||||
@@ -1,3 +0,0 @@
|
||||
import MdxCode from './mdx-code'
|
||||
|
||||
export default MdxCode
|
||||
@@ -1,3 +0,0 @@
|
||||
import MdxLink from './mdx-link'
|
||||
|
||||
export default MdxLink
|
||||
@@ -1,3 +0,0 @@
|
||||
import MdxPre from './mdx-pre'
|
||||
|
||||
export default MdxPre
|
||||
@@ -1,3 +0,0 @@
|
||||
import MdxQuote from './mdx-quote'
|
||||
|
||||
export default MdxQuote
|
||||
@@ -1,5 +0,0 @@
|
||||
import MdxTitle, { h } from './mdx-title'
|
||||
|
||||
export default MdxTitle
|
||||
|
||||
export { h }
|
||||
@@ -1,3 +0,0 @@
|
||||
import MetaTags from './meta-tags'
|
||||
|
||||
export default MetaTags
|
||||
@@ -1,3 +0,0 @@
|
||||
import Navbar from './navbar'
|
||||
|
||||
export default Navbar
|
||||
@@ -1,3 +0,0 @@
|
||||
import NavigationButtons from './navigation-buttons'
|
||||
|
||||
export default NavigationButtons
|
||||
@@ -1,3 +0,0 @@
|
||||
import Sidebar from './sidebar'
|
||||
|
||||
export default Sidebar
|
||||
@@ -1,3 +0,0 @@
|
||||
import ThemeBtn from './theme-btn'
|
||||
|
||||
export default ThemeBtn
|
||||
+35
-31
@@ -1,4 +1,5 @@
|
||||
import type { ReactNode, JSX } from 'react'
|
||||
import { TuonoScripts } from 'tuono'
|
||||
|
||||
import {
|
||||
ColorSchemeScript,
|
||||
@@ -6,15 +7,15 @@ import {
|
||||
MantineProvider,
|
||||
AppShell,
|
||||
Container,
|
||||
mantineHtmlProps,
|
||||
type CSSVariablesResolver,
|
||||
} from '@mantine/core'
|
||||
import type { CSSVariablesResolver } from '@mantine/core'
|
||||
import { useDisclosure } from '@mantine/hooks'
|
||||
import { Head } from 'tuono'
|
||||
|
||||
import EditPage from '@/components/edit-page'
|
||||
import MdxProvider from '@/components/mdx-provider'
|
||||
import Navbar from '@/components/navbar'
|
||||
import Sidebar from '@/components/sidebar'
|
||||
import EditPage from '@/components/EditPage'
|
||||
import MdxProvider from '@/components/MdxProvider'
|
||||
import Navbar from '@/components/Navbar'
|
||||
import Sidebar from '@/components/Sidebar'
|
||||
|
||||
import '@mantine/core/styles.css'
|
||||
import '@mantine/code-highlight/styles.css'
|
||||
@@ -87,8 +88,8 @@ export default function RootRoute({ children }: RootRouteProps): JSX.Element {
|
||||
const [opened, { toggle }] = useDisclosure()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<html lang="en" {...mantineHtmlProps}>
|
||||
<head>
|
||||
<meta charSet="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link
|
||||
@@ -109,28 +110,31 @@ export default function RootRoute({ children }: RootRouteProps): JSX.Element {
|
||||
href="/favicon-16x16.png"
|
||||
/>
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
</Head>
|
||||
<ColorSchemeScript />
|
||||
<MantineProvider theme={theme} cssVariablesResolver={resolver}>
|
||||
<AppShell
|
||||
layout="alt"
|
||||
header={{ height: 60 }}
|
||||
navbar={{
|
||||
width: 300,
|
||||
breakpoint: 'sm',
|
||||
collapsed: { mobile: !opened },
|
||||
}}
|
||||
>
|
||||
<Navbar toggle={toggle} />
|
||||
<Sidebar close={toggle} />
|
||||
<AppShell.Main>
|
||||
<Container id="mdx-root" component="article" size="md" p={20}>
|
||||
<MdxProvider>{children}</MdxProvider>
|
||||
<EditPage />
|
||||
</Container>
|
||||
</AppShell.Main>
|
||||
</AppShell>
|
||||
</MantineProvider>
|
||||
</>
|
||||
<ColorSchemeScript />
|
||||
</head>
|
||||
<body>
|
||||
<MantineProvider theme={theme} cssVariablesResolver={resolver}>
|
||||
<AppShell
|
||||
layout="alt"
|
||||
header={{ height: 60 }}
|
||||
navbar={{
|
||||
width: 300,
|
||||
breakpoint: 'sm',
|
||||
collapsed: { mobile: !opened },
|
||||
}}
|
||||
>
|
||||
<Navbar toggle={toggle} />
|
||||
<Sidebar close={toggle} />
|
||||
<AppShell.Main>
|
||||
<Container id="mdx-root" component="article" size="md" p={20}>
|
||||
<MdxProvider>{children}</MdxProvider>
|
||||
<EditPage />
|
||||
</Container>
|
||||
</AppShell.Main>
|
||||
</AppShell>
|
||||
</MantineProvider>
|
||||
<TuonoScripts />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Application state"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '@/components/meta-tags'
|
||||
description="Learn how to add features to your Tuono application"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Application state' }]} />
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - CLI"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '@/components/meta-tags'
|
||||
description="Tuono is the CLI that provides all the needed commands to handle the full-stack project."
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'CLI' }]} />
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Head"
|
||||
canonical="https://tuono.dev/documentation/components/head"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Components' }]} />
|
||||
|
||||
# Head
|
||||
|
||||
TODO
|
||||
@@ -1,14 +1,39 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Link"
|
||||
canonical="https://tuono.dev/documentation/components/link"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Components' }]} />
|
||||
|
||||
# Link
|
||||
|
||||
TODO
|
||||
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.
|
||||
|
||||
```typescript jsx
|
||||
import { Link } from 'tuono'
|
||||
|
||||
export default function Page() {
|
||||
return <Link href="/page2">My Other Page</Link>
|
||||
}
|
||||
```
|
||||
|
||||
For navigating to pages outside of your app (other websites), you should use the `<a>` tag.
|
||||
|
||||
> Additional considerations:
|
||||
>
|
||||
> - Any `Link` in the viewport is prefetched by default when it appears within the viewport.
|
||||
> - The corresponding data for server-rendered routes is fetched only when the `Link` is clicked.
|
||||
|
||||
## Reference
|
||||
|
||||
The `Link` component behaves similarly to the `<a>` HTML tag, with a few additional features controlled by the following props:
|
||||
|
||||
| Prop | Type | Default value | Description |
|
||||
| --------- | ------------------- | ------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| `href` | `string` (Required) | - | Relative path to the page in your application. Anchor names (links with hashtags) are also valid. |
|
||||
| `preload` | `boolean` | `true` | Whether to preload the page if the link is within the viewport. |
|
||||
| `scroll` | `boolean` | `true` | Whether to preserve scroll position between navigations. |
|
||||
|
||||
@@ -1,14 +1,57 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - tuono.config.ts"
|
||||
canonical="https://tuono.dev/documentation/configuration"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Configuration' }]} />
|
||||
|
||||
# Configuration
|
||||
|
||||
TODO
|
||||
Tuono can be configured using the `tuono.config.ts` file,
|
||||
which allows you to customize various aspects of the build process and development environment.
|
||||
|
||||
The config file is written in TypeScript,
|
||||
so you can take advantage of type checking and auto-suggestions provided by the `TuonoConfig` type,
|
||||
which is exported from `tuono/config`.
|
||||
|
||||
```ts
|
||||
import type { TuonoConfig } from 'tuono/config'
|
||||
|
||||
const config: TuonoConfig = {
|
||||
/* typesafe config */
|
||||
}
|
||||
|
||||
export default config
|
||||
```
|
||||
|
||||
## vite
|
||||
|
||||
Tuono leverages Vite, a modern and fast build tool and development server for web applications.
|
||||
|
||||
As a result, **some** Vite configuration properties can be set in the `tuono.config.ts` file under the `vite` property.
|
||||
|
||||
### vite.alias
|
||||
|
||||
Useful for configuring custom source alias paths during imports
|
||||
|
||||
- Type:
|
||||
- `Record<string, string>`
|
||||
- `Array<{ find: string | RegExp, replacement: string, customResolver?: ResolverFunction | ResolverObject }>`
|
||||
- [Vite documentation: resolve.alias](https://vite.dev/config/shared-options#resolve-alias)
|
||||
|
||||
### vite.optimizeDeps
|
||||
|
||||
Vite's dependency optimizer used only during dev
|
||||
|
||||
- [Vite documentation: Dep Optimization Options](https://vite.dev/config/dep-optimization-options)
|
||||
|
||||
### vite.plugins
|
||||
|
||||
Useful for extending vite's functionality
|
||||
|
||||
- Type: `Array<Plugin | Array<Plugin> | Promise<Plugin | Array<Plugin>>`
|
||||
- [Vite documentation: plugins](https://vite.dev/guide/using-plugins)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Contributing"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '@/components/meta-tags'
|
||||
description="The project is massive - if you like it, do consider contributing!"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: '✨ Contributing' }]} />
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Contributing"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '@/components/meta-tags'
|
||||
description="The project is massive - if you like it, do consider contributing!"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: '✨ Contributing' }]} />
|
||||
|
||||
@@ -46,7 +46,7 @@ Without taking into account specific cases, we can mostly split the domain requi
|
||||
- The documentation website needs just `React` & `Typescript` (or even less, since most of the
|
||||
code is markdown).
|
||||
|
||||
import NavigationButtons from '../../../components/navigation-buttons'
|
||||
import NavigationButtons from '../../../components/NavigationButtons'
|
||||
|
||||
<NavigationButtons
|
||||
next={{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Contributing - Local development"
|
||||
@@ -6,7 +6,7 @@ import MetaTags from '@/components/meta-tags'
|
||||
description="Contribute to Tuono. Learn here how to setup the repository for local development"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
@@ -30,12 +30,16 @@ git clone https://github.com/<your-name-here>/tuono
|
||||
cd tuono
|
||||
```
|
||||
|
||||
### Rust tool chain
|
||||
For the next steps, you can either set up the environment directly on your computer or use a ready-to-use Docker image (go to the [Docker setup](#docker-setup) part).
|
||||
|
||||
### Local setup
|
||||
|
||||
#### Rust tool chain
|
||||
|
||||
Install the Rust programming language tool chain (`rust` and `cargo`).
|
||||
Follows instructions in the official [docs](https://rustup.rs/)
|
||||
|
||||
### Node.js — runtime
|
||||
#### Node.js — runtime
|
||||
|
||||
Install `Node.js`.
|
||||
You can follow the instructions from the [Node official site](https://nodejs.org/en/download/package-manager)
|
||||
@@ -50,27 +54,69 @@ You can follow the instructions from the [Node official site](https://nodejs.org
|
||||
>
|
||||
> to simply pick up the correct version!
|
||||
|
||||
### Node.js — package manager
|
||||
#### Node.js — package manager
|
||||
|
||||
We use [`pnpm`](https://pnpm.io) as Node.js package manager.
|
||||
|
||||
You can see which version of yarn we use by checking the `packageManager` field in the root `package.json`.
|
||||
|
||||
### Pre-flight checks
|
||||
#### Pre-flight checks
|
||||
|
||||
To check that everything is working properly, run:
|
||||
|
||||
```sh
|
||||
turbo run check-all
|
||||
pnpm run check-all
|
||||
cargo build
|
||||
```
|
||||
|
||||
### Docker setup
|
||||
|
||||
#### Introduction
|
||||
|
||||
Docker takes care of configuring the development environment, so you don’t need to worry about installing specific versions of packages like Node.js or pnpm. The Docker image handles this for you!
|
||||
Using Docker, **the only operations you’ll need to manage on your host machine are related to git**. (don't use pnpm, cargo, ... from your host machine)
|
||||
Some IDEs (such as vscode with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)) allow you to connect directly to the Docker container.
|
||||
|
||||
**Before proceeding with this guide, make sure that the `node_modules` and `target` directories are either absent or empty in the subprojects of Tuono from your host machine where you want to contribute.**
|
||||
This ensures a clean and consistent environment when using Docker.
|
||||
|
||||
#### Build the Tuono's Docker Container
|
||||
|
||||
First, ensure Docker is installed on your machine by following the instructions on the [Docker official site](https://docs.docker.com/engine/install/).
|
||||
|
||||
Once Docker is installed, use the following command to build the image into a container named tuono-source-container:
|
||||
|
||||
```sh
|
||||
# Note: Execute this command in the project root
|
||||
docker compose -f docker/compose.yml up --build -d
|
||||
```
|
||||
|
||||
To verify that everything is working as expected, run the following command:
|
||||
|
||||
```sh
|
||||
docker images && docker ps -a --size
|
||||
```
|
||||
|
||||
Or on Windows:
|
||||
|
||||
```powershell
|
||||
docker images; docker ps -a --size
|
||||
```
|
||||
|
||||
You should see the image named tuono-source-image and the container tuono-source-container. The container's status should be "up".
|
||||
|
||||
Use the following command to connect to the container:
|
||||
|
||||
```sh
|
||||
docker exec -it tuono-source-container /bin/bash
|
||||
```
|
||||
|
||||
## Tuono development
|
||||
|
||||
1. Start tuono frontend build using
|
||||
|
||||
```sh
|
||||
turbo run dev
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
2. In another terminal run
|
||||
@@ -111,3 +157,16 @@ cargo build
|
||||
|
||||
> On the documentation remember that `tuono` `npm` package is installed from the registry and
|
||||
> it is not linked to the repository.
|
||||
|
||||
import NavigationButtons from '../../../components/NavigationButtons'
|
||||
|
||||
<NavigationButtons
|
||||
prev={{
|
||||
title: 'Guidelines',
|
||||
href: '/documentation/contributing',
|
||||
}}
|
||||
next={{
|
||||
title: 'Pull requests',
|
||||
href: '/documentation/contributing/pull-requests',
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Opening a pull request"
|
||||
canonical="https://tuono.dev/documentation/contributing/pull-requests"
|
||||
description="Contribute to Tuono. Learn here how to open a pull request."
|
||||
/>
|
||||
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs
|
||||
breadcrumbs={[
|
||||
{ label: '✨ Contributing', href: '/documentation/contributing' },
|
||||
{ label: 'Pull Requests' },
|
||||
]}
|
||||
/>
|
||||
|
||||
# Pull Requests
|
||||
|
||||
Once your changes are ready, you can create a PR!
|
||||
|
||||
If you are not familiar with GitHub pull requests,
|
||||
you can check the [official documentation](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request).
|
||||
|
||||
---
|
||||
|
||||
- If you are fixing an issue, bear in mind to link the issue itself in the PR description.
|
||||
- If you are adding a new feature, describe the intended use case that the feature fulfills.
|
||||
|
||||
> Bug fixes and new features should include tests.
|
||||
|
||||
## Title
|
||||
|
||||
The PR title must match the following format:
|
||||
|
||||
```text
|
||||
<type>[optional scope]: <short description>
|
||||
```
|
||||
|
||||
You can find commit examples in the [recent commits on main branch](https://github.com/tuono-labs/tuono/commits/main/)
|
||||
|
||||
Here are some examples:
|
||||
|
||||
- feat: add support for react 19
|
||||
- ci: create install-node-dependencies action
|
||||
- feat(packages/tuono-router): use React.Context to pass data
|
||||
- test(packages/tuono): messageChannel - use vi.fn
|
||||
|
||||
> We do not care about the number, or style of commits in your branch history,
|
||||
> because we squash merge every PR into `main`.
|
||||
>
|
||||
> Feel free to commit in whatever style you feel comfortable with.
|
||||
|
||||
### type
|
||||
|
||||
Must be one of the following
|
||||
|
||||
{/* @warning Keep in sync with .github/workflows/pr-title-checker.yml */}
|
||||
|
||||
- `docs` - if you only change documentation, and not shipped code
|
||||
- `feat` - any new functionality additions
|
||||
- `fix` - any bug fixes that don't add new functionality
|
||||
- `refactor` - a code change that neither fixes a bug or adds a feature
|
||||
- `test` - if you only change tests, and not shipped code
|
||||
- `ci` - if you change something related to continuos integration
|
||||
- `chore` - anything else (e.g.: release)
|
||||
|
||||
### optional scope
|
||||
|
||||
A scope may be provided to a commit's type,
|
||||
to provide additional contextual information and is contained within parenthesis
|
||||
E.g.: `fix(crates/tuono): remove cargo warnings`
|
||||
|
||||
### short description
|
||||
|
||||
A succinct title for the PR.
|
||||
(The title max length is set to 100 characters)
|
||||
|
||||
import NavigationButtons from '../../../components/NavigationButtons'
|
||||
|
||||
<NavigationButtons
|
||||
prev={{
|
||||
title: 'Local development',
|
||||
href: '/documentation/contributing/local-development',
|
||||
}}
|
||||
/>
|
||||
@@ -1,11 +1,11 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Multithreading"
|
||||
canonical="https://tuono.dev/documentation/core-concepts/multithreading"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Core concepts' }]} />
|
||||
|
||||
|
||||
@@ -1,14 +1,57 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - useRouter"
|
||||
canonical="https://tuono.dev/documentation/hooks/use-router"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Hooks' }]} />
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'useRouter' }]} />
|
||||
|
||||
# useRouter
|
||||
|
||||
TODO
|
||||
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
|
||||
import { JSX } from 'react'
|
||||
import { useRouter } from 'tuono'
|
||||
|
||||
export default function IndexPage(): JSX.Element {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>pathname: {router.pathname}</p>
|
||||
<button
|
||||
onClick={() => {
|
||||
router.push('/foo')
|
||||
}}
|
||||
>
|
||||
My link
|
||||
</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## `useRouter` result
|
||||
|
||||
- `pathname`: `string` - Returns the current path name
|
||||
- `query`: `Record<string, string>` - This object contains all the query params of the current route
|
||||
|
||||
The following methods are included inside `router`:
|
||||
|
||||
### `router.push`
|
||||
|
||||
Handles client side page navigation quickly. Useful for internal links, or for when you need to change url in some JS.
|
||||
|
||||
```ts
|
||||
router.push(path, options)
|
||||
```
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
| ---------------- | ------------------- | ------------- | ----------------------------------------------------------------- |
|
||||
| `path` | `string` (Required) | - | The path of the page you want to navigate to. |
|
||||
| `options` | `PushOptions` | - | Optional config object for additional control. |
|
||||
| `options.scroll` | `boolean` | `true` | If `false` the scroll offset will be kept across page navigation. |
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - tuono.config.ts"
|
||||
canonical="https://tuono.dev/documentation/how-is-tuono-different"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'How is tuono different?' }]} />
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Installation"
|
||||
@@ -8,6 +6,8 @@ import MetaTags from '@/components/meta-tags'
|
||||
description="Tuono is a development environment built in rust and typescript that outputs a website written in both the languages"
|
||||
/>
|
||||
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Installation' }]} />
|
||||
|
||||
# Installation
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - MDX"
|
||||
canonical="https://tuono.dev/documentation/integrations/mdx"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Integrations' }]} />
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Server side rendering"
|
||||
canonical="https://tuono.dev/documentation/rendering/server-side-rendering"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Rendering' }]} />
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Static site rendering"
|
||||
canonical="https://tuono.dev/documentation/rendering/static-site-rendering"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Rendering' }]} />
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Routing"
|
||||
canonical="https://tuono.dev/documentation/routing/defining-routes"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Defining routes' }]} />
|
||||
|
||||
@@ -54,7 +54,7 @@ then it will be accessible at `posts/1`, `posts/2`, etc.
|
||||
## The Root route (Layout components)
|
||||
|
||||
Tuono allows you to have a layout component to wrap all the routes included within the same folder.
|
||||
To define such component you will have to create a `__root.tsx` file (is allowed only a single `__root` file per folder).
|
||||
To define such component you will have to create a `__layout.tsx` file (is allowed only a single `__layout` file per folder).
|
||||
|
||||
This file won't generate any route.
|
||||
|
||||
@@ -63,7 +63,7 @@ This file won't generate any route.
|
||||
A file created in this location will wrap all project route.
|
||||
|
||||
```tsx
|
||||
// src/routes/__root.tsx
|
||||
// src/routes/__layout.tsx
|
||||
export default function RootLayout({ children }) {
|
||||
return <main>{children}</main>
|
||||
}
|
||||
@@ -74,8 +74,8 @@ export default function RootLayout({ children }) {
|
||||
A file created in this location will wrap only the routes defined within the `src/routes/posts` folder.
|
||||
|
||||
```tsx
|
||||
// src/routes/posts/__root.tsx
|
||||
export default function PostRootLayout({ children }) {
|
||||
// src/routes/posts/__layout.tsx
|
||||
export default function PostLayout({ children }) {
|
||||
return <article>{children}</article>
|
||||
}
|
||||
```
|
||||
@@ -86,9 +86,9 @@ Referring to the two examples above consider that:
|
||||
|
||||
```tsx
|
||||
<RootLayout>
|
||||
<PostRootLayout>
|
||||
<PostLayout>
|
||||
<ExamplePost />
|
||||
</PostRootLayout>
|
||||
</PostLayout>
|
||||
</RootLayout>
|
||||
```
|
||||
|
||||
|
||||
@@ -1,14 +1,61 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Routing"
|
||||
canonical="https://tuono.dev/documentation/routing/dynamic-routes"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Dynamic routes' }]} />
|
||||
|
||||
# Loading state
|
||||
# Dynamic routes
|
||||
|
||||
Todo
|
||||
> 🚧 Only available for SSR apps. This feature will be soon available also for static generated apps.
|
||||
|
||||
When the exact segment names are not known in advance and you need to generate routes from dynamic data,
|
||||
you can use dynamic segments, which are populated at request time.
|
||||
|
||||
## Convention
|
||||
|
||||
A dynamic segment can be created by wrapping a
|
||||
file or a folder name in square brackets: `[segmentName]`.
|
||||
|
||||
The dynamic segment can be used in folders as well as file names:
|
||||
|
||||
- `src/routes/blog/[slug].tsx`
|
||||
- `src/routes/blog/[slug]/index.tsx`
|
||||
|
||||
A path can contain multiple dynamic segments, allowing for more flexible routing:
|
||||
|
||||
- `src/routes/blog/[post]/[comment].tsx`
|
||||
|
||||
### Example
|
||||
|
||||
Assuming you're working on a blog with multiple posts,
|
||||
you can use a dynamic segment to define the post page: `src/routes/blog/[slug].tsx`.
|
||||
|
||||
The `[slug]` is the dynamic segment which will be used to identify individual blog posts.
|
||||
|
||||
```tsx
|
||||
import { useRouter } from 'tuono'
|
||||
|
||||
export default function Page() {
|
||||
const router = useRouter()
|
||||
return <p>Post: {router.pathname}</p>
|
||||
}
|
||||
```
|
||||
|
||||
## Catch all segments
|
||||
|
||||
Dynamic Segments can be extended to catch-all subsequent segments by adding
|
||||
an ellipsis inside the brackets `[...segmentName]`.
|
||||
|
||||
Given the following `src/routes/shop/[...slug].tsx`,
|
||||
the following paths will be matched:
|
||||
|
||||
- `/shop/clothes`
|
||||
- `/shop/clothes/tops`
|
||||
- `/shop`
|
||||
- `/shop/clothes/tops/t-shirts`
|
||||
- and so on.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Routing"
|
||||
canonical="https://tuono.dev/documentation/routing/intro"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Routing' }]} />
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Routing"
|
||||
canonical="https://tuono.dev/documentation/routing/layouts"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Layouts' }]} />
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import MetaTags from '@/components/meta-tags'
|
||||
import MetaTags from '@/components/MetaTags'
|
||||
|
||||
<MetaTags
|
||||
title="Tuono - Routing"
|
||||
canonical="https://tuono.dev/documentation/routing/link-and-navigation"
|
||||
/>
|
||||
|
||||
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
||||
|
||||
<Breadcrumbs breadcrumbs={[{ label: 'Link and navigation' }]} />
|
||||
|
||||
@@ -16,7 +16,16 @@ The Tuono router facilitates client-side route transitions between pages, enhanc
|
||||
- Enabling smooth navigation in single-page applications (SPAs)
|
||||
- Preventing page reloads during site navigation
|
||||
|
||||
How? Using the `Link` component provided from Tuono exports:
|
||||
Tuono provides two choices for navigation between pages of your app:
|
||||
|
||||
- The `Link` component - used in place of an `<a>` tag
|
||||
- The `useRouter` hook - used to programmatically change routes, or to access data about the current route
|
||||
|
||||
Use the `<a>` tag for navigating to other websites.
|
||||
|
||||
## The `Link` component
|
||||
|
||||
Tuono delivers this experience to users with the `Link` component provided from Tuono exports:
|
||||
|
||||
```tsx
|
||||
import { Link } from 'tuono'
|
||||
@@ -44,17 +53,14 @@ The example above uses multiple links. Each one maps a path (`href`) to a known
|
||||
- `/about` → `src/routes/about.tsx`
|
||||
- `/blog/hello-world` → `src/routes/blog/[slug].tsx`
|
||||
|
||||
> Additional considerations:
|
||||
>
|
||||
> - Any `<Link />` in the viewport is prefetched by default when it appears within the viewport.
|
||||
> - The corresponding data for server-rendered routes is fetched only when the `<Link />` is clicked.
|
||||
> For more information about this component visit the [Link component API reference page](/documentation/components/link).
|
||||
|
||||
## The `useRouter` hook
|
||||
|
||||
The Link component is not suitable for programmatic navigation.
|
||||
To handle this, the library provides the `useRouter` hook.
|
||||
|
||||
For example, after a user submits a form and the API request succeeds, they can be redirected to another page.
|
||||
For example, after a user submits a form and the API request succeeds, they can be redirected to another page:
|
||||
|
||||
```tsx
|
||||
import { useRouter } from 'tuono'
|
||||
@@ -72,4 +78,4 @@ export default function GoToAboutPage() {
|
||||
}
|
||||
```
|
||||
|
||||
> For more information about this hook visit the [dedicated API reference page](/documentation/hooks/use-router).
|
||||
> For more information about this hook visit the [useRouter API reference page](/documentation/hooks/use-router).
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user