Compare commits

...

246 Commits

Author SHA1 Message Date
Valerio Ageno 12a2144a0d feat: add tuono-api example 2024-12-14 12:15:13 +01:00
Valerio Ageno adf7ba5391 feat: add CLI support to api-only mode 2024-12-14 12:15:13 +01:00
Valerio Ageno edb21ab969 feat: add feature flat to tuono_lib 2024-12-14 12:15:12 +01:00
Valerio Ageno 4abc163a59 feat: update version to v0.16.2 2024-12-11 14:04:22 +01:00
Marco Pasqualetti 5bb9cf1e7c fix(packages/tuono): styles are not in the page when running tuono dev (#220) 2024-12-11 13:59:47 +01:00
Valerio Ageno a0cdf408a1 feat: update version to v0.16.1 2024-12-10 19:33:48 +01:00
Valerio Ageno 8467506915 feat: create [...catch_all] route (#210) 2024-12-10 19:30:35 +01:00
Valerio Ageno 704255774d fix: defining-routes.mdx 2024-12-10 08:22:03 +01:00
Valerio Ageno 10bb7b1cca feat: update polyfill-db json shape 2024-12-09 20:29:53 +01:00
Valerio Ageno 7f82af3d3b feat: add polyfill db to documentation (#213)
Co-authored-by: Marco Pasqualetti <marco.pasqualetti@live.com>
2024-12-09 12:23:33 +01:00
Marco Pasqualetti d7c729c035 docs: update tuono to 0.16 and add mdx support (#214) 2024-12-09 08:20:18 +01:00
Marco Pasqualetti 51fa904f9b docs: optimize public images (#215) 2024-12-09 07:57:25 +01:00
Valerio Ageno 6191e55745 Revert "Add ️ as default favicon for documentation and examples (#191) (#192)"
This reverts commit 7f9bf08f76.
2024-12-08 10:48:15 +01:00
Marco Pasqualetti c6e93c266a feat(packages/tuono): config – add optimizeDeps and plugins to vite options (#197) 2024-12-08 10:44:09 +01:00
Valerio Ageno bcf7e5b5ab docs: add link and navigation page content (#211)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
Co-authored-by: Marco Pasqualetti <marco.pasqualetti@live.com>
2024-12-08 10:18:20 +01:00
Valerio Ageno 466f122cc4 feat: update version to v0.16.0 2024-12-08 10:13:45 +01:00
Valerio Ageno 539484ea25 docs: fill defining-routes page (#207)
Co-authored-by: Marco Pasqualetti <24919330+marcalexiei@users.noreply.github.com>
2024-12-07 14:51:57 +01:00
Valerio Ageno db1cee25bf test: add integration tests for api/ build (#208) 2024-12-07 14:17:59 +01:00
Marco Pasqualetti 96502b18d0 refactor(apps/documentation): remove lint errors (#206) 2024-12-07 12:28:57 +01:00
Valerio Ageno c491ece8c5 refactor: revamp documentation (#196)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-12-07 12:06:08 +01:00
Marco Pasqualetti c76464bf8a refactor(typescript): use generic instead of simple array type (#205) 2024-12-07 11:58:58 +01:00
Marco Pasqualetti 08b75b1a79 chore(eslint): remove build folder exclusion (#202) 2024-12-07 11:42:38 +01:00
Valerio Ageno 90da869277 feat: update version to v0.15.1 2024-12-07 11:14:13 +01:00
Valerio Ageno 80c4affaa8 feat: add cookies to the response (#201) 2024-12-07 11:10:47 +01:00
Marco Pasqualetti aa087193fe fix(crates/tuono_lib_macros): remove Cargo.tml warnings (#200) 2024-12-06 19:00:54 +01:00
Marco Pasqualetti af7e51f69b chore(ci): setup rust consistently across all workflows (#198) 2024-12-06 14:05:03 +01:00
Marco Pasqualetti 1b62d8ddc2 refactor(crates/tuono): build - ssg - disable zombie_processes warning and use TUONO_PORT to generate server URL (#199) 2024-12-06 13:05:24 +01:00
Valerio Ageno 0839579733 fix: documentation burger menu 2024-12-03 19:38:58 +01:00
Nayan Radadiya 7f9bf08f76 Add ️ as default favicon for documentation and examples (#191) (#192) 2024-12-03 19:35:25 +01:00
Valerio Ageno 79ec1c6922 feat: remove home page from documentation website (#187)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-12-03 16:29:30 +01:00
Valerio Ageno c68246df83 chore: update contributing documentation (#194) 2024-12-03 16:08:49 +01:00
Marco Pasqualetti abc0ad7120 chore(github actions): refine on paths (#189) 2024-12-03 15:59:10 +01:00
Valerio Ageno 4356ca1cff chore: update CONTRIBUTING.md 2024-12-03 14:03:41 +01:00
Valerio Ageno d6215d009c Update health_check.rs 2024-12-03 09:51:42 +01:00
Marco Pasqualetti 0b501e95a5 chore(apps/documentation): migrate to eslint 9 (#188) 2024-12-01 16:40:58 +01:00
Marco Pasqualetti f157ff37e0 refactor(packages/router): removed unused code (#184) 2024-12-01 11:03:12 +01:00
Marco Pasqualetti 11d425faa9 chore(deps-dev): update eslint to v9 (#147) 2024-12-01 10:07:35 +01:00
Valerio Ageno 5fc68a1926 feat: update documentation to v0.15.0 and fix aliases (#182)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-11-30 21:37:02 +01:00
Valerio Ageno ec4577c187 feat: add tuono.config.ts support (#153)
Co-authored-by: Marco Pasqualetti <marco.pasqualetti@live.com>
2024-11-30 19:58:04 +01:00
Valerio Ageno 8052de8ad5 feat: update version to v0.15.0 (#181) 2024-11-30 19:03:01 +01:00
Valerio Ageno 2fda959cd6 feat: update tuono new repository reference (#178)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-11-30 14:16:18 +01:00
Valerio Ageno 05fa8a5ae2 feat: update docs and readme repo links (#180) 2024-11-30 14:16:10 +01:00
Valerio Ageno a341b41e9a chore: update repo reference withing manifests (#179)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-11-30 14:15:36 +01:00
Valerio Ageno a2e0a4d78a feat: update version to v0.14.6 2024-11-30 14:13:21 +01:00
Valerio Ageno 4fb1d6077c Add tuono cli integration test (#177)
Co-authored-by: KingTheSim <KingTheSim@abv.bg>
Co-authored-by: KingTheSim <122887037+KingTheSim@users.noreply.github.com>
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-11-29 16:34:56 +01:00
Valerio Ageno 53ab927544 feat: update version to v0.14.5 2024-11-27 21:07:50 +01:00
Valerio Ageno 897cc2daf2 feat: add --no-js-emit flag to tuono build command (#175)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-11-27 21:05:45 +01:00
Marco Pasqualetti 73ff31daf5 ci(rust): avoid beta and nightly toolchains to be executed on macos and windows (#174) 2024-11-27 20:40:00 +01:00
Marco Pasqualetti c387a9e17e chore(renovate): enable schedule (#172) 2024-11-27 15:33:14 +01:00
Valerio Ageno 1f92931076 Fix optional application state parameters (#173)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-11-27 15:25:05 +01:00
renovate[bot] d3105a1532 fix(deps): update dependency turbo to v2.3.3 (#169) 2024-11-27 08:26:54 +01:00
Marco Pasqualetti 7f50f31837 ci: trigger workflow only on push only on main (#166) 2024-11-26 21:49:14 +01:00
renovate[bot] 4c3e90ea4b chore(deps): update dependency @vitejs/plugin-react to v4.3.4 (#160)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 21:48:57 +01:00
renovate[bot] 8d80fc4aa9 chore(deps): update dependency vitest to v2.1.6 (#162)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 21:48:38 +01:00
renovate[bot] 78a04ffcf1 chore(deps): update dependency prettier to v3.4.1 (#165)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 21:48:23 +01:00
Valerio Ageno bcb2c91823 fix: windows path resolution (#167) 2024-11-26 21:37:00 +01:00
Marco Pasqualetti 9058f209dd ci: add Windows and MacOS to test matrix for both rust and typescript (#158) 2024-11-26 17:50:53 +01:00
renovate[bot] 1f172d583e fix(deps): update dependency @vitejs/plugin-react-swc to v3.7.2 (#161)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 13:48:13 +01:00
Valerio Ageno 439b4757df Turn main.rs into app.rs (#159)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-11-26 09:20:10 +01:00
renovate[bot] 9f8809bd51 fix(deps): update dependency @types/node to v22.10.0 (#157) 2024-11-26 08:02:27 +01:00
renovate[bot] 4e326650cc fix(deps): update dependency @types/node to v22.10.0 (#154) 2024-11-26 07:59:15 +01:00
renovate[bot] e27be27692 fix(deps): update dependency turbo to v2.3.2 (#155) 2024-11-26 07:58:58 +01:00
renovate[bot] 88eb2a1897 chore(deps): update dependency prettier to v3.4.0 (#156) 2024-11-26 07:58:43 +01:00
Valerio Ageno 8c84ef73c8 feat: update version to v0.14.1 2024-11-24 18:33:45 +01:00
renovate[bot] 859e49f16c fix(deps): update mantine monorepo to v7.14.2 (#145)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-24 18:16:13 +01:00
renovate[bot] 14ba8b0a23 chore(deps): update dependency typescript to v5.7.2 (#138)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-23 21:28:03 +01:00
Marco Pasqualetti d7c70f75f3 docs(CONTRIBUTING): add “Local development” (#136) 2024-11-23 21:04:01 +01:00
Valerio Ageno 2760e3ea08 feat(ci): update spellchecker workflow (#143) 2024-11-23 17:30:05 +01:00
Marco Pasqualetti f2f041fe55 ci: test spellcheck via reviewdog (#137)
* ci: use GITHUB_TOKEN in spell checking workflow

* ci(spell-checking): use different reporter based on github context
2024-11-23 10:56:45 +01:00
renovate[bot] 9ec9700ed4 fix(deps): update dependency @types/node to v22.9.3 (#140) 2024-11-23 10:27:51 +01:00
renovate[bot] c6b047fc02 fix(deps): update dependency @types/node to v22.9.2 (#139) 2024-11-23 09:14:22 +01:00
Myan V. 6727264e39 Better error handling when trying to overwrite an existing folder and using a non-existent template (#135)
* fix: prevent overwriting existing project directories

* refactor: improve scaffold error messages
2024-11-22 13:38:54 +01:00
Valerio Ageno d1a5fe234d fix: examples folder 2024-11-21 19:16:06 +01:00
renovate[bot] e84c7cd276 fix(deps): update dependency turbo to v2.3.1 (#132)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-21 19:02:52 +01:00
Valerio Ageno 087813fab9 Add support for api/ folder (#129)
* feat: detect api/ folder from tuono CLI

* feat: prevent adding the API in the data endpoints list

* feat: create basic API handler proc macro

* feat: parse api/ and build .tuono/main.rs file

* chore: remove unused cargo dependencies

* refactor: tuono base health_check

* fix: remove failing test

* feat: update version to v0.14.0
2024-11-21 19:02:11 +01:00
Valerio Ageno 3a4e7398c6 feat: update documentation og:cover 2024-11-21 18:53:32 +01:00
Valerio Ageno 1630fd7e71 Update README.md 2024-11-21 11:30:02 +01:00
Myan V. 4aa99beaff Better error handling for target ports conflict (#126)
* feat: add error message when port 3000 is already in use

* feat: expand port availability checking

* refactor: improve port extraction code modularity

* fix: formatting

* fix: clippy

* fix: move port checking logic to tuono crate

* fix(tuono): make main async

* fix: tokio panicking when testing CLI

* feat: working port conflict detection in crate tuono

* fix: passing format and lint checks

* refactor: refactor cli by making it non-async

* refactor: move port constants to module scope and remove unnecessary Result return type from port checker
2024-11-21 09:45:08 +01:00
Valerio Ageno eaa0ba28d8 Update README.md 2024-11-20 18:57:43 +01:00
renovate[bot] 3f3e1120b2 chore(deps): update pnpm to v9.14.2 (#127)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-20 13:52:19 +01:00
Marco Pasqualetti 89d7a2c740 chore: add examples folder to workspaces and make examples packages name unique (#125) 2024-11-20 13:46:31 +01:00
Valerio Ageno 56c31f0204 feat: update version to v0.13.3 2024-11-20 13:45:37 +01:00
renovate[bot] 338cfb5be2 fix(deps): update dependency @types/node to v22.9.1 (#121)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-20 09:03:32 +01:00
renovate[bot] 43f6fe664b chore(deps): update pnpm to v9.14.1 (#124)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-20 09:03:03 +01:00
Valerio Ageno 209c9fb7f7 feat: update version to v0.13.2 2024-11-19 17:34:33 +01:00
Valerio Ageno a562f67e8d Feat: added discord to README 2024-11-19 16:43:58 +01:00
Valerio Ageno ef0fe5a425 fix: seo page canonical 2024-11-19 15:50:58 +01:00
Myan V. b50902d23e Update watchexec to v5 and watchexec-signals to v4 (#118)
* fix(deps): update rust crate watchexec to v5

* fix(deps): update rust crate watchexec-signals to v4

* fix: revert unnecessary imports
2024-11-19 14:32:44 +01:00
Marco Pasqualetti 55490579ec refactor: replace () => JSX.Element with React.ComponentType (#120) 2024-11-18 21:45:27 +01:00
renovate[bot] 957d08701f chore(deps): update typescript-eslint monorepo to v8.15.0 (#119)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 20:41:04 +01:00
Valerio Ageno 61e1aed35d Add not expiring discord invite to documentation website 2024-11-18 18:36:33 +01:00
Valerio Ageno 2034f0ef5f fix: tutorial/redirections canonical tag 2024-11-18 12:35:14 +01:00
Valerio Ageno fcb92c7f0b fix(doc): spelling 2024-11-17 18:24:56 +01:00
Marco Pasqualetti 28ea1ca1df ci: add format check on repository root (#115) 2024-11-17 17:51:20 +01:00
Valerio Ageno ebc1a458a9 Fix tuono_lib_macro crate (#116)
* fix: tuono lib macro

* feat: remove reqwest re-export

* feat: update version to 0.13.1

* fix: remove reqwest from documentation
2024-11-17 17:11:07 +01:00
Valerio Ageno df92ef5296 Add support for custom global state (#111)
* feat: add 'has_main_file' to App struct

* feat: handle custom state from the main.rs file

* feat: update tutorial template with new setup

* fix: apply clippy hints

* feat: add ApplicationState mention to documentation website

* feat: update version to v0.13.0
2024-11-17 16:28:56 +01:00
Valerio Ageno 253e0a8378 feat(doc): keep social buttons on mobile website 2024-11-17 12:26:58 +01:00
Valerio Ageno a9fbe4eddd feat: add discord channel invite to documentation website 2024-11-17 12:19:25 +01:00
Valerio Ageno cfccc638c6 feat: update version to v0.12.4 2024-11-16 19:23:21 +01:00
renovate[bot] 9f1460cc26 fix(deps): update mantine monorepo to v7.14.1 (#110) 2024-11-16 17:11:02 +01:00
Henry Chen f0a4541420 fix: handle hyphen in route (#109) 2024-11-16 17:10:37 +01:00
renovate[bot] d0ce482680 chore(deps): update dependency vitest to v2.1.5 (#105)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-16 14:29:50 +01:00
renovate[bot] 40e2734a4e fix(deps): update dependency turbo to v2.3.0 (#106)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-16 14:28:58 +01:00
Marco Pasqualetti 8552796343 chore: fix typo and improve name on CI (#107) 2024-11-16 11:47:53 +01:00
Marco Pasqualetti 6d72ffb876 ci: create install-node-dependencies action (#100) 2024-11-16 11:27:10 +01:00
Valerio Ageno 65faaf0183 feat: added website to crates/package manifest 2024-11-16 11:08:50 +01:00
Valerio Ageno 7f7c2e8d6f feat: update documentation tuono to v0.12.3 (#104) 2024-11-16 11:02:47 +01:00
Valerio Ageno 3be491baa7 Fix tuono lib release (#103)
* fix: removed service

* feat: update version to v0.12.3
2024-11-16 10:50:02 +01:00
Valerio Ageno 48b974ae58 Fix failing release pipeline (#102)
* feat: add no-verify key to cargo publish script

* feat: update version to v0.12.2
2024-11-16 10:23:59 +01:00
Valerio Ageno c394898fcd Create logger service (#101)
* feat: create logger service

* feat: opt out __tuono/data routes from logger

* feat: update version to v0.12.1
2024-11-16 09:47:59 +01:00
renovate[bot] f22249f3e9 chore(deps): update pnpm to v9.13.2 (#99) 2024-11-15 07:08:49 +01:00
renovate[bot] 120cec52e9 chore(deps): update pnpm to v9.13.1 (#98)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-14 20:53:19 +01:00
Marco Pasqualetti 535cc6b3d9 chore: add apps/documentation to pnpm workspaces (#96) 2024-11-14 10:30:21 +01:00
renovate[bot] 18a060e2bf chore(deps): update pnpm to v9.13.0 (#94)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-13 16:55:37 +01:00
Marco Pasqualetti 7b8165cee6 refactor: use React.JSX rather than global JSX (#93) 2024-11-13 08:33:48 +01:00
Valerio Ageno 6331eb64e6 fix: development script watch loop (#92)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-11-12 14:21:16 +01:00
Marco Pasqualetti 3c38b551f0 docs(CONTRIBUTING): new link issue point to issue template chooser (#90) 2024-11-12 13:46:34 +01:00
renovate[bot] 8e761347f2 fix(deps): update rust crate tuono_lib to 0.12.0 (#89)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 08:45:21 +01:00
Valerio Ageno e2d44e0e6a fix: format documentation 2024-11-11 21:56:22 +01:00
Valerio Ageno 607da92c71 Make handler arguments optional (#87)
* feat: support axum extractors

* chore: update tuono example

* chore: update tutorial example

* doc: update documentation

* feat: update version to v0.12.0

* fix: use clippy suggestion
2024-11-11 21:52:22 +01:00
Henry Chen ae0427604e Fix tutorial link in README (#86) 2024-11-11 13:32:56 +01:00
Marco Pasqualetti 2aa981c581 chore: use GitHub forms in issue template (#85)
* chore: use GitHub forms in issue template

* Update .github/ISSUE_TEMPLATE/bug_report.yml

---------

Co-authored-by: Valerio Ageno <51341197+Valerioageno@users.noreply.github.com>
2024-11-11 09:28:25 +01:00
Valerio Ageno 5d8ec82502 feat: add log to catch_all routes (#83) 2024-11-10 11:08:06 +01:00
Valerio Ageno fc9bb52c41 Update getting started (#82)
* feat: update getting started doc

* feat: update README
2024-11-10 10:44:36 +01:00
Valerio Ageno 3224e4138f feat: update doc hero 2024-11-10 09:52:51 +01:00
Valerio Ageno 7ea28c4fd3 fix: documentation typo 2024-11-10 09:50:47 +01:00
Valerio Ageno acb5567f6a fix: breadcrumbs structured data 2024-11-09 19:27:02 +01:00
Valerio Ageno cc877c7c11 fix: doc formatting 2024-11-06 21:11:57 +01:00
Valerio Ageno 87bdddf7cf feat: add twitter OG 2024-11-06 21:11:32 +01:00
Valerio Ageno d939b64d64 fix: documentation meta breadcrumb 2024-11-06 21:09:30 +01:00
Valerio Ageno 3f64f71947 feat: update documentation version to v0.11.2 (#81)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-11-05 12:13:30 +01:00
Valerio Ageno aaae7db24d Improve route preloading (#80)
* feat: improve route preloading

* feat: update version to v0.11.2

---------

Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-11-05 12:03:20 +01:00
Valerio Ageno 48c3934b6e Add seo tags to documentation (#78)
* refactor: update documentation meta tags

* feat: update documentation version to v0.11.1

* fix: formatting

* feat: add SEO breadcrumb structured data
2024-11-04 21:23:56 +01:00
Valerio Ageno 258b4af0b1 feat: prevent scroll offset on page navigation (#77) 2024-11-04 19:29:37 +01:00
Valerio Ageno edfbd03f13 Prevent not exported routes error (#76)
* fix: prevent no exported route compiler error

* feat: update version to v0.11.1

* fix: formatting
2024-11-04 19:25:46 +01:00
Valerio Ageno 9cb0f62da7 fix: documentation server/client mismatch 2024-11-04 17:15:37 +01:00
Valerio Ageno 9591960e31 feat: add canonical tags to documentation 2024-11-03 22:34:23 +01:00
Valerio Ageno 132d8ebe8f feat: add navigation buttons to tutorial 2024-11-03 22:34:12 +01:00
Valerio Ageno 4020073aca feat: update doc tuono version to v0.11.0 2024-11-03 22:34:00 +01:00
Valerio Ageno 5025692220 fix: put mantine color scheme component outside Head 2024-11-03 22:27:17 +01:00
Valerio Ageno d04a4c4103 Move to react-helmet-async (#72)
* feat: move to react-helmet-async

* feat: set version to v0.11.0
2024-11-03 21:09:32 +01:00
renovate[bot] 7e6dea68f4 chore(deps): update pnpm to v9.12.3 (#58)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-03 19:02:59 +01:00
renovate[bot] a046833414 chore(deps): update dependency node to v22 (#71)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-03 19:02:43 +01:00
renovate[bot] cfa59ca8bf fix(deps): update dependency @types/node to v22 (#70) 2024-10-29 07:02:39 +01:00
renovate[bot] d470bd58f2 doc: update tuono version to v0.10.4 (#61)
Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-10-18 15:22:54 +02:00
Valerio Ageno ea82d2b1df Correct documentation spelling (#68)
* fix: documentation/index spelling

* fix: documentation/development-setup spelling

* fix: documentation/api-fetching spelling

* fix: documentation/components spelling

* fix: documentation/dynamic-routes spelling

* feat: add correct tutorial link to README.md

* chore: remove legacy  folder

* fix: formatting

* fix: documentation/error-handling spelling

* fix: documentation/seo spelling

* fix: documentation/redirections spelling

* fix: documentation/production spelling

* fix: documentation/conclusion spelling

* feat: update version to v0.10.4

* fix: redirections spelling

* fix: API fetching spelling

* feat: create CLI doc page

* fix: correct CLI spelling

* fix: update CLI output spelling
2024-10-17 19:00:23 +02:00
renovate[bot] 93b44088a9 chore(deps): update dependency node to v20.18.0 (#60)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-17 18:09:15 +02:00
renovate[bot] 625c091fdc chore(deps): update dependency @testing-library/react to v16 (#63)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-17 18:08:57 +02:00
Valerio Ageno e0c0447fb6 fix: remove useless container 2024-10-17 12:17:38 +02:00
Valerio Ageno b67a8e8537 fix: remove table of contents 2024-10-17 12:14:33 +02:00
renovate[bot] c9f1b02954 chore(deps): update dependency jsdom to v25 (#64)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-17 09:47:47 +02:00
renovate[bot] 6b3bfca1f6 chore(deps): update dependency vitest to v2 (#65)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-17 09:47:29 +02:00
Valerio Ageno 15e568594d feat: update code font size 2024-10-17 09:03:05 +02:00
Valerio Ageno 089f41ee89 feat: update doc code example font size 2024-10-17 08:56:17 +02:00
Valerio Ageno 636c68e532 chore: update doc sidebar 2024-10-17 08:55:23 +02:00
Valerio Ageno 6d8a04dfb2 Move tutorial into web documentation (#54)
* chore: move tutorial into web documentation

* fix: update ci-documentation tuono version

* fix: rollback documentation website version to v0.10.1

* temporaly remove 'dynamic' keyword

* feat: update tuono documentation to v0.10.3

* chore: format

---------

Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
2024-10-17 08:20:01 +02:00
Valerio Ageno 01d5aad8aa fix: update testing-library/jest-dom version 2024-10-16 20:49:46 +02:00
Valerio Ageno 002733cd99 Prevent dynamic fn replacement when not imported by tuono (#57)
* fix: prevent dynamic fn replacement when not imported by tuono

* feat: update version to v0.10.3

* Revert "fix(deps): update dependency zustand to v5 (#55)"

This reverts commit d7a086dfb1.

* Revert "fix(deps): update dependency zustand to v4.5.5 (#37)"

This reverts commit b36dc0b897.

* Revert "chore(deps): update dependency @testing-library/react to v16 (#38)"

This reverts commit 1a1b62698c.

* Revert "chore(deps): update dependency @tanstack/config to ^0.13.0 (#32)"

This reverts commit 6c7cc62371.

* revert pnpm update

* Revert "chore(deps): update dependency vitest to v2 (#45)"

This reverts commit c5b5f6aefe.

* Revert "chore(deps): update dependency node to v20.18.0 (#33)"

This reverts commit 588326cc57.
2024-10-16 20:41:33 +02:00
renovate[bot] d7a086dfb1 fix(deps): update dependency zustand to v5 (#55)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-14 19:38:29 +02:00
renovate[bot] d60c7dcd9b fix(deps): update rust crate watchexec-supervisor to v3 (#56)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-14 19:29:33 +02:00
renovate[bot] 58baf8aa82 fix(deps): update dependency tuono to v0.10.2 (#51)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-13 17:57:44 +02:00
Valerio Ageno 0a8504d9f2 feat: update version to v0.10.2 (#50) 2024-10-13 10:18:19 +02:00
Valerio Ageno 934a83c0e2 Fix spelling (#49)
* fix: README spelling

* fix: CONTRIBUTING spelling

* fix: CODE_OF_CONDUCT

* fix: documentation spelling
2024-10-12 19:03:05 +02:00
Valerio Ageno ea65ad042f fix: documentation eslint 2024-10-12 19:02:17 +02:00
renovate[bot] 3544cd2943 chore(deps): update typescript-eslint monorepo to v8 (major) (#47)
* chore(deps): update typescript-eslint monorepo to v8

* chore: update ban-type eslint rule

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Valerio Ageno <valerioageno@yahoo.it>
2024-10-12 18:40:04 +02:00
renovate[bot] e593707ce7 fix(deps): update rust crate syn to v2 (#48)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-12 18:38:44 +02:00
renovate[bot] 6dd0fc7410 chore(deps): update actions/checkout action to v4 (#46) 2024-10-12 13:55:40 +02:00
renovate[bot] faf7bf29e2 fix(deps): update rust crate tungstenite to 0.24.0 (#44) 2024-10-12 13:41:03 +02:00
renovate[bot] c5b5f6aefe chore(deps): update dependency vitest to v2 (#45) 2024-10-12 13:40:51 +02:00
renovate[bot] 8e48eec01d chore(deps): update dependency eslint-plugin-react-hooks to v5 (#42) 2024-10-12 13:37:33 +02:00
renovate[bot] e3c5cc882f chore(deps): update dependency jsdom to v25 (#43) 2024-10-12 13:37:15 +02:00
renovate[bot] dfb1bebc6b fix(deps): update rust crate tokio-tungstenite to 0.24.0 (#39)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-12 13:03:59 +02:00
renovate[bot] a40367f813 fix(deps): update rust crate tower-http to 0.6.0 (#40)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-12 13:03:44 +02:00
renovate[bot] 1a1b62698c chore(deps): update dependency @testing-library/react to v16 (#38)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-12 13:00:23 +02:00
renovate[bot] b36dc0b897 fix(deps): update dependency zustand to v4.5.5 (#37)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-12 12:55:01 +02:00
renovate[bot] a9eacf21f4 chore(deps): update pnpm to v9.12.1 (#36)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-12 12:51:50 +02:00
renovate[bot] 23d84b25be fix(deps): update rust crate ssr_rs to 0.7.0 (#35)
* fix(deps): update rust crate ssr_rs to 0.7.0

* chore: update ssr error

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Valerio Ageno <valerioageno@yahoo.it>
2024-10-12 12:45:23 +02:00
renovate[bot] 6c7cc62371 chore(deps): update dependency @tanstack/config to ^0.13.0 (#32)
* chore(deps): update dependency @tanstack/config to ^0.13.0

* fix: tanstack/config vite import

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Valerio Ageno <valerioageno@yahoo.it>
2024-10-12 12:40:03 +02:00
renovate[bot] 588326cc57 chore(deps): update dependency node to v20.18.0 (#33)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-12 12:34:06 +02:00
renovate[bot] ce654bf7a2 chore: Configure Renovate (#31)
* Add renovate.json

* fix: ignore benches/

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Valerio Ageno <valerioageno@yahoo.it>
2024-10-12 12:29:14 +02:00
Valerio Ageno a3bcb76105 CI: add spell checking pipeline (#30)
* ci: add spell checking pipeline

* fix: add github to the lookup folders

* fix: add patterns rule

* refactor: Github action definition

* test: introduce spell bug

* fix: update spell checker reporter

* fix: update action version

* feat: remove disabled_categories

* feat: remove github token

* feat: add fail level to pipeline

* fix: error as string

* feat: remove disabled rules

* feat: add reviewdog_token

* feat: change disabled_rules to string

* feat: add spell rules

* fix: spell categories

* Update bug_report.md
2024-10-12 12:05:45 +02:00
Valerio Ageno 4045ebc24e Update README.md 2024-08-20 14:34:37 +02:00
Valerio Ageno 2be3710462 Update README.md 2024-08-20 14:30:46 +02:00
Valerio Ageno fe3185c6dc Update documentation version to v0.10.1 2024-08-19 21:03:50 +02:00
Valerio Ageno f10b813e1e Update ci-documentation.yml 2024-08-19 18:44:32 +02:00
Valerio Ageno c67d4199a0 fix: github language checks 2024-08-19 18:27:45 +02:00
Valerio Ageno d0a6c59c62 Add response time to SSR GET log (#29)
* feat: add response time to SSR GET log

* feat: update version to v0.10.1
2024-08-19 18:25:00 +02:00
Valerio Ageno 60f622542f feat: update tuono version in deploy documentation CD 2024-08-18 12:36:51 +02:00
Valerio Ageno e7fcd64b3a feat: add sitemaps to documentation website 2024-08-18 12:25:12 +02:00
Valerio Ageno 3772e7307e feat: add favicon to documentation website 2024-08-18 11:32:57 +02:00
Valerio Ageno e853db164d fix: documentation types CI 2024-08-18 11:25:14 +02:00
Valerio Ageno 509283adab feat: update tuono version to v0.10.0 2024-08-18 11:19:54 +02:00
Valerio Ageno db56b7f2dc feat: remove default head meta tags (#28) 2024-08-18 11:17:38 +02:00
Valerio Ageno acd663d79f Add custom response type (#27)
* feat: support route names with dots

* feat: add support for Response::Custom value

* feat: statically export xml files
2024-08-18 11:09:27 +02:00
Valerio Ageno 3636268a71 fix: documentation hero 2024-08-17 20:16:26 +02:00
Valerio Ageno 6402f42d01 fix: documentation mdx container 2024-08-17 20:08:23 +02:00
Valerio Ageno 71ac19cbb9 fix: documentation padding 2024-08-17 17:35:45 +02:00
Valerio Ageno d99389a398 fix: prod TOC 2024-08-17 17:32:25 +02:00
Valerio Ageno 024c386af4 feat: add table of content 2024-08-17 17:21:29 +02:00
Valerio Ageno d982c9c24b feat: change documenation border radious 2024-08-17 16:23:57 +02:00
Valerio Ageno 480973318d feat: add X button on documentation website 2024-08-17 15:37:21 +02:00
Valerio Ageno a497937106 feat: update benches to speed up nextjs servers 2024-08-17 15:00:43 +02:00
Valerio Ageno 0d33150f30 feat: add benchmarks against nextjs (#26) 2024-08-16 16:23:39 +02:00
Valerio Ageno 94667b1454 Update documentation tuono version to v0.9.2 2024-08-16 11:38:24 +02:00
Valerio Ageno 2cbcd8ad70 feat: update version to v0.9.2 2024-08-16 11:28:42 +02:00
Valerio Ageno 9f40a55907 feat: add id to documentation headings 2024-08-16 11:27:29 +02:00
Valerio Ageno 51e01ec142 feat: add link support to hash 2024-08-16 11:21:18 +02:00
Valerio Ageno 63fc2b9855 fix: documentation mailto link 2024-08-16 11:05:49 +02:00
Valerio Ageno edd8a02423 fix: documentation type checking 2024-08-15 21:16:38 +02:00
Valerio Ageno a0a81b514c fix: documentation formatting 2024-08-15 21:08:48 +02:00
Valerio Ageno 92820804f8 fix: sidebar on mobile 2024-08-15 21:08:18 +02:00
Valerio Ageno e7ea7ed1c4 feat: improve contributing documentation 2024-08-15 21:07:28 +02:00
Valerio Ageno 7471c90f49 feat: update documentation tuono version to v0.9.1 2024-08-15 20:52:22 +02:00
Valerio Ageno f545a9c469 feat: update contributing and tutorial pages 2024-08-15 20:51:58 +02:00
Valerio Ageno 30073c226d feat: update version to v0.9.1 2024-08-15 20:44:25 +02:00
Valerio Ageno 1b1e91b6c0 fix: sanitize client side pathnames (#25) 2024-08-15 20:42:47 +02:00
Valerio Ageno 71d7ccf27d feat: update README header 2024-08-15 20:36:11 +02:00
Valerio Ageno 3ca24ec87f feat: create overview and getting started pages 2024-08-15 19:25:03 +02:00
Valerio Ageno b2940d9fa8 feat: add breadcrumbs to documentation 2024-08-15 18:52:56 +02:00
Valerio Ageno a7b7f0eac2 feat: update documentation sidebar 2024-08-15 18:20:20 +02:00
Valerio Ageno 4859916edd feat: update documentation sidebar 2024-08-15 11:31:33 +02:00
Valerio Ageno ad3e19e965 fix: documentation sidebar on mobile 2024-08-14 21:28:23 +02:00
Valerio Ageno 03dead1083 feat: update documentation tuono version to v0.9.0 2024-08-14 20:59:43 +02:00
Valerio Ageno 341fba6ca9 Preload chunks when links are visible in the viewport (#24)
* feat: preload chunk when links are visible in the viewport

* feat: update version to v0.9.0
2024-08-14 20:50:47 +02:00
Valerio Ageno 58c4890122 Update pull_request_template.md 2024-08-14 20:45:37 +02:00
Valerio Ageno af42e5ef21 fix: remove useless pendingElement 2024-08-14 14:48:26 +02:00
Valerio Ageno 5abff0384c feat: update documentation navbar 2024-08-14 14:45:47 +02:00
Valerio Ageno cc915560b8 update documentation tuono version to v0.8.4 2024-08-14 14:41:22 +02:00
Valerio Ageno 9835a4c0d1 fix: route switch wrappers re-rendering (#23)
* fix: route switch wrappers re-rendering

* feat: update version to v0.8.4
2024-08-14 14:26:52 +02:00
Valerio Ageno 90782ae710 fix: turbo dev task config 2024-08-11 18:19:38 +02:00
Valerio Ageno 75c790dd6e refactor: create standalone router package (#22)
* refactor: create standalone router package

* fix: add jsdom to tuono-router package

* fix: remove test in tuono vite.config

* update turbo to latest

* fix: wait build before lint

* fix: router types
2024-08-11 17:14:54 +02:00
Valerio Ageno 8604858a61 fix: documentation formatting 2024-08-11 16:33:45 +02:00
Valerio Ageno d1b6162d3a Update contributing.mdx 2024-08-09 17:48:23 +02:00
Valerio Ageno a445644b47 Update contributing.mdx 2024-08-09 17:47:07 +02:00
Valerio Ageno ebb4434506 Update contributing.mdx 2024-08-09 17:40:42 +02:00
Valerio Ageno 36a53662a0 Update contributing.mdx 2024-08-09 17:40:18 +02:00
Valerio Ageno 569d95dc9c fix: routing page 2024-07-27 14:58:18 +02:00
Valerio Ageno bc4c4e03f0 feat: update documentation tuono version (#21) 2024-07-27 14:52:02 +02:00
Valerio Ageno 170c5ea098 Update static build html structures (#20)
* fix: improve static build output structure

* feat: update version to v0.8.3
2024-07-27 14:42:28 +02:00
Valerio Ageno 3fd5f166e2 fix: edit page github link 2024-07-27 11:40:24 +02:00
Valerio Ageno a2285a78a1 fix: documentation output folder 2024-07-27 11:38:18 +02:00
Valerio Ageno 1ae7f72de3 Create documentation website (#19)
* feat: scaffold documentation app

* feat: init documentation website with mantine

* feat: add theme button

* feat: setup mdx link component

* feat: setup basic documentation folder

* feat: add routing folder

* feat: scaffold homepage

* feat: refined navbar and hero

* feat: create pre mdx component

* feat: create mdx blockquote component

* feat: create code mdx component

* fix: remove HTMLProps type

* feat: create base hero page

* ci: add lint/formatting/type checking to documentation

* ci: add documentation pipeline

* fix: static build documentation

* fix: remove documentation test check

* fix: install deps outside workspace

* fix: filter prettier checks

* fix: eslint plugins

* fix: clone eslintrc

* feat: update dark theme colors

* doc: add installation page

* feat: add deploy documenation CD pipeline

* fix: update documentation bucket region

* feat: update documentation head tags

* fix: deploy website on main branch push
2024-07-27 11:33:34 +02:00
Valerio Ageno 19782a2dbe feat: update version to v0.8.2 2024-07-25 19:06:15 +02:00
Valerio Ageno b755e658f5 fix: add mdx file to watch script 2024-07-25 19:06:15 +02:00
Valerio Ageno cc0279b964 fix: typescript check 2024-07-25 13:45:29 +02:00
Valerio Ageno 099da549b5 fix: eslint check on vite config 2024-07-25 13:43:24 +02:00
339 changed files with 19751 additions and 2172 deletions
-103
View File
@@ -1,103 +0,0 @@
{
"root": true,
"reportUnusedDisableDirectives": true,
"ignorePatterns": ["**/build", "**/dist"],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "import"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/stylistic",
"plugin:import/recommended",
"plugin:import/typescript",
"prettier",
],
"env": {
"browser": true,
"es2020": true,
},
"parserOptions": {
"tsconfigRootDir": ".",
"project": true,
"sourceType": "module",
"ecmaVersion": 2020,
},
"settings": {
"import/parsers": {
"@typescript-eslint/parser": [".ts", ".tsx"],
},
"import/resolver": {
"typescript": true,
},
"react": {
"version": "detect",
},
},
"rules": {
"@typescript-eslint/array-type": "error",
"@typescript-eslint/ban-types": "error",
"@typescript-eslint/ban-ts-comment": "error",
"@typescript-eslint/consistent-type-definitions": "error",
"@typescript-eslint/consistent-type-imports": [
"error",
{ "prefer": "type-imports" },
],
"@typescript-eslint/explicit-module-boundary-types": "error",
"@typescript-eslint/method-signature-style": ["error", "property"],
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "typeParameter",
"format": ["PascalCase"],
"leadingUnderscore": "forbid",
"trailingUnderscore": "forbid",
"custom": {
"regex": "^(T|T[A-Z][A-Za-z]+)$",
"match": true,
},
},
],
"@typescript-eslint/no-empty-function": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/no-unnecessary-condition": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/no-inferrable-types": [
"error",
{ "ignoreParameters": true },
],
"import/default": "error",
"import/export": "error",
"import/namespace": "error",
"import/newline-after-import": "error",
"import/no-cycle": "error",
"import/no-duplicates": "off",
"import/no-named-as-default-member": "error",
"import/no-unused-modules": "error",
"import/order": [
"off",
{
"groups": [
"builtin",
"external",
"internal",
"parent",
"sibling",
"index",
"object",
"type",
],
},
],
"no-case-declarations": "error",
"no-empty": "error",
"no-prototype-builtins": "error",
"no-redeclare": "error",
"no-shadow": "error",
"no-undef": "off",
"sort-imports": "off",
},
}
+9
View File
@@ -1 +1,10 @@
examples/** linguist-documentation
*.css linguist-detectable=false
*.scss linguist-detectable=false
*.js linguist-detectable=false
*.jsx linguist-detectable=true
*.tsx linguist-detectable=true
*.ts linguist-detectable=true
*.rs linguist-detectable=true
*.html linguist-detectable=false
*.sh linguist-detectable=false
-23
View File
@@ -1,23 +0,0 @@
## Description
A clear and concise description of what the bug is.
## Expected behaviour
A clear and concise description of what you expected to happen.
## How to reproduce
Steps to reproduce the behavior:
## Screenshots
If applicable, add screenshots to help explain your problem.
## Tooling and environment
- Tuono version [e.g. 0.4.0]
- OS: [e.g. MacOS, Windows]
- Browser: [e.g. chrome, safari]
- Node version: [e.g. 20.0.0]
- Rust version: [e.g. 1.79.0]
- Crate version: [e.g. 1.78.0]
- Node Package Manger version: [e.g. pnpm: 9.5.0]
## Additional context
Add any other context about the problem here.
+90
View File
@@ -0,0 +1,90 @@
name: Bug report
description: File a bug report
title: '[Bug]: '
labels: ['bug']
body:
- type: textarea
id: description
attributes:
label: Description
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: expected-behaviour
attributes:
label: Expected behaviour
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
id: steps
attributes:
label: How to reproduce
description: Steps to reproduce the behavior (code, example repository)
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
validations:
required: false
- type: input
id: tuono-version
attributes:
label: Tuono version
placeholder: '[e.g. 0.4.0]'
validations:
required: false
- type: input
id: os-version
attributes:
label: OS
placeholder: '[e.g. MacOS, Windows]'
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
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context about the bug here.
validations:
required: false
-20
View File
@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
@@ -0,0 +1,35 @@
name: Feature request
description: Suggest an idea for this project
title: '[Feature request]: '
labels: ['enhancement']
body:
- type: textarea
id: description
attributes:
label: Is your feature request related to a problem? Please describe.
description: A clear and concise description of what the problem is.
placeholder: I'm always frustrated when [...]
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here.
validations:
required: false
@@ -0,0 +1,37 @@
name: Install NodeJS Dependencies
description: This is a composite GitHub Action that sets up pnpm, node and installs the project's dependencies.
inputs:
node-version:
description: 'Explicit node version. Otherwise fallback reading `.nvmrc`. Use in conjunction with matrix'
required: false
registry-url:
description: 'https://github.com/actions/setup-node?tab=readme-ov-file#usage'
required: false
default: ''
runs:
using: composite
steps:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js (via input)
if: ${{ inputs.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
registry-url: ${{ inputs.registry-url }}
cache: 'pnpm'
- name: Setup Node.js (via .nvmrc)
if: ${{ !inputs.node-version }}
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
registry-url: ${{ inputs.registry-url }}
cache: 'pnpm'
- name: Install Dependencies
shell: bash
run: pnpm install --frozen-lockfile
+3 -8
View File
@@ -1,16 +1,11 @@
## Context
## Context & Description
<!--
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.
-->
## Description
<!--
Thank you for your Pull Request. Please provide a description above and review
the requirements below.
Bug fixes and new features should include tests.
+65
View File
@@ -0,0 +1,65 @@
name: Documentation Website CI
on:
push:
branches:
- 'main'
paths:
# ⬇ Keep paths in sync with `typescript.yml`
- '.github/**'
- '*'
- '!Cargo.toml'
# ⬆ Keep paths in sync with `typescript.yml`
- 'apps/documentation/**'
pull_request:
paths:
# ⬇ Keep paths in sync with `typescript.yml`
- '.github/**'
- '*'
- '!Cargo.toml'
# ⬆ Keep paths in sync with `typescript.yml`
- 'apps/documentation/**'
jobs:
build:
name: Check build
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install NodeJS Dependencies
uses: ./.github/actions/install-node-dependencies
- name: Setup rust
uses: actions-rust-lang/setup-rust-toolchain@v1
- name: Install tuono
run: cargo install tuono@0.15.0
- name: Build project
working-directory: ./apps/documentation
run: tuono build --static
code_check:
name: Check format, lint and types
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install NodeJS Dependencies
uses: ./.github/actions/install-node-dependencies
- name: Check formatting
run: pnpm docs:format:check
- name: Lint
run: pnpm docs:lint
- name: Types
run: pnpm docs:types
@@ -0,0 +1,47 @@
name: Deploy documentation website on AWS S3
on:
push:
branches:
- 'main'
paths:
- '.github/**'
- 'apps/documentation/**'
jobs:
deploy-documentation:
name: Deploy
runs-on: ubuntu-latest
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install NodeJS Dependencies
uses: ./.github/actions/install-node-dependencies
- name: Setup rust
uses: actions-rust-lang/setup-rust-toolchain@v1
- name: Install tuono
run: cargo install tuono@0.16.0
- name: Build project
working-directory: ./apps/documentation
run: tuono build --static
- name: Deploy
uses: reggionick/s3-deploy@v4
with:
folder: apps/documentation/out/static
bucket: tuono-documentation
bucket-region: eu-west-3
dist-id: ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }}
invalidation: /
delete-removed: true
no-cache: true
private: true
files-to-include: '{.*/**,**}'
+42 -47
View File
@@ -1,78 +1,68 @@
name: Publish on npm and crates
on:
release:
types: [published]
jobs:
publish-on-npm-dry-run:
publish_npm_dry_run:
name: NPM publish (dry run)
runs-on: ubuntu-latest
steps:
- name: Checkout
- name: Checkout code
uses: actions/checkout@v4
- name: Install Node.js
uses: actions/setup-node@v4
- name: Install NodeJS Dependencies
uses: ./.github/actions/install-node-dependencies
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
- uses: pnpm/action-setup@v3
name: Install pnpm
with:
version: 8
run_install: false
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build
- name: Publish
run: pnpm publish -r --no-git-checks --dry-run
run: pnpm publish -r --no-git-checks --dry-run
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-on-crates-dry-run:
publish_crates_dry_run:
name: Crates publish (dry run)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- uses: katyo/publish-crates@v2
with:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 'stable'
- uses: katyo/publish-crates@v2
with:
path: './crates/tuono'
dry-run: true
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
check-repo: true
publish-on-npm:
needs: [publish-on-crates-dry-run, publish-on-npm-dry-run]
publish_npm:
name: NPM publish
needs: [publish_npm_dry_run, publish_crates_dry_run]
runs-on: ubuntu-latest
steps:
- name: Checkout
- name: Checkout code
uses: actions/checkout@v4
- name: Install Node.js
uses: actions/setup-node@v4
- name: Install NodeJS Dependencies
uses: ./.github/actions/install-node-dependencies
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
- uses: pnpm/action-setup@v3
name: Install pnpm
with:
version: 8
run_install: false
- name: Clone root README.md on tuono package
run: cp README.md packages/tuono/README.md
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build
@@ -81,17 +71,22 @@ jobs:
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-on-crates:
needs: [publish-on-crates-dry-run, publish-on-npm-dry-run]
publish_crates:
name: Crates publish
needs: [publish_npm_dry_run, publish_crates_dry_run]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- uses: katyo/publish-crates@v2
with:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 'stable'
- uses: katyo/publish-crates@v2
with:
path: './crates/tuono'
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
check-repo: true
+33
View File
@@ -0,0 +1,33 @@
name: Repo root CI
# All workflows are triggered based on specific paths,
# the root repository is something that is not applicable to rust nor typescript
# so it has been moved in a standalone workflow
on:
push:
branches:
- 'main'
paths:
- '.github/**'
- '*'
pull_request:
paths:
- '.github/**'
- '*'
jobs:
build-and-test:
name: Check format
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install NodeJS Dependencies
uses: ./.github/actions/install-node-dependencies
- name: Test project
run: pnpm repo:root:format:check
+46 -18
View File
@@ -2,39 +2,67 @@ name: Rust CI
on:
push:
branches:
- 'main'
paths:
- '.github/**'
- 'Cargo.toml'
- 'crates/**'
pull_request:
paths:
- '.github/**'
- 'Cargo.toml'
- 'crates/**'
env:
env:
CARGO_TERM_COLOR: always
jobs:
lint_and_fmt:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cargo fmt --all -- --check
- run: cargo clippy -- -D warnings
build_and_test:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
name: Build and test rust crates
runs-on: ubuntu-latest
name: Build and test crates on ${{ matrix.os }} with rust ${{ matrix.toolchain }}
strategy:
fail-fast: true
matrix:
os:
- 'ubuntu-latest'
- 'macos-latest'
- 'windows-latest'
toolchain:
- stable
- beta
- nightly
- 'stable'
# Test `beta` and `nightly` toolchains only on `ubuntu`
# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/running-variations-of-jobs-in-a-workflow#expanding-or-adding-matrix-configurations
include:
- toolchain: 'beta'
os: 'ubuntu-latest'
- toolchain: 'nightly'
os: 'ubuntu-latest'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- name: Checkout code
uses: actions/checkout@v4
- name: Setup rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ matrix.toolchain }}
- run: cargo build --verbose
- run: cargo test --verbose
lint_and_fmt:
name: Check format and lint rust crates
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
- run: cargo fmt --all -- --check
- run: cargo clippy -- -D warnings
+66
View File
@@ -0,0 +1,66 @@
name: Spell Checker
on:
push:
branches:
- 'main'
pull_request:
jobs:
spell_checking:
name: LanguageTool
runs-on: ubuntu-latest
permissions:
checks: write
contents: read
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
# Keep this value in order to show the error comments
# also on edited files.
fetch-depth: 2
# If the workflow is triggered by a push use check reporter
#
# If the workflow is triggered by a PR coming from the
# same repository, the author has write access so we can
# use pr-review reporter since the GITHUB_TOKEN will have review
# write permissions
#
# Otherwise use annotation reporter that do not require any
# particular permission
#
# Why this?
# https://github.com/Valerioageno/tuono/pull/137#pullrequestreview-2455455272
- name: Set reporter
id: reporter
env:
EVENT_NAME: ${{ github.event_name }}
FROM_MAIN_REPO: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
run: |
echo "EVENT_NAME: $EVENT_NAME FROM_MAIN_REPO: $FROM_MAIN_REPO"
if [ "$EVENT_NAME" == 'push' ]; then
echo "name=github-check" >> $GITHUB_OUTPUT
elif [ "$FROM_MAIN_REPO" == 'true' ]; then
echo "name=github-pr-review" >> $GITHUB_OUTPUT
else
echo "name=github-pr-annotations" >> $GITHUB_OUTPUT
fi
- name: Review dog languagetool
uses: reviewdog/action-languagetool@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# Change reviewdog reporter if you need [github-pr-check,github-check,github-pr-review].
reporter: ${{ steps.reporter.outputs.name }}
# Change reporter level if you need.
level: 'warning'
patterns: '**/*.md **/*.txt **/*.mdx'
# enabled_categories: "STYLE,PLAIN_ENGLISH,WHITESPACE_RULE,EN_QUOTES,DASH_RULE,WORD_CONTAINS_UNDERSCORE,UPPERCASE_SENTENCE_START,ARROWS,COMMA_PARENTHESIS_WHITESPACE,UNLIKELY_OPENING_PUNCTUATION,SENTENCE_WHITESPACE,EN_UNPAIRED_BRACKETS,PHRASE_REPETITION,PUNCTUATION_PARAGRAPH_END"
disabled_categories: ''
disabled_rules: ''
+48 -44
View File
@@ -2,65 +2,69 @@ name: Typescript CI
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:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
build_and_test:
name: Check build and test
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: 20
strategy:
fail-fast: true
matrix:
os:
- 'ubuntu-latest'
- 'macos-latest'
- 'windows-latest'
- name: Install pnpm
run: npm i -g pnpm
- name: Install dependencies
run: pnpm install
- name: Build project
run: pnpm build
runs-on: ${{ matrix.os }}
- name: Test project
run: pnpm test
steps:
- name: Checkout code
uses: actions/checkout@v4
fmt-lint-and-types:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
- name: Install NodeJS Dependencies
uses: ./.github/actions/install-node-dependencies
- name: Build project
run: pnpm build
- name: Test project
run: pnpm test
lint_and_fmt:
name: Check format and lint
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Install pnpm
run: npm i -g pnpm
- name: Install dependencies
run: pnpm install
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Check formatting
run: pnpm format:check
- name: Lint
run: pnpm lint
- name: Types
run: pnpm types
- name: Install NodeJS Dependencies
uses: ./.github/actions/install-node-dependencies
- name: Check formatting
run: pnpm format:check
- name: Lint
run: pnpm lint
- name: Types
run: pnpm types
+6 -3
View File
@@ -1,12 +1,12 @@
## Node related ignores
node_modules/
dist/
.turbo/
*/**/routeTree.gen.ts
pnpm-lock.yaml
examples/playground/
examples/*/pnpm-lock.yaml
## Rust related ignores
@@ -24,3 +24,6 @@ examples/playground/
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# Files, generated by the code editors
.vscode/
+1 -1
View File
@@ -1 +1 @@
v20.10.0
22.11.0
+1
View File
@@ -0,0 +1 @@
pnpm-lock.yaml
+1
View File
@@ -1,4 +1,5 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"singleQuote": true,
"trailingComma": "all"
+15 -15
View File
@@ -2,7 +2,7 @@
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
We, as members, contributors, and leaders, pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
@@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
- Focusing on what is best, not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
- The use of sexualized language or imagery, and sexual attention or
Advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
- Other conduct that could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
@@ -45,13 +45,13 @@ or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
not aligned with this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
An individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
@@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
+16 -9
View File
@@ -1,21 +1,28 @@
![](https://github.com/Valerioageno/tuono/actions/workflows/rust.yml/badge.svg)
![](https://github.com/Valerioageno/tuono/actions/workflows/typescript.yml/badge.svg)
![](https://github.com/tuono-labs/tuono/actions/workflows/rust.yml/badge.svg)
![](https://github.com/tuono-labs/tuono/actions/workflows/typescript.yml/badge.svg)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
# How to contribute to Tuono
# How to Contribute to Tuono
## Contributions
## Contributions
Any feature contribution or suggestion is strongly appreciated.
Since the current project size there isn't yet a defined way to start a discussion. Consider to [open a new issue](https://github.com/Valerioageno/tuono/issues/new)
or to reach me using my email address [valerioageno@yahoo.it](mailto:valerioageno@ahoo.it). I'm also available on twitter (X) DMs @valerioageno.
We are currently managing the tasks' prioritization in the [Road to V1](https://github.com/orgs/tuono-labs/projects/2) project. You can pick any task that you see in the `ready` column that is not already assigned.
If you want to contribute on something that is in the `backlog` column, or it hasn't been scoped yet, please drop a message in the [#general](https://discord.com/invite/khQzPa654B) discord channel so we can all have visibility of it.
Consider [opening a new issue](https://github.com/tuono-labs/tuono/issues/new/choose) if you find a bug.
## Bugs
**Did you find a bug?**
- Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/Valerioageno/tuono/issues).
- If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/Valerioageno/tuono/issues/new). Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behavior that is not occurring.
- Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/tuono-labs/tuono/issues).
- If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/tuono-labs/tuono/issues/new/choose). Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behavior that is not occurring.
**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.
- 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
+6 -3
View File
@@ -6,7 +6,10 @@ members = [
"crates/tuono_lib_macros",
]
exclude = [
"examples/mdx",
"examples/tuono",
"examples/tutorial"
"apps/documentation",
"examples/with-mdx",
"examples/tuono-app",
"examples/tuono-api",
"examples/tuono-tutorial",
"benches/tuono"
]
+45 -64
View File
@@ -1,98 +1,79 @@
<p align="center">
<img src="https://raw.githubusercontent.com/Valerioageno/tuono/main/assets/logo.png" width="200px">
</p>
<h1 align="center">Tuono<br>The react/rust fullstack framework</h1>
<div align="center">
<img src="https://github.com/Valerioageno/tuono/actions/workflows/rust.yml/badge.svg" />
<img src="https://github.com/Valerioageno/tuono/actions/workflows/typescript.yml/badge.svg" />
</div>
[Documentation](https://tuono.dev) | [Tutorial](https://tuono.dev/documentation/tutorial) |
[Discord](https://discord.com/invite/khQzPa654B) | [✨Contributing](https://tuono.dev/documentation/contributing)
<br>
<br>
# Tuono
<img align="right" src="https://raw.githubusercontent.com/tuono-labs/tuono/main/assets/logo.png" width="160px">
Tuono (Italian word for "thunder", pronounced /2 Oh No/).
![](https://github.com/tuono-labs/tuono/actions/workflows/rust.yml/badge.svg)
![](https://github.com/tuono-labs/tuono/actions/workflows/typescript.yml/badge.svg)
**Tuono is a full-stack web framework for building React applications using Rust as the backend with
a strong focus on usability and performance.**
Tuono (Italian word for "thunder", pronounced /2 Oh No/).
Why Tuono? Just a badass name.
> Check out the [tutorial](https://github.com/Valerioageno/tuono/blob/main/docs/tutorial.md) to get started.
If you have experience with [Next.js](https://nextjs.org/) you will feel home here.
Some of its features are:
- 🟦 Native Typescript
- 🌐 Next.js like Routing
- 🍭 CSS/SCSS modules
- 🧬 Server Side Rendering
- 🔥 Hot Module Reload
## 📖 Documentation
The [documentation](https://tuono.dev/documentation) is available on
[tuono.dev](https://tuono.dev/).
## Introduction
**NodeJs/Deno/Bun are the only runtimes that allow a React app to be fullstack right? (no)**
**NodeJs/Deno/Bun are the only runtimes that allow a React app to be full-stack right? (no)**
Tuono is a fullstack React framework with the server side written in Rust.
Because of this Tuono is extremely fast and the requests are handled by multithreaded Rust server.
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 an hard language then writing server side code is hard as well right? (no again)**
**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 with a separate file alongside the React route. The routing is handled
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.
## Features
**How is Tuono different from Next.js?**
- 🟦 Typescript
- 🌐 Routing
- 🔥 Hot Module Reload
- 🍭 CSS modules
- 🧬 Server Side Rendering
- 🧵 Multi thread backend
- ⌨️ MDX support
- ⚙️ Build optimizations
- Custom APIs*
- Image optimization*
- Server streamed content*
> *Development in progress
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)).
## Getting started
As already mentioned above I strongly suggest you to take a look at the
[tutorial](https://github.com/Valerioageno/tuono/blob/main/docs/tutorial.md).
Tuono is the CLI that provides all the needed commands to handle the fullstack project.
To download it is required [cargo](https://doc.rust-lang.org/cargo/) which is the [rust](https://www.rust-lang.org/)
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.
Then run `cargo install tuono`.
To list all the available commands run `tuono -h`
To list all the available commands, run `tuono -h`
To create a new project run `tuono new [NAME]` (optionally you can pass the `--template` (or `-t`) flag - check the
[examples](https://github.com/Valerioageno/tuono/tree/main/examples) folder).
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).
Then to run the local development environment run inside the project folder `tuono dev`
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 will be ready to be deployed just run `tuono build` to create the final React assets
and to set the server project in the `production` mode.
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`.
## Requirements
- rust
- cargo
- node
- npm/pnpm/yarn*
> yarn [pnp](https://yarnpkg.com/features/pnp) is not supported yet
## Folder structure
```
├── package.json
├── public
├── src
│ ├── routes
│ └── styles
├── Cargo.toml
├── README.md
└── tsconfig.json
```
## Contributing
Any help or suggestion will be appreciated and encouraged.
Check the [✨Contributing](https://tuono.dev/documentation/contributing) page
## License
+1
View File
@@ -0,0 +1 @@
# Stadalone apps folder
+15
View File
@@ -0,0 +1,15 @@
[package]
name = "tuono"
version = "0.0.1"
edition = "2021"
[[bin]]
name = "tuono"
path = ".tuono/main.rs"
[dependencies]
tuono_lib = "0.15.0"
glob = "0.3.1"
time = { version = "0.3", features = ["macros"] }
serde = { version = "1.0.202", features = ["derive"] }
+7
View File
@@ -0,0 +1,7 @@
# Tuono starter
This is the starter tuono project. To download it run in your terminal:
```shell
$ tuono new [NAME]
```
+32
View File
@@ -0,0 +1,32 @@
{
"name": "documentation",
"description": "The react/rust fullstack framework documentation",
"version": "0.0.1",
"private": true,
"type": "module",
"scripts": {
"lint": "eslint .",
"format": "prettier -u --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",
"@mdx-js/react": "3.1.0",
"@tabler/icons-react": "3.22.0",
"clsx": "2.1.1",
"react": "18.3.1",
"react-dom": "18.3.1",
"tuono": "npm:tuono@0.16.0"
},
"devDependencies": {
"@mdx-js/rollup": "3.1.0",
"@types/react": "18.3.13",
"@types/react-dom": "18.3.0",
"postcss": "8.4.49",
"postcss-preset-mantine": "1.17.0",
"postcss-simple-vars": "7.0.1"
}
}
+14
View File
@@ -0,0 +1,14 @@
export default {
plugins: {
'postcss-preset-mantine': {},
'postcss-simple-vars': {
variables: {
'mantine-breakpoint-xs': '36em',
'mantine-breakpoint-sm': '48em',
'mantine-breakpoint-md': '62em',
'mantine-breakpoint-lg': '75em',
'mantine-breakpoint-xl': '88em',
},
},
},
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@@ -0,0 +1,18 @@
{
"polyfills": [
{
"identifier": "HTMLElement",
"import": {
"package": "@lit-labs/ssr-dom-shim",
"name": "HTMLElement"
}
},
{
"identifier": "customElements",
"import": {
"package": "@lit-labs/ssr-dom-shim",
"name": "customElements"
}
}
]
}
@@ -0,0 +1,19 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}
@@ -0,0 +1,84 @@
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>
)
}
@@ -0,0 +1,5 @@
import Breadcrumbs, { BreadcrumbElement } from './breadcrumbs'
export default Breadcrumbs
export { BreadcrumbElement as Element }
@@ -0,0 +1,24 @@
import type { JSX } from 'react'
import { Button } from '@mantine/core'
import { IconEdit } from '@tabler/icons-react'
import { useRouter } from 'tuono'
const GITHUB_URL =
'https://github.com/tuono-labs/tuono/tree/main/apps/documentation/src/routes'
export default function EditPage(): JSX.Element {
const { pathname } = useRouter()
return (
<Button
p={0}
mt={60}
component="a"
variant="transparent"
leftSection={<IconEdit />}
target="_blank"
href={GITHUB_URL.concat(pathname).concat('.mdx')}
>
Edit page
</Button>
)
}
@@ -0,0 +1,3 @@
import EditPage from './edit-page'
export default EditPage
@@ -0,0 +1,54 @@
import type { JSX } from 'react'
import {
Button,
Center,
Container,
CopyButton,
Group,
rem,
Text,
Title,
} from '@mantine/core'
import { IconCopy, IconCheck } from '@tabler/icons-react'
import { Link } from 'tuono'
export default function Hero(): JSX.Element {
return (
<Container size={1100} my={100}>
<Center>
<Title order={1}>Superfast fullstack react framework</Title>
</Center>
<Center mt={50}>
<Text fz="18px">
The technologies we love seamlessly working together to unleash the
<strong> highest web performance</strong> ever met on React
</Text>
</Center>
<Center mt={50}>
<Group>
<Button component={Link} href="/documentation" size="lg">
Get Started
</Button>
<CopyButton value="cargo install tuono">
{({ copied, copy }) => (
<Button
onClick={copy}
size="lg"
style={{ border: 'solid 1px var(--mantine-color-violet-1)' }}
color="gray"
leftSection="$ cargo install tuono"
rightSection={
copied ? (
<IconCheck style={{ width: rem(20) }} />
) : (
<IconCopy style={{ width: rem(20) }} />
)
}
/>
)}
</CopyButton>
</Group>
</Center>
</Container>
)
}
@@ -0,0 +1,3 @@
import Hero from './hero'
export default Hero
@@ -0,0 +1,3 @@
import MdxProvider from './mdx-provider'
export default MdxProvider
@@ -0,0 +1,6 @@
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} />
}
@@ -0,0 +1,3 @@
import MdxCode from './mdx-code'
export default MdxCode
@@ -0,0 +1,8 @@
import type { JSX, HTMLAttributes } from 'react'
import { Code } from '@mantine/core'
export default function MdxCode(
props: HTMLAttributes<HTMLPreElement>,
): JSX.Element {
return <Code {...props} style={{ fontSize: 'inherit' }} />
}
@@ -0,0 +1,3 @@
import MdxLink from './mdx-link'
export default MdxLink
@@ -0,0 +1,36 @@
import type { JSX, AnchorHTMLAttributes } from 'react'
import { Button } from '@mantine/core'
import { Link } from 'tuono'
import { IconExternalLink } from '@tabler/icons-react'
export default function MdxLink(
props: AnchorHTMLAttributes<HTMLAnchorElement>,
): JSX.Element {
if (props.href?.startsWith('http') || props.href?.startsWith('mailto')) {
return (
<Button
component="a"
{...props}
target="_blank"
rightSection={
<IconExternalLink size="16px" style={{ marginLeft: -5 }} />
}
variant="transparent"
style={{ height: '20px' }}
mt={-2}
p={0}
/>
)
}
return (
<Button
component={Link}
{...props}
target="_blank"
variant="transparent"
style={{ height: '20px' }}
mt={-2}
p={0}
/>
)
}
@@ -0,0 +1,3 @@
import MdxPre from './mdx-pre'
export default MdxPre
@@ -0,0 +1,5 @@
.pre {
code {
font-size: 14px;
}
}
@@ -0,0 +1,24 @@
import type { JSX } from 'react'
import { CodeHighlight } from '@mantine/code-highlight'
import styles from './mdx-pre.module.css'
interface PreProps {
children: {
props: {
children: string
className?: string
}
}
}
export default function MdxPre({ children }: PreProps): JSX.Element {
return (
<CodeHighlight
className={styles.pre}
code={children.props.children || ''}
style={{ borderRadius: 8, fontWeight: 100 }}
language={children.props.className?.replace('language-', '')}
/>
)
}
@@ -0,0 +1,38 @@
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'
interface MdxProviderProps {
children: ReactNode
}
export default function MdxProvider({
children,
}: MdxProviderProps): JSX.Element {
return (
<MDXProvider
components={{
a: MdxLink,
// @ts-expect-error: useless finding the correct props types
pre: MdxPre,
blockquote: MdxQuote,
code: MdxCode,
h1: h(1),
h2: h(2),
h3: h(3),
h4: h(4),
h5: h(5),
h6: h(6),
strong: MdxBold,
}}
>
{children}
</MDXProvider>
)
}
@@ -0,0 +1,3 @@
import MdxQuote from './mdx-quote'
export default MdxQuote
@@ -0,0 +1,21 @@
import type { JSX, HTMLAttributes } from 'react'
import { Blockquote, Space } from '@mantine/core'
export default function MdxQuote(
props: HTMLAttributes<HTMLQuoteElement>,
): JSX.Element {
return (
<>
<Blockquote
color="violet"
py={1}
px={20}
mt={30}
iconSize={30}
{...props}
style={{ borderRadius: 8 }}
/>
<Space h="md" />
</>
)
}
@@ -0,0 +1,5 @@
import MdxTitle, { h } from './mdx-title'
export default MdxTitle
export { h }
@@ -0,0 +1,21 @@
import type { JSX } from 'react'
import { Title, type TitleProps } from '@mantine/core'
export default function MdxTitle(props: TitleProps): JSX.Element {
return (
<Title
data-heading={props.children}
data-order={props.order}
mt={20}
{...props}
// eslint-disable-next-line @typescript-eslint/no-base-to-string
id={String(props.children ?? '')
.toLowerCase()
.replaceAll(' ', '-')}
/>
)
}
export const h =
(order: 1 | 2 | 3 | 4 | 5 | 6) =>
(props: TitleProps): JSX.Element => <MdxTitle order={order} {...props} />
@@ -0,0 +1,3 @@
import MetaTags from './meta-tags'
export default MetaTags
@@ -0,0 +1,46 @@
import type { ReactNode } from 'react'
import { Head } from 'tuono'
interface MetaTagsProps {
title: string
description?: string
type?: 'website' | 'article' | 'book' | 'video.movie' | 'music.song'
canonical: string
}
export default function MetaTags({
title,
description,
type = 'article',
canonical,
}: MetaTagsProps): ReactNode {
return (
<Head>
<title>{title}</title>
<link rel="canonical" href={canonical} />
<meta
name="description"
content={
description ??
'The technologies we love seamlessly working together to unleash the highest web performance ever met on React'
}
/>
<meta
name="keywords"
content="ReactJs, Typescript, Rust, JavaScript, Fullstack framework, Web development"
/>
<meta property="og:title" content={title} />
<meta property="og:type" content={type} />
<meta property="og:image" content="https://tuono.dev/og-cover.png" />
<meta property="og:url" content={canonical} />
<meta property="og:description" content={description} />
<meta property="og:site_name" content="Tuono" />
<meta property="og:locale" content="en_US" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@tuono_dev" />
<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,35 @@
import type { JSX } from 'react'
import { Flex, ActionIcon, Group } from '@mantine/core'
import { IconBrandGithub, IconBrandDiscord } from '@tabler/icons-react'
import ThemeBtn from '../theme-btn'
export default function Actions(): JSX.Element {
return (
<Flex gap={8}>
<Group gap={8}>
<ActionIcon
variant="default"
size="lg"
aria-label="Check the project on github"
href="https://github.com/tuono-labs/tuono"
target="_blank"
component="a"
>
<IconBrandGithub />
</ActionIcon>
<ActionIcon
variant="default"
size="lg"
aria-label="Join the Tuono's community on Discord!"
href="https://discord.com/invite/khQzPa654B"
target="_blank"
component="a"
>
<IconBrandDiscord />
</ActionIcon>
</Group>
<ThemeBtn />
</Flex>
)
}
@@ -0,0 +1,3 @@
import Navbar from './navbar'
export default Navbar
@@ -0,0 +1,33 @@
import type { JSX } from 'react'
import { AppShell, Box, Burger, Button, Flex } from '@mantine/core'
import { Link } from 'tuono'
import Actions from './actions'
interface NavbarProps {
toggle: () => void
}
export default function Navbar({ toggle }: NavbarProps): JSX.Element {
return (
<AppShell.Header p="sm">
<Flex justify="space-between">
<Button
component={Link}
href="/"
variant="transparent"
p={0}
fz={28}
hiddenFrom="sm"
>
Tuono
</Button>
<Box />
<Flex align="center" gap={8}>
<Actions />
<Burger onClick={toggle} hiddenFrom="sm" size="sm" />
</Flex>
</Flex>
</AppShell.Header>
)
}
@@ -0,0 +1,3 @@
import NavigationButtons from './navigation-buttons'
export default NavigationButtons
@@ -0,0 +1,63 @@
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'
interface NavigationButton {
href: string
title: string
}
interface NavigationButtonsProps {
prev?: NavigationButton
next?: NavigationButton
}
export default function NavigationButtons({
prev,
next,
}: NavigationButtonsProps): JSX.Element {
return (
<Flex mt={50} gap={10}>
{prev && <NavigationBtn type="prev" {...prev} />}
{next && <NavigationBtn type="next" {...next} />}
</Flex>
)
}
interface NavigationButtonProps extends NavigationButton {
type: 'next' | 'prev'
}
const NavigationBtn = ({
type,
title,
href,
}: NavigationButtonProps): JSX.Element => {
const heading = type === 'next' ? 'Next' : 'Previous'
const textAlign = type === 'next' ? 'left' : 'right'
const variant = type === 'next' ? 'filled' : 'outline'
return (
<Button
component={Link}
fullWidth
variant={variant}
href={href}
justify="space-between"
h="auto"
rightSection={type === 'next' && <IconArrowRight />}
leftSection={type === 'prev' && <IconArrowLeft />}
p="20"
>
<Box>
<Title component="span" display="block" order={4} style={{ textAlign }}>
{heading}
</Title>
<Text component="span" display="block" style={{ textAlign }}>
{title}
</Text>
</Box>
</Button>
)
}
@@ -0,0 +1,265 @@
import type { ReactNode } from 'react'
interface SidebarElementBase<T extends string> {
type: T
}
type SidebarDivider = SidebarElementBase<'divider'>
interface SidebarLink extends SidebarElementBase<'element'> {
label: string
href: string
children?: Array<SidebarLink>
leftIcon?: ReactNode
}
interface SidebarTitle extends SidebarElementBase<'title'> {
label: string
}
type SidebarElement = SidebarDivider | SidebarLink | SidebarTitle
export const sidebarElements: Array<SidebarElement> = [
{
type: 'element',
label: 'Home',
href: '/',
},
{
type: 'element',
label: 'Getting started',
href: '#focus',
children: [
{
type: 'element',
label: 'Installation',
href: '/documentation/installation',
},
{
type: 'element',
label: 'How is tuono different?',
href: '/documentation/how-is-tuono-different',
},
],
},
{
type: 'element',
label: 'Tutorial',
href: '#focus',
children: [
{
type: 'element',
href: '/documentation/tutorial',
label: 'Intro',
},
{
type: 'element',
href: '/documentation/tutorial/development-setup',
label: 'Development setup',
},
{
type: 'element',
href: '/documentation/tutorial/api-fetching',
label: 'API fetching',
},
{
type: 'element',
href: '/documentation/tutorial/components',
label: 'Components',
},
{
type: 'element',
href: '/documentation/tutorial/dynamic-routes',
label: 'Dynamic routes',
},
{
type: 'element',
href: '/documentation/tutorial/error-handling',
label: 'Error handling',
},
{
type: 'element',
href: '/documentation/tutorial/seo',
label: 'SEO and meta tags',
},
{
type: 'element',
href: '/documentation/tutorial/redirections',
label: 'Redirections',
},
{
type: 'element',
href: '/documentation/tutorial/production',
label: 'Production build',
},
{
type: 'element',
href: '/documentation/tutorial/conclusion',
label: 'Conclusion',
},
],
},
{ type: 'divider' },
{ type: 'title', label: 'Overview' },
{
type: 'element',
label: 'Routing',
href: '#focus',
children: [
{
type: 'element',
label: 'Defining routes',
href: '/documentation/routing/defining-routes',
},
{
type: 'element',
label: '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: 'Dynamic routes',
href: '/documentation/routing/dynamic-routes',
},
{
type: 'element',
label: 'Layouts',
href: '/documentation/routing/layouts',
},
{
type: 'element',
label: 'Redirecting',
href: '/documentation/routing/redirecting',
},
],
},
{
type: 'element',
label: 'Rendering',
href: '#focus',
children: [
{
type: 'element',
label: 'Server side rendering',
href: '/documentation/rendering/server-side-rendering',
},
{
type: 'element',
label: 'Static site rendering',
href: '/documentation/rendering/static-site-rendering',
},
],
},
{
type: 'element',
label: 'Styles',
href: '#focus',
children: [
{
type: 'element',
label: 'CSS modules',
href: '/documentation/styles/css-modules',
},
],
},
{
type: 'element',
label: 'Integrations',
href: '#focus',
children: [
{
type: 'element',
label: 'MDX',
href: '/documentation/integrations/mdx',
},
],
},
{
type: 'element',
label: 'Core concepts',
href: '#focus',
children: [
{
type: 'element',
label: 'Multithreading',
href: '/documentation/core-concepts/multithreading',
},
],
},
{ type: 'divider' },
{ type: 'title', label: 'API reference' },
{
type: 'element',
label: 'Components',
href: '#focus',
children: [
{
type: 'element',
label: 'Head',
href: '/documentation/components/head',
},
{
type: 'element',
label: 'Link',
href: '/documentation/components/link',
},
],
},
{
type: 'element',
label: 'Hooks',
href: '#focus',
children: [
{
type: 'element',
label: 'useRouter',
href: '/documentation/hooks/use-router',
},
],
},
{
type: 'element',
label: 'CLI',
href: '/documentation/cli',
},
{
type: 'element',
label: 'Application state',
href: '/documentation/application-state',
},
{
type: 'element',
label: 'tuono.config.ts',
href: '/documentation/configuration',
},
{ type: 'divider' },
{
type: 'element',
label: 'Contributing',
href: '#focus',
leftIcon: '✨',
children: [
{
type: 'element',
label: 'Guildelines',
href: '/documentation/contributing',
},
{
type: 'element',
label: 'Local development',
href: '/documentation/contributing/local-development',
},
],
},
]
@@ -0,0 +1,3 @@
import Sidebar from './sidebar'
export default Sidebar
@@ -0,0 +1,17 @@
.link {
border-radius: 8px;
margin-top: 0.25rem;
line-height: 1rem;
font-weight: 500;
transition: 0.3s;
}
.link span {
font-size: 14px !important;
color: var(--mantine-color-sidebar-gray);
}
.link:hover span,
.active span {
color: var(--mantine-color-sidebar-text-hover);
}
@@ -0,0 +1,42 @@
import type { JSX, ReactNode } from 'react'
import { NavLink, type NavLinkProps } from '@mantine/core'
import clsx from 'clsx'
import { Link, useRouter } from 'tuono'
import { IconChevronRight } from '@tabler/icons-react'
import styles from './sidebar-link.module.css'
interface SidebarLinkProps {
label: string
href: string
onClick?: () => void
children?: ReactNode
}
export default function SidebarLink(
props: SidebarLinkProps & NavLinkProps,
): JSX.Element {
const { pathname } = useRouter()
const isActive = pathname === props.href
const internalProps = {
active: isActive,
className: clsx(styles.link, isActive && styles.active),
rightSection: props.children && (
<IconChevronRight
size="1.2rem"
stroke={1.5}
className="mantine-rotate-rtl"
/>
),
autoContrast: true,
...props,
}
if (props.href.startsWith('#')) {
return <NavLink component="button" {...internalProps} />
}
return <NavLink component={Link} {...internalProps} />
}
@@ -0,0 +1,106 @@
import type { JSX } from 'react'
import {
AppShell,
Badge,
Flex,
Divider,
Title,
Button,
ScrollArea,
Text,
} from '@mantine/core'
import { IconX } from '@tabler/icons-react'
import { useMediaQuery } from '@mantine/hooks'
import { sidebarElements } from './config'
import SidebarLink from './sidebar-link'
interface SidebarProps {
close: () => void
}
function SidebarHeader({ close }: SidebarProps): JSX.Element {
const isSm = useMediaQuery('(min-width: 48em)')
return (
<AppShell.Section>
<Flex mb={20} w="100%" justify="space-between">
<Flex
gap={10}
align="center"
w={isSm ? '100%' : 'auto'}
justify="center"
>
<Title order={3}>Tuono</Title>
<Badge mt={4} size="xs" variant="outline">
Docs
</Badge>
</Flex>
<Button onClick={close} hiddenFrom="sm" variant="transparent" p="0">
<IconX />
</Button>
</Flex>
</AppShell.Section>
)
}
function SidebarElements({ close }: SidebarProps): JSX.Element {
return (
<AppShell.Section component={ScrollArea}>
{sidebarElements.map((el, i) => {
if (el.type === 'divider') {
return <Divider my="md" mx={10} />
}
if (el.type === 'title') {
return (
<Text
size="xs"
fw={700}
fz={12}
pl={12}
py={5}
children={el.label}
/>
)
}
if (el.children?.length) {
return (
<SidebarLink
href={el.href}
label={el.label}
key={i}
leftSection={el.leftIcon}
>
{el.children.map((child, index) => (
<SidebarLink
href={child.href}
label={child.label}
key={index}
onClick={close}
/>
))}
</SidebarLink>
)
}
return (
<SidebarLink
href={el.href}
label={el.label}
onClick={close}
key={i}
/>
)
})}
</AppShell.Section>
)
}
export default function Sidebar({ close }: SidebarProps): JSX.Element {
return (
<AppShell.Navbar p="md">
<SidebarHeader close={close} />
<SidebarElements close={close} />
</AppShell.Navbar>
)
}
@@ -0,0 +1,38 @@
/**
* Component inspired by: https://github.com/mantinedev/mantine/tree/master/apps/mantine.dev/src/components/TableOfContents
*/
export interface Heading {
depth: number
content: string
id: string
getNode: () => HTMLHeadingElement
}
function getHeadingsData(headings: Array<HTMLHeadingElement>): Array<Heading> {
const result: Array<Heading> = []
for (const heading of headings) {
if (heading.id) {
result.push({
depth: parseInt(heading.getAttribute('data-order') || '1', 10),
content: heading.getAttribute('data-heading') || '',
id: heading.id,
getNode: () =>
document.getElementById(heading.id) as HTMLHeadingElement,
})
}
}
return result
}
export function getHeadings(): Array<Heading> {
const root = document.getElementById('mdx-root')
console.log(root)
if (!root) {
return []
}
return getHeadingsData(Array.from(root.querySelectorAll('[data-heading]')))
}
@@ -0,0 +1,6 @@
/*
* Component inspired by: https://github.com/mantinedev/mantine/tree/master/apps/mantine.dev/src/components/TableOfContents
*/
import { TableOfContents } from './table-of-content'
export default TableOfContents
@@ -0,0 +1,120 @@
/*
* Component inspired by: https://github.com/mantinedev/mantine/tree/master/apps/mantine.dev/src/components/TableOfContents
*/
.wrapper {
padding-left: var(--mantine-spacing-md);
position: sticky;
top: var(--mantine-spacing-xl);
right: 0;
padding-top: 55px;
flex: 0 0 calc(var(--docs-table-of-contents-width) - 20px);
width: 200px;
@mixin rtl {
padding-left: 0;
padding-right: var(--mantine-spacing-md);
right: auto;
left: 0;
}
&[data-with-tabs] {
padding-top: 0;
top: calc(var(--mantine-spacing-xl) + 60px);
}
}
.inner {
padding-bottom: var(--mantine-spacing-xl);
padding-left: var(--mantine-spacing-md);
display: flex;
flex-direction: column;
justify-content: space-between;
@mixin rtl {
padding-left: 0;
padding-right: var(--mantine-spacing-md);
}
}
.link {
display: block;
border-left: 1px solid transparent;
padding: 8px var(--mantine-spacing-md);
margin-left: -1px;
padding-left: calc(var(--toc-link-offset) * var(--mantine-spacing-lg));
border-top-right-radius: var(--mantine-radius-sm);
border-bottom-right-radius: var(--mantine-radius-sm);
@mixin light {
color: var(--mantine-color-gray-7);
}
@mixin dark {
color: var(--mantine-color-dark-1);
}
@mixin rtl {
border-left: 0;
border-right: 1px solid transparent;
margin-left: 0;
margin-right: -1px;
border-top-left-radius: var(--mantine-radius-sm);
border-bottom-left-radius: var(--mantine-radius-sm);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&[data-active] {
border-color: var(--mantine-color-violet-5);
@mixin light {
color: var(--mantine-color-violet-8);
background-color: var(--mantine-color-violet-0);
}
@mixin dark {
color: var(--mantine-color-violet-1);
background-color: #534a6d;
}
}
}
.header {
display: flex;
align-items: center;
margin-bottom: var(--mantine-spacing-md);
}
.title {
margin-left: var(--mantine-spacing-md);
@mixin rtl {
margin-left: 0;
margin-right: var(--mantine-spacing-md);
}
}
.items {
border-left: 1px solid;
@mixin light {
border-color: var(--mantine-color-gray-3) !important;
}
@mixin dark {
border-color: var(--mantine-color-dark-4) !important;
}
@mixin rtl {
border-left: 0;
border-right: 1px solid;
@mixin light {
border-color: var(--mantine-color-gray-3) !important;
}
@mixin dark {
border-color: var(--mantine-color-dark-4) !important;
}
}
}
@@ -0,0 +1,115 @@
/*
* Component inspired by: https://github.com/mantinedev/mantine/tree/master/apps/mantine.dev/src/components/TableOfContents
*/
import type { JSX } from 'react'
import { useEffect, useRef, useState } from 'react'
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
}
function getActiveElement(rects: Array<DOMRect>): number {
if (rects.length === 0) {
return -1
}
const closest = rects.reduce(
(acc, item, index) => {
if (Math.abs(acc.position) < Math.abs(item.y)) {
return acc
}
return {
index,
position: item.y,
}
},
{ index: 0, position: rects[0].y },
)
return closest.index
}
export function TableOfContents({
withTabs,
}: TableOfContentsProps): JSX.Element | null {
const [active, setActive] = useState(0)
const [headings, setHeadings] = useState<Array<Heading>>([])
const headingsRef = useRef<Array<Heading>>([])
const router = useRouter()
const filteredHeadings = headings.filter((heading) => heading.depth > 1)
const handleScroll = (): void => {
setActive(
getActiveElement(
headingsRef.current.map((d) => d.getNode().getBoundingClientRect()),
),
)
}
useEffect(() => {
const _headings = getHeadings()
headingsRef.current = _headings
setHeadings(_headings)
setActive(
getActiveElement(
_headings.map((d) => d.getNode().getBoundingClientRect()),
),
)
window.addEventListener('scroll', handleScroll)
return (): void => window.removeEventListener('scroll', handleScroll)
}, [router.pathname])
if (filteredHeadings.length === 0) {
return null
}
const items = filteredHeadings.map((heading, index) => (
<Text
key={heading.id}
component={Link}
fz="sm"
p={10}
className={classes.link}
mod={{ active: active === index }}
href={`#${heading.id}`}
__vars={{ '--toc-link-offset': `${heading.depth - 1}` }}
>
{heading.content}
</Text>
))
return (
<Box
component="nav"
mod={{ 'with-tabs': withTabs }}
className={classes.wrapper}
>
<div className={classes.inner}>
<div>
<div className={classes.header}>
<IconList
style={{ width: rem(20), height: rem(20) }}
stroke={1.5}
/>
<Text className={classes.title}>Table of contents</Text>
</div>
<ScrollArea.Autosize
mah={`calc(100vh - ${rem(140)})`}
type="never"
offsetScrollbars
>
<div className={classes.items}>{items}</div>
</ScrollArea.Autosize>
</div>
</div>
</Box>
)
}
@@ -0,0 +1,3 @@
import ThemeBtn from './theme-btn'
export default ThemeBtn
@@ -0,0 +1,24 @@
.icon {
width: 22px;
height: 22px;
}
.dark {
@mixin dark {
display: none;
}
@mixin light {
display: block;
}
}
.light {
@mixin light {
display: none;
}
@mixin dark {
display: block;
}
}
@@ -0,0 +1,31 @@
import type { JSX } from 'react'
import {
ActionIcon,
useMantineColorScheme,
useComputedColorScheme,
} from '@mantine/core'
import { IconSun, IconMoon } from '@tabler/icons-react'
import cx from 'clsx'
import classes from './theme-btn.module.css'
export default function ThemeBtn(): JSX.Element {
const { setColorScheme } = useMantineColorScheme()
const computedColorScheme = useComputedColorScheme('light', {
getInitialValueInEffect: true,
})
return (
<ActionIcon
onClick={() =>
setColorScheme(computedColorScheme === 'light' ? 'dark' : 'light')
}
variant="default"
size="lg"
aria-label="Toggle color scheme"
>
<IconSun className={cx(classes.icon, classes.light)} stroke={1.5} />
<IconMoon className={cx(classes.icon, classes.dark)} stroke={1.5} />
</ActionIcon>
)
}
+5
View File
@@ -0,0 +1,5 @@
// declaration.d.ts
declare module '*.css' {
const CSSModule: Record<string, string>
export default CSSModule
}
+136
View File
@@ -0,0 +1,136 @@
import type { ReactNode, JSX } from 'react'
import {
ColorSchemeScript,
createTheme,
MantineProvider,
AppShell,
Container,
} 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 '@mantine/core/styles.css'
import '@mantine/code-highlight/styles.css'
interface RootRouteProps {
children: ReactNode
}
const theme = createTheme({
primaryColor: 'violet',
primaryShade: { light: 6, dark: 9 },
fontFamily: 'Inter',
respectReducedMotion: true,
radius: {
xs: '8px',
lg: '8px',
xl: '8px',
md: '8px',
sm: '8px',
},
fontSizes: {
// 'xs' | 'sm' | 'md' | 'lg' | 'xl'
xs: '16px',
sm: '16px',
},
colors: {
dark: [
'#d5d7e0',
'#acaebf',
'#8c8fa3',
'#666980',
'#4d4f66',
'#34354a',
'#2b2c3d',
'#1d1e30',
'#0c0d21',
'#01010a',
],
},
headings: {
sizes: {
h1: {
fontSize: '48px',
},
},
},
other: {
sidebarGrayLight: '#495057',
sidebarGrayDark: '#adb5bd',
sidebarTextHoverLight: '#212529',
sidebarTextHoverDark: '#f8f9fa',
},
})
const resolver: CSSVariablesResolver = (th) => ({
variables: {},
light: {
'--mantine-color-sidebar-gray': th.other.sidebarGrayLight as string,
'--mantine-color-sidebar-text-hover': th.other
.sidebarTextHoverLight as string,
},
dark: {
'--mantine-color-sidebar-gray': th.other.sidebarGrayDark as string,
'--mantine-color-sidebar-text-hover': th.other
.sidebarTextHoverDark as string,
},
})
export default function RootRoute({ children }: RootRouteProps): JSX.Element {
const [opened, { toggle }] = useDisclosure()
return (
<>
<Head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
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>
</>
)
}
@@ -0,0 +1,55 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Application state"
canonical="https://tuono.dev/documentation/application-state"
description="Learn how to add features to your Tuono application"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Application state' }]} />
# Application state
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
they will be automatically available in all the handlers you will define across the application.
```rs
// src/app.rs
#[derive(Clone)]
pub struct ApplicationState {
pub website_name: String,
pub base_path: String
}
pub fn main() -> ApplicationState {
let website_name = "tuono".to_string();
let base_path = "http://localhost:3000".to_string();
ApplicationState {
website_name,
base_path
}
}
```
> For the sake of simplicity here we just enable a `String` but you can add Database connections or
> HTTP clients (take a look [here](/documentation/tutorial/api-fetching) for an example with an HTTP client).
Now the `ApplicationState` is available on all the handlers as following:
```rs
// src/routes/index.rs
#[tuono_lib::handler]
// The first argument always is the Request
// The ApplicationState arguments are optional. You can use just the ones you need
// to use in the handler (with no specific order).
async fn my_handler(req: Request, website_name: String) -> Response {
...
}
```
@@ -0,0 +1,44 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - CLI"
canonical="https://tuono.dev/documentation/cli"
description="Tuono is the CLI that provides all the needed commands to handle the full-stack project."
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'CLI' }]} />
# CLI
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
> `tuono` CLI yet.
To list all the available commands, run `tuono -h`.
```bash
The React/Rust full-stack framework
Usage: tuono <COMMAND>
Commands:
dev Start the development environment
build Build the production assets
new Scaffold a new project
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
```
To create a new project, run `tuono new [NAME]` (optionally you can pass the --template (or -t) flag - check the examples' folder).
Then to run the local development environment run inside the project folder `tuono dev`
Finally, when the project will be ready to be deployed just run `tuono build` to create the final React assets and to set the server project in the production mode.
Now to execute it, just run `cargo run --release`.
@@ -0,0 +1,14 @@
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
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Link"
canonical="https://tuono.dev/documentation/components/link"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Components' }]} />
# Link
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - tuono.config.ts"
canonical="https://tuono.dev/documentation/configuration"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Configuration' }]} />
# Configuration
TODO
@@ -0,0 +1,48 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Contributing"
canonical="https://tuono.dev/documentation/contributing"
description="The project is massive - if you like it, do consider contributing!"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: '✨ Contributing' }]} />
# Contributing
## TL;DR
The project is massive - if you like it, do consider contributing!
## Getting started
The `tuono` project can mostly be split into the following subdomains:
- The CLI
- The Rust backend
- The React frontend
- The documentation website (which is written with tuono 🚀)
To check what the knowledge requirements are for each domain, check the
[requirements](#requirements) section below.
Currently, I'm keeping a private dashboard to prioritize new features and bug fixes, but if you
want to propose something, please open a new issue on Github or reach out to me using
my email address [valerioageno@yahoo.it](mailto:valerioageno@yahoo.it). I'm also available
on Twitter (X) DMs `@valerioageno`, [Linkedin](https://www.linkedin.com/in/valerioageno)
and discord `@__v__v__`.
## Requirements
It's not strictly required to know both React (& typescript) and Rust (even though it
would be a great nice to have).
Without taking into account specific cases, we can mostly split the domain requirements by:
- The `CLI` needs Rust knowledge (even though a couple of scenarios might also need Typescript)
- The Backend needs just `Rust`
- The Frontend needs just `React` & `Typescript`
- The documentation website needs just `React` & `Typescript` (or even less, since most of the
code is markdown).
@@ -0,0 +1,56 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Contributing"
canonical="https://tuono.dev/documentation/contributing"
description="The project is massive - if you like it, do consider contributing!"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: '✨ Contributing' }]} />
# Contributing
## TL;DR
The project is massive - if you like it, do consider contributing!
## Getting started
The `tuono` project can mostly be split into the following subdomains:
- The CLI
- The Rust backend
- The React frontend
- The documentation website (which is written with tuono 🚀)
To check what the knowledge requirements are for each domain, check the
[requirements](#requirements) section below.
We are currently managing the tasks' prioritization in the [Road to V1](https://github.com/orgs/tuono-labs/projects/2) project.
You can pick any task that you see in the `ready` column that is not already assigned.
If you want to contribute on something that is in the `backlog` column, or it hasn't been scoped yet, please drop a message in the [#general](https://discord.com/invite/khQzPa654B) discord channel so we can all have visibility of it.
## Requirements
It's not strictly required to know both React (& typescript) and Rust (even though it
would be a great nice to have).
Without taking into account specific cases, we can mostly split the domain requirements by:
- The `CLI` needs Rust knowledge (even though a couple of scenarios might also need Typescript)
- The Backend needs just `Rust`
- The Frontend needs just `React` & `Typescript`
- The documentation website needs just `React` & `Typescript` (or even less, since most of the
code is markdown).
import NavigationButtons from '../../../components/navigation-buttons'
<NavigationButtons
next={{
title: 'Local development',
href: '/documentation/contributing/local-development',
}}
/>
@@ -0,0 +1,113 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Contributing - Local development"
canonical="https://tuono.dev/documentation/contributing/local-development"
description="Contribute to Tuono. Learn here how to setup the repository for local development"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs
breadcrumbs={[
{ label: '✨ Contributing', href: '/documentation/contributing' },
{ label: 'Local development' },
]}
/>
# Local development
Thanks for your interest! In this page, you find the instructions to set up `tuono` on your local environment!
## Setup
### Fork and clone repository
After [forking the repo on GitHub](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo):
```sh
git clone https://github.com/<your-name-here>/tuono
cd tuono
```
### 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
Install `Node.js`.
You can follow the instructions from the [Node official site](https://nodejs.org/en/download/package-manager)
> 💡 This project has a `.nvmrc` file to specify the node version used in development.
>
> Consider to use [nvm](https://github.com/nvm-sh/nvm) so you can run
>
> ```sh
> nvm use
> ```
>
> to simply pick up the correct version!
### 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
To check that everything is working properly, run:
```sh
turbo run check-all
cargo build
```
## Tuono development
1. Start tuono frontend build using
```sh
turbo run dev
```
2. In another terminal run
```sh
cargo build
```
To automatically rebuild crates on code change, consider using `cargo-watch` crate
```sh
cargo watch -x build -w crates/
```
3. You can now use the binary inside `/target/debug/tuono` in another folder on your local machine
> Consider adding an alias to your shell setup file
>
> ```sh
> alias t="/path-to-repo/target/debug/tuono"
> ```
## Documentation development
1. Change the current working directory to the documentation folder:
```sh
cd apps/documentation
```
2. Run
```sh
tuono dev
```
3. Open the localhost URL.
> On the documentation remember that `tuono` `npm` package is installed from the registry and
> it is not linked to the repository.
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Multithreading"
canonical="https://tuono.dev/documentation/core-concepts/multithreading"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Core concepts' }]} />
# Multithreading
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - useRouter"
canonical="https://tuono.dev/documentation/hooks/use-router"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Hooks' }]} />
# useRouter
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - tuono.config.ts"
canonical="https://tuono.dev/documentation/how-is-tuono-different"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'How is tuono different?' }]} />
# How is tuono different?
TODO
@@ -0,0 +1,57 @@
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Installation"
canonical="https://tuono.dev/documentation/installation"
description="Tuono is a development environment built in rust and typescript that outputs a website written in both the languages"
/>
<Breadcrumbs breadcrumbs={[{ label: 'Installation' }]} />
# Installation
## Requirements
`Tuono` is a development environment built in rust and typescript that outputs a website written in both the
languages. Since then, you need the following tools installed on your computer to work with it:
- `Rust` - The Rust programming language tool chain (Go [here](https://rustup.rs/) for installing both `rust` and `cargo`)
- `Cargo` - The rust package manager
- `NodeJs` - The JavaScript runtime (Go [here](https://nodejs.org/en/download/package-manager) for installing both `nodejs` and `npm`)
- `npm` or `yarn` or `pnpm` - A javaScript package manager
> Node.js is needed just for the development environment. The final output will run on a Rust server.
## Installation
The tuono `CLI` is hosted on [crates.io](https://crates.io/crates/tuono) to download and install it, just run it on a terminal:
```bash
cargo install tuono
```
To check that it is correctly installed, run:
```bash
tuono --version
```
Run `tuono -h` to see all the available commands.
```bash
The React/Rust full-stack framework
Usage: tuono <COMMAND>
Commands:
dev Start the development environment
build Build the production assets
new Scaffold a new project
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
```
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - MDX"
canonical="https://tuono.dev/documentation/integrations/mdx"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Integrations' }]} />
# MDX
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Server side rendering"
canonical="https://tuono.dev/documentation/rendering/server-side-rendering"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Rendering' }]} />
# SSR
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Static site rendering"
canonical="https://tuono.dev/documentation/rendering/static-site-rendering"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Rendering' }]} />
# Static Site Rendering
TODO
@@ -0,0 +1,101 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/defining-routes"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Defining routes' }]} />
# Defining routes
Tuono has a file-system based router built on the concept of routes.
When a file is added to the `src/routes` directory, it's automatically available as a route.
In Tuono, a page is a [React Component](https://react.dev/learn/your-first-component) exported from a `.tsx` file in the `src/routes` directory.
Each page is associated with a route based on its file name.
Every page is rendered server side by default.
Example:
If you create `src/routes/about.tsx` that exports a React component like:
```
export default function About() {
return <div>About</div>
}
```
The `About` component will be rendered when loading `/about` route.
## Index routes
The router will automatically route files named `index` to the root of the directory.
- `src/routes/index.tsx` → `/`
- `src/routes/blog/index.tsx`→ `/blog`
## Nested routes
You can also create a nested folder structure, and files will still be routed in the same way.
- `src/routes/blog/first-post.tsx` → `/blog/first-post`
- `src/routes/dashboard/settings/username.tsx` → `/dashboard/settings/username`
## Pages with Dynamic Routes
Tuono supports pages with dynamic routes segments.
For example, if you create a file called `src/routes/posts/[id].tsx`,
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).
This file won't generate any route.
### Layout component for all routes
A file created in this location will wrap all project route.
```tsx
// src/routes/__root.tsx
export default function RootLayout({ children }) {
return <main>{children}</main>
}
```
### Layout component for specific routes
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 }) {
return <article>{children}</article>
}
```
Referring to the two examples above consider that:
- `/posts/examples-post` → will be wrapped by:
```tsx
<RootLayout>
<PostRootLayout>
<ExamplePost />
</PostRootLayout>
</RootLayout>
```
- `/about` → will be wrapped by:
```tsx
<RootLayout>
<About />
</RootLayout>
```
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/dynamic-routes"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Dynamic routes' }]} />
# Loading state
Todo
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/intro"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Routing' }]} />
# Routing index
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/layouts"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Layouts' }]} />
# Layouts
Todo
@@ -0,0 +1,75 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/link-and-navigation"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Link and navigation' }]} />
# Link and navigation
The Tuono router facilitates client-side route transitions between pages, enhancing the user experience by:
- Enabling smooth navigation in single-page applications (SPAs)
- Preventing page reloads during site navigation
How? Using the `Link` component provided from Tuono exports:
```tsx
import { Link } from 'tuono'
export default function HomePage() {
return (
<ul>
<li>
<Link href="/">Home</Link>
</li>
<li>
<Link href="/about">About Us</Link>
</li>
<li>
<Link href="/blog/hello-world">Blog Post</Link>
</li>
</ul>
)
}
```
The example above uses multiple links. Each one maps a path (`href`) to a known route:
- `/` → `src/routes/index.tsx`
- `/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.
## 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.
```tsx
import { useRouter } from 'tuono'
export default function GoToAboutPage() {
const router = useRouter()
return (
<ProfileForm
onUpdateSuccess={() => {
router.push('/profile')
}}
/>
)
}
```
> For more information about this hook visit the [dedicated API reference page](/documentation/hooks/use-router).

Some files were not shown because too many files have changed in this diff Show More