From 1ae7f72de3b3fc6cdc4b6d6a4634565852e2a57e Mon Sep 17 00:00:00 2001 From: Valerio Ageno <51341197+Valerioageno@users.noreply.github.com> Date: Sat, 27 Jul 2024 11:33:34 +0200 Subject: [PATCH] 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 --- .github/workflows/ci-documentation.yml | 75 +++++++++++++ .github/workflows/deploy-documentation.yml | 55 ++++++++++ Cargo.toml | 1 + apps/README.md | 1 + apps/documentation/.eslintrc | 103 ++++++++++++++++++ apps/documentation/.gitignore | 13 +++ apps/documentation/Cargo.toml | 13 +++ apps/documentation/README.md | 7 ++ apps/documentation/package.json | 40 +++++++ apps/documentation/postcss.config.cjs | 14 +++ apps/documentation/public/favicon.ico | Bin 0 -> 39529 bytes apps/documentation/public/logo.svg | 5 + .../src/components/edit-page/edit-page.tsx | 23 ++++ .../src/components/edit-page/index.ts | 3 + .../src/components/hero/hero.tsx | 53 +++++++++ .../src/components/hero/index.ts | 3 + .../src/components/mdx-provider/index.ts | 3 + .../components/mdx-provider/mdx-code/index.ts | 3 + .../mdx-provider/mdx-code/mdx-code.tsx | 8 ++ .../components/mdx-provider/mdx-h2/mdx-h2.tsx | 8 ++ .../components/mdx-provider/mdx-link/index.ts | 3 + .../mdx-provider/mdx-link/mdx-link.tsx | 37 +++++++ .../components/mdx-provider/mdx-pre/index.ts | 3 + .../mdx-provider/mdx-pre/mdx-pre.module.css | 5 + .../mdx-provider/mdx-pre/mdx-pre.tsx | 16 +++ .../components/mdx-provider/mdx-provider.tsx | 33 ++++++ .../mdx-provider/mdx-quote/index.ts | 3 + .../mdx-provider/mdx-quote/mdx-quote.tsx | 21 ++++ .../mdx-provider/mdx-title/index.ts | 3 + .../mdx-provider/mdx-title/mdx-title.tsx | 8 ++ .../src/components/navbar/actions.tsx | 31 ++++++ .../src/components/navbar/index.ts | 3 + .../src/components/navbar/navbar.tsx | 32 ++++++ .../src/components/sidebar/index.ts | 3 + .../src/components/sidebar/sidebar.tsx | 33 ++++++ .../src/components/theme-btn/index.ts | 3 + .../components/theme-btn/theme-btn.module.css | 24 ++++ .../src/components/theme-btn/theme-btn.tsx | 30 +++++ apps/documentation/src/modules.d.ts | 2 + apps/documentation/src/routes/__root.tsx | 75 +++++++++++++ .../src/routes/documentation/__root.tsx | 23 ++++ .../src/routes/documentation/contributing.mdx | 9 ++ .../src/routes/documentation/installation.mdx | 51 +++++++++ .../routes/documentation/routing/index.mdx | 9 ++ .../routes/documentation/tutorial/intro.mdx | 9 ++ apps/documentation/src/routes/index.tsx | 17 +++ apps/documentation/src/styles/global.css | 1 + apps/documentation/tsconfig.json | 25 +++++ apps/documentation/tsconfig.node.json | 11 ++ pnpm-workspace.yaml | 1 + 50 files changed, 955 insertions(+) create mode 100644 .github/workflows/ci-documentation.yml create mode 100644 .github/workflows/deploy-documentation.yml create mode 100644 apps/README.md create mode 100644 apps/documentation/.eslintrc create mode 100644 apps/documentation/.gitignore create mode 100644 apps/documentation/Cargo.toml create mode 100644 apps/documentation/README.md create mode 100644 apps/documentation/package.json create mode 100644 apps/documentation/postcss.config.cjs create mode 100644 apps/documentation/public/favicon.ico create mode 100644 apps/documentation/public/logo.svg create mode 100644 apps/documentation/src/components/edit-page/edit-page.tsx create mode 100644 apps/documentation/src/components/edit-page/index.ts create mode 100644 apps/documentation/src/components/hero/hero.tsx create mode 100644 apps/documentation/src/components/hero/index.ts create mode 100644 apps/documentation/src/components/mdx-provider/index.ts create mode 100644 apps/documentation/src/components/mdx-provider/mdx-code/index.ts create mode 100644 apps/documentation/src/components/mdx-provider/mdx-code/mdx-code.tsx create mode 100644 apps/documentation/src/components/mdx-provider/mdx-h2/mdx-h2.tsx create mode 100644 apps/documentation/src/components/mdx-provider/mdx-link/index.ts create mode 100644 apps/documentation/src/components/mdx-provider/mdx-link/mdx-link.tsx create mode 100644 apps/documentation/src/components/mdx-provider/mdx-pre/index.ts create mode 100644 apps/documentation/src/components/mdx-provider/mdx-pre/mdx-pre.module.css create mode 100644 apps/documentation/src/components/mdx-provider/mdx-pre/mdx-pre.tsx create mode 100644 apps/documentation/src/components/mdx-provider/mdx-provider.tsx create mode 100644 apps/documentation/src/components/mdx-provider/mdx-quote/index.ts create mode 100644 apps/documentation/src/components/mdx-provider/mdx-quote/mdx-quote.tsx create mode 100644 apps/documentation/src/components/mdx-provider/mdx-title/index.ts create mode 100644 apps/documentation/src/components/mdx-provider/mdx-title/mdx-title.tsx create mode 100644 apps/documentation/src/components/navbar/actions.tsx create mode 100644 apps/documentation/src/components/navbar/index.ts create mode 100644 apps/documentation/src/components/navbar/navbar.tsx create mode 100644 apps/documentation/src/components/sidebar/index.ts create mode 100644 apps/documentation/src/components/sidebar/sidebar.tsx create mode 100644 apps/documentation/src/components/theme-btn/index.ts create mode 100644 apps/documentation/src/components/theme-btn/theme-btn.module.css create mode 100644 apps/documentation/src/components/theme-btn/theme-btn.tsx create mode 100644 apps/documentation/src/modules.d.ts create mode 100644 apps/documentation/src/routes/__root.tsx create mode 100644 apps/documentation/src/routes/documentation/__root.tsx create mode 100644 apps/documentation/src/routes/documentation/contributing.mdx create mode 100644 apps/documentation/src/routes/documentation/installation.mdx create mode 100644 apps/documentation/src/routes/documentation/routing/index.mdx create mode 100644 apps/documentation/src/routes/documentation/tutorial/intro.mdx create mode 100644 apps/documentation/src/routes/index.tsx create mode 100644 apps/documentation/src/styles/global.css create mode 100644 apps/documentation/tsconfig.json create mode 100644 apps/documentation/tsconfig.node.json diff --git a/.github/workflows/ci-documentation.yml b/.github/workflows/ci-documentation.yml new file mode 100644 index 00000000..67f051b7 --- /dev/null +++ b/.github/workflows/ci-documentation.yml @@ -0,0 +1,75 @@ +name: Documentation Website CI + +on: + push: + paths: + - '.github/**' + - 'apps/documentation/**' + pull_request: + paths: + - '.github/**' + - 'apps/documentation/**' + +jobs: + build: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + timeout-minutes: 15 + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./apps/documentation + + 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 + + - name: Setup rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + + - name: Install tuono + run: cargo install tuono@0.8.2 + + - name: Install pnpm + run: npm i -g pnpm + + - name: Install dependencies + run: pnpm install --ignore-workspace + + - name: Build project + run: tuono build --static + + 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 + runs-on: ubuntu-latest + timeout-minutes: 15 + defaults: + run: + working-directory: ./apps/documentation + + 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 --ignore-workspace + + - name: Check formatting + run: pnpm format:check + + - name: Lint + run: pnpm lint + + - name: Types + run: pnpm types diff --git a/.github/workflows/deploy-documentation.yml b/.github/workflows/deploy-documentation.yml new file mode 100644 index 00000000..fed312b5 --- /dev/null +++ b/.github/workflows/deploy-documentation.yml @@ -0,0 +1,55 @@ +name: Deploy documentation website on AWS S3 +on: + push: + branches: + - main + paths: + - 'apps/documentation/**' + +jobs: + deploy-documentation: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./apps/documentation + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + 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 + + - name: Setup rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + + - name: Install tuono + run: cargo install tuono@0.8.2 + + - name: Install pnpm + run: npm i -g pnpm + + - name: Install dependencies + run: pnpm install --ignore-workspace + + - name: Build project + run: tuono build --static + + - name: Deploy + uses: reggionick/s3-deploy@v4 + with: + folder: 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: '{.*/**,**}' diff --git a/Cargo.toml b/Cargo.toml index 5e8613a1..ded17e4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "crates/tuono_lib_macros", ] exclude = [ + "apps/documentation", "examples/mdx", "examples/tuono", "examples/tutorial" diff --git a/apps/README.md b/apps/README.md new file mode 100644 index 00000000..33fd8bf7 --- /dev/null +++ b/apps/README.md @@ -0,0 +1 @@ +# Stadalone apps folder diff --git a/apps/documentation/.eslintrc b/apps/documentation/.eslintrc new file mode 100644 index 00000000..87e55820 --- /dev/null +++ b/apps/documentation/.eslintrc @@ -0,0 +1,103 @@ +{ + "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", + }, +} diff --git a/apps/documentation/.gitignore b/apps/documentation/.gitignore new file mode 100644 index 00000000..071acad0 --- /dev/null +++ b/apps/documentation/.gitignore @@ -0,0 +1,13 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.tuono +out +target diff --git a/apps/documentation/Cargo.toml b/apps/documentation/Cargo.toml new file mode 100644 index 00000000..0776c041 --- /dev/null +++ b/apps/documentation/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "tuono" +version = "0.0.1" +edition = "2021" + +[[bin]] +name = "tuono" +path = ".tuono/main.rs" + +[dependencies] +tuono_lib = "0.8.1" +serde = { version = "1.0.202", features = ["derive"] } + diff --git a/apps/documentation/README.md b/apps/documentation/README.md new file mode 100644 index 00000000..5ecd43ac --- /dev/null +++ b/apps/documentation/README.md @@ -0,0 +1,7 @@ +# Tuono starter + +This is the starter tuono project. To download it run in your terminal: + +```shell +$ tuono new [NAME] +``` diff --git a/apps/documentation/package.json b/apps/documentation/package.json new file mode 100644 index 00000000..79bbea69 --- /dev/null +++ b/apps/documentation/package.json @@ -0,0 +1,40 @@ +{ + "name": "tuono", + "description": "The react/rust fullstack framework", + "version": "0.0.1", + "scripts": { + "lint": "eslint --ext .ts,.tsx ./src -c .eslintrc", + "format": "prettier -u --write --ignore-unknown './src/**/*'", + "format:check": "prettier --check --ignore-unknown './src/**/*'", + "types": "tsc --noEmit" + }, + "dependencies": { + "@mantine/code-highlight": "^7.11.2", + "@mantine/core": "^7.11.2", + "@mantine/hooks": "^7.11.2", + "@mdx-js/react": "^3.0.1", + "@tabler/icons-react": "^3.11.0", + "clsx": "^2.1.1", + "react": "18.3.1", + "react-dom": "18.3.1", + "tuono": "0.8.1" + }, + "devDependencies": { + "@types/mdx": "^2.0.13", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.7.1", + "@typescript-eslint/parser": "^7.7.1", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "postcss": "^8.4.39", + "postcss-preset-mantine": "^1.17.0", + "postcss-simple-vars": "^7.0.1", + "prettier": "^3.2.4", + "typescript": "^5.5.4" + } +} diff --git a/apps/documentation/postcss.config.cjs b/apps/documentation/postcss.config.cjs new file mode 100644 index 00000000..6a683623 --- /dev/null +++ b/apps/documentation/postcss.config.cjs @@ -0,0 +1,14 @@ +module.exports = { + 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', + }, + }, + }, +} diff --git a/apps/documentation/public/favicon.ico b/apps/documentation/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d03bcc6640d69649846a0028bcfff9950c261789 GIT binary patch literal 39529 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 literal 0 HcmV?d00001 diff --git a/apps/documentation/public/logo.svg b/apps/documentation/public/logo.svg new file mode 100644 index 00000000..57df3036 --- /dev/null +++ b/apps/documentation/public/logo.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/apps/documentation/src/components/edit-page/edit-page.tsx b/apps/documentation/src/components/edit-page/edit-page.tsx new file mode 100644 index 00000000..f246d424 --- /dev/null +++ b/apps/documentation/src/components/edit-page/edit-page.tsx @@ -0,0 +1,23 @@ +import { Button } from '@mantine/core' +import { IconEdit } from '@tabler/icons-react' +import { useRouter } from 'tuono' + +const GITHUB_URL = + 'https://github.com/Valerioageno/tuono/tree/main/apps/documentation/src/routes' + +export default function EditPage(): JSX.Element { + const { pathname } = useRouter() + return ( + + ) +} diff --git a/apps/documentation/src/components/edit-page/index.ts b/apps/documentation/src/components/edit-page/index.ts new file mode 100644 index 00000000..9469e890 --- /dev/null +++ b/apps/documentation/src/components/edit-page/index.ts @@ -0,0 +1,3 @@ +import EditPage from './edit-page' + +export default EditPage diff --git a/apps/documentation/src/components/hero/hero.tsx b/apps/documentation/src/components/hero/hero.tsx new file mode 100644 index 00000000..f3f68dbc --- /dev/null +++ b/apps/documentation/src/components/hero/hero.tsx @@ -0,0 +1,53 @@ +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 ( + +
+ The react/rust fullstack framework +
+
+ + The technologies we love seamessly working together to unleash the + highest web performance ever met on react + +
+
+ + + + {({ copied, copy }) => ( +
+
+ ) +} diff --git a/apps/documentation/src/components/hero/index.ts b/apps/documentation/src/components/hero/index.ts new file mode 100644 index 00000000..2b4b7fec --- /dev/null +++ b/apps/documentation/src/components/hero/index.ts @@ -0,0 +1,3 @@ +import Hero from './hero' + +export default Hero diff --git a/apps/documentation/src/components/mdx-provider/index.ts b/apps/documentation/src/components/mdx-provider/index.ts new file mode 100644 index 00000000..275c5ecf --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/index.ts @@ -0,0 +1,3 @@ +import MdxProvider from './mdx-provider' + +export default MdxProvider diff --git a/apps/documentation/src/components/mdx-provider/mdx-code/index.ts b/apps/documentation/src/components/mdx-provider/mdx-code/index.ts new file mode 100644 index 00000000..32dc03c6 --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-code/index.ts @@ -0,0 +1,3 @@ +import MdxCode from './mdx-code' + +export default MdxCode diff --git a/apps/documentation/src/components/mdx-provider/mdx-code/mdx-code.tsx b/apps/documentation/src/components/mdx-provider/mdx-code/mdx-code.tsx new file mode 100644 index 00000000..3f8c6f2c --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-code/mdx-code.tsx @@ -0,0 +1,8 @@ +import { Code } from '@mantine/core' +import type { HTMLAttributes } from 'react' + +export default function MdxCode( + props: HTMLAttributes, +): JSX.Element { + return +} diff --git a/apps/documentation/src/components/mdx-provider/mdx-h2/mdx-h2.tsx b/apps/documentation/src/components/mdx-provider/mdx-h2/mdx-h2.tsx new file mode 100644 index 00000000..a48e54b1 --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-h2/mdx-h2.tsx @@ -0,0 +1,8 @@ +import { Title } from '@mantine/core' +import type { HTMLAttributes } from 'react' + +export default function MdxH2( + props: HTMLAttributes, +): JSX.Element { + return +} diff --git a/apps/documentation/src/components/mdx-provider/mdx-link/index.ts b/apps/documentation/src/components/mdx-provider/mdx-link/index.ts new file mode 100644 index 00000000..9ef1ac78 --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-link/index.ts @@ -0,0 +1,3 @@ +import MdxLink from './mdx-link' + +export default MdxLink diff --git a/apps/documentation/src/components/mdx-provider/mdx-link/mdx-link.tsx b/apps/documentation/src/components/mdx-provider/mdx-link/mdx-link.tsx new file mode 100644 index 00000000..8e040d80 --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-link/mdx-link.tsx @@ -0,0 +1,37 @@ +import type { 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')) { + 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" + rightSection={<IconExternalLink size="16px" style={{ marginLeft: -5 }} />} + variant="transparent" + style={{ height: '20px' }} + mt={-2} + p={0} + /> + ) +} diff --git a/apps/documentation/src/components/mdx-provider/mdx-pre/index.ts b/apps/documentation/src/components/mdx-provider/mdx-pre/index.ts new file mode 100644 index 00000000..54fa53df --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-pre/index.ts @@ -0,0 +1,3 @@ +import MdxPre from './mdx-pre' + +export default MdxPre diff --git a/apps/documentation/src/components/mdx-provider/mdx-pre/mdx-pre.module.css b/apps/documentation/src/components/mdx-provider/mdx-pre/mdx-pre.module.css new file mode 100644 index 00000000..bfb74786 --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-pre/mdx-pre.module.css @@ -0,0 +1,5 @@ +.pre { + code { + font-size: 16px; + } +} diff --git a/apps/documentation/src/components/mdx-provider/mdx-pre/mdx-pre.tsx b/apps/documentation/src/components/mdx-provider/mdx-pre/mdx-pre.tsx new file mode 100644 index 00000000..4b8c4fea --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-pre/mdx-pre.tsx @@ -0,0 +1,16 @@ +import { CodeHighlight } from '@mantine/code-highlight' +import styles from './mdx-pre.module.css' + +interface PreProps { + children: any +} +export default function MdxPre({ children }: PreProps): JSX.Element { + return ( + <CodeHighlight + className={styles.pre} + style={{ borderRadius: 8 }} + code={children.props.children || ''} + language={children.props.className?.replace('language-', '')} + /> + ) +} diff --git a/apps/documentation/src/components/mdx-provider/mdx-provider.tsx b/apps/documentation/src/components/mdx-provider/mdx-provider.tsx new file mode 100644 index 00000000..0342d0ae --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-provider.tsx @@ -0,0 +1,33 @@ +import { MDXProvider } from '@mdx-js/react' + +import MdxLink from './mdx-link' +import type { ReactNode } from 'react' +import MdxPre from './mdx-pre' +import MdxQuote from './mdx-quote' +import MdxCode from './mdx-code' +import MdxTitle from './mdx-title' +import MdxH2 from './mdx-h2/mdx-h2' + +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: MdxTitle, + h2: MdxH2, + }} + > + {children} + </MDXProvider> + ) +} diff --git a/apps/documentation/src/components/mdx-provider/mdx-quote/index.ts b/apps/documentation/src/components/mdx-provider/mdx-quote/index.ts new file mode 100644 index 00000000..60c00daa --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-quote/index.ts @@ -0,0 +1,3 @@ +import MdxQuote from './mdx-quote' + +export default MdxQuote diff --git a/apps/documentation/src/components/mdx-provider/mdx-quote/mdx-quote.tsx b/apps/documentation/src/components/mdx-provider/mdx-quote/mdx-quote.tsx new file mode 100644 index 00000000..a256f3d3 --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-quote/mdx-quote.tsx @@ -0,0 +1,21 @@ +import { Blockquote, Space } from '@mantine/core' +import type { HTMLAttributes } from 'react' + +export default function MdxQuote( + props: HTMLAttributes<HTMLQuoteElement>, +): JSX.Element { + return ( + <> + <Blockquote + color="violet" + p={8} + px={20} + mt={30} + iconSize={30} + {...props} + style={{ borderRadius: 8 }} + /> + <Space h="md" /> + </> + ) +} diff --git a/apps/documentation/src/components/mdx-provider/mdx-title/index.ts b/apps/documentation/src/components/mdx-provider/mdx-title/index.ts new file mode 100644 index 00000000..db92451e --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-title/index.ts @@ -0,0 +1,3 @@ +import MdxTitle from './mdx-title' + +export default MdxTitle diff --git a/apps/documentation/src/components/mdx-provider/mdx-title/mdx-title.tsx b/apps/documentation/src/components/mdx-provider/mdx-title/mdx-title.tsx new file mode 100644 index 00000000..d562ed9d --- /dev/null +++ b/apps/documentation/src/components/mdx-provider/mdx-title/mdx-title.tsx @@ -0,0 +1,8 @@ +import { Title } from '@mantine/core' +import type { HTMLAttributes } from 'react' + +export default function MdxTitle( + props: HTMLAttributes<HTMLHeadingElement>, +): JSX.Element { + return <Title {...props} order={1} /> +} diff --git a/apps/documentation/src/components/navbar/actions.tsx b/apps/documentation/src/components/navbar/actions.tsx new file mode 100644 index 00000000..6586057d --- /dev/null +++ b/apps/documentation/src/components/navbar/actions.tsx @@ -0,0 +1,31 @@ +import { Flex, Button, ActionIcon } from '@mantine/core' +import { IconBrandGithub, IconBook } from '@tabler/icons-react' +import ThemeBtn from '../theme-btn' +import { Link } from 'tuono' + +export default function Actions(): JSX.Element { + return ( + <Flex gap={8}> + <Button + href="/documentation/installation" + component={Link} + size="compact-lg" + rightSection={<IconBook />} + autoContrast + > + Get started + </Button> + <ActionIcon + variant="default" + size="lg" + aria-label="Check the project on github" + href="https://github.com/Valerioageno/tuono" + target="_blank" + component="a" + > + <IconBrandGithub /> + </ActionIcon> + <ThemeBtn /> + </Flex> + ) +} diff --git a/apps/documentation/src/components/navbar/index.ts b/apps/documentation/src/components/navbar/index.ts new file mode 100644 index 00000000..19eb850e --- /dev/null +++ b/apps/documentation/src/components/navbar/index.ts @@ -0,0 +1,3 @@ +import Navbar from './navbar' + +export default Navbar diff --git a/apps/documentation/src/components/navbar/navbar.tsx b/apps/documentation/src/components/navbar/navbar.tsx new file mode 100644 index 00000000..7f470356 --- /dev/null +++ b/apps/documentation/src/components/navbar/navbar.tsx @@ -0,0 +1,32 @@ +import { AppShell, Burger, Button, Flex } from '@mantine/core' +import { Link, useRouter } from 'tuono' +import Actions from './actions' + +interface NavbarProps { + opened: boolean + toggle: () => void +} + +export default function Navbar({ opened, toggle }: NavbarProps): JSX.Element { + const { pathname } = useRouter() + return ( + <AppShell.Header p="sm"> + <Flex justify="space-between"> + <Flex align="center" gap={8}> + {pathname.startsWith('/documentation') && ( + <Burger + opened={opened} + onClick={toggle} + hiddenFrom="sm" + size="sm" + /> + )} + <Button component={Link} href="/" variant="transparent" p={0} fz={28}> + Tuono + </Button> + </Flex> + <Actions /> + </Flex> + </AppShell.Header> + ) +} diff --git a/apps/documentation/src/components/sidebar/index.ts b/apps/documentation/src/components/sidebar/index.ts new file mode 100644 index 00000000..1c6b4eb3 --- /dev/null +++ b/apps/documentation/src/components/sidebar/index.ts @@ -0,0 +1,3 @@ +import Sidebar from './sidebar' + +export default Sidebar diff --git a/apps/documentation/src/components/sidebar/sidebar.tsx b/apps/documentation/src/components/sidebar/sidebar.tsx new file mode 100644 index 00000000..03a96a1e --- /dev/null +++ b/apps/documentation/src/components/sidebar/sidebar.tsx @@ -0,0 +1,33 @@ +import { AppShell, NavLink } from '@mantine/core' +import { Link } from 'tuono' + +export default function Sidebar(): JSX.Element { + return ( + <AppShell.Navbar p="md"> + <h3>Tutorial</h3> + <NavLink + href="/documentation/tutorial/intro" + component={Link} + label="Intro" + /> + <h3>Documentation</h3> + <NavLink + href="/documentation/installation" + component={Link} + label="Installation" + /> + <NavLink label="Routing" href="#required-for-focus" defaultOpened> + <NavLink + href="/documentation/routing" + component={Link} + label="FS routing" + /> + </NavLink> + <NavLink + label="Contributing" + component={Link} + href="/documentation/contributing" + /> + </AppShell.Navbar> + ) +} diff --git a/apps/documentation/src/components/theme-btn/index.ts b/apps/documentation/src/components/theme-btn/index.ts new file mode 100644 index 00000000..20f54231 --- /dev/null +++ b/apps/documentation/src/components/theme-btn/index.ts @@ -0,0 +1,3 @@ +import ThemeBtn from './theme-btn' + +export default ThemeBtn diff --git a/apps/documentation/src/components/theme-btn/theme-btn.module.css b/apps/documentation/src/components/theme-btn/theme-btn.module.css new file mode 100644 index 00000000..e111fe8d --- /dev/null +++ b/apps/documentation/src/components/theme-btn/theme-btn.module.css @@ -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; + } +} diff --git a/apps/documentation/src/components/theme-btn/theme-btn.tsx b/apps/documentation/src/components/theme-btn/theme-btn.tsx new file mode 100644 index 00000000..638e6413 --- /dev/null +++ b/apps/documentation/src/components/theme-btn/theme-btn.tsx @@ -0,0 +1,30 @@ +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> + ) +} diff --git a/apps/documentation/src/modules.d.ts b/apps/documentation/src/modules.d.ts new file mode 100644 index 00000000..248c50ee --- /dev/null +++ b/apps/documentation/src/modules.d.ts @@ -0,0 +1,2 @@ +// declaration.d.ts +declare module '*.css' diff --git a/apps/documentation/src/routes/__root.tsx b/apps/documentation/src/routes/__root.tsx new file mode 100644 index 00000000..b063f980 --- /dev/null +++ b/apps/documentation/src/routes/__root.tsx @@ -0,0 +1,75 @@ +import type { ReactNode } from 'react' +import { + ColorSchemeScript, + createTheme, + MantineProvider, + AppShell, +} from '@mantine/core' +import { useDisclosure } from '@mantine/hooks' +import { Head } from 'tuono' +import Navbar from '../components/navbar' + +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: 'Roboto', + respectReducedMotion: true, + 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', + }, + }, + }, +}) + +export default function RootRoute({ children }: RootRouteProps): JSX.Element { + const [opened, { toggle }] = useDisclosure() + + return ( + <> + <Head> + <ColorSchemeScript /> + </Head> + <MantineProvider theme={theme}> + <AppShell + header={{ height: 60 }} + navbar={{ + width: 300, + breakpoint: 'sm', + collapsed: { mobile: !opened }, + }} + > + <Navbar opened={opened} toggle={toggle} /> + {children} + </AppShell> + </MantineProvider> + </> + ) +} diff --git a/apps/documentation/src/routes/documentation/__root.tsx b/apps/documentation/src/routes/documentation/__root.tsx new file mode 100644 index 00000000..63e7ae01 --- /dev/null +++ b/apps/documentation/src/routes/documentation/__root.tsx @@ -0,0 +1,23 @@ +import type { ReactNode } from 'react' +import { AppShell, Container } from '@mantine/core' +import MdxProvider from '../../components/mdx-provider' +import Sidebar from '../../components/sidebar' +import EditPage from '../../components/edit-page' + +interface RootRouteProps { + children: ReactNode +} + +export default function RootRoute({ children }: RootRouteProps): JSX.Element { + return ( + <> + <Sidebar /> + <AppShell.Main> + <Container component="article" p={20}> + <MdxProvider>{children}</MdxProvider> + <EditPage /> + </Container> + </AppShell.Main> + </> + ) +} diff --git a/apps/documentation/src/routes/documentation/contributing.mdx b/apps/documentation/src/routes/documentation/contributing.mdx new file mode 100644 index 00000000..8c722d78 --- /dev/null +++ b/apps/documentation/src/routes/documentation/contributing.mdx @@ -0,0 +1,9 @@ +import { Head } from 'tuono' + +<Head> + <title>Tuono - Contributing + + +# How to contribute + +Todo diff --git a/apps/documentation/src/routes/documentation/installation.mdx b/apps/documentation/src/routes/documentation/installation.mdx new file mode 100644 index 00000000..ca10ebbb --- /dev/null +++ b/apps/documentation/src/routes/documentation/installation.mdx @@ -0,0 +1,51 @@ +import { Head } from 'tuono' + + + Tuono - Installation + + +# Installation + +## Requirements + +`Tuono` is a development environment built in rust and typescript that outputs a website written with both the +languages. Since that you need the following tools installed on your computer to work with it: + +- `Rust` - The rust programming language toolchain (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 + +> NodeJs 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 on a terminal: + +```bash +cargo install tuono +``` + +To check that is correctly installed run: + +```bash +tuono --version +``` + +Run `tuono -h` to see all the available commands. + +```bash +The react/rust fullstack framework + +Usage: tuono + +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 +``` diff --git a/apps/documentation/src/routes/documentation/routing/index.mdx b/apps/documentation/src/routes/documentation/routing/index.mdx new file mode 100644 index 00000000..e611e7a2 --- /dev/null +++ b/apps/documentation/src/routes/documentation/routing/index.mdx @@ -0,0 +1,9 @@ +import { Head } from 'tuono' + + + Tuono - Routing + + +# Routing + +Todo diff --git a/apps/documentation/src/routes/documentation/tutorial/intro.mdx b/apps/documentation/src/routes/documentation/tutorial/intro.mdx new file mode 100644 index 00000000..adfb42eb --- /dev/null +++ b/apps/documentation/src/routes/documentation/tutorial/intro.mdx @@ -0,0 +1,9 @@ +import { Head } from 'tuono' + + + Tuono - Tutorial intro + + +# Tutorial intro + +TODO diff --git a/apps/documentation/src/routes/index.tsx b/apps/documentation/src/routes/index.tsx new file mode 100644 index 00000000..4b96781a --- /dev/null +++ b/apps/documentation/src/routes/index.tsx @@ -0,0 +1,17 @@ +import { Head } from 'tuono' +import Hero from '../components/hero' + +export default function IndexPage(): JSX.Element { + return ( + <> + + Tuono - The react/rust fullstack framework + + + + + ) +} diff --git a/apps/documentation/src/styles/global.css b/apps/documentation/src/styles/global.css new file mode 100644 index 00000000..9483fd6a --- /dev/null +++ b/apps/documentation/src/styles/global.css @@ -0,0 +1 @@ +@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap'); diff --git a/apps/documentation/tsconfig.json b/apps/documentation/tsconfig.json new file mode 100644 index 00000000..a7fc6fbf --- /dev/null +++ b/apps/documentation/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/apps/documentation/tsconfig.node.json b/apps/documentation/tsconfig.node.json new file mode 100644 index 00000000..97ede7ee --- /dev/null +++ b/apps/documentation/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "strict": true + }, + "include": ["vite.config.ts"] +} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index d15a1f0b..582a1f3b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,4 @@ packages: - "packages/*" - "!**/examples/**" + - "!**/apps/**"