├── .dockerignore ├── .env.example ├── .eslintignore ├── .eslintrc.cjs ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── config.yml │ └── feature-request.yml ├── pull_request_template.md ├── spelling │ ├── check_spelling.py │ └── known_words_corpus.txt └── workflows │ ├── ci.yml │ ├── deploy-production.yml │ ├── deploy-staging-revamp.yml │ ├── deploy-staging.yml │ ├── pr-title-linting.yml │ └── spellcheck.yml ├── .gitignore ├── .gitmodules ├── .nvmrc ├── .prettierignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DEVELOPING.md ├── Dockerfile ├── LICENSE ├── README.md ├── SECURITY.md ├── components ├── api-endpoint.tsx ├── chat │ ├── chat-window.tsx │ ├── chat-with-us.tsx │ ├── custome-code-blocks.tsx │ └── mark-down-render.tsx ├── code.tsx ├── components.module.css ├── dark-logo.tsx ├── error-404.tsx ├── examples-mdx.tsx ├── feature-guide-tabs.tsx ├── feedback.tsx ├── footer.module.css ├── footer.tsx ├── grid-view.tsx ├── grid.module.css ├── guide-mdx.tsx ├── info-card.tsx ├── info-image-card-png.tsx ├── info-image-card.tsx ├── landing-page.tsx ├── landing.module.css ├── last-updated.tsx ├── logo.tsx ├── mdx.tsx ├── package-version.tsx ├── tab.module.css └── tooltip.tsx ├── next-env.d.ts ├── next.config.js ├── package.json ├── pages ├── 404.mdx ├── _app.js ├── _meta.json ├── api │ ├── chat.ts │ ├── feedback.ts │ ├── last-updated.ts │ ├── newsletter.ts │ └── search.ts ├── concepts.mdx └── index.mdx ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── poetry.lock ├── postcss.config.js ├── public ├── Logo.png ├── assets │ ├── agentverse_chat.svg │ ├── agentverse_deployhost.svg │ ├── agentverse_marketplace.svg │ ├── agentverse_templates.svg │ ├── flockx_integrations.svg │ ├── flockx_knowledgemanagement.svg │ ├── hover.svg │ ├── icon_agenticsearch.svg │ ├── icon_almanac.svg │ ├── icon_chatprotocol.svg │ ├── icon_cosmpy.svg │ ├── icon_ledger.svg │ ├── icon_mailbox.svg │ ├── icon_multiagentsystem.svg │ ├── icon_ragagent.svg │ ├── icon_wallet.svg │ ├── iconlogo_agentverse.svg │ ├── iconlogo_asione.svg │ ├── iconlogo_flockx.svg │ ├── opne-new-tab-icon.svg │ └── solana.svg ├── docs-logo.svg └── favicon.png ├── pyproject.toml ├── scripts ├── build-img-revamp.py └── build-img.py ├── src ├── icons │ ├── footer-icons.tsx │ ├── main-page-icons.tsx │ ├── os-icons.tsx │ └── shared-icons.tsx ├── images │ ├── agentverse │ │ └── explorer │ │ │ └── agentverse-explorer_1.png │ ├── concepts │ │ ├── about │ │ │ └── Dark-high-level-system-diagram.svg │ │ ├── ai-agents │ │ │ ├── Dark_agents_interacting.svg │ │ │ ├── Dark_decentralised_network.svg │ │ │ ├── dark_public_and_private_agents.svg │ │ │ └── fetpayment.png │ │ ├── ai-engine │ │ │ ├── dark_ai_with_personal_data.svg │ │ │ ├── dark_hotel_tasks_go_through_the_engine_to_representative_agents.svg │ │ │ ├── dark_human_text_in.svg │ │ │ ├── dark_system_diagram_ai_engine.svg │ │ │ ├── hotel_tasks_go_through_the_engine_to_representative_agents.png │ │ │ └── system_diagram_ai_engine.png │ │ └── tech │ │ │ ├── I1.png │ │ │ ├── I1.svg │ │ │ └── I2.svg │ ├── dark-an-agent-for-everyone.svg │ ├── dark-hosting-name-service_1.svg │ ├── dark-mailroom.svg │ ├── dark-scaling-hosting.svg │ ├── fetch_logo_only_white.svg │ ├── flockx_collab.png │ ├── flockx_nocodeagentstudio.png │ ├── guides │ │ └── agentverse │ │ │ └── agentverse_intro.png │ ├── landing │ │ ├── leading │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ └── asi1.svg │ │ └── leaves.png │ ├── mailroom.png │ └── scaling-hosting.png ├── index.css ├── lib │ └── fetch-json.ts ├── styles │ └── tailwind.css └── svgs │ ├── agent-functions.svg │ ├── agentverse-getstarted.svg │ ├── ai-engine.svg │ ├── almanac.svg │ ├── analytics.svg │ ├── api-agents.svg │ ├── build-chatai.svg │ ├── build-your-agent.svg │ ├── communicate.svg │ ├── context-control.svg │ ├── cosmpy.svg │ ├── courses-background.svg │ ├── courses-stack-second.svg │ ├── courses-stack.svg │ ├── crewai.svg │ ├── dark-build-agent.svg │ ├── dark-course-stack.svg │ ├── dark-crew-ai.svg │ ├── dark-ethereum.svg │ ├── dark-executable.svg │ ├── dark-fast-api.svg │ ├── dark-fetch-logo.svg │ ├── dark-langchain.svg │ ├── dark-openai.svg │ ├── dark-system-diagram.svg │ ├── dark-tech-stack.svg │ ├── delta-v.svg │ ├── desktop │ ├── 404.svg │ ├── footer_left_bottom.svg │ ├── footer_left_top.svg │ ├── footer_right_green.svg │ ├── footer_right_purple.svg │ ├── header_left.svg │ ├── header_right.svg │ └── search-icon.svg │ ├── docs-logo.svg │ ├── ethereum.svg │ ├── executable.svg │ ├── explorer.svg │ ├── external-link.svg │ ├── fastapi.svg │ ├── fetch-logo.svg │ ├── hosting.svg │ ├── internal-link.svg │ ├── langchain.svg │ ├── ledger.svg │ ├── logo.svg │ ├── mac.svg │ ├── mailbox.svg │ ├── mobile │ ├── footer_left_bottom.svg │ ├── footer_right_green.svg │ ├── footer_right_purple.svg │ └── footer_top.svg │ ├── openai.svg │ ├── profile.svg │ ├── revenue.svg │ ├── stack.svg │ ├── synergy.svg │ ├── system-diagram.svg │ ├── tech-stack.svg │ ├── ubuntu.svg │ ├── wallet.svg │ └── windows.svg ├── styles ├── globals.css ├── hamburger.css └── typesetting-article.css ├── tailwind.config.js ├── test.mdx ├── theme.config.tsx ├── theme └── fetch-ai-docs │ ├── components │ ├── anchor.tsx │ ├── banner.tsx │ ├── breadcrumb.tsx │ ├── collapse.tsx │ ├── footer.tsx │ ├── head.tsx │ ├── highlight-matches.tsx │ ├── index.ts │ ├── input.tsx │ ├── instant-algolia-search.tsx │ ├── match-sorter-search.tsx │ ├── nav-links.tsx │ ├── navbar.tsx │ ├── not-found.tsx │ ├── search-model.tsx │ ├── search.tsx │ ├── select.tsx │ ├── server-side-error.tsx │ ├── sidebar.tsx │ ├── skip-nav.tsx │ ├── theme-switcher.tsx │ └── toc.tsx │ ├── constants.tsx │ ├── contexts │ ├── active-anchor.tsx │ ├── config.tsx │ ├── details.ts │ ├── index.ts │ ├── menu.ts │ ├── os-provider.tsx │ └── theme-provider.tsx │ ├── helpers.ts │ ├── index.tsx │ ├── mdx-components.tsx │ ├── polyfill.ts │ ├── types.ts │ └── utils │ ├── get-git-issue-url.ts │ ├── index.ts │ ├── render.tsx │ ├── use-git-edit-url.ts │ └── use-popper.ts ├── tsconfig.json └── update_code.py /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .nvmrc 3 | .next/ 4 | 5 | k8s/ 6 | 7 | .gitignore 8 | .gitmodules 9 | 10 | .idea/ 11 | .vscode/ 12 | 13 | Dockerfile 14 | .dockerignore 15 | 16 | README.md 17 | LICENSE 18 | 19 | .eslintrc.json 20 | next-env.d.ts 21 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | BACKEND_URL= 2 | NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID= 3 | NEXT_PUBLIC_ALGOLIA_APP_ID= 4 | NEXT_PUBLIC_ALGOLIA_API_KEY= 5 | NEXT_PUBLIC_ALGOLIA_INDEX= 6 | NEWSLETTER_BASE_URL= 7 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | tailwind.config.js 2 | postcss.config.js 3 | _app.js 4 | next.config.js 5 | index-data-to-algolia.js -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | }, 6 | settings: { 7 | react: { 8 | version: "detect", 9 | }, 10 | }, 11 | extends: [ 12 | "eslint:recommended", 13 | "plugin:react/recommended", 14 | "plugin:@typescript-eslint/recommended", 15 | "plugin:unicorn/recommended", 16 | ], 17 | parser: "@typescript-eslint/parser", 18 | parserOptions: { 19 | ecmaFeatures: { 20 | jsx: true, 21 | }, 22 | ecmaVersion: "latest", 23 | sourceType: "module", 24 | }, 25 | plugins: ["react", "@typescript-eslint", "unicorn"], 26 | rules: { 27 | "unicorn/no-useless-undefined": ["error", { checkArguments: false }], 28 | "unicorn/prevent-abbreviations": "off", 29 | "unicorn/no-null": "off", 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @devjsc @FelixNicolaeBucsa @gautamgambhir97 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Bug Report 2 | description: Report a bug. 3 | labels: ["bug", "unconfirmed"] 4 | assignees: 5 | - devjsc 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to report a bug! We appreciate your contribution to improving the code. 11 | - type: checkboxes 12 | id: prerequisites 13 | attributes: 14 | label: Prerequisites 15 | description: Please confirm before submitting any new bug report. 16 | options: 17 | - label: I checked the [existing issues](https://github.com/fetchai/docs/issues) and made sure there are no similar bug reports 18 | required: true 19 | - type: dropdown 20 | id: category 21 | attributes: 22 | label: Category 23 | description: Select the category that best describes the bug. 24 | options: 25 | - Incorrect or missing Content 26 | - Technical Bug (unexpected behavior) 27 | - Other 28 | validations: 29 | required: false 30 | - type: textarea 31 | id: expected 32 | attributes: 33 | label: Expected Behavior / Content 34 | description: Describe the behavior / content you are expecting. 35 | validations: 36 | required: false 37 | - type: textarea 38 | id: actual 39 | attributes: 40 | label: Observed Behavior / Content 41 | description: Describe the behavior / content you are observing. 42 | validations: 43 | required: false 44 | - type: textarea 45 | id: steps 46 | attributes: 47 | label: To Reproduce 48 | description: Provide steps to reproduce the issue, the location where content is incorrect, or the location where the missing content should be. 49 | validations: 50 | required: false 51 | - type: textarea 52 | id: environment 53 | attributes: 54 | label: Environment Details (Optional) 55 | description: Provide any relevant information about your environment, such as operating system, and any libraries used. 56 | render: markdown 57 | validations: 58 | required: false 59 | - type: textarea 60 | id: logs 61 | attributes: 62 | label: Failure Logs (Optional) 63 | description: Include any relevant log snippets or files here. You can paste directly or drag and drop files into this area. 64 | render: shell 65 | validations: 66 | required: false 67 | - type: textarea 68 | id: additional 69 | attributes: 70 | label: Additional Information (Optional) 71 | description: Include any screenshots, code snippets, or other relevant details that might help us understand the issue. 72 | render: markdown 73 | validations: 74 | required: false 75 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: ☝️Feature request 2 | description: Suggest an idea. 3 | labels: ["enhancement", "unconfirmed"] 4 | assignees: 5 | - devjsc 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thank you for suggesting a new idea! Please complete the following so we have everything to get started. 11 | - type: checkboxes 12 | id: prerequisites 13 | attributes: 14 | label: Prerequisites 15 | description: Please confirm before submitting a feature request. 16 | options: 17 | - label: I checked the [existing issues](https://github.com/fetchai/docs/issues) to make sure this feature has not already been requested 18 | required: true 19 | - type: textarea 20 | id: feature 21 | attributes: 22 | label: Feature 23 | description: | 24 | Provide a description of the feature you would like to see implemented. 25 | validations: 26 | required: true 27 | - type: textarea 28 | id: info 29 | attributes: 30 | label: Additional Information (Optional) 31 | description: | 32 | Add any other context, screenshots, or information that could be helpful for understanding your feature request. 33 | validations: 34 | required: false 35 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Proposed Changes 2 | 3 | _[describe the changes here...]_ 4 | 5 | ## Linked Issues 6 | 7 | _[if applicable, add links to issues resolved by this PR]_ 8 | 9 | ## Types of changes 10 | 11 | _What type of change does this pull request make (put an `x` in the boxes that apply)?_ 12 | 13 | - [ ] Content update. 14 | - [ ] Bug fix (non-breaking change that fixes an issue). 15 | - [ ] New feature added (non-breaking change that adds functionality). 16 | - [ ] Breaking change (fix or feature that would cause existing functionality to stop working as expected). 17 | - [ ] Something else (e.g., tests, scripts, example, deployment, infrastructure). 18 | 19 | ## Checklist 20 | 21 | _Put an `x` in the boxes that apply:_ 22 | 23 | - [ ] I have read the [CONTRIBUTING](https://github.com/fetchai/docs/blob/main/CONTRIBUTING.md) guide 24 | - [ ] Checks and tests pass locally 25 | 26 | ## Further comments 27 | 28 | _[if this is a relatively large or complex change, kick off a discussion by explaining why you chose the solution you did, what alternatives you considered, etc...]_ 29 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | build: 14 | name: Build 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - uses: actions/setup-node@v3 21 | with: 22 | node-version-file: ".nvmrc" 23 | 24 | - uses: pnpm/action-setup@v2 25 | with: 26 | version: 8.6.10 27 | 28 | - name: Dependencies 29 | run: | 30 | pnpm install 31 | 32 | - name: Build 33 | run: | 34 | pnpm run build 35 | 36 | - name: Lint 37 | run: | 38 | pnpm run lint 39 | 40 | - name: Formatting 41 | run: | 42 | pnpm run fmt:check 43 | -------------------------------------------------------------------------------- /.github/workflows/deploy-production.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Production 2 | 3 | on: 4 | push: 5 | branches: 6 | - release/production 7 | 8 | jobs: 9 | build: 10 | name: Build Images 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 18 | 19 | - name: Setup Gcloud Auth 20 | uses: google-github-actions/auth@v1 21 | with: 22 | credentials_json: "${{ secrets.ORG_PRODUCTION_IMAGES_PUSH }}" 23 | 24 | - name: Setup Cloud SDK 25 | uses: google-github-actions/setup-gcloud@v1 26 | 27 | - name: Set Image Tag 28 | id: lookup 29 | run: echo "version=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT 30 | 31 | - run: | 32 | gcloud auth list 33 | gcloud auth configure-docker -q 34 | echo "VERSION: ${{ steps.lookup.outputs.version }}" 35 | 36 | - name: Build and Push Images 37 | run: | 38 | ./scripts/build-img.py 39 | env: 40 | IMAGE_REPOSITORY: ${{ secrets.PRODUCTION_IMAGE_REPOSITORY }} 41 | BACKEND_URL: ${{ secrets.NEXT_PUBLIC_BACKEND_URL }} 42 | NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID: ${{ secrets.NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID }} 43 | NEXT_PUBLIC_ALGOLIA_APP_ID: ${{ secrets.NEXT_PUBLIC_ALGOLIA_APP_ID }} 44 | NEXT_PUBLIC_ALGOLIA_API_KEY: ${{ secrets.NEXT_PUBLIC_ALGOLIA_API_KEY }} 45 | NEXT_PUBLIC_ALGOLIA_INDEX: ${{ secrets.NEXT_PUBLIC_ALGOLIA_INDEX }} 46 | NEWSLETTER_BASE_URL: ${{ secrets.NEWSLETTER_BASE_URL }} 47 | SENDER_TOKEN: ${{ secrets.SENDER_TOKEN }} 48 | 49 | - name: Trigger Image Update 50 | run: | 51 | curl -H "Accept: application/vnd.github.everest-preview+json" \ 52 | -H "Authorization: token ${{ secrets.ORG_DISPATCH_RENDER_TOKEN }}" \ 53 | --request POST \ 54 | --data '{"event_type": "docs-build", "client_payload": {"image": "${{ env.IMAGE }}", "image_path": "${{ env.IMAGE_PATH }}", "key_path": "${{ env.KEY_PATH }}", "tag": "${{ env.TAG }}", "commit_message_service": "${{ env.SERVICE_NAME }}"}}' \ 55 | ${{ env.TARGET_REPO }} 56 | env: 57 | IMAGE: gcr.io/fetch-ai-images/docs-website 58 | KEY_PATH: ".website.image.tag" 59 | TAG: ${{ steps.lookup.outputs.version }} 60 | IMAGE_PATH: values 61 | SERVICE_NAME: Documentation 62 | TARGET_REPO: https://api.github.com/repos/fetchai/infra-production-deployment/dispatches 63 | -------------------------------------------------------------------------------- /.github/workflows/deploy-staging-revamp.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Staging 2 | 3 | on: 4 | push: 5 | branches: 6 | - feat/docs-revamps 7 | 8 | jobs: 9 | build: 10 | name: Build Images 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 18 | 19 | - name: Setup Gcloud Auth 20 | uses: google-github-actions/auth@v1 21 | with: 22 | credentials_json: "${{ secrets.ORG_SANDBOX_DEPLOYMENT_KEY }}" 23 | 24 | - name: Setup Cloud SDK 25 | uses: google-github-actions/setup-gcloud@v1 26 | 27 | - name: Set Image Tag 28 | id: lookup 29 | run: echo "version=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT 30 | 31 | - run: | 32 | gcloud auth list 33 | gcloud auth configure-docker -q 34 | echo "VERSION: ${{ steps.lookup.outputs.version }}" 35 | 36 | - name: Build and Push Images 37 | run: | 38 | ./scripts/build-img-revamp.py 39 | env: 40 | IMAGE_REVAMP_REPOSITORY: ${{ secrets.IMAGE_REVAMP_REPOSITORY }} 41 | BACKEND_URL: ${{ secrets.STAGING_NEXT_PUBLIC_BACKEND_URL }} 42 | NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID: ${{ secrets.NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID }} 43 | NEXT_PUBLIC_ALGOLIA_APP_ID: ${{ secrets.NEXT_PUBLIC_ALGOLIA_APP_ID }} 44 | NEXT_PUBLIC_ALGOLIA_API_KEY: ${{ secrets.NEXT_PUBLIC_ALGOLIA_API_KEY }} 45 | NEXT_PUBLIC_ALGOLIA_INDEX: ${{ secrets.NEXT_PUBLIC_ALGOLIA_INDEX }} 46 | NEWSLETTER_BASE_URL: ${{ secrets.NEWSLETTER_BASE_URL }} 47 | SENDER_TOKEN: ${{ secrets.SENDER_TOKEN }} 48 | 49 | - name: Repository Dispatch 50 | run: | 51 | curl -f -H "Accept: application/vnd.github.everest-preview+json" \ 52 | -H "Authorization: token ${{ secrets.ORG_DISPATCH_RENDER_TOKEN }}" \ 53 | --request POST \ 54 | --data '{"event_type": "docs-revamp-staging-build", "client_payload": {"image": "'"${{ secrets.IMAGE_REVAMP_REPOSITORY }}"'" , "image_path": "values", "key_path": ".image.tag", "commit_message_service": "Docs Revamp Staging", "tag": "'"${{ steps.lookup.outputs.version }}"'"}}' \ 55 | https://api.github.com/repos/fetchai/infra-sandbox-london-b-deployment/dispatches 56 | -------------------------------------------------------------------------------- /.github/workflows/deploy-staging.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Staging 2 | 3 | on: 4 | push: 5 | branches: 6 | - feat/new-landing 7 | 8 | jobs: 9 | build: 10 | name: Build Images 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 18 | 19 | - name: Setup Gcloud Auth 20 | uses: google-github-actions/auth@v1 21 | with: 22 | credentials_json: "${{ secrets.ORG_SANDBOX_DEPLOYMENT_KEY }}" 23 | 24 | - name: Setup Cloud SDK 25 | uses: google-github-actions/setup-gcloud@v1 26 | 27 | - name: Set Image Tag 28 | id: lookup 29 | run: echo "version=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT 30 | 31 | - run: | 32 | gcloud auth list 33 | gcloud auth configure-docker -q 34 | echo "VERSION: ${{ steps.lookup.outputs.version }}" 35 | 36 | - name: Build and Push Images 37 | run: | 38 | ./scripts/build-img.py 39 | env: 40 | IMAGE_REPOSITORY: ${{ secrets.STAGING_IMAGE_REPOSITORY }} 41 | BACKEND_URL: ${{ secrets.STAGING_NEXT_PUBLIC_BACKEND_URL }} 42 | NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID: ${{ secrets.NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID }} 43 | NEXT_PUBLIC_ALGOLIA_APP_ID: ${{ secrets.NEXT_PUBLIC_ALGOLIA_APP_ID }} 44 | NEXT_PUBLIC_ALGOLIA_API_KEY: ${{ secrets.NEXT_PUBLIC_ALGOLIA_API_KEY }} 45 | NEXT_PUBLIC_ALGOLIA_INDEX: ${{ secrets.NEXT_PUBLIC_ALGOLIA_INDEX }} 46 | NEWSLETTER_BASE_URL: ${{ secrets.NEWSLETTER_BASE_URL }} 47 | SENDER_TOKEN: ${{ secrets.SENDER_TOKEN }} 48 | 49 | - name: Repository Dispatch 50 | run: | 51 | curl -f -H "Accept: application/vnd.github.everest-preview+json" \ 52 | -H "Authorization: token ${{ secrets.ORG_DISPATCH_RENDER_TOKEN }}" \ 53 | --request POST \ 54 | --data '{"event_type": "docs-staging-build", "client_payload": {"image": "'"${{ secrets.STAGING_IMAGE_REPOSITORY }}"'" , "image_path": "values", "key_path": ".website.image.tag", "commit_message_service": "Docs Staging", "tag": "'"${{ steps.lookup.outputs.version }}"'"}}' \ 55 | https://api.github.com/repos/fetchai/infra-sandbox-london-b-deployment/dispatches 56 | -------------------------------------------------------------------------------- /.github/workflows/pr-title-linting.yml: -------------------------------------------------------------------------------- 1 | name: Lint PR Title 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | main: 12 | name: PR Title Checks 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: amannn/action-semantic-pull-request@v5.1.0 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | # Optionally, you can provide options for further constraints. 19 | with: 20 | # Configure which types are allowed. 21 | # Default: https://github.com/commitizen/conventional-commit-types 22 | types: | 23 | chore 24 | content 25 | fix 26 | refactor 27 | feat 28 | test 29 | experiment 30 | # Configure which scopes are allowed. 31 | scopes: | 32 | docs 33 | theme 34 | deps 35 | misc 36 | # Configure that a scope must always be provided. 37 | requireScope: true 38 | # For work-in-progress PRs you can typically use draft pull requests 39 | # from Github. However, private repositories on the free plan don't have 40 | # this option and therefore this action allows you to opt-in to using the 41 | # special "[WIP]" prefix to indicate this state. This will avoid the 42 | # validation of the PR title and the pull request checks remain pending. 43 | # Note that a second check will be reported if this is enabled. 44 | wip: true 45 | -------------------------------------------------------------------------------- /.github/workflows/spellcheck.yml: -------------------------------------------------------------------------------- 1 | name: Spell Checking 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "**" 7 | 8 | jobs: 9 | spellcheck: 10 | name: Check Spelling with custom Python script 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | python-version: [3.9] 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v2 18 | 19 | - name: Set up Python 20 | uses: actions/setup-python@v2 21 | with: 22 | python-version: ${{ matrix.python-version }} 23 | 24 | - name: Install dependencies 25 | run: | 26 | sudo apt-get update 27 | sudo apt-get install -y aspell aspell-en 28 | python -m pip install --upgrade pip 29 | pip install spacy markdown-it-py pyspellchecker 30 | python -m spacy download en_core_web_sm 31 | 32 | - name: Run spell-check script 33 | run: | 34 | set -e 35 | python .github/spelling/check_spelling.py 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .next 2 | node_modules 3 | .DS_Store 4 | .idea/ 5 | .env 6 | .history/ 7 | .env.local 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/.gitmodules -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18.17 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | pnpm-lock.yaml 2 | **/*.mdx 3 | -------------------------------------------------------------------------------- /DEVELOPING.md: -------------------------------------------------------------------------------- 1 | # Development Guidelines 2 | 3 | - [Getting the Source](#get) 4 | - [Development](#dev) 5 | - [Contributing](#contributing) 6 | 7 | ## Getting the Source 8 | 9 | 10 | 11 | 1. Fork the [repository](https://github.com/fetchai/docs.git). 12 | 2. Clone your fork of the repository: 13 | 14 | 15 | ```shell 16 | git clone https://github.com/fetchai/docs.git 17 | ``` 18 | 19 | 3. Define an `upstream` remote pointing back to the main repository: 20 | 21 | ```shell 22 | git remote add upstream https://github.com/fetchai/docs.git 23 | ``` 24 | 25 | ## Development 26 | 27 | Install dependencies: 28 | 29 | ```bash 30 | pnpm install 31 | ``` 32 | 33 | Run Development Server 34 | 35 | ```bash 36 | pnpm dev 37 | ``` 38 | 39 | The site is then visible at: 40 | 41 | 42 | 43 | http://127.0.0.1:3000/docs 44 | 45 | 46 | 47 | ## Contributing 48 | 49 | 50 | 51 | For instructions on how to contribute to the project (e.g. creating Pull Requests, commit message convention, etc), see the [contributing guide](CONTRIBUTING.md). 52 | 53 | 54 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20.17.0 2 | 3 | ARG BACKEND_URL="" 4 | ARG NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID="" 5 | ARG NEXT_PUBLIC_ALGOLIA_APP_ID="" 6 | ARG NEXT_PUBLIC_ALGOLIA_API_KEY="" 7 | ARG NEXT_PUBLIC_ALGOLIA_INDEX="" 8 | ARG NEWSLETTER_BASE_URL="" 9 | ARG SENDER_TOKEN="" 10 | 11 | RUN npm install --global corepack@latest 12 | 13 | RUN corepack prepare pnpm@10.5.2 --activate && \ 14 | corepack enable 15 | 16 | WORKDIR /app 17 | ADD package.json pnpm-lock.yaml /app/ 18 | 19 | RUN pnpm install --verbose 20 | 21 | COPY . /app 22 | 23 | ENV NODE_ENV="production" 24 | ENV NODE_OPTIONS="--max-old-space-size=8192" 25 | 26 | RUN echo BACKEND_URL="${BACKEND_URL}" > .env.local && \ 27 | echo SENDER_TOKEN="${SENDER_TOKEN}" >> .env.local && \ 28 | echo NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID="${NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID}" >> .env.local && \ 29 | echo NEXT_PUBLIC_ALGOLIA_APP_ID="${NEXT_PUBLIC_ALGOLIA_APP_ID}" >> .env.local && \ 30 | echo NEXT_PUBLIC_ALGOLIA_API_KEY="${NEXT_PUBLIC_ALGOLIA_API_KEY}" >> .env.local && \ 31 | echo NEXT_PUBLIC_ALGOLIA_INDEX="${NEXT_PUBLIC_ALGOLIA_INDEX}" >> .env.local && \ 32 | echo NEWSLETTER_BASE_URL="${NEWSLETTER_BASE_URL}" >> .env.local 33 | 34 | RUN pnpm run build 35 | 36 | ENTRYPOINT ["pnpm"] 37 | CMD ["start"] 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fetch.ai Documentation Repo 2 | 3 | [](https://fetch.ai) [](https://twitter.com/fetch_ai) 4 | 5 | Welcome to the code repository for Fetch.ai's documentation at [fetch.ai/docs](fetch.ai/docs). 6 | 7 | ## Developing 8 | 9 | ### Install dependencies 10 | 11 | ```bash 12 | pnpm install test 13 | ``` 14 | 15 | ### Run Development Server 16 | 17 | ```bash 18 | pnpm dev 19 | ``` 20 | 21 | The site is then visible at: 22 | 23 | http://127.0.0.1:3000/docs 24 | 25 | ## Contributing 26 | 27 | All contributions are welcome! Remember, contribution includes not only code, but any help with docs or issues raised by other developers. See our [contribution guidelines](https://github.com/fetchai/docs/blob/main/CONTRIBUTING.md) for more details. 28 | 29 | ### Code of Conduct 30 | 31 | Please be sure to read and follow our [Code of Conduct](https://github.com/fetchai/docs/blob/main/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. 32 | 33 | ### Development Guidelines 34 | 35 | Read our [development guidelines](https://github.com/fetchai/docs/blob/main/DEVELOPING.md) to learn some useful tips related to development. 36 | 37 | ### Issues, Questions, and Discussions 38 | 39 | We use [GitHub Issues](https://github.com/fetchai/docs/issues) for tracking requests and bugs, and [GitHub Discussions](https://github.com/fetchai/docs/discussions) for general questions and discussion. 40 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | Security is very important for Fetch.ai and its community. This document outlines security procedures and general policies for this repository. 4 | 5 | ## How to Report 6 | 7 | Please follow the steps listed below to report your bug: 8 | 9 | - In an email, describe the issue clearly with reference to the underlying source code and indicate whether the bug is **Critical** or **Non-critical**. 10 | - Attach all relevant information that is required to reproduce the bug in a test environment. 11 | - Include the relevant version information associated with the faulty software of the components along with any other relevant system information such as OS versions. 12 | - Include suggested solutions and/or mitigations (if known). 13 | - Send this email to [security@fetch.ai](mailto:security@fetch.ai) and start the subject with your classification **Critical** or **Non-critical** followed by a short title of the bug. 14 | 15 | The Fetch team will review your information and your classification of the bug. 16 | 17 | For non-critical bugs, the Fetch team will create an issue or a pull request allowing you to follow the progress on the bug fix. 18 | 19 | For critical bugs that can result in loss of funds, it is important that the Fetch team has an opportunity to deploy a patched version before the exploit is acknowledged publicly. Hence, critical bugs and their fixes will be shared after the code is patched to prevent the targeting of such exploits. 20 | 21 | ## Disclosure Policy 22 | 23 | When the security team receives a security bug report, they will assign it to a primary handler. This person will coordinate the fix and release process, involving the following steps: 24 | 25 | - Confirm the problem and determine the affected versions. 26 | - Audit code to find any potential similar problems. 27 | - Prepare fixes for all releases still under maintenance. These fixes will be released as fast as possible to PyPI. 28 | 29 | ## Comments on this Policy 30 | 31 | If you have suggestions on how this process could be improved please submit a pull request. 32 | 33 | ## Public Discussions 34 | 35 | Please restrain from publicly discussing a potential security vulnerability. 🙊 36 | 37 | It's better to discuss privately and try to find a solution first, to limit the potential impact as much as possible. 38 | 39 | --- 40 | 41 | Thanks for your help! 42 | -------------------------------------------------------------------------------- /components/chat/chat-with-us.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import ChatWindow from "./chat-window"; 4 | import Image from "next/image"; 5 | import FetchWhite from "src/images/fetch_logo_only_white.svg"; 6 | 7 | const ChatWithUs = () => { 8 | const [isChatOpen, setIsChatOpen] = useState(false); 9 | 10 | return ( 11 | <> 12 | setIsChatOpen(!isChatOpen)} 14 | className="nx-fixed nx-bottom-12 nx-right-12 !nx-px-6 !nx-py-4 nx-z-40 nx-flex nx-bg-chatwithus nx-uppercase nx-font-medium geist-mono-font-family nx-text-white nx-rounded-lg nx-gap-2" 15 | > 16 | 23 | Chat with us 24 | 25 | {isChatOpen && setIsChatOpen(false)} />} 26 | > 27 | ); 28 | }; 29 | 30 | export default ChatWithUs; 31 | -------------------------------------------------------------------------------- /components/chat/custome-code-blocks.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { ModifiedPre } from "components/code"; 3 | import React, { useState, useEffect } from "react"; 4 | import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; 5 | 6 | const CustomCodeBlock = ({ 7 | children, 8 | }: { 9 | children: React.ReactNode | string; 10 | }) => { 11 | const [numberLines, setNumberLines] = useState(0); 12 | 13 | useEffect(() => { 14 | const text = typeof children === "string" ? children : children?.toString(); 15 | const lines = text?.split("\n").filter(Boolean).length; 16 | setNumberLines(lines ?? 0); 17 | }, [children]); 18 | 19 | if (numberLines === 1) { 20 | return ( 21 | 22 | 31 | {children as string} 32 | 33 | 34 | ); 35 | } 36 | 37 | return ( 38 | 39 | {children} 40 | 41 | ); 42 | }; 43 | export default CustomCodeBlock; 44 | -------------------------------------------------------------------------------- /components/chat/mark-down-render.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactMarkdown from "react-markdown"; 3 | import rehypeSanitize from "rehype-sanitize"; 4 | 5 | import CustomCodeBlock from "./custome-code-blocks"; 6 | 7 | interface MarkdownRendererProperties { 8 | markdownContent: string; 9 | } 10 | 11 | const MarkdownRenderer: React.FC = ({ 12 | markdownContent, 13 | }) => { 14 | return ( 15 | 20 | {markdownContent} 21 | 22 | ); 23 | }; 24 | 25 | export default MarkdownRenderer; 26 | -------------------------------------------------------------------------------- /components/dark-logo.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Image from "next/image"; 3 | import darkFetchLogo from "../src/svgs/dark-fetch-logo.svg"; 4 | 5 | const DarkLogo: React.FC = () => { 6 | return ( 7 | 8 | 15 | 16 | ); 17 | }; 18 | 19 | export default DarkLogo; 20 | -------------------------------------------------------------------------------- /components/error-404.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode, useEffect } from "react"; 2 | import Image from "next/image"; 3 | import Error from "../src/svgs/desktop/404.svg"; 4 | 5 | const Description = ({ children }: { children: ReactNode }) => ( 6 | 13 | {children} 14 | 15 | ); 16 | 17 | const Error404 = () => { 18 | useEffect(() => { 19 | const timer = setTimeout(() => { 20 | window.location.href = "/docs"; 21 | }, 10_000); 22 | 23 | return () => { 24 | clearTimeout(timer); 25 | }; 26 | }, []); 27 | return ( 28 | 29 | 30 | 31 | 32 | Oops, we can’t find the page you’re looking for. 33 | 34 | 35 | 36 | You can{" "} 37 | window.location.replace("/docs")} 40 | > 41 | go back to the homepage or 42 | 43 | 44 | 45 | 46 | 47 | ); 48 | }; 49 | 50 | export default Error404; 51 | -------------------------------------------------------------------------------- /components/examples-mdx.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, ChangeEvent } from "react"; 2 | import { GuideBox } from "./feature-guide-tabs"; 3 | import styles from "./footer.module.css"; 4 | import { Grid2 } from "./mdx"; 5 | import { SearchIcon } from "src/icons/shared-icons"; 6 | 7 | interface Content { 8 | type: string; 9 | title: string; 10 | description: string; 11 | path: string; 12 | } 13 | 14 | interface FilterMdxProps { 15 | content: Content[]; 16 | } 17 | 18 | const ExamplesMdx: React.FC = ({ content }) => { 19 | const [value, setValue] = useState(""); 20 | const [evt, setEvt] = useState(""); 21 | const [inputVal, setInputVal] = useState(""); 22 | 23 | const onSelectChange = (event: ChangeEvent) => { 24 | setEvt(event.target.name); 25 | setValue(event.target.value); 26 | }; 27 | 28 | const onInputChange = (event: ChangeEvent) => { 29 | setEvt(event.target.name); 30 | setInputVal(event.target.value); 31 | if (event.target.value === "") { 32 | setEvt("select"); 33 | setValue(value); 34 | } 35 | }; 36 | 37 | return ( 38 | 39 | 40 | 45 | All Types 46 | {content 47 | .map((item) => item.type) 48 | .filter((type, index, array) => array.indexOf(type) === index) 49 | .map((type) => ( 50 | 51 | {type} 52 | 53 | ))} 54 | 55 | 56 | 63 | 64 | 65 | 66 | 67 | {content 68 | .filter((item) => { 69 | if (evt === "select") { 70 | return value === "" || item.type === value; 71 | } else if (evt === "input") { 72 | const searchInTitle = item.title 73 | .toLowerCase() 74 | .includes(inputVal.toLowerCase()); 75 | const searchInDescription = item.description 76 | .toLowerCase() 77 | .includes(inputVal.toLowerCase()); 78 | return searchInTitle || searchInDescription; 79 | } else { 80 | return true; 81 | } 82 | }) 83 | .map((item, index) => ( 84 | 92 | ))} 93 | 94 | 95 | ); 96 | }; 97 | 98 | export default ExamplesMdx; 99 | -------------------------------------------------------------------------------- /components/grid-view.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import styles from "./grid.module.css"; 3 | import { useRouter } from "next/router"; 4 | 5 | export const GridView = ({ 6 | content, 7 | }: { 8 | content: { 9 | title: string; 10 | description: string; 11 | path: string; 12 | }; 13 | }) => { 14 | const router = useRouter(); 15 | const [hover, setHover] = useState(false); 16 | 17 | return ( 18 | { 21 | router.push(content.path); 22 | }} 23 | onMouseOver={() => { 24 | setHover(true); 25 | }} 26 | onMouseLeave={() => { 27 | setHover(false); 28 | }} 29 | id={content.title.toLowerCase().split(" ").join("-")} 30 | > 31 | 32 | {content.title} 33 | 34 | 35 | {content.description} 36 | 37 | 38 | ); 39 | }; 40 | -------------------------------------------------------------------------------- /components/grid.module.css: -------------------------------------------------------------------------------- 1 | .gridBox { 2 | padding: 16px; 3 | border-radius: 8px; 4 | border: 1px solid #b9c5d4; 5 | backdrop-filter: blur(35px); 6 | flex-direction: column; 7 | align-items: flex-start; 8 | width: 209px; 9 | cursor: pointer; 10 | color: #000d3d; 11 | } 12 | 13 | .hoverGridBox { 14 | padding: 16px; 15 | border-radius: 8px; 16 | border: 1px solid #b9c5d4; 17 | backdrop-filter: blur(35px); 18 | flex-direction: column; 19 | align-items: flex-start; 20 | background: #efebff; 21 | width: 209px; 22 | cursor: pointer; 23 | color: #5f38fb; 24 | } 25 | 26 | :is(html[class~="dark"] .gridBox) { 27 | background-color: #2c2e38; 28 | border: none; 29 | color: #e9e9ea; 30 | } 31 | 32 | :is(html[class~="dark"] .hoverGridBox) { 33 | background: rgba(95, 56, 251, 0.2); 34 | backdrop-filter: blur(35px); 35 | border: none; 36 | color: #bfaffd; 37 | } 38 | -------------------------------------------------------------------------------- /components/info-card.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Image from "next/image"; 3 | import Link from "next/link"; 4 | 5 | function InfoCard({ 6 | icon, 7 | href, 8 | mainTitle, 9 | firstTitle, 10 | mainTitleFont, 11 | displayFlex, 12 | displayTitleReverse, 13 | }: { 14 | icon: string; 15 | href: string; 16 | mainTitle: string; 17 | firstTitle: string; 18 | mainTitleFont?: string; 19 | displayFlex?: boolean; 20 | displayTitleReverse?: boolean; 21 | }) { 22 | return ( 23 | 29 | 30 | 37 | 38 | 41 | 42 | {firstTitle} 43 | 44 | 47 | {mainTitle} 48 | 49 | 50 | 51 | ); 52 | } 53 | 54 | export default InfoCard; 55 | -------------------------------------------------------------------------------- /components/info-image-card-png.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Image from "next/image"; 3 | import Link from "next/link"; 4 | 5 | function InfoImagePngCard({ 6 | image, 7 | href, 8 | mainTitle, 9 | firstTitle, 10 | }: { 11 | image: string; 12 | href: string; 13 | mainTitle: string; 14 | firstTitle: string; 15 | }) { 16 | return ( 17 | 23 | 24 | 25 | {firstTitle} 26 | 27 | 28 | {mainTitle} 29 | 30 | 31 | 32 | 39 | 40 | 41 | ); 42 | } 43 | 44 | export default InfoImagePngCard; 45 | -------------------------------------------------------------------------------- /components/info-image-card.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Image from "next/image"; 3 | import Link from "next/link"; 4 | 5 | function InfoImageCard({ 6 | image, 7 | href, 8 | mainTitle, 9 | firstTitle, 10 | }: { 11 | image: string; 12 | href: string; 13 | mainTitle: string; 14 | firstTitle: string; 15 | }) { 16 | return ( 17 | 23 | 24 | 25 | {firstTitle} 26 | 27 | 28 | {mainTitle} 29 | 30 | 31 | 32 | 33 | 34 | 35 | ); 36 | } 37 | 38 | export default InfoImageCard; 39 | -------------------------------------------------------------------------------- /components/last-updated.tsx: -------------------------------------------------------------------------------- 1 | import { useRouter } from "next/router"; 2 | import React, { useState, useEffect } from "react"; 3 | 4 | const LastUpdatedTime = ({ filePath }: { filePath: string }) => { 5 | const DEFAULT_LOCALE = "en-US"; 6 | const { locale = DEFAULT_LOCALE, pathname } = useRouter(); 7 | const [lastUpdated, setLastUpdated] = useState(undefined); 8 | 9 | useEffect(() => { 10 | const fetchLastUpdated = async () => { 11 | try { 12 | const response = await fetch("/docs/api/last-updated", { 13 | method: "POST", 14 | headers: { 15 | "Content-Type": "application/json", 16 | }, 17 | body: JSON.stringify({ 18 | filePath, 19 | }), 20 | }); 21 | const { lastUpdatedDate } = await response.json(); 22 | if (lastUpdatedDate) { 23 | setLastUpdated(new Date(lastUpdatedDate)); 24 | } else { 25 | setLastUpdated(undefined); 26 | } 27 | } catch (error) { 28 | console.error("Error fetching the last updated time:", error); 29 | } 30 | }; 31 | 32 | fetchLastUpdated(); 33 | }, [filePath]); 34 | 35 | return ( 36 | <> 37 | {lastUpdated && pathname !== "/" && ( 38 | 39 | Last updated on 40 | 41 | 42 | {lastUpdated?.toLocaleDateString(locale, { 43 | day: "numeric", 44 | month: "long", 45 | year: "numeric", 46 | })} 47 | 48 | 49 | )} 50 | > 51 | ); 52 | }; 53 | 54 | export default LastUpdatedTime; 55 | -------------------------------------------------------------------------------- /components/logo.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import Image from "next/image"; 3 | import fetchLogo from "../src/svgs/logo.svg"; 4 | import darkfetchLogo from "../src/svgs/dark-fetch-logo.svg"; 5 | import { useTheme } from "next-themes"; 6 | import { ThemeMode } from "theme/fetch-ai-docs/helpers"; 7 | 8 | const Logo: React.FC = () => { 9 | const { resolvedTheme } = useTheme(); 10 | const [mounted, setMounted] = useState(false); 11 | useEffect(() => { 12 | setMounted(true); 13 | }, []); 14 | 15 | if (!mounted) { 16 | return null; 17 | } 18 | return ( 19 | 20 | 27 | 28 | ); 29 | }; 30 | 31 | export default Logo; 32 | -------------------------------------------------------------------------------- /components/package-version.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | 3 | const PackageVersion = ({ 4 | packageName, 5 | packageType, 6 | }: { 7 | packageName: string; 8 | packageType: string; 9 | }) => { 10 | const [version, setVersion] = useState(""); 11 | 12 | useEffect(() => { 13 | const fetchVersion = async () => { 14 | try { 15 | const response = await fetch("/docs/api/package-version", { 16 | method: "POST", 17 | headers: { 18 | "Content-Type": "application/json", 19 | }, 20 | body: JSON.stringify({ 21 | packageName, 22 | packageType, 23 | }), 24 | }); 25 | const responseJson = await response.json(); 26 | setVersion(responseJson?.latestVersion); 27 | } catch (error) { 28 | console.error("Error fetching the package version:", error); 29 | } 30 | }; 31 | 32 | fetchVersion(); 33 | }, [packageName, packageType]); 34 | 35 | return {version}; 36 | }; 37 | 38 | export default PackageVersion; 39 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextra-docs-template", 3 | "version": "0.0.1", 4 | "description": "Nextra docs template", 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "fmt": "prettier --write .", 10 | "fmt:check": "prettier --check .", 11 | "lint": "eslint . --max-warnings 0" 12 | }, 13 | "dependencies": { 14 | "@headlessui/react": "^1.7.15", 15 | "@monaco-editor/react": "^4.5.1", 16 | "@popperjs/core": "^2.11.6", 17 | "@tailwindcss/typography": "^0.5.9", 18 | "@types/react": "^18.2.15", 19 | "algoliasearch": "^4.20.0", 20 | "autoprefixer": "^10.4.14", 21 | "axios": "^1.5.0", 22 | "clsx": "^2.0.0", 23 | "cookies-next": "^4.0.0", 24 | "escape-string-regexp": "^5.0.0", 25 | "focus-visible": "^5.2.0", 26 | "framer-motion": "^10.12.22", 27 | "git-url-parse": "^13.1.0", 28 | "gray-matter": "^4.0.3", 29 | "instantsearch.js": "^4.60.0", 30 | "intersection-observer": "^0.12.2", 31 | "iron-session": "^6.3.1", 32 | "match-sorter": "^6.3.1", 33 | "next": "^13.4.10", 34 | "next-seo": "^6.0.0", 35 | "next-themes": "^0.2.1", 36 | "nextra": "^2.10.0", 37 | "pnpm": "^8.6.9", 38 | "postcss": "^8.4.26", 39 | "prettier": "^3.0.3", 40 | "react": "^18.2.0", 41 | "react-dom": "^18.2.0", 42 | "react-error-boundary": "^4.0.13", 43 | "react-icons": "^4.11.0", 44 | "react-instantsearch-dom": "^6.40.4", 45 | "react-markdown": "^9.0.1", 46 | "react-syntax-highlighter": "^15.6.1", 47 | "rehype-sanitize": "^6.0.0", 48 | "remark": "^15.0.1", 49 | "remark-html": "^16.0.1", 50 | "scroll-into-view-if-needed": "^3.0.0", 51 | "sharp": "^0.32.5", 52 | "simple-git": "^3.20.0", 53 | "striptags": "^3.2.0", 54 | "swr": "^2.2.4", 55 | "typography": "^0.16.24", 56 | "zod": "^3.20.2", 57 | "zustand": "^4.3.9" 58 | }, 59 | "devDependencies": { 60 | "@types/node": "18.11.10", 61 | "@typescript-eslint/eslint-plugin": "^6.4.0", 62 | "eslint": "^8.49.0", 63 | "eslint-config-standard-with-typescript": "^39.0.0", 64 | "eslint-plugin-import": "^2.25.2", 65 | "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", 66 | "eslint-plugin-promise": "^6.0.0", 67 | "eslint-plugin-react": "^7.33.2", 68 | "eslint-plugin-unicorn": "^48.0.1", 69 | "tailwindcss": "^3.3.3", 70 | "typescript": "^4.9.5" 71 | }, 72 | "packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b" 73 | } 74 | -------------------------------------------------------------------------------- /pages/404.mdx: -------------------------------------------------------------------------------- 1 | import Error404 from "../components/error-404.tsx"; 2 | 3 | -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | //Import required libraries and/or modules 2 | import "../styles/globals.css"; 3 | import Script from "next/script"; 4 | import { useEffect } from "react"; 5 | 6 | // ID is fetched from .env.local created at project root to maintain security + ability to easily change in the future 7 | export default function MyApp({ Component, pageProps }) { 8 | const googleAnalyticsTrackingId = 9 | process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID; 10 | // useEffect webhook used to dynamically add GA to pages 11 | useEffect(() => { 12 | if (googleAnalyticsTrackingId) { 13 | const script = document.createElement("script"); 14 | script.src = `https://www.googletagmanager.com/gtag/js?id=${googleAnalyticsTrackingId}`; 15 | // async script loading to ensure smooth page render 16 | script.async = true; 17 | script.onload = () => { 18 | window.dataLayer = window.dataLayer || []; 19 | function gtag() { 20 | dataLayer.push(arguments); 21 | } 22 | gtag("js", new Date()); 23 | gtag("config", googleAnalyticsTrackingId); 24 | }; 25 | document.head.appendChild(script); 26 | 27 | return () => { 28 | document.head.removeChild(script); 29 | }; 30 | } 31 | }, [googleAnalyticsTrackingId]); 32 | 33 | return ; 34 | } 35 | -------------------------------------------------------------------------------- /pages/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "index": { 3 | "title": "Home", 4 | "display": "hidden", 5 | "theme": { 6 | "breadcrumb": false, 7 | "footer": true, 8 | "sidebar": false, 9 | "toc": true, 10 | "pagination": false, 11 | "layout": "full", 12 | "isUnderCurrentDocsTree": false, 13 | "timestamp": false 14 | } 15 | }, 16 | "404": { 17 | "title": "Home", 18 | "theme": { 19 | "breadcrumb": false, 20 | "footer": true, 21 | "sidebar": false, 22 | "toc": true, 23 | "pagination": false, 24 | "layout": "full", 25 | "isUnderCurrentDocsTree": false, 26 | "timestamp": false 27 | } 28 | }, 29 | "concepts": { 30 | "title": "ASI:One", 31 | "href": "#asi1", 32 | "theme": { 33 | "sidebar": false 34 | } 35 | }, 36 | "innovation-lab": { 37 | "title": "Innovation Lab", 38 | "href": "#innovationlab" 39 | }, 40 | "agentverse": { 41 | "title": "Agentverse", 42 | "href": "#agentverse" 43 | }, 44 | "Flockx": { 45 | "title": "Flockx", 46 | "href": "#flockx" 47 | }, 48 | "uAgents": { 49 | "title": "uAgents", 50 | "href": "#ugents-section" 51 | }, 52 | "Network": { 53 | "title": "Network", 54 | "href": "#network" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /pages/api/chat.ts: -------------------------------------------------------------------------------- 1 | // src/pages/api/chat.ts 2 | import type { NextApiRequest, NextApiResponse } from "next"; 3 | 4 | export default async function handler( 5 | req: NextApiRequest, 6 | res: NextApiResponse, 7 | ) { 8 | if (req.method === "POST") { 9 | const { message, sessionId } = req.body; 10 | 11 | try { 12 | const response = await fetch( 13 | "https://chat-with-docs-staging.onrender.com/echo", 14 | { 15 | method: "POST", 16 | headers: { "Content-Type": "application/json" }, 17 | body: JSON.stringify({ 18 | message: message, 19 | session_id: sessionId || "", 20 | }), 21 | }, 22 | ); 23 | const data = await response.json(); 24 | return res 25 | .status(200) 26 | .json({ reply: data.response, sessionId: data.session_id }); 27 | } catch (error) { 28 | console.log("error", error); 29 | return res 30 | .status(500) 31 | .json({ reply: "Something went wrong. Please try again." }); 32 | } 33 | } else { 34 | res.setHeader("Allow", ["POST"]); 35 | res.status(405).end(`Method ${req.method} Not Allowed`); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pages/api/feedback.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from "next"; 2 | 3 | export default async function handler( 4 | req: NextApiRequest, 5 | res: NextApiResponse, 6 | ) { 7 | try { 8 | const { feedback_type, description, page_url } = req.body; 9 | const response = await fetch(`${process.env.BACKEND_URL}/api/feedback`, { 10 | method: "POST", 11 | headers: { 12 | "Content-Type": "application/json", 13 | }, 14 | body: JSON.stringify({ 15 | feedback_type: feedback_type, 16 | description: description, 17 | page_url: page_url, 18 | }), 19 | }); 20 | const apiResponse = await response.json(); 21 | return res.status(response.status).json({ apiResponse }); 22 | } catch (error) { 23 | console.error(error); 24 | return res.status(500).json({ error: "Internal Server Error" }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /pages/api/last-updated.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from "next"; 2 | import { execSync } from "node:child_process"; 3 | 4 | export function getLastUpdatedDate(filePath: string) { 5 | try { 6 | const lastUpdatedDate = execSync(`git log -1 --format="%cd" -- ${filePath}`) 7 | .toString() 8 | .trim(); 9 | return lastUpdatedDate; 10 | } catch (error) { 11 | console.error("Error getting last updated date:", error); 12 | return null; 13 | } 14 | } 15 | 16 | export default async function handler( 17 | req: NextApiRequest, 18 | res: NextApiResponse, 19 | ) { 20 | const { filePath } = req.body; 21 | try { 22 | const lastUpdatedDate = getLastUpdatedDate(filePath); 23 | return res.status(200).json({ lastUpdatedDate }); 24 | } catch (error) { 25 | console.error(error); 26 | return res.status(500).json({ error: "Internal Server Error" }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pages/api/newsletter.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from "next"; 2 | 3 | export default async function handler( 4 | req: NextApiRequest, 5 | res: NextApiResponse, 6 | ) { 7 | const email = req.body; 8 | try { 9 | const headers = { 10 | Authorization: `Bearer ${process.env.SENDER_TOKEN}`, 11 | "Content-Type": "application/json", 12 | Accept: "application/json", 13 | }; 14 | 15 | const data = { 16 | email: email, 17 | groups: ["e1rVB0"], 18 | }; 19 | 20 | const response = await fetch( 21 | `${process.env.NEWSLETTER_BASE_URL}/v2/subscribers`, 22 | { 23 | method: "POST", 24 | headers, 25 | body: JSON.stringify(data), 26 | }, 27 | ).then((response) => response.json()); 28 | if (!response.success) { 29 | console.log("unable to subscribe user"); 30 | } 31 | return res.status(200).json({ response }); 32 | } catch (error) { 33 | console.error(error); 34 | return res.status(500).json({ error: "Internal Server Error" }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /pages/api/search.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from "next"; 2 | 3 | export default async function handler( 4 | req: NextApiRequest, 5 | res: NextApiResponse, 6 | ) { 7 | try { 8 | const { search_term, selected_path } = req.body; 9 | const response = await fetch(`${process.env.BACKEND_URL}/api/search`, { 10 | method: "POST", 11 | headers: { 12 | "Content-Type": "application/json", 13 | }, 14 | body: JSON.stringify({ 15 | search_term: search_term, 16 | selected_path: selected_path, 17 | }), 18 | }); 19 | const apiResponse = await response.json(); 20 | return res.status(response.status).json({ apiResponse }); 21 | } catch { 22 | return res.status(500).json({ error: "Internal Server Error" }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pages/index.mdx: -------------------------------------------------------------------------------- 1 | import LandingPage from "../components/landing-page.tsx"; 2 | 3 | 4 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | # all packages in direct subdirs of packages/ 3 | - "components/*" 4 | # all packages in subdirs of components/ 5 | - "pages/*" 6 | # exclude packages that are inside test directories 7 | - "theme/*" 8 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | "postcss-import": {}, 4 | "tailwindcss/nesting": {}, 5 | tailwindcss: {}, 6 | autoprefixer: {}, 7 | // Add any other PostCSS plugins as needed 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /public/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/public/Logo.png -------------------------------------------------------------------------------- /public/assets/icon_agenticsearch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/assets/icon_almanac.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /public/assets/icon_cosmpy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /public/assets/icon_ledger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /public/assets/icon_mailbox.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /public/assets/icon_multiagentsystem.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /public/assets/icon_ragagent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /public/assets/icon_wallet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /public/assets/iconlogo_agentverse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/iconlogo_asione.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /public/assets/iconlogo_flockx.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/assets/opne-new-tab-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/solana.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/public/favicon.png -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "docs" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Your Name "] 6 | readme = "README.md" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.11" 10 | pyspellchecker = "^0.8.1" 11 | spacy = "^3.8.2" 12 | markdown-it-py = "^3.0.0" 13 | beautifulsoup4 = "^4.13.3" 14 | openai = "^1.68.2" 15 | 16 | 17 | [build-system] 18 | requires = ["poetry-core"] 19 | build-backend = "poetry.core.masonry.api" 20 | -------------------------------------------------------------------------------- /scripts/build-img-revamp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import subprocess 5 | import argparse 6 | 7 | 8 | PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 9 | 10 | REPOSITORY = os.environ.get('IMAGE_REVAMP_REPOSITORY') 11 | 12 | BUILD_ENV_VARS = ( 13 | 'BACKEND_URL', 14 | 'NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID', 15 | 'NEXT_PUBLIC_ALGOLIA_APP_ID', 16 | 'NEXT_PUBLIC_ALGOLIA_API_KEY', 17 | 'NEXT_PUBLIC_ALGOLIA_INDEX', 18 | 'NEWSLETTER_BASE_URL', 19 | 'SENDER_TOKEN' 20 | ) 21 | 22 | 23 | def parse_commandline() -> argparse.Namespace: 24 | parser = argparse.ArgumentParser() 25 | parser.add_argument('-n', '--no-push', dest='push', action='store_false', help='Disable pusing of the image') 26 | parser.add_argument('-f', '--force-build', action='store_true', help=argparse.SUPPRESS) 27 | return parser.parse_args() 28 | 29 | 30 | def detect_local_modifications() -> bool: 31 | exit_code = subprocess.call(['git', 'diff-index', '--quiet', 'HEAD']) 32 | return exit_code != 0 33 | 34 | 35 | def get_version() -> str: 36 | return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode().strip() 37 | 38 | 39 | def main(): 40 | args = parse_commandline() 41 | 42 | # validate the repository environment variable 43 | if REPOSITORY is None: 44 | print('Missing IMAGE_REPOSITORY environment variable') 45 | sys.exit(1) 46 | 47 | # argument validation / augmentation 48 | push = args.push 49 | if detect_local_modifications(): 50 | if args.force_build: 51 | push = False 52 | print('Disabling push of images due to local modifications') 53 | else: 54 | print('Detected local modifications. Please commit and try again') 55 | sys.exit(1) 56 | 57 | # lookup the required information 58 | version = get_version() 59 | 60 | image_url = f'{REPOSITORY}:{version}' 61 | 62 | print() 63 | print(f'Project root: {PROJECT_ROOT}') 64 | print(f'Image Ref...: {image_url}') 65 | print(f'Push........: {push}') 66 | print() 67 | 68 | # Step 0. Collect up the build environment variables 69 | build_args = [] 70 | for env_name in BUILD_ENV_VARS: 71 | if env_name not in os.environ: 72 | print('Missing build variable', env_name) 73 | sys.exit(1) 74 | 75 | build_args.append(f'--build-arg={env_name}={os.environ[env_name]}') 76 | 77 | # Step 1. Build the image 78 | cmd = [ 79 | 'docker', 80 | 'build', 81 | ] + build_args + [ 82 | '--platform', 'linux/amd64', 83 | '-t', image_url, 84 | PROJECT_ROOT, 85 | ] 86 | subprocess.check_call(cmd) 87 | 88 | # Step 2. Push the image 89 | if push: 90 | subprocess.check_call([ 91 | 'docker', 92 | 'push', 93 | image_url, 94 | ]) 95 | 96 | 97 | 98 | if __name__ == '__main__': 99 | main() 100 | -------------------------------------------------------------------------------- /scripts/build-img.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import subprocess 5 | import argparse 6 | 7 | 8 | PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 9 | 10 | REPOSITORY = os.environ.get('IMAGE_REPOSITORY') 11 | 12 | BUILD_ENV_VARS = ( 13 | 'BACKEND_URL', 14 | 'NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID', 15 | 'NEXT_PUBLIC_ALGOLIA_APP_ID', 16 | 'NEXT_PUBLIC_ALGOLIA_API_KEY', 17 | 'NEXT_PUBLIC_ALGOLIA_INDEX', 18 | 'NEWSLETTER_BASE_URL', 19 | 'SENDER_TOKEN' 20 | ) 21 | 22 | 23 | def parse_commandline() -> argparse.Namespace: 24 | parser = argparse.ArgumentParser() 25 | parser.add_argument('-n', '--no-push', dest='push', action='store_false', help='Disable pusing of the image') 26 | parser.add_argument('-f', '--force-build', action='store_true', help=argparse.SUPPRESS) 27 | return parser.parse_args() 28 | 29 | 30 | def detect_local_modifications() -> bool: 31 | exit_code = subprocess.call(['git', 'diff-index', '--quiet', 'HEAD']) 32 | return exit_code != 0 33 | 34 | 35 | def get_version() -> str: 36 | return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode().strip() 37 | 38 | 39 | def main(): 40 | args = parse_commandline() 41 | 42 | # validate the repository environment variable 43 | if REPOSITORY is None: 44 | print('Missing IMAGE_REPOSITORY environment variable') 45 | sys.exit(1) 46 | 47 | # argument validation / augmentation 48 | push = args.push 49 | if detect_local_modifications(): 50 | if args.force_build: 51 | push = False 52 | print('Disabling push of images due to local modifications') 53 | else: 54 | print('Detected local modifications. Please commit and try again') 55 | sys.exit(1) 56 | 57 | # lookup the required information 58 | version = get_version() 59 | 60 | image_url = f'{REPOSITORY}:{version}' 61 | 62 | print() 63 | print(f'Project root: {PROJECT_ROOT}') 64 | print(f'Image Ref...: {image_url}') 65 | print(f'Push........: {push}') 66 | print() 67 | 68 | # Step 0. Collect up the build environment variables 69 | build_args = [] 70 | for env_name in BUILD_ENV_VARS: 71 | if env_name not in os.environ: 72 | print('Missing build variable', env_name) 73 | sys.exit(1) 74 | 75 | build_args.append(f'--build-arg={env_name}={os.environ[env_name]}') 76 | 77 | # Step 1. Build the image 78 | cmd = [ 79 | 'docker', 80 | 'build', 81 | ] + build_args + [ 82 | '--platform', 'linux/amd64', 83 | '-t', image_url, 84 | PROJECT_ROOT, 85 | ] 86 | subprocess.check_call(cmd) 87 | 88 | # Step 2. Push the image 89 | if push: 90 | subprocess.check_call([ 91 | 'docker', 92 | 'push', 93 | image_url, 94 | ]) 95 | 96 | 97 | 98 | if __name__ == '__main__': 99 | main() 100 | -------------------------------------------------------------------------------- /src/images/agentverse/explorer/agentverse-explorer_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/agentverse/explorer/agentverse-explorer_1.png -------------------------------------------------------------------------------- /src/images/concepts/ai-agents/fetpayment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/concepts/ai-agents/fetpayment.png -------------------------------------------------------------------------------- /src/images/concepts/ai-engine/hotel_tasks_go_through_the_engine_to_representative_agents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/concepts/ai-engine/hotel_tasks_go_through_the_engine_to_representative_agents.png -------------------------------------------------------------------------------- /src/images/concepts/ai-engine/system_diagram_ai_engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/concepts/ai-engine/system_diagram_ai_engine.png -------------------------------------------------------------------------------- /src/images/concepts/tech/I1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/concepts/tech/I1.png -------------------------------------------------------------------------------- /src/images/fetch_logo_only_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/images/flockx_collab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/flockx_collab.png -------------------------------------------------------------------------------- /src/images/flockx_nocodeagentstudio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/flockx_nocodeagentstudio.png -------------------------------------------------------------------------------- /src/images/guides/agentverse/agentverse_intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/guides/agentverse/agentverse_intro.png -------------------------------------------------------------------------------- /src/images/landing/leading/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/landing/leading/1.jpg -------------------------------------------------------------------------------- /src/images/landing/leading/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/landing/leading/2.jpg -------------------------------------------------------------------------------- /src/images/landing/leading/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/landing/leading/3.jpg -------------------------------------------------------------------------------- /src/images/landing/leading/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/landing/leading/4.jpg -------------------------------------------------------------------------------- /src/images/landing/leaves.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/landing/leaves.png -------------------------------------------------------------------------------- /src/images/mailroom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/mailroom.png -------------------------------------------------------------------------------- /src/images/scaling-hosting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchai/docs/b1f32c304c67f0f401eec8f098ce3751c953eaeb/src/images/scaling-hosting.png -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/lib/fetch-json.ts: -------------------------------------------------------------------------------- 1 | export class FetchError extends Error { 2 | response: Response; 3 | data: { 4 | message: string; 5 | }; 6 | constructor({ 7 | message, 8 | response, 9 | data, 10 | }: { 11 | message: string; 12 | response: Response; 13 | data: { 14 | message: string; 15 | }; 16 | }) { 17 | super(message); 18 | if (Error.captureStackTrace) { 19 | Error.captureStackTrace(this, FetchError); 20 | } 21 | 22 | this.name = "FetchError"; 23 | this.response = response; 24 | this.data = data ?? { message: message }; 25 | } 26 | } 27 | 28 | export default async function fetchJson( 29 | input: RequestInfo, 30 | init?: RequestInit, 31 | ): Promise { 32 | if ( 33 | init && 34 | init.method && 35 | !init.method.includes("GET") && 36 | init.body && 37 | init.body 38 | ) { 39 | init.body = JSON.stringify(init.body); 40 | if (!init.headers) { 41 | init.headers = {}; 42 | } 43 | init.headers["Content-Type"] = "application/json"; 44 | } 45 | 46 | const response = await fetch(input, init); 47 | const data = await response.json(); 48 | if (response.ok) { 49 | return data; 50 | } 51 | 52 | throw new FetchError({ 53 | message: response.statusText, 54 | response, 55 | data, 56 | }); 57 | } 58 | -------------------------------------------------------------------------------- /src/styles/tailwind.css: -------------------------------------------------------------------------------- 1 | @layer base { 2 | :root { 3 | --shiki-color-text: theme("colors.white"); 4 | --shiki-token-constant: theme("colors.emerald.300"); 5 | --shiki-token-string: theme("colors.emerald.300"); 6 | --shiki-token-comment: theme("colors.zinc.500"); 7 | --shiki-token-keyword: theme("colors.sky.300"); 8 | --shiki-token-parameter: theme("colors.pink.300"); 9 | --shiki-token-function: theme("colors.violet.300"); 10 | --shiki-token-string-expression: theme("colors.emerald.300"); 11 | --shiki-token-punctuation: theme("colors.zinc.200"); 12 | } 13 | 14 | [inert] ::-webkit-scrollbar { 15 | display: none; 16 | } 17 | } 18 | 19 | @tailwind base; 20 | @tailwind components; 21 | @tailwind utilities; 22 | -------------------------------------------------------------------------------- /src/svgs/agent-functions.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/svgs/ai-engine.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/svgs/almanac.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/svgs/analytics.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/svgs/api-agents.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/svgs/cosmpy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/svgs/courses-background.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/svgs/courses-stack.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/svgs/dark-course-stack.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/svgs/dark-ethereum.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/svgs/dark-fast-api.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/svgs/dark-openai.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/svgs/delta-v.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/svgs/desktop/footer_left_bottom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/svgs/desktop/footer_left_top.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/svgs/desktop/footer_right_green.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/svgs/desktop/footer_right_purple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/svgs/desktop/search-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/svgs/ethereum.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/svgs/explorer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/svgs/external-link.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/svgs/fastapi.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/svgs/hosting.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/svgs/internal-link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/svgs/langchain.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/svgs/ledger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/svgs/mac.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/svgs/mailbox.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/svgs/mobile/footer_left_bottom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/svgs/mobile/footer_right_green.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/svgs/mobile/footer_right_purple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/svgs/mobile/footer_top.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/svgs/openai.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/svgs/profile.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | -------------------------------------------------------------------------------- /src/svgs/synergy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/svgs/wallet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/svgs/windows.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /styles/hamburger.css: -------------------------------------------------------------------------------- 1 | .nextra-hamburger svg { 2 | g { 3 | @apply nx-origin-center; 4 | transition: transform 0.2s cubic-bezier(0.25, 1, 0.5, 1); 5 | } 6 | path { 7 | opacity: 1; 8 | transition: 9 | transform 0.2s cubic-bezier(0.25, 1, 0.5, 1) 0.2s, 10 | opacity 0.2s ease 0.2s; 11 | } 12 | 13 | &.open { 14 | path { 15 | transition: 16 | transform 0.2s cubic-bezier(0.25, 1, 0.5, 1), 17 | opacity 0s ease 0.2s; 18 | } 19 | g { 20 | transition: transform 0.2s cubic-bezier(0.25, 1, 0.5, 1) 0.2s; 21 | } 22 | } 23 | 24 | &.open > { 25 | path { 26 | @apply nx-opacity-0; 27 | } 28 | g:nth-of-type(1) { 29 | @apply nx-rotate-45; 30 | path { 31 | transform: translate3d(0, 6px, 0); 32 | } 33 | } 34 | g:nth-of-type(2) { 35 | @apply -nx-rotate-45; 36 | path { 37 | transform: translate3d(0, -6px, 0); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /styles/typesetting-article.css: -------------------------------------------------------------------------------- 1 | article.nextra-body-typesetting-article { 2 | font-size: 17px; 3 | font-feature-settings: 4 | "rlig" 1, 5 | "calt" 1; 6 | h1 { 7 | @apply nx-mt-6 nx-mb-4 nx-text-center; 8 | font-size: 2.5rem; 9 | } 10 | h2 { 11 | @apply nx-border-none; 12 | } 13 | a { 14 | @apply nx-no-underline hover:nx-underline; 15 | } 16 | p { 17 | @apply nx-leading-8; 18 | } 19 | code { 20 | @apply nx-border-none dark:nx-bg-neutral-700; 21 | } 22 | pre code { 23 | @apply dark:nx-bg-transparent; 24 | } 25 | .subheading-anchor + a { 26 | @apply nx-no-underline hover:nx-no-underline after:nx-hidden; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | const colors = require("tailwindcss/colors"); 2 | 3 | const makePrimaryColor = 4 | (l) => 5 | ({ opacityValue }) => { 6 | if (opacityValue === undefined) { 7 | return `hsl(var(--nextra-primary-hue) 100% ${l}%)`; 8 | } 9 | return `hsl(var(--nextra-primary-hue) 100% ${l}% / ${opacityValue})`; 10 | }; 11 | 12 | module.exports = { 13 | prefix: "nx-", 14 | content: [ 15 | "./pages/**/*.{js,mjs,jsx,ts,tsx,mdx}", 16 | "./components/**/*.{js,mjs,jsx,ts,tsx,mdx}", 17 | // './styles/**/*.css', // Add this line to include the nextra-theme-docs CSS files 18 | ], 19 | theme: { 20 | screens: { 21 | sm: "640px", 22 | md: "768px", 23 | lg: "1024px", 24 | xl: "1280px", 25 | "2xl": "1536px", 26 | }, 27 | fontSize: { 28 | xs: ".75rem", 29 | sm: ".875rem", 30 | base: "1rem", 31 | lg: "1.125rem", 32 | xl: "1.25rem", 33 | "2xl": "1.5rem", 34 | "3xl": "1.875rem", 35 | "4xl": "2.25rem", 36 | "5xl": "3rem", 37 | "6xl": "4rem", 38 | }, 39 | letterSpacing: { 40 | tight: "-0.015em", 41 | }, 42 | colors: { 43 | transparent: "transparent", 44 | current: "currentColor", 45 | black: "#000", 46 | white: "#fff", 47 | gray: colors.gray, 48 | slate: colors.slate, 49 | neutral: colors.neutral, 50 | red: colors.red, 51 | orange: colors.orange, 52 | blue: colors.blue, 53 | yellow: colors.yellow, 54 | primary: { 55 | 50: makePrimaryColor(97), 56 | 100: makePrimaryColor(94), 57 | 200: makePrimaryColor(86), 58 | 300: makePrimaryColor(77), 59 | 400: makePrimaryColor(66), 60 | 500: makePrimaryColor(50), 61 | 600: makePrimaryColor(45), 62 | 700: makePrimaryColor(39), 63 | 750: makePrimaryColor(35), 64 | 800: makePrimaryColor(32), 65 | 900: makePrimaryColor(24), 66 | }, 67 | }, 68 | extend: { 69 | colors: { 70 | dark: "#111", 71 | }, 72 | }, 73 | }, 74 | darkMode: ["class", 'html[class~="dark"]'], 75 | }; 76 | -------------------------------------------------------------------------------- /theme.config.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { DocsThemeConfig } from "./theme/fetch-ai-docs"; 3 | import Footer from "./components/footer"; 4 | import Logo from "components/logo"; 5 | 6 | const config: DocsThemeConfig = { 7 | logo: , 8 | project: { 9 | link: "https://github.com/fetchai", 10 | }, 11 | chat: { 12 | link: "https://discord.gg/fetchai", 13 | }, 14 | docsRepositoryBase: "https://github.com/fetchai/docs/tree/master/pages", 15 | footer: { 16 | component: , 17 | }, 18 | search: { 19 | placeholder: "Search in documentation", 20 | }, 21 | darkMode: false, 22 | head: ( 23 | <> 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 | 39 | 40 | 49 | > 50 | ), 51 | }; 52 | 53 | export default config; 54 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/anchor.tsx: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-restricted-imports -- only in this file we determine either we include as child of based of `newNextLinkBehavior` value 2 | import NextLink from "next/link"; 3 | import next from "next/package.json"; 4 | import type { ComponentProps, ReactElement } from "react"; 5 | import { forwardRef } from "react"; 6 | import { useConfig } from "../contexts"; 7 | import React from "react"; 8 | 9 | export type AnchorProps = Omit, "ref"> & { 10 | newWindow?: boolean; 11 | }; 12 | 13 | const nextVersion = Number(next.version.split(".")[0]); 14 | 15 | export const Anchor = forwardRef(function ( 16 | { href = "", children, newWindow, ...props }, 17 | // ref is used in 18 | forwardedRef, 19 | ): ReactElement { 20 | const config = useConfig(); 21 | 22 | if (newWindow) { 23 | return ( 24 | 31 | {children} 32 | (opens in a new tab) 33 | 34 | ); 35 | } 36 | 37 | if (!href) { 38 | return ( 39 | 40 | {children} 41 | 42 | ); 43 | } 44 | 45 | if (nextVersion > 12 || config.newNextLinkBehavior) { 46 | return ( 47 | 48 | {children} 49 | 50 | ); 51 | } 52 | 53 | return ( 54 | 55 | 56 | {children} 57 | 58 | 59 | ); 60 | }); 61 | 62 | Anchor.displayName = "Anchor"; 63 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/banner.tsx: -------------------------------------------------------------------------------- 1 | import cn from "clsx"; 2 | import React from "react"; 3 | import { XIcon } from "nextra/icons"; 4 | import type { ReactElement } from "react"; 5 | import { useConfig } from "../contexts"; 6 | import { renderComponent } from "../utils"; 7 | 8 | export function Banner(): ReactElement | null { 9 | const { banner } = useConfig(); 10 | if (!banner.text) { 11 | return null; 12 | } 13 | const hideBannerScript = `try{if(localStorage.getItem(${JSON.stringify( 14 | banner.key, 15 | )})==='0'){document.body.classList.add('nextra-banner-hidden')}}catch(e){}`; 16 | 17 | return ( 18 | <> 19 | 20 | 28 | 29 | {renderComponent(banner.text)} 30 | 31 | {banner.dismissible && ( 32 | { 37 | try { 38 | localStorage.setItem(banner.key, "0"); 39 | } catch { 40 | /* ignore */ 41 | } 42 | document.body.classList.add("nextra-banner-hidden"); 43 | }} 44 | > 45 | 46 | 47 | )} 48 | 49 | > 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/breadcrumb.tsx: -------------------------------------------------------------------------------- 1 | import cn from "clsx"; 2 | import React from "react"; 3 | import { ArrowRightIcon } from "nextra/icons"; 4 | import type { Item } from "nextra/normalize-pages"; 5 | import type { ReactElement } from "react"; 6 | import { Fragment } from "react"; 7 | import { Anchor } from "./anchor"; 8 | 9 | export function Breadcrumb({ 10 | activePath, 11 | }: { 12 | activePath: Item[]; 13 | }): ReactElement { 14 | return ( 15 | 16 | {activePath.map((item, index) => { 17 | const isLink = !item.children || item.withIndexPage; 18 | const isActive = index === activePath.length - 1; 19 | return ( 20 | 21 | {index > 0 && } 22 | 35 | {isLink && !isActive ? ( 36 | {item.title} 37 | ) : ( 38 | activePath?.length > 1 && item.title 39 | )} 40 | 41 | 42 | ); 43 | })} 44 | 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/collapse.tsx: -------------------------------------------------------------------------------- 1 | import cn from "clsx"; 2 | import React from "react"; 3 | 4 | import type { ReactElement, ReactNode } from "react"; 5 | import { useEffect, useRef } from "react"; 6 | 7 | export function Collapse({ 8 | children, 9 | className, 10 | isOpen, 11 | horizontal = false, 12 | }: { 13 | children: ReactNode; 14 | className?: string; 15 | isOpen: boolean; 16 | horizontal?: boolean; 17 | }): ReactElement { 18 | const containerRef = useRef(null); 19 | const innerRef = useRef(null); 20 | const animationRef = useRef(0); 21 | const initialOpen = useRef(isOpen); 22 | const initialRender = useRef(true); 23 | 24 | useEffect(() => { 25 | const container = containerRef.current; 26 | const inner = innerRef.current; 27 | const animation = animationRef.current; 28 | if (animation) { 29 | clearTimeout(animation); 30 | } 31 | if (initialRender.current || !container || !inner) return; 32 | 33 | container.classList.toggle("nx-duration-500", !isOpen); 34 | container.classList.toggle("nx-duration-300", isOpen); 35 | 36 | if (horizontal) { 37 | // save initial width to avoid word wrapping when container width will be changed 38 | inner.style.width = `${inner.clientWidth}px`; 39 | container.style.width = `${inner.clientWidth}px`; 40 | } else { 41 | container.style.height = `${inner.clientHeight}px`; 42 | } 43 | 44 | if (isOpen) { 45 | animationRef.current = window.setTimeout(() => { 46 | // should be style property in kebab-case, not css class name 47 | container.style.removeProperty("height"); 48 | }, 300); 49 | } else { 50 | setTimeout(() => { 51 | if (horizontal) { 52 | container.style.width = "0px"; 53 | } else { 54 | container.style.height = "0px"; 55 | } 56 | }, 0); 57 | } 58 | }, [horizontal, isOpen]); 59 | 60 | useEffect(() => { 61 | initialRender.current = false; 62 | }, []); 63 | 64 | return ( 65 | 70 | 78 | {children} 79 | 80 | 81 | ); 82 | } 83 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/footer.tsx: -------------------------------------------------------------------------------- 1 | import cn from "clsx"; 2 | import React from "react"; 3 | import type { ReactElement } from "react"; 4 | import { useConfig } from "../contexts"; 5 | import { renderComponent } from "../utils"; 6 | 7 | export function Footer({ menu }: { menu?: boolean }): ReactElement { 8 | const config = useConfig(); 9 | return ( 10 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/head.tsx: -------------------------------------------------------------------------------- 1 | import type { NextSeoProps } from "next-seo"; 2 | import React from "react"; 3 | import { NextSeo } from "next-seo"; 4 | import { useTheme } from "next-themes"; 5 | import NextHead from "next/head"; 6 | import { useMounted } from "nextra/hooks"; 7 | import type { ReactElement } from "react"; 8 | import { useConfig } from "../contexts"; 9 | import { useRouter } from "next/router"; 10 | 11 | export function Head(): ReactElement { 12 | const config = useConfig(); 13 | const { resolvedTheme } = useTheme(); 14 | const mounted = useMounted(); 15 | const router = useRouter(); 16 | const DOMAIN = "https://fetch.ai"; 17 | 18 | // `head` can be either FC or ReactNode. We have to directly call it if it's an 19 | // FC because hooks like Next.js' `useRouter` aren't allowed inside NextHead. 20 | const head = 21 | typeof config.head === "function" ? config.head({}) : config.head; 22 | const hue = config.primaryHue; 23 | const { dark: darkHue, light: lightHue } = 24 | typeof hue === "number" ? { dark: hue, light: hue } : hue; 25 | const frontMatter = config.frontMatter as NextSeoProps; 26 | 27 | return ( 28 | <> 29 | 36 | 37 | {mounted ? ( 38 | 42 | ) : ( 43 | <> 44 | 49 | 54 | > 55 | )} 56 | 60 | 72 | {head} 73 | 74 | > 75 | ); 76 | } 77 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/highlight-matches.tsx: -------------------------------------------------------------------------------- 1 | import escapeStringRegexp from "escape-string-regexp"; 2 | import React from "react"; 3 | import type { ReactElement, ReactNode } from "react"; 4 | import { memo } from "react"; 5 | 6 | type MatchArgs = { 7 | value?: string; 8 | match: string; 9 | }; 10 | 11 | export const HighlightMatches = memo(function HighlightMatches({ 12 | value, 13 | match, 14 | }: MatchArgs): ReactElement | null { 15 | if (!value) { 16 | return null; 17 | } 18 | // eslint-disable-next-line unicorn/prefer-spread 19 | const splitText = value.split(""); 20 | const escapedSearch = escapeStringRegexp(match.trim()); 21 | const regexp = new RegExp(escapedSearch.replaceAll(" ", "|"), "ig"); 22 | let result; 23 | let index = 0; 24 | const content: (string | ReactNode)[] = []; 25 | 26 | while ( 27 | (result = regexp.exec(value)) && 28 | // case `> ` replaced previously to `>||` + some character provoke memory leak because 29 | // `RegExp#exec` will always return a match 30 | regexp.lastIndex !== 0 31 | ) { 32 | const before = splitText.splice(0, result.index - index).join(""); 33 | const after = splitText.splice(0, regexp.lastIndex - result.index).join(""); 34 | content.push( 35 | before, 36 | 37 | {after} 38 | , 39 | ); 40 | index = regexp.lastIndex; 41 | } 42 | 43 | return ( 44 | <> 45 | {content} 46 | {splitText.join("")} 47 | > 48 | ); 49 | }); 50 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/index.ts: -------------------------------------------------------------------------------- 1 | export { Anchor } from "./anchor"; 2 | export { Banner } from "./banner"; 3 | export { Breadcrumb } from "./breadcrumb"; 4 | export { Collapse } from "./collapse"; 5 | export { Footer } from "./footer"; 6 | export { Head } from "./head"; 7 | export { Input } from "./input"; 8 | export { NavLinks } from "./nav-links"; 9 | export { Navbar } from "./navbar"; 10 | export { NotFoundPage } from "./not-found"; 11 | export { Search } from "./search"; 12 | export { InstantAlgoliaSearch } from "./instant-algolia-search"; 13 | export { Select } from "./select"; 14 | export { ServerSideErrorPage } from "./server-side-error"; 15 | export { Sidebar } from "./sidebar"; 16 | export { SkipNavContent, SkipNavLink } from "./skip-nav"; 17 | export { TOC } from "./toc"; 18 | export { ThemeSwitcher } from "./theme-switcher"; 19 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/input.tsx: -------------------------------------------------------------------------------- 1 | import cn from "clsx"; 2 | import React from "react"; 3 | import type { ComponentProps, ReactNode } from "react"; 4 | import { forwardRef } from "react"; 5 | 6 | type InputProps = ComponentProps<"input"> & { suffix?: ReactNode }; 7 | 8 | export const Input = forwardRef( 9 | ({ className, suffix, ...props }, forwardedRef) => ( 10 | 11 | 25 | {suffix} 26 | 27 | ), 28 | ); 29 | 30 | Input.displayName = "Input"; 31 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/match-sorter-search.tsx: -------------------------------------------------------------------------------- 1 | import { matchSorter } from "match-sorter"; 2 | import React from "react"; 3 | import type { Item as NormalItem } from "nextra/normalize-pages"; 4 | import type { ReactElement } from "react"; 5 | import { useMemo, useState } from "react"; 6 | import type { SearchResult } from "../types"; 7 | import { HighlightMatches } from "./highlight-matches"; 8 | import { Search } from "./search"; 9 | 10 | export function MatchSorterSearch({ 11 | className, 12 | directories, 13 | }: { 14 | className?: string; 15 | directories: NormalItem[]; 16 | }): ReactElement { 17 | const [search, setSearch] = useState(""); 18 | const results = useMemo( 19 | () => 20 | // Will need to scrape all the headers from each page and search through them here 21 | // (similar to what we already do to render the hash links in sidebar) 22 | // We could also try to search the entire string text from each page 23 | search 24 | ? matchSorter(directories, search, { keys: ["tags", "title"] }).map( 25 | ({ route, title }) => ({ 26 | id: route + title, 27 | route, 28 | children: , 29 | }), 30 | ) 31 | : [], 32 | [search, directories], 33 | ); 34 | 35 | return ( 36 | 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/nav-links.tsx: -------------------------------------------------------------------------------- 1 | import cn from "clsx"; 2 | import React from "react"; 3 | import { ArrowRightIcon } from "nextra/icons"; 4 | import type { Item } from "nextra/normalize-pages"; 5 | import type { ReactElement } from "react"; 6 | import { useConfig } from "../contexts"; 7 | import type { DocsThemeConfig } from "../index"; 8 | import { Anchor } from "./anchor"; 9 | 10 | interface NavLinkProps { 11 | currentIndex: number; 12 | flatDirectories: Item[]; 13 | } 14 | 15 | const classes = { 16 | link: cn( 17 | "nx-flex nx-max-w-[50%] nx-items-center nx-gap-1 nx-py-4 nx-text-base nx-font-medium nx-text-gray-600 nx-transition-colors [word-break:break-word] hover:nx-text-primary-600 dark:nx-text-gray-300 md:nx-text-lg", 18 | ), 19 | icon: cn("nx-inline nx-h-5 nx-shrink-0"), 20 | }; 21 | 22 | export const NavLinks = ({ 23 | flatDirectories, 24 | currentIndex, 25 | }: NavLinkProps): ReactElement | null => { 26 | const config = useConfig(); 27 | const nav = config.navigation; 28 | const navigation: Exclude = 29 | typeof nav === "boolean" ? { prev: nav, next: nav } : nav; 30 | 31 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 32 | let prev: any = navigation.prev && flatDirectories[currentIndex - 1]; 33 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 34 | let next: any = navigation.next && flatDirectories[currentIndex + 1]; 35 | 36 | if (prev && !prev.isUnderCurrentDocsTree) prev = false; 37 | if (next && !next.isUnderCurrentDocsTree) next = false; 38 | 39 | if (!prev && !next) return null; 40 | 41 | return ( 42 | 49 | {prev && ( 50 | 55 | 56 | {prev.title} 57 | 58 | )} 59 | {next && ( 60 | 68 | {next.title} 69 | 70 | 71 | )} 72 | 73 | ); 74 | }; 75 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { useRouter } from "next/router"; 2 | import React from "react"; 3 | import { useMounted } from "nextra/hooks"; 4 | import type { ReactElement } from "react"; 5 | import { useConfig } from "../contexts"; 6 | import { getGitIssueUrl, renderComponent } from "../utils"; 7 | import { Anchor } from "./anchor"; 8 | 9 | export function NotFoundPage(): ReactElement | null { 10 | const config = useConfig(); 11 | const mounted = useMounted(); 12 | const { asPath } = useRouter(); 13 | const { content, labels } = config.notFound; 14 | if (!content) { 15 | return null; 16 | } 17 | 18 | return ( 19 | 20 | 29 | {renderComponent(content)} 30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/search-model.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/no-unknown-property */ 2 | import React, { useEffect, ReactNode } from "react"; 3 | import ReactDOM from "react-dom"; 4 | 5 | interface ModalProps { 6 | isOpen: boolean; 7 | onClose: () => void; 8 | children: ReactNode; 9 | } 10 | 11 | const Modal = ({ isOpen, onClose, children }: ModalProps) => { 12 | useEffect(() => { 13 | const closeOnEscapeKey = (e: KeyboardEvent) => 14 | e.key === "Escape" ? onClose() : null; 15 | document.body.addEventListener("keydown", closeOnEscapeKey); 16 | 17 | document.body.style.overflow = isOpen ? "hidden" : "unset"; 18 | 19 | return () => { 20 | document.body.removeEventListener("keydown", closeOnEscapeKey); 21 | document.body.style.overflow = "unset"; 22 | }; 23 | }, [isOpen, onClose]); 24 | 25 | if (!isOpen) return null; 26 | 27 | return ReactDOM.createPortal( 28 | 29 | 30 | e.stopPropagation()} 33 | > 34 | {children} 35 | 36 | 37 | 38 | 125 | , 126 | // eslint-disable-next-line unicorn/prefer-query-selector 127 | document.getElementById("modal-root") as HTMLElement, 128 | ); 129 | }; 130 | 131 | export default Modal; 132 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/select.tsx: -------------------------------------------------------------------------------- 1 | import { Listbox, Transition } from "@headlessui/react"; 2 | import cn from "clsx"; 3 | import React from "react"; 4 | import { useMounted } from "nextra/hooks"; 5 | import { CheckIcon } from "nextra/icons"; 6 | import type { ReactElement, ReactNode } from "react"; 7 | import { createPortal } from "react-dom"; 8 | import { usePopper } from "../utils"; 9 | 10 | interface MenuOption { 11 | key: string; 12 | name: ReactElement | string; 13 | } 14 | 15 | interface MenuProps { 16 | selected: MenuOption; 17 | onChange: (option: MenuOption) => void; 18 | options: MenuOption[]; 19 | title?: string; 20 | className?: string; 21 | } 22 | 23 | export function Select({ 24 | options, 25 | selected, 26 | onChange, 27 | title, 28 | className, 29 | }: MenuProps): ReactElement { 30 | const [trigger, container] = usePopper({ 31 | strategy: "fixed", 32 | placement: "top-start", 33 | modifiers: [ 34 | { name: "offset", options: { offset: [0, 10] } }, 35 | { 36 | name: "sameWidth", 37 | enabled: true, 38 | fn({ state }) { 39 | state.styles.popper.minWidth = `${state.rects.reference.width}px`; 40 | }, 41 | phase: "beforeWrite", 42 | requires: ["computeStyles"], 43 | }, 44 | ], 45 | }); 46 | 47 | return ( 48 | 49 | {({ open }) => ( 50 | 61 | {selected.name} 62 | 63 | 72 | {options.map((option) => ( 73 | 77 | cn( 78 | active 79 | ? "nx-bg-primary-50 nx-text-primary-600 dark:nx-bg-primary-500/10" 80 | : "nx-text-gray-800 dark:nx-text-gray-100", 81 | "nx-relative nx-cursor-pointer nx-whitespace-nowrap nx-py-1.5", 82 | "nx-transition-colors ltr:nx-pl-3 ltr:nx-pr-9 rtl:nx-pr-3 rtl:nx-pl-9", 83 | ) 84 | } 85 | > 86 | {option.name} 87 | {option.key === selected.key && ( 88 | 89 | 90 | 91 | )} 92 | 93 | ))} 94 | 95 | 96 | 97 | )} 98 | 99 | ); 100 | } 101 | 102 | function Portal(props: { children: ReactNode }): ReactElement | null { 103 | const mounted = useMounted(); 104 | if (!mounted) return null; 105 | return createPortal(props.children, document.body); 106 | } 107 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/components/server-side-error.tsx: -------------------------------------------------------------------------------- 1 | import { useRouter } from "next/router"; 2 | import React from "react"; 3 | import { useMounted } from "nextra/hooks"; 4 | import type { ReactElement } from "react"; 5 | import { useConfig } from "../contexts"; 6 | import { getGitIssueUrl, renderComponent } from "../utils"; 7 | import { Anchor } from "./anchor"; 8 | 9 | export function ServerSideErrorPage(): ReactElement | null { 10 | const config = useConfig(); 11 | const mounted = useMounted(); 12 | const { asPath } = useRouter(); 13 | const { content, labels } = config.serverSideError; 14 | if (!content) { 15 | return null; 16 | } 17 | 18 | return ( 19 | 20 | 31 | {renderComponent(content)} 32 | 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/contexts/active-anchor.tsx: -------------------------------------------------------------------------------- 1 | import type { Dispatch, ReactElement, ReactNode, SetStateAction } from "react"; 2 | import "intersection-observer"; 3 | import { createContext, useContext, useRef, useState } from "react"; 4 | import { IS_BROWSER } from "../constants"; 5 | import React from "react"; 6 | 7 | type ActiveAnchor = Record< 8 | string, 9 | { 10 | isActive?: boolean; 11 | aboveHalfViewport: boolean; 12 | index: number; 13 | insideHalfViewport: boolean; 14 | } 15 | >; 16 | 17 | const ActiveAnchorContext = createContext({}); 18 | const SetActiveAnchorContext = createContext< 19 | Dispatch> 20 | >((v) => v); 21 | 22 | const IntersectionObserverContext = createContext( 23 | null, 24 | ); 25 | const slugs = new WeakMap(); 26 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 27 | const SlugsContext = createContext>(slugs); 28 | // Separate the state as 2 contexts here to avoid 29 | // re-renders of the content triggered by the state update. 30 | export const useActiveAnchor = () => useContext(ActiveAnchorContext); 31 | export const useSetActiveAnchor = () => useContext(SetActiveAnchorContext); 32 | 33 | export const useIntersectionObserver = () => 34 | useContext(IntersectionObserverContext); 35 | export const useSlugs = () => useContext(SlugsContext); 36 | 37 | export const ActiveAnchorProvider = ({ 38 | children, 39 | }: { 40 | children: ReactNode; 41 | }): ReactElement => { 42 | const [activeAnchor, setActiveAnchor] = useState({}); 43 | const observerRef = useRef(null); 44 | if (IS_BROWSER && !observerRef.current) { 45 | observerRef.current = new IntersectionObserver( 46 | (entries) => { 47 | setActiveAnchor((f) => { 48 | const ret = { ...f }; 49 | 50 | for (const entry of entries) { 51 | if (entry?.rootBounds && slugs.has(entry.target)) { 52 | const [slug, index] = slugs.get(entry.target); 53 | const aboveHalfViewport = 54 | entry.boundingClientRect.y + entry.boundingClientRect.height <= 55 | entry.rootBounds.y + entry.rootBounds.height; 56 | const insideHalfViewport = entry.intersectionRatio > 0; 57 | ret[slug] = { 58 | index, 59 | aboveHalfViewport, 60 | insideHalfViewport, 61 | }; 62 | } 63 | } 64 | 65 | let activeSlug = ""; 66 | let smallestIndexInViewport = Number.POSITIVE_INFINITY; 67 | let largestIndexAboveViewport = -1; 68 | for (const s in ret) { 69 | ret[s].isActive = false; 70 | if ( 71 | ret[s].insideHalfViewport && 72 | ret[s].index < smallestIndexInViewport 73 | ) { 74 | smallestIndexInViewport = ret[s].index; 75 | activeSlug = s; 76 | } 77 | if ( 78 | smallestIndexInViewport === Number.POSITIVE_INFINITY && 79 | ret[s].aboveHalfViewport && 80 | ret[s].index > largestIndexAboveViewport 81 | ) { 82 | largestIndexAboveViewport = ret[s].index; 83 | activeSlug = s; 84 | } 85 | } 86 | 87 | if (ret[activeSlug]) ret[activeSlug].isActive = true; 88 | return ret; 89 | }); 90 | }, 91 | { 92 | rootMargin: "0px 0px -50%", 93 | threshold: [0, 1], 94 | }, 95 | ); 96 | } 97 | return ( 98 | 99 | 100 | 101 | 102 | {children} 103 | 104 | 105 | 106 | 107 | ); 108 | }; 109 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/contexts/details.ts: -------------------------------------------------------------------------------- 1 | import type { Dispatch, SetStateAction } from "react"; 2 | import { createContext, useContext } from "react"; 3 | 4 | const DetailsContext = createContext>>( 5 | (v) => v, 6 | ); 7 | 8 | export const useDetails = () => useContext(DetailsContext); 9 | 10 | export const DetailsProvider = DetailsContext.Provider; 11 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/contexts/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | useActiveAnchor, 3 | useSetActiveAnchor, 4 | ActiveAnchorProvider, 5 | } from "./active-anchor"; 6 | export { useConfig, ConfigProvider } from "./config"; 7 | export { useDetails, DetailsProvider } from "./details"; 8 | export { useMenu } from "./menu"; 9 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/contexts/menu.ts: -------------------------------------------------------------------------------- 1 | import type { Dispatch, SetStateAction } from "react"; 2 | import { createContext, useContext } from "react"; 3 | 4 | interface Menu { 5 | menu: boolean; 6 | setMenu: Dispatch>; 7 | } 8 | 9 | const MenuContext = createContext({ 10 | menu: false, 11 | setMenu: () => false, 12 | }); 13 | 14 | export const useMenu = () => useContext(MenuContext); 15 | 16 | export const MenuProvider = MenuContext.Provider; 17 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/contexts/os-provider.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useContext, useEffect, useState } from "react"; 2 | 3 | const OSContext = createContext<{ 4 | selectedOS: string; 5 | setSelectedOS: (os: string) => void; 6 | }>({ 7 | selectedOS: "windows", 8 | setSelectedOS: () => {}, 9 | }); 10 | 11 | export const OSProvider: React.FC<{ children: React.ReactNode }> = ({ 12 | children, 13 | }) => { 14 | const [selectedOS, setSelectedOS] = useState("windows"); 15 | 16 | useEffect(() => { 17 | const osString = localStorage.getItem("storedOsOption") || "windows"; 18 | setSelectedOS(osString); 19 | }, []); 20 | 21 | return ( 22 | 23 | {children} 24 | 25 | ); 26 | }; 27 | 28 | export const useOSContext = () => useContext(OSContext); 29 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/contexts/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { ThemeProvider } from "next-themes"; 3 | import React from "react"; 4 | export function ThemeDocProvider({ children }: { children: React.ReactNode }) { 5 | return ( 6 | 7 | {children} 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/helpers.ts: -------------------------------------------------------------------------------- 1 | export const isLinkInResponse = (response) => { 2 | const flattenedArray = response?.flat(); 3 | const isPresent = flattenedArray?.includes( 4 | typeof window === "undefined" ? "" : window.location.pathname, 5 | ); 6 | return isPresent; 7 | }; 8 | 9 | export const addUnderscoreInText = (text) => { 10 | const lowercasedText = text.toLowerCase(); 11 | const snakecasedText = lowercasedText.replaceAll(/\s+/g, "_"); 12 | return snakecasedText; 13 | }; 14 | 15 | export enum ThemeMode { 16 | Light = "light", 17 | Dark = "dark", 18 | } 19 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/polyfill.ts: -------------------------------------------------------------------------------- 1 | import { IS_BROWSER } from "./constants"; 2 | 3 | if (IS_BROWSER) { 4 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 5 | let resizeTimer: any; 6 | 7 | const addResizingClass = () => { 8 | document.body.classList.add("resizing"); 9 | clearTimeout(resizeTimer); 10 | resizeTimer = setTimeout(() => { 11 | document.body.classList.remove("resizing"); 12 | }, 200); 13 | }; 14 | 15 | window.addEventListener("resize", addResizingClass); 16 | } 17 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/types.ts: -------------------------------------------------------------------------------- 1 | import type { PageOpts } from "nextra"; 2 | import type { ReactNode } from "react"; 3 | import type { DocsThemeConfig } from "./constants"; 4 | 5 | export type Context = { 6 | pageOpts: PageOpts; 7 | themeConfig: DocsThemeConfig; 8 | }; 9 | 10 | export type SearchResult = { 11 | children: ReactNode; 12 | id: string; 13 | prefix?: ReactNode; 14 | route: string; 15 | }; 16 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/utils/get-git-issue-url.ts: -------------------------------------------------------------------------------- 1 | import gitUrlParse from "git-url-parse"; 2 | 3 | export const getGitIssueUrl = ({ 4 | repository = "", 5 | title, 6 | labels, 7 | }: { 8 | repository?: string; 9 | title: string; 10 | labels?: string; 11 | }): string => { 12 | const repo = gitUrlParse(repository); 13 | if (!repo) throw new Error("Invalid `docsRepositoryBase` URL!"); 14 | 15 | if (repo.resource.includes("gitlab")) { 16 | return `${repo.protocol}://${repo.resource}/${repo.owner}/${ 17 | repo.name 18 | }/-/issues/new?issue[title]=${encodeURIComponent(title)}`; 19 | } 20 | if (repo.resource.includes("github")) { 21 | return `${repo.protocol}://${repo.resource}/${repo.owner}/${ 22 | repo.name 23 | }/issues/new?title=${encodeURIComponent(title)}&labels=${labels || ""}`; 24 | } 25 | return "#"; 26 | }; 27 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { getGitIssueUrl } from "./get-git-issue-url"; 2 | export { renderComponent, renderString } from "./render"; 3 | export { usePopper } from "./use-popper"; 4 | export { useGitEditUrl } from "./use-git-edit-url"; 5 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/utils/render.tsx: -------------------------------------------------------------------------------- 1 | import type { FC, ReactNode } from "react"; 2 | import React from "react"; 3 | 4 | export function renderComponent( 5 | ComponentOrNode: FC | ReactNode, 6 | props?: T, 7 | ) { 8 | if (!ComponentOrNode) return null; 9 | if (typeof ComponentOrNode !== "function") return ComponentOrNode; 10 | return ; 11 | } 12 | 13 | export function renderString( 14 | stringOrFunction?: string | ((props: T) => string), 15 | // @ts-expect-error TS2322: Type '{}' is not assignable to type 'T'. 16 | props: T = {}, 17 | ): string { 18 | const result = 19 | typeof stringOrFunction === "function" 20 | ? stringOrFunction(props) 21 | : stringOrFunction; 22 | return result || ""; 23 | } 24 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/utils/use-git-edit-url.ts: -------------------------------------------------------------------------------- 1 | import gitUrlParse from "git-url-parse"; 2 | import { useConfig } from "../contexts"; 3 | 4 | export function useGitEditUrl(filePath = ""): string { 5 | const config = useConfig(); 6 | const repo = gitUrlParse(config.docsRepositoryBase || ""); 7 | 8 | if (!repo) throw new Error("Invalid `docsRepositoryBase` URL!"); 9 | 10 | return filePath.includes("/references/uagents/api") 11 | ? `${repo.href}/${filePath}.md` 12 | : `${repo.href}/${filePath}.mdx`; 13 | } 14 | -------------------------------------------------------------------------------- /theme/fetch-ai-docs/utils/use-popper.ts: -------------------------------------------------------------------------------- 1 | import type { Options } from "@popperjs/core"; 2 | import { createPopper } from "@popperjs/core"; 3 | import type { RefCallback } from "react"; 4 | import { useCallback, useMemo, useRef } from "react"; 5 | 6 | /** 7 | * https://github.com/tailwindlabs/headlessui/issues/59 8 | * Example implementation to use Popper: https://popper.js.org 9 | */ 10 | export function usePopper( 11 | options?: Partial, 12 | ): [RefCallback, RefCallback] { 13 | const reference = useRef(null); 14 | const popper = useRef(null); 15 | 16 | const cleanupCallback = useRef<() => void>(); 17 | 18 | const instantiatePopper = useCallback(() => { 19 | if (!reference.current || !popper.current) return; 20 | 21 | cleanupCallback.current?.(); 22 | cleanupCallback.current = createPopper( 23 | reference.current, 24 | popper.current, 25 | options, 26 | ).destroy; 27 | }, [reference, popper, cleanupCallback, options]); 28 | 29 | return useMemo( 30 | () => [ 31 | (referenceDomNode) => { 32 | reference.current = referenceDomNode; 33 | instantiatePopper(); 34 | }, 35 | (popperDomNode) => { 36 | popper.current = popperDomNode; 37 | instantiatePopper(); 38 | }, 39 | ], 40 | [reference, popper, instantiatePopper], 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": false, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "incremental": true, 11 | "esModuleInterop": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "jsx": "preserve", 17 | // Add the following path mapping for the theme components 18 | "baseUrl": ".", 19 | "paths": { 20 | "@nextra/docs-theme/*": ["./theme/fetch-ai-docs/components/*"] 21 | } 22 | }, 23 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/404.mdx"], 24 | "exclude": ["node_modules"] 25 | } 26 | --------------------------------------------------------------------------------
35 | {content.description} 36 |
20 | 29 | {renderComponent(content)} 30 | 31 |
20 | 31 | {renderComponent(content)} 32 | 33 |