diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index f79bddd9..00000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Deploy to GitHub Pages - -on: - push: - branches: - - production - # Review gh actions docs if you want to further define triggers, paths, etc - # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on - -jobs: - deploy: - name: Deploy to GitHub Pages - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 18 - cache: yarn - - - name: Install dependencies - run: yarn install --frozen-lockfile - - name: Build website - run: yarn build - - # Popular action to deploy to GitHub Pages: - # Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v4 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - # Build output to publish to the `gh-pages` branch: - publish_dir: ./build - # The following lines assign commit authorship to the official - # GH-Actions bot for deploys to `gh-pages` branch: - # https://github.com/actions/checkout/issues/13#issuecomment-724415212 - # The GH actions bot is used by default if you didn't specify the two fields. - # You can swap them out with your own user credentials. - user_name: github-actions[bot] - user_email: 41898282+github-actions[bot]@users.noreply.github.com diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 7d73ce81..db61e50c 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - node-version: [18] + node-version: [22.6.0] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: diff --git a/.github/workflows/test-deploy.yml b/.github/workflows/test-deploy.yml index 3b506d6d..0557747e 100644 --- a/.github/workflows/test-deploy.yml +++ b/.github/workflows/test-deploy.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 22.6.0 cache: yarn - name: Install dependencies diff --git a/babel.config.js b/babel.config.js index e00595da..8dcf3b17 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,3 +1,15 @@ -module.exports = { - presets: [require.resolve('@docusaurus/core/lib/babel/preset')], -}; +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], + plugins: [ + [ + 'module-resolver', + { + root: ['./'], + alias: { + '@components': './src/components', + '@constants': './src/constants', + }, + }, + ], + ], +}; \ No newline at end of file diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 00000000..8928ab37 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,17 @@ +base_url: "https://pycord.crowdin.com" +project_id_env: CROWDIN_PROJECT_ID +api_token_env: CROWDIN_API_TOKEN + +preserve_hierarchy: true + +commit_message: "docs: Update translations" + +export_languages: ["de", "ja", "fr", "it", "hi", "ko", "pt-BR", "es-ES", "zh-CN", "ru"] + +files: + - source: /i18n/en/**/* + translation: /i18n/%two_letters_code%/**/%original_file_name% + - source: /docs/**/* + translation: /i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name% + - source: /src/pages/* + translation: /i18n/%two_letters_code%/docusaurus-plugin-content-pages%original_file_name% \ No newline at end of file diff --git a/docs/extensions/_category_.json b/docs/extensions/_category_.json index be8342b3..2691dc3d 100644 --- a/docs/extensions/_category_.json +++ b/docs/extensions/_category_.json @@ -1,7 +1,7 @@ -{ - "position": 5, - "label": "Extensions", - "link": { - "type": "generated-index" - } -} +{ + "position": 5, + "label": "Extensions", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/docs/extensions/bridge/_category_.json b/docs/extensions/bridge/_category_.json index 87a0687c..312090fc 100644 --- a/docs/extensions/bridge/_category_.json +++ b/docs/extensions/bridge/_category_.json @@ -1,3 +1,3 @@ -{ - "label": "Bridge" -} +{ + "label": "Bridge" +} \ No newline at end of file diff --git a/docs/extensions/bridge/index.mdx b/docs/extensions/bridge/index.mdx index 91604dd0..df406d5c 100644 --- a/docs/extensions/bridge/index.mdx +++ b/docs/extensions/bridge/index.mdx @@ -11,7 +11,7 @@ import { } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent from "../../../src/components/DiscordComponent"; +import DiscordComponent from "@site/src/components/DiscordComponent"; ## Concept diff --git a/docs/extensions/commands/_category_.json b/docs/extensions/commands/_category_.json index 0e93834f..cf96d5a4 100644 --- a/docs/extensions/commands/_category_.json +++ b/docs/extensions/commands/_category_.json @@ -1,6 +1,6 @@ -{ - "label": "Commands", - "link": { - "type": "generated-index" - } -} +{ + "label": "Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/docs/extensions/commands/groups.mdx b/docs/extensions/commands/groups.mdx index b3ac2d18..f35adee9 100644 --- a/docs/extensions/commands/groups.mdx +++ b/docs/extensions/commands/groups.mdx @@ -1,56 +1,56 @@ ---- -title: Command Groups ---- - -Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk -remove`. - -## Syntax - -Creating a command group is very simple. - -```python title="Command Groups Example" -import discord -from discord.ext import commands - -bot = commands.Bot(command_prefix='!') - -@bot.group() -async def afk(): - pass - -@afk.command() -async def set(): - ... - -@afk.command() -async def remove(): - ... - -# Another command group - -@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. -async def math(ctx): - await ctx.send('Subcommand not found') - -@math.command() -async def add(ctx, a: int, b: int): - ... - -@math.command() -async def subtract(ctx, a: int, b: int): - ... -``` - -To create a command group, the command's decorator must be `@bot.group`. Once you have a command with -that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand -groups! - - - -:::info Related Topics - -- [Prefixed Commands](./prefixed-commands.mdx) -- [Cogs](../../popular-topics/cogs) - -::: +--- +title: Command Groups +--- + +Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk +remove`. + +## Syntax + +Creating a command group is very simple. + +```python title="Command Groups Example" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!') + +@bot.group() +async def afk(): + pass + +@afk.command() +async def set(): + ... + +@afk.command() +async def remove(): + ... + +# Another command group + +@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. +async def math(ctx): + await ctx.send('Subcommand not found') + +@math.command() +async def add(ctx, a: int, b: int): + ... + +@math.command() +async def subtract(ctx, a: int, b: int): + ... +``` + +To create a command group, the command's decorator must be `@bot.group`. Once you have a command with +that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand +groups! + + + +:::info Related Topics + +- [Prefixed Commands](./prefixed-commands.mdx) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/docs/extensions/commands/help-command.mdx b/docs/extensions/commands/help-command.mdx index bea91f45..7fe15791 100644 --- a/docs/extensions/commands/help-command.mdx +++ b/docs/extensions/commands/help-command.mdx @@ -12,7 +12,7 @@ import { } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent from "../../../src/components/DiscordComponent"; +import DiscordComponent from "@site/src/components/DiscordComponent"; import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; diff --git a/docs/extensions/commands/prefixed-commands.mdx b/docs/extensions/commands/prefixed-commands.mdx index 2de69a0b..66496e7e 100644 --- a/docs/extensions/commands/prefixed-commands.mdx +++ b/docs/extensions/commands/prefixed-commands.mdx @@ -12,7 +12,7 @@ import { } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent from "../../../src/components/DiscordComponent"; +import DiscordComponent from "@site/src/components/DiscordComponent"; import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; diff --git a/docs/extensions/pages/_category_.json b/docs/extensions/pages/_category_.json index 2dc66bb2..ca1119ce 100644 --- a/docs/extensions/pages/_category_.json +++ b/docs/extensions/pages/_category_.json @@ -1,6 +1,6 @@ -{ - "label": "Pages", - "link": { - "type": "generated-index" - } -} +{ + "label": "Pages", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/docs/extensions/pages/paginator-faq.mdx b/docs/extensions/pages/paginator-faq.mdx index e13273e1..d95c8c65 100644 --- a/docs/extensions/pages/paginator-faq.mdx +++ b/docs/extensions/pages/paginator-faq.mdx @@ -1,18 +1,18 @@ ---- -title: Paginator FAQ ---- - -# Paginator FAQ - -- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** - - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. - - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. - -- **How can the bot send a paginator to a different destination than where it was invoked?** - - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. - - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. - - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. -- **How can I change the paginator's behavior without re-creating and re-sending it?** - - Use the `Paginator.update()` method. -- **How can I make the bot actually do something with the contents of a page?** - - Use the (upcoming) `Paginator.page_action()` method. +--- +title: Paginator FAQ +--- + +# Paginator FAQ + +- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** + - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. + - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. + +- **How can the bot send a paginator to a different destination than where it was invoked?** + - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. + - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. + - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. +- **How can I change the paginator's behavior without re-creating and re-sending it?** + - Use the `Paginator.update()` method. +- **How can I make the bot actually do something with the contents of a page?** + - Use the (upcoming) `Paginator.page_action()` method. \ No newline at end of file diff --git a/docs/extensions/tasks/_category_.json b/docs/extensions/tasks/_category_.json index 73e9299c..430dcab9 100644 --- a/docs/extensions/tasks/_category_.json +++ b/docs/extensions/tasks/_category_.json @@ -1,3 +1,3 @@ -{ - "label": "Tasks" -} +{ + "label": "Tasks" +} \ No newline at end of file diff --git a/docs/getting-started/_category_.json b/docs/getting-started/_category_.json index 0d1c1336..ceb18281 100644 --- a/docs/getting-started/_category_.json +++ b/docs/getting-started/_category_.json @@ -1,7 +1,7 @@ -{ - "position": 3, - "label": "Getting Started", - "link": { - "type": "generated-index" - } -} +{ + "position": 3, + "label": "Getting Started", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/docs/getting-started/creating-your-first-bot.mdx b/docs/getting-started/creating-your-first-bot.mdx index 69f09ee8..21472571 100644 --- a/docs/getting-started/creating-your-first-bot.mdx +++ b/docs/getting-started/creating-your-first-bot.mdx @@ -3,15 +3,15 @@ title: Creating Your First Bot --- import { - DiscordButton, - DiscordButtons, - DiscordInteraction, - DiscordMessage, - DiscordMessages, + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent from "../../src/components/DiscordComponent"; +import DiscordComponent from "@site/src/components/DiscordComponent"; Excited to create your first bot? Once you [install Pycord](../installation.mdx), you can start right away! @@ -259,6 +259,6 @@ To learn more, read about Message Commands in our [interactions directory](../in :::info Related Topics -- [Prefixed Commands](../../extensions/commands/prefixed-commands) +- [Prefixed Commands](../extensions/commands/prefixed-commands) ::: diff --git a/docs/getting-started/more-features.mdx b/docs/getting-started/more-features.mdx index 7516a479..33d90f82 100644 --- a/docs/getting-started/more-features.mdx +++ b/docs/getting-started/more-features.mdx @@ -4,16 +4,16 @@ description: More features to make your bot cool and snazzy. --- import { - DiscordInteraction, - DiscordMessage, - DiscordMessages, - DiscordEmbed, - DiscordEmbedField, - DiscordEmbedFields, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, + DiscordEmbedField, + DiscordEmbedFields, } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent from "../../src/components/DiscordComponent"; +import DiscordComponent from "@site/src/components/DiscordComponent"; So, you just created your first Pycord bot! Now, let's add some more features to it. This will include adding event handlers, waiting for user response, styling the messages, and more. diff --git a/docs/interactions/_category_.json b/docs/interactions/_category_.json index 82131df3..986fb7a2 100644 --- a/docs/interactions/_category_.json +++ b/docs/interactions/_category_.json @@ -1,4 +1,4 @@ -{ - "position": 4, - "label": "Interactions" -} +{ + "position": 4, + "label": "Interactions" +} \ No newline at end of file diff --git a/docs/interactions/application-commands/_category_.json b/docs/interactions/application-commands/_category_.json index 77d9fe26..d523c407 100644 --- a/docs/interactions/application-commands/_category_.json +++ b/docs/interactions/application-commands/_category_.json @@ -1,6 +1,6 @@ -{ - "label": "Application Commands", - "link": { - "type": "generated-index" - } -} +{ + "label": "Application Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/docs/interactions/application-commands/context-menus.mdx b/docs/interactions/application-commands/context-menus.mdx index cf4c8eba..503f27f4 100644 --- a/docs/interactions/application-commands/context-menus.mdx +++ b/docs/interactions/application-commands/context-menus.mdx @@ -12,7 +12,7 @@ import { } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent, { defaultOptions } from "../../../src/components/DiscordComponent"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; When you right-click a message, you may see an option called "Apps". Hover over it, and you can see commands a bot can run with that message. These are called message commands. diff --git a/docs/interactions/application-commands/slash-commands.mdx b/docs/interactions/application-commands/slash-commands.mdx index 1aff47b1..5a6049d5 100644 --- a/docs/interactions/application-commands/slash-commands.mdx +++ b/docs/interactions/application-commands/slash-commands.mdx @@ -12,7 +12,7 @@ import { } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent from "../../../src/components/DiscordComponent"; +import DiscordComponent from "@site/src/components/DiscordComponent"; import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; diff --git a/docs/interactions/index.mdx b/docs/interactions/index.mdx index 6e68aca7..a8a19b93 100644 --- a/docs/interactions/index.mdx +++ b/docs/interactions/index.mdx @@ -3,15 +3,15 @@ title: Discord Interactions --- import { - DiscordButton, - DiscordButtons, - DiscordInteraction, - DiscordMessage, - DiscordMessages, + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent, { defaultOptions } from "../../src/components/DiscordComponent"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; In December 2020, Discord released their first Interaction: the [Slash Command](https://discord.com/developers/docs/interactions/application-commands#slash-commands). diff --git a/docs/interactions/ui-components/_category_.json b/docs/interactions/ui-components/_category_.json index 6d518fac..53ba623e 100644 --- a/docs/interactions/ui-components/_category_.json +++ b/docs/interactions/ui-components/_category_.json @@ -1,6 +1,6 @@ -{ - "label": "UI Components", - "link": { - "type": "generated-index" - } -} +{ + "label": "UI Components", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/docs/interactions/ui-components/buttons.mdx b/docs/interactions/ui-components/buttons.mdx index 1c41ace8..ed84dfff 100644 --- a/docs/interactions/ui-components/buttons.mdx +++ b/docs/interactions/ui-components/buttons.mdx @@ -12,7 +12,7 @@ import { } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent from "../../../src/components/DiscordComponent"; +import DiscordComponent from "@site/src/components/DiscordComponent"; import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; diff --git a/docs/interactions/ui-components/modal-dialogs.mdx b/docs/interactions/ui-components/modal-dialogs.mdx index 3d595b1d..d13c9447 100644 --- a/docs/interactions/ui-components/modal-dialogs.mdx +++ b/docs/interactions/ui-components/modal-dialogs.mdx @@ -4,15 +4,15 @@ description: Learn how you can implement Modals in your Discord Bot with Pycord! --- import { - DiscordButton, - DiscordButtons, - DiscordInteraction, - DiscordMessage, - DiscordMessages, + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent from "../../../src/components/DiscordComponent"; +import DiscordComponent from "@site/src/components/DiscordComponent"; import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; diff --git a/docs/more/_category_.json b/docs/more/_category_.json index d26564f9..a8601729 100644 --- a/docs/more/_category_.json +++ b/docs/more/_category_.json @@ -1,7 +1,7 @@ -{ - "position": 8, - "label": "More", - "link": { - "type": "generated-index" - } -} +{ + "position": 8, + "label": "More", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/docs/more/contributing.mdx b/docs/more/contributing.mdx index 94d9c635..fde3eaaf 100644 --- a/docs/more/contributing.mdx +++ b/docs/more/contributing.mdx @@ -12,7 +12,7 @@ import { } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent from "../../src/components/DiscordComponent"; +import DiscordComponent from "@site/src/components/DiscordComponent"; This page outlines some of the basic syntax you need to know to contribute to the guide. We recommend you also check out: @@ -122,7 +122,7 @@ Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ t print("We can use code blocks like this.") ``` -You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](../../static/img/favicon.ico). +You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](@site/static/img/favicon.ico). - You can create - unordered lists like this @@ -295,7 +295,7 @@ import { } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent from "../../src/components/DiscordComponent"; +import DiscordComponent from "@site/src/components/DiscordComponent"; ``` The div starts like so: diff --git a/docs/more/git.mdx b/docs/more/git.mdx index 86c93a3f..4bd09ce7 100644 --- a/docs/more/git.mdx +++ b/docs/more/git.mdx @@ -1,47 +1,47 @@ ---- -title: Installing Git -description: Learn how you can install Git on your system. ---- - -Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). - -Let's see how to install Git on different platforms. - -## Windows - -On Windows, Git can be installed via: - -- [Git for Windows](https://gitforwindows.org) -- [Git Scm](https://git-scm.com/download/windows) - -## Linux - -On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. - -## Mac - -You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: - - xcode-select --install - -## Using Package Managers - -You can also install Git using package managers. - -### Chocolatey - -If you use the Chocolatey package manager, you can install Git using: - - choco install git - -### Scoop - -If you use Scoop, you can install Git using: - - scoop install git - -### Brew - -If you're on macOS or Linux, you can install Git using: - - brew install git +--- +title: Installing Git +description: Learn how you can install Git on your system. +--- + +Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Let's see how to install Git on different platforms. + +## Windows + +On Windows, Git can be installed via: + +- [Git for Windows](https://gitforwindows.org) +- [Git Scm](https://git-scm.com/download/windows) + +## Linux + +On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. + +## Mac + +You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: + + xcode-select --install + +## Using Package Managers + +You can also install Git using package managers. + +### Chocolatey + +If you use the Chocolatey package manager, you can install Git using: + + choco install git + +### Scoop + +If you use Scoop, you can install Git using: + + scoop install git + +### Brew + +If you're on macOS or Linux, you can install Git using: + + brew install git diff --git a/docs/popular-topics/_category_.json b/docs/popular-topics/_category_.json index a091060f..bafc4bd8 100644 --- a/docs/popular-topics/_category_.json +++ b/docs/popular-topics/_category_.json @@ -1,7 +1,7 @@ -{ - "position": 7, - "label": "Popular Topics", - "link": { - "type": "generated-index" - } -} +{ + "position": 7, + "label": "Popular Topics", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/docs/popular-topics/error-handling.mdx b/docs/popular-topics/error-handling.mdx index b760f2ba..d2dea731 100644 --- a/docs/popular-topics/error-handling.mdx +++ b/docs/popular-topics/error-handling.mdx @@ -8,7 +8,7 @@ import { DiscordInteraction, DiscordMessage, } from "discord-message-components/packages/react"; -import DiscordComponent, { defaultOptions } from "../../src/components/DiscordComponent"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; ## About diff --git a/docs/voice/_category_.json b/docs/voice/_category_.json index 89d79e7b..769c773e 100644 --- a/docs/voice/_category_.json +++ b/docs/voice/_category_.json @@ -1,4 +1,4 @@ -{ - "position": 6, - "label": "Voice" -} +{ + "position": 6, + "label": "Voice" +} \ No newline at end of file diff --git a/docs/voice/index.mdx b/docs/voice/index.mdx index a49a21c7..f56ca692 100644 --- a/docs/voice/index.mdx +++ b/docs/voice/index.mdx @@ -1,24 +1,24 @@ ---- -title: Voice ---- - -Welcome to the guide for voice features in Pycord. - -:::caution -This guide requires previous experience with Pycord and Python. -::: - -## Requirements - -The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). -The following features are optional: - -:::tip -Opus is also a required library, but this comes with Pycord. -Some hosts may not come with it, though, so remember to always check if required dependencies are installed. -::: - -- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` -- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), -[`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), -[`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. +--- +title: Voice +--- + +Welcome to the guide for voice features in Pycord. + +:::caution +This guide requires previous experience with Pycord and Python. +::: + +## Requirements + +The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). +The following features are optional: + +:::tip +Opus is also a required library, but this comes with Pycord. +Some hosts may not come with it, though, so remember to always check if required dependencies are installed. +::: + +- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` +- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), +[`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), +[`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. diff --git a/docs/voice/playing.mdx b/docs/voice/playing.mdx index 1f1f3c76..55e97bb6 100644 --- a/docs/voice/playing.mdx +++ b/docs/voice/playing.mdx @@ -14,7 +14,7 @@ import "discord-message-components/packages/react/dist/style.css"; import DiscordComponent, { defaultOptions, -} from "../../src/components/DiscordComponent"; +} from "@site/src/components/DiscordComponent"; # About diff --git a/docs/voice/receiving.mdx b/docs/voice/receiving.mdx index fdb79a1b..bb0360d0 100644 --- a/docs/voice/receiving.mdx +++ b/docs/voice/receiving.mdx @@ -12,7 +12,7 @@ import { } from "discord-message-components/packages/react"; import "discord-message-components/packages/react/dist/style.css"; -import DiscordComponent, { defaultOptions } from "../../src/components/DiscordComponent"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; # About diff --git a/docusaurus.config.js b/docusaurus.config.js index dabea174..5663b361 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -1,8 +1,10 @@ // @ts-check // Note: type annotations allow type checking and IDEs autocompletion -const lightCodeTheme = require("prism-react-renderer/themes/vsLight"); -const darkCodeTheme = require("prism-react-renderer/themes/vsDark"); +const lightCodeTheme = require("prism-react-renderer").themes.vsLight; +const darkCodeTheme = require("prism-react-renderer").themes.vsDark; + +const DefaultLocale = 'en'; /** @type {import('@docusaurus/types').Config} */ const config = { @@ -23,8 +25,14 @@ const config = { "classic", { docs: { - editUrl: - "https://github.com/Pycord-Development/guide/tree/main", + editUrl: ({locale, versionDocsDirPath, docPath}) => { + // Link to Crowdin for French docs + if (locale !== DefaultLocale) { + return `https://translations.pycord.dev/guide/${locale}`; + } + // Link to GitHub for English docs + return `https://github.com/Pycord-Development/guide/edit/main/${versionDocsDirPath}/${docPath}`; + }, routeBasePath: "/", showLastUpdateAuthor: true, showLastUpdateTime: true, @@ -35,7 +43,10 @@ const config = { }, ], ], - + i18n: { + defaultLocale: 'en', + locales: ['en', 'de', 'ja', 'fr', 'it', 'hi', 'ko', 'pt-BR', 'es-ES', 'zh-CN', 'ru'], + }, themeConfig: { docs: { sidebar: { @@ -55,26 +66,26 @@ const config = { position: "left", href: "https://pycord.dev/", }, -// { -// label: "Docs", -// position: "left", -// href: "https://docs.pycord.dev", -// }, -// { -// label: "GitHub", -// position: "left", -// href: "https://pycord.dev/github", -// }, + { + label: "Docs", + position: "left", + href: "https://docs.pycord.dev", + }, + { + label: "GitHub", + position: "left", + href: "https://pycord.dev/github", + }, // TODO: Post v2.0: Version the docs // { // type: 'docsVersionDropdown', // position: 'right', // }, // TODO: Locales - // { - // type: 'localeDropdown', - // position: 'right', - // }, + { + type: 'localeDropdown', + position: 'right', + }, { label: "Source", // We should use href instead of to, but it creates a strange styling issue diff --git a/i18n/de/code.json b/i18n/de/code.json new file mode 100644 index 00000000..9cce6148 --- /dev/null +++ b/i18n/de/code.json @@ -0,0 +1,404 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { + "message": "Toggle the collapsible sidebar category '{label}'", + "description": "The ARIA label to toggle the collapsible sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search here", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.algoliaLabel": { + "message": "Search by Algolia", + "description": "The ARIA label for Algolia mention" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorite", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "You might want to check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Algolia" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Try searching for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Believe this query should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/i18n/de/docusaurus-plugin-content-blog/options.json b/i18n/de/docusaurus-plugin-content-blog/options.json new file mode 100644 index 00000000..9239ff70 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/de/docusaurus-plugin-content-docs/current.json b/i18n/de/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..36b4849a --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,46 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.defaultSidebar.category.Getting Started": { + "message": "Getting Started", + "description": "The label for category Getting Started in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Interactions": { + "message": "Interactions", + "description": "The label for category Interactions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Application Commands": { + "message": "Application Commands", + "description": "The label for category Application Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.UI Components": { + "message": "UI Components", + "description": "The label for category UI Components in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Extensions": { + "message": "Extensions", + "description": "The label for category Extensions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Commands": { + "message": "Commands", + "description": "The label for category Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Pages": { + "message": "Pages", + "description": "The label for category Pages in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Voice": { + "message": "Voice", + "description": "The label for category Voice in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Popular Topics": { + "message": "Popular Topics", + "description": "The label for category Popular Topics in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.More": { + "message": "More", + "description": "The label for category More in sidebar defaultSidebar" + } +} diff --git a/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png b/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png new file mode 100644 index 00000000..7480e1da Binary files /dev/null and b/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png differ diff --git a/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg b/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg new file mode 100644 index 00000000..ce6b5110 Binary files /dev/null and b/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg differ diff --git a/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png b/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png new file mode 100644 index 00000000..846eee15 Binary files /dev/null and b/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png differ diff --git a/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png b/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png new file mode 100644 index 00000000..32a47d04 Binary files /dev/null and b/i18n/de/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png differ diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/extensions/_category_.json new file mode 100644 index 00000000..309b494a --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 5, + "label": "Extensions", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json new file mode 100644 index 00000000..652aa4ee --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Bridge" +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx b/i18n/de/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx new file mode 100644 index 00000000..81545fa2 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx @@ -0,0 +1,190 @@ +--- +title: Bridge +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +## Concept + +Let's say that you want to make a command that is both a Slash Command and a Prefixed Command. Now, you could just copy and paste the code from the first command callback to the other and make some adjustments, but that's not very efficient. + +This is where the `ext.bridge` module comes in. It allows you to use one callback to make both a Slash Command and a Prefixed Command. + +### Example Usage + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def hello(ctx): + await ctx.respond("Hello!") + +bot.run("TOKEN") +``` + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+
+ +## Syntax + +First, instead of using `discord.Bot` or `commands.Bot`, we use `bridge.Bot`. `bridge.Bot` does inherit from `commands.Bot`, so you can do anything with `bridge.Bot` that `commands.Bot` can do. +Then, we define a command with `@bot.bridge_command()`. This makes a Bridge Command, which has both a Prefixed Command counterpart and a Slash Command counterpart. +Next, the callback has access to a `ctx` object, which is the context of the command. This context is either of `BridgeApplicationContext` type or `BridgeExtContext`. Because of that, it makes detecting how the function was called easier. + +### Using Bridge Commands in a Cog + +Like Slash Commands and Prefixed Commands, you can use Bridge Commands in a Cog. You can do this by using the `bridge_command` decorator. Here's an example: + +```python +import discord +from discord.ext import bridge, commands + +class Greetings(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @bridge.bridge_command() + async def hello(self, ctx): + await ctx.respond("Hello!") + + @bridge.bridge_command() + async def bye(self, ctx): + await ctx.respond("Bye!") + +def setup(bot): + bot.add_cog(Greetings(bot)) +``` + +The cog will automatically split the Bridge Command into their Slash Command and Prefixed Command counterparts. + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+ + +
+ + bye + +
+ Bye! +
+ + + !bye + + + +
+ + !bye + +
+ Bye! +
+
+ +### Deferring + +You can defer if you want to communicate to the user that your bot is busy processing the command. This is done by using `ctx.defer()`. For the Slash Command implementation, `ctx.defer()` calls the function that gives out a "Bot is thinking" message. For the Prefixed Command implementation, `ctx.defer()` enables the typing indicator. + + + +### Options + +Options are pretty straightforward. You just specify them like you do with prefixed commands, and you're all set! + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def sum(ctx, a: int, b: int): + await ctx.respond(a + b) + +bot.run("TOKEN") +``` + + + +
+ + sum + +
+ 4 +
+ + + !sum 2 2 + + + +
+ + !sum 2 2 + +
+ 4 +
+
diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json new file mode 100644 index 00000000..63f8e08e --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx b/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx new file mode 100644 index 00000000..bf345c07 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx @@ -0,0 +1,56 @@ +--- +title: Command Groups +--- + +Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk +remove`. + +## Syntax + +Creating a command group is very simple. + +```python title="Command Groups Example" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!') + +@bot.group() +async def afk(): + pass + +@afk.command() +async def set(): + ... + +@afk.command() +async def remove(): + ... + +# Another command group + +@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. +async def math(ctx): + await ctx.send('Subcommand not found') + +@math.command() +async def add(ctx, a: int, b: int): + ... + +@math.command() +async def subtract(ctx, a: int, b: int): + ... +``` + +To create a command group, the command's decorator must be `@bot.group`. Once you have a command with +that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand +groups! + + + +:::info Related Topics + +- [Prefixed Commands](./prefixed-commands.mdx) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx b/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx new file mode 100644 index 00000000..acbdc0a8 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx @@ -0,0 +1,481 @@ +--- +title: Help Command +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Pycord's `commands` extension comes with a built-in help command. In this guide, we will take a look at them as well as learn how to create your own. Let's dive in! + +:::note + +This guide demonstrates using object-oriented programming and subclassing to make a help command for your +Pycord bot. It is important to understand these two concepts before continuing. + +**Learning Resources**: + +- [W3Schools - Python Subclassing](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools - Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +::: + +## The Wrong Way + +A popular way to create a help command is to disable the built-in help command and create your own. This is not recommended as it will lead to a lot of confusion. + +```python title="The Wrong Way" +bot = commands.Bot(command_prefix='!', help_command=None) +# OR +bot.help_command = None +# OR +bot.remove_command("help") + +@bot.command() +async def help(ctx, *, argument=None): + ... +``` + +While it's possible to create a help command this way, doing so does not utilize the full capabilities +of making one with Pycord. Making a help command with subclassing and OOP will save time and effort. + +## Types of Help Commands + +There are two types of built-in help commands: + +- [`DefaultHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand) +- [`MinimalHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand) + +`DefaultHelpCommand` is the command enabled by default. It isn't the best looking, but `MinimalHelpCommand` can help make it look a bit better. + + + + +```python title="Default Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.DefaultHelpCommand()) # help_command is DefaultHelpCommand by default so it isn't necessary to enable it like this +# We enable it here for the sake of understanding + +... + +bot.run("token") +``` + + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ + +```python title="Minimal Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.MinimalHelpCommand()) + +... + +bot.run("token") +``` + + + + !help + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+ +
+ +
+ +## Updating Built-in Help Commands + +Let's try to make the `MinimalHelpCommand` look better. We can do this by putting its content in an +embed. + +```python title="Minimal Help Command Example" +bot = commands.Bot(command_prefix='!') + + +class MyNewHelp(commands.MinimalHelpCommand): + async def send_pages(self): + destination = self.get_destination() + for page in self.paginator.pages: + emby = discord.Embed(description=page) + await destination.send(embed=emby) + +bot.help_command = MyNewHelp() +``` + +Let's go through the code. + +First, we create a new class called `MyNewHelp`. This class is a subclass of `MinimalHelpCommand`. + +Next, we override the `send_pages` method. This method is responsible for sending the help command to +the user. We override this method because we don't want to change the content of the pages, just how +they are sent. + +We use the `get_destination` method to get the destination of the message. This is the channel or use that the help +command is to be sent to. + +We use the `paginator.pages` property to get the different pages of the help command. We put the page +in an embed, and then send the embed to the destination channel. + +Finally, we set this as our new help command using `bot.help_command = MyNewHelp()`. + + + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a + category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+
+ +## Creating Your Help Command + +Not satisfied with the built-in help commands? You can create your own! + +For this, we will subclass the `HelpCommand` class. + +There are 4 methods that we need to override: + +- `HelpCommand.send_bot_help(mapping)` that gets called with `help` +- `HelpCommand.send_command_help(command)` that gets called with `help ` +- `HelpCommand.send_group_help(group)` that gets called with `help ` +- `HelpCommand.send_cog_help(cog)` that gets called with `help ` + +### Bot Help + +```python title="Bot Help Example" +class MyHelp(commands.HelpCommand): + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help") + for cog, commands in mapping.items(): + command_signatures = [self.get_command_signature(c) for c in commands] + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's go through the code. + +- First, we create a new class called `MyHelp`. This class is a subclass of `HelpCommand`. + +- Next, we override the `send_bot_help` method. This method is responsible for sending the main help + command to the user. + +- We create an embed with the title "Help". + +- We iterate through `mapping.items()`, which returns a list of tuples, the first element being the + cog and the second element being a list of commands. + +- By using `self.get_command_signature(c)` we get the signature of the command, also known as the + `parameters` or `arguments`. + +- There is a chance that the cog is empty, so we use `if command_signatures:`. + +- We get the name of the cog using `getattr(cog, "qualified_name", "No Category")`. This calls the + cog's attribute `qualified_name` which returns "No Category" if the cog has no name. + +- We add a field to the embed with the name of the cog and the value of the command signatures. + +- Finally, we send the embed to the channel. + +Let's improve the code a little. + +```python title="Improved Bot Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + command_signatures = [self.get_command_signature(c) for c in filtered] + + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Now the help command won't show commands that the user can't use, as well as aliases for commands. +Let's get the help command to show command aliases. + +### Command Help + +This function is called when the user uses `help `. + +```python title="Command Help Example" +class MyHelp(commands.HelpCommand): + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command), color=discord.Color.random()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's quickly go through the code we haven't discussed yet. + +- In line 3, we create an embed with a title the signature of the command (so that the title of the + embed looks like ` [parameter]`), and a random color. + +- In lines 4 and 5, we get the command's `help` description and add it to the embed. The help description + of a command can be specified in the docstrings of a command function. For example: + + ```` + ```python + @bot.command() + async def ping(ctx): + """Returns the latency of the bot.""" + await ctx.send(f"Pong! {round(bot.latency * 1000)}ms") + ``` + ```` + +- Line 6 is shorthand for + + ```python + alias = command.aliases + if alias: + ... + + # is the same as + + if alias := command.aliases: + ... + ``` + + A very helpful (but not well-known) Python shorthand! + +- In line 7, we get the aliases of the command and add them to the embed. + +### Cog Help + +This is pretty easy! + +```python title="Custom Cog Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_cog_help(self, cog): + embed = discord.Embed(title=cog.qualified_name or "No Category", description=cog.description, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(cog.get_commands()): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Once again, we create an embed, get the commands that the user can use, and add them to the embed. + +### Group Help + +Similar to the cog help, this is pretty easy! + +```python title = "Custom Group Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_group_help(self, group): + embed = discord.Embed(title=self.get_command_signature(group), description=group.help, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(group.commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Add all of these methods together, and you have a fully functioning help command! + +
+Click to see the final code for this section +
+ +:::note + +The following code has been slightly edited from the tutorial version. + +::: + +```python title="Custom Help Command Example" +class SupremeHelpCommand(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + if command_signatures := [ + self.get_command_signature(c) for c in filtered + ]: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command) , color=discord.Color.blurple()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_help_embed(self, title, description, commands): # a helper function to add commands to an embed + embed = discord.Embed(title=title, description=description or "No help found...") + + if filtered_commands := await self.filter_commands(commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No help found...") + + await self.get_destination().send(embed=embed) + + async def send_group_help(self, group): + title = self.get_command_signature(group) + await self.send_help_embed(title, group.help, group.commands) + + async def send_cog_help(self, cog): + title = cog.qualified_name or "No" + await self.send_help_embed(f'{title} Category', cog.description, cog.get_commands()) + +bot.help_command = SupremeHelpCommand() +``` + +
+
+ +## Command Attributes + +How can you add cooldowns, set aliases, and change the name of help commands? Command attributes can +help you do all of that, and more! + +```python title="Help Command Attributes" +attributes = { + 'name': "help", + 'aliases': ["helpme"], + 'cooldown': commands.CooldownMapping.from_cooldown(3, 5, commands.BucketType.user), +} + +# You need to use CooldownMapping.from_cooldown(rate, per, type) + +bot.help_command = MyHelp(command_attrs=attributes) +``` + +## Error Handling + +When a user attempts to use a command that does not exist, we need to inform the user. +We can do this by overriding the `send_error_message` function. + +```python title="Custom Help Error Example" +class MyHelp(commands.HelpCommand): + async def send_error_message(self, error): + embed = discord.Embed(title="Error", description=error, color=discord.Color.red()) + channel = self.get_destination() + + await channel.send(embed=embed) +``` + + + + !help update_pycord + + + + Command 'update_pycord' not found. + + + + +## Credits + +Most of the content from this guide is from +[InterStella0's walkthrough guide on subclassing HelpCommand](https://gist.github.com/InterStella0/b78488fb28cadf279dfd3164b9f0cf96). +Thanks to InterStella0 for making this guide amazing. + +:::info Related Topics + +- [Subclassing Bots](../../Popular-Topics/subclassing-bots) +- [Prefixed Commands](./prefixed-commands) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx b/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx new file mode 100644 index 00000000..b8f567fd --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx @@ -0,0 +1,324 @@ +--- +title: Prefixed Commands +description: Learn how to use the commands extension for Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Before Discord added slash commands, all bots had prefixed commands. A user would type the bot's prefix +followed by a word or phrase to invoke a command, such as `?help` or `!help`. +However, this prefixed commands system isn't native to Discord! Developers made use of an `on_message` +event to check if the message began with a certain character, then invoke the command. Every time a +message was sent, the bot would see the message and check for its "prefix" + +The syntax becomes a little more complicated when you want to have multiple commands. There are several +disadvantages to this system. This is where the commands extension comes in. `ext.commands` has +various advantages, such as: + +- Simpler syntax +- Easier to use +- Easier to parse user input +- Comes with built-in help commands +- Comes with a built-in system for categorizing commands + + + + +```python title="Prefixed Commands with Events" +import discord + +client = discord.Client() + +@client.event +async def on_message(message): + if message.content.startswith("!ping"): + await message.channel.send("Pong!") + + elif message.content.startswith("!announce"): + if len(message.content.split(" ")) < 3: + await message.channel.send("You need to specify a title and a message. Correct usage: `!announce Hello Hello everyone!`") + return + + msg = message.content.split(" ", 2) + title = msg[1] + content = msg[2] + + await message.channel.send("**{}**\n{}".format(title, content)) + + elif message.content.startswith("!"): + await message.channel.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !help + + + Unknown Command. + +
+ +
+ + +```python title="The Commands Extension" +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix="!", intents=intents) + +@bot.command() +async def ping(ctx): + await ctx.send("Pong!") + +@bot.command() +async def announce(ctx, title, *, message): + await ctx.send("**{}**\n{}".format(title, message)) + +@bot.event +async def on_command_error(ctx, error): + if isinstance(error, commands.CommandNotFound): + await ctx.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !pycord + + + Unknown command. + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+ !announce +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The commands extension has many more uses. This example only showcases the basic features mentioned +in the previous example. Other things you can do with the commands extension include using a different +built-in help command and creating your own. The following tutorials showcase these. + +::: + +
+
+ +## Syntax + +Before we check out the syntax, let's take a look at the bot classes. + +> `discord.Client` - Contains only events. +> +> `discord.Bot` - Subclasses `discord.Client`, adds commands. +> +> `discord.ext.commands.Bot` - Subclasses `discord.Bot`, adds prefixed commands, cogs, and more. + +This means that `discord.ext.commands.Bot` has both slash commands and prefixed commands, as well as +events, cogs and more. + +Now let's look at the syntax. + +```python title="A Simple Prefixed Bot" +import discord +from discord.ext import commands # Import the commands extension +# discord.ext.commands are not the same as discord.commands! + +intents = discord.Intents.default() #Defining intents +intents.message_content = True # Adding the message_content intent so that the bot can read user messages + +bot = commands.Bot(command_prefix="!", intents=intents) # You can change the command prefix to whatever you want. + +@bot.command() # This is the decorator we use to create a prefixed command. +async def ping(ctx): # This is the function we will use to create the command. + await ctx.send("Pong!") # This is the response the bot will send. + + +bot.run("token") # Run the bot with your token. +``` + + + + !ping + + + Pong! + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The help command is a built-in command and is enabled by default. You will learn more about it in the +following guides. + +::: + +## Parameters + +Prefixed commands can take parameters, just like slash commands. You can specify the parameters in +the function itself. + +```python title="Parameters Example 1" +@bot.command() +async def echo(ctx, *, message): + await ctx.send(message) +``` + +`ctx` is the context of the message. `*` means that the parameter can be any number of words. `message` +is the parameter. If you had not passed `*`, `message` would only have been one word. + +For example, if a user had used `!echo hello world`, `message` would have been `hello`. Since we +passed `*`, `message` is `hello world`, or the rest of the message. + +We can pass multiple parameters too! + +```python title="Parameters Example 2" +@bot.command() +async def echo(ctx, channel:discord.TextChannel, title, *, message): + await channel.send("**{}**\n{}".format(title, message)) +``` + +In the example above, `channel` is a parameter that is of type `discord.TextChannel`. When you +specify the type of the parameter, Pycord will automatically try to convert the parameter to that type. +That is why you can use `channel.send` directly without needing to convert it first. + +We also have a new parameter, `title`. This does not have a type, so it will be a string. `*` means +that the rest of the message belongs to the next parameter, in this case, `message`. + +When a user types `!echo #general Greetings! Hello World!`, `channel` will be the text channel +`#general`, `title` will be `Greetings!` and `message` will be `Hello World!`. + +Let's take an example where the user passes `!echo #general Holiday Greetings! Greetings to you all!`. +Here, the user wants the title to be "Holiday Greetings!" and the message to be "Greetings to you all!". +However, since Pycord parses the message at whitespaces, the title will end up being "Holiday" and the +message "Greetings! Greetings to you all!". The user can prevent this by typing `!echo "Holiday +Greetings!" Greetings to you all!`. + + + + + + !echo #general Holiday Greetings! Greetings to you all! + + + Holiday +
+ Greetings! Greetings to you all! +
+ + !echo #general "Holiday Greetings!" Greetings to you all! + + + Holiday Greetings! +
+ Greetings to you all! +
+
+ +Let's check out another example for parameters and parameter types. + +```python title="Parameters Example 3" +import random + +@bot.command() +async def gtn(ctx, guess:int): + number = random.randint(1, 10) + if guess == number: + await ctx.send("You guessed it!") + else: + await ctx.send("Nope! Better luck next time :)") +``` + +If you had not specified the type of the parameter, it would have been a string. And since `"5"` is not +the same as `5` in python, the bot would have responded with "Nope! Better luck next time :)". +Even if you do not specify the type of the parameter, you can still convert it later on, in this case, +with `int(guess)`. + +:::info Related Topics + +- [Command Groups](groups) +- [Rules and Common Practices](../../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json new file mode 100644 index 00000000..baeba701 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Pages", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx b/i18n/de/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx new file mode 100644 index 00000000..be90b035 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx @@ -0,0 +1,168 @@ +--- +title: Paginator Basics +--- + +# Paginator Basics + +## [Page](https://docs.pycord.dev/en/stable/ext/pages/index.html#page) + +This class contains two attributes: `content` and `embeds`, which correspond to the attributes of the same name on the +`discord.Message` class. +To create a new Page, use the following syntax: + +```py +import discord +page = Page(content="My Page Content", embeds=[discord.Embed(title="My First Embed Title")]) +``` + +## [PageGroup](https://docs.pycord.dev/en/stable/ext/pages/index.html#pagegroup) + +This class represents a group of pages. It uses most of the same parameters as `Paginator`, which allows each +`PageGroup` to effectively have its own settings and behaviours. + +## [Paginator](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator) + +This is the main class for `ext.pages`, and is used to control most of the functionality of the extension. + +In its most basic form, with no arguments provided (default values listed below), a paginator can be created like so: + +```py title="Paginator Example" +import discord +from discord.ext.pages import Paginator, Page + +my_pages = [ + Page( + content="This is my first page. It has a list of embeds and message content.", + embeds=[ + discord.Embed(title="My First Embed Title"), + discord.Embed(title="My Second Embed Title"), + ], + ), + Page( + content="This is my second page. It only has message content.", + ), + Page( + embeds=[ + discord.Embed( + title="This is my third page.", + description="It has no message content, and one embed.", + ) + ], + ), +] +paginator = Paginator(pages=my_pages) +``` + +The only required parameter for `Paginator` is the `pages` parameter, which is usually a list of `Page` objects. + +You can also pass in a list of `PageGroup` objects, a list of strings, a list of embeds, or a list of lists of embeds. + +Once the `Paginator` instance is created, you can call either +[`Paginator.send()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.send) +or [`Paginator.respond()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.respond) +to send a message or response with the paginator's contents. + +#### Depending on what's being passed to the `pages` parameter, the behaviour of the paginator may differ: + +- Passing a list of `PageGroup` objects will essentially treat each `PageGroup` as its own Paginator, with most + `Paginator` attributes able to be set independently for each `PageGroup`. + \- Each `PageGroup` accepts its own `pages` parameter, which inherits the same behaviour as the `pages` parameter + of `Paginator`, except it cannot contain other `PageGroup` objects. +- If a page is a `Page` object, this will allow you to specify both the `discord.Message.content` and + `discord.Message.embeds` attributes for a page. + \- **This is the preferred method of defining a page.** +- If a page is a string, this will be used for the `discord.Message.content` attribute. This type of page cannot have + any embeds. +- If a page is a list of embeds, this will be used for the `discord.Message.embeds` attribute. This type of page + cannot have any message content. +- If a page is a list of lists of embeds, each parent list item will create a page containing all embeds from its + child list. This type of page cannot have any message content. + +#### Parameters for the `Paginator` class which have default values: + +- `show_disabled` **:** `True` + - Show buttons that are disabled (i.e. can't be clicked) +- `author_check` **:** `True` + - Only the author can interact with the paginator. +- `timeout` **:** `180` _(seconds)_ + - The paginator will time out and become inactive after this many seconds. +- `disable_on_timeout` **:** `True` + - If the paginator times out, it will be automatically disabled and all buttons will be unusable. +- `use_default_buttons` **:** `True` + - Use the default set of 4 buttons and a page indicator. +- `show_indicator` **:** `True` + - When using the default buttons, shows a middle 5th button with the current/total page numbers. + +**For other parameters that can be set on initialization, please check the +[API Reference](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator)** + +## [PaginatorButton](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatorbutton) + +This class represents a button used to navigate between the pages of a paginator. It's also used to create the page +indicator. + +When creating your own custom buttons, you can either use this class directly or subclass it to add any additional +functionality you may need. + +To add custom buttons to the paginator instead of the default navigation buttons, you have two options to do so: + +1. **Using the `custom_buttons` parameter of `Paginator`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + buttons = [ + PaginatorButton("first", label="<<-", style=discord.ButtonStyle.green), + PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), + PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True), + PaginatorButton("next", label="->", style=discord.ButtonStyle.green), + PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), + ] + paginator = Paginator( + pages=["Page 1", "Page 2", "Page 3"], + show_indicator=True, + use_default_buttons=False, + custom_buttons=buttons, + ) + ``` +2. **Using `Paginator.add_button()`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"], use_default_buttons=False) + paginator.add_button(PaginatorButton("prev", label="<", style=discord.ButtonStyle.green)) + paginator.add_button(PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True)) + paginator.add_button(PaginatorButton("next", label=">", style=discord.ButtonStyle.green)) + ``` + +If you want to use the default navigation buttons, but not all of them, you can also use `Paginator.remove_button()` to +selectively remove them: + +```py +from discord.ext.pages import Paginator + +paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"]) +paginator.remove_button("first") +paginator.remove_button("last") +``` + +## [PaginatorMenu](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatormenu) + +This class represents the `discord.Select` menu used to navigate between `PageGroup` instances. In most situations, you +will not need to interact with this class directly. + +If you do subclass it, you'll likely want to call `super()` in your `__init__` method to ensure that the `PageGroup` +navigation functionality is retained. + +## Usage Examples + +For a comprehensive list of examples showing all `Paginator` functionality, please see the +[example in cog form](https://github.com/Pycord-Development/pycord/blob/master/examples/views/paginator.py) in the repo. + +## Support and Feedback + +If you have any questions, suggestions, or feedback for `ext.pages`, please join the +[Discord server](https://discord.gg/pycord). diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx b/i18n/de/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx new file mode 100644 index 00000000..b8d68925 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx @@ -0,0 +1,20 @@ +--- +title: Paginator FAQ +--- + +# Paginator FAQ + +- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** + - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. + - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. + +- **How can the bot send a paginator to a different destination than where it was invoked?** + - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. + - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. + - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. + +- **How can I change the paginator's behavior without re-creating and re-sending it?** + - Use the `Paginator.update()` method. + +- **How can I make the bot actually do something with the contents of a page?** + - Use the (upcoming) `Paginator.page_action()` method. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json new file mode 100644 index 00000000..36dfb009 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Tasks" +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx b/i18n/de/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx new file mode 100644 index 00000000..848f6066 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx @@ -0,0 +1,216 @@ +--- +title: Tasks +--- + +## Concept + +So you want to run a background task running at some specified interval? Thankfully, that's a common thing to do, whether you're working with some API or handling some background logic don't worry, the Pycord tasks extension is here to make life easier for you! + +With the tasks extension, you can make background tasks without worrying about the asyncio hell and mind bogglers like "what if my internet dies" and "how do I handle reconnecting" with the added benefit of a lot of useful additions that are one line of code away! + +### Example Usage + +```py +import discord +from discord.ext import tasks + +bot = discord.Bot() + +@bot.event +async def on_ready(): + very_useful_task.start() + +@tasks.loop(seconds=5) +async def very_useful_task(): + print('doing very useful stuff.') + +bot.run("TOKEN") +``` + +If you do run this code in your terminal you should see something like this after about 15 seconds: + +``` +doing very useful stuff. +doing very useful stuff. +doing very useful stuff. +``` + +For a more useful example here's a task in a cog context ripped straight from the [docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#recipes): + +```py +from discord.ext import tasks, commands + +class MyCog(commands.Cog): + def __init__(self): + self.index = 0 + self.printer.start() + + def cog_unload(self): + self.printer.cancel() + + @tasks.loop(seconds=5) + async def printer(self): + print(self.index) + self.index += 1 +``` + +As you'd expect this will increment a number and print it out every 5 seconds like so: + +```sh +0 +# 5 seconds later +1 +# 5 more seconds later +2 +# ... +``` + +## [Tasks](https://docs.pycord.dev/en/stable/ext/tasks/index.html) + +Now let's get into the nitty-gritty of tasks. + +As you've seen tasks can work in both outer scope and class contexts and the handle is roughly the same, you define a task using the `tasks.loop` decorator and use the `start` method to start it, the difference is you add the `self` argument when in a class context so since most people have all their bot's code in Cogs all the following code blocks will be in a Cog context to make it easy to copy it then apply whatever modifications you might need! + +### [Creating a task](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop) + +A look at `discord.ext.tasks.loop`'s definition in the documentation reveals that: + +1. As you've seen before it expects the time between each execution, that however doesn't have to be in seconds as + there are `seconds`, `minutes` and `hours` parameters to make it easier for us, they can also be floats in case you want + ultra-precision. +2. You can also pass in a `datetime.time` object or a sequence of them in the `time` parameter which will make it run + at the specified time(s). +3. You can pass in how many times a loop runs before it stops by passing in the `count` parameter, you can use `None` + to make it run forever which is also the default. +4. The loop function **_must_** be a coroutine. + +These are all really useful, and they aren't the only parameters so if you want to know more about them check out the +[docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop)! + +### Attributes + +A task has the following attributes: + +- `current_loop`: The current loop the task is on. +- `hours`, `minutes`, `seconds`: attributes that represent the time between each execution. +- `time`: A list of datetime.time objects that represent the times the task will run, returns `None` if no datetime + objects were passed. +- `next_iteration`: A `datetime.datetime` object that represents the next time the next iteration of the task will + run, can return `None` if the task stopped running. + +These attributes serve as a really powerful asset to get info about your loop. + +### Example + +Now let's create a cog that handles a leaderboard we have in our bot using Tasks then explain what we did after that and +also provide a refresher of how slash commands groups work in cogs. + +For the sake of this example let's pretend that we have a leaderboard module that does all the leaderboard handling for +us and that computing the leaderboard is very expensive computationally wise, so we want to store one version of it that +gets regularly updated instead of generating it every time someone calls the `/leaderboard view` command. + +```py +from discord.ext import tasks, commands +from discord.commands import SlashCommandGroup, CommandPermissions + +from leaderboard import * # Mock leaderboard module. + +class LeaderboardCog(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.update_leaderboard.start() + self.leaderboard_embed = generate_leaderboard_embed() + + leaderboard = SlashCommandGroup(name='leaderboard', description='Leaderboard commands.') + + @tasks.loop(minutes=10) + async def update_leaderboard(self): + print('Updating leaderboard...') + await update_leaderboard() + self.leaderboard_embed = generate_leaderboard_embed() + + @update_leaderboard.before_loop + async def before_update_leaderboard(self): + await self.bot.wait_until_ready() + print("About to start updating leaderboard.") + + @update_leaderboard.after_loop + async def after_update_leaderboard(self): + leaderboard_cleanup() + print("Stopped updating leaderboard.") + + @update_leaderboard.error + async def update_leaderboard_error(self, error): + print(f"Oh no, an error occurred while updating the leaderboard. Error: {error}") + + @leaderboard.command() + async def view(self, ctx): + await ctx.respond(embed=self.leaderboard_embed) + + @leaderboard.command() + async def update_info(self, ctx): + await ctx.respond(f"""***Leaderboard Info***\n + Last update: {(600 - self.update_leaderboard.next_iteration.timestamp())//60} minutes ago.\n + Next update: in {self.update_leaderboard.next_iteration.timestamp() // 60} minutes.\n + Time between loops: {self.update_leaderboard.minutes} minutes.\n + Times updated this session: {self.update_leaderboard.current_loop}. + Running? {self.update_leaderboard.is_running()} + Failed? {self.update_leaderboard.failed()}""", ephemeral=True) + + # Now for the owner only commands: + + leaderboard_config = SlashCommandGroup(name="leaderboard_config", description="Leaderboard configuration commands", permission=[CommandPermissions("owner", 2, True)]) + + @leaderboard_config.command() + async def set_time_between_updates(self, ctx, minutes: int): + self.update_leaderboard.change_interval(minutes=minutes) + await ctx.respond(f"Set time between updates to {minutes} minutes.") + + @leaderboard_config.command() + async def stop(self, ctx): + self.update_leaderboard.stop() + await ctx.respond("Stopped the leaderboard update.") + + @leaderboard_config.command() + async def restart(self, ctx): + self.update_leaderboard.restart() + await ctx.respond("Restarted the leaderboard update.") + +def setup(bot): + bot.add_cog(LeaderboardCog(bot)) +``` + +Phew, that was quite a bit of code. + +Now to explain what's going on: + +First things first we create a cog and in its `__init__` function we start the `update_leaderboard` task and generate +the first instance of our leaderboard's embed. + +After that, we define the `update_leaderboard` task using the `loop` decorator, and we make it run every ten minutes by +passing 10 to the `minutes` parameter. + +Then that we define the `before_update_leaderboard` task using the `before_loop` decorator, and we make it wait until the +bot is ready before starting the task. + +Next up we define the `after_update_leaderboard` task using the `after_loop` decorator, and we make it clean up the +leaderboard when the loop finally stops running. + +Then we define the `update_leaderboard_error` task using the `error` decorator, and we make it print any errors that may +occur while we update our leaderboard to the console. + +Then we get into the fun stuff, we create a slash command group using the `SlashCommandGroup` class and name it +`leaderboard`, we then create the `view` sub-command which sends the embed generated when the leaderboard is updated and +`update_info` which shows a lot of data about the task using some attributes and functions available to us. + +We also create a slash command group called `leaderboard_config` which is only available to the owner of the bot. + +Then we create the `set_time_between_updates` sub-command which takes in the time in minutes and changes the time +between updates of the leaderboard using the `change_interval` method, the `stop` sub-command which stops the task using +the `stop` method and `restart` which restarts the task using the `restart` method. + +Finally, we add the `LeaderboardCog` cog to the bot, and we're done! + +I'd highly recommend you check the tasks extension +[documentation](https://docs.pycord.dev/en/stable/ext/tasks/index.html) for more info on how to use them and what other +functions they have. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/getting-started/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/getting-started/_category_.json new file mode 100644 index 00000000..9d6255f5 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 3, + "label": "Getting Started", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx b/i18n/de/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx new file mode 100644 index 00000000..864206a6 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx @@ -0,0 +1,262 @@ +--- +title: Creating Your First Bot +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +Excited to create your first bot? Once you [install Pycord](../installation.mdx), you can start right +away! + +## Creating the Bot Application + +Just like how you need to sign up to use Discord, your bot also has to be signed up. To do this, +you should: + +1. Go to the [Discord Developer Portal](https://discord.com/developers/applications) and click + on . +2. Give your bot a name, and click . +3. Now, you should see a page like this. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdW3OQnwUhacopqSWw%2F-Mjd_-mxrJCrzmaXrAg8%2Fimage.png?alt=media&token=b8e2ae6c-2290-4d37-ad7c-eb412f3fb00e) +4. Click on the tab on the left side of the screen. +5. Click on . +6. You can give it a name, change the Avatar, etc. + +## Inviting the bot + +Now, lets get the bot added to some servers. Go to the tab +in the left pane and select `bot` and `applications.commands` as scopes. + +You may want your bot to have application commands, which is what the `application.commands` scope +allows your bot to make. + +Next, you want to choose what permissions the bot will have and select them. For now, you can just +give your bot the `administrator` permission, which gives your bot every permission. Once you select +your bot's permissions, click on to get the bot invite link. + +:::tip + +When your bot is all ready to go, make sure that administrator permissions aren't selected unless +your bot truly needs them. Try selecting only permissions the bot will need. For testing, +Administrator permissions are fine. + +::: + +![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-Mk6tNY3LfDkjd6pqdpL%2F-Mk6tkdpddEWoa2jczZk%2Fimage.png?alt=media&token=52c8a29f-a798-48f8-a8c7-4ecca2681f79) + +You can use this link to invite the bot. + +## Tokens + +Now that you have an account for your bot, you need to log in. To log in, we need the bot's +password. All users and bots have a "token." You may think of this token as a password, as this allows +us to log our bot into Discord. + +Tokens are "snowflakes." Not actual snowflakes, though. Just like how no two snowflakes in real life have the same +pattern, snowflakes in computers are unique things - no two bots have the same token - so a token is +considered a snowflake. A Discord user ID is also a snowflake. + +Now, lets get your bot's token. To do this, you want to: + +1. Go back to the tab. +2. Click on the button in the "Token" section. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdbU12JISJorAZxrKH%2F-MjdbpUsapzb5n15Po5P%2Fimage.png?alt=media&token=118e259f-940a-4f6c-b3a3-c29f3a54100d) + +Now, you have your bot's token copied to your clipboard. + +:::danger + +Do not, under any circumstances, give your token to anyone. Even if you are contacted by someone +claiming to be Discord staff, do not give them your bot's token. They are lying to you to try and +gain access to your bot. If an unauthorized user gains access to your bot's token, they can access +your bot and use it in malicious ways. + +Never push your token to GitHub or include it in your code. One way to prevent your token from +getting leaked is to store it in `.env` files. + +::: + +### Protecting Tokens + +#### Using dotenv + +You can store your tokens in `.env` files. This is a simple way to store sensitive information. + +1. Create a file with the name `.env` (only the extension, with a dot/period at the start and without a name before it). +2. Define the token in the `.env` file (replace the example value with your token). + ```env title=".env" + TOKEN = NzkyNzE1NDU0MTk2MDg4ODQy.X-hvzA.Ovy4MCQywSkoMRRclStW4xAYK7I + ``` +3. Install [`python-dotenv`](https://pypi.org/project/python-dotenv/). + ```bash + python -m pip install python-dotenv + ``` +4. Load the token from the `.env` file. + ```python + import dotenv + dotenv.load_dotenv() + token = str(os.getenv("TOKEN")) + ``` +5. Pass your token as parameter when running the bot. + ```python + client.run(token) + ``` + +:::tip + +If you are using Git to track your bot's changes, you should create a file called `.gitignore` and add +`.env` to it. This stops your `.env` file from getting tracked along with the rest of your code, and +will not be pushed to a remote Git repository. As a consequence, it will stay secure on your local machine. + +::: + +## Coding the Basics + +Here's an example of code you'll write with Pycord: + +```py +import discord +import os # default module +from dotenv import load_dotenv + +load_dotenv() # load all the variables from the env file +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") + +bot.run(os.getenv('TOKEN')) # run the bot with the token +``` + + + +
+ + hello + +
+ Hey! +
+
+
+ +Let's go through the code. First, the imports. + +```py +import discord +import os +from dotenv import load_dotenv +``` + +In the first line, `import discord`, we import Pycord. Although you install Pycord with `pip install py-cord`, you +import it with `import discord`. This is so it's as easy as possible when switching from Discord.py to Pycord. + +We then import `os` and `dotenv`. `os` is a default module that we will use to get the token from the env file. `dotenv` +is a module that we will use to load the env file. You installed this with `pip install python-dotenv`. + +Next, we load the env file with `load_dotenv()`. + +```py +bot = discord.Bot() +``` + +In this line, we create a new instance of [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). +In this object, we can pass various parameters for configuration purposes, such as `owner_ids` +and [`intents`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```py +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") +``` + +We use the [`event`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) decorator to override +the [`on_ready`](https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready) function to define an +event that is automatically called when the bot is ready to use. + +```py +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") +``` + +Here, we use the [`slash_command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.slash_command) +decorator to define a slash command. We specify the `name` and `description` arguments. If not +specified, the name of the slash command would be the function name and the command description would +be empty. + +Optional: We type-hint the context parameter (`ctx`) as [`discord.ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext). In modern IDEs, type-hinting allows access to autocompletion and docstrings. You can read more about type-hinting [here](https://docs.python.org/3/library/typing.html). + +Finally, you want to run the bot using the token specified in the `.env` file. + +Now you have finished creating your first Pycord bot! What we have shown you is just the basic structure +of a bot. You can do a lot more with Python and Pycord knowledge, as well as your imagination! Pycord +will not limit your bot's abilities. + +:::note + +The part where we load the token from the environmental variables is not required. You may use another way to keep your token secure, or, although not recommended, simply specify the token normally as a string, as shown below. + +
+A Basic Bot without securing the token +
+ +```py +import discord + +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.send("Hey!") + +bot.run("TOKEN") +``` + +
+
+ +::: + +## FAQ + +### How do I make prefixed commands? + +Prefixed commands are an older method of creating bot commands that listen for messages and replies +if the message starts with a certain character. You can read [this page](../extensions/commands/prefixed-commands.mdx) +to learn more about prefixed commands. + +### How do I setup modules/cogs? + +[Cogs](../popular-topics/cogs) are a great way to organize your commands by putting them into +groups called cogs. Cogs are separate files that your bot loads to get the commands inside. +You can read more about cogs, as well as learn how to use them and their benefits, +[here](../popular-topics/cogs). + +### How do I add components, such as buttons and dropdown menus, to my bot? + +Pycord makes it very easy to use Message Commands with your bot by using the `discord.ui` module. +To learn more, read about Message Commands in our [interactions directory](../interactions). + +:::info Related Topics + +- [Prefixed Commands](../extensions/commands/prefixed-commands) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx b/i18n/de/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx new file mode 100644 index 00000000..2a68677b --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx @@ -0,0 +1,109 @@ +--- +title: Hosting Your Pycord Bot +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Hosting Your Pycord Bot + +If you're completely new to this, you might have thought something along the lines of "Yay! I got my +bot working," after following our [Creating your First Bot](creating-your-first-bot) guide, only +to close your IDE or shut down your computer to find your bot offline. + +The reason for this is that programs have to be hosted somewhere, meaning some machine somewhere has +to constantly run your bot. There are tons of hosting services that can help you host your bot for +little to no cost. + +## Can I get a Clear Explanation? + +Sure thing. When you run your bot, it first makes a connection to Discord's API. Once that's done, +Pycord sends "heartbeats" to Discord. "heartbeats" are small packets sent at a set interval telling +Discord that your bot is indeed still alive. If Discord doesn't receive a heartbeat after a certain +amount of time, your bot is pronounced dead and buried in the graveyard (not really). It is, though, +taken offline and its connection with Discord is terminated. + +Once you close the terminal that you've run your program on, the program is no longer running, and +the bot stops sending heartbeats and can no longer process commands. This is why you have to constantly +keep the process running. + +This goes for all programs, in a different nature. If the code isn't compiled/built/assembled/interpreted, +it can't be running. + +## What is a Host? + +A host is a server or container for running code offered by a **hosting provider.** There are a lot +of hosting providers, such as bigger ones like Amazon Web Services (AWS) and Google Cloud, and smaller +ones like GalaxyGate and DigitalOcean. + +There are three types of hosts. + + + + Shared hosting is a type of hosting where multiple people share one VPS. Getting a spot on + a shared host is usually cheap, sometimes even free. Shared hosts do not give you a lot of + resources, from less than a gigabyte of RAM (usually 512MB on free hosts) and half of a CPU + with very little storage. Shared hosting is usually used for website hosting and is not + recommended for hosting a Discord bot. + + + A virtual private server (VPS) is a virtual computer (virtual machine) that is rented out to + customers. Most people use a VPS for hosting their projects such as Discord bots. You can get + anywhere from less than a gigabyte of RAM and a less powerful CPU to just under one hundred + gigabytes of RAM, a (or multiple) powerful CPU(s), and a fair amount of storage. A VPS is the + best choice for most users and can be fairly cheap. + + + A dedicated host is a physical computer. You can buy these yourself or rent one from a hosting + provider. Dedicated hosts are often very expensive, but are also very powerful, having a + few hundred gigabytes of RAM and a few very powerful CPUs, along with a good amount of storage. + Dedicated hosts are usually used for very large projects and are overkill for something like + a Discord bot. + + +
+ +:::danger + +Make sure you choose a hosting provider you trust. Also make +sure the hosting provider you're looking at has good reviews on public forums. Googling along the +lines of "[host] review" should do the trick. A provider you don't trust can compromise your token. + +::: + +Most hosting providers rent their services to you for a monthly or yearly fee. These can be anywhere +from a few dollars to hundreds or thousands of dollars. + +## How to Host Your Bot + +Once you rent or buy a VPS, you can get to work. Most hosting providers allow you to choose from a +wide range of operating systems, most allow you to choose one but some allow you to choose +multiple. Once that's ready, you have to SSH into the system. We won't get into SSH here, but you can +read [this article from DigitalOcean](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys). +You can also use VNC, which is remote desktop software. If you are using an OS that does not have a +GUI, and is only a command line (a "server" OS), such as Ubuntu Server or most Linux Server Operating Servers, you will most +likely use SSH. If you are using an OS that has a GUI, such as Windows Server, you will most likely use VNC. + +Once you've decided on your operating system, you'll want to set it up and install Python. Once that's +done, you can copy your bot's files to your remote system, install the required packages, and run +the bot. + +:::warning + +If you are using SSH to run the file, your bot will not stay running. This is because the file is +only told to run during your session. You can use a command like [nohup](https://en.wikipedia.org/wiki/Nohup) +to make sure your file stays running after you disconnect. + +::: + +Now your bot is hosted, but that doesn't mean it can't go offline. If your bot encounters an error, +it can often go offline or stop its process. For this, make sure you have proper error handling. +Also be sure to pay attention to your hosting provider's updates or news, as they usually notify +users of when they plan on doing maintenance to their servers, making their services unavailable for +a short time. + +:::info Related Topics + +- [Creating Your First Bot](creating-your-first-bot) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx b/i18n/de/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx new file mode 100644 index 00000000..ee6b9417 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx @@ -0,0 +1,379 @@ +--- +title: More Features +description: More features to make your bot cool and snazzy. +--- + +import { + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, + DiscordEmbedField, + DiscordEmbedFields, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +So, you just created your first Pycord bot! Now, let's add some more features to it. This will include adding event handlers, waiting for user response, styling the messages, and more. + +## Events + +### Event Handlers + +Events in Discord are a way to listen for certain actions. For example, if you want to know when a user joins your server, so you could send a welcome message, you can use the `on_member_join` event. + +First, you need to ask Discord to send you events. This is done via "Intents". Read up the [Intents](../Popular-Topics/intents) page for more information. + +Once you understand what intents are, you can enable the events you need, or just use the default ones with `discord.Intents.all()`. + +Now that that's done, let's add an event handler for when a user joins the server. We will use the [`on_member_join` event](https://docs.pycord.dev/en/stable/api/events.html#discord.on_member_join). We will send a private message to the user welcoming them to the server. + +```python +@bot.event +async def on_member_join(member): + await member.send( + f'Welcome to the server, {member.mention}! Enjoy your stay here.' + ) +``` + +We use the [`discord.Bot.event` decorator](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) to add the event handler. + +The `on_member_join` event is called when a user joins the server. The `member` parameter is the user that joined. Different events have different names and parameters. You can find all of them [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +So, that's how you add event handlers! + +### Waiting for User Response + +Let's say you want to create a Guess-the-Number game (where the user has to guess a number between 1-10). You need to send a message to a user and wait for them to respond. You can do this with the [`wait_for`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.wait_for) method. + +```python +@bot.command() +async def gtn(ctx): + """A Slash Command to play a Guess-the-Number game.""" + + await ctx.respond('Guess a number between 1 and 10.') + guess = await bot.wait_for('message', check=lambda message: message.author == ctx.author) + + if int(guess.content) == 5: + await ctx.send('You guessed it!') + else: + await ctx.send('Nope, try again.') +``` + +`wait_for` takes one argument, which is the event type. The event type is the name of the event you want to wait for. In this case, it's `message`. It could also be `reaction` to wait for a reaction to be added. + +We pass a keyword argument to `wait_for` called `check`. The function may look complicated if you're a beginner. We pass a `lambda` function, which simplifies the code a bit. + +The lambda function takes one parameter, `message`. When Pycord receives a message, it passes it to the `check` function. If the function returns `True`, the message is returned. If the function returns `False`, the message is ignored and the bot waits for another message. + +Here, we check if the message is from the user that sent the command. We simply use `message.author == ctx.author`. This will check if the author of the message was the person who invoked the command. + +## Styling Messages + +### Embeds + +Embeds are a Discord feature that allows applications to format their messages in cool embedded format, +enabling your bot to lay out messages with a lot of text into neat fields. + + + + + The Pycord Guide is a detailed guide that explains how to use Pycord and all of its features. + + + The Getting Started section explains how you can get a brand new bot created and running from scratch. + + + Interactions with Pycord + + + Pycord's various Extensions + + + Other Popular Topics + + + We have so much more! Just explore, and you will find everything you need. If you want another page added, open an issue on the GitHub. + + + Created with 💖 by the Pycord Team & Contributors + + + + +
+ +Creating embeds is simple! Just create an instance of [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) and edit it to your liking. Once you're done, send it! + +```python +import discord + +bot = discord.Bot() + +@bot.command() +async def hello(ctx): + embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from + ) + embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") + + embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) + embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) + embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) + + embed.set_footer(text="Footer! No markdown here.") # footers can have icons too + embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") + embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") + embed.set_image(url="https://example.com/link-to-my-banner.png") + + await ctx.respond("Hello! Here's a cool embed.", embed=embed) # Send the embed with some text + +bot.run("TOKEN") +``` + + + +
+ hello +
+ Hello! Here's a cool embed. + + Embeds are super easy, barely an inconvenience. + + + A really nice field with some information. The description as well as the fields support markdown! + + Inline Field 1 + Inline Field 2 + Inline Field 3 + + Footer! No markdown here. + +
+
+ +
+ +This simple command sends replies to a [slash command](../interactions/application-commands/slash-commands) with an embed. +Let's break it down: + +```py +embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), + ) +``` + +This command creates an embed. We use the [`Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) +class to create an embed object with the title "My Amazing Embed", the description "Embeds are super easy, barely an inconvenience.", and the color `blurple`, Discord's main theme color. + +[discord.Colour](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Colour) is a class full of [classmethods](https://docs.python.org/3/library/functions.html#classmethod) +that return color values. While the official, documented name of this is `discord.Colour`, `discord.Color` +works as well. + +```py +embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") +embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) +embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) +embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) +``` + +This small section shows off embed fields. You can add fields to embeds with the [`add_field` method](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.add_field) +of the [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) class. These consist of three +keyword arguments: `title`, `value`, and `inline`. `title` and `value` are both required arguments, which inline defaults to `False` if it's not defined. The `inline` argument specifies whether space will be divided among the inline fields. There could be a mix of fields where inline has different values too. + +```py +embed.set_footer(text="Footer! No markdown here.") # footers can have icons too +embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") +embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") +embed.set_image(url="https://example.com/link-to-my-banner.png") +``` + +In this section, we're adding unique items to the embed. These items are: + +- Footer - With the [`set_footer()`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_footer) + method, you can set a small footer that holds a message. This has `text` and `icon_url` kwargs. +- Author - With the [`set_author`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_author) + method, you can set an author for the embed. This is a small text field at the top of the embed. This + includes `name`, `url` and `icon_url` kwargs. +- Thumbnail - With the [`set_thumbnail`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_thumbnail) + method, you can set a small image to reside at the top-right of the embed. This has a single `url` kwarg. +- Image - With the [`set_image`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_image) + method, you can set an image to sit at the bottom of an embed. This has a single `url` kwarg. + +There are a lot more methods and attributes you can use to configure embeds. Here, we just covered the basics. Also, remember that all of these values are not necessary in an embed. An embed may only contain a few of these. For example, only a description, a title and a description, and so on. + +### Markdown + +Markdown is a type of markup language that's limited in terms of formatting yet simple. Discord allows +for a watered-down version of markdown to be in their messages. + +#### Text Markdown + +Text formatting can be used in messages and in most embed parts, +as explained in the dedicated section below. + + + + + + + + + + + + + + + + + + + + +
*italics*__*underlined italics*__
**bold**__**underlined bold**__
***bold italics***__***underlined bold italics***__
__underlined__~~strikethrough~~
+ +#### Code Markdown + +To create a single-line code block without syntax highlight, wrap the text between single backticks. +This code block will only add a dark background to the text. + +``` +`print("Hello world!")` +``` + +To create a multi-line code block without syntax highlight, wrap the text between triple backticks +on first and last line. This type of code block will encase the code inside a box. + +```` +``` +message = "Hello world!" +print(message) +``` +```` + +To create a multi-line block with syntax highlight, add the name of the language you are using right after +the triple backticks on the first line. For example, for Python you can write either "python" or "py". + +```` +```python +message = "Hello world!" +print(message) +``` +```` + +If you want to use syntax highlight for a single line of code, you still have to format it +like a multi-line block but the code must be on a separate line than the triple backticks. + +#### Quote Markdown + +To create a single-line quote block, start the line with `>` followed by a space. + +``` +> This is a single-line quote. +``` + +To create a multi-line quote block, write `>>>` followed by a space. All text +from that point onwards will be included in that quote block. + +``` +>>> This is a +multi-line quote. +``` + +#### Spoiler Markdown + +To hide a spoiler, encase the text between double pipes. The users +will have to click on it before being able to see the text contained in it. + +``` +||spoiler|| +``` + +#### Link Markdown + +Link formatting only works in embeds and messages sent through webhooks, +by using the following syntax: + +``` +[Pycord](https://pycord.dev/) +``` + +Inside the supported elements that have just been mentioned, +the example above will look like this: [`Pycord`](https://pycord.dev/) + +Outside them, the link will still be clickable but the formatting will be ignored, +therefore the example above will look similarly to this: `[Pycord](https://pycord.dev/)` + +#### Embed Markdown + +Adding markdown to your embeds or messages will give your bot the sparkle it needs, +however, markdown is limited inside embeds. Use the following table as a reference +and keep in mind that embed title and filed names will always show in **bold**. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PartTextLink
Embed AuthorNoNo
Embed TitleYesNo
Embed DescriptionYesYes
Field NameYesNo
Field ValueYesYes
Embed FooterNoNo
diff --git a/i18n/de/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx b/i18n/de/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx new file mode 100644 index 00000000..e44b7c49 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx @@ -0,0 +1,184 @@ +--- +title: Rules and Common Practices +description: All about the rules and common practices for coding a Discord bot +--- + +# Rules and Common Practices of Creating a Bot + +When creating almost anything, there's always a certain set of rules to follow or common practices, +such as [PEP8](https://www.python.org/dev/peps/pep-0008/) for Python. This applies to creating bots +with Pycord as well. + +:::note + +Most of these rules and common practices are only applicable for +[verified bots](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting), +but it's good to follow them nonetheless. + +::: + +## Rules + +There are rules for creating bots, and most of these are required by Discord themselves, not us at +Pycord. Not following these rules may get your bot denied for verification. + +### Terms of Service and Privacy Policy + +Starting at some point in time, Discord has made providing a privacy policy with your bot a requirement. +This is so that Discord knows exactly what you are doing with its users' data. + +:::tip +You don't need a lawyer or anyone special to write out a privacy policy for you, nor do you need +it approved by some official entity. Simply writing out how you are going to use Discord user +information neatly is all you need to do. +::: + +Providing a Terms of Service for your bot is optional, though usually a best practice. It tells users +what they can and cannot do with your service, and makes it easier to settle disputes if someone +disagrees with you. + +Read more in Discord's official [Legal Docs](https://discord.com/developers/docs/legal). + +### Developer Policy + +We could list almost every rule about using Discord's API here. _Or_ we could simply link Discord's +Developer Policy to make it easier on us. You can find Discord's Developer Policy +[here](https://discord.com/developers/docs/policy). This outlines what you can and cannot do with +Discord's Developer API. And, don't worry, it's completely readable and understandable. + +## Best Practices + +Now, here's something we _can't_ simply link an article for. We're going to discuss the best practices +of creating a Discord bot with Pycord. + +### Bot Sharding + +To any new or maybe even experienced bot developer, sharding a bot sounds beneficial once you hear +about it. I'm here to tell you that it isn't a good idea to shard your bot. + +_Wait a minute, why would it be an option if it wasn't a good idea?_ It's simple. I lied. Sort of. +I'm not going to go into the details of sharding a bot, so you can read about it on +[this page](../Popular-Topics/sharding). Sharding is the process of taking your bot +and breaking it up into small pieces, so it's easier to perform tasks. This is very useful for large +bots, as it makes them faster and more reliable. Sharding is not a good practice for small bots. + +:::note +Discord will notify you once it is time to shard your bot, and will eventually force you to do so. +::: + +At the very least, wait for one thousand servers to shard your bot. If you shard your bot while it's +small, you'll just be wasting resources and possibly making your bot slower. + +### [Verification](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting) + +Verifying your Discord bot is something every developer would like to achieve. It shows that your bot +is in more than 75 servers. It's generally a good idea to try to get your bot verified as soon as +possible. We're talking at 76 servers soon. This is because Discord can be somewhat slow in terms of +bot verification, so verifying as soon as possible gives them enough time to verify before your bot +reaches the 100 server cap. If a bot is not verified, it cannot grow beyond 100 servers. + +It's also a good idea to only apply for the privileged intents that you need. Applying for intents +your bot doesn't use wastes both your time and Discord's time, as your privileged intent request +will be denied simply because you applied for an intent you didn't need. + +### Subclassing + +While it may take some time, subclassing a bot is very worth it. Once again, this was explained +elsewhere, so I won't go into the details, but I felt it fit here, so I put it here. + +Subclassing a bot makes it more flexible and allows it to do a lot more. Read more about subclassing +bots [here](../Popular-Topics/subclassing-bots) + +### Your Bot's Token + +Your bot is only able to be run for one reason: its token. If you followed the +[guide for creating your first bot](creating-your-first-bot), you should already know a bit about +keeping that token safe. That's exactly what you want to do. + +Sharing your token is never good. If someone evil gets a hold of your token, they can do terrible things, +such as making your bot leave all of its servers, spamming all the members the bot has contact with, +and even manipulating the servers the bot is in, if given the permissions. That's why it's very important +to keep your token safe. To learn how to do so, read [this part](creating-your-first-bot#tokens) of +the Creating Your First Bot guide. + +### Backups + +You always want to back up your bot's data. This includes both its code _and_ its databases. This way, +if something tragic happens, such as your host failing a data migration or you breaking your Raspberry +Pi's SD card that held your bot, you'll still have its precious user data. I have a small program for +my bot that uploads its databases to a remote GitHub repository periodically to not lose any data. +It may be smarter to find a bit more of a reliable way to do so, though. + +Public or private, having a local Git repository connected to a remote one is a good idea for making +almost any application. For a lot of developers, it's like saving your work. If you do this, all of +your bot's code won't be lost if your computer spontaneously combusts, or you smash it to bits from +anger. You can simply grab the backup computer that everyone has lying around, and you're back +in business. + +### Organization and Cleanliness + +It is _extremely_ important to have organized code. This includes commands, objects, functions, +and classes. If you don't have organized code, it will get progressively harder for you to recognize +it, and others won't be able to decipher it. + +Make sure you utilize indents and spaces, as these are very important in making your code readable. + +```py title="Bad Spacing" +class MyClass: + async def add(self,num1,num2): + return num1+num2 + async def sub(self,num1,num2): + return num1-num2 +``` + +```py title="Good Spacing" +class MyClass: + async def add(self, num1, num2): + return num1 + num2 + + async def sub(self, num1, num2): + return num1 - num2 +``` + +See the difference? Now, which one looks more readable? Hopefully, you answered the second example. +Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is a PEP (**Python Enhancement Proposal**) +style guide for Python. It is the style guide that is used by most Python developers and programmers, +providing a universal way to write and read code. + +### Databases + +As your bot grows, you'll inevitably have to store data for your bot. Now, most people would probably just load up some +JSON file on boot into a `dict`, modify it in memory then write to the file. However, JSON files aren't the solution. +When you write to a JSON file, it rewrites the entire file instead of just rewriting the section that changed. It's also +a configuration file format, not a storage file format. + +Instead of using a JSON file or some other related format, you should instead use a database. There are many databases +out there, like MongoDB, SQLite, and PostgreSQL to name a few. + +All of these databases I named do the job well, and which one you use depends on what features you want out of a database. + +<>{/* Maybe clarify these/add more options */} + +#### MongoDB + +MongoDB is a JSON-like format and if you already use JSON files, it shouldn't be too hard to migrate over to. + +#### SQLite + +SQLite is based on SQL, a common relational data model. It's a lightweight, easy-to-use, portable database solution that +works entirely on files. However, if for some reason you cannot read/write to and from a file, and you need to manage +lots of data, SQLite might not be for you. + +While SQLite is a part of the Python Standard Library as the `sqlite3` package, we recommend not using it as it is +synchronous and blocking. You should use an asynchronous alternative, such as [`aiosqlite`](https://pypi.org/project/aiosqlite/). + +#### PostgreSQL + +PostgreSQL is also based on SQL, but it also has more features than SQLite. It's compliant with the SQL standard, +open-source, and extensible. However, it's not that fast or simple compared to SQLite. + +#### MariaDB + +MariaDB is also based on SQL and is a fork of the MySQL project. It's compliant with the SQL standard, it's also open +source and is a complete drop-in replacement for any code with MySQL. You don't even need to change what package you're +using! diff --git a/i18n/de/docusaurus-plugin-content-docs/current/installation.mdx b/i18n/de/docusaurus-plugin-content-docs/current/installation.mdx new file mode 100644 index 00000000..521c69cd --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/installation.mdx @@ -0,0 +1,80 @@ +--- +title: Installation +sidebar_position: 2 +--- + +Before you can start using Pycord, you need to install the library. + +:::note +Python **3.8 or above** is required to use Pycord. +::: + +:::tip +Before you start installing python packages globally, it's recommended you set up a virtual environment. +You can find instructions for that [here](More/virtual-environments). +::: + +## Fresh Installation + +To install Pycord, you can use the following command in your terminal: + +``` +pip install py-cord +``` + +:::tip +Remember that you need to install `py-cord`, not `pycord`. +Also, the `pip` command varies depending on your installation. For example, it might be `python3 -m pip` on macOS/Linux or `py3 -m pip` on some versions of Windows. +::: + +If you need voice support for your bot, you should run: + +``` +pip install "py-cord[voice]" +``` + +## Migration + +### Updating Pycord + +If you are upgrading from a previous version of Pycord, you can use the following command in your terminal to upgrade to the latest version: + +``` +pip install -U py-cord +``` + +### Migrating from other libraries + +If you are migrating from another library, say, `discord.py`, first of all, you need to uninstall it. + +``` +pip uninstall discord.py +``` + +Then, you can install Pycord, it's as simple as that!: + +``` +pip install py-cord +``` + +:::caution +Uninstalling `discord.py` _after_ installing `py-cord` can cause issues. Make sure to uninstall it first! +::: + +## Installing Other Builds + +### Development Build + +:::caution +The development build comes with cutting edge features and new functionality, but as it isn't a stable build you may encounter bugs. +::: + +To install the development build, you can use the following command in your terminal: + +``` +pip install -U git+https://github.com/Pycord-Development/pycord +``` + +:::important +Git is required to install this build. [Learn how you can install Git](./more/git). +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/interactions/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/interactions/_category_.json new file mode 100644 index 00000000..ea28be60 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/interactions/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 4, + "label": "Interactions" +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json new file mode 100644 index 00000000..6dcafe83 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Application Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx b/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx new file mode 100644 index 00000000..b4ffeade --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx @@ -0,0 +1,85 @@ +--- +title: Context Menus +description: Learn all about Context Menus (User Commands & Message Commands) and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +When you right-click a message, you may see an option called "Apps". Hover over it, and you can see +commands a bot can run with that message. These are called message commands. + +When you right-click a user in the user list, you can once again see an option called "Apps". +Hover over it, and you can see commands a bot can run with that message. These are called user commands. + +Together, these two are called Context Menus or Context Menu Commands. These commands work very much like normal commands, except they take a member or message. + +:::note + +A bot can have up to 5 global Context Menus of each type. + +::: + +## User Commands + +Creating a user command is very simple. + +```python +@bot.user_command(name="Account Creation Date", guild_ids=[...]) # create a user command for the supplied guilds +async def account_creation_date(ctx, member: discord.Member): # user commands return the member + await ctx.respond(f"{member.name}'s account was created on {member.created_at}") +``` + + + +
+ + Account Creation Date + +
+ {defaultOptions.profiles.bob.author}'s account was created on 2020-01-01 +
+
+ +## Message Commands + +```python +@bot.message_command(name="Get Message ID") # creates a global message command. use guild_ids=[] to create guild-specific commands. +async def get_message_id(ctx, message: discord.Message): # message commands return the message + await ctx.respond(f"Message ID: `{message.id}`") +``` + + + + Do. Or do not. There is no try. + + +
+ + Get Message ID + +
+ Message ID: 930650407917748286 +
+
+ +
+ +:::info Related Topics + +- [Slash Commands](./slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx b/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx new file mode 100644 index 00000000..edac55b3 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx @@ -0,0 +1,56 @@ +--- +title: Localizations +description: Localizations are a way to make your bot more accessible to your users. Learn all about localizations now! +--- + +Localizations are a way to make your bot more accessible to your users. You can localize the command +name, the names of any arguments, and any text that is displayed to the user. + +## Syntax + +```python +@bot.slash_command( + name="ping", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + }, + options=[ + Option( + name="Example", + name_localizations={ + "en-GB": "British Example" + }, + description="Example option that does nothing", + description_localizations={ + "en-GB": "British example option that does nothing" + } + ) + ] +) +async def ping(ctx, example): + responses = {"en-US": "Pong!", + "en-GB": "British Pong!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +@bot.slash_command( + name="ping2", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + } +) +async def ping2(ctx, example: Option(str, "example", name_localizations={"en-GB": "British Example"}, description="Example option that does nothing", description_localizations={"en-GB": "British example option that does nothing"})): + responses = {"en-US": "Pong2!", + "en-GB": "British Pong2!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +``` + +- [`Locales`](https://discord.com/developers/docs/reference#locales) - List of valid locales recognized by Discord diff --git a/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx b/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx new file mode 100644 index 00000000..ed454dad --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx @@ -0,0 +1,292 @@ +--- +title: Slash Commands +description: Learn all about Slash Commands and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On March 24, 2021, Discord added Slash Commands to Discord as an easier, more efficient, and better way of using bot commands. Pycord has implemented Slash Commands into the library, so it's simple, efficient, and familiar. + +:::important + +Remember that Slash Commands require your bot to be invited with the `application.commands` scope or Slash Commands will not show up. Bots already in the guild can simply be invited again with the scope; there is no need to kick the bot. + +::: + +## Syntax + +Let's create a simple Slash Command. + +```py +import discord + +bot = discord.Bot() + +# we need to limit the guilds for testing purposes +# so other users wouldn't see the command that we're testing + +@bot.command(description="Sends the bot's latency.") # this decorator makes a slash command +async def ping(ctx): # a slash command will be created with the name "ping" + await ctx.respond(f"Pong! Latency is {bot.latency}") + +bot.run("TOKEN") +``` + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +Let's go through the code. + +First, we import Pycord's `discord` package. + +Next, we create a [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot) object and assign it to a variable `bot`. + +We then go ahead and use the [`@bot.command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.command) decorator, which registers a new Slash Command. We pass a `description` parameter to give a description to the Slash Command. We can also pass a `name` parameter to change the Slash Command's name. By default, the name of the Slash Command will be the name of the function, in this case, `/ping`. + +We create an async function called `ping` with parameters `ctx`, which, when called, sends the bot's ping/latency using [`ctx.respond`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext.respond). + +## Subcommand Groups + +You might want to group certain commands together to make them more organised. A command group is exactly what it sounds like, a group of individual Slash Commands together. + +In order to make a Slash Command group, you can use the `bot.create_group` function. + +```python +import discord + +bot = discord.Bot() + +# create Slash Command group with bot.create_group +greetings = bot.create_group("greetings", "Greet people") + +@greetings.command() +async def hello(ctx): + await ctx.respond(f"Hello, {ctx.author}!") + +@greetings.command() +async def bye(ctx): + await ctx.respond(f"Bye, {ctx.author}!") + +bot.run("TOKEN") +``` + +Or, you can instead manually make a `SlashCommandGroup` class like so: + +```python +import discord + +math = discord.SlashCommandGroup("math", "Math related commands") + +@math.command() +async def add(ctx, num1: int, num2: int): + sum = num1 + num2 + await ctx.respond(f"{num1} plus {num2} is {sum}.") + +@math.command() +async def subtract(ctx, num1: int, num2: int): + sum = num1 - num2 + await ctx.respond(f"{num1} minus {num2} is {sum}.") + +# you'll have to manually add the manually created Slash Command group +bot.add_application_command(math) +``` + +Here's what the registered subcommands will look like in the Slash Command Menu: + +![Picture of the subcommands in the Slash Command Menu](../../assets/interactions/groups-and-subcommands.jpg) + +You'll notice that there's the name of the Slash Command Group and then the name of the subcommand separated by a space. + +::: + +:::info Cogs + +If you are looking to add Slash Command Groups to cogs, please look at our [Cogs page](../../popular-topics/cogs)! + +::: + +## Sub-groups + +We've made a subcommand group, but did you know that you could create a group inside another? + +```python +from discord import SlashCommandGroup +from math import sqrt + +math = SlashCommandGroup("math", "Math related commands") +advanced = math.create_subgroup("advanced", "Advanced math commands") + +@advanced.command() +async def square_root(ctx, x: int): + await ctx.respond(sqrt(x)) + +bot.add_application_command(math) +``` + +The command created above can be invoked by typing `/math advanced square_root`. + +## Options & Option Types + +Whenever you're using Slash Commands, you might notice that you can specify parameters that the user has to set or can optionally set. These are called Options. + +Options can also include a description to provide more information. [You can learn more about Options in our documentation!](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.Option) + +Since you want different inputs from Options, you'll have to specify the type for that Option; there are a few ways of doing this. + + + + +You could use Type Annotations and let Pycord figure out the option type or explicitly specified using the [`SlashCommandOptionType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.SlashCommandOptionType) enum. + +```python +import discord + +bot = discord.Bot() + +@bot.command() +# pycord will figure out the types for you +async def add(ctx, first: discord.Option(int), second: discord.Option(int)): + # you can use them as they were actual integers + sum = first + second + await ctx.respond(f"The sum of {first} and {second} is {sum}.") + +@bot.command() +# this explicitly tells pycord what types the options are instead +async def join( + ctx, + first: discord.Option(discord.SlashCommandOptionType.string), + second: discord.Option(discord.SlashCommandOptionType.string) +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + add + +
+ The sum of 1 and 1 is 2. +
+ +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+ + +Instead of Type Annotations, you can also use the option decorator. This is usually done to have type-hinting. + +```python title="Slash Command Type" +import discord + +bot = discord.Bot() + +@bot.command() +@discord.option("first", type=discord.SlashCommandOptionType.string) # type = str also works +@discord.option("second", type=discord.SlashCommandOptionType.string) # type = str also works +async def join( + ctx, + first: str, + second: str, +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+
+ +## Autocomplete + +Discord's autocomplete allows developers to determine option choices that are used in a slash command option. You can do this by defining a function: + +```py +async def get_animal_types(ctx: discord.AutocompleteContext): + """ + Here we will check if 'ctx.options['animal_type']' is a marine or land animal and return respective option choices + """ + animal_type = ctx.options['animal_type'] + if animal_type == 'Marine': + return ['Whale', 'Shark', 'Fish', 'Octopus', 'Turtle'] + else: # is land animal + return ['Snake', 'Wolf', 'Lizard', 'Lion', 'Bird'] + +@bot.slash_command(name="animal") +async def animal_command( + ctx: discord.ApplicationContext, + animal_type: discord.Option(str, choices=['Marine', 'Land']), + animal: discord.Option(str, autocomplete=discord.utils.basic_autocomplete(get_animal_types)) +): + await ctx.respond(f'You picked an animal type of `{animal_type}` that led you to pick `{animal}`!') +``` + + + +
+ + animal + +
+ You picked an animal type of Marine that led you to pick Shark! +
+
+ +:::warning + +Autocomplete can **only** be used with slash commands. + +::: + +:::info Related Topics + +- [Interactions Index](../../interactions) +- [Rules and Common Practices](../../getting-started/rules-and-common-practices) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/interactions/index.mdx b/i18n/de/docusaurus-plugin-content-docs/current/interactions/index.mdx new file mode 100644 index 00000000..8603437f --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/interactions/index.mdx @@ -0,0 +1,242 @@ +--- +title: Discord Interactions +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +In December 2020, Discord released their first Interaction: the +[Slash Command](https://discord.com/developers/docs/interactions/application-commands#slash-commands). +Since then, Discord has added many types of Interactions, including: + +[**Application Commands**](https://discord.com/developers/docs/interactions/application-commands) + +- [**Slash Commands**](https://discord.com/developers/docs/interactions/application-commands#slash-commands): + Commands that can be used with the `/` prefix. +- **Context Menu Commands**: Commands that can be used from the right-click menu. + - [**User Commands**](https://discord.com/developers/docs/interactions/application-commands#user-commands): + Commands that can be used on a user by alt-clicking/selecting them. + - [**Message Commands**](https://discord.com/developers/docs/interactions/application-commands#message-commands): + Commands that can be used on a message by alt-clicking/selecting it. + +[**UI Components**](https://discord.com/developers/docs/interactions/message-components) + +- [**Buttons**](https://discord.com/developers/docs/interactions/message-components#buttons): + Buttons are attached to a message and can be clicked on to perform an action. +- [**Select Menus**](https://discord.com/developers/docs/interactions/message-components#select-menus): + Drop-down menus are used to select a number of options from a list. +- [**Modals**](https://discord.com/developers/docs/interactions/message-components#text-inputs): + Form-like modals can be used to ask for input from a user. + +## Application Commands + +Application Commands are another set of new features that are intended to avoid compromising users' safety and privacy. +They're relatively easy to add to your bot, and give people a simpler and safer way to use commands. + +### [Slash Commands](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.SlashCommand) + +Slash Commands were the first Interaction added to Discord. They're easy to use and create, and +is the only prefix commands alternative that does not need Message Content intent. + +:::note + +Preferring prefix commands over Application Commands is **not** a valid reason to apply for the +Message Content intent. Using that as a reason will get your application denied. + +::: + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +This is what a Slash Command looks like. Not too different from a prefix command, +apart from the note telling you who invoked it. A Slash Command's fields can accept any of the following: + +- Members +- Roles +- Channels +- Attachments +- Text + +Just about as good as it gets. + +### [Message](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.MessageCommand) and [User](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.UserCommand) Commands + +Message Commands and User Commands were both introduced at around the same time, and are very similar to each other, so we'll be +introducing them together. These commands can be found in the `Apps` tab when alt-clicking. The only difference between the two is that +Message Commands only appear in the `Apps` tab of a message, while User Commands are found in the `Apps` tab of a user. Message Commands +can be used to quickly report a message, warn a user for a message, and other functions. Likewise, User Commands can be used to add a +user to a ticket, warn a user, and more. + +Here's an example of a Message Command: + + + + Hello World! + + +
+ + Reverse Message + +
+ Message 930650407917748286 reversed is "!dlroW olleH" +
+
+ +
+ +And here's an example of a User Command: + + + + {defaultOptions.profiles.dorukyum.author} has been on Discord for a long time + + +
+ + User Age + +
+ {defaultOptions.profiles.dorukyum.author} is 1 week old. +
+ +
+ + User Age + +
+ {defaultOptions.profiles.bob.author} is 40 years old. +
+ + 🤔 + +
+ +
+ +Pretty cool, right? To learn more about these two, please read the [Context Menus guide](./application-commands/context-menus.mdx). + +## [Application Commands](#application-commands) vs. [Prefix Commands](../extensions/commands/prefixed-commands) + +Ever since Discord was created, apps on it have used prefix commands. Using prefixes meant that you would have to put a +certain character (or string of characters) in front of your command, such as the exclamation mark in `!ping`. The way this +worked was that your bot would listen for messages, pick out the ones that had their specific prefix, and then respond to the command. +Now, Discord is encouraging developers to switch their bots over to Application Commands, which is a new system meant to preserve the +privacy and safety of their users. But why exactly is Discord making us switch? What's the better option, Application Commands or prefix +commands? Below, we'll discuss everything you need to know. + +### Discord's Decision + +Application Commands were conceptualized partly due to privacy concerns. When Discord first began, they weren't entirely concerned about bots +having access to the content of every message that was being sent. However, as Discord grew, this became more of a problem. Hypothetically, bots +could simply log every message they're able to receive via the Discord API and hand their contents over to a company or other third party. This is +a problem, since that data is meant to be used only by Discord. As such, they locked down Message Content, and introduced Application Commands for +bot developers to use instead. + +Prefix commands work by reading messages, as described before. Application Commands, however, don't +work this way; instead, they work by having your bot get information from Discord about when a command was used. This way, Discord can limit +Message Content only to bots that _absolutely_ depend on it, such as auto-moderation bots. + +### Who has to Use Application Commands + +Any verified bot that does not have the Message Content intent must use Application Commands. Discord is allowing developers to submit +applications for the ability to use the intent; however, since they don't want to keep supporting prefix commands due to privacy concerns, +they will automatically decline any application that includes only that as a reason. So, if your bot doesn't have an auto-moderation feature +(or any other functionality that requires Message Content), you're out of luck. + +Unverified bots, however, don't have to use Application Commands. This is because the Message Content intent is a `Privileged Intent`, meaning that +it must be applied for only if your bot is verified or about to be verified. Unverified bots don't have to apply for Privileged Intents, so they can +use them freely. + +So, if your bot is made only for a couple of servers, you can choose between prefix commands and Application Commands. However, if you plan on expanding +your bot's reach, it'll have to use Application Commands. + +### What's the Better Option + +Choosing which is the better option is up to you, if you're starting small. If +you plan on growing your bot, however, you will have to use Application Commands. Since prefix commands are slowly being phased out by Discord, +there isn't much of a choice for developers of larger bots. + +## Message Components + +Message Components are fairly new features in Discord, allowing developers to give their bots a fast +and understandable user interface. Message Components are easy to use and make your bot look modern, +sleek, and downright awesome. + +### [Views](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View) + +Views are not an Application Command nor are they a Message Component. Views are the invisible placeholders, or grid, +that Message Components lie in. Views can have up to 5 [`Action Rows`](https://docs.pycord.dev/en/stable/api/models.html#discord.ActionRow), +and Action Rows can have a maximum of 5 slots. Below, you can find a table showing how many slots a Message Interaction takes up. + +| Component | Slots | +| ------------ | ----------------------------------------------- | +| Buttons | 1 Slot | +| Select Menus | 5 Slots | +| Text Modals | 1 Slot (opened via a Button) | + +So, based on this, you could have a maximum of 25 Buttons in a View with no Select Menus, and 5 Select +Menus in a View with no Buttons. This doesn't mean you can't have them both in a View, however. You can have +a combination of them, such as 20 Buttons and a Select Menu or 10 Buttons and 3 Select Menus. + +### [Buttons](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button) + +Buttons are the first of the Message Components. They allow for quick responses to prompts, such as for canceling or continuing an action. +Of course, these aren't their only uses; people have created awesome things with Buttons, such as calculators, games, and more! + + + + Discord Buttons are awesome! +
+ + Click me! + +
+
+
+ +
+ +This is what a Button looks like, very simple and modern. To learn more about Buttons, refer to our +[Buttons page](./ui-components/buttons.mdx). + +### [Select Menus](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Select) + +Select Menus are the second of Discord's Message Components. They allow users to select from a list of choices, which your bot can then use. +Select Menus are good for things such as choosing features, pages of a help menu, and more. + +![Select Menu Example Image](../assets/interactions/select-menus-example.png) + +This is what a Select Menu looks like. While not looking as good as Buttons, they still look great +and have even greater possibilities. To learn more about Select Menus, please refer to our [Select +Menus page](./ui-components/dropdowns.mdx). + +### [Modal Dialogs](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal) + +Text Modals are the most recently added Message Component in Discord. They're useful for text input and filling out forms, such as a +sign-up for your bot's service. These are meant to replace long bot setup processes by allowing users to fill out multiple text fields, +which avoids having the user send multiple messages for the bot. Modals can be accessed by either invoking an Application Command or by +interacting with another UI Component. + +![Text Modal Example Image](../assets/interactions/modal-example.png) + +This is what a Text Modal looks like, easy to use and one of the most useful Message Components yet. To learn more about Text Modals, +please visit our [Modal Dialogs page](./ui-components/modal-dialogs.mdx). diff --git a/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json new file mode 100644 index 00000000..7b0a72fe --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "UI Components", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx b/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx new file mode 100644 index 00000000..046b36c7 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx @@ -0,0 +1,314 @@ +--- +title: Buttons +description: Learn all about implementing buttons in your Discord Bot using Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On May 26, 2021, Discord added a new interaction called buttons. Instead of reactions, bots could now +send buttons and users could use them to interact with bots. This opened up a whole new world of +possibilities for bots. Soon after, developers made calculators, polls, and games like blackjack, UNO, +and even Minecraft! Buttons provided a clear and easy to use interface for interacting with bots. + +So, let's learn how you can add buttons to your bot! + +## Concept + +Buttons weren't the only update to the interactions system in Discord. Discord also added [Select Menus](./dropdowns) and [Modal Dialogs](./modal-dialogs), both of which work very similarly to buttons. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive button. + +```python +import discord + +bot = discord.Bot() # Create a bot object + +class MyView(discord.ui.View): # Create a class called MyView that subclasses discord.ui.View + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.primary, emoji="😎") # Create a button with the label "😎 Click me!" with color Blurple + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") # Send a message when the button is clicked + +@bot.slash_command() # Create a slash command +async def button(ctx): + await ctx.respond("This is a button!", view=MyView()) # Send a message with our View class that contains the button + +bot.run("TOKEN") # Run the bot +``` + +Using this command should return the following message: + + + +
+ + button + +
+ This is a button! +
+ + Click me! + +
+
+
+ +
+ +As you can see, we create a class called `MyView` that [subclasses](#oop) +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `button_callback` to the `MyView` class with the decorator +[`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button). +This decorator adds a button to a component. This function takes two arguments: the button that was +clicked and the interaction. These arguments are passed to the function when the button is clicked +by the module. We use the [`interaction.response.send_message`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse.send_message) +function to send a message to the channel where the interaction was sent. + +Finally, we create a global slash command called `button` that sends the message, along with the view +that contains a button. + +This is the basic syntax of creating a button. What you create with it is up to you. You can worry +about making your button do amazing things, while Pycord handles the rest! + +## Button Styles + + + +| Name | Usage | Color | +| --------- | ----------------------------------------------------------------------------------------- | ------- | +| Primary | `discord.ButtonStyle.primary` / `discord.ButtonStyle.blurple` | Blurple | +| Secondary | `discord.ButtonStyle.secondary` / `discord.ButtonStyle.grey` / `discord.ButtonStyle.gray` | Grey | +| Success | `discord.ButtonStyle.success` / `discord.ButtonStyle.green` | Green | +| Danger | `discord.ButtonStyle.danger` / `discord.ButtonStyle.red` | Red | +| Link | `discord.ButtonStyle.link` / `discord.ButtonStyle.url` | Grey | + +Check out the [`discord.ButtonStyle`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ButtonStyle) class for more information. + +![Different Button Styles](../../assets/interactions/button-styles.png) + +You can set a button's style by adding the `style` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) decorator. + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.success) + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots, and each button takes up 1 slot. +So, how do we move the buttons to another row? + +This can be done by specifying the `row` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) +decorator. + +:::info The `row` argument + +The row argument specifies the relative row this button belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=1, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") +``` + +## Disabling Buttons + +### Pre-Disabled Buttons + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary, disabled=True) # pass `disabled=True` to make the button pre-disabled + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView()) +``` + +### Disabling Buttons on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + button.disabled = True # set button.disabled to True to disable the button + button.label = "No more pressing!" # change the button's label to something else + await interaction.response.edit_message(view=self) # edit the message's view +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(emoji="😀", label="Button 1", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) + + @discord.ui.button(label="Button 2", style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +Sometimes, you want to have a button that is disabled after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView(timeout=30)) +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a button that is disabled after a certain amount of time, you want to have a +button that is always working. + +Normally, when the bot goes offline, all of its buttons stop working. You will be able to see the +buttons, but nothing will happen when you press them. This is a problem +if you are trying to create a self-role system with buttons, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons will stop working. When the bot comes back online, however, the buttons will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view must have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.button(label="A button", custom_id="button-1", style=discord.ButtonStyle.primary, emoji="😎") # the button has a custom_id set + async def button_callback(self, button, interaction): + await interaction.response.send_message("Button was pressed", ephemeral=True) + +@bot.command() +async def button(ctx): + await ctx.send(f"Press the button! View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many buttons can I have in a message? + +Each message can have a maximum of 25 buttons. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do buttons need any special permissions? + +No new permissions are needed for either the bot or the server to allow bots to use buttons. + +#### Should I replace reactions with buttons for my bot? + +That is up to you. Buttons do provide a cleaner interface for your bot and are easier to use. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx b/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx new file mode 100644 index 00000000..8320f25d --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx @@ -0,0 +1,339 @@ +--- +title: Select Menus +description: Learn all about implementing Select Menus or Dropdowns in your Discord Bot with Pycord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Shortly after the buttons were added, Discord added their second message component: Select Menus. Select Menus allow users to choose from a list of items sent by a bot. These are a great substitute for having a user send a number that corresponds to an option. You can even allow users to select multiple options from the Select Menus. This guide will show you the easy and painless ways of using them with Pycord. + +## Concept + +Select Menus aren't the only message component in Discord. There's also [Buttons](./buttons) and [Modal Dialogs](./modal-dialogs). Select Menus make it easy for users to pick one or multiple options from a list provided by a bot. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive select menu. + +```python +import discord + +bot = discord.Bot() + +class MyView(discord.ui.View): + @discord.ui.select( # the decorator that lets you specify the properties of the select menu + placeholder = "Choose a Flavor!", # the placeholder text that will be displayed if nothing is selected + min_values = 1, # the minimum number of values that must be selected by the users + max_values = 1, # the maximum number of values that can be selected by the users + options = [ # the list of options from which users can choose, a required field + discord.SelectOption( + label="Vanilla", + description="Pick this if you like vanilla!" + ), + discord.SelectOption( + label="Chocolate", + description="Pick this if you like chocolate!" + ), + discord.SelectOption( + label="Strawberry", + description="Pick this if you like strawberry!" + ) + ] + ) + async def select_callback(self, select, interaction): # the function called when the user is done selecting options + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") + +@bot.command() +async def flavor(ctx): + await ctx.respond("Choose a flavor!", view=MyView()) + +bot.run("TOKEN") +``` + +There's a lot going on over here! Don't worry, we will go over the code and explain it. + +As you can see, we create a class called `MyView` that subclasses +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `select_callback` to the `View` class with the decorator +[`discord.ui.select`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.select). +This decorator adds a select menu to the view. This decorator takes a few arguments to customize your select menu. Read them in the [Customization section](#customization). + +That was the decorator. Now, the function itself is pretty simple. It takes two parameters, not including `self`. The parameters are `select`: The select menu, and `interaction`: a [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object. Both of these are passed by Pycord, so you just need to specify them in the function! + + + +In the callback, you could do anything you want. You get the two parameters `select` and `interaction` to play around with. Here, we send a message using `await interaction.response.send_message` (where interaction is [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse)) with content `select.values[0]`, which sends the label of the first/only option the user selected. Obviously, this is only an example, and you could do just about anything you want. + +Finally, we create a global slash command called `flavour` that sends a message "Choose a flavor!" along with the view +that contains our select menu. + +This is the basic syntax of creating a select menu. What you create with it is up to you. You can worry +about making your code do amazing things, while Pycord handles the rest! + +## Customization + +#### Select Menu Properties + +- `select_type`: The type of select to create. This must be a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. +- `channel_types`: A list of channel types that can be selected in the menu. This is only valid for selects of `select_type` [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType). +- `options`: A list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. These are the options that can be selected in this menu. +- `placeholder` is the placeholder text shown in the select menu if no option is selected. +- `custom_id`: The ID of the select menu that gets received during an interaction. It is recommended not to set this to anything unless you are trying to create a persistent view. +- `row`: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). +- `min_values`: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `max_values`: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `disabled`: Whether the select is disabled or not. Defaults to False. + +#### Select Option Properties + +In the `options` parameter, you pass a list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. This class also has a few parameters: + +- `default` (whether the option is selected by default) +- `description` (an additional description, if any) +- `emoji` (a string or an emoji object, if any) +- `label` (the name displayed to users, can be up to 100 characters) +- `value` (a special value of the option, defaults to the label). + +## Select Types + +In addition to regular string selects, you can also have your select menu contain users, roles, mentionables, and channels as its options. You can use these alternative select types by passing a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value for the `select_type` parameter when creating the Select. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.user_select + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +Additionally, you can use shortcut decorators to create a [`discord.ui.Select`](https://docs.pycord.dev/en/master/api/ui_kit.html#discord.ui.select) with a predetermined [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. Using a shortcut decorator, the above code can be rewritten like this: + +```python +class MyView(discord.ui.View): + @discord.ui.user_select() + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +### Specifying Channel Types + +When using a [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType.channel_select) type select menu, you can pass in a list of [`discord.ChannelType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ChannelType) values to limit which types of channels users can choose when interacting with the select menu. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.channel_select, + channel_types=[discord.ChannelType.text, discord.ChannelType.voice] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"You selected {select.values[0].mention}") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots. A button takes a single slot, while a select menu takes up all 5 of them. This means a view can have a maximum of 5 select menus, or any possible combination of select menus and buttons. + +The arrangement of buttons and select menus is generally adjusted by Pycord. However, it is possible to move them to specific relative rows. This is done by specifying the `row` argument. + +:::info The `row` argument + +The row argument specifies the relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero-indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=0, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.select( + row = 1, + options = [...] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") +``` + +## Disabling Select Menus + +### Pre-Disabled Menus + +```python +class MyView(discord.ui.View): + @discord.ui.select( + disabled = True, # pass disabled=True to set the menu as disabled + options = [...] + ) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send("Select and option from the menu!", view=MyView()) +``` + +### Disabling Menus on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + select.disabled = True # set the status of the select as disabled + await interaction.response.edit_message(view=self) # edit the message to show the changes +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def first_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) # edit the message to show the changes + + @discord.ui.select(options = [...]) + async def second_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +You may want a select menu to automatically stop working after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select(ctx): + await ctx.send(view=MyView(timeout=30)) # specify the timeout here +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a select menu that is disabled after a certain amount of time, you want to have a +select menu that is always working. + +Normally, when the bot goes offline, all of its views stop working, even if they don't have a timeout. You will be able to see the +views, but nothing will happen when you try to interact with them. This is a problem +if you are trying to create a self-role system, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons and select menus will stop working. However, when the bot comes back online, the buttons and select menus will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view much have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.select(custom_id="select-1", options = [...]) # a custom_id must be set + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send(f"View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many select menus can I have in a message? + +Each message can have a maximum of 5 select menus. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do select menus need any special permissions? + +No new permissions are needed in the bot or in the server. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx b/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx new file mode 100644 index 00000000..bd585c77 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx @@ -0,0 +1,107 @@ +--- +title: Modal Dialogs +description: Learn how you can implement Modals in your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Modal Dialogs, also known as "modals", provide a form-like structure for bots to receive input from users. No extra permissions are needed for bots to send modal dialogs, so it becomes a convenient workaround for bots to receive longer input without needing the Message Content [intent](../../popular-topics/intents). + +## Concept + +Modal Dialogs consist of a title, custom ID, and up to 5 [`discord.ui.InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) components. While creating modals, we generally subclass [`discord.ui.Modal`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal), as we'll see later. + +Unlike other UI Components, Modals cannot be sent with messages. They must be invoked by an Application Command or another UI Component. + +## Usage Syntax + +```py +class MyModal(discord.ui.Modal): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.add_item(discord.ui.InputText(label="Short Input")) + self.add_item(discord.ui.InputText(label="Long Input", style=discord.InputTextStyle.long)) + + async def callback(self, interaction: discord.Interaction): + embed = discord.Embed(title="Modal Results") + embed.add_field(name="Short Input", value=self.children[0].value) + embed.add_field(name="Long Input", value=self.children[1].value) + await interaction.response.send_message(embeds=[embed]) +``` + + + + +The `ctx` parameter we define in Application Commands receives an [`ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext) object. Using its `send_modal()` coroutine, you can send a Modal dialog to the user invoking the Application Command. + +```py +@bot.slash_command() +async def modal_slash(ctx: discord.ApplicationContext): + """Shows an example of a modal dialog being invoked from a slash command.""" + modal = MyModal(title="Modal via Slash Command") + await ctx.send_modal(modal) +``` + + + + +The `interaction` parameter we define in UI Components receives an [`Interaction`](https://docs.pycord.dev/en/stable/api/models.html#discord.Interaction) object. The `response` attribute of the object contains an [`InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object, with various coroutines such as `send_message()` and `send_modal()`, which we utilize. + +```py +class MyView(discord.ui.View): + @discord.ui.button(label="Send Modal") + async def button_callback(self, button, interaction): + await interaction.response.send_modal(MyModal(title="Modal via Button")) + +@bot.slash_command() +async def send_modal(ctx): + await ctx.respond(view=MyView()) +``` + + + + +The above example uses an embed to display the results of the modal submission, but you can do anything you want with the text provided by the user. +Each input field can be accessed in the order it was added to the modal dialog, via `Modal.children`. + +## Customization + +A Modal can have up to 5 [`InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) fields. These fields offer some customization. + +Each field has a label which is shown to the user. This is defined with `label`. + +The `style` parameter is used to determine whether it should be a short (single-line) or long (multi-line) input field. + +There are a number of aliases that can be used: + +```x title="Single-line InputTextStyle values:" +short +singleline +``` + +```x title="Multi-line InputTextStyle values:" +paragraph = 2 +multiline = 2 +long = 2 +``` + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Buttons](./buttons) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/introduction.mdx b/i18n/de/docusaurus-plugin-content-docs/current/introduction.mdx new file mode 100644 index 00000000..3262c632 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/introduction.mdx @@ -0,0 +1,50 @@ +--- +title: Introduction +description: Pycord Guide is a complete guide for Pycord. Learn how to create Discord Bots today! +sidebar_position: 1 +--- + +Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord, written in Python. Pycord is a maintained fork of [discord.py](https://github.com/Rapptz/discord.py). + +## Before you begin + +Pycord is an advanced and complex Python library. To take advantage of the full capabilities of Pycord, you will need to have a good understanding of Python. You should know the basics of Python and have an understanding of the following concepts: + +- Variables +- Data Types +- Functions +- Packages +- Conditionals +- Loops +- Classes +- Object-Oriented Programming +- Inheritance +- Exception Handling +- Iterators +- Coroutines +- Async/Await + +This list is not exhaustive, but it should give you a good idea of what you need to know to get started. + +When you see an ellipsis - that's the three dots - in this guide, it is a placeholder for code that you need to fill in. Sometimes, it may be code for a command, while other times it could be something simple like a Guild ID. Make sure to replace them before running your bot! + +## Learning Resources + +Here are some good resources to get started or to freshen up your Python knowledge: + +- [Official Beginner's Guide](https://wiki.python.org/moin/BeginnersGuide) +- [Official Tutorial](https://docs.python.org/3/tutorial/) +- [Automate the Boring Stuff, a free online book for complete beginners to programming](https://automatetheboringstuff.com/) +- [Learn Python in y Minutes, complete cheat sheet for people who know programming already](https://learnxinyminutes.com/docs/python3/) +- [Swaroopch's free Python book](http://python.swaroopch.com/) +- [Codeabbey, exercises for beginners](http://www.codeabbey.com/) + +## Credits + +First of all, we would like to thank [Rapptz](https://github.com/Rapptz) for the original [discord.py](https://pypi.org/project/discord.py) library. Pycord is a maintained fork of this library. + +We would also like to thank the [discord.js guide](https://discordjs.guide), which inspired this guide style-wise, and the [original Pycord Guide](https://namantech.me/pycord), which inspired some content in this guide. + +We created this guide using [Docusaurus v2](https://docusaurus.io), a modern static site generator for React. We would also like to thank Danktuary for his [`@discord-message-components/react`](https://www.npmjs.com/package/@discord-message-components/react) package, from which we took the Discord message components. + +And finally, we would like to thank the amazing and loving community of Pycord users, contributors and developers. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/more/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/more/_category_.json new file mode 100644 index 00000000..2cbe2c56 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/more/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 8, + "label": "More", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/more/community-resources.mdx b/i18n/de/docusaurus-plugin-content-docs/current/more/community-resources.mdx new file mode 100644 index 00000000..ed3075bd --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/more/community-resources.mdx @@ -0,0 +1,23 @@ +--- +title: Community Resources +--- + +This page showcases the amazing things created by the Pycord community, including bots, Plugins, and more. + +## Plugins + +| Name | Type | GitHub | +| --------------- | ------------ | --------------------------------------------------------------- | +| Music Cord | Music | [NixonXC/cord-music](https://github.com/NixonXC/cord-music) | +| pycord-i18n | Localization | [Dorukyum-pycord-i18n](https://github.com/Dorukyum/pycord-i18n) | +| pycord-multicog | Cogs | [pycord-multicog](https://github.com/Dorukyum/pycord-multicog) | +| EzCord | Utilities | [EzCord](https://github.com/tibue99/ezcord) | + +## Bots + +| Name | Type | Link | +| ------------------------ | ------------ | ----------------------------------------------------------------------------------- | +| Discord-Multipurpose-Bot | Multipurpose | [github](https://github.com/pogrammar/Discord-multipurpose-bot/tree/master/Python) | +| inconnu | Fun & QOL | [github](https://github.com/tiltowait/inconnu) | +| Mai | Multipurpose | [github](https://github.com/TeamMai/Mai) & [website](https://xfghoul.github.io/Mai) | +| Toolkit | Multipurpose | [github](https://github.com/Dorukyum/Toolkit) | diff --git a/i18n/de/docusaurus-plugin-content-docs/current/more/contributing.mdx b/i18n/de/docusaurus-plugin-content-docs/current/more/contributing.mdx new file mode 100644 index 00000000..469ea3ee --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/more/contributing.mdx @@ -0,0 +1,463 @@ +--- +title: Contributing to the Guide +description: Learn how to contribute to the Pycord Guide. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +This page outlines some of the basic syntax you need to know to contribute to the guide. We recommend you also check out: + +- [Docusaurus's Docs](https://docusaurus.io/docs/) +- [Contributing Rules](https://github.com/Pycord-Development/guide/blob/master/.github/CONTRIBUTING.md) + +## Info + +We use [Docusaurus v2](https://docusaurus.io/) to generate our guide. All the guide pages are generated +from `mdx` files in the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory. +MDX allows you to use JSX in your markdown content. + +## Structure + +Let's visit the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory and check its file structure. + +We can see various folders and a few files in it. Let's talk a bit about the `introduction.mdx` file. At the top, you can see something like: + +```md +--- +title: Introduction +description: ... +sidebar_position: 1 +--- +``` + +Most pages have this at the top. The `title` defaults to the file name. Since the titles need to be Capitalized according to need while the file names are lowercased (sometimes, the file names are shorter than the title!), we set a title ourselves. + +The `description` field is also important. This is the text shown in an embed when the page's link is shared on Discord, Twitter or other websites that support embedded links. Make sure to give a nice an interesting description! + +The `sidebar_position` field is pretty self-explanatory. It sets the position of the page in the sidebar. Most files in categories do not need this since they are sorted alphabetically. + +## Markdown Syntax + +This page quickly outlines some of the syntax that is used in markdown. + +````mdx +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + + ```python + print("We can use code blocks like this.") + ``` + +You can add [links to other websites](https://pycord.dev). You can add images like this: ![alternate text that describes the image](https://pycord.dev/image.png). + +- You can create +- unordered lists like this + +1. Or ordered lists +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` +4. Like this + +# Headers + +## Go + +### Like + +#### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet +```` + +
+Preview +
+ +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + +```python +print("We can use code blocks like this.") +``` + +You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](@site/static/img/favicon.ico). + +- You can create +- unordered lists like this + +1. Or ordered lists + +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` + +4. Like this + + # Headers + + ## Go + + ### Like + + #### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet + +
+
+ +## Admonitions + +We can add warnings, notes, etc. with the following syntax: + +```md +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: +``` + +
+Preview +
+ +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: + +
+ +
+ +## Discord Message Components + +As most files already have the imports for these, it's not that hard to add them. + +First, import the necessary components: + +```tsx +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; +``` + +The div starts like so: + +```tsx + + + + +
+``` + +This is where you list a `DiscordMessage`. + +```tsx + + + Hello! + + + +
+``` + + + + Hello! + + + +
+ +It has a pretty straightforward syntax. + +:::tip + +Add a `
` to the end of a component to make the content below it look better. + +::: + +### Slash Commands + +To make a message authored by a slash command, do the following: + +```tsx + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+``` + + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+ +### Buttons + +To make a message with buttons, do the following: + +```tsx + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+``` + + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+ +## Page Format + +There are a few things you need to take care of: + +1. Make sure that the spelling and grammar is perfect. We have a GitHub action configured that will warn you about spelling errors when you start a pull request. Make sure to commit your changes accordingly. + + As for the grammar, you should try reading the changes you have done and wait for reviews from others. + +2. A common mistake people make is incorrect header style. People often think that the less the important the topic is, the lower it's heading style should be. + + ```md + [PAGE STARTS] + # Topic + ## Less Important Topic + ## Subtopic + ``` + + ```md + [PAGE STARTS] + # About + [Introduction] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + That's VERY wrong. Here's the correct example: + + ```md + [PAGE STARTS] + [Introduction] + ## Topic + ## Less Important Topic + ### Subtopic + ``` + + ```md + [PAGE STARTS] + [Introduction] + + ## About + [More Information] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + Note that the `---`s at the beginning have been skipped here. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/more/git.mdx b/i18n/de/docusaurus-plugin-content-docs/current/more/git.mdx new file mode 100644 index 00000000..0f929d6d --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/more/git.mdx @@ -0,0 +1,55 @@ +--- +title: Installing Git +description: Learn how you can install Git on your system. +--- + +Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Let's see how to install Git on different platforms. + +## Windows + +On Windows, Git can be installed via: + +- [Git for Windows](https://gitforwindows.org) +- [Git Scm](https://git-scm.com/download/windows) + +## Linux + +On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. + +## Mac + +You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: + +``` +xcode-select --install +``` + +## Using Package Managers + +You can also install Git using package managers. + +### Chocolatey + +If you use the Chocolatey package manager, you can install Git using: + +``` +choco install git +``` + +### Scoop + +If you use Scoop, you can install Git using: + +``` +scoop install git +``` + +### Brew + +If you're on macOS or Linux, you can install Git using: + +``` +brew install git +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx b/i18n/de/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx new file mode 100644 index 00000000..b0b8c7ea --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx @@ -0,0 +1,62 @@ +--- +title: Virtual Environments +description: Learn how to set up a virtual environment for Pycord. +--- + +## Setup + +Sometimes you want to keep libraries from polluting system installs or use a different version of libraries than the ones installed on the system. You might also not have permissions to install libraries system-wide. For this purpose, the standard library as of Python 3.3 comes with a concept called “Virtual Environment”s to help maintain these separate versions. + +A more in-depth tutorial is found on [Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html). + +However, for the quick and dirty: + +Go to your project’s working directory: + +```bash +$ cd your-bot-source +$ python3 -m venv venv +``` + +Activate the virtual environment: + +```bash +$ source venv/bin/activate +``` + +On Windows you activate it with: + +```batch +$ venv\Scripts\activate.bat +``` + +Use pip like usual: + +```bash +$ pip install -U py-cord +``` + +Congratulations. You now have a virtual environment all set up. + +## Additional info + +It can be useful to set up a requirements.txt, so you can just put all of your dependencies in there and have pip install it. +For instance, if you wanted to have the latest 2.0 version of pycord and [pytz](https://github.com/stub42/pytz/blob/master/src/README.rst), just create a file named requirements.txt with the following contents: + +``` +py-cord>=2.0.0 +pytz +``` + +And then (in your virtual environment) you can just execute + +```bash +pip install -r requirements.txt +``` + +To keep from committing your virtual environment to git, you can set up a .gitignore file with the following line +(assuming you named your virtual environment venv like the above example): + +``` +venv/ +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/_category_.json new file mode 100644 index 00000000..c38ea014 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 7, + "label": "Popular Topics", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx new file mode 100644 index 00000000..5377a6c3 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx @@ -0,0 +1,140 @@ +--- +title: Cogs +--- + +Cogs, often known as modules or extensions, are used to organize commands into groups. This is useful +for grouping commands that have the same general idea (such as moderation commands). This also helps +to avoid making your bot's files messy and cluttered. + +## Getting Started + +First, you'll need to create a folder to store your cogs, e.g. `cogs/`. + +Then, create a file inside the folder, e.g. `cogs/greetings.py`. By convention, the file name should +be the same as the name of the cog or module. + +We can then create the cog. + +```python title="./cogs/greetings.py" +import discord +from discord.ext import commands + +class Greetings(commands.Cog): # create a class for our cog that inherits from commands.Cog + # this class is used to create a cog, which is a module that can be added to the bot + + def __init__(self, bot): # this is a special method that is called when the cog is loaded + self.bot = bot + + @commands.command() # creates a prefixed command + async def hello(self, ctx): # all methods now must have both self and ctx parameters + await ctx.send('Hello!') + + @discord.slash_command() # we can also add application commands + async def goodbye(self, ctx): + await ctx.respond('Goodbye!') + + @discord.user_command() + async def greet(self, ctx, member: discord.Member): + await ctx.respond(f'{ctx.author.mention} says hello to {member.mention}!') + + math = discord.SlashCommandGroup("math", "Spooky math stuff") # create a Slash Command Group called "math" + advanced_math = math.create_subgroup( + "advanced", + "super hard math commands!" + ) + + @math.command() + async def add(self, a: int, b: int): + c = a + b + await ctx.respond(f"{a} + {b} is {c}.") + + @advanced_math.command() + async def midpoint(self, x1: float, y1: float, x2: float, y2: float): + mid_x = (x1 + x2)/2 + mid_y = (y1 + y2)/2 + await ctx.respond(f"The midpoint between those coordinates is ({mid_x}, {mid_y}).") + + @commands.Cog.listener() # we can add event listeners to our cog + async def on_member_join(self, member): # this is called when a member joins the server + # you must enable the proper intents + # to access this event. + # See the Popular-Topics/Intents page for more info + await member.send('Welcome to the server!') + +def setup(bot): # this is called by Pycord to setup the cog + bot.add_cog(Greetings(bot)) # add the cog to the bot +``` + +You can add any number of commands to your cog, as well as event listeners. However, this code will +not work on its own. In your main bot file, you must add the following code: + +```python +bot.load_extension('cogs.greetings') +``` + +This loads the file `cogs/greetings.py` and adds it to the bot. +The argument of `load_extension` should be your cog's path (e.g. cogs/greetings.py) without the file +extension and with the `/` replaced with `.` + +If you have multiple cogs, you can add them all at once by adding the following code: + +```python +cogs_list = [ + 'greetings', + 'moderation', + 'fun', + 'owner' +] + +for cog in cogs_list: + bot.load_extension(f'cogs.{cog}') +``` + +## Cog Rules + +When using a cog instead of the main file, there are some changes you have to make to your code. This +is because cogs work slightly different from a regular file. + +### The `self` variable + +The self variable is a variable that represents a class. In the case of cogs, `self` represents +the cog. In the `__init__` function, you can see that we have `self.bot = bot`. `bot` represents your +`discord.Bot` or `discord.ext.commands.Bot` instance, which is used for some functions. + +This means that instead of using functions that would usually be accessed via `bot`, you now need +to access them via `self.bot` + +Because we're in a class, all of our commands are methods of that class. Because of this, all of our +functions need to have `self` as the first parameter, where `self` is the cog. Without this, we +wouldn't be able to access our bot instance. + +### Creating Commands + +When creating prefixed commands, your decorator would usually be something like `@bot.command()`. If you're using +cogs, this isn't the case. In a cog, you can't access the bot instance outside of functions, so to +register a function as a command, you must instead use `@commands.command()`. + +Similar to prefixed commands, you'll have to use either the `@discord.slash_command()`, `@discord.user_command()`, +or `@discord.message_command()` decorators for Application Commands. + +Also, when creating a command, make sure that it is indented. If we want a command to be actually +inside a cog, it has to be inside your cog's class. If the command is not inside the cog, +your command becomes useless. + +### Events + +When creating events, you can no longer use `@bot.event` as a decorator. This is because we cannot +access the `bot` variable outside a function. To make an event, you have to use the `ext.commands` +method, `@commands.Cog.listener()`. Events also need `self` as their first parameter. + +And that's it! Cogs are a simple and easy way of organizing your code. Now you can check out how to +create a help command [here](../extensions/commands/help-command). + +:::info Related Topics + +- [Creating a Help Command](../extensions/commands/help-command) +- [Rules and Common Practices](../getting-started/rules-and-common-practices) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Application Commands](../interactions#application-commands) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx new file mode 100644 index 00000000..6c19dd29 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx @@ -0,0 +1,383 @@ +--- +title: Error Handling +description: All about handling errors. +--- + +import { + DiscordEmbed, + DiscordInteraction, + DiscordMessage, +} from "discord-message-components/packages/react"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +## About + +When using the library, errors are frequently raised due to various reasons. These reasons range from the Discord API +failing your bot's request due to missing permissions or an invalid syntax error. + +Before going into error handling, it's best that you learn the basic ways of handling errors. A good resource is: + +- [W3Schools' Guide to Python Try-Except Statements](https://www.w3schools.com/python/python_try_except.asp) + +## Basic Handling + +The most basic way to handle errors is to tackle it at the source. This can be done like so: + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +import asyncio + +import discord + +intents = discord.Intents.default() +intents.message_content = True + +bot = discord.Bot(intents=intents) + + +@bot.slash_command(description="Gets some feedback.") +@discord.option("name", description="Enter your name.") +async def feedback(ctx: discord.ApplicationContext, name: str): + try: + await ctx.respond(f"Hey, {name}! Send your feedback within the next 30 seconds please!") + + def is_author(m: discord.Message): + return m.author.id == ctx.author.id + + feedback_message = await bot.wait_for("message", check=is_author, timeout=30.0) + await ctx.send(f"Thanks for the feedback!\nReceived feedback: `{feedback_message.content}`") + except asyncio.TimeoutError: + await ctx.send("Timed out, please try again!") + + +bot.run("TOKEN") +``` + +If you respond within 30 seconds, the interaction will look like so: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Great bot! + + + Thanks for the feedback! +
+ Received feedback: Great bot! +
+
+
+ +Otherwise, if you don't respond in time, the interaction will go as follows: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Timed out, please try again! + +
+
+ +This basic method of error handling can be extended to handle +many other errors including ones raised directly by py-cord. + +## Per-Command Handling + +This type of error handling allows you to handle errors per each command you have on your bot. +Each and every command can have it's own error handler made to handle specific errors that each command may raise! + +An example of per-command error handling is as follows: + +:::note Bridge Commands + +For these types of commands, it is recommended to utilize global error handling +until [the feature](https://github.com/Pycord-Development/pycord/issues/1388) is added. +::: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot(owner_id=...) # Your Discord user ID goes in owner_id + + +@bot.slash_command(description="A private command...") +@commands.is_owner() # This decorator will raise commands.NotOwner if the invoking user doesn't have the owner_id +async def secret(ctx: discord.ApplicationContext): + await ctx.respond(f"Hey {ctx.author.name}! This is a secret command!") + + +@secret.error +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.NotOwner): + await ctx.respond("Sorry, only the bot owner can use this command!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If your ID is registered as the owner ID, you'll get the following: + + + +
+ + secret + +
+ Hey Dorukyum! This is a secret command! +
+
+
+ +Any other user whose ID doesn't match the bot owner's will get the following: + + + +
+ + secret + +
+ Sorry, only the bot owner can use this command! +
+
+
+ +This local (per-command) error handler can also be used to handle the same types of errors that standard try-except +statements can handle. This is done by using the same method as above with the `isinstance` built-in function. + +## Per-Cog Handling + +Adding error handlers per-command can be quite the task in terms of work if you have a lot. If you have happened to +group your commands in cogs, then you're in luck! You can create an error handler that is specific to a cog and +handles all errors raised by commands inside that cog. + +Here's an example of a bot with a cog that implements its own error handling: + +```python title="./cogs/dm.py" +# This cog is for DM only commands! Sadly, we only have 1 command here right now... + +import discord +from discord.ext import commands + + +class DM(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.command() + @commands.dm_only() # This decorator will raise commands.PrivateMessageOnly if invoked in a guild context. + async def avatar(self, ctx: commands.Context): + embed = discord.Embed( + title="Avatar", + description=f"Here's your enlarged avatar, {ctx.author.name}!", + color=ctx.author.top_role.color + ) + embed.set_image(url=ctx.author.display_avatar.url) + await ctx.send(embed=embed, reference=ctx.message) + + async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): + if isinstance(error, commands.PrivateMessageOnly): + await ctx.send("Sorry, you can only use this in private messages!", reference=ctx.message) + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +def setup(bot: commands.Bot): + bot.add_cog(DM(bot)) +``` + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +# This is the main file where we load the DM cog and run the bot. + +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix=commands.when_mentioned_or("!")) +bot.load_extension("cogs.dm") +bot.run("TOKEN") +``` + +If you use this command in a DM context, you'll get the following: + + + + !avatar + + +
+ + !avatar + +
+ + Here's your enlarged avatar, BobDotCom! + +
+
+
+ +Otherwise, if used in a guild context: + + + + !avatar + + +
+ + !avatar + +
+ Sorry, you can only use this in private messages! +
+
+
+ +Per-cog error handling comes in very handy as you can relegate all of your error handling to a single function instead +of spreading it out across several per-command error handlers or inside the commands themselves. + +## Global Handling + +If separating your error handling is not how you would like to handle errors, then global error handling is the way to +go. This method of handling allows you to relegate all handling to a single function that resides within your bot +instance. + +A non-subclassed bot would implement this like so: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot() + + +@bot.slash_command(description="Get the bot's current latency!") +@commands.cooldown(1, 30, commands.BucketType.user) +# ^ This decorator allows one usage of the command every 30 seconds and raises commands.CommandOnCooldown if exceeded +async def ping(ctx: discord.ApplicationContext): + await ctx.respond(f"Pong! `{int(bot.latency*1000)} ms`.") + + +@bot.event +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.CommandOnCooldown): + await ctx.respond("This command is currently on cooldown!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If you've subclassed your bot, the `on_application_command_error` event will be placed inside the subclass without a +`bot.event` decorator and `bot.slash_command` will be replaced with `discord.slash_command`. + +The error handling used above will yield this interaction if the command is used again too quickly: + + + +
+ + ping + +
+ Pong! 49 ms. +
+ +
+ + ping + +
+ This command is currently on cooldown! +
+
+
+ +The only issue regarding global error handling is that, if you have a large amount of commands, the global handler may +start to get crammed with a lot of code. This is where all the previously mentioned handlers can take their place! + +## FAQ + +#### Why does the example in per-cog handling have self at the start of its function signatures? + +This is a feature of classes and allows you to reference the cog object as `self` and get access to the bot object +passed at initialization through `self.bot`. + +If this is new to you, we recommend checking out these helpful resources to learn more about classes and cogs: + +- [W3Schools' Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [Our Cogs Guide Page](./cogs) + +#### How many errors can I handle in a single error handler? + +While all the examples in this guide page only handle one specific error and re-raise all others, all of these +error handlers can be extended to catch many errors. + +In [basic handling](#basic) (i.e. try/except statements) you can do one of two things: + +- Explicitly handle the errors you know might get raised and then have a broad `except Exception as exc:` statement + as a catch-all. +- Catch any and all errors via the catch-all statement mentioned above. + +In [per-command](#percommand), [per-cog](#percog), and [global handling](#global), you can use elif clauses with the +built-in isinstance function to catch specific errors. Atop of this, an else clause can be used to catch any other +errors you either don't want to handle or want to relegate to a different error handler. + +#### Can I use more than one type of error handler at once? + +Thankfully, all of these different ways of error handling can be mixed together, so you don't have to pick just one! +For commands that raise specific errors that no other commands will raise, you can use [per-command](#percommand). +For cogs that raise specific errors that no other cogs will raise, use [per-cog](#percog)! Lastly, for errors that +occur frequently across all commands and cogs, use [global handling](#global)! + +However, one important note to remember is that you should always raise the error again in an error handler if it +isn't handled there! If you don't do this, the error will go ignored and your other handlers won't have a chance to +do their work! + +#### What's the difference between slash and prefixed command error handling? + +Although most examples shown here use slash commands, the [per-cog handling](#percog) section presents a prefixed +command. The main difference you may notice is the change in command signature. + +To make the distinguishing features apparent: + +- Slash commands use `on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException)` + as presented in the [per-command](#percommand) and [global handling](#global) examples. +- Prefixed commands use `on_command_error(ctx: commands.Context, error: commands.CommandError)` as presented in the + [per-cog handling](#percog) example. + +This distinction is made as both types of commands need their own system for handling errors that are specific to +themselves. + +:::info Related Topics + +- [Slash Commands](../interactions/application-commands/slash-commands) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Cogs](./cogs) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx new file mode 100644 index 00000000..9f4210af --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx @@ -0,0 +1,62 @@ +--- +title: Intents +description: All about intents in Discord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +## What are Intents? + +Intents allow bot developers to "subscribe" to specific events in Discord. This is useful for bots that need to respond to specific events, such as when a user joins a server or sends a message. You could choose to enable all intents or to enable only specific intents that your bot requires. + +## How do I enable intents? + +:::important + +Remember that [Privileged Intents](#what-are-privileged-intents) require you to enable them in the Discord Developer Portal. Verified Discord Bots that don't already have access to them will need to request Discord to allow access. + +::: + + + + +```python +import discord + +bot = discord.Bot(intents=discord.Intents.all()) +``` + + + + + +You can view a list of intents and the events they subscribe to [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```python title="Enabling Intents" +import discord + +bot = discord.Bot(intents=discord.intents.members(bans=True, guilds=True)) +``` + + + + +## What are Privileged Intents? + +Discord defines some intents as "privileged" because of the sensitive information they contain. Currently, there are three privileged intents: `members`, `presences`, and `message_content`. These intents must be enabled in your bot's Developer Portal. Once your bot reaches 100 servers, you will need to verify your bot for these intents to keep working and for your bot to be able to be invited to more guilds. + +:::tip + +Only enable these intents if you need them. These intents give your bot access to quite sensitive information about the users in your guild. These intents are privileged to respect the privacy of users, and you should do that as well. + +Not enabling these intents doesn't mean you won't be able to ban users, but you will be unable to detect when a new user joins a guild, or what game they are playing. The majority of bots won't need all intents. + +::: + +:::info Related Topics + +- [Sharding Bots](sharding) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx new file mode 100644 index 00000000..c3d17197 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx @@ -0,0 +1,48 @@ +--- +title: Sharding +description: All about Sharding Discord Bots. +--- + +# Sharding + +## What is Sharding? + +Sharding is the process of breaking up your bot into smaller pieces so that it has a better time handling +events. As [Discord's Documentation](https://discord.com/developers/docs/topics/gateway#sharding) puts +it, sharding is "a method of user-controlled guild sharding which allows for splitting events across +several gateway connections." + +Sharding is used only for large bots and takes up additional resources for managing the new processes. +Pycord automatically shards your bot, so the only thing you need to do is use an `AutoShardedClient` +or `AutoShardedBot` class instead of a plain `Client` or `Bot` class. Pretty cool, right? + +Just because you _can_ shard your bot doesn't mean you _should_. While Pycord makes it easy to shard +your bot, it isn't necessary to shard unless your bot is large. Sharding a small bot isn't +just useless, but _harmful_, as it uses extra resources and may slow down your bot. Discord +themselves will let you know when your bot needs sharding, so you won't need to worry about this until they contact you. + +## How Do I Shard in Pycord? + +Sharding in Pycord is straightforward. + +Just replace your `discord.Client`, `discord.Bot`, `commands.Bot` objects +with `discord.AutoShardedClient`, `discord.AutoShardedBot`, `commands.AutoShardedBot` respectively. + +These new objects have been inherited from the original objects, so all the functions from those other types should be present. + +If you want to specify the number of shards your bot uses, +just add the `shards` parameter, along with the number of shards you want. + +## Why Should I Shard my Bot? + +Sharding is very necessary for big bots. While your bot grows, it gets harder for your bot to control +how many guilds it is in and what parts of your code should do what. This is exactly what sharding +handles, it makes all of this easier for your bot. Remember, though, only shard your bot once it's +big enough, and that's at _least_ 1,000 guilds. + +:::info Related Topics + +- [Hosting your Bot](../Getting-Started/hosting-your-bot) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx new file mode 100644 index 00000000..bd2969c1 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx @@ -0,0 +1,115 @@ +--- +title: Subclassing Bots +description: Subclassing is a popular way of creating Discord Bots. Explore how you can create a Discord bot by subclassing. +--- + +## About + +Subclassing is another popular way of creating Discord Bots. Here, you create a bot by extending a bot class. To some advanced users, this is preferable to creating a bot instance with `bot = discord.Bot()`. + +Subclassing is an intermediate python concept, so we recommend you learn about it before continuing. Some good resources are: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +## Why Subclassing? + +Many developers prefer to subclass their bots for many reasons, some of them being: + +#### Skeletal Frameworks for Bots + +Developers often share their bots code on open-source platforms, mostly GitHub, and allow users to self-host the bot (running their own instance of the bot with the code provided by the developer. Permissions vary in accordance to licences). Here, users find it easier and more convenient to have a small file that imports the custom bot class and runs it, rather than having to go through the code of the bot and find out which file to run. This makes it easier for people not familiar with programming to run and customize the bot, since it often brings down the code to: + +```python title="./main.py" +from src import Bot + +bot = Bot() + +bot.run("TOKEN") +``` + +Here, all the commands are inside the `/src` folder that the user need not bother with. + +#### Running Multiple Instances + +Some developers may need to run multiple instances of their bot (perhaps on different bot accounts). For example, a developer might have a second bot for testing alpha features. This system makes it simpler for the developer, and allows them to maintain multiple versions of the bot in the same directory: + +```python title="./alpha_bot.py" +from src import Bot + +class AlphaBot(Bot): # subclasses Bot + ... # insert any custom configuration + +bot = AlphaBot() + +@bot.slash_command() # adds a new slash command to this subclassed bot +async def alpha_feature(ctx): + await ctx.respond("Alpha Feature!") + +bot.run("TOKEN") +``` + +There are many more reasons to subclass! It's not required, and won't affect the speed of the bot, but it may affect your development process, for the good or for the worse. You don't miss out on any features when you subclass, either. Some developers want the OOP feel, while some just prefer that method and find it easier. + +## Basic Example + +```python +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override the on_ready event + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') + +bot = MyBot() + +@bot.slash_command() # create a slash command +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run('token') +``` + +As you can see, instead of creating a bot object with `bot = discord.Bot()`, we subclass [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). We then create an instance of our new bot class and run it. Notice how we don't need to use the `@event` decorator. + +Here's another example: + +```python title="./src/bot.py" +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override on_ready + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') +``` + +```python title="./src/\_\_init\_\_.py" +from .bot import MyBot # import the MyBot class from the bot.py file +``` + +```python title="./main.py" +from src import MyBot # import MyBot from /src + +bot = MyBot() # create an instance of MyBot + +@bot.slash_command() +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run("TOKEN") # run the bot +``` + +These are just two ways you could do it. There are ton of other structures you can implement. It's up to you. + +So, should you subclass? There are no limitations you face if you decide to subclass your bot, but, once again, it's up to you. + +:::info Related Topics + +- [Making a Help Command](../Extensions/Commands/help-command) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx new file mode 100644 index 00000000..23220b0e --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx @@ -0,0 +1,105 @@ +--- +title: Threads +description: Threads with Pycord +--- + +In programming, threads are a way to run multiple processes at the same time. In Discord, threads are +a way to keep multiple conversations going at the same time. Let's take a brief look at how to use threads in Pycord. + +:::tip + +Not all the methods and attributes will be covered in this guide, but you can find them in our documentation! +[Check it out!](https://docs.pycord.dev/en/stable/api/models.html#discord.Thread) + +::: + +## Creating a thread + +With a few simple lines of code, we can create threads in Pycord. + +:::important + +All public threads need a starting message. This message will start the thread. However, private threads +(which are unlocked with having your server boosted to Level 2), do not require a starting message. + +::: + +### Creating thread from a message + +```python title="Creating a Thread from a Message" +message = await ctx.send("My Starting Message") +await message.create_thread(name="thread name", auto_archive_duration=60) +``` + +You may also use other ways to create the thread, for example, by using `on_message` events or by commands. + +### Creating thread in a channel + +```python title="Creating a Thread from a Channel" +channel = bot.get_channel(...) # define this! +await channel.create_thread(name="Thread Name", message=None, auto_archive_duration=60, type=None, reason=None) +``` + +A thread type could be `news_thread`, `public_thread`, `private_thread`. You may use it by passing `type=discord.ChannelType.news_thread`. + +## Deleting Threads + +Deleting Threads is simple. You need to get a thread and then use the `delete` method. + +```python title="Deleting a Thread" +thread = bot.get_channel(thread_id) # you could use other ways to get a thread +await thread.delete() +``` + +## Editing Threads + +**Parameters** + +- `name` (str) – The new name of the thread + +- `archived` (bool) – Whether to archive the thread or not. + +- `locked` (bool) – Whether to lock the thread or not. + +- `invitable` (bool) – Whether non-moderators can add other non-moderators to this thread. Only available for private threads. + +- `auto_archive_duration` (int) – The new duration in minutes before a thread gets automatically archived for inactivity. Must be one of 60, 1440, 4320, or 10080. + +- `slowmode_delay` (int) – Specifies the slow-mode rate limit for users in the thread, in seconds. A value of 0 disables slow-mode. The maximum value possible is 21600. + +```python title="Editing a Thread" +thread = bot.get_channel(id) +await thread.edit( + name="New Name", + archived=True, + locked=True, + slowmode_delay=10, + auto_archive_duration=60, +) +``` + +As you can see, threads are very simple. Once you learn how to use them, it's easy to create whatever you want. + +## FAQ + +### Why am I getting a `Forbidden` error when I try to create a thread? + +A `Forbidden` error occurs when the bot does not have the correct permissions to create threads. + +### Why am I getting an Unknown Message error when I try to create a thread? + +Getting an error looking something like `discord.ext.commands.errors.CommandInvokeError: Command +raised an exception: HTTPException: 400 Bad Request (error code: 10008): Unknown Message`? + +There could be multiple reasons, some of them being: + +- The message does not exist +- The message already has a thread +- The message is in channel x, you are trying to start a thread in channel y. +- The message was deleted. + +:::info Related Topics + +<>{/* I can't think of any related topics for this at the moment. */} + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/voice/_category_.json b/i18n/de/docusaurus-plugin-content-docs/current/voice/_category_.json new file mode 100644 index 00000000..8baf3da8 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/voice/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 6, + "label": "Voice" +} \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/current/voice/index.mdx b/i18n/de/docusaurus-plugin-content-docs/current/voice/index.mdx new file mode 100644 index 00000000..835838c6 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/voice/index.mdx @@ -0,0 +1,24 @@ +--- +title: Voice +--- + +Welcome to the guide for voice features in Pycord. + +:::caution +This guide requires previous experience with Pycord and Python. +::: + +## Requirements + +The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). +The following features are optional: + +:::tip +Opus is also a required library, but this comes with Pycord. +Some hosts may not come with it, though, so remember to always check if required dependencies are installed. +::: + +- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` +- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), + [`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), + [`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/voice/playing.mdx b/i18n/de/docusaurus-plugin-content-docs/current/voice/playing.mdx new file mode 100644 index 00000000..fe14c52a --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/voice/playing.mdx @@ -0,0 +1,149 @@ +--- +title: Wavelink Audio Player +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { + defaultOptions, +} from "@site/src/components/DiscordComponent"; + +# About + +Pycord and Wavelink try to keep the playing of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio playing feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/). + +## Starting out + +First you need to run a [Lavalink Server](https://github.com/freyacodes/Lavalink) to connect with. +There a multiple documentations to do this, so we are not covering that here. + +You also need to install the [wavelink](https://github.com/PythonistaGuild/Wavelink) library. + +```py title="Installing wavelink" +python3 -m pip install wavelink +``` + +You will now want to connect to your server via a node. + +```py title="Connect Node with Lavalink" +import discord +import wavelink + +bot = discord.Bot() + +async def connect_nodes(): + """Connect to our Lavalink nodes.""" + await bot.wait_until_ready() # wait until the bot is ready + + nodes = [ + wavelink.Node( + identifier="Node1", # This identifier must be unique for all the nodes you are going to use + uri="http://0.0.0.0:443", # Protocol (http/s) is required, port must be 443 as it is the one lavalink uses + password="youshallnotpass" + ) + ] + + await wavelink.Pool.connect(nodes=nodes, client=bot) # Connect our nodes +``` + +
+ +Now you are finished making your node! Next, you will want to: + +1. Making a play command +2. Adding connect events + +### Making a play command + +To make a play command, you will need to make a function to connect and play audio in a voice channel. + +```py title="Play Command Example" +import typing + +@bot.slash_command(name="play") +async def play(ctx, search: str): + # First we may define our voice client, + # for this, we are going to use typing.cast() + # function just for the type checker know that + # `ctx.voice_client` is going to be from type + # `wavelink.Player` + vc = typing.cast(wavelink.Player, ctx.voice_client) + + if not vc: # We firstly check if there is a voice client + vc = await ctx.author.voice.channel.connect(cls=wavelink.Player) # If there isn't, we connect it to the channel + + # Now we are going to check if the invoker of the command + # is in the same voice channel than the voice client, when defined. + # If not, we return an error message. + if ctx.author.voice.channel.id != vc.channel.id: + return await ctx.respond("You must be in the same voice channel as the bot.") + + # Now we search for the song. You can optionally + # pass the "source" keyword, of type "wavelink.TrackSource" + song = await wavelink.Playable.search(search) + + if not song: # In case the song is not found + return await ctx.respond("No song found.") # we return an error message + + await vc.play(song) # Else, we play it + await ctx.respond(f"Now playing: `{song.title}`") # and return a success message +``` + + + +
+ + play + +
+ Now playing: Never Gonna Give You Up +
+
+ +
+ +Now that you've done this, the only thing left to do is make your connect events. + +### Adding connect events + +The final step to this guide is connecting the node to your server when the bot goes online. + +To make it, you will want to do the following: + +```py title="Adding connect events" +@bot.event +async def on_ready(): + await connect_nodes() # connect to the server + +@bot.event +async def on_wavelink_node_ready(payload: wavelink.NodeReadyEventPayload): + # Everytime a node is successfully connected, we + # will print a message letting it know. + print(f"Node with ID {payload.session_id} has connected") + print(f"Resumed session: {payload.resumed}") + +bot.run("token") +``` + +Congratulations! You have now implemented voice playing into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/current/voice/receiving.mdx b/i18n/de/docusaurus-plugin-content-docs/current/voice/receiving.mdx new file mode 100644 index 00000000..1bc364e1 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/voice/receiving.mdx @@ -0,0 +1,130 @@ +--- +title: Receiving Voice Samples +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +# About + +Pycord tries to keep the recording of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio recording feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/audio_recording.py). + +## Starting out + +The first thing you want to do is make a cache of your voice connections. This is fairly easy; as +it's just putting a variable with an empty dictionary in our code, such as `connections = {}`. + +You will now want to create your command for recording. + +```py title="Record Command Example" +import discord + +bot = discord.Bot() +connections = {} + +@bot.command() +async def record(ctx): # If you're using commands.Bot, this will also work. + voice = ctx.author.voice + + if not voice: + await ctx.respond("You aren't in a voice channel!") + + vc = await voice.channel.connect() # Connect to the voice channel the author is in. + connections.update({ctx.guild.id: vc}) # Updating the cache with the guild and channel. + + vc.start_recording( + discord.sinks.WaveSink(), # The sink type to use. + once_done, # What to do once done. + ctx.channel # The channel to disconnect from. + ) + await ctx.respond("Started recording!") +``` + + + +
+ + record + +
+ Started recording! +
+
+ +
+ +Now you are finished making your command for voice receiving! Next, you will want to: + +1. Make your finished callback +2. Make a stop command + +### Making a Callback + +To make a callback, you will want to define the currently undefined `once_done` function inside +our command, like so: + +```py title="Recorder Callback" +async def once_done(sink: discord.sinks, channel: discord.TextChannel, *args): # Our voice client already passes these in. + recorded_users = [ # A list of recorded users + f"<@{user_id}>" + for user_id, audio in sink.audio_data.items() + ] + await sink.vc.disconnect() # Disconnect from the voice channel. + files = [discord.File(audio.file, f"{user_id}.{sink.encoding}") for user_id, audio in sink.audio_data.items()] # List down the files. + await channel.send(f"finished recording audio for: {', '.join(recorded_users)}.", files=files) # Send a message with the accumulated files. +``` + + + + finished recording audio for:{" "} + {defaultOptions.profiles.bob.author} + + + +
+ +Now that you've done this, the only thing left to do is make your stop command. + +### Making a Stop Command + +The final step to this guide is stopping the audio recording. This is the easiest step by far. + +To make it, you will want to do the following: + +```py title="Stop Recording Command" +@bot.command() +async def stop_recording(ctx): + if ctx.guild.id in connections: # Check if the guild is in the cache. + vc = connections[ctx.guild.id] + vc.stop_recording() # Stop recording, and call the callback (once_done). + del connections[ctx.guild.id] # Remove the guild from the cache. + await ctx.delete() # And delete. + else: + await ctx.respond("I am currently not recording here.") # Respond with this if we aren't recording. + +bot.run("token") +``` + +Congratulations! You have now implemented voice recording into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/de/docusaurus-plugin-content-pagesindex.tsx b/i18n/de/docusaurus-plugin-content-pagesindex.tsx new file mode 100644 index 00000000..84df3a9c --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-pagesindex.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import DefaultLayout from "../layouts/DefaultLayout"; +import PYCHero from "@site/src/components/PYCHero"; +import PYCButton from "@site/src/components/PYCButton"; + +export default function Home(): JSX.Element { + return ( + + +
+ Imagine a place where you can learn how to create an awesome Discord + bot, equip it with Pycord, and have it running in less than a minute. + Imagine a place where you can learn everything about Pycord. Imagine a + guide. A Pycord Guide! +

+ Whether you are a newbie or an experienced developer, you will find + everything you need to know about Pycord here. This guide will teach + you: +
    +
  • How to get a brand new bot running from scratch;
  • +
  • How to create Interactions, Context Menus and Commands;
  • +
  • In-depth concepts such as Embeds, Reactions, Help Commands, Paginators, etc;
  • +
  • Popular Topics such as working with Databases, Sharding, etc;
  • +
  • Ways to handle and manage common errors and best practices for bots;
  • +
  • And Much More!
  • +
+
+
+ ); +} diff --git a/i18n/de/docusaurus-theme-classic/footer.json b/i18n/de/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..ffb8a652 --- /dev/null +++ b/i18n/de/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Pycord Development, All rights reserved.", + "description": "The footer copyright" + } +} diff --git a/i18n/de/docusaurus-theme-classic/navbar.json b/i18n/de/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..473b847e --- /dev/null +++ b/i18n/de/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "Pycord Guide", + "description": "The title in the navbar" + }, + "item.label.Home": { + "message": "Home", + "description": "Navbar item with label Home" + }, + "item.label.Docs": { + "message": "Docs", + "description": "Navbar item with label Docs" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + }, + "item.label.Source": { + "message": "Source", + "description": "Navbar item with label Source" + } +} diff --git a/i18n/en/code.json b/i18n/en/code.json new file mode 100644 index 00000000..9cce6148 --- /dev/null +++ b/i18n/en/code.json @@ -0,0 +1,404 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { + "message": "Toggle the collapsible sidebar category '{label}'", + "description": "The ARIA label to toggle the collapsible sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search here", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.algoliaLabel": { + "message": "Search by Algolia", + "description": "The ARIA label for Algolia mention" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorite", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "You might want to check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Algolia" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Try searching for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Believe this query should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/i18n/en/docusaurus-plugin-content-blog/options.json b/i18n/en/docusaurus-plugin-content-blog/options.json new file mode 100644 index 00000000..9239ff70 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/en/docusaurus-plugin-content-docs/current.json b/i18n/en/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..36b4849a --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,46 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.defaultSidebar.category.Getting Started": { + "message": "Getting Started", + "description": "The label for category Getting Started in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Interactions": { + "message": "Interactions", + "description": "The label for category Interactions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Application Commands": { + "message": "Application Commands", + "description": "The label for category Application Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.UI Components": { + "message": "UI Components", + "description": "The label for category UI Components in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Extensions": { + "message": "Extensions", + "description": "The label for category Extensions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Commands": { + "message": "Commands", + "description": "The label for category Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Pages": { + "message": "Pages", + "description": "The label for category Pages in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Voice": { + "message": "Voice", + "description": "The label for category Voice in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Popular Topics": { + "message": "Popular Topics", + "description": "The label for category Popular Topics in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.More": { + "message": "More", + "description": "The label for category More in sidebar defaultSidebar" + } +} diff --git a/i18n/en/docusaurus-theme-classic/footer.json b/i18n/en/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..ffb8a652 --- /dev/null +++ b/i18n/en/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Pycord Development, All rights reserved.", + "description": "The footer copyright" + } +} diff --git a/i18n/en/docusaurus-theme-classic/navbar.json b/i18n/en/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..473b847e --- /dev/null +++ b/i18n/en/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "Pycord Guide", + "description": "The title in the navbar" + }, + "item.label.Home": { + "message": "Home", + "description": "Navbar item with label Home" + }, + "item.label.Docs": { + "message": "Docs", + "description": "Navbar item with label Docs" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + }, + "item.label.Source": { + "message": "Source", + "description": "Navbar item with label Source" + } +} diff --git a/i18n/es/code.json b/i18n/es/code.json new file mode 100644 index 00000000..9cce6148 --- /dev/null +++ b/i18n/es/code.json @@ -0,0 +1,404 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { + "message": "Toggle the collapsible sidebar category '{label}'", + "description": "The ARIA label to toggle the collapsible sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search here", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.algoliaLabel": { + "message": "Search by Algolia", + "description": "The ARIA label for Algolia mention" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorite", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "You might want to check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Algolia" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Try searching for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Believe this query should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/i18n/es/docusaurus-plugin-content-blog/options.json b/i18n/es/docusaurus-plugin-content-blog/options.json new file mode 100644 index 00000000..9239ff70 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/es/docusaurus-plugin-content-docs/current.json b/i18n/es/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..36b4849a --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,46 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.defaultSidebar.category.Getting Started": { + "message": "Getting Started", + "description": "The label for category Getting Started in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Interactions": { + "message": "Interactions", + "description": "The label for category Interactions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Application Commands": { + "message": "Application Commands", + "description": "The label for category Application Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.UI Components": { + "message": "UI Components", + "description": "The label for category UI Components in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Extensions": { + "message": "Extensions", + "description": "The label for category Extensions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Commands": { + "message": "Commands", + "description": "The label for category Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Pages": { + "message": "Pages", + "description": "The label for category Pages in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Voice": { + "message": "Voice", + "description": "The label for category Voice in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Popular Topics": { + "message": "Popular Topics", + "description": "The label for category Popular Topics in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.More": { + "message": "More", + "description": "The label for category More in sidebar defaultSidebar" + } +} diff --git a/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png b/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png new file mode 100644 index 00000000..7480e1da Binary files /dev/null and b/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png differ diff --git a/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg b/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg new file mode 100644 index 00000000..ce6b5110 Binary files /dev/null and b/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg differ diff --git a/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png b/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png new file mode 100644 index 00000000..846eee15 Binary files /dev/null and b/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png differ diff --git a/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png b/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png new file mode 100644 index 00000000..32a47d04 Binary files /dev/null and b/i18n/es/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png differ diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/extensions/_category_.json new file mode 100644 index 00000000..309b494a --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 5, + "label": "Extensions", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json new file mode 100644 index 00000000..652aa4ee --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Bridge" +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx b/i18n/es/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx new file mode 100644 index 00000000..81545fa2 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx @@ -0,0 +1,190 @@ +--- +title: Bridge +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +## Concept + +Let's say that you want to make a command that is both a Slash Command and a Prefixed Command. Now, you could just copy and paste the code from the first command callback to the other and make some adjustments, but that's not very efficient. + +This is where the `ext.bridge` module comes in. It allows you to use one callback to make both a Slash Command and a Prefixed Command. + +### Example Usage + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def hello(ctx): + await ctx.respond("Hello!") + +bot.run("TOKEN") +``` + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+
+ +## Syntax + +First, instead of using `discord.Bot` or `commands.Bot`, we use `bridge.Bot`. `bridge.Bot` does inherit from `commands.Bot`, so you can do anything with `bridge.Bot` that `commands.Bot` can do. +Then, we define a command with `@bot.bridge_command()`. This makes a Bridge Command, which has both a Prefixed Command counterpart and a Slash Command counterpart. +Next, the callback has access to a `ctx` object, which is the context of the command. This context is either of `BridgeApplicationContext` type or `BridgeExtContext`. Because of that, it makes detecting how the function was called easier. + +### Using Bridge Commands in a Cog + +Like Slash Commands and Prefixed Commands, you can use Bridge Commands in a Cog. You can do this by using the `bridge_command` decorator. Here's an example: + +```python +import discord +from discord.ext import bridge, commands + +class Greetings(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @bridge.bridge_command() + async def hello(self, ctx): + await ctx.respond("Hello!") + + @bridge.bridge_command() + async def bye(self, ctx): + await ctx.respond("Bye!") + +def setup(bot): + bot.add_cog(Greetings(bot)) +``` + +The cog will automatically split the Bridge Command into their Slash Command and Prefixed Command counterparts. + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+ + +
+ + bye + +
+ Bye! +
+ + + !bye + + + +
+ + !bye + +
+ Bye! +
+
+ +### Deferring + +You can defer if you want to communicate to the user that your bot is busy processing the command. This is done by using `ctx.defer()`. For the Slash Command implementation, `ctx.defer()` calls the function that gives out a "Bot is thinking" message. For the Prefixed Command implementation, `ctx.defer()` enables the typing indicator. + + + +### Options + +Options are pretty straightforward. You just specify them like you do with prefixed commands, and you're all set! + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def sum(ctx, a: int, b: int): + await ctx.respond(a + b) + +bot.run("TOKEN") +``` + + + +
+ + sum + +
+ 4 +
+ + + !sum 2 2 + + + +
+ + !sum 2 2 + +
+ 4 +
+
diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json new file mode 100644 index 00000000..63f8e08e --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx b/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx new file mode 100644 index 00000000..bf345c07 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx @@ -0,0 +1,56 @@ +--- +title: Command Groups +--- + +Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk +remove`. + +## Syntax + +Creating a command group is very simple. + +```python title="Command Groups Example" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!') + +@bot.group() +async def afk(): + pass + +@afk.command() +async def set(): + ... + +@afk.command() +async def remove(): + ... + +# Another command group + +@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. +async def math(ctx): + await ctx.send('Subcommand not found') + +@math.command() +async def add(ctx, a: int, b: int): + ... + +@math.command() +async def subtract(ctx, a: int, b: int): + ... +``` + +To create a command group, the command's decorator must be `@bot.group`. Once you have a command with +that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand +groups! + + + +:::info Related Topics + +- [Prefixed Commands](./prefixed-commands.mdx) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx b/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx new file mode 100644 index 00000000..acbdc0a8 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx @@ -0,0 +1,481 @@ +--- +title: Help Command +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Pycord's `commands` extension comes with a built-in help command. In this guide, we will take a look at them as well as learn how to create your own. Let's dive in! + +:::note + +This guide demonstrates using object-oriented programming and subclassing to make a help command for your +Pycord bot. It is important to understand these two concepts before continuing. + +**Learning Resources**: + +- [W3Schools - Python Subclassing](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools - Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +::: + +## The Wrong Way + +A popular way to create a help command is to disable the built-in help command and create your own. This is not recommended as it will lead to a lot of confusion. + +```python title="The Wrong Way" +bot = commands.Bot(command_prefix='!', help_command=None) +# OR +bot.help_command = None +# OR +bot.remove_command("help") + +@bot.command() +async def help(ctx, *, argument=None): + ... +``` + +While it's possible to create a help command this way, doing so does not utilize the full capabilities +of making one with Pycord. Making a help command with subclassing and OOP will save time and effort. + +## Types of Help Commands + +There are two types of built-in help commands: + +- [`DefaultHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand) +- [`MinimalHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand) + +`DefaultHelpCommand` is the command enabled by default. It isn't the best looking, but `MinimalHelpCommand` can help make it look a bit better. + + + + +```python title="Default Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.DefaultHelpCommand()) # help_command is DefaultHelpCommand by default so it isn't necessary to enable it like this +# We enable it here for the sake of understanding + +... + +bot.run("token") +``` + + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ + +```python title="Minimal Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.MinimalHelpCommand()) + +... + +bot.run("token") +``` + + + + !help + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+ +
+ +
+ +## Updating Built-in Help Commands + +Let's try to make the `MinimalHelpCommand` look better. We can do this by putting its content in an +embed. + +```python title="Minimal Help Command Example" +bot = commands.Bot(command_prefix='!') + + +class MyNewHelp(commands.MinimalHelpCommand): + async def send_pages(self): + destination = self.get_destination() + for page in self.paginator.pages: + emby = discord.Embed(description=page) + await destination.send(embed=emby) + +bot.help_command = MyNewHelp() +``` + +Let's go through the code. + +First, we create a new class called `MyNewHelp`. This class is a subclass of `MinimalHelpCommand`. + +Next, we override the `send_pages` method. This method is responsible for sending the help command to +the user. We override this method because we don't want to change the content of the pages, just how +they are sent. + +We use the `get_destination` method to get the destination of the message. This is the channel or use that the help +command is to be sent to. + +We use the `paginator.pages` property to get the different pages of the help command. We put the page +in an embed, and then send the embed to the destination channel. + +Finally, we set this as our new help command using `bot.help_command = MyNewHelp()`. + + + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a + category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+
+ +## Creating Your Help Command + +Not satisfied with the built-in help commands? You can create your own! + +For this, we will subclass the `HelpCommand` class. + +There are 4 methods that we need to override: + +- `HelpCommand.send_bot_help(mapping)` that gets called with `help` +- `HelpCommand.send_command_help(command)` that gets called with `help ` +- `HelpCommand.send_group_help(group)` that gets called with `help ` +- `HelpCommand.send_cog_help(cog)` that gets called with `help ` + +### Bot Help + +```python title="Bot Help Example" +class MyHelp(commands.HelpCommand): + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help") + for cog, commands in mapping.items(): + command_signatures = [self.get_command_signature(c) for c in commands] + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's go through the code. + +- First, we create a new class called `MyHelp`. This class is a subclass of `HelpCommand`. + +- Next, we override the `send_bot_help` method. This method is responsible for sending the main help + command to the user. + +- We create an embed with the title "Help". + +- We iterate through `mapping.items()`, which returns a list of tuples, the first element being the + cog and the second element being a list of commands. + +- By using `self.get_command_signature(c)` we get the signature of the command, also known as the + `parameters` or `arguments`. + +- There is a chance that the cog is empty, so we use `if command_signatures:`. + +- We get the name of the cog using `getattr(cog, "qualified_name", "No Category")`. This calls the + cog's attribute `qualified_name` which returns "No Category" if the cog has no name. + +- We add a field to the embed with the name of the cog and the value of the command signatures. + +- Finally, we send the embed to the channel. + +Let's improve the code a little. + +```python title="Improved Bot Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + command_signatures = [self.get_command_signature(c) for c in filtered] + + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Now the help command won't show commands that the user can't use, as well as aliases for commands. +Let's get the help command to show command aliases. + +### Command Help + +This function is called when the user uses `help `. + +```python title="Command Help Example" +class MyHelp(commands.HelpCommand): + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command), color=discord.Color.random()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's quickly go through the code we haven't discussed yet. + +- In line 3, we create an embed with a title the signature of the command (so that the title of the + embed looks like ` [parameter]`), and a random color. + +- In lines 4 and 5, we get the command's `help` description and add it to the embed. The help description + of a command can be specified in the docstrings of a command function. For example: + + ```` + ```python + @bot.command() + async def ping(ctx): + """Returns the latency of the bot.""" + await ctx.send(f"Pong! {round(bot.latency * 1000)}ms") + ``` + ```` + +- Line 6 is shorthand for + + ```python + alias = command.aliases + if alias: + ... + + # is the same as + + if alias := command.aliases: + ... + ``` + + A very helpful (but not well-known) Python shorthand! + +- In line 7, we get the aliases of the command and add them to the embed. + +### Cog Help + +This is pretty easy! + +```python title="Custom Cog Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_cog_help(self, cog): + embed = discord.Embed(title=cog.qualified_name or "No Category", description=cog.description, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(cog.get_commands()): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Once again, we create an embed, get the commands that the user can use, and add them to the embed. + +### Group Help + +Similar to the cog help, this is pretty easy! + +```python title = "Custom Group Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_group_help(self, group): + embed = discord.Embed(title=self.get_command_signature(group), description=group.help, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(group.commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Add all of these methods together, and you have a fully functioning help command! + +
+Click to see the final code for this section +
+ +:::note + +The following code has been slightly edited from the tutorial version. + +::: + +```python title="Custom Help Command Example" +class SupremeHelpCommand(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + if command_signatures := [ + self.get_command_signature(c) for c in filtered + ]: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command) , color=discord.Color.blurple()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_help_embed(self, title, description, commands): # a helper function to add commands to an embed + embed = discord.Embed(title=title, description=description or "No help found...") + + if filtered_commands := await self.filter_commands(commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No help found...") + + await self.get_destination().send(embed=embed) + + async def send_group_help(self, group): + title = self.get_command_signature(group) + await self.send_help_embed(title, group.help, group.commands) + + async def send_cog_help(self, cog): + title = cog.qualified_name or "No" + await self.send_help_embed(f'{title} Category', cog.description, cog.get_commands()) + +bot.help_command = SupremeHelpCommand() +``` + +
+
+ +## Command Attributes + +How can you add cooldowns, set aliases, and change the name of help commands? Command attributes can +help you do all of that, and more! + +```python title="Help Command Attributes" +attributes = { + 'name': "help", + 'aliases': ["helpme"], + 'cooldown': commands.CooldownMapping.from_cooldown(3, 5, commands.BucketType.user), +} + +# You need to use CooldownMapping.from_cooldown(rate, per, type) + +bot.help_command = MyHelp(command_attrs=attributes) +``` + +## Error Handling + +When a user attempts to use a command that does not exist, we need to inform the user. +We can do this by overriding the `send_error_message` function. + +```python title="Custom Help Error Example" +class MyHelp(commands.HelpCommand): + async def send_error_message(self, error): + embed = discord.Embed(title="Error", description=error, color=discord.Color.red()) + channel = self.get_destination() + + await channel.send(embed=embed) +``` + + + + !help update_pycord + + + + Command 'update_pycord' not found. + + + + +## Credits + +Most of the content from this guide is from +[InterStella0's walkthrough guide on subclassing HelpCommand](https://gist.github.com/InterStella0/b78488fb28cadf279dfd3164b9f0cf96). +Thanks to InterStella0 for making this guide amazing. + +:::info Related Topics + +- [Subclassing Bots](../../Popular-Topics/subclassing-bots) +- [Prefixed Commands](./prefixed-commands) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx b/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx new file mode 100644 index 00000000..b8f567fd --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx @@ -0,0 +1,324 @@ +--- +title: Prefixed Commands +description: Learn how to use the commands extension for Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Before Discord added slash commands, all bots had prefixed commands. A user would type the bot's prefix +followed by a word or phrase to invoke a command, such as `?help` or `!help`. +However, this prefixed commands system isn't native to Discord! Developers made use of an `on_message` +event to check if the message began with a certain character, then invoke the command. Every time a +message was sent, the bot would see the message and check for its "prefix" + +The syntax becomes a little more complicated when you want to have multiple commands. There are several +disadvantages to this system. This is where the commands extension comes in. `ext.commands` has +various advantages, such as: + +- Simpler syntax +- Easier to use +- Easier to parse user input +- Comes with built-in help commands +- Comes with a built-in system for categorizing commands + + + + +```python title="Prefixed Commands with Events" +import discord + +client = discord.Client() + +@client.event +async def on_message(message): + if message.content.startswith("!ping"): + await message.channel.send("Pong!") + + elif message.content.startswith("!announce"): + if len(message.content.split(" ")) < 3: + await message.channel.send("You need to specify a title and a message. Correct usage: `!announce Hello Hello everyone!`") + return + + msg = message.content.split(" ", 2) + title = msg[1] + content = msg[2] + + await message.channel.send("**{}**\n{}".format(title, content)) + + elif message.content.startswith("!"): + await message.channel.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !help + + + Unknown Command. + +
+ +
+ + +```python title="The Commands Extension" +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix="!", intents=intents) + +@bot.command() +async def ping(ctx): + await ctx.send("Pong!") + +@bot.command() +async def announce(ctx, title, *, message): + await ctx.send("**{}**\n{}".format(title, message)) + +@bot.event +async def on_command_error(ctx, error): + if isinstance(error, commands.CommandNotFound): + await ctx.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !pycord + + + Unknown command. + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+ !announce +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The commands extension has many more uses. This example only showcases the basic features mentioned +in the previous example. Other things you can do with the commands extension include using a different +built-in help command and creating your own. The following tutorials showcase these. + +::: + +
+
+ +## Syntax + +Before we check out the syntax, let's take a look at the bot classes. + +> `discord.Client` - Contains only events. +> +> `discord.Bot` - Subclasses `discord.Client`, adds commands. +> +> `discord.ext.commands.Bot` - Subclasses `discord.Bot`, adds prefixed commands, cogs, and more. + +This means that `discord.ext.commands.Bot` has both slash commands and prefixed commands, as well as +events, cogs and more. + +Now let's look at the syntax. + +```python title="A Simple Prefixed Bot" +import discord +from discord.ext import commands # Import the commands extension +# discord.ext.commands are not the same as discord.commands! + +intents = discord.Intents.default() #Defining intents +intents.message_content = True # Adding the message_content intent so that the bot can read user messages + +bot = commands.Bot(command_prefix="!", intents=intents) # You can change the command prefix to whatever you want. + +@bot.command() # This is the decorator we use to create a prefixed command. +async def ping(ctx): # This is the function we will use to create the command. + await ctx.send("Pong!") # This is the response the bot will send. + + +bot.run("token") # Run the bot with your token. +``` + + + + !ping + + + Pong! + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The help command is a built-in command and is enabled by default. You will learn more about it in the +following guides. + +::: + +## Parameters + +Prefixed commands can take parameters, just like slash commands. You can specify the parameters in +the function itself. + +```python title="Parameters Example 1" +@bot.command() +async def echo(ctx, *, message): + await ctx.send(message) +``` + +`ctx` is the context of the message. `*` means that the parameter can be any number of words. `message` +is the parameter. If you had not passed `*`, `message` would only have been one word. + +For example, if a user had used `!echo hello world`, `message` would have been `hello`. Since we +passed `*`, `message` is `hello world`, or the rest of the message. + +We can pass multiple parameters too! + +```python title="Parameters Example 2" +@bot.command() +async def echo(ctx, channel:discord.TextChannel, title, *, message): + await channel.send("**{}**\n{}".format(title, message)) +``` + +In the example above, `channel` is a parameter that is of type `discord.TextChannel`. When you +specify the type of the parameter, Pycord will automatically try to convert the parameter to that type. +That is why you can use `channel.send` directly without needing to convert it first. + +We also have a new parameter, `title`. This does not have a type, so it will be a string. `*` means +that the rest of the message belongs to the next parameter, in this case, `message`. + +When a user types `!echo #general Greetings! Hello World!`, `channel` will be the text channel +`#general`, `title` will be `Greetings!` and `message` will be `Hello World!`. + +Let's take an example where the user passes `!echo #general Holiday Greetings! Greetings to you all!`. +Here, the user wants the title to be "Holiday Greetings!" and the message to be "Greetings to you all!". +However, since Pycord parses the message at whitespaces, the title will end up being "Holiday" and the +message "Greetings! Greetings to you all!". The user can prevent this by typing `!echo "Holiday +Greetings!" Greetings to you all!`. + + + + + + !echo #general Holiday Greetings! Greetings to you all! + + + Holiday +
+ Greetings! Greetings to you all! +
+ + !echo #general "Holiday Greetings!" Greetings to you all! + + + Holiday Greetings! +
+ Greetings to you all! +
+
+ +Let's check out another example for parameters and parameter types. + +```python title="Parameters Example 3" +import random + +@bot.command() +async def gtn(ctx, guess:int): + number = random.randint(1, 10) + if guess == number: + await ctx.send("You guessed it!") + else: + await ctx.send("Nope! Better luck next time :)") +``` + +If you had not specified the type of the parameter, it would have been a string. And since `"5"` is not +the same as `5` in python, the bot would have responded with "Nope! Better luck next time :)". +Even if you do not specify the type of the parameter, you can still convert it later on, in this case, +with `int(guess)`. + +:::info Related Topics + +- [Command Groups](groups) +- [Rules and Common Practices](../../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json new file mode 100644 index 00000000..baeba701 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Pages", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx b/i18n/es/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx new file mode 100644 index 00000000..be90b035 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx @@ -0,0 +1,168 @@ +--- +title: Paginator Basics +--- + +# Paginator Basics + +## [Page](https://docs.pycord.dev/en/stable/ext/pages/index.html#page) + +This class contains two attributes: `content` and `embeds`, which correspond to the attributes of the same name on the +`discord.Message` class. +To create a new Page, use the following syntax: + +```py +import discord +page = Page(content="My Page Content", embeds=[discord.Embed(title="My First Embed Title")]) +``` + +## [PageGroup](https://docs.pycord.dev/en/stable/ext/pages/index.html#pagegroup) + +This class represents a group of pages. It uses most of the same parameters as `Paginator`, which allows each +`PageGroup` to effectively have its own settings and behaviours. + +## [Paginator](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator) + +This is the main class for `ext.pages`, and is used to control most of the functionality of the extension. + +In its most basic form, with no arguments provided (default values listed below), a paginator can be created like so: + +```py title="Paginator Example" +import discord +from discord.ext.pages import Paginator, Page + +my_pages = [ + Page( + content="This is my first page. It has a list of embeds and message content.", + embeds=[ + discord.Embed(title="My First Embed Title"), + discord.Embed(title="My Second Embed Title"), + ], + ), + Page( + content="This is my second page. It only has message content.", + ), + Page( + embeds=[ + discord.Embed( + title="This is my third page.", + description="It has no message content, and one embed.", + ) + ], + ), +] +paginator = Paginator(pages=my_pages) +``` + +The only required parameter for `Paginator` is the `pages` parameter, which is usually a list of `Page` objects. + +You can also pass in a list of `PageGroup` objects, a list of strings, a list of embeds, or a list of lists of embeds. + +Once the `Paginator` instance is created, you can call either +[`Paginator.send()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.send) +or [`Paginator.respond()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.respond) +to send a message or response with the paginator's contents. + +#### Depending on what's being passed to the `pages` parameter, the behaviour of the paginator may differ: + +- Passing a list of `PageGroup` objects will essentially treat each `PageGroup` as its own Paginator, with most + `Paginator` attributes able to be set independently for each `PageGroup`. + \- Each `PageGroup` accepts its own `pages` parameter, which inherits the same behaviour as the `pages` parameter + of `Paginator`, except it cannot contain other `PageGroup` objects. +- If a page is a `Page` object, this will allow you to specify both the `discord.Message.content` and + `discord.Message.embeds` attributes for a page. + \- **This is the preferred method of defining a page.** +- If a page is a string, this will be used for the `discord.Message.content` attribute. This type of page cannot have + any embeds. +- If a page is a list of embeds, this will be used for the `discord.Message.embeds` attribute. This type of page + cannot have any message content. +- If a page is a list of lists of embeds, each parent list item will create a page containing all embeds from its + child list. This type of page cannot have any message content. + +#### Parameters for the `Paginator` class which have default values: + +- `show_disabled` **:** `True` + - Show buttons that are disabled (i.e. can't be clicked) +- `author_check` **:** `True` + - Only the author can interact with the paginator. +- `timeout` **:** `180` _(seconds)_ + - The paginator will time out and become inactive after this many seconds. +- `disable_on_timeout` **:** `True` + - If the paginator times out, it will be automatically disabled and all buttons will be unusable. +- `use_default_buttons` **:** `True` + - Use the default set of 4 buttons and a page indicator. +- `show_indicator` **:** `True` + - When using the default buttons, shows a middle 5th button with the current/total page numbers. + +**For other parameters that can be set on initialization, please check the +[API Reference](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator)** + +## [PaginatorButton](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatorbutton) + +This class represents a button used to navigate between the pages of a paginator. It's also used to create the page +indicator. + +When creating your own custom buttons, you can either use this class directly or subclass it to add any additional +functionality you may need. + +To add custom buttons to the paginator instead of the default navigation buttons, you have two options to do so: + +1. **Using the `custom_buttons` parameter of `Paginator`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + buttons = [ + PaginatorButton("first", label="<<-", style=discord.ButtonStyle.green), + PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), + PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True), + PaginatorButton("next", label="->", style=discord.ButtonStyle.green), + PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), + ] + paginator = Paginator( + pages=["Page 1", "Page 2", "Page 3"], + show_indicator=True, + use_default_buttons=False, + custom_buttons=buttons, + ) + ``` +2. **Using `Paginator.add_button()`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"], use_default_buttons=False) + paginator.add_button(PaginatorButton("prev", label="<", style=discord.ButtonStyle.green)) + paginator.add_button(PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True)) + paginator.add_button(PaginatorButton("next", label=">", style=discord.ButtonStyle.green)) + ``` + +If you want to use the default navigation buttons, but not all of them, you can also use `Paginator.remove_button()` to +selectively remove them: + +```py +from discord.ext.pages import Paginator + +paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"]) +paginator.remove_button("first") +paginator.remove_button("last") +``` + +## [PaginatorMenu](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatormenu) + +This class represents the `discord.Select` menu used to navigate between `PageGroup` instances. In most situations, you +will not need to interact with this class directly. + +If you do subclass it, you'll likely want to call `super()` in your `__init__` method to ensure that the `PageGroup` +navigation functionality is retained. + +## Usage Examples + +For a comprehensive list of examples showing all `Paginator` functionality, please see the +[example in cog form](https://github.com/Pycord-Development/pycord/blob/master/examples/views/paginator.py) in the repo. + +## Support and Feedback + +If you have any questions, suggestions, or feedback for `ext.pages`, please join the +[Discord server](https://discord.gg/pycord). diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx b/i18n/es/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx new file mode 100644 index 00000000..b8d68925 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx @@ -0,0 +1,20 @@ +--- +title: Paginator FAQ +--- + +# Paginator FAQ + +- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** + - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. + - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. + +- **How can the bot send a paginator to a different destination than where it was invoked?** + - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. + - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. + - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. + +- **How can I change the paginator's behavior without re-creating and re-sending it?** + - Use the `Paginator.update()` method. + +- **How can I make the bot actually do something with the contents of a page?** + - Use the (upcoming) `Paginator.page_action()` method. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json new file mode 100644 index 00000000..36dfb009 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Tasks" +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx b/i18n/es/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx new file mode 100644 index 00000000..848f6066 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx @@ -0,0 +1,216 @@ +--- +title: Tasks +--- + +## Concept + +So you want to run a background task running at some specified interval? Thankfully, that's a common thing to do, whether you're working with some API or handling some background logic don't worry, the Pycord tasks extension is here to make life easier for you! + +With the tasks extension, you can make background tasks without worrying about the asyncio hell and mind bogglers like "what if my internet dies" and "how do I handle reconnecting" with the added benefit of a lot of useful additions that are one line of code away! + +### Example Usage + +```py +import discord +from discord.ext import tasks + +bot = discord.Bot() + +@bot.event +async def on_ready(): + very_useful_task.start() + +@tasks.loop(seconds=5) +async def very_useful_task(): + print('doing very useful stuff.') + +bot.run("TOKEN") +``` + +If you do run this code in your terminal you should see something like this after about 15 seconds: + +``` +doing very useful stuff. +doing very useful stuff. +doing very useful stuff. +``` + +For a more useful example here's a task in a cog context ripped straight from the [docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#recipes): + +```py +from discord.ext import tasks, commands + +class MyCog(commands.Cog): + def __init__(self): + self.index = 0 + self.printer.start() + + def cog_unload(self): + self.printer.cancel() + + @tasks.loop(seconds=5) + async def printer(self): + print(self.index) + self.index += 1 +``` + +As you'd expect this will increment a number and print it out every 5 seconds like so: + +```sh +0 +# 5 seconds later +1 +# 5 more seconds later +2 +# ... +``` + +## [Tasks](https://docs.pycord.dev/en/stable/ext/tasks/index.html) + +Now let's get into the nitty-gritty of tasks. + +As you've seen tasks can work in both outer scope and class contexts and the handle is roughly the same, you define a task using the `tasks.loop` decorator and use the `start` method to start it, the difference is you add the `self` argument when in a class context so since most people have all their bot's code in Cogs all the following code blocks will be in a Cog context to make it easy to copy it then apply whatever modifications you might need! + +### [Creating a task](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop) + +A look at `discord.ext.tasks.loop`'s definition in the documentation reveals that: + +1. As you've seen before it expects the time between each execution, that however doesn't have to be in seconds as + there are `seconds`, `minutes` and `hours` parameters to make it easier for us, they can also be floats in case you want + ultra-precision. +2. You can also pass in a `datetime.time` object or a sequence of them in the `time` parameter which will make it run + at the specified time(s). +3. You can pass in how many times a loop runs before it stops by passing in the `count` parameter, you can use `None` + to make it run forever which is also the default. +4. The loop function **_must_** be a coroutine. + +These are all really useful, and they aren't the only parameters so if you want to know more about them check out the +[docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop)! + +### Attributes + +A task has the following attributes: + +- `current_loop`: The current loop the task is on. +- `hours`, `minutes`, `seconds`: attributes that represent the time between each execution. +- `time`: A list of datetime.time objects that represent the times the task will run, returns `None` if no datetime + objects were passed. +- `next_iteration`: A `datetime.datetime` object that represents the next time the next iteration of the task will + run, can return `None` if the task stopped running. + +These attributes serve as a really powerful asset to get info about your loop. + +### Example + +Now let's create a cog that handles a leaderboard we have in our bot using Tasks then explain what we did after that and +also provide a refresher of how slash commands groups work in cogs. + +For the sake of this example let's pretend that we have a leaderboard module that does all the leaderboard handling for +us and that computing the leaderboard is very expensive computationally wise, so we want to store one version of it that +gets regularly updated instead of generating it every time someone calls the `/leaderboard view` command. + +```py +from discord.ext import tasks, commands +from discord.commands import SlashCommandGroup, CommandPermissions + +from leaderboard import * # Mock leaderboard module. + +class LeaderboardCog(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.update_leaderboard.start() + self.leaderboard_embed = generate_leaderboard_embed() + + leaderboard = SlashCommandGroup(name='leaderboard', description='Leaderboard commands.') + + @tasks.loop(minutes=10) + async def update_leaderboard(self): + print('Updating leaderboard...') + await update_leaderboard() + self.leaderboard_embed = generate_leaderboard_embed() + + @update_leaderboard.before_loop + async def before_update_leaderboard(self): + await self.bot.wait_until_ready() + print("About to start updating leaderboard.") + + @update_leaderboard.after_loop + async def after_update_leaderboard(self): + leaderboard_cleanup() + print("Stopped updating leaderboard.") + + @update_leaderboard.error + async def update_leaderboard_error(self, error): + print(f"Oh no, an error occurred while updating the leaderboard. Error: {error}") + + @leaderboard.command() + async def view(self, ctx): + await ctx.respond(embed=self.leaderboard_embed) + + @leaderboard.command() + async def update_info(self, ctx): + await ctx.respond(f"""***Leaderboard Info***\n + Last update: {(600 - self.update_leaderboard.next_iteration.timestamp())//60} minutes ago.\n + Next update: in {self.update_leaderboard.next_iteration.timestamp() // 60} minutes.\n + Time between loops: {self.update_leaderboard.minutes} minutes.\n + Times updated this session: {self.update_leaderboard.current_loop}. + Running? {self.update_leaderboard.is_running()} + Failed? {self.update_leaderboard.failed()}""", ephemeral=True) + + # Now for the owner only commands: + + leaderboard_config = SlashCommandGroup(name="leaderboard_config", description="Leaderboard configuration commands", permission=[CommandPermissions("owner", 2, True)]) + + @leaderboard_config.command() + async def set_time_between_updates(self, ctx, minutes: int): + self.update_leaderboard.change_interval(minutes=minutes) + await ctx.respond(f"Set time between updates to {minutes} minutes.") + + @leaderboard_config.command() + async def stop(self, ctx): + self.update_leaderboard.stop() + await ctx.respond("Stopped the leaderboard update.") + + @leaderboard_config.command() + async def restart(self, ctx): + self.update_leaderboard.restart() + await ctx.respond("Restarted the leaderboard update.") + +def setup(bot): + bot.add_cog(LeaderboardCog(bot)) +``` + +Phew, that was quite a bit of code. + +Now to explain what's going on: + +First things first we create a cog and in its `__init__` function we start the `update_leaderboard` task and generate +the first instance of our leaderboard's embed. + +After that, we define the `update_leaderboard` task using the `loop` decorator, and we make it run every ten minutes by +passing 10 to the `minutes` parameter. + +Then that we define the `before_update_leaderboard` task using the `before_loop` decorator, and we make it wait until the +bot is ready before starting the task. + +Next up we define the `after_update_leaderboard` task using the `after_loop` decorator, and we make it clean up the +leaderboard when the loop finally stops running. + +Then we define the `update_leaderboard_error` task using the `error` decorator, and we make it print any errors that may +occur while we update our leaderboard to the console. + +Then we get into the fun stuff, we create a slash command group using the `SlashCommandGroup` class and name it +`leaderboard`, we then create the `view` sub-command which sends the embed generated when the leaderboard is updated and +`update_info` which shows a lot of data about the task using some attributes and functions available to us. + +We also create a slash command group called `leaderboard_config` which is only available to the owner of the bot. + +Then we create the `set_time_between_updates` sub-command which takes in the time in minutes and changes the time +between updates of the leaderboard using the `change_interval` method, the `stop` sub-command which stops the task using +the `stop` method and `restart` which restarts the task using the `restart` method. + +Finally, we add the `LeaderboardCog` cog to the bot, and we're done! + +I'd highly recommend you check the tasks extension +[documentation](https://docs.pycord.dev/en/stable/ext/tasks/index.html) for more info on how to use them and what other +functions they have. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/getting-started/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/getting-started/_category_.json new file mode 100644 index 00000000..9d6255f5 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 3, + "label": "Getting Started", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx b/i18n/es/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx new file mode 100644 index 00000000..864206a6 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx @@ -0,0 +1,262 @@ +--- +title: Creating Your First Bot +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +Excited to create your first bot? Once you [install Pycord](../installation.mdx), you can start right +away! + +## Creating the Bot Application + +Just like how you need to sign up to use Discord, your bot also has to be signed up. To do this, +you should: + +1. Go to the [Discord Developer Portal](https://discord.com/developers/applications) and click + on . +2. Give your bot a name, and click . +3. Now, you should see a page like this. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdW3OQnwUhacopqSWw%2F-Mjd_-mxrJCrzmaXrAg8%2Fimage.png?alt=media&token=b8e2ae6c-2290-4d37-ad7c-eb412f3fb00e) +4. Click on the tab on the left side of the screen. +5. Click on . +6. You can give it a name, change the Avatar, etc. + +## Inviting the bot + +Now, lets get the bot added to some servers. Go to the tab +in the left pane and select `bot` and `applications.commands` as scopes. + +You may want your bot to have application commands, which is what the `application.commands` scope +allows your bot to make. + +Next, you want to choose what permissions the bot will have and select them. For now, you can just +give your bot the `administrator` permission, which gives your bot every permission. Once you select +your bot's permissions, click on to get the bot invite link. + +:::tip + +When your bot is all ready to go, make sure that administrator permissions aren't selected unless +your bot truly needs them. Try selecting only permissions the bot will need. For testing, +Administrator permissions are fine. + +::: + +![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-Mk6tNY3LfDkjd6pqdpL%2F-Mk6tkdpddEWoa2jczZk%2Fimage.png?alt=media&token=52c8a29f-a798-48f8-a8c7-4ecca2681f79) + +You can use this link to invite the bot. + +## Tokens + +Now that you have an account for your bot, you need to log in. To log in, we need the bot's +password. All users and bots have a "token." You may think of this token as a password, as this allows +us to log our bot into Discord. + +Tokens are "snowflakes." Not actual snowflakes, though. Just like how no two snowflakes in real life have the same +pattern, snowflakes in computers are unique things - no two bots have the same token - so a token is +considered a snowflake. A Discord user ID is also a snowflake. + +Now, lets get your bot's token. To do this, you want to: + +1. Go back to the tab. +2. Click on the button in the "Token" section. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdbU12JISJorAZxrKH%2F-MjdbpUsapzb5n15Po5P%2Fimage.png?alt=media&token=118e259f-940a-4f6c-b3a3-c29f3a54100d) + +Now, you have your bot's token copied to your clipboard. + +:::danger + +Do not, under any circumstances, give your token to anyone. Even if you are contacted by someone +claiming to be Discord staff, do not give them your bot's token. They are lying to you to try and +gain access to your bot. If an unauthorized user gains access to your bot's token, they can access +your bot and use it in malicious ways. + +Never push your token to GitHub or include it in your code. One way to prevent your token from +getting leaked is to store it in `.env` files. + +::: + +### Protecting Tokens + +#### Using dotenv + +You can store your tokens in `.env` files. This is a simple way to store sensitive information. + +1. Create a file with the name `.env` (only the extension, with a dot/period at the start and without a name before it). +2. Define the token in the `.env` file (replace the example value with your token). + ```env title=".env" + TOKEN = NzkyNzE1NDU0MTk2MDg4ODQy.X-hvzA.Ovy4MCQywSkoMRRclStW4xAYK7I + ``` +3. Install [`python-dotenv`](https://pypi.org/project/python-dotenv/). + ```bash + python -m pip install python-dotenv + ``` +4. Load the token from the `.env` file. + ```python + import dotenv + dotenv.load_dotenv() + token = str(os.getenv("TOKEN")) + ``` +5. Pass your token as parameter when running the bot. + ```python + client.run(token) + ``` + +:::tip + +If you are using Git to track your bot's changes, you should create a file called `.gitignore` and add +`.env` to it. This stops your `.env` file from getting tracked along with the rest of your code, and +will not be pushed to a remote Git repository. As a consequence, it will stay secure on your local machine. + +::: + +## Coding the Basics + +Here's an example of code you'll write with Pycord: + +```py +import discord +import os # default module +from dotenv import load_dotenv + +load_dotenv() # load all the variables from the env file +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") + +bot.run(os.getenv('TOKEN')) # run the bot with the token +``` + + + +
+ + hello + +
+ Hey! +
+
+
+ +Let's go through the code. First, the imports. + +```py +import discord +import os +from dotenv import load_dotenv +``` + +In the first line, `import discord`, we import Pycord. Although you install Pycord with `pip install py-cord`, you +import it with `import discord`. This is so it's as easy as possible when switching from Discord.py to Pycord. + +We then import `os` and `dotenv`. `os` is a default module that we will use to get the token from the env file. `dotenv` +is a module that we will use to load the env file. You installed this with `pip install python-dotenv`. + +Next, we load the env file with `load_dotenv()`. + +```py +bot = discord.Bot() +``` + +In this line, we create a new instance of [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). +In this object, we can pass various parameters for configuration purposes, such as `owner_ids` +and [`intents`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```py +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") +``` + +We use the [`event`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) decorator to override +the [`on_ready`](https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready) function to define an +event that is automatically called when the bot is ready to use. + +```py +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") +``` + +Here, we use the [`slash_command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.slash_command) +decorator to define a slash command. We specify the `name` and `description` arguments. If not +specified, the name of the slash command would be the function name and the command description would +be empty. + +Optional: We type-hint the context parameter (`ctx`) as [`discord.ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext). In modern IDEs, type-hinting allows access to autocompletion and docstrings. You can read more about type-hinting [here](https://docs.python.org/3/library/typing.html). + +Finally, you want to run the bot using the token specified in the `.env` file. + +Now you have finished creating your first Pycord bot! What we have shown you is just the basic structure +of a bot. You can do a lot more with Python and Pycord knowledge, as well as your imagination! Pycord +will not limit your bot's abilities. + +:::note + +The part where we load the token from the environmental variables is not required. You may use another way to keep your token secure, or, although not recommended, simply specify the token normally as a string, as shown below. + +
+A Basic Bot without securing the token +
+ +```py +import discord + +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.send("Hey!") + +bot.run("TOKEN") +``` + +
+
+ +::: + +## FAQ + +### How do I make prefixed commands? + +Prefixed commands are an older method of creating bot commands that listen for messages and replies +if the message starts with a certain character. You can read [this page](../extensions/commands/prefixed-commands.mdx) +to learn more about prefixed commands. + +### How do I setup modules/cogs? + +[Cogs](../popular-topics/cogs) are a great way to organize your commands by putting them into +groups called cogs. Cogs are separate files that your bot loads to get the commands inside. +You can read more about cogs, as well as learn how to use them and their benefits, +[here](../popular-topics/cogs). + +### How do I add components, such as buttons and dropdown menus, to my bot? + +Pycord makes it very easy to use Message Commands with your bot by using the `discord.ui` module. +To learn more, read about Message Commands in our [interactions directory](../interactions). + +:::info Related Topics + +- [Prefixed Commands](../extensions/commands/prefixed-commands) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx b/i18n/es/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx new file mode 100644 index 00000000..2a68677b --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx @@ -0,0 +1,109 @@ +--- +title: Hosting Your Pycord Bot +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Hosting Your Pycord Bot + +If you're completely new to this, you might have thought something along the lines of "Yay! I got my +bot working," after following our [Creating your First Bot](creating-your-first-bot) guide, only +to close your IDE or shut down your computer to find your bot offline. + +The reason for this is that programs have to be hosted somewhere, meaning some machine somewhere has +to constantly run your bot. There are tons of hosting services that can help you host your bot for +little to no cost. + +## Can I get a Clear Explanation? + +Sure thing. When you run your bot, it first makes a connection to Discord's API. Once that's done, +Pycord sends "heartbeats" to Discord. "heartbeats" are small packets sent at a set interval telling +Discord that your bot is indeed still alive. If Discord doesn't receive a heartbeat after a certain +amount of time, your bot is pronounced dead and buried in the graveyard (not really). It is, though, +taken offline and its connection with Discord is terminated. + +Once you close the terminal that you've run your program on, the program is no longer running, and +the bot stops sending heartbeats and can no longer process commands. This is why you have to constantly +keep the process running. + +This goes for all programs, in a different nature. If the code isn't compiled/built/assembled/interpreted, +it can't be running. + +## What is a Host? + +A host is a server or container for running code offered by a **hosting provider.** There are a lot +of hosting providers, such as bigger ones like Amazon Web Services (AWS) and Google Cloud, and smaller +ones like GalaxyGate and DigitalOcean. + +There are three types of hosts. + + + + Shared hosting is a type of hosting where multiple people share one VPS. Getting a spot on + a shared host is usually cheap, sometimes even free. Shared hosts do not give you a lot of + resources, from less than a gigabyte of RAM (usually 512MB on free hosts) and half of a CPU + with very little storage. Shared hosting is usually used for website hosting and is not + recommended for hosting a Discord bot. + + + A virtual private server (VPS) is a virtual computer (virtual machine) that is rented out to + customers. Most people use a VPS for hosting their projects such as Discord bots. You can get + anywhere from less than a gigabyte of RAM and a less powerful CPU to just under one hundred + gigabytes of RAM, a (or multiple) powerful CPU(s), and a fair amount of storage. A VPS is the + best choice for most users and can be fairly cheap. + + + A dedicated host is a physical computer. You can buy these yourself or rent one from a hosting + provider. Dedicated hosts are often very expensive, but are also very powerful, having a + few hundred gigabytes of RAM and a few very powerful CPUs, along with a good amount of storage. + Dedicated hosts are usually used for very large projects and are overkill for something like + a Discord bot. + + +
+ +:::danger + +Make sure you choose a hosting provider you trust. Also make +sure the hosting provider you're looking at has good reviews on public forums. Googling along the +lines of "[host] review" should do the trick. A provider you don't trust can compromise your token. + +::: + +Most hosting providers rent their services to you for a monthly or yearly fee. These can be anywhere +from a few dollars to hundreds or thousands of dollars. + +## How to Host Your Bot + +Once you rent or buy a VPS, you can get to work. Most hosting providers allow you to choose from a +wide range of operating systems, most allow you to choose one but some allow you to choose +multiple. Once that's ready, you have to SSH into the system. We won't get into SSH here, but you can +read [this article from DigitalOcean](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys). +You can also use VNC, which is remote desktop software. If you are using an OS that does not have a +GUI, and is only a command line (a "server" OS), such as Ubuntu Server or most Linux Server Operating Servers, you will most +likely use SSH. If you are using an OS that has a GUI, such as Windows Server, you will most likely use VNC. + +Once you've decided on your operating system, you'll want to set it up and install Python. Once that's +done, you can copy your bot's files to your remote system, install the required packages, and run +the bot. + +:::warning + +If you are using SSH to run the file, your bot will not stay running. This is because the file is +only told to run during your session. You can use a command like [nohup](https://en.wikipedia.org/wiki/Nohup) +to make sure your file stays running after you disconnect. + +::: + +Now your bot is hosted, but that doesn't mean it can't go offline. If your bot encounters an error, +it can often go offline or stop its process. For this, make sure you have proper error handling. +Also be sure to pay attention to your hosting provider's updates or news, as they usually notify +users of when they plan on doing maintenance to their servers, making their services unavailable for +a short time. + +:::info Related Topics + +- [Creating Your First Bot](creating-your-first-bot) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx b/i18n/es/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx new file mode 100644 index 00000000..ee6b9417 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx @@ -0,0 +1,379 @@ +--- +title: More Features +description: More features to make your bot cool and snazzy. +--- + +import { + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, + DiscordEmbedField, + DiscordEmbedFields, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +So, you just created your first Pycord bot! Now, let's add some more features to it. This will include adding event handlers, waiting for user response, styling the messages, and more. + +## Events + +### Event Handlers + +Events in Discord are a way to listen for certain actions. For example, if you want to know when a user joins your server, so you could send a welcome message, you can use the `on_member_join` event. + +First, you need to ask Discord to send you events. This is done via "Intents". Read up the [Intents](../Popular-Topics/intents) page for more information. + +Once you understand what intents are, you can enable the events you need, or just use the default ones with `discord.Intents.all()`. + +Now that that's done, let's add an event handler for when a user joins the server. We will use the [`on_member_join` event](https://docs.pycord.dev/en/stable/api/events.html#discord.on_member_join). We will send a private message to the user welcoming them to the server. + +```python +@bot.event +async def on_member_join(member): + await member.send( + f'Welcome to the server, {member.mention}! Enjoy your stay here.' + ) +``` + +We use the [`discord.Bot.event` decorator](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) to add the event handler. + +The `on_member_join` event is called when a user joins the server. The `member` parameter is the user that joined. Different events have different names and parameters. You can find all of them [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +So, that's how you add event handlers! + +### Waiting for User Response + +Let's say you want to create a Guess-the-Number game (where the user has to guess a number between 1-10). You need to send a message to a user and wait for them to respond. You can do this with the [`wait_for`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.wait_for) method. + +```python +@bot.command() +async def gtn(ctx): + """A Slash Command to play a Guess-the-Number game.""" + + await ctx.respond('Guess a number between 1 and 10.') + guess = await bot.wait_for('message', check=lambda message: message.author == ctx.author) + + if int(guess.content) == 5: + await ctx.send('You guessed it!') + else: + await ctx.send('Nope, try again.') +``` + +`wait_for` takes one argument, which is the event type. The event type is the name of the event you want to wait for. In this case, it's `message`. It could also be `reaction` to wait for a reaction to be added. + +We pass a keyword argument to `wait_for` called `check`. The function may look complicated if you're a beginner. We pass a `lambda` function, which simplifies the code a bit. + +The lambda function takes one parameter, `message`. When Pycord receives a message, it passes it to the `check` function. If the function returns `True`, the message is returned. If the function returns `False`, the message is ignored and the bot waits for another message. + +Here, we check if the message is from the user that sent the command. We simply use `message.author == ctx.author`. This will check if the author of the message was the person who invoked the command. + +## Styling Messages + +### Embeds + +Embeds are a Discord feature that allows applications to format their messages in cool embedded format, +enabling your bot to lay out messages with a lot of text into neat fields. + + + + + The Pycord Guide is a detailed guide that explains how to use Pycord and all of its features. + + + The Getting Started section explains how you can get a brand new bot created and running from scratch. + + + Interactions with Pycord + + + Pycord's various Extensions + + + Other Popular Topics + + + We have so much more! Just explore, and you will find everything you need. If you want another page added, open an issue on the GitHub. + + + Created with 💖 by the Pycord Team & Contributors + + + + +
+ +Creating embeds is simple! Just create an instance of [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) and edit it to your liking. Once you're done, send it! + +```python +import discord + +bot = discord.Bot() + +@bot.command() +async def hello(ctx): + embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from + ) + embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") + + embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) + embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) + embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) + + embed.set_footer(text="Footer! No markdown here.") # footers can have icons too + embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") + embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") + embed.set_image(url="https://example.com/link-to-my-banner.png") + + await ctx.respond("Hello! Here's a cool embed.", embed=embed) # Send the embed with some text + +bot.run("TOKEN") +``` + + + +
+ hello +
+ Hello! Here's a cool embed. + + Embeds are super easy, barely an inconvenience. + + + A really nice field with some information. The description as well as the fields support markdown! + + Inline Field 1 + Inline Field 2 + Inline Field 3 + + Footer! No markdown here. + +
+
+ +
+ +This simple command sends replies to a [slash command](../interactions/application-commands/slash-commands) with an embed. +Let's break it down: + +```py +embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), + ) +``` + +This command creates an embed. We use the [`Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) +class to create an embed object with the title "My Amazing Embed", the description "Embeds are super easy, barely an inconvenience.", and the color `blurple`, Discord's main theme color. + +[discord.Colour](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Colour) is a class full of [classmethods](https://docs.python.org/3/library/functions.html#classmethod) +that return color values. While the official, documented name of this is `discord.Colour`, `discord.Color` +works as well. + +```py +embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") +embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) +embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) +embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) +``` + +This small section shows off embed fields. You can add fields to embeds with the [`add_field` method](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.add_field) +of the [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) class. These consist of three +keyword arguments: `title`, `value`, and `inline`. `title` and `value` are both required arguments, which inline defaults to `False` if it's not defined. The `inline` argument specifies whether space will be divided among the inline fields. There could be a mix of fields where inline has different values too. + +```py +embed.set_footer(text="Footer! No markdown here.") # footers can have icons too +embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") +embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") +embed.set_image(url="https://example.com/link-to-my-banner.png") +``` + +In this section, we're adding unique items to the embed. These items are: + +- Footer - With the [`set_footer()`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_footer) + method, you can set a small footer that holds a message. This has `text` and `icon_url` kwargs. +- Author - With the [`set_author`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_author) + method, you can set an author for the embed. This is a small text field at the top of the embed. This + includes `name`, `url` and `icon_url` kwargs. +- Thumbnail - With the [`set_thumbnail`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_thumbnail) + method, you can set a small image to reside at the top-right of the embed. This has a single `url` kwarg. +- Image - With the [`set_image`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_image) + method, you can set an image to sit at the bottom of an embed. This has a single `url` kwarg. + +There are a lot more methods and attributes you can use to configure embeds. Here, we just covered the basics. Also, remember that all of these values are not necessary in an embed. An embed may only contain a few of these. For example, only a description, a title and a description, and so on. + +### Markdown + +Markdown is a type of markup language that's limited in terms of formatting yet simple. Discord allows +for a watered-down version of markdown to be in their messages. + +#### Text Markdown + +Text formatting can be used in messages and in most embed parts, +as explained in the dedicated section below. + + + + + + + + + + + + + + + + + + + + +
*italics*__*underlined italics*__
**bold**__**underlined bold**__
***bold italics***__***underlined bold italics***__
__underlined__~~strikethrough~~
+ +#### Code Markdown + +To create a single-line code block without syntax highlight, wrap the text between single backticks. +This code block will only add a dark background to the text. + +``` +`print("Hello world!")` +``` + +To create a multi-line code block without syntax highlight, wrap the text between triple backticks +on first and last line. This type of code block will encase the code inside a box. + +```` +``` +message = "Hello world!" +print(message) +``` +```` + +To create a multi-line block with syntax highlight, add the name of the language you are using right after +the triple backticks on the first line. For example, for Python you can write either "python" or "py". + +```` +```python +message = "Hello world!" +print(message) +``` +```` + +If you want to use syntax highlight for a single line of code, you still have to format it +like a multi-line block but the code must be on a separate line than the triple backticks. + +#### Quote Markdown + +To create a single-line quote block, start the line with `>` followed by a space. + +``` +> This is a single-line quote. +``` + +To create a multi-line quote block, write `>>>` followed by a space. All text +from that point onwards will be included in that quote block. + +``` +>>> This is a +multi-line quote. +``` + +#### Spoiler Markdown + +To hide a spoiler, encase the text between double pipes. The users +will have to click on it before being able to see the text contained in it. + +``` +||spoiler|| +``` + +#### Link Markdown + +Link formatting only works in embeds and messages sent through webhooks, +by using the following syntax: + +``` +[Pycord](https://pycord.dev/) +``` + +Inside the supported elements that have just been mentioned, +the example above will look like this: [`Pycord`](https://pycord.dev/) + +Outside them, the link will still be clickable but the formatting will be ignored, +therefore the example above will look similarly to this: `[Pycord](https://pycord.dev/)` + +#### Embed Markdown + +Adding markdown to your embeds or messages will give your bot the sparkle it needs, +however, markdown is limited inside embeds. Use the following table as a reference +and keep in mind that embed title and filed names will always show in **bold**. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PartTextLink
Embed AuthorNoNo
Embed TitleYesNo
Embed DescriptionYesYes
Field NameYesNo
Field ValueYesYes
Embed FooterNoNo
diff --git a/i18n/es/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx b/i18n/es/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx new file mode 100644 index 00000000..e44b7c49 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx @@ -0,0 +1,184 @@ +--- +title: Rules and Common Practices +description: All about the rules and common practices for coding a Discord bot +--- + +# Rules and Common Practices of Creating a Bot + +When creating almost anything, there's always a certain set of rules to follow or common practices, +such as [PEP8](https://www.python.org/dev/peps/pep-0008/) for Python. This applies to creating bots +with Pycord as well. + +:::note + +Most of these rules and common practices are only applicable for +[verified bots](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting), +but it's good to follow them nonetheless. + +::: + +## Rules + +There are rules for creating bots, and most of these are required by Discord themselves, not us at +Pycord. Not following these rules may get your bot denied for verification. + +### Terms of Service and Privacy Policy + +Starting at some point in time, Discord has made providing a privacy policy with your bot a requirement. +This is so that Discord knows exactly what you are doing with its users' data. + +:::tip +You don't need a lawyer or anyone special to write out a privacy policy for you, nor do you need +it approved by some official entity. Simply writing out how you are going to use Discord user +information neatly is all you need to do. +::: + +Providing a Terms of Service for your bot is optional, though usually a best practice. It tells users +what they can and cannot do with your service, and makes it easier to settle disputes if someone +disagrees with you. + +Read more in Discord's official [Legal Docs](https://discord.com/developers/docs/legal). + +### Developer Policy + +We could list almost every rule about using Discord's API here. _Or_ we could simply link Discord's +Developer Policy to make it easier on us. You can find Discord's Developer Policy +[here](https://discord.com/developers/docs/policy). This outlines what you can and cannot do with +Discord's Developer API. And, don't worry, it's completely readable and understandable. + +## Best Practices + +Now, here's something we _can't_ simply link an article for. We're going to discuss the best practices +of creating a Discord bot with Pycord. + +### Bot Sharding + +To any new or maybe even experienced bot developer, sharding a bot sounds beneficial once you hear +about it. I'm here to tell you that it isn't a good idea to shard your bot. + +_Wait a minute, why would it be an option if it wasn't a good idea?_ It's simple. I lied. Sort of. +I'm not going to go into the details of sharding a bot, so you can read about it on +[this page](../Popular-Topics/sharding). Sharding is the process of taking your bot +and breaking it up into small pieces, so it's easier to perform tasks. This is very useful for large +bots, as it makes them faster and more reliable. Sharding is not a good practice for small bots. + +:::note +Discord will notify you once it is time to shard your bot, and will eventually force you to do so. +::: + +At the very least, wait for one thousand servers to shard your bot. If you shard your bot while it's +small, you'll just be wasting resources and possibly making your bot slower. + +### [Verification](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting) + +Verifying your Discord bot is something every developer would like to achieve. It shows that your bot +is in more than 75 servers. It's generally a good idea to try to get your bot verified as soon as +possible. We're talking at 76 servers soon. This is because Discord can be somewhat slow in terms of +bot verification, so verifying as soon as possible gives them enough time to verify before your bot +reaches the 100 server cap. If a bot is not verified, it cannot grow beyond 100 servers. + +It's also a good idea to only apply for the privileged intents that you need. Applying for intents +your bot doesn't use wastes both your time and Discord's time, as your privileged intent request +will be denied simply because you applied for an intent you didn't need. + +### Subclassing + +While it may take some time, subclassing a bot is very worth it. Once again, this was explained +elsewhere, so I won't go into the details, but I felt it fit here, so I put it here. + +Subclassing a bot makes it more flexible and allows it to do a lot more. Read more about subclassing +bots [here](../Popular-Topics/subclassing-bots) + +### Your Bot's Token + +Your bot is only able to be run for one reason: its token. If you followed the +[guide for creating your first bot](creating-your-first-bot), you should already know a bit about +keeping that token safe. That's exactly what you want to do. + +Sharing your token is never good. If someone evil gets a hold of your token, they can do terrible things, +such as making your bot leave all of its servers, spamming all the members the bot has contact with, +and even manipulating the servers the bot is in, if given the permissions. That's why it's very important +to keep your token safe. To learn how to do so, read [this part](creating-your-first-bot#tokens) of +the Creating Your First Bot guide. + +### Backups + +You always want to back up your bot's data. This includes both its code _and_ its databases. This way, +if something tragic happens, such as your host failing a data migration or you breaking your Raspberry +Pi's SD card that held your bot, you'll still have its precious user data. I have a small program for +my bot that uploads its databases to a remote GitHub repository periodically to not lose any data. +It may be smarter to find a bit more of a reliable way to do so, though. + +Public or private, having a local Git repository connected to a remote one is a good idea for making +almost any application. For a lot of developers, it's like saving your work. If you do this, all of +your bot's code won't be lost if your computer spontaneously combusts, or you smash it to bits from +anger. You can simply grab the backup computer that everyone has lying around, and you're back +in business. + +### Organization and Cleanliness + +It is _extremely_ important to have organized code. This includes commands, objects, functions, +and classes. If you don't have organized code, it will get progressively harder for you to recognize +it, and others won't be able to decipher it. + +Make sure you utilize indents and spaces, as these are very important in making your code readable. + +```py title="Bad Spacing" +class MyClass: + async def add(self,num1,num2): + return num1+num2 + async def sub(self,num1,num2): + return num1-num2 +``` + +```py title="Good Spacing" +class MyClass: + async def add(self, num1, num2): + return num1 + num2 + + async def sub(self, num1, num2): + return num1 - num2 +``` + +See the difference? Now, which one looks more readable? Hopefully, you answered the second example. +Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is a PEP (**Python Enhancement Proposal**) +style guide for Python. It is the style guide that is used by most Python developers and programmers, +providing a universal way to write and read code. + +### Databases + +As your bot grows, you'll inevitably have to store data for your bot. Now, most people would probably just load up some +JSON file on boot into a `dict`, modify it in memory then write to the file. However, JSON files aren't the solution. +When you write to a JSON file, it rewrites the entire file instead of just rewriting the section that changed. It's also +a configuration file format, not a storage file format. + +Instead of using a JSON file or some other related format, you should instead use a database. There are many databases +out there, like MongoDB, SQLite, and PostgreSQL to name a few. + +All of these databases I named do the job well, and which one you use depends on what features you want out of a database. + +<>{/* Maybe clarify these/add more options */} + +#### MongoDB + +MongoDB is a JSON-like format and if you already use JSON files, it shouldn't be too hard to migrate over to. + +#### SQLite + +SQLite is based on SQL, a common relational data model. It's a lightweight, easy-to-use, portable database solution that +works entirely on files. However, if for some reason you cannot read/write to and from a file, and you need to manage +lots of data, SQLite might not be for you. + +While SQLite is a part of the Python Standard Library as the `sqlite3` package, we recommend not using it as it is +synchronous and blocking. You should use an asynchronous alternative, such as [`aiosqlite`](https://pypi.org/project/aiosqlite/). + +#### PostgreSQL + +PostgreSQL is also based on SQL, but it also has more features than SQLite. It's compliant with the SQL standard, +open-source, and extensible. However, it's not that fast or simple compared to SQLite. + +#### MariaDB + +MariaDB is also based on SQL and is a fork of the MySQL project. It's compliant with the SQL standard, it's also open +source and is a complete drop-in replacement for any code with MySQL. You don't even need to change what package you're +using! diff --git a/i18n/es/docusaurus-plugin-content-docs/current/installation.mdx b/i18n/es/docusaurus-plugin-content-docs/current/installation.mdx new file mode 100644 index 00000000..521c69cd --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/installation.mdx @@ -0,0 +1,80 @@ +--- +title: Installation +sidebar_position: 2 +--- + +Before you can start using Pycord, you need to install the library. + +:::note +Python **3.8 or above** is required to use Pycord. +::: + +:::tip +Before you start installing python packages globally, it's recommended you set up a virtual environment. +You can find instructions for that [here](More/virtual-environments). +::: + +## Fresh Installation + +To install Pycord, you can use the following command in your terminal: + +``` +pip install py-cord +``` + +:::tip +Remember that you need to install `py-cord`, not `pycord`. +Also, the `pip` command varies depending on your installation. For example, it might be `python3 -m pip` on macOS/Linux or `py3 -m pip` on some versions of Windows. +::: + +If you need voice support for your bot, you should run: + +``` +pip install "py-cord[voice]" +``` + +## Migration + +### Updating Pycord + +If you are upgrading from a previous version of Pycord, you can use the following command in your terminal to upgrade to the latest version: + +``` +pip install -U py-cord +``` + +### Migrating from other libraries + +If you are migrating from another library, say, `discord.py`, first of all, you need to uninstall it. + +``` +pip uninstall discord.py +``` + +Then, you can install Pycord, it's as simple as that!: + +``` +pip install py-cord +``` + +:::caution +Uninstalling `discord.py` _after_ installing `py-cord` can cause issues. Make sure to uninstall it first! +::: + +## Installing Other Builds + +### Development Build + +:::caution +The development build comes with cutting edge features and new functionality, but as it isn't a stable build you may encounter bugs. +::: + +To install the development build, you can use the following command in your terminal: + +``` +pip install -U git+https://github.com/Pycord-Development/pycord +``` + +:::important +Git is required to install this build. [Learn how you can install Git](./more/git). +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/interactions/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/interactions/_category_.json new file mode 100644 index 00000000..ea28be60 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/interactions/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 4, + "label": "Interactions" +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json new file mode 100644 index 00000000..6dcafe83 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Application Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx b/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx new file mode 100644 index 00000000..b4ffeade --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx @@ -0,0 +1,85 @@ +--- +title: Context Menus +description: Learn all about Context Menus (User Commands & Message Commands) and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +When you right-click a message, you may see an option called "Apps". Hover over it, and you can see +commands a bot can run with that message. These are called message commands. + +When you right-click a user in the user list, you can once again see an option called "Apps". +Hover over it, and you can see commands a bot can run with that message. These are called user commands. + +Together, these two are called Context Menus or Context Menu Commands. These commands work very much like normal commands, except they take a member or message. + +:::note + +A bot can have up to 5 global Context Menus of each type. + +::: + +## User Commands + +Creating a user command is very simple. + +```python +@bot.user_command(name="Account Creation Date", guild_ids=[...]) # create a user command for the supplied guilds +async def account_creation_date(ctx, member: discord.Member): # user commands return the member + await ctx.respond(f"{member.name}'s account was created on {member.created_at}") +``` + + + +
+ + Account Creation Date + +
+ {defaultOptions.profiles.bob.author}'s account was created on 2020-01-01 +
+
+ +## Message Commands + +```python +@bot.message_command(name="Get Message ID") # creates a global message command. use guild_ids=[] to create guild-specific commands. +async def get_message_id(ctx, message: discord.Message): # message commands return the message + await ctx.respond(f"Message ID: `{message.id}`") +``` + + + + Do. Or do not. There is no try. + + +
+ + Get Message ID + +
+ Message ID: 930650407917748286 +
+
+ +
+ +:::info Related Topics + +- [Slash Commands](./slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx b/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx new file mode 100644 index 00000000..edac55b3 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx @@ -0,0 +1,56 @@ +--- +title: Localizations +description: Localizations are a way to make your bot more accessible to your users. Learn all about localizations now! +--- + +Localizations are a way to make your bot more accessible to your users. You can localize the command +name, the names of any arguments, and any text that is displayed to the user. + +## Syntax + +```python +@bot.slash_command( + name="ping", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + }, + options=[ + Option( + name="Example", + name_localizations={ + "en-GB": "British Example" + }, + description="Example option that does nothing", + description_localizations={ + "en-GB": "British example option that does nothing" + } + ) + ] +) +async def ping(ctx, example): + responses = {"en-US": "Pong!", + "en-GB": "British Pong!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +@bot.slash_command( + name="ping2", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + } +) +async def ping2(ctx, example: Option(str, "example", name_localizations={"en-GB": "British Example"}, description="Example option that does nothing", description_localizations={"en-GB": "British example option that does nothing"})): + responses = {"en-US": "Pong2!", + "en-GB": "British Pong2!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +``` + +- [`Locales`](https://discord.com/developers/docs/reference#locales) - List of valid locales recognized by Discord diff --git a/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx b/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx new file mode 100644 index 00000000..ed454dad --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx @@ -0,0 +1,292 @@ +--- +title: Slash Commands +description: Learn all about Slash Commands and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On March 24, 2021, Discord added Slash Commands to Discord as an easier, more efficient, and better way of using bot commands. Pycord has implemented Slash Commands into the library, so it's simple, efficient, and familiar. + +:::important + +Remember that Slash Commands require your bot to be invited with the `application.commands` scope or Slash Commands will not show up. Bots already in the guild can simply be invited again with the scope; there is no need to kick the bot. + +::: + +## Syntax + +Let's create a simple Slash Command. + +```py +import discord + +bot = discord.Bot() + +# we need to limit the guilds for testing purposes +# so other users wouldn't see the command that we're testing + +@bot.command(description="Sends the bot's latency.") # this decorator makes a slash command +async def ping(ctx): # a slash command will be created with the name "ping" + await ctx.respond(f"Pong! Latency is {bot.latency}") + +bot.run("TOKEN") +``` + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +Let's go through the code. + +First, we import Pycord's `discord` package. + +Next, we create a [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot) object and assign it to a variable `bot`. + +We then go ahead and use the [`@bot.command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.command) decorator, which registers a new Slash Command. We pass a `description` parameter to give a description to the Slash Command. We can also pass a `name` parameter to change the Slash Command's name. By default, the name of the Slash Command will be the name of the function, in this case, `/ping`. + +We create an async function called `ping` with parameters `ctx`, which, when called, sends the bot's ping/latency using [`ctx.respond`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext.respond). + +## Subcommand Groups + +You might want to group certain commands together to make them more organised. A command group is exactly what it sounds like, a group of individual Slash Commands together. + +In order to make a Slash Command group, you can use the `bot.create_group` function. + +```python +import discord + +bot = discord.Bot() + +# create Slash Command group with bot.create_group +greetings = bot.create_group("greetings", "Greet people") + +@greetings.command() +async def hello(ctx): + await ctx.respond(f"Hello, {ctx.author}!") + +@greetings.command() +async def bye(ctx): + await ctx.respond(f"Bye, {ctx.author}!") + +bot.run("TOKEN") +``` + +Or, you can instead manually make a `SlashCommandGroup` class like so: + +```python +import discord + +math = discord.SlashCommandGroup("math", "Math related commands") + +@math.command() +async def add(ctx, num1: int, num2: int): + sum = num1 + num2 + await ctx.respond(f"{num1} plus {num2} is {sum}.") + +@math.command() +async def subtract(ctx, num1: int, num2: int): + sum = num1 - num2 + await ctx.respond(f"{num1} minus {num2} is {sum}.") + +# you'll have to manually add the manually created Slash Command group +bot.add_application_command(math) +``` + +Here's what the registered subcommands will look like in the Slash Command Menu: + +![Picture of the subcommands in the Slash Command Menu](../../assets/interactions/groups-and-subcommands.jpg) + +You'll notice that there's the name of the Slash Command Group and then the name of the subcommand separated by a space. + +::: + +:::info Cogs + +If you are looking to add Slash Command Groups to cogs, please look at our [Cogs page](../../popular-topics/cogs)! + +::: + +## Sub-groups + +We've made a subcommand group, but did you know that you could create a group inside another? + +```python +from discord import SlashCommandGroup +from math import sqrt + +math = SlashCommandGroup("math", "Math related commands") +advanced = math.create_subgroup("advanced", "Advanced math commands") + +@advanced.command() +async def square_root(ctx, x: int): + await ctx.respond(sqrt(x)) + +bot.add_application_command(math) +``` + +The command created above can be invoked by typing `/math advanced square_root`. + +## Options & Option Types + +Whenever you're using Slash Commands, you might notice that you can specify parameters that the user has to set or can optionally set. These are called Options. + +Options can also include a description to provide more information. [You can learn more about Options in our documentation!](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.Option) + +Since you want different inputs from Options, you'll have to specify the type for that Option; there are a few ways of doing this. + + + + +You could use Type Annotations and let Pycord figure out the option type or explicitly specified using the [`SlashCommandOptionType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.SlashCommandOptionType) enum. + +```python +import discord + +bot = discord.Bot() + +@bot.command() +# pycord will figure out the types for you +async def add(ctx, first: discord.Option(int), second: discord.Option(int)): + # you can use them as they were actual integers + sum = first + second + await ctx.respond(f"The sum of {first} and {second} is {sum}.") + +@bot.command() +# this explicitly tells pycord what types the options are instead +async def join( + ctx, + first: discord.Option(discord.SlashCommandOptionType.string), + second: discord.Option(discord.SlashCommandOptionType.string) +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + add + +
+ The sum of 1 and 1 is 2. +
+ +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+ + +Instead of Type Annotations, you can also use the option decorator. This is usually done to have type-hinting. + +```python title="Slash Command Type" +import discord + +bot = discord.Bot() + +@bot.command() +@discord.option("first", type=discord.SlashCommandOptionType.string) # type = str also works +@discord.option("second", type=discord.SlashCommandOptionType.string) # type = str also works +async def join( + ctx, + first: str, + second: str, +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+
+ +## Autocomplete + +Discord's autocomplete allows developers to determine option choices that are used in a slash command option. You can do this by defining a function: + +```py +async def get_animal_types(ctx: discord.AutocompleteContext): + """ + Here we will check if 'ctx.options['animal_type']' is a marine or land animal and return respective option choices + """ + animal_type = ctx.options['animal_type'] + if animal_type == 'Marine': + return ['Whale', 'Shark', 'Fish', 'Octopus', 'Turtle'] + else: # is land animal + return ['Snake', 'Wolf', 'Lizard', 'Lion', 'Bird'] + +@bot.slash_command(name="animal") +async def animal_command( + ctx: discord.ApplicationContext, + animal_type: discord.Option(str, choices=['Marine', 'Land']), + animal: discord.Option(str, autocomplete=discord.utils.basic_autocomplete(get_animal_types)) +): + await ctx.respond(f'You picked an animal type of `{animal_type}` that led you to pick `{animal}`!') +``` + + + +
+ + animal + +
+ You picked an animal type of Marine that led you to pick Shark! +
+
+ +:::warning + +Autocomplete can **only** be used with slash commands. + +::: + +:::info Related Topics + +- [Interactions Index](../../interactions) +- [Rules and Common Practices](../../getting-started/rules-and-common-practices) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/interactions/index.mdx b/i18n/es/docusaurus-plugin-content-docs/current/interactions/index.mdx new file mode 100644 index 00000000..8603437f --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/interactions/index.mdx @@ -0,0 +1,242 @@ +--- +title: Discord Interactions +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +In December 2020, Discord released their first Interaction: the +[Slash Command](https://discord.com/developers/docs/interactions/application-commands#slash-commands). +Since then, Discord has added many types of Interactions, including: + +[**Application Commands**](https://discord.com/developers/docs/interactions/application-commands) + +- [**Slash Commands**](https://discord.com/developers/docs/interactions/application-commands#slash-commands): + Commands that can be used with the `/` prefix. +- **Context Menu Commands**: Commands that can be used from the right-click menu. + - [**User Commands**](https://discord.com/developers/docs/interactions/application-commands#user-commands): + Commands that can be used on a user by alt-clicking/selecting them. + - [**Message Commands**](https://discord.com/developers/docs/interactions/application-commands#message-commands): + Commands that can be used on a message by alt-clicking/selecting it. + +[**UI Components**](https://discord.com/developers/docs/interactions/message-components) + +- [**Buttons**](https://discord.com/developers/docs/interactions/message-components#buttons): + Buttons are attached to a message and can be clicked on to perform an action. +- [**Select Menus**](https://discord.com/developers/docs/interactions/message-components#select-menus): + Drop-down menus are used to select a number of options from a list. +- [**Modals**](https://discord.com/developers/docs/interactions/message-components#text-inputs): + Form-like modals can be used to ask for input from a user. + +## Application Commands + +Application Commands are another set of new features that are intended to avoid compromising users' safety and privacy. +They're relatively easy to add to your bot, and give people a simpler and safer way to use commands. + +### [Slash Commands](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.SlashCommand) + +Slash Commands were the first Interaction added to Discord. They're easy to use and create, and +is the only prefix commands alternative that does not need Message Content intent. + +:::note + +Preferring prefix commands over Application Commands is **not** a valid reason to apply for the +Message Content intent. Using that as a reason will get your application denied. + +::: + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +This is what a Slash Command looks like. Not too different from a prefix command, +apart from the note telling you who invoked it. A Slash Command's fields can accept any of the following: + +- Members +- Roles +- Channels +- Attachments +- Text + +Just about as good as it gets. + +### [Message](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.MessageCommand) and [User](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.UserCommand) Commands + +Message Commands and User Commands were both introduced at around the same time, and are very similar to each other, so we'll be +introducing them together. These commands can be found in the `Apps` tab when alt-clicking. The only difference between the two is that +Message Commands only appear in the `Apps` tab of a message, while User Commands are found in the `Apps` tab of a user. Message Commands +can be used to quickly report a message, warn a user for a message, and other functions. Likewise, User Commands can be used to add a +user to a ticket, warn a user, and more. + +Here's an example of a Message Command: + + + + Hello World! + + +
+ + Reverse Message + +
+ Message 930650407917748286 reversed is "!dlroW olleH" +
+
+ +
+ +And here's an example of a User Command: + + + + {defaultOptions.profiles.dorukyum.author} has been on Discord for a long time + + +
+ + User Age + +
+ {defaultOptions.profiles.dorukyum.author} is 1 week old. +
+ +
+ + User Age + +
+ {defaultOptions.profiles.bob.author} is 40 years old. +
+ + 🤔 + +
+ +
+ +Pretty cool, right? To learn more about these two, please read the [Context Menus guide](./application-commands/context-menus.mdx). + +## [Application Commands](#application-commands) vs. [Prefix Commands](../extensions/commands/prefixed-commands) + +Ever since Discord was created, apps on it have used prefix commands. Using prefixes meant that you would have to put a +certain character (or string of characters) in front of your command, such as the exclamation mark in `!ping`. The way this +worked was that your bot would listen for messages, pick out the ones that had their specific prefix, and then respond to the command. +Now, Discord is encouraging developers to switch their bots over to Application Commands, which is a new system meant to preserve the +privacy and safety of their users. But why exactly is Discord making us switch? What's the better option, Application Commands or prefix +commands? Below, we'll discuss everything you need to know. + +### Discord's Decision + +Application Commands were conceptualized partly due to privacy concerns. When Discord first began, they weren't entirely concerned about bots +having access to the content of every message that was being sent. However, as Discord grew, this became more of a problem. Hypothetically, bots +could simply log every message they're able to receive via the Discord API and hand their contents over to a company or other third party. This is +a problem, since that data is meant to be used only by Discord. As such, they locked down Message Content, and introduced Application Commands for +bot developers to use instead. + +Prefix commands work by reading messages, as described before. Application Commands, however, don't +work this way; instead, they work by having your bot get information from Discord about when a command was used. This way, Discord can limit +Message Content only to bots that _absolutely_ depend on it, such as auto-moderation bots. + +### Who has to Use Application Commands + +Any verified bot that does not have the Message Content intent must use Application Commands. Discord is allowing developers to submit +applications for the ability to use the intent; however, since they don't want to keep supporting prefix commands due to privacy concerns, +they will automatically decline any application that includes only that as a reason. So, if your bot doesn't have an auto-moderation feature +(or any other functionality that requires Message Content), you're out of luck. + +Unverified bots, however, don't have to use Application Commands. This is because the Message Content intent is a `Privileged Intent`, meaning that +it must be applied for only if your bot is verified or about to be verified. Unverified bots don't have to apply for Privileged Intents, so they can +use them freely. + +So, if your bot is made only for a couple of servers, you can choose between prefix commands and Application Commands. However, if you plan on expanding +your bot's reach, it'll have to use Application Commands. + +### What's the Better Option + +Choosing which is the better option is up to you, if you're starting small. If +you plan on growing your bot, however, you will have to use Application Commands. Since prefix commands are slowly being phased out by Discord, +there isn't much of a choice for developers of larger bots. + +## Message Components + +Message Components are fairly new features in Discord, allowing developers to give their bots a fast +and understandable user interface. Message Components are easy to use and make your bot look modern, +sleek, and downright awesome. + +### [Views](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View) + +Views are not an Application Command nor are they a Message Component. Views are the invisible placeholders, or grid, +that Message Components lie in. Views can have up to 5 [`Action Rows`](https://docs.pycord.dev/en/stable/api/models.html#discord.ActionRow), +and Action Rows can have a maximum of 5 slots. Below, you can find a table showing how many slots a Message Interaction takes up. + +| Component | Slots | +| ------------ | ----------------------------------------------- | +| Buttons | 1 Slot | +| Select Menus | 5 Slots | +| Text Modals | 1 Slot (opened via a Button) | + +So, based on this, you could have a maximum of 25 Buttons in a View with no Select Menus, and 5 Select +Menus in a View with no Buttons. This doesn't mean you can't have them both in a View, however. You can have +a combination of them, such as 20 Buttons and a Select Menu or 10 Buttons and 3 Select Menus. + +### [Buttons](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button) + +Buttons are the first of the Message Components. They allow for quick responses to prompts, such as for canceling or continuing an action. +Of course, these aren't their only uses; people have created awesome things with Buttons, such as calculators, games, and more! + + + + Discord Buttons are awesome! +
+ + Click me! + +
+
+
+ +
+ +This is what a Button looks like, very simple and modern. To learn more about Buttons, refer to our +[Buttons page](./ui-components/buttons.mdx). + +### [Select Menus](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Select) + +Select Menus are the second of Discord's Message Components. They allow users to select from a list of choices, which your bot can then use. +Select Menus are good for things such as choosing features, pages of a help menu, and more. + +![Select Menu Example Image](../assets/interactions/select-menus-example.png) + +This is what a Select Menu looks like. While not looking as good as Buttons, they still look great +and have even greater possibilities. To learn more about Select Menus, please refer to our [Select +Menus page](./ui-components/dropdowns.mdx). + +### [Modal Dialogs](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal) + +Text Modals are the most recently added Message Component in Discord. They're useful for text input and filling out forms, such as a +sign-up for your bot's service. These are meant to replace long bot setup processes by allowing users to fill out multiple text fields, +which avoids having the user send multiple messages for the bot. Modals can be accessed by either invoking an Application Command or by +interacting with another UI Component. + +![Text Modal Example Image](../assets/interactions/modal-example.png) + +This is what a Text Modal looks like, easy to use and one of the most useful Message Components yet. To learn more about Text Modals, +please visit our [Modal Dialogs page](./ui-components/modal-dialogs.mdx). diff --git a/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json new file mode 100644 index 00000000..7b0a72fe --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "UI Components", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx b/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx new file mode 100644 index 00000000..046b36c7 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx @@ -0,0 +1,314 @@ +--- +title: Buttons +description: Learn all about implementing buttons in your Discord Bot using Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On May 26, 2021, Discord added a new interaction called buttons. Instead of reactions, bots could now +send buttons and users could use them to interact with bots. This opened up a whole new world of +possibilities for bots. Soon after, developers made calculators, polls, and games like blackjack, UNO, +and even Minecraft! Buttons provided a clear and easy to use interface for interacting with bots. + +So, let's learn how you can add buttons to your bot! + +## Concept + +Buttons weren't the only update to the interactions system in Discord. Discord also added [Select Menus](./dropdowns) and [Modal Dialogs](./modal-dialogs), both of which work very similarly to buttons. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive button. + +```python +import discord + +bot = discord.Bot() # Create a bot object + +class MyView(discord.ui.View): # Create a class called MyView that subclasses discord.ui.View + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.primary, emoji="😎") # Create a button with the label "😎 Click me!" with color Blurple + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") # Send a message when the button is clicked + +@bot.slash_command() # Create a slash command +async def button(ctx): + await ctx.respond("This is a button!", view=MyView()) # Send a message with our View class that contains the button + +bot.run("TOKEN") # Run the bot +``` + +Using this command should return the following message: + + + +
+ + button + +
+ This is a button! +
+ + Click me! + +
+
+
+ +
+ +As you can see, we create a class called `MyView` that [subclasses](#oop) +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `button_callback` to the `MyView` class with the decorator +[`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button). +This decorator adds a button to a component. This function takes two arguments: the button that was +clicked and the interaction. These arguments are passed to the function when the button is clicked +by the module. We use the [`interaction.response.send_message`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse.send_message) +function to send a message to the channel where the interaction was sent. + +Finally, we create a global slash command called `button` that sends the message, along with the view +that contains a button. + +This is the basic syntax of creating a button. What you create with it is up to you. You can worry +about making your button do amazing things, while Pycord handles the rest! + +## Button Styles + + + +| Name | Usage | Color | +| --------- | ----------------------------------------------------------------------------------------- | ------- | +| Primary | `discord.ButtonStyle.primary` / `discord.ButtonStyle.blurple` | Blurple | +| Secondary | `discord.ButtonStyle.secondary` / `discord.ButtonStyle.grey` / `discord.ButtonStyle.gray` | Grey | +| Success | `discord.ButtonStyle.success` / `discord.ButtonStyle.green` | Green | +| Danger | `discord.ButtonStyle.danger` / `discord.ButtonStyle.red` | Red | +| Link | `discord.ButtonStyle.link` / `discord.ButtonStyle.url` | Grey | + +Check out the [`discord.ButtonStyle`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ButtonStyle) class for more information. + +![Different Button Styles](../../assets/interactions/button-styles.png) + +You can set a button's style by adding the `style` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) decorator. + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.success) + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots, and each button takes up 1 slot. +So, how do we move the buttons to another row? + +This can be done by specifying the `row` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) +decorator. + +:::info The `row` argument + +The row argument specifies the relative row this button belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=1, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") +``` + +## Disabling Buttons + +### Pre-Disabled Buttons + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary, disabled=True) # pass `disabled=True` to make the button pre-disabled + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView()) +``` + +### Disabling Buttons on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + button.disabled = True # set button.disabled to True to disable the button + button.label = "No more pressing!" # change the button's label to something else + await interaction.response.edit_message(view=self) # edit the message's view +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(emoji="😀", label="Button 1", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) + + @discord.ui.button(label="Button 2", style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +Sometimes, you want to have a button that is disabled after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView(timeout=30)) +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a button that is disabled after a certain amount of time, you want to have a +button that is always working. + +Normally, when the bot goes offline, all of its buttons stop working. You will be able to see the +buttons, but nothing will happen when you press them. This is a problem +if you are trying to create a self-role system with buttons, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons will stop working. When the bot comes back online, however, the buttons will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view must have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.button(label="A button", custom_id="button-1", style=discord.ButtonStyle.primary, emoji="😎") # the button has a custom_id set + async def button_callback(self, button, interaction): + await interaction.response.send_message("Button was pressed", ephemeral=True) + +@bot.command() +async def button(ctx): + await ctx.send(f"Press the button! View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many buttons can I have in a message? + +Each message can have a maximum of 25 buttons. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do buttons need any special permissions? + +No new permissions are needed for either the bot or the server to allow bots to use buttons. + +#### Should I replace reactions with buttons for my bot? + +That is up to you. Buttons do provide a cleaner interface for your bot and are easier to use. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx b/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx new file mode 100644 index 00000000..8320f25d --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx @@ -0,0 +1,339 @@ +--- +title: Select Menus +description: Learn all about implementing Select Menus or Dropdowns in your Discord Bot with Pycord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Shortly after the buttons were added, Discord added their second message component: Select Menus. Select Menus allow users to choose from a list of items sent by a bot. These are a great substitute for having a user send a number that corresponds to an option. You can even allow users to select multiple options from the Select Menus. This guide will show you the easy and painless ways of using them with Pycord. + +## Concept + +Select Menus aren't the only message component in Discord. There's also [Buttons](./buttons) and [Modal Dialogs](./modal-dialogs). Select Menus make it easy for users to pick one or multiple options from a list provided by a bot. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive select menu. + +```python +import discord + +bot = discord.Bot() + +class MyView(discord.ui.View): + @discord.ui.select( # the decorator that lets you specify the properties of the select menu + placeholder = "Choose a Flavor!", # the placeholder text that will be displayed if nothing is selected + min_values = 1, # the minimum number of values that must be selected by the users + max_values = 1, # the maximum number of values that can be selected by the users + options = [ # the list of options from which users can choose, a required field + discord.SelectOption( + label="Vanilla", + description="Pick this if you like vanilla!" + ), + discord.SelectOption( + label="Chocolate", + description="Pick this if you like chocolate!" + ), + discord.SelectOption( + label="Strawberry", + description="Pick this if you like strawberry!" + ) + ] + ) + async def select_callback(self, select, interaction): # the function called when the user is done selecting options + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") + +@bot.command() +async def flavor(ctx): + await ctx.respond("Choose a flavor!", view=MyView()) + +bot.run("TOKEN") +``` + +There's a lot going on over here! Don't worry, we will go over the code and explain it. + +As you can see, we create a class called `MyView` that subclasses +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `select_callback` to the `View` class with the decorator +[`discord.ui.select`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.select). +This decorator adds a select menu to the view. This decorator takes a few arguments to customize your select menu. Read them in the [Customization section](#customization). + +That was the decorator. Now, the function itself is pretty simple. It takes two parameters, not including `self`. The parameters are `select`: The select menu, and `interaction`: a [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object. Both of these are passed by Pycord, so you just need to specify them in the function! + + + +In the callback, you could do anything you want. You get the two parameters `select` and `interaction` to play around with. Here, we send a message using `await interaction.response.send_message` (where interaction is [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse)) with content `select.values[0]`, which sends the label of the first/only option the user selected. Obviously, this is only an example, and you could do just about anything you want. + +Finally, we create a global slash command called `flavour` that sends a message "Choose a flavor!" along with the view +that contains our select menu. + +This is the basic syntax of creating a select menu. What you create with it is up to you. You can worry +about making your code do amazing things, while Pycord handles the rest! + +## Customization + +#### Select Menu Properties + +- `select_type`: The type of select to create. This must be a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. +- `channel_types`: A list of channel types that can be selected in the menu. This is only valid for selects of `select_type` [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType). +- `options`: A list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. These are the options that can be selected in this menu. +- `placeholder` is the placeholder text shown in the select menu if no option is selected. +- `custom_id`: The ID of the select menu that gets received during an interaction. It is recommended not to set this to anything unless you are trying to create a persistent view. +- `row`: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). +- `min_values`: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `max_values`: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `disabled`: Whether the select is disabled or not. Defaults to False. + +#### Select Option Properties + +In the `options` parameter, you pass a list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. This class also has a few parameters: + +- `default` (whether the option is selected by default) +- `description` (an additional description, if any) +- `emoji` (a string or an emoji object, if any) +- `label` (the name displayed to users, can be up to 100 characters) +- `value` (a special value of the option, defaults to the label). + +## Select Types + +In addition to regular string selects, you can also have your select menu contain users, roles, mentionables, and channels as its options. You can use these alternative select types by passing a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value for the `select_type` parameter when creating the Select. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.user_select + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +Additionally, you can use shortcut decorators to create a [`discord.ui.Select`](https://docs.pycord.dev/en/master/api/ui_kit.html#discord.ui.select) with a predetermined [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. Using a shortcut decorator, the above code can be rewritten like this: + +```python +class MyView(discord.ui.View): + @discord.ui.user_select() + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +### Specifying Channel Types + +When using a [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType.channel_select) type select menu, you can pass in a list of [`discord.ChannelType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ChannelType) values to limit which types of channels users can choose when interacting with the select menu. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.channel_select, + channel_types=[discord.ChannelType.text, discord.ChannelType.voice] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"You selected {select.values[0].mention}") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots. A button takes a single slot, while a select menu takes up all 5 of them. This means a view can have a maximum of 5 select menus, or any possible combination of select menus and buttons. + +The arrangement of buttons and select menus is generally adjusted by Pycord. However, it is possible to move them to specific relative rows. This is done by specifying the `row` argument. + +:::info The `row` argument + +The row argument specifies the relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero-indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=0, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.select( + row = 1, + options = [...] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") +``` + +## Disabling Select Menus + +### Pre-Disabled Menus + +```python +class MyView(discord.ui.View): + @discord.ui.select( + disabled = True, # pass disabled=True to set the menu as disabled + options = [...] + ) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send("Select and option from the menu!", view=MyView()) +``` + +### Disabling Menus on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + select.disabled = True # set the status of the select as disabled + await interaction.response.edit_message(view=self) # edit the message to show the changes +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def first_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) # edit the message to show the changes + + @discord.ui.select(options = [...]) + async def second_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +You may want a select menu to automatically stop working after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select(ctx): + await ctx.send(view=MyView(timeout=30)) # specify the timeout here +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a select menu that is disabled after a certain amount of time, you want to have a +select menu that is always working. + +Normally, when the bot goes offline, all of its views stop working, even if they don't have a timeout. You will be able to see the +views, but nothing will happen when you try to interact with them. This is a problem +if you are trying to create a self-role system, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons and select menus will stop working. However, when the bot comes back online, the buttons and select menus will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view much have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.select(custom_id="select-1", options = [...]) # a custom_id must be set + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send(f"View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many select menus can I have in a message? + +Each message can have a maximum of 5 select menus. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do select menus need any special permissions? + +No new permissions are needed in the bot or in the server. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx b/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx new file mode 100644 index 00000000..bd585c77 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx @@ -0,0 +1,107 @@ +--- +title: Modal Dialogs +description: Learn how you can implement Modals in your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Modal Dialogs, also known as "modals", provide a form-like structure for bots to receive input from users. No extra permissions are needed for bots to send modal dialogs, so it becomes a convenient workaround for bots to receive longer input without needing the Message Content [intent](../../popular-topics/intents). + +## Concept + +Modal Dialogs consist of a title, custom ID, and up to 5 [`discord.ui.InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) components. While creating modals, we generally subclass [`discord.ui.Modal`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal), as we'll see later. + +Unlike other UI Components, Modals cannot be sent with messages. They must be invoked by an Application Command or another UI Component. + +## Usage Syntax + +```py +class MyModal(discord.ui.Modal): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.add_item(discord.ui.InputText(label="Short Input")) + self.add_item(discord.ui.InputText(label="Long Input", style=discord.InputTextStyle.long)) + + async def callback(self, interaction: discord.Interaction): + embed = discord.Embed(title="Modal Results") + embed.add_field(name="Short Input", value=self.children[0].value) + embed.add_field(name="Long Input", value=self.children[1].value) + await interaction.response.send_message(embeds=[embed]) +``` + + + + +The `ctx` parameter we define in Application Commands receives an [`ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext) object. Using its `send_modal()` coroutine, you can send a Modal dialog to the user invoking the Application Command. + +```py +@bot.slash_command() +async def modal_slash(ctx: discord.ApplicationContext): + """Shows an example of a modal dialog being invoked from a slash command.""" + modal = MyModal(title="Modal via Slash Command") + await ctx.send_modal(modal) +``` + + + + +The `interaction` parameter we define in UI Components receives an [`Interaction`](https://docs.pycord.dev/en/stable/api/models.html#discord.Interaction) object. The `response` attribute of the object contains an [`InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object, with various coroutines such as `send_message()` and `send_modal()`, which we utilize. + +```py +class MyView(discord.ui.View): + @discord.ui.button(label="Send Modal") + async def button_callback(self, button, interaction): + await interaction.response.send_modal(MyModal(title="Modal via Button")) + +@bot.slash_command() +async def send_modal(ctx): + await ctx.respond(view=MyView()) +``` + + + + +The above example uses an embed to display the results of the modal submission, but you can do anything you want with the text provided by the user. +Each input field can be accessed in the order it was added to the modal dialog, via `Modal.children`. + +## Customization + +A Modal can have up to 5 [`InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) fields. These fields offer some customization. + +Each field has a label which is shown to the user. This is defined with `label`. + +The `style` parameter is used to determine whether it should be a short (single-line) or long (multi-line) input field. + +There are a number of aliases that can be used: + +```x title="Single-line InputTextStyle values:" +short +singleline +``` + +```x title="Multi-line InputTextStyle values:" +paragraph = 2 +multiline = 2 +long = 2 +``` + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Buttons](./buttons) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/introduction.mdx b/i18n/es/docusaurus-plugin-content-docs/current/introduction.mdx new file mode 100644 index 00000000..3262c632 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/introduction.mdx @@ -0,0 +1,50 @@ +--- +title: Introduction +description: Pycord Guide is a complete guide for Pycord. Learn how to create Discord Bots today! +sidebar_position: 1 +--- + +Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord, written in Python. Pycord is a maintained fork of [discord.py](https://github.com/Rapptz/discord.py). + +## Before you begin + +Pycord is an advanced and complex Python library. To take advantage of the full capabilities of Pycord, you will need to have a good understanding of Python. You should know the basics of Python and have an understanding of the following concepts: + +- Variables +- Data Types +- Functions +- Packages +- Conditionals +- Loops +- Classes +- Object-Oriented Programming +- Inheritance +- Exception Handling +- Iterators +- Coroutines +- Async/Await + +This list is not exhaustive, but it should give you a good idea of what you need to know to get started. + +When you see an ellipsis - that's the three dots - in this guide, it is a placeholder for code that you need to fill in. Sometimes, it may be code for a command, while other times it could be something simple like a Guild ID. Make sure to replace them before running your bot! + +## Learning Resources + +Here are some good resources to get started or to freshen up your Python knowledge: + +- [Official Beginner's Guide](https://wiki.python.org/moin/BeginnersGuide) +- [Official Tutorial](https://docs.python.org/3/tutorial/) +- [Automate the Boring Stuff, a free online book for complete beginners to programming](https://automatetheboringstuff.com/) +- [Learn Python in y Minutes, complete cheat sheet for people who know programming already](https://learnxinyminutes.com/docs/python3/) +- [Swaroopch's free Python book](http://python.swaroopch.com/) +- [Codeabbey, exercises for beginners](http://www.codeabbey.com/) + +## Credits + +First of all, we would like to thank [Rapptz](https://github.com/Rapptz) for the original [discord.py](https://pypi.org/project/discord.py) library. Pycord is a maintained fork of this library. + +We would also like to thank the [discord.js guide](https://discordjs.guide), which inspired this guide style-wise, and the [original Pycord Guide](https://namantech.me/pycord), which inspired some content in this guide. + +We created this guide using [Docusaurus v2](https://docusaurus.io), a modern static site generator for React. We would also like to thank Danktuary for his [`@discord-message-components/react`](https://www.npmjs.com/package/@discord-message-components/react) package, from which we took the Discord message components. + +And finally, we would like to thank the amazing and loving community of Pycord users, contributors and developers. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/more/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/more/_category_.json new file mode 100644 index 00000000..2cbe2c56 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/more/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 8, + "label": "More", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/more/community-resources.mdx b/i18n/es/docusaurus-plugin-content-docs/current/more/community-resources.mdx new file mode 100644 index 00000000..ed3075bd --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/more/community-resources.mdx @@ -0,0 +1,23 @@ +--- +title: Community Resources +--- + +This page showcases the amazing things created by the Pycord community, including bots, Plugins, and more. + +## Plugins + +| Name | Type | GitHub | +| --------------- | ------------ | --------------------------------------------------------------- | +| Music Cord | Music | [NixonXC/cord-music](https://github.com/NixonXC/cord-music) | +| pycord-i18n | Localization | [Dorukyum-pycord-i18n](https://github.com/Dorukyum/pycord-i18n) | +| pycord-multicog | Cogs | [pycord-multicog](https://github.com/Dorukyum/pycord-multicog) | +| EzCord | Utilities | [EzCord](https://github.com/tibue99/ezcord) | + +## Bots + +| Name | Type | Link | +| ------------------------ | ------------ | ----------------------------------------------------------------------------------- | +| Discord-Multipurpose-Bot | Multipurpose | [github](https://github.com/pogrammar/Discord-multipurpose-bot/tree/master/Python) | +| inconnu | Fun & QOL | [github](https://github.com/tiltowait/inconnu) | +| Mai | Multipurpose | [github](https://github.com/TeamMai/Mai) & [website](https://xfghoul.github.io/Mai) | +| Toolkit | Multipurpose | [github](https://github.com/Dorukyum/Toolkit) | diff --git a/i18n/es/docusaurus-plugin-content-docs/current/more/contributing.mdx b/i18n/es/docusaurus-plugin-content-docs/current/more/contributing.mdx new file mode 100644 index 00000000..469ea3ee --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/more/contributing.mdx @@ -0,0 +1,463 @@ +--- +title: Contributing to the Guide +description: Learn how to contribute to the Pycord Guide. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +This page outlines some of the basic syntax you need to know to contribute to the guide. We recommend you also check out: + +- [Docusaurus's Docs](https://docusaurus.io/docs/) +- [Contributing Rules](https://github.com/Pycord-Development/guide/blob/master/.github/CONTRIBUTING.md) + +## Info + +We use [Docusaurus v2](https://docusaurus.io/) to generate our guide. All the guide pages are generated +from `mdx` files in the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory. +MDX allows you to use JSX in your markdown content. + +## Structure + +Let's visit the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory and check its file structure. + +We can see various folders and a few files in it. Let's talk a bit about the `introduction.mdx` file. At the top, you can see something like: + +```md +--- +title: Introduction +description: ... +sidebar_position: 1 +--- +``` + +Most pages have this at the top. The `title` defaults to the file name. Since the titles need to be Capitalized according to need while the file names are lowercased (sometimes, the file names are shorter than the title!), we set a title ourselves. + +The `description` field is also important. This is the text shown in an embed when the page's link is shared on Discord, Twitter or other websites that support embedded links. Make sure to give a nice an interesting description! + +The `sidebar_position` field is pretty self-explanatory. It sets the position of the page in the sidebar. Most files in categories do not need this since they are sorted alphabetically. + +## Markdown Syntax + +This page quickly outlines some of the syntax that is used in markdown. + +````mdx +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + + ```python + print("We can use code blocks like this.") + ``` + +You can add [links to other websites](https://pycord.dev). You can add images like this: ![alternate text that describes the image](https://pycord.dev/image.png). + +- You can create +- unordered lists like this + +1. Or ordered lists +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` +4. Like this + +# Headers + +## Go + +### Like + +#### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet +```` + +
+Preview +
+ +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + +```python +print("We can use code blocks like this.") +``` + +You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](@site/static/img/favicon.ico). + +- You can create +- unordered lists like this + +1. Or ordered lists + +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` + +4. Like this + + # Headers + + ## Go + + ### Like + + #### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet + +
+
+ +## Admonitions + +We can add warnings, notes, etc. with the following syntax: + +```md +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: +``` + +
+Preview +
+ +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: + +
+ +
+ +## Discord Message Components + +As most files already have the imports for these, it's not that hard to add them. + +First, import the necessary components: + +```tsx +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; +``` + +The div starts like so: + +```tsx + + + + +
+``` + +This is where you list a `DiscordMessage`. + +```tsx + + + Hello! + + + +
+``` + + + + Hello! + + + +
+ +It has a pretty straightforward syntax. + +:::tip + +Add a `
` to the end of a component to make the content below it look better. + +::: + +### Slash Commands + +To make a message authored by a slash command, do the following: + +```tsx + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+``` + + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+ +### Buttons + +To make a message with buttons, do the following: + +```tsx + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+``` + + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+ +## Page Format + +There are a few things you need to take care of: + +1. Make sure that the spelling and grammar is perfect. We have a GitHub action configured that will warn you about spelling errors when you start a pull request. Make sure to commit your changes accordingly. + + As for the grammar, you should try reading the changes you have done and wait for reviews from others. + +2. A common mistake people make is incorrect header style. People often think that the less the important the topic is, the lower it's heading style should be. + + ```md + [PAGE STARTS] + # Topic + ## Less Important Topic + ## Subtopic + ``` + + ```md + [PAGE STARTS] + # About + [Introduction] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + That's VERY wrong. Here's the correct example: + + ```md + [PAGE STARTS] + [Introduction] + ## Topic + ## Less Important Topic + ### Subtopic + ``` + + ```md + [PAGE STARTS] + [Introduction] + + ## About + [More Information] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + Note that the `---`s at the beginning have been skipped here. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/more/git.mdx b/i18n/es/docusaurus-plugin-content-docs/current/more/git.mdx new file mode 100644 index 00000000..0f929d6d --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/more/git.mdx @@ -0,0 +1,55 @@ +--- +title: Installing Git +description: Learn how you can install Git on your system. +--- + +Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Let's see how to install Git on different platforms. + +## Windows + +On Windows, Git can be installed via: + +- [Git for Windows](https://gitforwindows.org) +- [Git Scm](https://git-scm.com/download/windows) + +## Linux + +On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. + +## Mac + +You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: + +``` +xcode-select --install +``` + +## Using Package Managers + +You can also install Git using package managers. + +### Chocolatey + +If you use the Chocolatey package manager, you can install Git using: + +``` +choco install git +``` + +### Scoop + +If you use Scoop, you can install Git using: + +``` +scoop install git +``` + +### Brew + +If you're on macOS or Linux, you can install Git using: + +``` +brew install git +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx b/i18n/es/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx new file mode 100644 index 00000000..b0b8c7ea --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx @@ -0,0 +1,62 @@ +--- +title: Virtual Environments +description: Learn how to set up a virtual environment for Pycord. +--- + +## Setup + +Sometimes you want to keep libraries from polluting system installs or use a different version of libraries than the ones installed on the system. You might also not have permissions to install libraries system-wide. For this purpose, the standard library as of Python 3.3 comes with a concept called “Virtual Environment”s to help maintain these separate versions. + +A more in-depth tutorial is found on [Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html). + +However, for the quick and dirty: + +Go to your project’s working directory: + +```bash +$ cd your-bot-source +$ python3 -m venv venv +``` + +Activate the virtual environment: + +```bash +$ source venv/bin/activate +``` + +On Windows you activate it with: + +```batch +$ venv\Scripts\activate.bat +``` + +Use pip like usual: + +```bash +$ pip install -U py-cord +``` + +Congratulations. You now have a virtual environment all set up. + +## Additional info + +It can be useful to set up a requirements.txt, so you can just put all of your dependencies in there and have pip install it. +For instance, if you wanted to have the latest 2.0 version of pycord and [pytz](https://github.com/stub42/pytz/blob/master/src/README.rst), just create a file named requirements.txt with the following contents: + +``` +py-cord>=2.0.0 +pytz +``` + +And then (in your virtual environment) you can just execute + +```bash +pip install -r requirements.txt +``` + +To keep from committing your virtual environment to git, you can set up a .gitignore file with the following line +(assuming you named your virtual environment venv like the above example): + +``` +venv/ +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/_category_.json new file mode 100644 index 00000000..c38ea014 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 7, + "label": "Popular Topics", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx new file mode 100644 index 00000000..5377a6c3 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx @@ -0,0 +1,140 @@ +--- +title: Cogs +--- + +Cogs, often known as modules or extensions, are used to organize commands into groups. This is useful +for grouping commands that have the same general idea (such as moderation commands). This also helps +to avoid making your bot's files messy and cluttered. + +## Getting Started + +First, you'll need to create a folder to store your cogs, e.g. `cogs/`. + +Then, create a file inside the folder, e.g. `cogs/greetings.py`. By convention, the file name should +be the same as the name of the cog or module. + +We can then create the cog. + +```python title="./cogs/greetings.py" +import discord +from discord.ext import commands + +class Greetings(commands.Cog): # create a class for our cog that inherits from commands.Cog + # this class is used to create a cog, which is a module that can be added to the bot + + def __init__(self, bot): # this is a special method that is called when the cog is loaded + self.bot = bot + + @commands.command() # creates a prefixed command + async def hello(self, ctx): # all methods now must have both self and ctx parameters + await ctx.send('Hello!') + + @discord.slash_command() # we can also add application commands + async def goodbye(self, ctx): + await ctx.respond('Goodbye!') + + @discord.user_command() + async def greet(self, ctx, member: discord.Member): + await ctx.respond(f'{ctx.author.mention} says hello to {member.mention}!') + + math = discord.SlashCommandGroup("math", "Spooky math stuff") # create a Slash Command Group called "math" + advanced_math = math.create_subgroup( + "advanced", + "super hard math commands!" + ) + + @math.command() + async def add(self, a: int, b: int): + c = a + b + await ctx.respond(f"{a} + {b} is {c}.") + + @advanced_math.command() + async def midpoint(self, x1: float, y1: float, x2: float, y2: float): + mid_x = (x1 + x2)/2 + mid_y = (y1 + y2)/2 + await ctx.respond(f"The midpoint between those coordinates is ({mid_x}, {mid_y}).") + + @commands.Cog.listener() # we can add event listeners to our cog + async def on_member_join(self, member): # this is called when a member joins the server + # you must enable the proper intents + # to access this event. + # See the Popular-Topics/Intents page for more info + await member.send('Welcome to the server!') + +def setup(bot): # this is called by Pycord to setup the cog + bot.add_cog(Greetings(bot)) # add the cog to the bot +``` + +You can add any number of commands to your cog, as well as event listeners. However, this code will +not work on its own. In your main bot file, you must add the following code: + +```python +bot.load_extension('cogs.greetings') +``` + +This loads the file `cogs/greetings.py` and adds it to the bot. +The argument of `load_extension` should be your cog's path (e.g. cogs/greetings.py) without the file +extension and with the `/` replaced with `.` + +If you have multiple cogs, you can add them all at once by adding the following code: + +```python +cogs_list = [ + 'greetings', + 'moderation', + 'fun', + 'owner' +] + +for cog in cogs_list: + bot.load_extension(f'cogs.{cog}') +``` + +## Cog Rules + +When using a cog instead of the main file, there are some changes you have to make to your code. This +is because cogs work slightly different from a regular file. + +### The `self` variable + +The self variable is a variable that represents a class. In the case of cogs, `self` represents +the cog. In the `__init__` function, you can see that we have `self.bot = bot`. `bot` represents your +`discord.Bot` or `discord.ext.commands.Bot` instance, which is used for some functions. + +This means that instead of using functions that would usually be accessed via `bot`, you now need +to access them via `self.bot` + +Because we're in a class, all of our commands are methods of that class. Because of this, all of our +functions need to have `self` as the first parameter, where `self` is the cog. Without this, we +wouldn't be able to access our bot instance. + +### Creating Commands + +When creating prefixed commands, your decorator would usually be something like `@bot.command()`. If you're using +cogs, this isn't the case. In a cog, you can't access the bot instance outside of functions, so to +register a function as a command, you must instead use `@commands.command()`. + +Similar to prefixed commands, you'll have to use either the `@discord.slash_command()`, `@discord.user_command()`, +or `@discord.message_command()` decorators for Application Commands. + +Also, when creating a command, make sure that it is indented. If we want a command to be actually +inside a cog, it has to be inside your cog's class. If the command is not inside the cog, +your command becomes useless. + +### Events + +When creating events, you can no longer use `@bot.event` as a decorator. This is because we cannot +access the `bot` variable outside a function. To make an event, you have to use the `ext.commands` +method, `@commands.Cog.listener()`. Events also need `self` as their first parameter. + +And that's it! Cogs are a simple and easy way of organizing your code. Now you can check out how to +create a help command [here](../extensions/commands/help-command). + +:::info Related Topics + +- [Creating a Help Command](../extensions/commands/help-command) +- [Rules and Common Practices](../getting-started/rules-and-common-practices) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Application Commands](../interactions#application-commands) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx new file mode 100644 index 00000000..6c19dd29 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx @@ -0,0 +1,383 @@ +--- +title: Error Handling +description: All about handling errors. +--- + +import { + DiscordEmbed, + DiscordInteraction, + DiscordMessage, +} from "discord-message-components/packages/react"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +## About + +When using the library, errors are frequently raised due to various reasons. These reasons range from the Discord API +failing your bot's request due to missing permissions or an invalid syntax error. + +Before going into error handling, it's best that you learn the basic ways of handling errors. A good resource is: + +- [W3Schools' Guide to Python Try-Except Statements](https://www.w3schools.com/python/python_try_except.asp) + +## Basic Handling + +The most basic way to handle errors is to tackle it at the source. This can be done like so: + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +import asyncio + +import discord + +intents = discord.Intents.default() +intents.message_content = True + +bot = discord.Bot(intents=intents) + + +@bot.slash_command(description="Gets some feedback.") +@discord.option("name", description="Enter your name.") +async def feedback(ctx: discord.ApplicationContext, name: str): + try: + await ctx.respond(f"Hey, {name}! Send your feedback within the next 30 seconds please!") + + def is_author(m: discord.Message): + return m.author.id == ctx.author.id + + feedback_message = await bot.wait_for("message", check=is_author, timeout=30.0) + await ctx.send(f"Thanks for the feedback!\nReceived feedback: `{feedback_message.content}`") + except asyncio.TimeoutError: + await ctx.send("Timed out, please try again!") + + +bot.run("TOKEN") +``` + +If you respond within 30 seconds, the interaction will look like so: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Great bot! + + + Thanks for the feedback! +
+ Received feedback: Great bot! +
+
+
+ +Otherwise, if you don't respond in time, the interaction will go as follows: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Timed out, please try again! + +
+
+ +This basic method of error handling can be extended to handle +many other errors including ones raised directly by py-cord. + +## Per-Command Handling + +This type of error handling allows you to handle errors per each command you have on your bot. +Each and every command can have it's own error handler made to handle specific errors that each command may raise! + +An example of per-command error handling is as follows: + +:::note Bridge Commands + +For these types of commands, it is recommended to utilize global error handling +until [the feature](https://github.com/Pycord-Development/pycord/issues/1388) is added. +::: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot(owner_id=...) # Your Discord user ID goes in owner_id + + +@bot.slash_command(description="A private command...") +@commands.is_owner() # This decorator will raise commands.NotOwner if the invoking user doesn't have the owner_id +async def secret(ctx: discord.ApplicationContext): + await ctx.respond(f"Hey {ctx.author.name}! This is a secret command!") + + +@secret.error +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.NotOwner): + await ctx.respond("Sorry, only the bot owner can use this command!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If your ID is registered as the owner ID, you'll get the following: + + + +
+ + secret + +
+ Hey Dorukyum! This is a secret command! +
+
+
+ +Any other user whose ID doesn't match the bot owner's will get the following: + + + +
+ + secret + +
+ Sorry, only the bot owner can use this command! +
+
+
+ +This local (per-command) error handler can also be used to handle the same types of errors that standard try-except +statements can handle. This is done by using the same method as above with the `isinstance` built-in function. + +## Per-Cog Handling + +Adding error handlers per-command can be quite the task in terms of work if you have a lot. If you have happened to +group your commands in cogs, then you're in luck! You can create an error handler that is specific to a cog and +handles all errors raised by commands inside that cog. + +Here's an example of a bot with a cog that implements its own error handling: + +```python title="./cogs/dm.py" +# This cog is for DM only commands! Sadly, we only have 1 command here right now... + +import discord +from discord.ext import commands + + +class DM(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.command() + @commands.dm_only() # This decorator will raise commands.PrivateMessageOnly if invoked in a guild context. + async def avatar(self, ctx: commands.Context): + embed = discord.Embed( + title="Avatar", + description=f"Here's your enlarged avatar, {ctx.author.name}!", + color=ctx.author.top_role.color + ) + embed.set_image(url=ctx.author.display_avatar.url) + await ctx.send(embed=embed, reference=ctx.message) + + async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): + if isinstance(error, commands.PrivateMessageOnly): + await ctx.send("Sorry, you can only use this in private messages!", reference=ctx.message) + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +def setup(bot: commands.Bot): + bot.add_cog(DM(bot)) +``` + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +# This is the main file where we load the DM cog and run the bot. + +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix=commands.when_mentioned_or("!")) +bot.load_extension("cogs.dm") +bot.run("TOKEN") +``` + +If you use this command in a DM context, you'll get the following: + + + + !avatar + + +
+ + !avatar + +
+ + Here's your enlarged avatar, BobDotCom! + +
+
+
+ +Otherwise, if used in a guild context: + + + + !avatar + + +
+ + !avatar + +
+ Sorry, you can only use this in private messages! +
+
+
+ +Per-cog error handling comes in very handy as you can relegate all of your error handling to a single function instead +of spreading it out across several per-command error handlers or inside the commands themselves. + +## Global Handling + +If separating your error handling is not how you would like to handle errors, then global error handling is the way to +go. This method of handling allows you to relegate all handling to a single function that resides within your bot +instance. + +A non-subclassed bot would implement this like so: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot() + + +@bot.slash_command(description="Get the bot's current latency!") +@commands.cooldown(1, 30, commands.BucketType.user) +# ^ This decorator allows one usage of the command every 30 seconds and raises commands.CommandOnCooldown if exceeded +async def ping(ctx: discord.ApplicationContext): + await ctx.respond(f"Pong! `{int(bot.latency*1000)} ms`.") + + +@bot.event +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.CommandOnCooldown): + await ctx.respond("This command is currently on cooldown!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If you've subclassed your bot, the `on_application_command_error` event will be placed inside the subclass without a +`bot.event` decorator and `bot.slash_command` will be replaced with `discord.slash_command`. + +The error handling used above will yield this interaction if the command is used again too quickly: + + + +
+ + ping + +
+ Pong! 49 ms. +
+ +
+ + ping + +
+ This command is currently on cooldown! +
+
+
+ +The only issue regarding global error handling is that, if you have a large amount of commands, the global handler may +start to get crammed with a lot of code. This is where all the previously mentioned handlers can take their place! + +## FAQ + +#### Why does the example in per-cog handling have self at the start of its function signatures? + +This is a feature of classes and allows you to reference the cog object as `self` and get access to the bot object +passed at initialization through `self.bot`. + +If this is new to you, we recommend checking out these helpful resources to learn more about classes and cogs: + +- [W3Schools' Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [Our Cogs Guide Page](./cogs) + +#### How many errors can I handle in a single error handler? + +While all the examples in this guide page only handle one specific error and re-raise all others, all of these +error handlers can be extended to catch many errors. + +In [basic handling](#basic) (i.e. try/except statements) you can do one of two things: + +- Explicitly handle the errors you know might get raised and then have a broad `except Exception as exc:` statement + as a catch-all. +- Catch any and all errors via the catch-all statement mentioned above. + +In [per-command](#percommand), [per-cog](#percog), and [global handling](#global), you can use elif clauses with the +built-in isinstance function to catch specific errors. Atop of this, an else clause can be used to catch any other +errors you either don't want to handle or want to relegate to a different error handler. + +#### Can I use more than one type of error handler at once? + +Thankfully, all of these different ways of error handling can be mixed together, so you don't have to pick just one! +For commands that raise specific errors that no other commands will raise, you can use [per-command](#percommand). +For cogs that raise specific errors that no other cogs will raise, use [per-cog](#percog)! Lastly, for errors that +occur frequently across all commands and cogs, use [global handling](#global)! + +However, one important note to remember is that you should always raise the error again in an error handler if it +isn't handled there! If you don't do this, the error will go ignored and your other handlers won't have a chance to +do their work! + +#### What's the difference between slash and prefixed command error handling? + +Although most examples shown here use slash commands, the [per-cog handling](#percog) section presents a prefixed +command. The main difference you may notice is the change in command signature. + +To make the distinguishing features apparent: + +- Slash commands use `on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException)` + as presented in the [per-command](#percommand) and [global handling](#global) examples. +- Prefixed commands use `on_command_error(ctx: commands.Context, error: commands.CommandError)` as presented in the + [per-cog handling](#percog) example. + +This distinction is made as both types of commands need their own system for handling errors that are specific to +themselves. + +:::info Related Topics + +- [Slash Commands](../interactions/application-commands/slash-commands) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Cogs](./cogs) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx new file mode 100644 index 00000000..9f4210af --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx @@ -0,0 +1,62 @@ +--- +title: Intents +description: All about intents in Discord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +## What are Intents? + +Intents allow bot developers to "subscribe" to specific events in Discord. This is useful for bots that need to respond to specific events, such as when a user joins a server or sends a message. You could choose to enable all intents or to enable only specific intents that your bot requires. + +## How do I enable intents? + +:::important + +Remember that [Privileged Intents](#what-are-privileged-intents) require you to enable them in the Discord Developer Portal. Verified Discord Bots that don't already have access to them will need to request Discord to allow access. + +::: + + + + +```python +import discord + +bot = discord.Bot(intents=discord.Intents.all()) +``` + + + + + +You can view a list of intents and the events they subscribe to [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```python title="Enabling Intents" +import discord + +bot = discord.Bot(intents=discord.intents.members(bans=True, guilds=True)) +``` + + + + +## What are Privileged Intents? + +Discord defines some intents as "privileged" because of the sensitive information they contain. Currently, there are three privileged intents: `members`, `presences`, and `message_content`. These intents must be enabled in your bot's Developer Portal. Once your bot reaches 100 servers, you will need to verify your bot for these intents to keep working and for your bot to be able to be invited to more guilds. + +:::tip + +Only enable these intents if you need them. These intents give your bot access to quite sensitive information about the users in your guild. These intents are privileged to respect the privacy of users, and you should do that as well. + +Not enabling these intents doesn't mean you won't be able to ban users, but you will be unable to detect when a new user joins a guild, or what game they are playing. The majority of bots won't need all intents. + +::: + +:::info Related Topics + +- [Sharding Bots](sharding) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx new file mode 100644 index 00000000..c3d17197 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx @@ -0,0 +1,48 @@ +--- +title: Sharding +description: All about Sharding Discord Bots. +--- + +# Sharding + +## What is Sharding? + +Sharding is the process of breaking up your bot into smaller pieces so that it has a better time handling +events. As [Discord's Documentation](https://discord.com/developers/docs/topics/gateway#sharding) puts +it, sharding is "a method of user-controlled guild sharding which allows for splitting events across +several gateway connections." + +Sharding is used only for large bots and takes up additional resources for managing the new processes. +Pycord automatically shards your bot, so the only thing you need to do is use an `AutoShardedClient` +or `AutoShardedBot` class instead of a plain `Client` or `Bot` class. Pretty cool, right? + +Just because you _can_ shard your bot doesn't mean you _should_. While Pycord makes it easy to shard +your bot, it isn't necessary to shard unless your bot is large. Sharding a small bot isn't +just useless, but _harmful_, as it uses extra resources and may slow down your bot. Discord +themselves will let you know when your bot needs sharding, so you won't need to worry about this until they contact you. + +## How Do I Shard in Pycord? + +Sharding in Pycord is straightforward. + +Just replace your `discord.Client`, `discord.Bot`, `commands.Bot` objects +with `discord.AutoShardedClient`, `discord.AutoShardedBot`, `commands.AutoShardedBot` respectively. + +These new objects have been inherited from the original objects, so all the functions from those other types should be present. + +If you want to specify the number of shards your bot uses, +just add the `shards` parameter, along with the number of shards you want. + +## Why Should I Shard my Bot? + +Sharding is very necessary for big bots. While your bot grows, it gets harder for your bot to control +how many guilds it is in and what parts of your code should do what. This is exactly what sharding +handles, it makes all of this easier for your bot. Remember, though, only shard your bot once it's +big enough, and that's at _least_ 1,000 guilds. + +:::info Related Topics + +- [Hosting your Bot](../Getting-Started/hosting-your-bot) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx new file mode 100644 index 00000000..bd2969c1 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx @@ -0,0 +1,115 @@ +--- +title: Subclassing Bots +description: Subclassing is a popular way of creating Discord Bots. Explore how you can create a Discord bot by subclassing. +--- + +## About + +Subclassing is another popular way of creating Discord Bots. Here, you create a bot by extending a bot class. To some advanced users, this is preferable to creating a bot instance with `bot = discord.Bot()`. + +Subclassing is an intermediate python concept, so we recommend you learn about it before continuing. Some good resources are: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +## Why Subclassing? + +Many developers prefer to subclass their bots for many reasons, some of them being: + +#### Skeletal Frameworks for Bots + +Developers often share their bots code on open-source platforms, mostly GitHub, and allow users to self-host the bot (running their own instance of the bot with the code provided by the developer. Permissions vary in accordance to licences). Here, users find it easier and more convenient to have a small file that imports the custom bot class and runs it, rather than having to go through the code of the bot and find out which file to run. This makes it easier for people not familiar with programming to run and customize the bot, since it often brings down the code to: + +```python title="./main.py" +from src import Bot + +bot = Bot() + +bot.run("TOKEN") +``` + +Here, all the commands are inside the `/src` folder that the user need not bother with. + +#### Running Multiple Instances + +Some developers may need to run multiple instances of their bot (perhaps on different bot accounts). For example, a developer might have a second bot for testing alpha features. This system makes it simpler for the developer, and allows them to maintain multiple versions of the bot in the same directory: + +```python title="./alpha_bot.py" +from src import Bot + +class AlphaBot(Bot): # subclasses Bot + ... # insert any custom configuration + +bot = AlphaBot() + +@bot.slash_command() # adds a new slash command to this subclassed bot +async def alpha_feature(ctx): + await ctx.respond("Alpha Feature!") + +bot.run("TOKEN") +``` + +There are many more reasons to subclass! It's not required, and won't affect the speed of the bot, but it may affect your development process, for the good or for the worse. You don't miss out on any features when you subclass, either. Some developers want the OOP feel, while some just prefer that method and find it easier. + +## Basic Example + +```python +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override the on_ready event + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') + +bot = MyBot() + +@bot.slash_command() # create a slash command +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run('token') +``` + +As you can see, instead of creating a bot object with `bot = discord.Bot()`, we subclass [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). We then create an instance of our new bot class and run it. Notice how we don't need to use the `@event` decorator. + +Here's another example: + +```python title="./src/bot.py" +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override on_ready + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') +``` + +```python title="./src/\_\_init\_\_.py" +from .bot import MyBot # import the MyBot class from the bot.py file +``` + +```python title="./main.py" +from src import MyBot # import MyBot from /src + +bot = MyBot() # create an instance of MyBot + +@bot.slash_command() +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run("TOKEN") # run the bot +``` + +These are just two ways you could do it. There are ton of other structures you can implement. It's up to you. + +So, should you subclass? There are no limitations you face if you decide to subclass your bot, but, once again, it's up to you. + +:::info Related Topics + +- [Making a Help Command](../Extensions/Commands/help-command) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx new file mode 100644 index 00000000..23220b0e --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx @@ -0,0 +1,105 @@ +--- +title: Threads +description: Threads with Pycord +--- + +In programming, threads are a way to run multiple processes at the same time. In Discord, threads are +a way to keep multiple conversations going at the same time. Let's take a brief look at how to use threads in Pycord. + +:::tip + +Not all the methods and attributes will be covered in this guide, but you can find them in our documentation! +[Check it out!](https://docs.pycord.dev/en/stable/api/models.html#discord.Thread) + +::: + +## Creating a thread + +With a few simple lines of code, we can create threads in Pycord. + +:::important + +All public threads need a starting message. This message will start the thread. However, private threads +(which are unlocked with having your server boosted to Level 2), do not require a starting message. + +::: + +### Creating thread from a message + +```python title="Creating a Thread from a Message" +message = await ctx.send("My Starting Message") +await message.create_thread(name="thread name", auto_archive_duration=60) +``` + +You may also use other ways to create the thread, for example, by using `on_message` events or by commands. + +### Creating thread in a channel + +```python title="Creating a Thread from a Channel" +channel = bot.get_channel(...) # define this! +await channel.create_thread(name="Thread Name", message=None, auto_archive_duration=60, type=None, reason=None) +``` + +A thread type could be `news_thread`, `public_thread`, `private_thread`. You may use it by passing `type=discord.ChannelType.news_thread`. + +## Deleting Threads + +Deleting Threads is simple. You need to get a thread and then use the `delete` method. + +```python title="Deleting a Thread" +thread = bot.get_channel(thread_id) # you could use other ways to get a thread +await thread.delete() +``` + +## Editing Threads + +**Parameters** + +- `name` (str) – The new name of the thread + +- `archived` (bool) – Whether to archive the thread or not. + +- `locked` (bool) – Whether to lock the thread or not. + +- `invitable` (bool) – Whether non-moderators can add other non-moderators to this thread. Only available for private threads. + +- `auto_archive_duration` (int) – The new duration in minutes before a thread gets automatically archived for inactivity. Must be one of 60, 1440, 4320, or 10080. + +- `slowmode_delay` (int) – Specifies the slow-mode rate limit for users in the thread, in seconds. A value of 0 disables slow-mode. The maximum value possible is 21600. + +```python title="Editing a Thread" +thread = bot.get_channel(id) +await thread.edit( + name="New Name", + archived=True, + locked=True, + slowmode_delay=10, + auto_archive_duration=60, +) +``` + +As you can see, threads are very simple. Once you learn how to use them, it's easy to create whatever you want. + +## FAQ + +### Why am I getting a `Forbidden` error when I try to create a thread? + +A `Forbidden` error occurs when the bot does not have the correct permissions to create threads. + +### Why am I getting an Unknown Message error when I try to create a thread? + +Getting an error looking something like `discord.ext.commands.errors.CommandInvokeError: Command +raised an exception: HTTPException: 400 Bad Request (error code: 10008): Unknown Message`? + +There could be multiple reasons, some of them being: + +- The message does not exist +- The message already has a thread +- The message is in channel x, you are trying to start a thread in channel y. +- The message was deleted. + +:::info Related Topics + +<>{/* I can't think of any related topics for this at the moment. */} + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/voice/_category_.json b/i18n/es/docusaurus-plugin-content-docs/current/voice/_category_.json new file mode 100644 index 00000000..8baf3da8 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/voice/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 6, + "label": "Voice" +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/current/voice/index.mdx b/i18n/es/docusaurus-plugin-content-docs/current/voice/index.mdx new file mode 100644 index 00000000..835838c6 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/voice/index.mdx @@ -0,0 +1,24 @@ +--- +title: Voice +--- + +Welcome to the guide for voice features in Pycord. + +:::caution +This guide requires previous experience with Pycord and Python. +::: + +## Requirements + +The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). +The following features are optional: + +:::tip +Opus is also a required library, but this comes with Pycord. +Some hosts may not come with it, though, so remember to always check if required dependencies are installed. +::: + +- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` +- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), + [`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), + [`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/voice/playing.mdx b/i18n/es/docusaurus-plugin-content-docs/current/voice/playing.mdx new file mode 100644 index 00000000..fe14c52a --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/voice/playing.mdx @@ -0,0 +1,149 @@ +--- +title: Wavelink Audio Player +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { + defaultOptions, +} from "@site/src/components/DiscordComponent"; + +# About + +Pycord and Wavelink try to keep the playing of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio playing feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/). + +## Starting out + +First you need to run a [Lavalink Server](https://github.com/freyacodes/Lavalink) to connect with. +There a multiple documentations to do this, so we are not covering that here. + +You also need to install the [wavelink](https://github.com/PythonistaGuild/Wavelink) library. + +```py title="Installing wavelink" +python3 -m pip install wavelink +``` + +You will now want to connect to your server via a node. + +```py title="Connect Node with Lavalink" +import discord +import wavelink + +bot = discord.Bot() + +async def connect_nodes(): + """Connect to our Lavalink nodes.""" + await bot.wait_until_ready() # wait until the bot is ready + + nodes = [ + wavelink.Node( + identifier="Node1", # This identifier must be unique for all the nodes you are going to use + uri="http://0.0.0.0:443", # Protocol (http/s) is required, port must be 443 as it is the one lavalink uses + password="youshallnotpass" + ) + ] + + await wavelink.Pool.connect(nodes=nodes, client=bot) # Connect our nodes +``` + +
+ +Now you are finished making your node! Next, you will want to: + +1. Making a play command +2. Adding connect events + +### Making a play command + +To make a play command, you will need to make a function to connect and play audio in a voice channel. + +```py title="Play Command Example" +import typing + +@bot.slash_command(name="play") +async def play(ctx, search: str): + # First we may define our voice client, + # for this, we are going to use typing.cast() + # function just for the type checker know that + # `ctx.voice_client` is going to be from type + # `wavelink.Player` + vc = typing.cast(wavelink.Player, ctx.voice_client) + + if not vc: # We firstly check if there is a voice client + vc = await ctx.author.voice.channel.connect(cls=wavelink.Player) # If there isn't, we connect it to the channel + + # Now we are going to check if the invoker of the command + # is in the same voice channel than the voice client, when defined. + # If not, we return an error message. + if ctx.author.voice.channel.id != vc.channel.id: + return await ctx.respond("You must be in the same voice channel as the bot.") + + # Now we search for the song. You can optionally + # pass the "source" keyword, of type "wavelink.TrackSource" + song = await wavelink.Playable.search(search) + + if not song: # In case the song is not found + return await ctx.respond("No song found.") # we return an error message + + await vc.play(song) # Else, we play it + await ctx.respond(f"Now playing: `{song.title}`") # and return a success message +``` + + + +
+ + play + +
+ Now playing: Never Gonna Give You Up +
+
+ +
+ +Now that you've done this, the only thing left to do is make your connect events. + +### Adding connect events + +The final step to this guide is connecting the node to your server when the bot goes online. + +To make it, you will want to do the following: + +```py title="Adding connect events" +@bot.event +async def on_ready(): + await connect_nodes() # connect to the server + +@bot.event +async def on_wavelink_node_ready(payload: wavelink.NodeReadyEventPayload): + # Everytime a node is successfully connected, we + # will print a message letting it know. + print(f"Node with ID {payload.session_id} has connected") + print(f"Resumed session: {payload.resumed}") + +bot.run("token") +``` + +Congratulations! You have now implemented voice playing into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/current/voice/receiving.mdx b/i18n/es/docusaurus-plugin-content-docs/current/voice/receiving.mdx new file mode 100644 index 00000000..1bc364e1 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/voice/receiving.mdx @@ -0,0 +1,130 @@ +--- +title: Receiving Voice Samples +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +# About + +Pycord tries to keep the recording of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio recording feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/audio_recording.py). + +## Starting out + +The first thing you want to do is make a cache of your voice connections. This is fairly easy; as +it's just putting a variable with an empty dictionary in our code, such as `connections = {}`. + +You will now want to create your command for recording. + +```py title="Record Command Example" +import discord + +bot = discord.Bot() +connections = {} + +@bot.command() +async def record(ctx): # If you're using commands.Bot, this will also work. + voice = ctx.author.voice + + if not voice: + await ctx.respond("You aren't in a voice channel!") + + vc = await voice.channel.connect() # Connect to the voice channel the author is in. + connections.update({ctx.guild.id: vc}) # Updating the cache with the guild and channel. + + vc.start_recording( + discord.sinks.WaveSink(), # The sink type to use. + once_done, # What to do once done. + ctx.channel # The channel to disconnect from. + ) + await ctx.respond("Started recording!") +``` + + + +
+ + record + +
+ Started recording! +
+
+ +
+ +Now you are finished making your command for voice receiving! Next, you will want to: + +1. Make your finished callback +2. Make a stop command + +### Making a Callback + +To make a callback, you will want to define the currently undefined `once_done` function inside +our command, like so: + +```py title="Recorder Callback" +async def once_done(sink: discord.sinks, channel: discord.TextChannel, *args): # Our voice client already passes these in. + recorded_users = [ # A list of recorded users + f"<@{user_id}>" + for user_id, audio in sink.audio_data.items() + ] + await sink.vc.disconnect() # Disconnect from the voice channel. + files = [discord.File(audio.file, f"{user_id}.{sink.encoding}") for user_id, audio in sink.audio_data.items()] # List down the files. + await channel.send(f"finished recording audio for: {', '.join(recorded_users)}.", files=files) # Send a message with the accumulated files. +``` + + + + finished recording audio for:{" "} + {defaultOptions.profiles.bob.author} + + + +
+ +Now that you've done this, the only thing left to do is make your stop command. + +### Making a Stop Command + +The final step to this guide is stopping the audio recording. This is the easiest step by far. + +To make it, you will want to do the following: + +```py title="Stop Recording Command" +@bot.command() +async def stop_recording(ctx): + if ctx.guild.id in connections: # Check if the guild is in the cache. + vc = connections[ctx.guild.id] + vc.stop_recording() # Stop recording, and call the callback (once_done). + del connections[ctx.guild.id] # Remove the guild from the cache. + await ctx.delete() # And delete. + else: + await ctx.respond("I am currently not recording here.") # Respond with this if we aren't recording. + +bot.run("token") +``` + +Congratulations! You have now implemented voice recording into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/es/docusaurus-plugin-content-pagesindex.tsx b/i18n/es/docusaurus-plugin-content-pagesindex.tsx new file mode 100644 index 00000000..84df3a9c --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-pagesindex.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import DefaultLayout from "../layouts/DefaultLayout"; +import PYCHero from "@site/src/components/PYCHero"; +import PYCButton from "@site/src/components/PYCButton"; + +export default function Home(): JSX.Element { + return ( + + +
+ Imagine a place where you can learn how to create an awesome Discord + bot, equip it with Pycord, and have it running in less than a minute. + Imagine a place where you can learn everything about Pycord. Imagine a + guide. A Pycord Guide! +

+ Whether you are a newbie or an experienced developer, you will find + everything you need to know about Pycord here. This guide will teach + you: +
    +
  • How to get a brand new bot running from scratch;
  • +
  • How to create Interactions, Context Menus and Commands;
  • +
  • In-depth concepts such as Embeds, Reactions, Help Commands, Paginators, etc;
  • +
  • Popular Topics such as working with Databases, Sharding, etc;
  • +
  • Ways to handle and manage common errors and best practices for bots;
  • +
  • And Much More!
  • +
+
+
+ ); +} diff --git a/i18n/es/docusaurus-theme-classic/footer.json b/i18n/es/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..ffb8a652 --- /dev/null +++ b/i18n/es/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Pycord Development, All rights reserved.", + "description": "The footer copyright" + } +} diff --git a/i18n/es/docusaurus-theme-classic/navbar.json b/i18n/es/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..473b847e --- /dev/null +++ b/i18n/es/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "Pycord Guide", + "description": "The title in the navbar" + }, + "item.label.Home": { + "message": "Home", + "description": "Navbar item with label Home" + }, + "item.label.Docs": { + "message": "Docs", + "description": "Navbar item with label Docs" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + }, + "item.label.Source": { + "message": "Source", + "description": "Navbar item with label Source" + } +} diff --git a/i18n/fr/code.json b/i18n/fr/code.json new file mode 100644 index 00000000..9cce6148 --- /dev/null +++ b/i18n/fr/code.json @@ -0,0 +1,404 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { + "message": "Toggle the collapsible sidebar category '{label}'", + "description": "The ARIA label to toggle the collapsible sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search here", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.algoliaLabel": { + "message": "Search by Algolia", + "description": "The ARIA label for Algolia mention" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorite", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "You might want to check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Algolia" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Try searching for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Believe this query should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/i18n/fr/docusaurus-plugin-content-blog/options.json b/i18n/fr/docusaurus-plugin-content-blog/options.json new file mode 100644 index 00000000..9239ff70 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/fr/docusaurus-plugin-content-docs/current.json b/i18n/fr/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..36b4849a --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,46 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.defaultSidebar.category.Getting Started": { + "message": "Getting Started", + "description": "The label for category Getting Started in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Interactions": { + "message": "Interactions", + "description": "The label for category Interactions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Application Commands": { + "message": "Application Commands", + "description": "The label for category Application Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.UI Components": { + "message": "UI Components", + "description": "The label for category UI Components in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Extensions": { + "message": "Extensions", + "description": "The label for category Extensions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Commands": { + "message": "Commands", + "description": "The label for category Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Pages": { + "message": "Pages", + "description": "The label for category Pages in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Voice": { + "message": "Voice", + "description": "The label for category Voice in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Popular Topics": { + "message": "Popular Topics", + "description": "The label for category Popular Topics in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.More": { + "message": "More", + "description": "The label for category More in sidebar defaultSidebar" + } +} diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png b/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png new file mode 100644 index 00000000..7480e1da Binary files /dev/null and b/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png differ diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg b/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg new file mode 100644 index 00000000..ce6b5110 Binary files /dev/null and b/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg differ diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png b/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png new file mode 100644 index 00000000..846eee15 Binary files /dev/null and b/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png differ diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png b/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png new file mode 100644 index 00000000..32a47d04 Binary files /dev/null and b/i18n/fr/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png differ diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/_category_.json new file mode 100644 index 00000000..309b494a --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 5, + "label": "Extensions", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json new file mode 100644 index 00000000..652aa4ee --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Bridge" +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx new file mode 100644 index 00000000..81545fa2 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx @@ -0,0 +1,190 @@ +--- +title: Bridge +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +## Concept + +Let's say that you want to make a command that is both a Slash Command and a Prefixed Command. Now, you could just copy and paste the code from the first command callback to the other and make some adjustments, but that's not very efficient. + +This is where the `ext.bridge` module comes in. It allows you to use one callback to make both a Slash Command and a Prefixed Command. + +### Example Usage + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def hello(ctx): + await ctx.respond("Hello!") + +bot.run("TOKEN") +``` + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+
+ +## Syntax + +First, instead of using `discord.Bot` or `commands.Bot`, we use `bridge.Bot`. `bridge.Bot` does inherit from `commands.Bot`, so you can do anything with `bridge.Bot` that `commands.Bot` can do. +Then, we define a command with `@bot.bridge_command()`. This makes a Bridge Command, which has both a Prefixed Command counterpart and a Slash Command counterpart. +Next, the callback has access to a `ctx` object, which is the context of the command. This context is either of `BridgeApplicationContext` type or `BridgeExtContext`. Because of that, it makes detecting how the function was called easier. + +### Using Bridge Commands in a Cog + +Like Slash Commands and Prefixed Commands, you can use Bridge Commands in a Cog. You can do this by using the `bridge_command` decorator. Here's an example: + +```python +import discord +from discord.ext import bridge, commands + +class Greetings(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @bridge.bridge_command() + async def hello(self, ctx): + await ctx.respond("Hello!") + + @bridge.bridge_command() + async def bye(self, ctx): + await ctx.respond("Bye!") + +def setup(bot): + bot.add_cog(Greetings(bot)) +``` + +The cog will automatically split the Bridge Command into their Slash Command and Prefixed Command counterparts. + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+ + +
+ + bye + +
+ Bye! +
+ + + !bye + + + +
+ + !bye + +
+ Bye! +
+
+ +### Deferring + +You can defer if you want to communicate to the user that your bot is busy processing the command. This is done by using `ctx.defer()`. For the Slash Command implementation, `ctx.defer()` calls the function that gives out a "Bot is thinking" message. For the Prefixed Command implementation, `ctx.defer()` enables the typing indicator. + + + +### Options + +Options are pretty straightforward. You just specify them like you do with prefixed commands, and you're all set! + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def sum(ctx, a: int, b: int): + await ctx.respond(a + b) + +bot.run("TOKEN") +``` + + + +
+ + sum + +
+ 4 +
+ + + !sum 2 2 + + + +
+ + !sum 2 2 + +
+ 4 +
+
diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json new file mode 100644 index 00000000..63f8e08e --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx new file mode 100644 index 00000000..bf345c07 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx @@ -0,0 +1,56 @@ +--- +title: Command Groups +--- + +Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk +remove`. + +## Syntax + +Creating a command group is very simple. + +```python title="Command Groups Example" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!') + +@bot.group() +async def afk(): + pass + +@afk.command() +async def set(): + ... + +@afk.command() +async def remove(): + ... + +# Another command group + +@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. +async def math(ctx): + await ctx.send('Subcommand not found') + +@math.command() +async def add(ctx, a: int, b: int): + ... + +@math.command() +async def subtract(ctx, a: int, b: int): + ... +``` + +To create a command group, the command's decorator must be `@bot.group`. Once you have a command with +that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand +groups! + + + +:::info Related Topics + +- [Prefixed Commands](./prefixed-commands.mdx) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx new file mode 100644 index 00000000..acbdc0a8 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx @@ -0,0 +1,481 @@ +--- +title: Help Command +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Pycord's `commands` extension comes with a built-in help command. In this guide, we will take a look at them as well as learn how to create your own. Let's dive in! + +:::note + +This guide demonstrates using object-oriented programming and subclassing to make a help command for your +Pycord bot. It is important to understand these two concepts before continuing. + +**Learning Resources**: + +- [W3Schools - Python Subclassing](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools - Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +::: + +## The Wrong Way + +A popular way to create a help command is to disable the built-in help command and create your own. This is not recommended as it will lead to a lot of confusion. + +```python title="The Wrong Way" +bot = commands.Bot(command_prefix='!', help_command=None) +# OR +bot.help_command = None +# OR +bot.remove_command("help") + +@bot.command() +async def help(ctx, *, argument=None): + ... +``` + +While it's possible to create a help command this way, doing so does not utilize the full capabilities +of making one with Pycord. Making a help command with subclassing and OOP will save time and effort. + +## Types of Help Commands + +There are two types of built-in help commands: + +- [`DefaultHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand) +- [`MinimalHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand) + +`DefaultHelpCommand` is the command enabled by default. It isn't the best looking, but `MinimalHelpCommand` can help make it look a bit better. + + + + +```python title="Default Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.DefaultHelpCommand()) # help_command is DefaultHelpCommand by default so it isn't necessary to enable it like this +# We enable it here for the sake of understanding + +... + +bot.run("token") +``` + + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ + +```python title="Minimal Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.MinimalHelpCommand()) + +... + +bot.run("token") +``` + + + + !help + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+ +
+ +
+ +## Updating Built-in Help Commands + +Let's try to make the `MinimalHelpCommand` look better. We can do this by putting its content in an +embed. + +```python title="Minimal Help Command Example" +bot = commands.Bot(command_prefix='!') + + +class MyNewHelp(commands.MinimalHelpCommand): + async def send_pages(self): + destination = self.get_destination() + for page in self.paginator.pages: + emby = discord.Embed(description=page) + await destination.send(embed=emby) + +bot.help_command = MyNewHelp() +``` + +Let's go through the code. + +First, we create a new class called `MyNewHelp`. This class is a subclass of `MinimalHelpCommand`. + +Next, we override the `send_pages` method. This method is responsible for sending the help command to +the user. We override this method because we don't want to change the content of the pages, just how +they are sent. + +We use the `get_destination` method to get the destination of the message. This is the channel or use that the help +command is to be sent to. + +We use the `paginator.pages` property to get the different pages of the help command. We put the page +in an embed, and then send the embed to the destination channel. + +Finally, we set this as our new help command using `bot.help_command = MyNewHelp()`. + + + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a + category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+
+ +## Creating Your Help Command + +Not satisfied with the built-in help commands? You can create your own! + +For this, we will subclass the `HelpCommand` class. + +There are 4 methods that we need to override: + +- `HelpCommand.send_bot_help(mapping)` that gets called with `help` +- `HelpCommand.send_command_help(command)` that gets called with `help ` +- `HelpCommand.send_group_help(group)` that gets called with `help ` +- `HelpCommand.send_cog_help(cog)` that gets called with `help ` + +### Bot Help + +```python title="Bot Help Example" +class MyHelp(commands.HelpCommand): + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help") + for cog, commands in mapping.items(): + command_signatures = [self.get_command_signature(c) for c in commands] + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's go through the code. + +- First, we create a new class called `MyHelp`. This class is a subclass of `HelpCommand`. + +- Next, we override the `send_bot_help` method. This method is responsible for sending the main help + command to the user. + +- We create an embed with the title "Help". + +- We iterate through `mapping.items()`, which returns a list of tuples, the first element being the + cog and the second element being a list of commands. + +- By using `self.get_command_signature(c)` we get the signature of the command, also known as the + `parameters` or `arguments`. + +- There is a chance that the cog is empty, so we use `if command_signatures:`. + +- We get the name of the cog using `getattr(cog, "qualified_name", "No Category")`. This calls the + cog's attribute `qualified_name` which returns "No Category" if the cog has no name. + +- We add a field to the embed with the name of the cog and the value of the command signatures. + +- Finally, we send the embed to the channel. + +Let's improve the code a little. + +```python title="Improved Bot Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + command_signatures = [self.get_command_signature(c) for c in filtered] + + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Now the help command won't show commands that the user can't use, as well as aliases for commands. +Let's get the help command to show command aliases. + +### Command Help + +This function is called when the user uses `help `. + +```python title="Command Help Example" +class MyHelp(commands.HelpCommand): + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command), color=discord.Color.random()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's quickly go through the code we haven't discussed yet. + +- In line 3, we create an embed with a title the signature of the command (so that the title of the + embed looks like ` [parameter]`), and a random color. + +- In lines 4 and 5, we get the command's `help` description and add it to the embed. The help description + of a command can be specified in the docstrings of a command function. For example: + + ```` + ```python + @bot.command() + async def ping(ctx): + """Returns the latency of the bot.""" + await ctx.send(f"Pong! {round(bot.latency * 1000)}ms") + ``` + ```` + +- Line 6 is shorthand for + + ```python + alias = command.aliases + if alias: + ... + + # is the same as + + if alias := command.aliases: + ... + ``` + + A very helpful (but not well-known) Python shorthand! + +- In line 7, we get the aliases of the command and add them to the embed. + +### Cog Help + +This is pretty easy! + +```python title="Custom Cog Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_cog_help(self, cog): + embed = discord.Embed(title=cog.qualified_name or "No Category", description=cog.description, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(cog.get_commands()): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Once again, we create an embed, get the commands that the user can use, and add them to the embed. + +### Group Help + +Similar to the cog help, this is pretty easy! + +```python title = "Custom Group Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_group_help(self, group): + embed = discord.Embed(title=self.get_command_signature(group), description=group.help, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(group.commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Add all of these methods together, and you have a fully functioning help command! + +
+Click to see the final code for this section +
+ +:::note + +The following code has been slightly edited from the tutorial version. + +::: + +```python title="Custom Help Command Example" +class SupremeHelpCommand(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + if command_signatures := [ + self.get_command_signature(c) for c in filtered + ]: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command) , color=discord.Color.blurple()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_help_embed(self, title, description, commands): # a helper function to add commands to an embed + embed = discord.Embed(title=title, description=description or "No help found...") + + if filtered_commands := await self.filter_commands(commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No help found...") + + await self.get_destination().send(embed=embed) + + async def send_group_help(self, group): + title = self.get_command_signature(group) + await self.send_help_embed(title, group.help, group.commands) + + async def send_cog_help(self, cog): + title = cog.qualified_name or "No" + await self.send_help_embed(f'{title} Category', cog.description, cog.get_commands()) + +bot.help_command = SupremeHelpCommand() +``` + +
+
+ +## Command Attributes + +How can you add cooldowns, set aliases, and change the name of help commands? Command attributes can +help you do all of that, and more! + +```python title="Help Command Attributes" +attributes = { + 'name': "help", + 'aliases': ["helpme"], + 'cooldown': commands.CooldownMapping.from_cooldown(3, 5, commands.BucketType.user), +} + +# You need to use CooldownMapping.from_cooldown(rate, per, type) + +bot.help_command = MyHelp(command_attrs=attributes) +``` + +## Error Handling + +When a user attempts to use a command that does not exist, we need to inform the user. +We can do this by overriding the `send_error_message` function. + +```python title="Custom Help Error Example" +class MyHelp(commands.HelpCommand): + async def send_error_message(self, error): + embed = discord.Embed(title="Error", description=error, color=discord.Color.red()) + channel = self.get_destination() + + await channel.send(embed=embed) +``` + + + + !help update_pycord + + + + Command 'update_pycord' not found. + + + + +## Credits + +Most of the content from this guide is from +[InterStella0's walkthrough guide on subclassing HelpCommand](https://gist.github.com/InterStella0/b78488fb28cadf279dfd3164b9f0cf96). +Thanks to InterStella0 for making this guide amazing. + +:::info Related Topics + +- [Subclassing Bots](../../Popular-Topics/subclassing-bots) +- [Prefixed Commands](./prefixed-commands) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx new file mode 100644 index 00000000..b8f567fd --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx @@ -0,0 +1,324 @@ +--- +title: Prefixed Commands +description: Learn how to use the commands extension for Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Before Discord added slash commands, all bots had prefixed commands. A user would type the bot's prefix +followed by a word or phrase to invoke a command, such as `?help` or `!help`. +However, this prefixed commands system isn't native to Discord! Developers made use of an `on_message` +event to check if the message began with a certain character, then invoke the command. Every time a +message was sent, the bot would see the message and check for its "prefix" + +The syntax becomes a little more complicated when you want to have multiple commands. There are several +disadvantages to this system. This is where the commands extension comes in. `ext.commands` has +various advantages, such as: + +- Simpler syntax +- Easier to use +- Easier to parse user input +- Comes with built-in help commands +- Comes with a built-in system for categorizing commands + + + + +```python title="Prefixed Commands with Events" +import discord + +client = discord.Client() + +@client.event +async def on_message(message): + if message.content.startswith("!ping"): + await message.channel.send("Pong!") + + elif message.content.startswith("!announce"): + if len(message.content.split(" ")) < 3: + await message.channel.send("You need to specify a title and a message. Correct usage: `!announce Hello Hello everyone!`") + return + + msg = message.content.split(" ", 2) + title = msg[1] + content = msg[2] + + await message.channel.send("**{}**\n{}".format(title, content)) + + elif message.content.startswith("!"): + await message.channel.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !help + + + Unknown Command. + +
+ +
+ + +```python title="The Commands Extension" +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix="!", intents=intents) + +@bot.command() +async def ping(ctx): + await ctx.send("Pong!") + +@bot.command() +async def announce(ctx, title, *, message): + await ctx.send("**{}**\n{}".format(title, message)) + +@bot.event +async def on_command_error(ctx, error): + if isinstance(error, commands.CommandNotFound): + await ctx.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !pycord + + + Unknown command. + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+ !announce +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The commands extension has many more uses. This example only showcases the basic features mentioned +in the previous example. Other things you can do with the commands extension include using a different +built-in help command and creating your own. The following tutorials showcase these. + +::: + +
+
+ +## Syntax + +Before we check out the syntax, let's take a look at the bot classes. + +> `discord.Client` - Contains only events. +> +> `discord.Bot` - Subclasses `discord.Client`, adds commands. +> +> `discord.ext.commands.Bot` - Subclasses `discord.Bot`, adds prefixed commands, cogs, and more. + +This means that `discord.ext.commands.Bot` has both slash commands and prefixed commands, as well as +events, cogs and more. + +Now let's look at the syntax. + +```python title="A Simple Prefixed Bot" +import discord +from discord.ext import commands # Import the commands extension +# discord.ext.commands are not the same as discord.commands! + +intents = discord.Intents.default() #Defining intents +intents.message_content = True # Adding the message_content intent so that the bot can read user messages + +bot = commands.Bot(command_prefix="!", intents=intents) # You can change the command prefix to whatever you want. + +@bot.command() # This is the decorator we use to create a prefixed command. +async def ping(ctx): # This is the function we will use to create the command. + await ctx.send("Pong!") # This is the response the bot will send. + + +bot.run("token") # Run the bot with your token. +``` + + + + !ping + + + Pong! + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The help command is a built-in command and is enabled by default. You will learn more about it in the +following guides. + +::: + +## Parameters + +Prefixed commands can take parameters, just like slash commands. You can specify the parameters in +the function itself. + +```python title="Parameters Example 1" +@bot.command() +async def echo(ctx, *, message): + await ctx.send(message) +``` + +`ctx` is the context of the message. `*` means that the parameter can be any number of words. `message` +is the parameter. If you had not passed `*`, `message` would only have been one word. + +For example, if a user had used `!echo hello world`, `message` would have been `hello`. Since we +passed `*`, `message` is `hello world`, or the rest of the message. + +We can pass multiple parameters too! + +```python title="Parameters Example 2" +@bot.command() +async def echo(ctx, channel:discord.TextChannel, title, *, message): + await channel.send("**{}**\n{}".format(title, message)) +``` + +In the example above, `channel` is a parameter that is of type `discord.TextChannel`. When you +specify the type of the parameter, Pycord will automatically try to convert the parameter to that type. +That is why you can use `channel.send` directly without needing to convert it first. + +We also have a new parameter, `title`. This does not have a type, so it will be a string. `*` means +that the rest of the message belongs to the next parameter, in this case, `message`. + +When a user types `!echo #general Greetings! Hello World!`, `channel` will be the text channel +`#general`, `title` will be `Greetings!` and `message` will be `Hello World!`. + +Let's take an example where the user passes `!echo #general Holiday Greetings! Greetings to you all!`. +Here, the user wants the title to be "Holiday Greetings!" and the message to be "Greetings to you all!". +However, since Pycord parses the message at whitespaces, the title will end up being "Holiday" and the +message "Greetings! Greetings to you all!". The user can prevent this by typing `!echo "Holiday +Greetings!" Greetings to you all!`. + + + + + + !echo #general Holiday Greetings! Greetings to you all! + + + Holiday +
+ Greetings! Greetings to you all! +
+ + !echo #general "Holiday Greetings!" Greetings to you all! + + + Holiday Greetings! +
+ Greetings to you all! +
+
+ +Let's check out another example for parameters and parameter types. + +```python title="Parameters Example 3" +import random + +@bot.command() +async def gtn(ctx, guess:int): + number = random.randint(1, 10) + if guess == number: + await ctx.send("You guessed it!") + else: + await ctx.send("Nope! Better luck next time :)") +``` + +If you had not specified the type of the parameter, it would have been a string. And since `"5"` is not +the same as `5` in python, the bot would have responded with "Nope! Better luck next time :)". +Even if you do not specify the type of the parameter, you can still convert it later on, in this case, +with `int(guess)`. + +:::info Related Topics + +- [Command Groups](groups) +- [Rules and Common Practices](../../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json new file mode 100644 index 00000000..baeba701 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Pages", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx new file mode 100644 index 00000000..be90b035 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx @@ -0,0 +1,168 @@ +--- +title: Paginator Basics +--- + +# Paginator Basics + +## [Page](https://docs.pycord.dev/en/stable/ext/pages/index.html#page) + +This class contains two attributes: `content` and `embeds`, which correspond to the attributes of the same name on the +`discord.Message` class. +To create a new Page, use the following syntax: + +```py +import discord +page = Page(content="My Page Content", embeds=[discord.Embed(title="My First Embed Title")]) +``` + +## [PageGroup](https://docs.pycord.dev/en/stable/ext/pages/index.html#pagegroup) + +This class represents a group of pages. It uses most of the same parameters as `Paginator`, which allows each +`PageGroup` to effectively have its own settings and behaviours. + +## [Paginator](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator) + +This is the main class for `ext.pages`, and is used to control most of the functionality of the extension. + +In its most basic form, with no arguments provided (default values listed below), a paginator can be created like so: + +```py title="Paginator Example" +import discord +from discord.ext.pages import Paginator, Page + +my_pages = [ + Page( + content="This is my first page. It has a list of embeds and message content.", + embeds=[ + discord.Embed(title="My First Embed Title"), + discord.Embed(title="My Second Embed Title"), + ], + ), + Page( + content="This is my second page. It only has message content.", + ), + Page( + embeds=[ + discord.Embed( + title="This is my third page.", + description="It has no message content, and one embed.", + ) + ], + ), +] +paginator = Paginator(pages=my_pages) +``` + +The only required parameter for `Paginator` is the `pages` parameter, which is usually a list of `Page` objects. + +You can also pass in a list of `PageGroup` objects, a list of strings, a list of embeds, or a list of lists of embeds. + +Once the `Paginator` instance is created, you can call either +[`Paginator.send()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.send) +or [`Paginator.respond()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.respond) +to send a message or response with the paginator's contents. + +#### Depending on what's being passed to the `pages` parameter, the behaviour of the paginator may differ: + +- Passing a list of `PageGroup` objects will essentially treat each `PageGroup` as its own Paginator, with most + `Paginator` attributes able to be set independently for each `PageGroup`. + \- Each `PageGroup` accepts its own `pages` parameter, which inherits the same behaviour as the `pages` parameter + of `Paginator`, except it cannot contain other `PageGroup` objects. +- If a page is a `Page` object, this will allow you to specify both the `discord.Message.content` and + `discord.Message.embeds` attributes for a page. + \- **This is the preferred method of defining a page.** +- If a page is a string, this will be used for the `discord.Message.content` attribute. This type of page cannot have + any embeds. +- If a page is a list of embeds, this will be used for the `discord.Message.embeds` attribute. This type of page + cannot have any message content. +- If a page is a list of lists of embeds, each parent list item will create a page containing all embeds from its + child list. This type of page cannot have any message content. + +#### Parameters for the `Paginator` class which have default values: + +- `show_disabled` **:** `True` + - Show buttons that are disabled (i.e. can't be clicked) +- `author_check` **:** `True` + - Only the author can interact with the paginator. +- `timeout` **:** `180` _(seconds)_ + - The paginator will time out and become inactive after this many seconds. +- `disable_on_timeout` **:** `True` + - If the paginator times out, it will be automatically disabled and all buttons will be unusable. +- `use_default_buttons` **:** `True` + - Use the default set of 4 buttons and a page indicator. +- `show_indicator` **:** `True` + - When using the default buttons, shows a middle 5th button with the current/total page numbers. + +**For other parameters that can be set on initialization, please check the +[API Reference](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator)** + +## [PaginatorButton](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatorbutton) + +This class represents a button used to navigate between the pages of a paginator. It's also used to create the page +indicator. + +When creating your own custom buttons, you can either use this class directly or subclass it to add any additional +functionality you may need. + +To add custom buttons to the paginator instead of the default navigation buttons, you have two options to do so: + +1. **Using the `custom_buttons` parameter of `Paginator`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + buttons = [ + PaginatorButton("first", label="<<-", style=discord.ButtonStyle.green), + PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), + PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True), + PaginatorButton("next", label="->", style=discord.ButtonStyle.green), + PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), + ] + paginator = Paginator( + pages=["Page 1", "Page 2", "Page 3"], + show_indicator=True, + use_default_buttons=False, + custom_buttons=buttons, + ) + ``` +2. **Using `Paginator.add_button()`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"], use_default_buttons=False) + paginator.add_button(PaginatorButton("prev", label="<", style=discord.ButtonStyle.green)) + paginator.add_button(PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True)) + paginator.add_button(PaginatorButton("next", label=">", style=discord.ButtonStyle.green)) + ``` + +If you want to use the default navigation buttons, but not all of them, you can also use `Paginator.remove_button()` to +selectively remove them: + +```py +from discord.ext.pages import Paginator + +paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"]) +paginator.remove_button("first") +paginator.remove_button("last") +``` + +## [PaginatorMenu](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatormenu) + +This class represents the `discord.Select` menu used to navigate between `PageGroup` instances. In most situations, you +will not need to interact with this class directly. + +If you do subclass it, you'll likely want to call `super()` in your `__init__` method to ensure that the `PageGroup` +navigation functionality is retained. + +## Usage Examples + +For a comprehensive list of examples showing all `Paginator` functionality, please see the +[example in cog form](https://github.com/Pycord-Development/pycord/blob/master/examples/views/paginator.py) in the repo. + +## Support and Feedback + +If you have any questions, suggestions, or feedback for `ext.pages`, please join the +[Discord server](https://discord.gg/pycord). diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx new file mode 100644 index 00000000..b8d68925 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx @@ -0,0 +1,20 @@ +--- +title: Paginator FAQ +--- + +# Paginator FAQ + +- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** + - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. + - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. + +- **How can the bot send a paginator to a different destination than where it was invoked?** + - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. + - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. + - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. + +- **How can I change the paginator's behavior without re-creating and re-sending it?** + - Use the `Paginator.update()` method. + +- **How can I make the bot actually do something with the contents of a page?** + - Use the (upcoming) `Paginator.page_action()` method. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json new file mode 100644 index 00000000..36dfb009 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Tasks" +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx new file mode 100644 index 00000000..848f6066 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx @@ -0,0 +1,216 @@ +--- +title: Tasks +--- + +## Concept + +So you want to run a background task running at some specified interval? Thankfully, that's a common thing to do, whether you're working with some API or handling some background logic don't worry, the Pycord tasks extension is here to make life easier for you! + +With the tasks extension, you can make background tasks without worrying about the asyncio hell and mind bogglers like "what if my internet dies" and "how do I handle reconnecting" with the added benefit of a lot of useful additions that are one line of code away! + +### Example Usage + +```py +import discord +from discord.ext import tasks + +bot = discord.Bot() + +@bot.event +async def on_ready(): + very_useful_task.start() + +@tasks.loop(seconds=5) +async def very_useful_task(): + print('doing very useful stuff.') + +bot.run("TOKEN") +``` + +If you do run this code in your terminal you should see something like this after about 15 seconds: + +``` +doing very useful stuff. +doing very useful stuff. +doing very useful stuff. +``` + +For a more useful example here's a task in a cog context ripped straight from the [docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#recipes): + +```py +from discord.ext import tasks, commands + +class MyCog(commands.Cog): + def __init__(self): + self.index = 0 + self.printer.start() + + def cog_unload(self): + self.printer.cancel() + + @tasks.loop(seconds=5) + async def printer(self): + print(self.index) + self.index += 1 +``` + +As you'd expect this will increment a number and print it out every 5 seconds like so: + +```sh +0 +# 5 seconds later +1 +# 5 more seconds later +2 +# ... +``` + +## [Tasks](https://docs.pycord.dev/en/stable/ext/tasks/index.html) + +Now let's get into the nitty-gritty of tasks. + +As you've seen tasks can work in both outer scope and class contexts and the handle is roughly the same, you define a task using the `tasks.loop` decorator and use the `start` method to start it, the difference is you add the `self` argument when in a class context so since most people have all their bot's code in Cogs all the following code blocks will be in a Cog context to make it easy to copy it then apply whatever modifications you might need! + +### [Creating a task](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop) + +A look at `discord.ext.tasks.loop`'s definition in the documentation reveals that: + +1. As you've seen before it expects the time between each execution, that however doesn't have to be in seconds as + there are `seconds`, `minutes` and `hours` parameters to make it easier for us, they can also be floats in case you want + ultra-precision. +2. You can also pass in a `datetime.time` object or a sequence of them in the `time` parameter which will make it run + at the specified time(s). +3. You can pass in how many times a loop runs before it stops by passing in the `count` parameter, you can use `None` + to make it run forever which is also the default. +4. The loop function **_must_** be a coroutine. + +These are all really useful, and they aren't the only parameters so if you want to know more about them check out the +[docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop)! + +### Attributes + +A task has the following attributes: + +- `current_loop`: The current loop the task is on. +- `hours`, `minutes`, `seconds`: attributes that represent the time between each execution. +- `time`: A list of datetime.time objects that represent the times the task will run, returns `None` if no datetime + objects were passed. +- `next_iteration`: A `datetime.datetime` object that represents the next time the next iteration of the task will + run, can return `None` if the task stopped running. + +These attributes serve as a really powerful asset to get info about your loop. + +### Example + +Now let's create a cog that handles a leaderboard we have in our bot using Tasks then explain what we did after that and +also provide a refresher of how slash commands groups work in cogs. + +For the sake of this example let's pretend that we have a leaderboard module that does all the leaderboard handling for +us and that computing the leaderboard is very expensive computationally wise, so we want to store one version of it that +gets regularly updated instead of generating it every time someone calls the `/leaderboard view` command. + +```py +from discord.ext import tasks, commands +from discord.commands import SlashCommandGroup, CommandPermissions + +from leaderboard import * # Mock leaderboard module. + +class LeaderboardCog(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.update_leaderboard.start() + self.leaderboard_embed = generate_leaderboard_embed() + + leaderboard = SlashCommandGroup(name='leaderboard', description='Leaderboard commands.') + + @tasks.loop(minutes=10) + async def update_leaderboard(self): + print('Updating leaderboard...') + await update_leaderboard() + self.leaderboard_embed = generate_leaderboard_embed() + + @update_leaderboard.before_loop + async def before_update_leaderboard(self): + await self.bot.wait_until_ready() + print("About to start updating leaderboard.") + + @update_leaderboard.after_loop + async def after_update_leaderboard(self): + leaderboard_cleanup() + print("Stopped updating leaderboard.") + + @update_leaderboard.error + async def update_leaderboard_error(self, error): + print(f"Oh no, an error occurred while updating the leaderboard. Error: {error}") + + @leaderboard.command() + async def view(self, ctx): + await ctx.respond(embed=self.leaderboard_embed) + + @leaderboard.command() + async def update_info(self, ctx): + await ctx.respond(f"""***Leaderboard Info***\n + Last update: {(600 - self.update_leaderboard.next_iteration.timestamp())//60} minutes ago.\n + Next update: in {self.update_leaderboard.next_iteration.timestamp() // 60} minutes.\n + Time between loops: {self.update_leaderboard.minutes} minutes.\n + Times updated this session: {self.update_leaderboard.current_loop}. + Running? {self.update_leaderboard.is_running()} + Failed? {self.update_leaderboard.failed()}""", ephemeral=True) + + # Now for the owner only commands: + + leaderboard_config = SlashCommandGroup(name="leaderboard_config", description="Leaderboard configuration commands", permission=[CommandPermissions("owner", 2, True)]) + + @leaderboard_config.command() + async def set_time_between_updates(self, ctx, minutes: int): + self.update_leaderboard.change_interval(minutes=minutes) + await ctx.respond(f"Set time between updates to {minutes} minutes.") + + @leaderboard_config.command() + async def stop(self, ctx): + self.update_leaderboard.stop() + await ctx.respond("Stopped the leaderboard update.") + + @leaderboard_config.command() + async def restart(self, ctx): + self.update_leaderboard.restart() + await ctx.respond("Restarted the leaderboard update.") + +def setup(bot): + bot.add_cog(LeaderboardCog(bot)) +``` + +Phew, that was quite a bit of code. + +Now to explain what's going on: + +First things first we create a cog and in its `__init__` function we start the `update_leaderboard` task and generate +the first instance of our leaderboard's embed. + +After that, we define the `update_leaderboard` task using the `loop` decorator, and we make it run every ten minutes by +passing 10 to the `minutes` parameter. + +Then that we define the `before_update_leaderboard` task using the `before_loop` decorator, and we make it wait until the +bot is ready before starting the task. + +Next up we define the `after_update_leaderboard` task using the `after_loop` decorator, and we make it clean up the +leaderboard when the loop finally stops running. + +Then we define the `update_leaderboard_error` task using the `error` decorator, and we make it print any errors that may +occur while we update our leaderboard to the console. + +Then we get into the fun stuff, we create a slash command group using the `SlashCommandGroup` class and name it +`leaderboard`, we then create the `view` sub-command which sends the embed generated when the leaderboard is updated and +`update_info` which shows a lot of data about the task using some attributes and functions available to us. + +We also create a slash command group called `leaderboard_config` which is only available to the owner of the bot. + +Then we create the `set_time_between_updates` sub-command which takes in the time in minutes and changes the time +between updates of the leaderboard using the `change_interval` method, the `stop` sub-command which stops the task using +the `stop` method and `restart` which restarts the task using the `restart` method. + +Finally, we add the `LeaderboardCog` cog to the bot, and we're done! + +I'd highly recommend you check the tasks extension +[documentation](https://docs.pycord.dev/en/stable/ext/tasks/index.html) for more info on how to use them and what other +functions they have. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/_category_.json new file mode 100644 index 00000000..9d6255f5 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 3, + "label": "Getting Started", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx new file mode 100644 index 00000000..864206a6 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx @@ -0,0 +1,262 @@ +--- +title: Creating Your First Bot +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +Excited to create your first bot? Once you [install Pycord](../installation.mdx), you can start right +away! + +## Creating the Bot Application + +Just like how you need to sign up to use Discord, your bot also has to be signed up. To do this, +you should: + +1. Go to the [Discord Developer Portal](https://discord.com/developers/applications) and click + on . +2. Give your bot a name, and click . +3. Now, you should see a page like this. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdW3OQnwUhacopqSWw%2F-Mjd_-mxrJCrzmaXrAg8%2Fimage.png?alt=media&token=b8e2ae6c-2290-4d37-ad7c-eb412f3fb00e) +4. Click on the tab on the left side of the screen. +5. Click on . +6. You can give it a name, change the Avatar, etc. + +## Inviting the bot + +Now, lets get the bot added to some servers. Go to the tab +in the left pane and select `bot` and `applications.commands` as scopes. + +You may want your bot to have application commands, which is what the `application.commands` scope +allows your bot to make. + +Next, you want to choose what permissions the bot will have and select them. For now, you can just +give your bot the `administrator` permission, which gives your bot every permission. Once you select +your bot's permissions, click on to get the bot invite link. + +:::tip + +When your bot is all ready to go, make sure that administrator permissions aren't selected unless +your bot truly needs them. Try selecting only permissions the bot will need. For testing, +Administrator permissions are fine. + +::: + +![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-Mk6tNY3LfDkjd6pqdpL%2F-Mk6tkdpddEWoa2jczZk%2Fimage.png?alt=media&token=52c8a29f-a798-48f8-a8c7-4ecca2681f79) + +You can use this link to invite the bot. + +## Tokens + +Now that you have an account for your bot, you need to log in. To log in, we need the bot's +password. All users and bots have a "token." You may think of this token as a password, as this allows +us to log our bot into Discord. + +Tokens are "snowflakes." Not actual snowflakes, though. Just like how no two snowflakes in real life have the same +pattern, snowflakes in computers are unique things - no two bots have the same token - so a token is +considered a snowflake. A Discord user ID is also a snowflake. + +Now, lets get your bot's token. To do this, you want to: + +1. Go back to the tab. +2. Click on the button in the "Token" section. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdbU12JISJorAZxrKH%2F-MjdbpUsapzb5n15Po5P%2Fimage.png?alt=media&token=118e259f-940a-4f6c-b3a3-c29f3a54100d) + +Now, you have your bot's token copied to your clipboard. + +:::danger + +Do not, under any circumstances, give your token to anyone. Even if you are contacted by someone +claiming to be Discord staff, do not give them your bot's token. They are lying to you to try and +gain access to your bot. If an unauthorized user gains access to your bot's token, they can access +your bot and use it in malicious ways. + +Never push your token to GitHub or include it in your code. One way to prevent your token from +getting leaked is to store it in `.env` files. + +::: + +### Protecting Tokens + +#### Using dotenv + +You can store your tokens in `.env` files. This is a simple way to store sensitive information. + +1. Create a file with the name `.env` (only the extension, with a dot/period at the start and without a name before it). +2. Define the token in the `.env` file (replace the example value with your token). + ```env title=".env" + TOKEN = NzkyNzE1NDU0MTk2MDg4ODQy.X-hvzA.Ovy4MCQywSkoMRRclStW4xAYK7I + ``` +3. Install [`python-dotenv`](https://pypi.org/project/python-dotenv/). + ```bash + python -m pip install python-dotenv + ``` +4. Load the token from the `.env` file. + ```python + import dotenv + dotenv.load_dotenv() + token = str(os.getenv("TOKEN")) + ``` +5. Pass your token as parameter when running the bot. + ```python + client.run(token) + ``` + +:::tip + +If you are using Git to track your bot's changes, you should create a file called `.gitignore` and add +`.env` to it. This stops your `.env` file from getting tracked along with the rest of your code, and +will not be pushed to a remote Git repository. As a consequence, it will stay secure on your local machine. + +::: + +## Coding the Basics + +Here's an example of code you'll write with Pycord: + +```py +import discord +import os # default module +from dotenv import load_dotenv + +load_dotenv() # load all the variables from the env file +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") + +bot.run(os.getenv('TOKEN')) # run the bot with the token +``` + + + +
+ + hello + +
+ Hey! +
+
+
+ +Let's go through the code. First, the imports. + +```py +import discord +import os +from dotenv import load_dotenv +``` + +In the first line, `import discord`, we import Pycord. Although you install Pycord with `pip install py-cord`, you +import it with `import discord`. This is so it's as easy as possible when switching from Discord.py to Pycord. + +We then import `os` and `dotenv`. `os` is a default module that we will use to get the token from the env file. `dotenv` +is a module that we will use to load the env file. You installed this with `pip install python-dotenv`. + +Next, we load the env file with `load_dotenv()`. + +```py +bot = discord.Bot() +``` + +In this line, we create a new instance of [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). +In this object, we can pass various parameters for configuration purposes, such as `owner_ids` +and [`intents`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```py +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") +``` + +We use the [`event`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) decorator to override +the [`on_ready`](https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready) function to define an +event that is automatically called when the bot is ready to use. + +```py +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") +``` + +Here, we use the [`slash_command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.slash_command) +decorator to define a slash command. We specify the `name` and `description` arguments. If not +specified, the name of the slash command would be the function name and the command description would +be empty. + +Optional: We type-hint the context parameter (`ctx`) as [`discord.ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext). In modern IDEs, type-hinting allows access to autocompletion and docstrings. You can read more about type-hinting [here](https://docs.python.org/3/library/typing.html). + +Finally, you want to run the bot using the token specified in the `.env` file. + +Now you have finished creating your first Pycord bot! What we have shown you is just the basic structure +of a bot. You can do a lot more with Python and Pycord knowledge, as well as your imagination! Pycord +will not limit your bot's abilities. + +:::note + +The part where we load the token from the environmental variables is not required. You may use another way to keep your token secure, or, although not recommended, simply specify the token normally as a string, as shown below. + +
+A Basic Bot without securing the token +
+ +```py +import discord + +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.send("Hey!") + +bot.run("TOKEN") +``` + +
+
+ +::: + +## FAQ + +### How do I make prefixed commands? + +Prefixed commands are an older method of creating bot commands that listen for messages and replies +if the message starts with a certain character. You can read [this page](../extensions/commands/prefixed-commands.mdx) +to learn more about prefixed commands. + +### How do I setup modules/cogs? + +[Cogs](../popular-topics/cogs) are a great way to organize your commands by putting them into +groups called cogs. Cogs are separate files that your bot loads to get the commands inside. +You can read more about cogs, as well as learn how to use them and their benefits, +[here](../popular-topics/cogs). + +### How do I add components, such as buttons and dropdown menus, to my bot? + +Pycord makes it very easy to use Message Commands with your bot by using the `discord.ui` module. +To learn more, read about Message Commands in our [interactions directory](../interactions). + +:::info Related Topics + +- [Prefixed Commands](../extensions/commands/prefixed-commands) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx new file mode 100644 index 00000000..2a68677b --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx @@ -0,0 +1,109 @@ +--- +title: Hosting Your Pycord Bot +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Hosting Your Pycord Bot + +If you're completely new to this, you might have thought something along the lines of "Yay! I got my +bot working," after following our [Creating your First Bot](creating-your-first-bot) guide, only +to close your IDE or shut down your computer to find your bot offline. + +The reason for this is that programs have to be hosted somewhere, meaning some machine somewhere has +to constantly run your bot. There are tons of hosting services that can help you host your bot for +little to no cost. + +## Can I get a Clear Explanation? + +Sure thing. When you run your bot, it first makes a connection to Discord's API. Once that's done, +Pycord sends "heartbeats" to Discord. "heartbeats" are small packets sent at a set interval telling +Discord that your bot is indeed still alive. If Discord doesn't receive a heartbeat after a certain +amount of time, your bot is pronounced dead and buried in the graveyard (not really). It is, though, +taken offline and its connection with Discord is terminated. + +Once you close the terminal that you've run your program on, the program is no longer running, and +the bot stops sending heartbeats and can no longer process commands. This is why you have to constantly +keep the process running. + +This goes for all programs, in a different nature. If the code isn't compiled/built/assembled/interpreted, +it can't be running. + +## What is a Host? + +A host is a server or container for running code offered by a **hosting provider.** There are a lot +of hosting providers, such as bigger ones like Amazon Web Services (AWS) and Google Cloud, and smaller +ones like GalaxyGate and DigitalOcean. + +There are three types of hosts. + + + + Shared hosting is a type of hosting where multiple people share one VPS. Getting a spot on + a shared host is usually cheap, sometimes even free. Shared hosts do not give you a lot of + resources, from less than a gigabyte of RAM (usually 512MB on free hosts) and half of a CPU + with very little storage. Shared hosting is usually used for website hosting and is not + recommended for hosting a Discord bot. + + + A virtual private server (VPS) is a virtual computer (virtual machine) that is rented out to + customers. Most people use a VPS for hosting their projects such as Discord bots. You can get + anywhere from less than a gigabyte of RAM and a less powerful CPU to just under one hundred + gigabytes of RAM, a (or multiple) powerful CPU(s), and a fair amount of storage. A VPS is the + best choice for most users and can be fairly cheap. + + + A dedicated host is a physical computer. You can buy these yourself or rent one from a hosting + provider. Dedicated hosts are often very expensive, but are also very powerful, having a + few hundred gigabytes of RAM and a few very powerful CPUs, along with a good amount of storage. + Dedicated hosts are usually used for very large projects and are overkill for something like + a Discord bot. + + +
+ +:::danger + +Make sure you choose a hosting provider you trust. Also make +sure the hosting provider you're looking at has good reviews on public forums. Googling along the +lines of "[host] review" should do the trick. A provider you don't trust can compromise your token. + +::: + +Most hosting providers rent their services to you for a monthly or yearly fee. These can be anywhere +from a few dollars to hundreds or thousands of dollars. + +## How to Host Your Bot + +Once you rent or buy a VPS, you can get to work. Most hosting providers allow you to choose from a +wide range of operating systems, most allow you to choose one but some allow you to choose +multiple. Once that's ready, you have to SSH into the system. We won't get into SSH here, but you can +read [this article from DigitalOcean](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys). +You can also use VNC, which is remote desktop software. If you are using an OS that does not have a +GUI, and is only a command line (a "server" OS), such as Ubuntu Server or most Linux Server Operating Servers, you will most +likely use SSH. If you are using an OS that has a GUI, such as Windows Server, you will most likely use VNC. + +Once you've decided on your operating system, you'll want to set it up and install Python. Once that's +done, you can copy your bot's files to your remote system, install the required packages, and run +the bot. + +:::warning + +If you are using SSH to run the file, your bot will not stay running. This is because the file is +only told to run during your session. You can use a command like [nohup](https://en.wikipedia.org/wiki/Nohup) +to make sure your file stays running after you disconnect. + +::: + +Now your bot is hosted, but that doesn't mean it can't go offline. If your bot encounters an error, +it can often go offline or stop its process. For this, make sure you have proper error handling. +Also be sure to pay attention to your hosting provider's updates or news, as they usually notify +users of when they plan on doing maintenance to their servers, making their services unavailable for +a short time. + +:::info Related Topics + +- [Creating Your First Bot](creating-your-first-bot) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx new file mode 100644 index 00000000..ee6b9417 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx @@ -0,0 +1,379 @@ +--- +title: More Features +description: More features to make your bot cool and snazzy. +--- + +import { + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, + DiscordEmbedField, + DiscordEmbedFields, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +So, you just created your first Pycord bot! Now, let's add some more features to it. This will include adding event handlers, waiting for user response, styling the messages, and more. + +## Events + +### Event Handlers + +Events in Discord are a way to listen for certain actions. For example, if you want to know when a user joins your server, so you could send a welcome message, you can use the `on_member_join` event. + +First, you need to ask Discord to send you events. This is done via "Intents". Read up the [Intents](../Popular-Topics/intents) page for more information. + +Once you understand what intents are, you can enable the events you need, or just use the default ones with `discord.Intents.all()`. + +Now that that's done, let's add an event handler for when a user joins the server. We will use the [`on_member_join` event](https://docs.pycord.dev/en/stable/api/events.html#discord.on_member_join). We will send a private message to the user welcoming them to the server. + +```python +@bot.event +async def on_member_join(member): + await member.send( + f'Welcome to the server, {member.mention}! Enjoy your stay here.' + ) +``` + +We use the [`discord.Bot.event` decorator](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) to add the event handler. + +The `on_member_join` event is called when a user joins the server. The `member` parameter is the user that joined. Different events have different names and parameters. You can find all of them [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +So, that's how you add event handlers! + +### Waiting for User Response + +Let's say you want to create a Guess-the-Number game (where the user has to guess a number between 1-10). You need to send a message to a user and wait for them to respond. You can do this with the [`wait_for`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.wait_for) method. + +```python +@bot.command() +async def gtn(ctx): + """A Slash Command to play a Guess-the-Number game.""" + + await ctx.respond('Guess a number between 1 and 10.') + guess = await bot.wait_for('message', check=lambda message: message.author == ctx.author) + + if int(guess.content) == 5: + await ctx.send('You guessed it!') + else: + await ctx.send('Nope, try again.') +``` + +`wait_for` takes one argument, which is the event type. The event type is the name of the event you want to wait for. In this case, it's `message`. It could also be `reaction` to wait for a reaction to be added. + +We pass a keyword argument to `wait_for` called `check`. The function may look complicated if you're a beginner. We pass a `lambda` function, which simplifies the code a bit. + +The lambda function takes one parameter, `message`. When Pycord receives a message, it passes it to the `check` function. If the function returns `True`, the message is returned. If the function returns `False`, the message is ignored and the bot waits for another message. + +Here, we check if the message is from the user that sent the command. We simply use `message.author == ctx.author`. This will check if the author of the message was the person who invoked the command. + +## Styling Messages + +### Embeds + +Embeds are a Discord feature that allows applications to format their messages in cool embedded format, +enabling your bot to lay out messages with a lot of text into neat fields. + + + + + The Pycord Guide is a detailed guide that explains how to use Pycord and all of its features. + + + The Getting Started section explains how you can get a brand new bot created and running from scratch. + + + Interactions with Pycord + + + Pycord's various Extensions + + + Other Popular Topics + + + We have so much more! Just explore, and you will find everything you need. If you want another page added, open an issue on the GitHub. + + + Created with 💖 by the Pycord Team & Contributors + + + + +
+ +Creating embeds is simple! Just create an instance of [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) and edit it to your liking. Once you're done, send it! + +```python +import discord + +bot = discord.Bot() + +@bot.command() +async def hello(ctx): + embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from + ) + embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") + + embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) + embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) + embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) + + embed.set_footer(text="Footer! No markdown here.") # footers can have icons too + embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") + embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") + embed.set_image(url="https://example.com/link-to-my-banner.png") + + await ctx.respond("Hello! Here's a cool embed.", embed=embed) # Send the embed with some text + +bot.run("TOKEN") +``` + + + +
+ hello +
+ Hello! Here's a cool embed. + + Embeds are super easy, barely an inconvenience. + + + A really nice field with some information. The description as well as the fields support markdown! + + Inline Field 1 + Inline Field 2 + Inline Field 3 + + Footer! No markdown here. + +
+
+ +
+ +This simple command sends replies to a [slash command](../interactions/application-commands/slash-commands) with an embed. +Let's break it down: + +```py +embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), + ) +``` + +This command creates an embed. We use the [`Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) +class to create an embed object with the title "My Amazing Embed", the description "Embeds are super easy, barely an inconvenience.", and the color `blurple`, Discord's main theme color. + +[discord.Colour](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Colour) is a class full of [classmethods](https://docs.python.org/3/library/functions.html#classmethod) +that return color values. While the official, documented name of this is `discord.Colour`, `discord.Color` +works as well. + +```py +embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") +embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) +embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) +embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) +``` + +This small section shows off embed fields. You can add fields to embeds with the [`add_field` method](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.add_field) +of the [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) class. These consist of three +keyword arguments: `title`, `value`, and `inline`. `title` and `value` are both required arguments, which inline defaults to `False` if it's not defined. The `inline` argument specifies whether space will be divided among the inline fields. There could be a mix of fields where inline has different values too. + +```py +embed.set_footer(text="Footer! No markdown here.") # footers can have icons too +embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") +embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") +embed.set_image(url="https://example.com/link-to-my-banner.png") +``` + +In this section, we're adding unique items to the embed. These items are: + +- Footer - With the [`set_footer()`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_footer) + method, you can set a small footer that holds a message. This has `text` and `icon_url` kwargs. +- Author - With the [`set_author`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_author) + method, you can set an author for the embed. This is a small text field at the top of the embed. This + includes `name`, `url` and `icon_url` kwargs. +- Thumbnail - With the [`set_thumbnail`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_thumbnail) + method, you can set a small image to reside at the top-right of the embed. This has a single `url` kwarg. +- Image - With the [`set_image`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_image) + method, you can set an image to sit at the bottom of an embed. This has a single `url` kwarg. + +There are a lot more methods and attributes you can use to configure embeds. Here, we just covered the basics. Also, remember that all of these values are not necessary in an embed. An embed may only contain a few of these. For example, only a description, a title and a description, and so on. + +### Markdown + +Markdown is a type of markup language that's limited in terms of formatting yet simple. Discord allows +for a watered-down version of markdown to be in their messages. + +#### Text Markdown + +Text formatting can be used in messages and in most embed parts, +as explained in the dedicated section below. + + + + + + + + + + + + + + + + + + + + +
*italics*__*underlined italics*__
**bold**__**underlined bold**__
***bold italics***__***underlined bold italics***__
__underlined__~~strikethrough~~
+ +#### Code Markdown + +To create a single-line code block without syntax highlight, wrap the text between single backticks. +This code block will only add a dark background to the text. + +``` +`print("Hello world!")` +``` + +To create a multi-line code block without syntax highlight, wrap the text between triple backticks +on first and last line. This type of code block will encase the code inside a box. + +```` +``` +message = "Hello world!" +print(message) +``` +```` + +To create a multi-line block with syntax highlight, add the name of the language you are using right after +the triple backticks on the first line. For example, for Python you can write either "python" or "py". + +```` +```python +message = "Hello world!" +print(message) +``` +```` + +If you want to use syntax highlight for a single line of code, you still have to format it +like a multi-line block but the code must be on a separate line than the triple backticks. + +#### Quote Markdown + +To create a single-line quote block, start the line with `>` followed by a space. + +``` +> This is a single-line quote. +``` + +To create a multi-line quote block, write `>>>` followed by a space. All text +from that point onwards will be included in that quote block. + +``` +>>> This is a +multi-line quote. +``` + +#### Spoiler Markdown + +To hide a spoiler, encase the text between double pipes. The users +will have to click on it before being able to see the text contained in it. + +``` +||spoiler|| +``` + +#### Link Markdown + +Link formatting only works in embeds and messages sent through webhooks, +by using the following syntax: + +``` +[Pycord](https://pycord.dev/) +``` + +Inside the supported elements that have just been mentioned, +the example above will look like this: [`Pycord`](https://pycord.dev/) + +Outside them, the link will still be clickable but the formatting will be ignored, +therefore the example above will look similarly to this: `[Pycord](https://pycord.dev/)` + +#### Embed Markdown + +Adding markdown to your embeds or messages will give your bot the sparkle it needs, +however, markdown is limited inside embeds. Use the following table as a reference +and keep in mind that embed title and filed names will always show in **bold**. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PartTextLink
Embed AuthorNoNo
Embed TitleYesNo
Embed DescriptionYesYes
Field NameYesNo
Field ValueYesYes
Embed FooterNoNo
diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx new file mode 100644 index 00000000..e44b7c49 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx @@ -0,0 +1,184 @@ +--- +title: Rules and Common Practices +description: All about the rules and common practices for coding a Discord bot +--- + +# Rules and Common Practices of Creating a Bot + +When creating almost anything, there's always a certain set of rules to follow or common practices, +such as [PEP8](https://www.python.org/dev/peps/pep-0008/) for Python. This applies to creating bots +with Pycord as well. + +:::note + +Most of these rules and common practices are only applicable for +[verified bots](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting), +but it's good to follow them nonetheless. + +::: + +## Rules + +There are rules for creating bots, and most of these are required by Discord themselves, not us at +Pycord. Not following these rules may get your bot denied for verification. + +### Terms of Service and Privacy Policy + +Starting at some point in time, Discord has made providing a privacy policy with your bot a requirement. +This is so that Discord knows exactly what you are doing with its users' data. + +:::tip +You don't need a lawyer or anyone special to write out a privacy policy for you, nor do you need +it approved by some official entity. Simply writing out how you are going to use Discord user +information neatly is all you need to do. +::: + +Providing a Terms of Service for your bot is optional, though usually a best practice. It tells users +what they can and cannot do with your service, and makes it easier to settle disputes if someone +disagrees with you. + +Read more in Discord's official [Legal Docs](https://discord.com/developers/docs/legal). + +### Developer Policy + +We could list almost every rule about using Discord's API here. _Or_ we could simply link Discord's +Developer Policy to make it easier on us. You can find Discord's Developer Policy +[here](https://discord.com/developers/docs/policy). This outlines what you can and cannot do with +Discord's Developer API. And, don't worry, it's completely readable and understandable. + +## Best Practices + +Now, here's something we _can't_ simply link an article for. We're going to discuss the best practices +of creating a Discord bot with Pycord. + +### Bot Sharding + +To any new or maybe even experienced bot developer, sharding a bot sounds beneficial once you hear +about it. I'm here to tell you that it isn't a good idea to shard your bot. + +_Wait a minute, why would it be an option if it wasn't a good idea?_ It's simple. I lied. Sort of. +I'm not going to go into the details of sharding a bot, so you can read about it on +[this page](../Popular-Topics/sharding). Sharding is the process of taking your bot +and breaking it up into small pieces, so it's easier to perform tasks. This is very useful for large +bots, as it makes them faster and more reliable. Sharding is not a good practice for small bots. + +:::note +Discord will notify you once it is time to shard your bot, and will eventually force you to do so. +::: + +At the very least, wait for one thousand servers to shard your bot. If you shard your bot while it's +small, you'll just be wasting resources and possibly making your bot slower. + +### [Verification](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting) + +Verifying your Discord bot is something every developer would like to achieve. It shows that your bot +is in more than 75 servers. It's generally a good idea to try to get your bot verified as soon as +possible. We're talking at 76 servers soon. This is because Discord can be somewhat slow in terms of +bot verification, so verifying as soon as possible gives them enough time to verify before your bot +reaches the 100 server cap. If a bot is not verified, it cannot grow beyond 100 servers. + +It's also a good idea to only apply for the privileged intents that you need. Applying for intents +your bot doesn't use wastes both your time and Discord's time, as your privileged intent request +will be denied simply because you applied for an intent you didn't need. + +### Subclassing + +While it may take some time, subclassing a bot is very worth it. Once again, this was explained +elsewhere, so I won't go into the details, but I felt it fit here, so I put it here. + +Subclassing a bot makes it more flexible and allows it to do a lot more. Read more about subclassing +bots [here](../Popular-Topics/subclassing-bots) + +### Your Bot's Token + +Your bot is only able to be run for one reason: its token. If you followed the +[guide for creating your first bot](creating-your-first-bot), you should already know a bit about +keeping that token safe. That's exactly what you want to do. + +Sharing your token is never good. If someone evil gets a hold of your token, they can do terrible things, +such as making your bot leave all of its servers, spamming all the members the bot has contact with, +and even manipulating the servers the bot is in, if given the permissions. That's why it's very important +to keep your token safe. To learn how to do so, read [this part](creating-your-first-bot#tokens) of +the Creating Your First Bot guide. + +### Backups + +You always want to back up your bot's data. This includes both its code _and_ its databases. This way, +if something tragic happens, such as your host failing a data migration or you breaking your Raspberry +Pi's SD card that held your bot, you'll still have its precious user data. I have a small program for +my bot that uploads its databases to a remote GitHub repository periodically to not lose any data. +It may be smarter to find a bit more of a reliable way to do so, though. + +Public or private, having a local Git repository connected to a remote one is a good idea for making +almost any application. For a lot of developers, it's like saving your work. If you do this, all of +your bot's code won't be lost if your computer spontaneously combusts, or you smash it to bits from +anger. You can simply grab the backup computer that everyone has lying around, and you're back +in business. + +### Organization and Cleanliness + +It is _extremely_ important to have organized code. This includes commands, objects, functions, +and classes. If you don't have organized code, it will get progressively harder for you to recognize +it, and others won't be able to decipher it. + +Make sure you utilize indents and spaces, as these are very important in making your code readable. + +```py title="Bad Spacing" +class MyClass: + async def add(self,num1,num2): + return num1+num2 + async def sub(self,num1,num2): + return num1-num2 +``` + +```py title="Good Spacing" +class MyClass: + async def add(self, num1, num2): + return num1 + num2 + + async def sub(self, num1, num2): + return num1 - num2 +``` + +See the difference? Now, which one looks more readable? Hopefully, you answered the second example. +Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is a PEP (**Python Enhancement Proposal**) +style guide for Python. It is the style guide that is used by most Python developers and programmers, +providing a universal way to write and read code. + +### Databases + +As your bot grows, you'll inevitably have to store data for your bot. Now, most people would probably just load up some +JSON file on boot into a `dict`, modify it in memory then write to the file. However, JSON files aren't the solution. +When you write to a JSON file, it rewrites the entire file instead of just rewriting the section that changed. It's also +a configuration file format, not a storage file format. + +Instead of using a JSON file or some other related format, you should instead use a database. There are many databases +out there, like MongoDB, SQLite, and PostgreSQL to name a few. + +All of these databases I named do the job well, and which one you use depends on what features you want out of a database. + +<>{/* Maybe clarify these/add more options */} + +#### MongoDB + +MongoDB is a JSON-like format and if you already use JSON files, it shouldn't be too hard to migrate over to. + +#### SQLite + +SQLite is based on SQL, a common relational data model. It's a lightweight, easy-to-use, portable database solution that +works entirely on files. However, if for some reason you cannot read/write to and from a file, and you need to manage +lots of data, SQLite might not be for you. + +While SQLite is a part of the Python Standard Library as the `sqlite3` package, we recommend not using it as it is +synchronous and blocking. You should use an asynchronous alternative, such as [`aiosqlite`](https://pypi.org/project/aiosqlite/). + +#### PostgreSQL + +PostgreSQL is also based on SQL, but it also has more features than SQLite. It's compliant with the SQL standard, +open-source, and extensible. However, it's not that fast or simple compared to SQLite. + +#### MariaDB + +MariaDB is also based on SQL and is a fork of the MySQL project. It's compliant with the SQL standard, it's also open +source and is a complete drop-in replacement for any code with MySQL. You don't even need to change what package you're +using! diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/installation.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/installation.mdx new file mode 100644 index 00000000..521c69cd --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/installation.mdx @@ -0,0 +1,80 @@ +--- +title: Installation +sidebar_position: 2 +--- + +Before you can start using Pycord, you need to install the library. + +:::note +Python **3.8 or above** is required to use Pycord. +::: + +:::tip +Before you start installing python packages globally, it's recommended you set up a virtual environment. +You can find instructions for that [here](More/virtual-environments). +::: + +## Fresh Installation + +To install Pycord, you can use the following command in your terminal: + +``` +pip install py-cord +``` + +:::tip +Remember that you need to install `py-cord`, not `pycord`. +Also, the `pip` command varies depending on your installation. For example, it might be `python3 -m pip` on macOS/Linux or `py3 -m pip` on some versions of Windows. +::: + +If you need voice support for your bot, you should run: + +``` +pip install "py-cord[voice]" +``` + +## Migration + +### Updating Pycord + +If you are upgrading from a previous version of Pycord, you can use the following command in your terminal to upgrade to the latest version: + +``` +pip install -U py-cord +``` + +### Migrating from other libraries + +If you are migrating from another library, say, `discord.py`, first of all, you need to uninstall it. + +``` +pip uninstall discord.py +``` + +Then, you can install Pycord, it's as simple as that!: + +``` +pip install py-cord +``` + +:::caution +Uninstalling `discord.py` _after_ installing `py-cord` can cause issues. Make sure to uninstall it first! +::: + +## Installing Other Builds + +### Development Build + +:::caution +The development build comes with cutting edge features and new functionality, but as it isn't a stable build you may encounter bugs. +::: + +To install the development build, you can use the following command in your terminal: + +``` +pip install -U git+https://github.com/Pycord-Development/pycord +``` + +:::important +Git is required to install this build. [Learn how you can install Git](./more/git). +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/interactions/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/_category_.json new file mode 100644 index 00000000..ea28be60 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 4, + "label": "Interactions" +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json new file mode 100644 index 00000000..6dcafe83 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Application Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx new file mode 100644 index 00000000..b4ffeade --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx @@ -0,0 +1,85 @@ +--- +title: Context Menus +description: Learn all about Context Menus (User Commands & Message Commands) and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +When you right-click a message, you may see an option called "Apps". Hover over it, and you can see +commands a bot can run with that message. These are called message commands. + +When you right-click a user in the user list, you can once again see an option called "Apps". +Hover over it, and you can see commands a bot can run with that message. These are called user commands. + +Together, these two are called Context Menus or Context Menu Commands. These commands work very much like normal commands, except they take a member or message. + +:::note + +A bot can have up to 5 global Context Menus of each type. + +::: + +## User Commands + +Creating a user command is very simple. + +```python +@bot.user_command(name="Account Creation Date", guild_ids=[...]) # create a user command for the supplied guilds +async def account_creation_date(ctx, member: discord.Member): # user commands return the member + await ctx.respond(f"{member.name}'s account was created on {member.created_at}") +``` + + + +
+ + Account Creation Date + +
+ {defaultOptions.profiles.bob.author}'s account was created on 2020-01-01 +
+
+ +## Message Commands + +```python +@bot.message_command(name="Get Message ID") # creates a global message command. use guild_ids=[] to create guild-specific commands. +async def get_message_id(ctx, message: discord.Message): # message commands return the message + await ctx.respond(f"Message ID: `{message.id}`") +``` + + + + Do. Or do not. There is no try. + + +
+ + Get Message ID + +
+ Message ID: 930650407917748286 +
+
+ +
+ +:::info Related Topics + +- [Slash Commands](./slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx new file mode 100644 index 00000000..edac55b3 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx @@ -0,0 +1,56 @@ +--- +title: Localizations +description: Localizations are a way to make your bot more accessible to your users. Learn all about localizations now! +--- + +Localizations are a way to make your bot more accessible to your users. You can localize the command +name, the names of any arguments, and any text that is displayed to the user. + +## Syntax + +```python +@bot.slash_command( + name="ping", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + }, + options=[ + Option( + name="Example", + name_localizations={ + "en-GB": "British Example" + }, + description="Example option that does nothing", + description_localizations={ + "en-GB": "British example option that does nothing" + } + ) + ] +) +async def ping(ctx, example): + responses = {"en-US": "Pong!", + "en-GB": "British Pong!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +@bot.slash_command( + name="ping2", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + } +) +async def ping2(ctx, example: Option(str, "example", name_localizations={"en-GB": "British Example"}, description="Example option that does nothing", description_localizations={"en-GB": "British example option that does nothing"})): + responses = {"en-US": "Pong2!", + "en-GB": "British Pong2!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +``` + +- [`Locales`](https://discord.com/developers/docs/reference#locales) - List of valid locales recognized by Discord diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx new file mode 100644 index 00000000..ed454dad --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx @@ -0,0 +1,292 @@ +--- +title: Slash Commands +description: Learn all about Slash Commands and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On March 24, 2021, Discord added Slash Commands to Discord as an easier, more efficient, and better way of using bot commands. Pycord has implemented Slash Commands into the library, so it's simple, efficient, and familiar. + +:::important + +Remember that Slash Commands require your bot to be invited with the `application.commands` scope or Slash Commands will not show up. Bots already in the guild can simply be invited again with the scope; there is no need to kick the bot. + +::: + +## Syntax + +Let's create a simple Slash Command. + +```py +import discord + +bot = discord.Bot() + +# we need to limit the guilds for testing purposes +# so other users wouldn't see the command that we're testing + +@bot.command(description="Sends the bot's latency.") # this decorator makes a slash command +async def ping(ctx): # a slash command will be created with the name "ping" + await ctx.respond(f"Pong! Latency is {bot.latency}") + +bot.run("TOKEN") +``` + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +Let's go through the code. + +First, we import Pycord's `discord` package. + +Next, we create a [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot) object and assign it to a variable `bot`. + +We then go ahead and use the [`@bot.command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.command) decorator, which registers a new Slash Command. We pass a `description` parameter to give a description to the Slash Command. We can also pass a `name` parameter to change the Slash Command's name. By default, the name of the Slash Command will be the name of the function, in this case, `/ping`. + +We create an async function called `ping` with parameters `ctx`, which, when called, sends the bot's ping/latency using [`ctx.respond`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext.respond). + +## Subcommand Groups + +You might want to group certain commands together to make them more organised. A command group is exactly what it sounds like, a group of individual Slash Commands together. + +In order to make a Slash Command group, you can use the `bot.create_group` function. + +```python +import discord + +bot = discord.Bot() + +# create Slash Command group with bot.create_group +greetings = bot.create_group("greetings", "Greet people") + +@greetings.command() +async def hello(ctx): + await ctx.respond(f"Hello, {ctx.author}!") + +@greetings.command() +async def bye(ctx): + await ctx.respond(f"Bye, {ctx.author}!") + +bot.run("TOKEN") +``` + +Or, you can instead manually make a `SlashCommandGroup` class like so: + +```python +import discord + +math = discord.SlashCommandGroup("math", "Math related commands") + +@math.command() +async def add(ctx, num1: int, num2: int): + sum = num1 + num2 + await ctx.respond(f"{num1} plus {num2} is {sum}.") + +@math.command() +async def subtract(ctx, num1: int, num2: int): + sum = num1 - num2 + await ctx.respond(f"{num1} minus {num2} is {sum}.") + +# you'll have to manually add the manually created Slash Command group +bot.add_application_command(math) +``` + +Here's what the registered subcommands will look like in the Slash Command Menu: + +![Picture of the subcommands in the Slash Command Menu](../../assets/interactions/groups-and-subcommands.jpg) + +You'll notice that there's the name of the Slash Command Group and then the name of the subcommand separated by a space. + +::: + +:::info Cogs + +If you are looking to add Slash Command Groups to cogs, please look at our [Cogs page](../../popular-topics/cogs)! + +::: + +## Sub-groups + +We've made a subcommand group, but did you know that you could create a group inside another? + +```python +from discord import SlashCommandGroup +from math import sqrt + +math = SlashCommandGroup("math", "Math related commands") +advanced = math.create_subgroup("advanced", "Advanced math commands") + +@advanced.command() +async def square_root(ctx, x: int): + await ctx.respond(sqrt(x)) + +bot.add_application_command(math) +``` + +The command created above can be invoked by typing `/math advanced square_root`. + +## Options & Option Types + +Whenever you're using Slash Commands, you might notice that you can specify parameters that the user has to set or can optionally set. These are called Options. + +Options can also include a description to provide more information. [You can learn more about Options in our documentation!](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.Option) + +Since you want different inputs from Options, you'll have to specify the type for that Option; there are a few ways of doing this. + + + + +You could use Type Annotations and let Pycord figure out the option type or explicitly specified using the [`SlashCommandOptionType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.SlashCommandOptionType) enum. + +```python +import discord + +bot = discord.Bot() + +@bot.command() +# pycord will figure out the types for you +async def add(ctx, first: discord.Option(int), second: discord.Option(int)): + # you can use them as they were actual integers + sum = first + second + await ctx.respond(f"The sum of {first} and {second} is {sum}.") + +@bot.command() +# this explicitly tells pycord what types the options are instead +async def join( + ctx, + first: discord.Option(discord.SlashCommandOptionType.string), + second: discord.Option(discord.SlashCommandOptionType.string) +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + add + +
+ The sum of 1 and 1 is 2. +
+ +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+ + +Instead of Type Annotations, you can also use the option decorator. This is usually done to have type-hinting. + +```python title="Slash Command Type" +import discord + +bot = discord.Bot() + +@bot.command() +@discord.option("first", type=discord.SlashCommandOptionType.string) # type = str also works +@discord.option("second", type=discord.SlashCommandOptionType.string) # type = str also works +async def join( + ctx, + first: str, + second: str, +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+
+ +## Autocomplete + +Discord's autocomplete allows developers to determine option choices that are used in a slash command option. You can do this by defining a function: + +```py +async def get_animal_types(ctx: discord.AutocompleteContext): + """ + Here we will check if 'ctx.options['animal_type']' is a marine or land animal and return respective option choices + """ + animal_type = ctx.options['animal_type'] + if animal_type == 'Marine': + return ['Whale', 'Shark', 'Fish', 'Octopus', 'Turtle'] + else: # is land animal + return ['Snake', 'Wolf', 'Lizard', 'Lion', 'Bird'] + +@bot.slash_command(name="animal") +async def animal_command( + ctx: discord.ApplicationContext, + animal_type: discord.Option(str, choices=['Marine', 'Land']), + animal: discord.Option(str, autocomplete=discord.utils.basic_autocomplete(get_animal_types)) +): + await ctx.respond(f'You picked an animal type of `{animal_type}` that led you to pick `{animal}`!') +``` + + + +
+ + animal + +
+ You picked an animal type of Marine that led you to pick Shark! +
+
+ +:::warning + +Autocomplete can **only** be used with slash commands. + +::: + +:::info Related Topics + +- [Interactions Index](../../interactions) +- [Rules and Common Practices](../../getting-started/rules-and-common-practices) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/interactions/index.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/index.mdx new file mode 100644 index 00000000..8603437f --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/index.mdx @@ -0,0 +1,242 @@ +--- +title: Discord Interactions +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +In December 2020, Discord released their first Interaction: the +[Slash Command](https://discord.com/developers/docs/interactions/application-commands#slash-commands). +Since then, Discord has added many types of Interactions, including: + +[**Application Commands**](https://discord.com/developers/docs/interactions/application-commands) + +- [**Slash Commands**](https://discord.com/developers/docs/interactions/application-commands#slash-commands): + Commands that can be used with the `/` prefix. +- **Context Menu Commands**: Commands that can be used from the right-click menu. + - [**User Commands**](https://discord.com/developers/docs/interactions/application-commands#user-commands): + Commands that can be used on a user by alt-clicking/selecting them. + - [**Message Commands**](https://discord.com/developers/docs/interactions/application-commands#message-commands): + Commands that can be used on a message by alt-clicking/selecting it. + +[**UI Components**](https://discord.com/developers/docs/interactions/message-components) + +- [**Buttons**](https://discord.com/developers/docs/interactions/message-components#buttons): + Buttons are attached to a message and can be clicked on to perform an action. +- [**Select Menus**](https://discord.com/developers/docs/interactions/message-components#select-menus): + Drop-down menus are used to select a number of options from a list. +- [**Modals**](https://discord.com/developers/docs/interactions/message-components#text-inputs): + Form-like modals can be used to ask for input from a user. + +## Application Commands + +Application Commands are another set of new features that are intended to avoid compromising users' safety and privacy. +They're relatively easy to add to your bot, and give people a simpler and safer way to use commands. + +### [Slash Commands](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.SlashCommand) + +Slash Commands were the first Interaction added to Discord. They're easy to use and create, and +is the only prefix commands alternative that does not need Message Content intent. + +:::note + +Preferring prefix commands over Application Commands is **not** a valid reason to apply for the +Message Content intent. Using that as a reason will get your application denied. + +::: + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +This is what a Slash Command looks like. Not too different from a prefix command, +apart from the note telling you who invoked it. A Slash Command's fields can accept any of the following: + +- Members +- Roles +- Channels +- Attachments +- Text + +Just about as good as it gets. + +### [Message](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.MessageCommand) and [User](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.UserCommand) Commands + +Message Commands and User Commands were both introduced at around the same time, and are very similar to each other, so we'll be +introducing them together. These commands can be found in the `Apps` tab when alt-clicking. The only difference between the two is that +Message Commands only appear in the `Apps` tab of a message, while User Commands are found in the `Apps` tab of a user. Message Commands +can be used to quickly report a message, warn a user for a message, and other functions. Likewise, User Commands can be used to add a +user to a ticket, warn a user, and more. + +Here's an example of a Message Command: + + + + Hello World! + + +
+ + Reverse Message + +
+ Message 930650407917748286 reversed is "!dlroW olleH" +
+
+ +
+ +And here's an example of a User Command: + + + + {defaultOptions.profiles.dorukyum.author} has been on Discord for a long time + + +
+ + User Age + +
+ {defaultOptions.profiles.dorukyum.author} is 1 week old. +
+ +
+ + User Age + +
+ {defaultOptions.profiles.bob.author} is 40 years old. +
+ + 🤔 + +
+ +
+ +Pretty cool, right? To learn more about these two, please read the [Context Menus guide](./application-commands/context-menus.mdx). + +## [Application Commands](#application-commands) vs. [Prefix Commands](../extensions/commands/prefixed-commands) + +Ever since Discord was created, apps on it have used prefix commands. Using prefixes meant that you would have to put a +certain character (or string of characters) in front of your command, such as the exclamation mark in `!ping`. The way this +worked was that your bot would listen for messages, pick out the ones that had their specific prefix, and then respond to the command. +Now, Discord is encouraging developers to switch their bots over to Application Commands, which is a new system meant to preserve the +privacy and safety of their users. But why exactly is Discord making us switch? What's the better option, Application Commands or prefix +commands? Below, we'll discuss everything you need to know. + +### Discord's Decision + +Application Commands were conceptualized partly due to privacy concerns. When Discord first began, they weren't entirely concerned about bots +having access to the content of every message that was being sent. However, as Discord grew, this became more of a problem. Hypothetically, bots +could simply log every message they're able to receive via the Discord API and hand their contents over to a company or other third party. This is +a problem, since that data is meant to be used only by Discord. As such, they locked down Message Content, and introduced Application Commands for +bot developers to use instead. + +Prefix commands work by reading messages, as described before. Application Commands, however, don't +work this way; instead, they work by having your bot get information from Discord about when a command was used. This way, Discord can limit +Message Content only to bots that _absolutely_ depend on it, such as auto-moderation bots. + +### Who has to Use Application Commands + +Any verified bot that does not have the Message Content intent must use Application Commands. Discord is allowing developers to submit +applications for the ability to use the intent; however, since they don't want to keep supporting prefix commands due to privacy concerns, +they will automatically decline any application that includes only that as a reason. So, if your bot doesn't have an auto-moderation feature +(or any other functionality that requires Message Content), you're out of luck. + +Unverified bots, however, don't have to use Application Commands. This is because the Message Content intent is a `Privileged Intent`, meaning that +it must be applied for only if your bot is verified or about to be verified. Unverified bots don't have to apply for Privileged Intents, so they can +use them freely. + +So, if your bot is made only for a couple of servers, you can choose between prefix commands and Application Commands. However, if you plan on expanding +your bot's reach, it'll have to use Application Commands. + +### What's the Better Option + +Choosing which is the better option is up to you, if you're starting small. If +you plan on growing your bot, however, you will have to use Application Commands. Since prefix commands are slowly being phased out by Discord, +there isn't much of a choice for developers of larger bots. + +## Message Components + +Message Components are fairly new features in Discord, allowing developers to give their bots a fast +and understandable user interface. Message Components are easy to use and make your bot look modern, +sleek, and downright awesome. + +### [Views](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View) + +Views are not an Application Command nor are they a Message Component. Views are the invisible placeholders, or grid, +that Message Components lie in. Views can have up to 5 [`Action Rows`](https://docs.pycord.dev/en/stable/api/models.html#discord.ActionRow), +and Action Rows can have a maximum of 5 slots. Below, you can find a table showing how many slots a Message Interaction takes up. + +| Component | Slots | +| ------------ | ----------------------------------------------- | +| Buttons | 1 Slot | +| Select Menus | 5 Slots | +| Text Modals | 1 Slot (opened via a Button) | + +So, based on this, you could have a maximum of 25 Buttons in a View with no Select Menus, and 5 Select +Menus in a View with no Buttons. This doesn't mean you can't have them both in a View, however. You can have +a combination of them, such as 20 Buttons and a Select Menu or 10 Buttons and 3 Select Menus. + +### [Buttons](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button) + +Buttons are the first of the Message Components. They allow for quick responses to prompts, such as for canceling or continuing an action. +Of course, these aren't their only uses; people have created awesome things with Buttons, such as calculators, games, and more! + + + + Discord Buttons are awesome! +
+ + Click me! + +
+
+
+ +
+ +This is what a Button looks like, very simple and modern. To learn more about Buttons, refer to our +[Buttons page](./ui-components/buttons.mdx). + +### [Select Menus](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Select) + +Select Menus are the second of Discord's Message Components. They allow users to select from a list of choices, which your bot can then use. +Select Menus are good for things such as choosing features, pages of a help menu, and more. + +![Select Menu Example Image](../assets/interactions/select-menus-example.png) + +This is what a Select Menu looks like. While not looking as good as Buttons, they still look great +and have even greater possibilities. To learn more about Select Menus, please refer to our [Select +Menus page](./ui-components/dropdowns.mdx). + +### [Modal Dialogs](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal) + +Text Modals are the most recently added Message Component in Discord. They're useful for text input and filling out forms, such as a +sign-up for your bot's service. These are meant to replace long bot setup processes by allowing users to fill out multiple text fields, +which avoids having the user send multiple messages for the bot. Modals can be accessed by either invoking an Application Command or by +interacting with another UI Component. + +![Text Modal Example Image](../assets/interactions/modal-example.png) + +This is what a Text Modal looks like, easy to use and one of the most useful Message Components yet. To learn more about Text Modals, +please visit our [Modal Dialogs page](./ui-components/modal-dialogs.mdx). diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json new file mode 100644 index 00000000..7b0a72fe --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "UI Components", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx new file mode 100644 index 00000000..046b36c7 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx @@ -0,0 +1,314 @@ +--- +title: Buttons +description: Learn all about implementing buttons in your Discord Bot using Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On May 26, 2021, Discord added a new interaction called buttons. Instead of reactions, bots could now +send buttons and users could use them to interact with bots. This opened up a whole new world of +possibilities for bots. Soon after, developers made calculators, polls, and games like blackjack, UNO, +and even Minecraft! Buttons provided a clear and easy to use interface for interacting with bots. + +So, let's learn how you can add buttons to your bot! + +## Concept + +Buttons weren't the only update to the interactions system in Discord. Discord also added [Select Menus](./dropdowns) and [Modal Dialogs](./modal-dialogs), both of which work very similarly to buttons. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive button. + +```python +import discord + +bot = discord.Bot() # Create a bot object + +class MyView(discord.ui.View): # Create a class called MyView that subclasses discord.ui.View + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.primary, emoji="😎") # Create a button with the label "😎 Click me!" with color Blurple + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") # Send a message when the button is clicked + +@bot.slash_command() # Create a slash command +async def button(ctx): + await ctx.respond("This is a button!", view=MyView()) # Send a message with our View class that contains the button + +bot.run("TOKEN") # Run the bot +``` + +Using this command should return the following message: + + + +
+ + button + +
+ This is a button! +
+ + Click me! + +
+
+
+ +
+ +As you can see, we create a class called `MyView` that [subclasses](#oop) +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `button_callback` to the `MyView` class with the decorator +[`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button). +This decorator adds a button to a component. This function takes two arguments: the button that was +clicked and the interaction. These arguments are passed to the function when the button is clicked +by the module. We use the [`interaction.response.send_message`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse.send_message) +function to send a message to the channel where the interaction was sent. + +Finally, we create a global slash command called `button` that sends the message, along with the view +that contains a button. + +This is the basic syntax of creating a button. What you create with it is up to you. You can worry +about making your button do amazing things, while Pycord handles the rest! + +## Button Styles + + + +| Name | Usage | Color | +| --------- | ----------------------------------------------------------------------------------------- | ------- | +| Primary | `discord.ButtonStyle.primary` / `discord.ButtonStyle.blurple` | Blurple | +| Secondary | `discord.ButtonStyle.secondary` / `discord.ButtonStyle.grey` / `discord.ButtonStyle.gray` | Grey | +| Success | `discord.ButtonStyle.success` / `discord.ButtonStyle.green` | Green | +| Danger | `discord.ButtonStyle.danger` / `discord.ButtonStyle.red` | Red | +| Link | `discord.ButtonStyle.link` / `discord.ButtonStyle.url` | Grey | + +Check out the [`discord.ButtonStyle`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ButtonStyle) class for more information. + +![Different Button Styles](../../assets/interactions/button-styles.png) + +You can set a button's style by adding the `style` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) decorator. + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.success) + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots, and each button takes up 1 slot. +So, how do we move the buttons to another row? + +This can be done by specifying the `row` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) +decorator. + +:::info The `row` argument + +The row argument specifies the relative row this button belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=1, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") +``` + +## Disabling Buttons + +### Pre-Disabled Buttons + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary, disabled=True) # pass `disabled=True` to make the button pre-disabled + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView()) +``` + +### Disabling Buttons on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + button.disabled = True # set button.disabled to True to disable the button + button.label = "No more pressing!" # change the button's label to something else + await interaction.response.edit_message(view=self) # edit the message's view +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(emoji="😀", label="Button 1", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) + + @discord.ui.button(label="Button 2", style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +Sometimes, you want to have a button that is disabled after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView(timeout=30)) +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a button that is disabled after a certain amount of time, you want to have a +button that is always working. + +Normally, when the bot goes offline, all of its buttons stop working. You will be able to see the +buttons, but nothing will happen when you press them. This is a problem +if you are trying to create a self-role system with buttons, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons will stop working. When the bot comes back online, however, the buttons will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view must have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.button(label="A button", custom_id="button-1", style=discord.ButtonStyle.primary, emoji="😎") # the button has a custom_id set + async def button_callback(self, button, interaction): + await interaction.response.send_message("Button was pressed", ephemeral=True) + +@bot.command() +async def button(ctx): + await ctx.send(f"Press the button! View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many buttons can I have in a message? + +Each message can have a maximum of 25 buttons. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do buttons need any special permissions? + +No new permissions are needed for either the bot or the server to allow bots to use buttons. + +#### Should I replace reactions with buttons for my bot? + +That is up to you. Buttons do provide a cleaner interface for your bot and are easier to use. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx new file mode 100644 index 00000000..8320f25d --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx @@ -0,0 +1,339 @@ +--- +title: Select Menus +description: Learn all about implementing Select Menus or Dropdowns in your Discord Bot with Pycord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Shortly after the buttons were added, Discord added their second message component: Select Menus. Select Menus allow users to choose from a list of items sent by a bot. These are a great substitute for having a user send a number that corresponds to an option. You can even allow users to select multiple options from the Select Menus. This guide will show you the easy and painless ways of using them with Pycord. + +## Concept + +Select Menus aren't the only message component in Discord. There's also [Buttons](./buttons) and [Modal Dialogs](./modal-dialogs). Select Menus make it easy for users to pick one or multiple options from a list provided by a bot. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive select menu. + +```python +import discord + +bot = discord.Bot() + +class MyView(discord.ui.View): + @discord.ui.select( # the decorator that lets you specify the properties of the select menu + placeholder = "Choose a Flavor!", # the placeholder text that will be displayed if nothing is selected + min_values = 1, # the minimum number of values that must be selected by the users + max_values = 1, # the maximum number of values that can be selected by the users + options = [ # the list of options from which users can choose, a required field + discord.SelectOption( + label="Vanilla", + description="Pick this if you like vanilla!" + ), + discord.SelectOption( + label="Chocolate", + description="Pick this if you like chocolate!" + ), + discord.SelectOption( + label="Strawberry", + description="Pick this if you like strawberry!" + ) + ] + ) + async def select_callback(self, select, interaction): # the function called when the user is done selecting options + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") + +@bot.command() +async def flavor(ctx): + await ctx.respond("Choose a flavor!", view=MyView()) + +bot.run("TOKEN") +``` + +There's a lot going on over here! Don't worry, we will go over the code and explain it. + +As you can see, we create a class called `MyView` that subclasses +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `select_callback` to the `View` class with the decorator +[`discord.ui.select`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.select). +This decorator adds a select menu to the view. This decorator takes a few arguments to customize your select menu. Read them in the [Customization section](#customization). + +That was the decorator. Now, the function itself is pretty simple. It takes two parameters, not including `self`. The parameters are `select`: The select menu, and `interaction`: a [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object. Both of these are passed by Pycord, so you just need to specify them in the function! + + + +In the callback, you could do anything you want. You get the two parameters `select` and `interaction` to play around with. Here, we send a message using `await interaction.response.send_message` (where interaction is [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse)) with content `select.values[0]`, which sends the label of the first/only option the user selected. Obviously, this is only an example, and you could do just about anything you want. + +Finally, we create a global slash command called `flavour` that sends a message "Choose a flavor!" along with the view +that contains our select menu. + +This is the basic syntax of creating a select menu. What you create with it is up to you. You can worry +about making your code do amazing things, while Pycord handles the rest! + +## Customization + +#### Select Menu Properties + +- `select_type`: The type of select to create. This must be a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. +- `channel_types`: A list of channel types that can be selected in the menu. This is only valid for selects of `select_type` [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType). +- `options`: A list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. These are the options that can be selected in this menu. +- `placeholder` is the placeholder text shown in the select menu if no option is selected. +- `custom_id`: The ID of the select menu that gets received during an interaction. It is recommended not to set this to anything unless you are trying to create a persistent view. +- `row`: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). +- `min_values`: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `max_values`: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `disabled`: Whether the select is disabled or not. Defaults to False. + +#### Select Option Properties + +In the `options` parameter, you pass a list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. This class also has a few parameters: + +- `default` (whether the option is selected by default) +- `description` (an additional description, if any) +- `emoji` (a string or an emoji object, if any) +- `label` (the name displayed to users, can be up to 100 characters) +- `value` (a special value of the option, defaults to the label). + +## Select Types + +In addition to regular string selects, you can also have your select menu contain users, roles, mentionables, and channels as its options. You can use these alternative select types by passing a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value for the `select_type` parameter when creating the Select. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.user_select + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +Additionally, you can use shortcut decorators to create a [`discord.ui.Select`](https://docs.pycord.dev/en/master/api/ui_kit.html#discord.ui.select) with a predetermined [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. Using a shortcut decorator, the above code can be rewritten like this: + +```python +class MyView(discord.ui.View): + @discord.ui.user_select() + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +### Specifying Channel Types + +When using a [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType.channel_select) type select menu, you can pass in a list of [`discord.ChannelType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ChannelType) values to limit which types of channels users can choose when interacting with the select menu. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.channel_select, + channel_types=[discord.ChannelType.text, discord.ChannelType.voice] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"You selected {select.values[0].mention}") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots. A button takes a single slot, while a select menu takes up all 5 of them. This means a view can have a maximum of 5 select menus, or any possible combination of select menus and buttons. + +The arrangement of buttons and select menus is generally adjusted by Pycord. However, it is possible to move them to specific relative rows. This is done by specifying the `row` argument. + +:::info The `row` argument + +The row argument specifies the relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero-indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=0, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.select( + row = 1, + options = [...] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") +``` + +## Disabling Select Menus + +### Pre-Disabled Menus + +```python +class MyView(discord.ui.View): + @discord.ui.select( + disabled = True, # pass disabled=True to set the menu as disabled + options = [...] + ) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send("Select and option from the menu!", view=MyView()) +``` + +### Disabling Menus on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + select.disabled = True # set the status of the select as disabled + await interaction.response.edit_message(view=self) # edit the message to show the changes +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def first_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) # edit the message to show the changes + + @discord.ui.select(options = [...]) + async def second_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +You may want a select menu to automatically stop working after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select(ctx): + await ctx.send(view=MyView(timeout=30)) # specify the timeout here +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a select menu that is disabled after a certain amount of time, you want to have a +select menu that is always working. + +Normally, when the bot goes offline, all of its views stop working, even if they don't have a timeout. You will be able to see the +views, but nothing will happen when you try to interact with them. This is a problem +if you are trying to create a self-role system, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons and select menus will stop working. However, when the bot comes back online, the buttons and select menus will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view much have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.select(custom_id="select-1", options = [...]) # a custom_id must be set + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send(f"View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many select menus can I have in a message? + +Each message can have a maximum of 5 select menus. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do select menus need any special permissions? + +No new permissions are needed in the bot or in the server. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx new file mode 100644 index 00000000..bd585c77 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx @@ -0,0 +1,107 @@ +--- +title: Modal Dialogs +description: Learn how you can implement Modals in your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Modal Dialogs, also known as "modals", provide a form-like structure for bots to receive input from users. No extra permissions are needed for bots to send modal dialogs, so it becomes a convenient workaround for bots to receive longer input without needing the Message Content [intent](../../popular-topics/intents). + +## Concept + +Modal Dialogs consist of a title, custom ID, and up to 5 [`discord.ui.InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) components. While creating modals, we generally subclass [`discord.ui.Modal`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal), as we'll see later. + +Unlike other UI Components, Modals cannot be sent with messages. They must be invoked by an Application Command or another UI Component. + +## Usage Syntax + +```py +class MyModal(discord.ui.Modal): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.add_item(discord.ui.InputText(label="Short Input")) + self.add_item(discord.ui.InputText(label="Long Input", style=discord.InputTextStyle.long)) + + async def callback(self, interaction: discord.Interaction): + embed = discord.Embed(title="Modal Results") + embed.add_field(name="Short Input", value=self.children[0].value) + embed.add_field(name="Long Input", value=self.children[1].value) + await interaction.response.send_message(embeds=[embed]) +``` + + + + +The `ctx` parameter we define in Application Commands receives an [`ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext) object. Using its `send_modal()` coroutine, you can send a Modal dialog to the user invoking the Application Command. + +```py +@bot.slash_command() +async def modal_slash(ctx: discord.ApplicationContext): + """Shows an example of a modal dialog being invoked from a slash command.""" + modal = MyModal(title="Modal via Slash Command") + await ctx.send_modal(modal) +``` + + + + +The `interaction` parameter we define in UI Components receives an [`Interaction`](https://docs.pycord.dev/en/stable/api/models.html#discord.Interaction) object. The `response` attribute of the object contains an [`InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object, with various coroutines such as `send_message()` and `send_modal()`, which we utilize. + +```py +class MyView(discord.ui.View): + @discord.ui.button(label="Send Modal") + async def button_callback(self, button, interaction): + await interaction.response.send_modal(MyModal(title="Modal via Button")) + +@bot.slash_command() +async def send_modal(ctx): + await ctx.respond(view=MyView()) +``` + + + + +The above example uses an embed to display the results of the modal submission, but you can do anything you want with the text provided by the user. +Each input field can be accessed in the order it was added to the modal dialog, via `Modal.children`. + +## Customization + +A Modal can have up to 5 [`InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) fields. These fields offer some customization. + +Each field has a label which is shown to the user. This is defined with `label`. + +The `style` parameter is used to determine whether it should be a short (single-line) or long (multi-line) input field. + +There are a number of aliases that can be used: + +```x title="Single-line InputTextStyle values:" +short +singleline +``` + +```x title="Multi-line InputTextStyle values:" +paragraph = 2 +multiline = 2 +long = 2 +``` + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Buttons](./buttons) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/introduction.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/introduction.mdx new file mode 100644 index 00000000..3262c632 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/introduction.mdx @@ -0,0 +1,50 @@ +--- +title: Introduction +description: Pycord Guide is a complete guide for Pycord. Learn how to create Discord Bots today! +sidebar_position: 1 +--- + +Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord, written in Python. Pycord is a maintained fork of [discord.py](https://github.com/Rapptz/discord.py). + +## Before you begin + +Pycord is an advanced and complex Python library. To take advantage of the full capabilities of Pycord, you will need to have a good understanding of Python. You should know the basics of Python and have an understanding of the following concepts: + +- Variables +- Data Types +- Functions +- Packages +- Conditionals +- Loops +- Classes +- Object-Oriented Programming +- Inheritance +- Exception Handling +- Iterators +- Coroutines +- Async/Await + +This list is not exhaustive, but it should give you a good idea of what you need to know to get started. + +When you see an ellipsis - that's the three dots - in this guide, it is a placeholder for code that you need to fill in. Sometimes, it may be code for a command, while other times it could be something simple like a Guild ID. Make sure to replace them before running your bot! + +## Learning Resources + +Here are some good resources to get started or to freshen up your Python knowledge: + +- [Official Beginner's Guide](https://wiki.python.org/moin/BeginnersGuide) +- [Official Tutorial](https://docs.python.org/3/tutorial/) +- [Automate the Boring Stuff, a free online book for complete beginners to programming](https://automatetheboringstuff.com/) +- [Learn Python in y Minutes, complete cheat sheet for people who know programming already](https://learnxinyminutes.com/docs/python3/) +- [Swaroopch's free Python book](http://python.swaroopch.com/) +- [Codeabbey, exercises for beginners](http://www.codeabbey.com/) + +## Credits + +First of all, we would like to thank [Rapptz](https://github.com/Rapptz) for the original [discord.py](https://pypi.org/project/discord.py) library. Pycord is a maintained fork of this library. + +We would also like to thank the [discord.js guide](https://discordjs.guide), which inspired this guide style-wise, and the [original Pycord Guide](https://namantech.me/pycord), which inspired some content in this guide. + +We created this guide using [Docusaurus v2](https://docusaurus.io), a modern static site generator for React. We would also like to thank Danktuary for his [`@discord-message-components/react`](https://www.npmjs.com/package/@discord-message-components/react) package, from which we took the Discord message components. + +And finally, we would like to thank the amazing and loving community of Pycord users, contributors and developers. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/more/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/more/_category_.json new file mode 100644 index 00000000..2cbe2c56 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/more/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 8, + "label": "More", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/more/community-resources.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/more/community-resources.mdx new file mode 100644 index 00000000..ed3075bd --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/more/community-resources.mdx @@ -0,0 +1,23 @@ +--- +title: Community Resources +--- + +This page showcases the amazing things created by the Pycord community, including bots, Plugins, and more. + +## Plugins + +| Name | Type | GitHub | +| --------------- | ------------ | --------------------------------------------------------------- | +| Music Cord | Music | [NixonXC/cord-music](https://github.com/NixonXC/cord-music) | +| pycord-i18n | Localization | [Dorukyum-pycord-i18n](https://github.com/Dorukyum/pycord-i18n) | +| pycord-multicog | Cogs | [pycord-multicog](https://github.com/Dorukyum/pycord-multicog) | +| EzCord | Utilities | [EzCord](https://github.com/tibue99/ezcord) | + +## Bots + +| Name | Type | Link | +| ------------------------ | ------------ | ----------------------------------------------------------------------------------- | +| Discord-Multipurpose-Bot | Multipurpose | [github](https://github.com/pogrammar/Discord-multipurpose-bot/tree/master/Python) | +| inconnu | Fun & QOL | [github](https://github.com/tiltowait/inconnu) | +| Mai | Multipurpose | [github](https://github.com/TeamMai/Mai) & [website](https://xfghoul.github.io/Mai) | +| Toolkit | Multipurpose | [github](https://github.com/Dorukyum/Toolkit) | diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/more/contributing.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/more/contributing.mdx new file mode 100644 index 00000000..469ea3ee --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/more/contributing.mdx @@ -0,0 +1,463 @@ +--- +title: Contributing to the Guide +description: Learn how to contribute to the Pycord Guide. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +This page outlines some of the basic syntax you need to know to contribute to the guide. We recommend you also check out: + +- [Docusaurus's Docs](https://docusaurus.io/docs/) +- [Contributing Rules](https://github.com/Pycord-Development/guide/blob/master/.github/CONTRIBUTING.md) + +## Info + +We use [Docusaurus v2](https://docusaurus.io/) to generate our guide. All the guide pages are generated +from `mdx` files in the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory. +MDX allows you to use JSX in your markdown content. + +## Structure + +Let's visit the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory and check its file structure. + +We can see various folders and a few files in it. Let's talk a bit about the `introduction.mdx` file. At the top, you can see something like: + +```md +--- +title: Introduction +description: ... +sidebar_position: 1 +--- +``` + +Most pages have this at the top. The `title` defaults to the file name. Since the titles need to be Capitalized according to need while the file names are lowercased (sometimes, the file names are shorter than the title!), we set a title ourselves. + +The `description` field is also important. This is the text shown in an embed when the page's link is shared on Discord, Twitter or other websites that support embedded links. Make sure to give a nice an interesting description! + +The `sidebar_position` field is pretty self-explanatory. It sets the position of the page in the sidebar. Most files in categories do not need this since they are sorted alphabetically. + +## Markdown Syntax + +This page quickly outlines some of the syntax that is used in markdown. + +````mdx +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + + ```python + print("We can use code blocks like this.") + ``` + +You can add [links to other websites](https://pycord.dev). You can add images like this: ![alternate text that describes the image](https://pycord.dev/image.png). + +- You can create +- unordered lists like this + +1. Or ordered lists +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` +4. Like this + +# Headers + +## Go + +### Like + +#### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet +```` + +
+Preview +
+ +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + +```python +print("We can use code blocks like this.") +``` + +You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](@site/static/img/favicon.ico). + +- You can create +- unordered lists like this + +1. Or ordered lists + +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` + +4. Like this + + # Headers + + ## Go + + ### Like + + #### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet + +
+
+ +## Admonitions + +We can add warnings, notes, etc. with the following syntax: + +```md +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: +``` + +
+Preview +
+ +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: + +
+ +
+ +## Discord Message Components + +As most files already have the imports for these, it's not that hard to add them. + +First, import the necessary components: + +```tsx +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; +``` + +The div starts like so: + +```tsx + + + + +
+``` + +This is where you list a `DiscordMessage`. + +```tsx + + + Hello! + + + +
+``` + + + + Hello! + + + +
+ +It has a pretty straightforward syntax. + +:::tip + +Add a `
` to the end of a component to make the content below it look better. + +::: + +### Slash Commands + +To make a message authored by a slash command, do the following: + +```tsx + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+``` + + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+ +### Buttons + +To make a message with buttons, do the following: + +```tsx + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+``` + + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+ +## Page Format + +There are a few things you need to take care of: + +1. Make sure that the spelling and grammar is perfect. We have a GitHub action configured that will warn you about spelling errors when you start a pull request. Make sure to commit your changes accordingly. + + As for the grammar, you should try reading the changes you have done and wait for reviews from others. + +2. A common mistake people make is incorrect header style. People often think that the less the important the topic is, the lower it's heading style should be. + + ```md + [PAGE STARTS] + # Topic + ## Less Important Topic + ## Subtopic + ``` + + ```md + [PAGE STARTS] + # About + [Introduction] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + That's VERY wrong. Here's the correct example: + + ```md + [PAGE STARTS] + [Introduction] + ## Topic + ## Less Important Topic + ### Subtopic + ``` + + ```md + [PAGE STARTS] + [Introduction] + + ## About + [More Information] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + Note that the `---`s at the beginning have been skipped here. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/more/git.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/more/git.mdx new file mode 100644 index 00000000..0f929d6d --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/more/git.mdx @@ -0,0 +1,55 @@ +--- +title: Installing Git +description: Learn how you can install Git on your system. +--- + +Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Let's see how to install Git on different platforms. + +## Windows + +On Windows, Git can be installed via: + +- [Git for Windows](https://gitforwindows.org) +- [Git Scm](https://git-scm.com/download/windows) + +## Linux + +On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. + +## Mac + +You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: + +``` +xcode-select --install +``` + +## Using Package Managers + +You can also install Git using package managers. + +### Chocolatey + +If you use the Chocolatey package manager, you can install Git using: + +``` +choco install git +``` + +### Scoop + +If you use Scoop, you can install Git using: + +``` +scoop install git +``` + +### Brew + +If you're on macOS or Linux, you can install Git using: + +``` +brew install git +``` diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx new file mode 100644 index 00000000..b0b8c7ea --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx @@ -0,0 +1,62 @@ +--- +title: Virtual Environments +description: Learn how to set up a virtual environment for Pycord. +--- + +## Setup + +Sometimes you want to keep libraries from polluting system installs or use a different version of libraries than the ones installed on the system. You might also not have permissions to install libraries system-wide. For this purpose, the standard library as of Python 3.3 comes with a concept called “Virtual Environment”s to help maintain these separate versions. + +A more in-depth tutorial is found on [Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html). + +However, for the quick and dirty: + +Go to your project’s working directory: + +```bash +$ cd your-bot-source +$ python3 -m venv venv +``` + +Activate the virtual environment: + +```bash +$ source venv/bin/activate +``` + +On Windows you activate it with: + +```batch +$ venv\Scripts\activate.bat +``` + +Use pip like usual: + +```bash +$ pip install -U py-cord +``` + +Congratulations. You now have a virtual environment all set up. + +## Additional info + +It can be useful to set up a requirements.txt, so you can just put all of your dependencies in there and have pip install it. +For instance, if you wanted to have the latest 2.0 version of pycord and [pytz](https://github.com/stub42/pytz/blob/master/src/README.rst), just create a file named requirements.txt with the following contents: + +``` +py-cord>=2.0.0 +pytz +``` + +And then (in your virtual environment) you can just execute + +```bash +pip install -r requirements.txt +``` + +To keep from committing your virtual environment to git, you can set up a .gitignore file with the following line +(assuming you named your virtual environment venv like the above example): + +``` +venv/ +``` diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/_category_.json new file mode 100644 index 00000000..c38ea014 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 7, + "label": "Popular Topics", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx new file mode 100644 index 00000000..5377a6c3 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx @@ -0,0 +1,140 @@ +--- +title: Cogs +--- + +Cogs, often known as modules or extensions, are used to organize commands into groups. This is useful +for grouping commands that have the same general idea (such as moderation commands). This also helps +to avoid making your bot's files messy and cluttered. + +## Getting Started + +First, you'll need to create a folder to store your cogs, e.g. `cogs/`. + +Then, create a file inside the folder, e.g. `cogs/greetings.py`. By convention, the file name should +be the same as the name of the cog or module. + +We can then create the cog. + +```python title="./cogs/greetings.py" +import discord +from discord.ext import commands + +class Greetings(commands.Cog): # create a class for our cog that inherits from commands.Cog + # this class is used to create a cog, which is a module that can be added to the bot + + def __init__(self, bot): # this is a special method that is called when the cog is loaded + self.bot = bot + + @commands.command() # creates a prefixed command + async def hello(self, ctx): # all methods now must have both self and ctx parameters + await ctx.send('Hello!') + + @discord.slash_command() # we can also add application commands + async def goodbye(self, ctx): + await ctx.respond('Goodbye!') + + @discord.user_command() + async def greet(self, ctx, member: discord.Member): + await ctx.respond(f'{ctx.author.mention} says hello to {member.mention}!') + + math = discord.SlashCommandGroup("math", "Spooky math stuff") # create a Slash Command Group called "math" + advanced_math = math.create_subgroup( + "advanced", + "super hard math commands!" + ) + + @math.command() + async def add(self, a: int, b: int): + c = a + b + await ctx.respond(f"{a} + {b} is {c}.") + + @advanced_math.command() + async def midpoint(self, x1: float, y1: float, x2: float, y2: float): + mid_x = (x1 + x2)/2 + mid_y = (y1 + y2)/2 + await ctx.respond(f"The midpoint between those coordinates is ({mid_x}, {mid_y}).") + + @commands.Cog.listener() # we can add event listeners to our cog + async def on_member_join(self, member): # this is called when a member joins the server + # you must enable the proper intents + # to access this event. + # See the Popular-Topics/Intents page for more info + await member.send('Welcome to the server!') + +def setup(bot): # this is called by Pycord to setup the cog + bot.add_cog(Greetings(bot)) # add the cog to the bot +``` + +You can add any number of commands to your cog, as well as event listeners. However, this code will +not work on its own. In your main bot file, you must add the following code: + +```python +bot.load_extension('cogs.greetings') +``` + +This loads the file `cogs/greetings.py` and adds it to the bot. +The argument of `load_extension` should be your cog's path (e.g. cogs/greetings.py) without the file +extension and with the `/` replaced with `.` + +If you have multiple cogs, you can add them all at once by adding the following code: + +```python +cogs_list = [ + 'greetings', + 'moderation', + 'fun', + 'owner' +] + +for cog in cogs_list: + bot.load_extension(f'cogs.{cog}') +``` + +## Cog Rules + +When using a cog instead of the main file, there are some changes you have to make to your code. This +is because cogs work slightly different from a regular file. + +### The `self` variable + +The self variable is a variable that represents a class. In the case of cogs, `self` represents +the cog. In the `__init__` function, you can see that we have `self.bot = bot`. `bot` represents your +`discord.Bot` or `discord.ext.commands.Bot` instance, which is used for some functions. + +This means that instead of using functions that would usually be accessed via `bot`, you now need +to access them via `self.bot` + +Because we're in a class, all of our commands are methods of that class. Because of this, all of our +functions need to have `self` as the first parameter, where `self` is the cog. Without this, we +wouldn't be able to access our bot instance. + +### Creating Commands + +When creating prefixed commands, your decorator would usually be something like `@bot.command()`. If you're using +cogs, this isn't the case. In a cog, you can't access the bot instance outside of functions, so to +register a function as a command, you must instead use `@commands.command()`. + +Similar to prefixed commands, you'll have to use either the `@discord.slash_command()`, `@discord.user_command()`, +or `@discord.message_command()` decorators for Application Commands. + +Also, when creating a command, make sure that it is indented. If we want a command to be actually +inside a cog, it has to be inside your cog's class. If the command is not inside the cog, +your command becomes useless. + +### Events + +When creating events, you can no longer use `@bot.event` as a decorator. This is because we cannot +access the `bot` variable outside a function. To make an event, you have to use the `ext.commands` +method, `@commands.Cog.listener()`. Events also need `self` as their first parameter. + +And that's it! Cogs are a simple and easy way of organizing your code. Now you can check out how to +create a help command [here](../extensions/commands/help-command). + +:::info Related Topics + +- [Creating a Help Command](../extensions/commands/help-command) +- [Rules and Common Practices](../getting-started/rules-and-common-practices) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Application Commands](../interactions#application-commands) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx new file mode 100644 index 00000000..6c19dd29 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx @@ -0,0 +1,383 @@ +--- +title: Error Handling +description: All about handling errors. +--- + +import { + DiscordEmbed, + DiscordInteraction, + DiscordMessage, +} from "discord-message-components/packages/react"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +## About + +When using the library, errors are frequently raised due to various reasons. These reasons range from the Discord API +failing your bot's request due to missing permissions or an invalid syntax error. + +Before going into error handling, it's best that you learn the basic ways of handling errors. A good resource is: + +- [W3Schools' Guide to Python Try-Except Statements](https://www.w3schools.com/python/python_try_except.asp) + +## Basic Handling + +The most basic way to handle errors is to tackle it at the source. This can be done like so: + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +import asyncio + +import discord + +intents = discord.Intents.default() +intents.message_content = True + +bot = discord.Bot(intents=intents) + + +@bot.slash_command(description="Gets some feedback.") +@discord.option("name", description="Enter your name.") +async def feedback(ctx: discord.ApplicationContext, name: str): + try: + await ctx.respond(f"Hey, {name}! Send your feedback within the next 30 seconds please!") + + def is_author(m: discord.Message): + return m.author.id == ctx.author.id + + feedback_message = await bot.wait_for("message", check=is_author, timeout=30.0) + await ctx.send(f"Thanks for the feedback!\nReceived feedback: `{feedback_message.content}`") + except asyncio.TimeoutError: + await ctx.send("Timed out, please try again!") + + +bot.run("TOKEN") +``` + +If you respond within 30 seconds, the interaction will look like so: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Great bot! + + + Thanks for the feedback! +
+ Received feedback: Great bot! +
+
+
+ +Otherwise, if you don't respond in time, the interaction will go as follows: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Timed out, please try again! + +
+
+ +This basic method of error handling can be extended to handle +many other errors including ones raised directly by py-cord. + +## Per-Command Handling + +This type of error handling allows you to handle errors per each command you have on your bot. +Each and every command can have it's own error handler made to handle specific errors that each command may raise! + +An example of per-command error handling is as follows: + +:::note Bridge Commands + +For these types of commands, it is recommended to utilize global error handling +until [the feature](https://github.com/Pycord-Development/pycord/issues/1388) is added. +::: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot(owner_id=...) # Your Discord user ID goes in owner_id + + +@bot.slash_command(description="A private command...") +@commands.is_owner() # This decorator will raise commands.NotOwner if the invoking user doesn't have the owner_id +async def secret(ctx: discord.ApplicationContext): + await ctx.respond(f"Hey {ctx.author.name}! This is a secret command!") + + +@secret.error +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.NotOwner): + await ctx.respond("Sorry, only the bot owner can use this command!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If your ID is registered as the owner ID, you'll get the following: + + + +
+ + secret + +
+ Hey Dorukyum! This is a secret command! +
+
+
+ +Any other user whose ID doesn't match the bot owner's will get the following: + + + +
+ + secret + +
+ Sorry, only the bot owner can use this command! +
+
+
+ +This local (per-command) error handler can also be used to handle the same types of errors that standard try-except +statements can handle. This is done by using the same method as above with the `isinstance` built-in function. + +## Per-Cog Handling + +Adding error handlers per-command can be quite the task in terms of work if you have a lot. If you have happened to +group your commands in cogs, then you're in luck! You can create an error handler that is specific to a cog and +handles all errors raised by commands inside that cog. + +Here's an example of a bot with a cog that implements its own error handling: + +```python title="./cogs/dm.py" +# This cog is for DM only commands! Sadly, we only have 1 command here right now... + +import discord +from discord.ext import commands + + +class DM(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.command() + @commands.dm_only() # This decorator will raise commands.PrivateMessageOnly if invoked in a guild context. + async def avatar(self, ctx: commands.Context): + embed = discord.Embed( + title="Avatar", + description=f"Here's your enlarged avatar, {ctx.author.name}!", + color=ctx.author.top_role.color + ) + embed.set_image(url=ctx.author.display_avatar.url) + await ctx.send(embed=embed, reference=ctx.message) + + async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): + if isinstance(error, commands.PrivateMessageOnly): + await ctx.send("Sorry, you can only use this in private messages!", reference=ctx.message) + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +def setup(bot: commands.Bot): + bot.add_cog(DM(bot)) +``` + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +# This is the main file where we load the DM cog and run the bot. + +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix=commands.when_mentioned_or("!")) +bot.load_extension("cogs.dm") +bot.run("TOKEN") +``` + +If you use this command in a DM context, you'll get the following: + + + + !avatar + + +
+ + !avatar + +
+ + Here's your enlarged avatar, BobDotCom! + +
+
+
+ +Otherwise, if used in a guild context: + + + + !avatar + + +
+ + !avatar + +
+ Sorry, you can only use this in private messages! +
+
+
+ +Per-cog error handling comes in very handy as you can relegate all of your error handling to a single function instead +of spreading it out across several per-command error handlers or inside the commands themselves. + +## Global Handling + +If separating your error handling is not how you would like to handle errors, then global error handling is the way to +go. This method of handling allows you to relegate all handling to a single function that resides within your bot +instance. + +A non-subclassed bot would implement this like so: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot() + + +@bot.slash_command(description="Get the bot's current latency!") +@commands.cooldown(1, 30, commands.BucketType.user) +# ^ This decorator allows one usage of the command every 30 seconds and raises commands.CommandOnCooldown if exceeded +async def ping(ctx: discord.ApplicationContext): + await ctx.respond(f"Pong! `{int(bot.latency*1000)} ms`.") + + +@bot.event +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.CommandOnCooldown): + await ctx.respond("This command is currently on cooldown!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If you've subclassed your bot, the `on_application_command_error` event will be placed inside the subclass without a +`bot.event` decorator and `bot.slash_command` will be replaced with `discord.slash_command`. + +The error handling used above will yield this interaction if the command is used again too quickly: + + + +
+ + ping + +
+ Pong! 49 ms. +
+ +
+ + ping + +
+ This command is currently on cooldown! +
+
+
+ +The only issue regarding global error handling is that, if you have a large amount of commands, the global handler may +start to get crammed with a lot of code. This is where all the previously mentioned handlers can take their place! + +## FAQ + +#### Why does the example in per-cog handling have self at the start of its function signatures? + +This is a feature of classes and allows you to reference the cog object as `self` and get access to the bot object +passed at initialization through `self.bot`. + +If this is new to you, we recommend checking out these helpful resources to learn more about classes and cogs: + +- [W3Schools' Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [Our Cogs Guide Page](./cogs) + +#### How many errors can I handle in a single error handler? + +While all the examples in this guide page only handle one specific error and re-raise all others, all of these +error handlers can be extended to catch many errors. + +In [basic handling](#basic) (i.e. try/except statements) you can do one of two things: + +- Explicitly handle the errors you know might get raised and then have a broad `except Exception as exc:` statement + as a catch-all. +- Catch any and all errors via the catch-all statement mentioned above. + +In [per-command](#percommand), [per-cog](#percog), and [global handling](#global), you can use elif clauses with the +built-in isinstance function to catch specific errors. Atop of this, an else clause can be used to catch any other +errors you either don't want to handle or want to relegate to a different error handler. + +#### Can I use more than one type of error handler at once? + +Thankfully, all of these different ways of error handling can be mixed together, so you don't have to pick just one! +For commands that raise specific errors that no other commands will raise, you can use [per-command](#percommand). +For cogs that raise specific errors that no other cogs will raise, use [per-cog](#percog)! Lastly, for errors that +occur frequently across all commands and cogs, use [global handling](#global)! + +However, one important note to remember is that you should always raise the error again in an error handler if it +isn't handled there! If you don't do this, the error will go ignored and your other handlers won't have a chance to +do their work! + +#### What's the difference between slash and prefixed command error handling? + +Although most examples shown here use slash commands, the [per-cog handling](#percog) section presents a prefixed +command. The main difference you may notice is the change in command signature. + +To make the distinguishing features apparent: + +- Slash commands use `on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException)` + as presented in the [per-command](#percommand) and [global handling](#global) examples. +- Prefixed commands use `on_command_error(ctx: commands.Context, error: commands.CommandError)` as presented in the + [per-cog handling](#percog) example. + +This distinction is made as both types of commands need their own system for handling errors that are specific to +themselves. + +:::info Related Topics + +- [Slash Commands](../interactions/application-commands/slash-commands) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Cogs](./cogs) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx new file mode 100644 index 00000000..9f4210af --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx @@ -0,0 +1,62 @@ +--- +title: Intents +description: All about intents in Discord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +## What are Intents? + +Intents allow bot developers to "subscribe" to specific events in Discord. This is useful for bots that need to respond to specific events, such as when a user joins a server or sends a message. You could choose to enable all intents or to enable only specific intents that your bot requires. + +## How do I enable intents? + +:::important + +Remember that [Privileged Intents](#what-are-privileged-intents) require you to enable them in the Discord Developer Portal. Verified Discord Bots that don't already have access to them will need to request Discord to allow access. + +::: + + + + +```python +import discord + +bot = discord.Bot(intents=discord.Intents.all()) +``` + + + + + +You can view a list of intents and the events they subscribe to [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```python title="Enabling Intents" +import discord + +bot = discord.Bot(intents=discord.intents.members(bans=True, guilds=True)) +``` + + + + +## What are Privileged Intents? + +Discord defines some intents as "privileged" because of the sensitive information they contain. Currently, there are three privileged intents: `members`, `presences`, and `message_content`. These intents must be enabled in your bot's Developer Portal. Once your bot reaches 100 servers, you will need to verify your bot for these intents to keep working and for your bot to be able to be invited to more guilds. + +:::tip + +Only enable these intents if you need them. These intents give your bot access to quite sensitive information about the users in your guild. These intents are privileged to respect the privacy of users, and you should do that as well. + +Not enabling these intents doesn't mean you won't be able to ban users, but you will be unable to detect when a new user joins a guild, or what game they are playing. The majority of bots won't need all intents. + +::: + +:::info Related Topics + +- [Sharding Bots](sharding) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx new file mode 100644 index 00000000..c3d17197 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx @@ -0,0 +1,48 @@ +--- +title: Sharding +description: All about Sharding Discord Bots. +--- + +# Sharding + +## What is Sharding? + +Sharding is the process of breaking up your bot into smaller pieces so that it has a better time handling +events. As [Discord's Documentation](https://discord.com/developers/docs/topics/gateway#sharding) puts +it, sharding is "a method of user-controlled guild sharding which allows for splitting events across +several gateway connections." + +Sharding is used only for large bots and takes up additional resources for managing the new processes. +Pycord automatically shards your bot, so the only thing you need to do is use an `AutoShardedClient` +or `AutoShardedBot` class instead of a plain `Client` or `Bot` class. Pretty cool, right? + +Just because you _can_ shard your bot doesn't mean you _should_. While Pycord makes it easy to shard +your bot, it isn't necessary to shard unless your bot is large. Sharding a small bot isn't +just useless, but _harmful_, as it uses extra resources and may slow down your bot. Discord +themselves will let you know when your bot needs sharding, so you won't need to worry about this until they contact you. + +## How Do I Shard in Pycord? + +Sharding in Pycord is straightforward. + +Just replace your `discord.Client`, `discord.Bot`, `commands.Bot` objects +with `discord.AutoShardedClient`, `discord.AutoShardedBot`, `commands.AutoShardedBot` respectively. + +These new objects have been inherited from the original objects, so all the functions from those other types should be present. + +If you want to specify the number of shards your bot uses, +just add the `shards` parameter, along with the number of shards you want. + +## Why Should I Shard my Bot? + +Sharding is very necessary for big bots. While your bot grows, it gets harder for your bot to control +how many guilds it is in and what parts of your code should do what. This is exactly what sharding +handles, it makes all of this easier for your bot. Remember, though, only shard your bot once it's +big enough, and that's at _least_ 1,000 guilds. + +:::info Related Topics + +- [Hosting your Bot](../Getting-Started/hosting-your-bot) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx new file mode 100644 index 00000000..bd2969c1 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx @@ -0,0 +1,115 @@ +--- +title: Subclassing Bots +description: Subclassing is a popular way of creating Discord Bots. Explore how you can create a Discord bot by subclassing. +--- + +## About + +Subclassing is another popular way of creating Discord Bots. Here, you create a bot by extending a bot class. To some advanced users, this is preferable to creating a bot instance with `bot = discord.Bot()`. + +Subclassing is an intermediate python concept, so we recommend you learn about it before continuing. Some good resources are: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +## Why Subclassing? + +Many developers prefer to subclass their bots for many reasons, some of them being: + +#### Skeletal Frameworks for Bots + +Developers often share their bots code on open-source platforms, mostly GitHub, and allow users to self-host the bot (running their own instance of the bot with the code provided by the developer. Permissions vary in accordance to licences). Here, users find it easier and more convenient to have a small file that imports the custom bot class and runs it, rather than having to go through the code of the bot and find out which file to run. This makes it easier for people not familiar with programming to run and customize the bot, since it often brings down the code to: + +```python title="./main.py" +from src import Bot + +bot = Bot() + +bot.run("TOKEN") +``` + +Here, all the commands are inside the `/src` folder that the user need not bother with. + +#### Running Multiple Instances + +Some developers may need to run multiple instances of their bot (perhaps on different bot accounts). For example, a developer might have a second bot for testing alpha features. This system makes it simpler for the developer, and allows them to maintain multiple versions of the bot in the same directory: + +```python title="./alpha_bot.py" +from src import Bot + +class AlphaBot(Bot): # subclasses Bot + ... # insert any custom configuration + +bot = AlphaBot() + +@bot.slash_command() # adds a new slash command to this subclassed bot +async def alpha_feature(ctx): + await ctx.respond("Alpha Feature!") + +bot.run("TOKEN") +``` + +There are many more reasons to subclass! It's not required, and won't affect the speed of the bot, but it may affect your development process, for the good or for the worse. You don't miss out on any features when you subclass, either. Some developers want the OOP feel, while some just prefer that method and find it easier. + +## Basic Example + +```python +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override the on_ready event + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') + +bot = MyBot() + +@bot.slash_command() # create a slash command +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run('token') +``` + +As you can see, instead of creating a bot object with `bot = discord.Bot()`, we subclass [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). We then create an instance of our new bot class and run it. Notice how we don't need to use the `@event` decorator. + +Here's another example: + +```python title="./src/bot.py" +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override on_ready + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') +``` + +```python title="./src/\_\_init\_\_.py" +from .bot import MyBot # import the MyBot class from the bot.py file +``` + +```python title="./main.py" +from src import MyBot # import MyBot from /src + +bot = MyBot() # create an instance of MyBot + +@bot.slash_command() +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run("TOKEN") # run the bot +``` + +These are just two ways you could do it. There are ton of other structures you can implement. It's up to you. + +So, should you subclass? There are no limitations you face if you decide to subclass your bot, but, once again, it's up to you. + +:::info Related Topics + +- [Making a Help Command](../Extensions/Commands/help-command) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx new file mode 100644 index 00000000..23220b0e --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx @@ -0,0 +1,105 @@ +--- +title: Threads +description: Threads with Pycord +--- + +In programming, threads are a way to run multiple processes at the same time. In Discord, threads are +a way to keep multiple conversations going at the same time. Let's take a brief look at how to use threads in Pycord. + +:::tip + +Not all the methods and attributes will be covered in this guide, but you can find them in our documentation! +[Check it out!](https://docs.pycord.dev/en/stable/api/models.html#discord.Thread) + +::: + +## Creating a thread + +With a few simple lines of code, we can create threads in Pycord. + +:::important + +All public threads need a starting message. This message will start the thread. However, private threads +(which are unlocked with having your server boosted to Level 2), do not require a starting message. + +::: + +### Creating thread from a message + +```python title="Creating a Thread from a Message" +message = await ctx.send("My Starting Message") +await message.create_thread(name="thread name", auto_archive_duration=60) +``` + +You may also use other ways to create the thread, for example, by using `on_message` events or by commands. + +### Creating thread in a channel + +```python title="Creating a Thread from a Channel" +channel = bot.get_channel(...) # define this! +await channel.create_thread(name="Thread Name", message=None, auto_archive_duration=60, type=None, reason=None) +``` + +A thread type could be `news_thread`, `public_thread`, `private_thread`. You may use it by passing `type=discord.ChannelType.news_thread`. + +## Deleting Threads + +Deleting Threads is simple. You need to get a thread and then use the `delete` method. + +```python title="Deleting a Thread" +thread = bot.get_channel(thread_id) # you could use other ways to get a thread +await thread.delete() +``` + +## Editing Threads + +**Parameters** + +- `name` (str) – The new name of the thread + +- `archived` (bool) – Whether to archive the thread or not. + +- `locked` (bool) – Whether to lock the thread or not. + +- `invitable` (bool) – Whether non-moderators can add other non-moderators to this thread. Only available for private threads. + +- `auto_archive_duration` (int) – The new duration in minutes before a thread gets automatically archived for inactivity. Must be one of 60, 1440, 4320, or 10080. + +- `slowmode_delay` (int) – Specifies the slow-mode rate limit for users in the thread, in seconds. A value of 0 disables slow-mode. The maximum value possible is 21600. + +```python title="Editing a Thread" +thread = bot.get_channel(id) +await thread.edit( + name="New Name", + archived=True, + locked=True, + slowmode_delay=10, + auto_archive_duration=60, +) +``` + +As you can see, threads are very simple. Once you learn how to use them, it's easy to create whatever you want. + +## FAQ + +### Why am I getting a `Forbidden` error when I try to create a thread? + +A `Forbidden` error occurs when the bot does not have the correct permissions to create threads. + +### Why am I getting an Unknown Message error when I try to create a thread? + +Getting an error looking something like `discord.ext.commands.errors.CommandInvokeError: Command +raised an exception: HTTPException: 400 Bad Request (error code: 10008): Unknown Message`? + +There could be multiple reasons, some of them being: + +- The message does not exist +- The message already has a thread +- The message is in channel x, you are trying to start a thread in channel y. +- The message was deleted. + +:::info Related Topics + +<>{/* I can't think of any related topics for this at the moment. */} + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/voice/_category_.json b/i18n/fr/docusaurus-plugin-content-docs/current/voice/_category_.json new file mode 100644 index 00000000..8baf3da8 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/voice/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 6, + "label": "Voice" +} \ No newline at end of file diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/voice/index.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/voice/index.mdx new file mode 100644 index 00000000..835838c6 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/voice/index.mdx @@ -0,0 +1,24 @@ +--- +title: Voice +--- + +Welcome to the guide for voice features in Pycord. + +:::caution +This guide requires previous experience with Pycord and Python. +::: + +## Requirements + +The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). +The following features are optional: + +:::tip +Opus is also a required library, but this comes with Pycord. +Some hosts may not come with it, though, so remember to always check if required dependencies are installed. +::: + +- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` +- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), + [`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), + [`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/voice/playing.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/voice/playing.mdx new file mode 100644 index 00000000..fe14c52a --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/voice/playing.mdx @@ -0,0 +1,149 @@ +--- +title: Wavelink Audio Player +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { + defaultOptions, +} from "@site/src/components/DiscordComponent"; + +# About + +Pycord and Wavelink try to keep the playing of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio playing feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/). + +## Starting out + +First you need to run a [Lavalink Server](https://github.com/freyacodes/Lavalink) to connect with. +There a multiple documentations to do this, so we are not covering that here. + +You also need to install the [wavelink](https://github.com/PythonistaGuild/Wavelink) library. + +```py title="Installing wavelink" +python3 -m pip install wavelink +``` + +You will now want to connect to your server via a node. + +```py title="Connect Node with Lavalink" +import discord +import wavelink + +bot = discord.Bot() + +async def connect_nodes(): + """Connect to our Lavalink nodes.""" + await bot.wait_until_ready() # wait until the bot is ready + + nodes = [ + wavelink.Node( + identifier="Node1", # This identifier must be unique for all the nodes you are going to use + uri="http://0.0.0.0:443", # Protocol (http/s) is required, port must be 443 as it is the one lavalink uses + password="youshallnotpass" + ) + ] + + await wavelink.Pool.connect(nodes=nodes, client=bot) # Connect our nodes +``` + +
+ +Now you are finished making your node! Next, you will want to: + +1. Making a play command +2. Adding connect events + +### Making a play command + +To make a play command, you will need to make a function to connect and play audio in a voice channel. + +```py title="Play Command Example" +import typing + +@bot.slash_command(name="play") +async def play(ctx, search: str): + # First we may define our voice client, + # for this, we are going to use typing.cast() + # function just for the type checker know that + # `ctx.voice_client` is going to be from type + # `wavelink.Player` + vc = typing.cast(wavelink.Player, ctx.voice_client) + + if not vc: # We firstly check if there is a voice client + vc = await ctx.author.voice.channel.connect(cls=wavelink.Player) # If there isn't, we connect it to the channel + + # Now we are going to check if the invoker of the command + # is in the same voice channel than the voice client, when defined. + # If not, we return an error message. + if ctx.author.voice.channel.id != vc.channel.id: + return await ctx.respond("You must be in the same voice channel as the bot.") + + # Now we search for the song. You can optionally + # pass the "source" keyword, of type "wavelink.TrackSource" + song = await wavelink.Playable.search(search) + + if not song: # In case the song is not found + return await ctx.respond("No song found.") # we return an error message + + await vc.play(song) # Else, we play it + await ctx.respond(f"Now playing: `{song.title}`") # and return a success message +``` + + + +
+ + play + +
+ Now playing: Never Gonna Give You Up +
+
+ +
+ +Now that you've done this, the only thing left to do is make your connect events. + +### Adding connect events + +The final step to this guide is connecting the node to your server when the bot goes online. + +To make it, you will want to do the following: + +```py title="Adding connect events" +@bot.event +async def on_ready(): + await connect_nodes() # connect to the server + +@bot.event +async def on_wavelink_node_ready(payload: wavelink.NodeReadyEventPayload): + # Everytime a node is successfully connected, we + # will print a message letting it know. + print(f"Node with ID {payload.session_id} has connected") + print(f"Resumed session: {payload.resumed}") + +bot.run("token") +``` + +Congratulations! You have now implemented voice playing into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/voice/receiving.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/voice/receiving.mdx new file mode 100644 index 00000000..1bc364e1 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/voice/receiving.mdx @@ -0,0 +1,130 @@ +--- +title: Receiving Voice Samples +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +# About + +Pycord tries to keep the recording of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio recording feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/audio_recording.py). + +## Starting out + +The first thing you want to do is make a cache of your voice connections. This is fairly easy; as +it's just putting a variable with an empty dictionary in our code, such as `connections = {}`. + +You will now want to create your command for recording. + +```py title="Record Command Example" +import discord + +bot = discord.Bot() +connections = {} + +@bot.command() +async def record(ctx): # If you're using commands.Bot, this will also work. + voice = ctx.author.voice + + if not voice: + await ctx.respond("You aren't in a voice channel!") + + vc = await voice.channel.connect() # Connect to the voice channel the author is in. + connections.update({ctx.guild.id: vc}) # Updating the cache with the guild and channel. + + vc.start_recording( + discord.sinks.WaveSink(), # The sink type to use. + once_done, # What to do once done. + ctx.channel # The channel to disconnect from. + ) + await ctx.respond("Started recording!") +``` + + + +
+ + record + +
+ Started recording! +
+
+ +
+ +Now you are finished making your command for voice receiving! Next, you will want to: + +1. Make your finished callback +2. Make a stop command + +### Making a Callback + +To make a callback, you will want to define the currently undefined `once_done` function inside +our command, like so: + +```py title="Recorder Callback" +async def once_done(sink: discord.sinks, channel: discord.TextChannel, *args): # Our voice client already passes these in. + recorded_users = [ # A list of recorded users + f"<@{user_id}>" + for user_id, audio in sink.audio_data.items() + ] + await sink.vc.disconnect() # Disconnect from the voice channel. + files = [discord.File(audio.file, f"{user_id}.{sink.encoding}") for user_id, audio in sink.audio_data.items()] # List down the files. + await channel.send(f"finished recording audio for: {', '.join(recorded_users)}.", files=files) # Send a message with the accumulated files. +``` + + + + finished recording audio for:{" "} + {defaultOptions.profiles.bob.author} + + + +
+ +Now that you've done this, the only thing left to do is make your stop command. + +### Making a Stop Command + +The final step to this guide is stopping the audio recording. This is the easiest step by far. + +To make it, you will want to do the following: + +```py title="Stop Recording Command" +@bot.command() +async def stop_recording(ctx): + if ctx.guild.id in connections: # Check if the guild is in the cache. + vc = connections[ctx.guild.id] + vc.stop_recording() # Stop recording, and call the callback (once_done). + del connections[ctx.guild.id] # Remove the guild from the cache. + await ctx.delete() # And delete. + else: + await ctx.respond("I am currently not recording here.") # Respond with this if we aren't recording. + +bot.run("token") +``` + +Congratulations! You have now implemented voice recording into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/fr/docusaurus-plugin-content-pagesindex.tsx b/i18n/fr/docusaurus-plugin-content-pagesindex.tsx new file mode 100644 index 00000000..84df3a9c --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-pagesindex.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import DefaultLayout from "../layouts/DefaultLayout"; +import PYCHero from "@site/src/components/PYCHero"; +import PYCButton from "@site/src/components/PYCButton"; + +export default function Home(): JSX.Element { + return ( + + +
+ Imagine a place where you can learn how to create an awesome Discord + bot, equip it with Pycord, and have it running in less than a minute. + Imagine a place where you can learn everything about Pycord. Imagine a + guide. A Pycord Guide! +

+ Whether you are a newbie or an experienced developer, you will find + everything you need to know about Pycord here. This guide will teach + you: +
    +
  • How to get a brand new bot running from scratch;
  • +
  • How to create Interactions, Context Menus and Commands;
  • +
  • In-depth concepts such as Embeds, Reactions, Help Commands, Paginators, etc;
  • +
  • Popular Topics such as working with Databases, Sharding, etc;
  • +
  • Ways to handle and manage common errors and best practices for bots;
  • +
  • And Much More!
  • +
+
+
+ ); +} diff --git a/i18n/fr/docusaurus-theme-classic/footer.json b/i18n/fr/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..ffb8a652 --- /dev/null +++ b/i18n/fr/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Pycord Development, All rights reserved.", + "description": "The footer copyright" + } +} diff --git a/i18n/fr/docusaurus-theme-classic/navbar.json b/i18n/fr/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..473b847e --- /dev/null +++ b/i18n/fr/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "Pycord Guide", + "description": "The title in the navbar" + }, + "item.label.Home": { + "message": "Home", + "description": "Navbar item with label Home" + }, + "item.label.Docs": { + "message": "Docs", + "description": "Navbar item with label Docs" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + }, + "item.label.Source": { + "message": "Source", + "description": "Navbar item with label Source" + } +} diff --git a/i18n/hi/code.json b/i18n/hi/code.json new file mode 100644 index 00000000..9cce6148 --- /dev/null +++ b/i18n/hi/code.json @@ -0,0 +1,404 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { + "message": "Toggle the collapsible sidebar category '{label}'", + "description": "The ARIA label to toggle the collapsible sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search here", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.algoliaLabel": { + "message": "Search by Algolia", + "description": "The ARIA label for Algolia mention" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorite", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "You might want to check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Algolia" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Try searching for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Believe this query should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/i18n/hi/docusaurus-plugin-content-blog/options.json b/i18n/hi/docusaurus-plugin-content-blog/options.json new file mode 100644 index 00000000..9239ff70 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/hi/docusaurus-plugin-content-docs/current.json b/i18n/hi/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..36b4849a --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,46 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.defaultSidebar.category.Getting Started": { + "message": "Getting Started", + "description": "The label for category Getting Started in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Interactions": { + "message": "Interactions", + "description": "The label for category Interactions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Application Commands": { + "message": "Application Commands", + "description": "The label for category Application Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.UI Components": { + "message": "UI Components", + "description": "The label for category UI Components in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Extensions": { + "message": "Extensions", + "description": "The label for category Extensions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Commands": { + "message": "Commands", + "description": "The label for category Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Pages": { + "message": "Pages", + "description": "The label for category Pages in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Voice": { + "message": "Voice", + "description": "The label for category Voice in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Popular Topics": { + "message": "Popular Topics", + "description": "The label for category Popular Topics in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.More": { + "message": "More", + "description": "The label for category More in sidebar defaultSidebar" + } +} diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png b/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png new file mode 100644 index 00000000..7480e1da Binary files /dev/null and b/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png differ diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg b/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg new file mode 100644 index 00000000..ce6b5110 Binary files /dev/null and b/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg differ diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png b/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png new file mode 100644 index 00000000..846eee15 Binary files /dev/null and b/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png differ diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png b/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png new file mode 100644 index 00000000..32a47d04 Binary files /dev/null and b/i18n/hi/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png differ diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/_category_.json new file mode 100644 index 00000000..309b494a --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 5, + "label": "Extensions", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json new file mode 100644 index 00000000..652aa4ee --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Bridge" +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx new file mode 100644 index 00000000..81545fa2 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx @@ -0,0 +1,190 @@ +--- +title: Bridge +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +## Concept + +Let's say that you want to make a command that is both a Slash Command and a Prefixed Command. Now, you could just copy and paste the code from the first command callback to the other and make some adjustments, but that's not very efficient. + +This is where the `ext.bridge` module comes in. It allows you to use one callback to make both a Slash Command and a Prefixed Command. + +### Example Usage + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def hello(ctx): + await ctx.respond("Hello!") + +bot.run("TOKEN") +``` + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+
+ +## Syntax + +First, instead of using `discord.Bot` or `commands.Bot`, we use `bridge.Bot`. `bridge.Bot` does inherit from `commands.Bot`, so you can do anything with `bridge.Bot` that `commands.Bot` can do. +Then, we define a command with `@bot.bridge_command()`. This makes a Bridge Command, which has both a Prefixed Command counterpart and a Slash Command counterpart. +Next, the callback has access to a `ctx` object, which is the context of the command. This context is either of `BridgeApplicationContext` type or `BridgeExtContext`. Because of that, it makes detecting how the function was called easier. + +### Using Bridge Commands in a Cog + +Like Slash Commands and Prefixed Commands, you can use Bridge Commands in a Cog. You can do this by using the `bridge_command` decorator. Here's an example: + +```python +import discord +from discord.ext import bridge, commands + +class Greetings(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @bridge.bridge_command() + async def hello(self, ctx): + await ctx.respond("Hello!") + + @bridge.bridge_command() + async def bye(self, ctx): + await ctx.respond("Bye!") + +def setup(bot): + bot.add_cog(Greetings(bot)) +``` + +The cog will automatically split the Bridge Command into their Slash Command and Prefixed Command counterparts. + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+ + +
+ + bye + +
+ Bye! +
+ + + !bye + + + +
+ + !bye + +
+ Bye! +
+
+ +### Deferring + +You can defer if you want to communicate to the user that your bot is busy processing the command. This is done by using `ctx.defer()`. For the Slash Command implementation, `ctx.defer()` calls the function that gives out a "Bot is thinking" message. For the Prefixed Command implementation, `ctx.defer()` enables the typing indicator. + + + +### Options + +Options are pretty straightforward. You just specify them like you do with prefixed commands, and you're all set! + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def sum(ctx, a: int, b: int): + await ctx.respond(a + b) + +bot.run("TOKEN") +``` + + + +
+ + sum + +
+ 4 +
+ + + !sum 2 2 + + + +
+ + !sum 2 2 + +
+ 4 +
+
diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json new file mode 100644 index 00000000..63f8e08e --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx new file mode 100644 index 00000000..bf345c07 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx @@ -0,0 +1,56 @@ +--- +title: Command Groups +--- + +Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk +remove`. + +## Syntax + +Creating a command group is very simple. + +```python title="Command Groups Example" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!') + +@bot.group() +async def afk(): + pass + +@afk.command() +async def set(): + ... + +@afk.command() +async def remove(): + ... + +# Another command group + +@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. +async def math(ctx): + await ctx.send('Subcommand not found') + +@math.command() +async def add(ctx, a: int, b: int): + ... + +@math.command() +async def subtract(ctx, a: int, b: int): + ... +``` + +To create a command group, the command's decorator must be `@bot.group`. Once you have a command with +that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand +groups! + + + +:::info Related Topics + +- [Prefixed Commands](./prefixed-commands.mdx) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx new file mode 100644 index 00000000..acbdc0a8 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx @@ -0,0 +1,481 @@ +--- +title: Help Command +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Pycord's `commands` extension comes with a built-in help command. In this guide, we will take a look at them as well as learn how to create your own. Let's dive in! + +:::note + +This guide demonstrates using object-oriented programming and subclassing to make a help command for your +Pycord bot. It is important to understand these two concepts before continuing. + +**Learning Resources**: + +- [W3Schools - Python Subclassing](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools - Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +::: + +## The Wrong Way + +A popular way to create a help command is to disable the built-in help command and create your own. This is not recommended as it will lead to a lot of confusion. + +```python title="The Wrong Way" +bot = commands.Bot(command_prefix='!', help_command=None) +# OR +bot.help_command = None +# OR +bot.remove_command("help") + +@bot.command() +async def help(ctx, *, argument=None): + ... +``` + +While it's possible to create a help command this way, doing so does not utilize the full capabilities +of making one with Pycord. Making a help command with subclassing and OOP will save time and effort. + +## Types of Help Commands + +There are two types of built-in help commands: + +- [`DefaultHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand) +- [`MinimalHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand) + +`DefaultHelpCommand` is the command enabled by default. It isn't the best looking, but `MinimalHelpCommand` can help make it look a bit better. + + + + +```python title="Default Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.DefaultHelpCommand()) # help_command is DefaultHelpCommand by default so it isn't necessary to enable it like this +# We enable it here for the sake of understanding + +... + +bot.run("token") +``` + + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ + +```python title="Minimal Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.MinimalHelpCommand()) + +... + +bot.run("token") +``` + + + + !help + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+ +
+ +
+ +## Updating Built-in Help Commands + +Let's try to make the `MinimalHelpCommand` look better. We can do this by putting its content in an +embed. + +```python title="Minimal Help Command Example" +bot = commands.Bot(command_prefix='!') + + +class MyNewHelp(commands.MinimalHelpCommand): + async def send_pages(self): + destination = self.get_destination() + for page in self.paginator.pages: + emby = discord.Embed(description=page) + await destination.send(embed=emby) + +bot.help_command = MyNewHelp() +``` + +Let's go through the code. + +First, we create a new class called `MyNewHelp`. This class is a subclass of `MinimalHelpCommand`. + +Next, we override the `send_pages` method. This method is responsible for sending the help command to +the user. We override this method because we don't want to change the content of the pages, just how +they are sent. + +We use the `get_destination` method to get the destination of the message. This is the channel or use that the help +command is to be sent to. + +We use the `paginator.pages` property to get the different pages of the help command. We put the page +in an embed, and then send the embed to the destination channel. + +Finally, we set this as our new help command using `bot.help_command = MyNewHelp()`. + + + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a + category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+
+ +## Creating Your Help Command + +Not satisfied with the built-in help commands? You can create your own! + +For this, we will subclass the `HelpCommand` class. + +There are 4 methods that we need to override: + +- `HelpCommand.send_bot_help(mapping)` that gets called with `help` +- `HelpCommand.send_command_help(command)` that gets called with `help ` +- `HelpCommand.send_group_help(group)` that gets called with `help ` +- `HelpCommand.send_cog_help(cog)` that gets called with `help ` + +### Bot Help + +```python title="Bot Help Example" +class MyHelp(commands.HelpCommand): + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help") + for cog, commands in mapping.items(): + command_signatures = [self.get_command_signature(c) for c in commands] + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's go through the code. + +- First, we create a new class called `MyHelp`. This class is a subclass of `HelpCommand`. + +- Next, we override the `send_bot_help` method. This method is responsible for sending the main help + command to the user. + +- We create an embed with the title "Help". + +- We iterate through `mapping.items()`, which returns a list of tuples, the first element being the + cog and the second element being a list of commands. + +- By using `self.get_command_signature(c)` we get the signature of the command, also known as the + `parameters` or `arguments`. + +- There is a chance that the cog is empty, so we use `if command_signatures:`. + +- We get the name of the cog using `getattr(cog, "qualified_name", "No Category")`. This calls the + cog's attribute `qualified_name` which returns "No Category" if the cog has no name. + +- We add a field to the embed with the name of the cog and the value of the command signatures. + +- Finally, we send the embed to the channel. + +Let's improve the code a little. + +```python title="Improved Bot Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + command_signatures = [self.get_command_signature(c) for c in filtered] + + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Now the help command won't show commands that the user can't use, as well as aliases for commands. +Let's get the help command to show command aliases. + +### Command Help + +This function is called when the user uses `help `. + +```python title="Command Help Example" +class MyHelp(commands.HelpCommand): + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command), color=discord.Color.random()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's quickly go through the code we haven't discussed yet. + +- In line 3, we create an embed with a title the signature of the command (so that the title of the + embed looks like ` [parameter]`), and a random color. + +- In lines 4 and 5, we get the command's `help` description and add it to the embed. The help description + of a command can be specified in the docstrings of a command function. For example: + + ```` + ```python + @bot.command() + async def ping(ctx): + """Returns the latency of the bot.""" + await ctx.send(f"Pong! {round(bot.latency * 1000)}ms") + ``` + ```` + +- Line 6 is shorthand for + + ```python + alias = command.aliases + if alias: + ... + + # is the same as + + if alias := command.aliases: + ... + ``` + + A very helpful (but not well-known) Python shorthand! + +- In line 7, we get the aliases of the command and add them to the embed. + +### Cog Help + +This is pretty easy! + +```python title="Custom Cog Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_cog_help(self, cog): + embed = discord.Embed(title=cog.qualified_name or "No Category", description=cog.description, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(cog.get_commands()): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Once again, we create an embed, get the commands that the user can use, and add them to the embed. + +### Group Help + +Similar to the cog help, this is pretty easy! + +```python title = "Custom Group Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_group_help(self, group): + embed = discord.Embed(title=self.get_command_signature(group), description=group.help, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(group.commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Add all of these methods together, and you have a fully functioning help command! + +
+Click to see the final code for this section +
+ +:::note + +The following code has been slightly edited from the tutorial version. + +::: + +```python title="Custom Help Command Example" +class SupremeHelpCommand(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + if command_signatures := [ + self.get_command_signature(c) for c in filtered + ]: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command) , color=discord.Color.blurple()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_help_embed(self, title, description, commands): # a helper function to add commands to an embed + embed = discord.Embed(title=title, description=description or "No help found...") + + if filtered_commands := await self.filter_commands(commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No help found...") + + await self.get_destination().send(embed=embed) + + async def send_group_help(self, group): + title = self.get_command_signature(group) + await self.send_help_embed(title, group.help, group.commands) + + async def send_cog_help(self, cog): + title = cog.qualified_name or "No" + await self.send_help_embed(f'{title} Category', cog.description, cog.get_commands()) + +bot.help_command = SupremeHelpCommand() +``` + +
+
+ +## Command Attributes + +How can you add cooldowns, set aliases, and change the name of help commands? Command attributes can +help you do all of that, and more! + +```python title="Help Command Attributes" +attributes = { + 'name': "help", + 'aliases': ["helpme"], + 'cooldown': commands.CooldownMapping.from_cooldown(3, 5, commands.BucketType.user), +} + +# You need to use CooldownMapping.from_cooldown(rate, per, type) + +bot.help_command = MyHelp(command_attrs=attributes) +``` + +## Error Handling + +When a user attempts to use a command that does not exist, we need to inform the user. +We can do this by overriding the `send_error_message` function. + +```python title="Custom Help Error Example" +class MyHelp(commands.HelpCommand): + async def send_error_message(self, error): + embed = discord.Embed(title="Error", description=error, color=discord.Color.red()) + channel = self.get_destination() + + await channel.send(embed=embed) +``` + + + + !help update_pycord + + + + Command 'update_pycord' not found. + + + + +## Credits + +Most of the content from this guide is from +[InterStella0's walkthrough guide on subclassing HelpCommand](https://gist.github.com/InterStella0/b78488fb28cadf279dfd3164b9f0cf96). +Thanks to InterStella0 for making this guide amazing. + +:::info Related Topics + +- [Subclassing Bots](../../Popular-Topics/subclassing-bots) +- [Prefixed Commands](./prefixed-commands) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx new file mode 100644 index 00000000..b8f567fd --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx @@ -0,0 +1,324 @@ +--- +title: Prefixed Commands +description: Learn how to use the commands extension for Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Before Discord added slash commands, all bots had prefixed commands. A user would type the bot's prefix +followed by a word or phrase to invoke a command, such as `?help` or `!help`. +However, this prefixed commands system isn't native to Discord! Developers made use of an `on_message` +event to check if the message began with a certain character, then invoke the command. Every time a +message was sent, the bot would see the message and check for its "prefix" + +The syntax becomes a little more complicated when you want to have multiple commands. There are several +disadvantages to this system. This is where the commands extension comes in. `ext.commands` has +various advantages, such as: + +- Simpler syntax +- Easier to use +- Easier to parse user input +- Comes with built-in help commands +- Comes with a built-in system for categorizing commands + + + + +```python title="Prefixed Commands with Events" +import discord + +client = discord.Client() + +@client.event +async def on_message(message): + if message.content.startswith("!ping"): + await message.channel.send("Pong!") + + elif message.content.startswith("!announce"): + if len(message.content.split(" ")) < 3: + await message.channel.send("You need to specify a title and a message. Correct usage: `!announce Hello Hello everyone!`") + return + + msg = message.content.split(" ", 2) + title = msg[1] + content = msg[2] + + await message.channel.send("**{}**\n{}".format(title, content)) + + elif message.content.startswith("!"): + await message.channel.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !help + + + Unknown Command. + +
+ +
+ + +```python title="The Commands Extension" +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix="!", intents=intents) + +@bot.command() +async def ping(ctx): + await ctx.send("Pong!") + +@bot.command() +async def announce(ctx, title, *, message): + await ctx.send("**{}**\n{}".format(title, message)) + +@bot.event +async def on_command_error(ctx, error): + if isinstance(error, commands.CommandNotFound): + await ctx.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !pycord + + + Unknown command. + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+ !announce +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The commands extension has many more uses. This example only showcases the basic features mentioned +in the previous example. Other things you can do with the commands extension include using a different +built-in help command and creating your own. The following tutorials showcase these. + +::: + +
+
+ +## Syntax + +Before we check out the syntax, let's take a look at the bot classes. + +> `discord.Client` - Contains only events. +> +> `discord.Bot` - Subclasses `discord.Client`, adds commands. +> +> `discord.ext.commands.Bot` - Subclasses `discord.Bot`, adds prefixed commands, cogs, and more. + +This means that `discord.ext.commands.Bot` has both slash commands and prefixed commands, as well as +events, cogs and more. + +Now let's look at the syntax. + +```python title="A Simple Prefixed Bot" +import discord +from discord.ext import commands # Import the commands extension +# discord.ext.commands are not the same as discord.commands! + +intents = discord.Intents.default() #Defining intents +intents.message_content = True # Adding the message_content intent so that the bot can read user messages + +bot = commands.Bot(command_prefix="!", intents=intents) # You can change the command prefix to whatever you want. + +@bot.command() # This is the decorator we use to create a prefixed command. +async def ping(ctx): # This is the function we will use to create the command. + await ctx.send("Pong!") # This is the response the bot will send. + + +bot.run("token") # Run the bot with your token. +``` + + + + !ping + + + Pong! + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The help command is a built-in command and is enabled by default. You will learn more about it in the +following guides. + +::: + +## Parameters + +Prefixed commands can take parameters, just like slash commands. You can specify the parameters in +the function itself. + +```python title="Parameters Example 1" +@bot.command() +async def echo(ctx, *, message): + await ctx.send(message) +``` + +`ctx` is the context of the message. `*` means that the parameter can be any number of words. `message` +is the parameter. If you had not passed `*`, `message` would only have been one word. + +For example, if a user had used `!echo hello world`, `message` would have been `hello`. Since we +passed `*`, `message` is `hello world`, or the rest of the message. + +We can pass multiple parameters too! + +```python title="Parameters Example 2" +@bot.command() +async def echo(ctx, channel:discord.TextChannel, title, *, message): + await channel.send("**{}**\n{}".format(title, message)) +``` + +In the example above, `channel` is a parameter that is of type `discord.TextChannel`. When you +specify the type of the parameter, Pycord will automatically try to convert the parameter to that type. +That is why you can use `channel.send` directly without needing to convert it first. + +We also have a new parameter, `title`. This does not have a type, so it will be a string. `*` means +that the rest of the message belongs to the next parameter, in this case, `message`. + +When a user types `!echo #general Greetings! Hello World!`, `channel` will be the text channel +`#general`, `title` will be `Greetings!` and `message` will be `Hello World!`. + +Let's take an example where the user passes `!echo #general Holiday Greetings! Greetings to you all!`. +Here, the user wants the title to be "Holiday Greetings!" and the message to be "Greetings to you all!". +However, since Pycord parses the message at whitespaces, the title will end up being "Holiday" and the +message "Greetings! Greetings to you all!". The user can prevent this by typing `!echo "Holiday +Greetings!" Greetings to you all!`. + + + + + + !echo #general Holiday Greetings! Greetings to you all! + + + Holiday +
+ Greetings! Greetings to you all! +
+ + !echo #general "Holiday Greetings!" Greetings to you all! + + + Holiday Greetings! +
+ Greetings to you all! +
+
+ +Let's check out another example for parameters and parameter types. + +```python title="Parameters Example 3" +import random + +@bot.command() +async def gtn(ctx, guess:int): + number = random.randint(1, 10) + if guess == number: + await ctx.send("You guessed it!") + else: + await ctx.send("Nope! Better luck next time :)") +``` + +If you had not specified the type of the parameter, it would have been a string. And since `"5"` is not +the same as `5` in python, the bot would have responded with "Nope! Better luck next time :)". +Even if you do not specify the type of the parameter, you can still convert it later on, in this case, +with `int(guess)`. + +:::info Related Topics + +- [Command Groups](groups) +- [Rules and Common Practices](../../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json new file mode 100644 index 00000000..baeba701 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Pages", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx new file mode 100644 index 00000000..be90b035 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx @@ -0,0 +1,168 @@ +--- +title: Paginator Basics +--- + +# Paginator Basics + +## [Page](https://docs.pycord.dev/en/stable/ext/pages/index.html#page) + +This class contains two attributes: `content` and `embeds`, which correspond to the attributes of the same name on the +`discord.Message` class. +To create a new Page, use the following syntax: + +```py +import discord +page = Page(content="My Page Content", embeds=[discord.Embed(title="My First Embed Title")]) +``` + +## [PageGroup](https://docs.pycord.dev/en/stable/ext/pages/index.html#pagegroup) + +This class represents a group of pages. It uses most of the same parameters as `Paginator`, which allows each +`PageGroup` to effectively have its own settings and behaviours. + +## [Paginator](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator) + +This is the main class for `ext.pages`, and is used to control most of the functionality of the extension. + +In its most basic form, with no arguments provided (default values listed below), a paginator can be created like so: + +```py title="Paginator Example" +import discord +from discord.ext.pages import Paginator, Page + +my_pages = [ + Page( + content="This is my first page. It has a list of embeds and message content.", + embeds=[ + discord.Embed(title="My First Embed Title"), + discord.Embed(title="My Second Embed Title"), + ], + ), + Page( + content="This is my second page. It only has message content.", + ), + Page( + embeds=[ + discord.Embed( + title="This is my third page.", + description="It has no message content, and one embed.", + ) + ], + ), +] +paginator = Paginator(pages=my_pages) +``` + +The only required parameter for `Paginator` is the `pages` parameter, which is usually a list of `Page` objects. + +You can also pass in a list of `PageGroup` objects, a list of strings, a list of embeds, or a list of lists of embeds. + +Once the `Paginator` instance is created, you can call either +[`Paginator.send()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.send) +or [`Paginator.respond()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.respond) +to send a message or response with the paginator's contents. + +#### Depending on what's being passed to the `pages` parameter, the behaviour of the paginator may differ: + +- Passing a list of `PageGroup` objects will essentially treat each `PageGroup` as its own Paginator, with most + `Paginator` attributes able to be set independently for each `PageGroup`. + \- Each `PageGroup` accepts its own `pages` parameter, which inherits the same behaviour as the `pages` parameter + of `Paginator`, except it cannot contain other `PageGroup` objects. +- If a page is a `Page` object, this will allow you to specify both the `discord.Message.content` and + `discord.Message.embeds` attributes for a page. + \- **This is the preferred method of defining a page.** +- If a page is a string, this will be used for the `discord.Message.content` attribute. This type of page cannot have + any embeds. +- If a page is a list of embeds, this will be used for the `discord.Message.embeds` attribute. This type of page + cannot have any message content. +- If a page is a list of lists of embeds, each parent list item will create a page containing all embeds from its + child list. This type of page cannot have any message content. + +#### Parameters for the `Paginator` class which have default values: + +- `show_disabled` **:** `True` + - Show buttons that are disabled (i.e. can't be clicked) +- `author_check` **:** `True` + - Only the author can interact with the paginator. +- `timeout` **:** `180` _(seconds)_ + - The paginator will time out and become inactive after this many seconds. +- `disable_on_timeout` **:** `True` + - If the paginator times out, it will be automatically disabled and all buttons will be unusable. +- `use_default_buttons` **:** `True` + - Use the default set of 4 buttons and a page indicator. +- `show_indicator` **:** `True` + - When using the default buttons, shows a middle 5th button with the current/total page numbers. + +**For other parameters that can be set on initialization, please check the +[API Reference](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator)** + +## [PaginatorButton](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatorbutton) + +This class represents a button used to navigate between the pages of a paginator. It's also used to create the page +indicator. + +When creating your own custom buttons, you can either use this class directly or subclass it to add any additional +functionality you may need. + +To add custom buttons to the paginator instead of the default navigation buttons, you have two options to do so: + +1. **Using the `custom_buttons` parameter of `Paginator`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + buttons = [ + PaginatorButton("first", label="<<-", style=discord.ButtonStyle.green), + PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), + PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True), + PaginatorButton("next", label="->", style=discord.ButtonStyle.green), + PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), + ] + paginator = Paginator( + pages=["Page 1", "Page 2", "Page 3"], + show_indicator=True, + use_default_buttons=False, + custom_buttons=buttons, + ) + ``` +2. **Using `Paginator.add_button()`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"], use_default_buttons=False) + paginator.add_button(PaginatorButton("prev", label="<", style=discord.ButtonStyle.green)) + paginator.add_button(PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True)) + paginator.add_button(PaginatorButton("next", label=">", style=discord.ButtonStyle.green)) + ``` + +If you want to use the default navigation buttons, but not all of them, you can also use `Paginator.remove_button()` to +selectively remove them: + +```py +from discord.ext.pages import Paginator + +paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"]) +paginator.remove_button("first") +paginator.remove_button("last") +``` + +## [PaginatorMenu](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatormenu) + +This class represents the `discord.Select` menu used to navigate between `PageGroup` instances. In most situations, you +will not need to interact with this class directly. + +If you do subclass it, you'll likely want to call `super()` in your `__init__` method to ensure that the `PageGroup` +navigation functionality is retained. + +## Usage Examples + +For a comprehensive list of examples showing all `Paginator` functionality, please see the +[example in cog form](https://github.com/Pycord-Development/pycord/blob/master/examples/views/paginator.py) in the repo. + +## Support and Feedback + +If you have any questions, suggestions, or feedback for `ext.pages`, please join the +[Discord server](https://discord.gg/pycord). diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx new file mode 100644 index 00000000..b8d68925 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx @@ -0,0 +1,20 @@ +--- +title: Paginator FAQ +--- + +# Paginator FAQ + +- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** + - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. + - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. + +- **How can the bot send a paginator to a different destination than where it was invoked?** + - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. + - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. + - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. + +- **How can I change the paginator's behavior without re-creating and re-sending it?** + - Use the `Paginator.update()` method. + +- **How can I make the bot actually do something with the contents of a page?** + - Use the (upcoming) `Paginator.page_action()` method. diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json new file mode 100644 index 00000000..36dfb009 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Tasks" +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx new file mode 100644 index 00000000..848f6066 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx @@ -0,0 +1,216 @@ +--- +title: Tasks +--- + +## Concept + +So you want to run a background task running at some specified interval? Thankfully, that's a common thing to do, whether you're working with some API or handling some background logic don't worry, the Pycord tasks extension is here to make life easier for you! + +With the tasks extension, you can make background tasks without worrying about the asyncio hell and mind bogglers like "what if my internet dies" and "how do I handle reconnecting" with the added benefit of a lot of useful additions that are one line of code away! + +### Example Usage + +```py +import discord +from discord.ext import tasks + +bot = discord.Bot() + +@bot.event +async def on_ready(): + very_useful_task.start() + +@tasks.loop(seconds=5) +async def very_useful_task(): + print('doing very useful stuff.') + +bot.run("TOKEN") +``` + +If you do run this code in your terminal you should see something like this after about 15 seconds: + +``` +doing very useful stuff. +doing very useful stuff. +doing very useful stuff. +``` + +For a more useful example here's a task in a cog context ripped straight from the [docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#recipes): + +```py +from discord.ext import tasks, commands + +class MyCog(commands.Cog): + def __init__(self): + self.index = 0 + self.printer.start() + + def cog_unload(self): + self.printer.cancel() + + @tasks.loop(seconds=5) + async def printer(self): + print(self.index) + self.index += 1 +``` + +As you'd expect this will increment a number and print it out every 5 seconds like so: + +```sh +0 +# 5 seconds later +1 +# 5 more seconds later +2 +# ... +``` + +## [Tasks](https://docs.pycord.dev/en/stable/ext/tasks/index.html) + +Now let's get into the nitty-gritty of tasks. + +As you've seen tasks can work in both outer scope and class contexts and the handle is roughly the same, you define a task using the `tasks.loop` decorator and use the `start` method to start it, the difference is you add the `self` argument when in a class context so since most people have all their bot's code in Cogs all the following code blocks will be in a Cog context to make it easy to copy it then apply whatever modifications you might need! + +### [Creating a task](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop) + +A look at `discord.ext.tasks.loop`'s definition in the documentation reveals that: + +1. As you've seen before it expects the time between each execution, that however doesn't have to be in seconds as + there are `seconds`, `minutes` and `hours` parameters to make it easier for us, they can also be floats in case you want + ultra-precision. +2. You can also pass in a `datetime.time` object or a sequence of them in the `time` parameter which will make it run + at the specified time(s). +3. You can pass in how many times a loop runs before it stops by passing in the `count` parameter, you can use `None` + to make it run forever which is also the default. +4. The loop function **_must_** be a coroutine. + +These are all really useful, and they aren't the only parameters so if you want to know more about them check out the +[docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop)! + +### Attributes + +A task has the following attributes: + +- `current_loop`: The current loop the task is on. +- `hours`, `minutes`, `seconds`: attributes that represent the time between each execution. +- `time`: A list of datetime.time objects that represent the times the task will run, returns `None` if no datetime + objects were passed. +- `next_iteration`: A `datetime.datetime` object that represents the next time the next iteration of the task will + run, can return `None` if the task stopped running. + +These attributes serve as a really powerful asset to get info about your loop. + +### Example + +Now let's create a cog that handles a leaderboard we have in our bot using Tasks then explain what we did after that and +also provide a refresher of how slash commands groups work in cogs. + +For the sake of this example let's pretend that we have a leaderboard module that does all the leaderboard handling for +us and that computing the leaderboard is very expensive computationally wise, so we want to store one version of it that +gets regularly updated instead of generating it every time someone calls the `/leaderboard view` command. + +```py +from discord.ext import tasks, commands +from discord.commands import SlashCommandGroup, CommandPermissions + +from leaderboard import * # Mock leaderboard module. + +class LeaderboardCog(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.update_leaderboard.start() + self.leaderboard_embed = generate_leaderboard_embed() + + leaderboard = SlashCommandGroup(name='leaderboard', description='Leaderboard commands.') + + @tasks.loop(minutes=10) + async def update_leaderboard(self): + print('Updating leaderboard...') + await update_leaderboard() + self.leaderboard_embed = generate_leaderboard_embed() + + @update_leaderboard.before_loop + async def before_update_leaderboard(self): + await self.bot.wait_until_ready() + print("About to start updating leaderboard.") + + @update_leaderboard.after_loop + async def after_update_leaderboard(self): + leaderboard_cleanup() + print("Stopped updating leaderboard.") + + @update_leaderboard.error + async def update_leaderboard_error(self, error): + print(f"Oh no, an error occurred while updating the leaderboard. Error: {error}") + + @leaderboard.command() + async def view(self, ctx): + await ctx.respond(embed=self.leaderboard_embed) + + @leaderboard.command() + async def update_info(self, ctx): + await ctx.respond(f"""***Leaderboard Info***\n + Last update: {(600 - self.update_leaderboard.next_iteration.timestamp())//60} minutes ago.\n + Next update: in {self.update_leaderboard.next_iteration.timestamp() // 60} minutes.\n + Time between loops: {self.update_leaderboard.minutes} minutes.\n + Times updated this session: {self.update_leaderboard.current_loop}. + Running? {self.update_leaderboard.is_running()} + Failed? {self.update_leaderboard.failed()}""", ephemeral=True) + + # Now for the owner only commands: + + leaderboard_config = SlashCommandGroup(name="leaderboard_config", description="Leaderboard configuration commands", permission=[CommandPermissions("owner", 2, True)]) + + @leaderboard_config.command() + async def set_time_between_updates(self, ctx, minutes: int): + self.update_leaderboard.change_interval(minutes=minutes) + await ctx.respond(f"Set time between updates to {minutes} minutes.") + + @leaderboard_config.command() + async def stop(self, ctx): + self.update_leaderboard.stop() + await ctx.respond("Stopped the leaderboard update.") + + @leaderboard_config.command() + async def restart(self, ctx): + self.update_leaderboard.restart() + await ctx.respond("Restarted the leaderboard update.") + +def setup(bot): + bot.add_cog(LeaderboardCog(bot)) +``` + +Phew, that was quite a bit of code. + +Now to explain what's going on: + +First things first we create a cog and in its `__init__` function we start the `update_leaderboard` task and generate +the first instance of our leaderboard's embed. + +After that, we define the `update_leaderboard` task using the `loop` decorator, and we make it run every ten minutes by +passing 10 to the `minutes` parameter. + +Then that we define the `before_update_leaderboard` task using the `before_loop` decorator, and we make it wait until the +bot is ready before starting the task. + +Next up we define the `after_update_leaderboard` task using the `after_loop` decorator, and we make it clean up the +leaderboard when the loop finally stops running. + +Then we define the `update_leaderboard_error` task using the `error` decorator, and we make it print any errors that may +occur while we update our leaderboard to the console. + +Then we get into the fun stuff, we create a slash command group using the `SlashCommandGroup` class and name it +`leaderboard`, we then create the `view` sub-command which sends the embed generated when the leaderboard is updated and +`update_info` which shows a lot of data about the task using some attributes and functions available to us. + +We also create a slash command group called `leaderboard_config` which is only available to the owner of the bot. + +Then we create the `set_time_between_updates` sub-command which takes in the time in minutes and changes the time +between updates of the leaderboard using the `change_interval` method, the `stop` sub-command which stops the task using +the `stop` method and `restart` which restarts the task using the `restart` method. + +Finally, we add the `LeaderboardCog` cog to the bot, and we're done! + +I'd highly recommend you check the tasks extension +[documentation](https://docs.pycord.dev/en/stable/ext/tasks/index.html) for more info on how to use them and what other +functions they have. diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/_category_.json new file mode 100644 index 00000000..9d6255f5 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 3, + "label": "Getting Started", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx new file mode 100644 index 00000000..864206a6 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx @@ -0,0 +1,262 @@ +--- +title: Creating Your First Bot +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +Excited to create your first bot? Once you [install Pycord](../installation.mdx), you can start right +away! + +## Creating the Bot Application + +Just like how you need to sign up to use Discord, your bot also has to be signed up. To do this, +you should: + +1. Go to the [Discord Developer Portal](https://discord.com/developers/applications) and click + on . +2. Give your bot a name, and click . +3. Now, you should see a page like this. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdW3OQnwUhacopqSWw%2F-Mjd_-mxrJCrzmaXrAg8%2Fimage.png?alt=media&token=b8e2ae6c-2290-4d37-ad7c-eb412f3fb00e) +4. Click on the tab on the left side of the screen. +5. Click on . +6. You can give it a name, change the Avatar, etc. + +## Inviting the bot + +Now, lets get the bot added to some servers. Go to the tab +in the left pane and select `bot` and `applications.commands` as scopes. + +You may want your bot to have application commands, which is what the `application.commands` scope +allows your bot to make. + +Next, you want to choose what permissions the bot will have and select them. For now, you can just +give your bot the `administrator` permission, which gives your bot every permission. Once you select +your bot's permissions, click on to get the bot invite link. + +:::tip + +When your bot is all ready to go, make sure that administrator permissions aren't selected unless +your bot truly needs them. Try selecting only permissions the bot will need. For testing, +Administrator permissions are fine. + +::: + +![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-Mk6tNY3LfDkjd6pqdpL%2F-Mk6tkdpddEWoa2jczZk%2Fimage.png?alt=media&token=52c8a29f-a798-48f8-a8c7-4ecca2681f79) + +You can use this link to invite the bot. + +## Tokens + +Now that you have an account for your bot, you need to log in. To log in, we need the bot's +password. All users and bots have a "token." You may think of this token as a password, as this allows +us to log our bot into Discord. + +Tokens are "snowflakes." Not actual snowflakes, though. Just like how no two snowflakes in real life have the same +pattern, snowflakes in computers are unique things - no two bots have the same token - so a token is +considered a snowflake. A Discord user ID is also a snowflake. + +Now, lets get your bot's token. To do this, you want to: + +1. Go back to the tab. +2. Click on the button in the "Token" section. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdbU12JISJorAZxrKH%2F-MjdbpUsapzb5n15Po5P%2Fimage.png?alt=media&token=118e259f-940a-4f6c-b3a3-c29f3a54100d) + +Now, you have your bot's token copied to your clipboard. + +:::danger + +Do not, under any circumstances, give your token to anyone. Even if you are contacted by someone +claiming to be Discord staff, do not give them your bot's token. They are lying to you to try and +gain access to your bot. If an unauthorized user gains access to your bot's token, they can access +your bot and use it in malicious ways. + +Never push your token to GitHub or include it in your code. One way to prevent your token from +getting leaked is to store it in `.env` files. + +::: + +### Protecting Tokens + +#### Using dotenv + +You can store your tokens in `.env` files. This is a simple way to store sensitive information. + +1. Create a file with the name `.env` (only the extension, with a dot/period at the start and without a name before it). +2. Define the token in the `.env` file (replace the example value with your token). + ```env title=".env" + TOKEN = NzkyNzE1NDU0MTk2MDg4ODQy.X-hvzA.Ovy4MCQywSkoMRRclStW4xAYK7I + ``` +3. Install [`python-dotenv`](https://pypi.org/project/python-dotenv/). + ```bash + python -m pip install python-dotenv + ``` +4. Load the token from the `.env` file. + ```python + import dotenv + dotenv.load_dotenv() + token = str(os.getenv("TOKEN")) + ``` +5. Pass your token as parameter when running the bot. + ```python + client.run(token) + ``` + +:::tip + +If you are using Git to track your bot's changes, you should create a file called `.gitignore` and add +`.env` to it. This stops your `.env` file from getting tracked along with the rest of your code, and +will not be pushed to a remote Git repository. As a consequence, it will stay secure on your local machine. + +::: + +## Coding the Basics + +Here's an example of code you'll write with Pycord: + +```py +import discord +import os # default module +from dotenv import load_dotenv + +load_dotenv() # load all the variables from the env file +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") + +bot.run(os.getenv('TOKEN')) # run the bot with the token +``` + + + +
+ + hello + +
+ Hey! +
+
+
+ +Let's go through the code. First, the imports. + +```py +import discord +import os +from dotenv import load_dotenv +``` + +In the first line, `import discord`, we import Pycord. Although you install Pycord with `pip install py-cord`, you +import it with `import discord`. This is so it's as easy as possible when switching from Discord.py to Pycord. + +We then import `os` and `dotenv`. `os` is a default module that we will use to get the token from the env file. `dotenv` +is a module that we will use to load the env file. You installed this with `pip install python-dotenv`. + +Next, we load the env file with `load_dotenv()`. + +```py +bot = discord.Bot() +``` + +In this line, we create a new instance of [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). +In this object, we can pass various parameters for configuration purposes, such as `owner_ids` +and [`intents`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```py +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") +``` + +We use the [`event`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) decorator to override +the [`on_ready`](https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready) function to define an +event that is automatically called when the bot is ready to use. + +```py +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") +``` + +Here, we use the [`slash_command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.slash_command) +decorator to define a slash command. We specify the `name` and `description` arguments. If not +specified, the name of the slash command would be the function name and the command description would +be empty. + +Optional: We type-hint the context parameter (`ctx`) as [`discord.ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext). In modern IDEs, type-hinting allows access to autocompletion and docstrings. You can read more about type-hinting [here](https://docs.python.org/3/library/typing.html). + +Finally, you want to run the bot using the token specified in the `.env` file. + +Now you have finished creating your first Pycord bot! What we have shown you is just the basic structure +of a bot. You can do a lot more with Python and Pycord knowledge, as well as your imagination! Pycord +will not limit your bot's abilities. + +:::note + +The part where we load the token from the environmental variables is not required. You may use another way to keep your token secure, or, although not recommended, simply specify the token normally as a string, as shown below. + +
+A Basic Bot without securing the token +
+ +```py +import discord + +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.send("Hey!") + +bot.run("TOKEN") +``` + +
+
+ +::: + +## FAQ + +### How do I make prefixed commands? + +Prefixed commands are an older method of creating bot commands that listen for messages and replies +if the message starts with a certain character. You can read [this page](../extensions/commands/prefixed-commands.mdx) +to learn more about prefixed commands. + +### How do I setup modules/cogs? + +[Cogs](../popular-topics/cogs) are a great way to organize your commands by putting them into +groups called cogs. Cogs are separate files that your bot loads to get the commands inside. +You can read more about cogs, as well as learn how to use them and their benefits, +[here](../popular-topics/cogs). + +### How do I add components, such as buttons and dropdown menus, to my bot? + +Pycord makes it very easy to use Message Commands with your bot by using the `discord.ui` module. +To learn more, read about Message Commands in our [interactions directory](../interactions). + +:::info Related Topics + +- [Prefixed Commands](../extensions/commands/prefixed-commands) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx new file mode 100644 index 00000000..2a68677b --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx @@ -0,0 +1,109 @@ +--- +title: Hosting Your Pycord Bot +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Hosting Your Pycord Bot + +If you're completely new to this, you might have thought something along the lines of "Yay! I got my +bot working," after following our [Creating your First Bot](creating-your-first-bot) guide, only +to close your IDE or shut down your computer to find your bot offline. + +The reason for this is that programs have to be hosted somewhere, meaning some machine somewhere has +to constantly run your bot. There are tons of hosting services that can help you host your bot for +little to no cost. + +## Can I get a Clear Explanation? + +Sure thing. When you run your bot, it first makes a connection to Discord's API. Once that's done, +Pycord sends "heartbeats" to Discord. "heartbeats" are small packets sent at a set interval telling +Discord that your bot is indeed still alive. If Discord doesn't receive a heartbeat after a certain +amount of time, your bot is pronounced dead and buried in the graveyard (not really). It is, though, +taken offline and its connection with Discord is terminated. + +Once you close the terminal that you've run your program on, the program is no longer running, and +the bot stops sending heartbeats and can no longer process commands. This is why you have to constantly +keep the process running. + +This goes for all programs, in a different nature. If the code isn't compiled/built/assembled/interpreted, +it can't be running. + +## What is a Host? + +A host is a server or container for running code offered by a **hosting provider.** There are a lot +of hosting providers, such as bigger ones like Amazon Web Services (AWS) and Google Cloud, and smaller +ones like GalaxyGate and DigitalOcean. + +There are three types of hosts. + + + + Shared hosting is a type of hosting where multiple people share one VPS. Getting a spot on + a shared host is usually cheap, sometimes even free. Shared hosts do not give you a lot of + resources, from less than a gigabyte of RAM (usually 512MB on free hosts) and half of a CPU + with very little storage. Shared hosting is usually used for website hosting and is not + recommended for hosting a Discord bot. + + + A virtual private server (VPS) is a virtual computer (virtual machine) that is rented out to + customers. Most people use a VPS for hosting their projects such as Discord bots. You can get + anywhere from less than a gigabyte of RAM and a less powerful CPU to just under one hundred + gigabytes of RAM, a (or multiple) powerful CPU(s), and a fair amount of storage. A VPS is the + best choice for most users and can be fairly cheap. + + + A dedicated host is a physical computer. You can buy these yourself or rent one from a hosting + provider. Dedicated hosts are often very expensive, but are also very powerful, having a + few hundred gigabytes of RAM and a few very powerful CPUs, along with a good amount of storage. + Dedicated hosts are usually used for very large projects and are overkill for something like + a Discord bot. + + +
+ +:::danger + +Make sure you choose a hosting provider you trust. Also make +sure the hosting provider you're looking at has good reviews on public forums. Googling along the +lines of "[host] review" should do the trick. A provider you don't trust can compromise your token. + +::: + +Most hosting providers rent their services to you for a monthly or yearly fee. These can be anywhere +from a few dollars to hundreds or thousands of dollars. + +## How to Host Your Bot + +Once you rent or buy a VPS, you can get to work. Most hosting providers allow you to choose from a +wide range of operating systems, most allow you to choose one but some allow you to choose +multiple. Once that's ready, you have to SSH into the system. We won't get into SSH here, but you can +read [this article from DigitalOcean](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys). +You can also use VNC, which is remote desktop software. If you are using an OS that does not have a +GUI, and is only a command line (a "server" OS), such as Ubuntu Server or most Linux Server Operating Servers, you will most +likely use SSH. If you are using an OS that has a GUI, such as Windows Server, you will most likely use VNC. + +Once you've decided on your operating system, you'll want to set it up and install Python. Once that's +done, you can copy your bot's files to your remote system, install the required packages, and run +the bot. + +:::warning + +If you are using SSH to run the file, your bot will not stay running. This is because the file is +only told to run during your session. You can use a command like [nohup](https://en.wikipedia.org/wiki/Nohup) +to make sure your file stays running after you disconnect. + +::: + +Now your bot is hosted, but that doesn't mean it can't go offline. If your bot encounters an error, +it can often go offline or stop its process. For this, make sure you have proper error handling. +Also be sure to pay attention to your hosting provider's updates or news, as they usually notify +users of when they plan on doing maintenance to their servers, making their services unavailable for +a short time. + +:::info Related Topics + +- [Creating Your First Bot](creating-your-first-bot) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx new file mode 100644 index 00000000..ee6b9417 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx @@ -0,0 +1,379 @@ +--- +title: More Features +description: More features to make your bot cool and snazzy. +--- + +import { + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, + DiscordEmbedField, + DiscordEmbedFields, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +So, you just created your first Pycord bot! Now, let's add some more features to it. This will include adding event handlers, waiting for user response, styling the messages, and more. + +## Events + +### Event Handlers + +Events in Discord are a way to listen for certain actions. For example, if you want to know when a user joins your server, so you could send a welcome message, you can use the `on_member_join` event. + +First, you need to ask Discord to send you events. This is done via "Intents". Read up the [Intents](../Popular-Topics/intents) page for more information. + +Once you understand what intents are, you can enable the events you need, or just use the default ones with `discord.Intents.all()`. + +Now that that's done, let's add an event handler for when a user joins the server. We will use the [`on_member_join` event](https://docs.pycord.dev/en/stable/api/events.html#discord.on_member_join). We will send a private message to the user welcoming them to the server. + +```python +@bot.event +async def on_member_join(member): + await member.send( + f'Welcome to the server, {member.mention}! Enjoy your stay here.' + ) +``` + +We use the [`discord.Bot.event` decorator](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) to add the event handler. + +The `on_member_join` event is called when a user joins the server. The `member` parameter is the user that joined. Different events have different names and parameters. You can find all of them [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +So, that's how you add event handlers! + +### Waiting for User Response + +Let's say you want to create a Guess-the-Number game (where the user has to guess a number between 1-10). You need to send a message to a user and wait for them to respond. You can do this with the [`wait_for`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.wait_for) method. + +```python +@bot.command() +async def gtn(ctx): + """A Slash Command to play a Guess-the-Number game.""" + + await ctx.respond('Guess a number between 1 and 10.') + guess = await bot.wait_for('message', check=lambda message: message.author == ctx.author) + + if int(guess.content) == 5: + await ctx.send('You guessed it!') + else: + await ctx.send('Nope, try again.') +``` + +`wait_for` takes one argument, which is the event type. The event type is the name of the event you want to wait for. In this case, it's `message`. It could also be `reaction` to wait for a reaction to be added. + +We pass a keyword argument to `wait_for` called `check`. The function may look complicated if you're a beginner. We pass a `lambda` function, which simplifies the code a bit. + +The lambda function takes one parameter, `message`. When Pycord receives a message, it passes it to the `check` function. If the function returns `True`, the message is returned. If the function returns `False`, the message is ignored and the bot waits for another message. + +Here, we check if the message is from the user that sent the command. We simply use `message.author == ctx.author`. This will check if the author of the message was the person who invoked the command. + +## Styling Messages + +### Embeds + +Embeds are a Discord feature that allows applications to format their messages in cool embedded format, +enabling your bot to lay out messages with a lot of text into neat fields. + + + + + The Pycord Guide is a detailed guide that explains how to use Pycord and all of its features. + + + The Getting Started section explains how you can get a brand new bot created and running from scratch. + + + Interactions with Pycord + + + Pycord's various Extensions + + + Other Popular Topics + + + We have so much more! Just explore, and you will find everything you need. If you want another page added, open an issue on the GitHub. + + + Created with 💖 by the Pycord Team & Contributors + + + + +
+ +Creating embeds is simple! Just create an instance of [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) and edit it to your liking. Once you're done, send it! + +```python +import discord + +bot = discord.Bot() + +@bot.command() +async def hello(ctx): + embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from + ) + embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") + + embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) + embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) + embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) + + embed.set_footer(text="Footer! No markdown here.") # footers can have icons too + embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") + embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") + embed.set_image(url="https://example.com/link-to-my-banner.png") + + await ctx.respond("Hello! Here's a cool embed.", embed=embed) # Send the embed with some text + +bot.run("TOKEN") +``` + + + +
+ hello +
+ Hello! Here's a cool embed. + + Embeds are super easy, barely an inconvenience. + + + A really nice field with some information. The description as well as the fields support markdown! + + Inline Field 1 + Inline Field 2 + Inline Field 3 + + Footer! No markdown here. + +
+
+ +
+ +This simple command sends replies to a [slash command](../interactions/application-commands/slash-commands) with an embed. +Let's break it down: + +```py +embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), + ) +``` + +This command creates an embed. We use the [`Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) +class to create an embed object with the title "My Amazing Embed", the description "Embeds are super easy, barely an inconvenience.", and the color `blurple`, Discord's main theme color. + +[discord.Colour](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Colour) is a class full of [classmethods](https://docs.python.org/3/library/functions.html#classmethod) +that return color values. While the official, documented name of this is `discord.Colour`, `discord.Color` +works as well. + +```py +embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") +embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) +embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) +embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) +``` + +This small section shows off embed fields. You can add fields to embeds with the [`add_field` method](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.add_field) +of the [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) class. These consist of three +keyword arguments: `title`, `value`, and `inline`. `title` and `value` are both required arguments, which inline defaults to `False` if it's not defined. The `inline` argument specifies whether space will be divided among the inline fields. There could be a mix of fields where inline has different values too. + +```py +embed.set_footer(text="Footer! No markdown here.") # footers can have icons too +embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") +embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") +embed.set_image(url="https://example.com/link-to-my-banner.png") +``` + +In this section, we're adding unique items to the embed. These items are: + +- Footer - With the [`set_footer()`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_footer) + method, you can set a small footer that holds a message. This has `text` and `icon_url` kwargs. +- Author - With the [`set_author`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_author) + method, you can set an author for the embed. This is a small text field at the top of the embed. This + includes `name`, `url` and `icon_url` kwargs. +- Thumbnail - With the [`set_thumbnail`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_thumbnail) + method, you can set a small image to reside at the top-right of the embed. This has a single `url` kwarg. +- Image - With the [`set_image`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_image) + method, you can set an image to sit at the bottom of an embed. This has a single `url` kwarg. + +There are a lot more methods and attributes you can use to configure embeds. Here, we just covered the basics. Also, remember that all of these values are not necessary in an embed. An embed may only contain a few of these. For example, only a description, a title and a description, and so on. + +### Markdown + +Markdown is a type of markup language that's limited in terms of formatting yet simple. Discord allows +for a watered-down version of markdown to be in their messages. + +#### Text Markdown + +Text formatting can be used in messages and in most embed parts, +as explained in the dedicated section below. + + + + + + + + + + + + + + + + + + + + +
*italics*__*underlined italics*__
**bold**__**underlined bold**__
***bold italics***__***underlined bold italics***__
__underlined__~~strikethrough~~
+ +#### Code Markdown + +To create a single-line code block without syntax highlight, wrap the text between single backticks. +This code block will only add a dark background to the text. + +``` +`print("Hello world!")` +``` + +To create a multi-line code block without syntax highlight, wrap the text between triple backticks +on first and last line. This type of code block will encase the code inside a box. + +```` +``` +message = "Hello world!" +print(message) +``` +```` + +To create a multi-line block with syntax highlight, add the name of the language you are using right after +the triple backticks on the first line. For example, for Python you can write either "python" or "py". + +```` +```python +message = "Hello world!" +print(message) +``` +```` + +If you want to use syntax highlight for a single line of code, you still have to format it +like a multi-line block but the code must be on a separate line than the triple backticks. + +#### Quote Markdown + +To create a single-line quote block, start the line with `>` followed by a space. + +``` +> This is a single-line quote. +``` + +To create a multi-line quote block, write `>>>` followed by a space. All text +from that point onwards will be included in that quote block. + +``` +>>> This is a +multi-line quote. +``` + +#### Spoiler Markdown + +To hide a spoiler, encase the text between double pipes. The users +will have to click on it before being able to see the text contained in it. + +``` +||spoiler|| +``` + +#### Link Markdown + +Link formatting only works in embeds and messages sent through webhooks, +by using the following syntax: + +``` +[Pycord](https://pycord.dev/) +``` + +Inside the supported elements that have just been mentioned, +the example above will look like this: [`Pycord`](https://pycord.dev/) + +Outside them, the link will still be clickable but the formatting will be ignored, +therefore the example above will look similarly to this: `[Pycord](https://pycord.dev/)` + +#### Embed Markdown + +Adding markdown to your embeds or messages will give your bot the sparkle it needs, +however, markdown is limited inside embeds. Use the following table as a reference +and keep in mind that embed title and filed names will always show in **bold**. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PartTextLink
Embed AuthorNoNo
Embed TitleYesNo
Embed DescriptionYesYes
Field NameYesNo
Field ValueYesYes
Embed FooterNoNo
diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx new file mode 100644 index 00000000..e44b7c49 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx @@ -0,0 +1,184 @@ +--- +title: Rules and Common Practices +description: All about the rules and common practices for coding a Discord bot +--- + +# Rules and Common Practices of Creating a Bot + +When creating almost anything, there's always a certain set of rules to follow or common practices, +such as [PEP8](https://www.python.org/dev/peps/pep-0008/) for Python. This applies to creating bots +with Pycord as well. + +:::note + +Most of these rules and common practices are only applicable for +[verified bots](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting), +but it's good to follow them nonetheless. + +::: + +## Rules + +There are rules for creating bots, and most of these are required by Discord themselves, not us at +Pycord. Not following these rules may get your bot denied for verification. + +### Terms of Service and Privacy Policy + +Starting at some point in time, Discord has made providing a privacy policy with your bot a requirement. +This is so that Discord knows exactly what you are doing with its users' data. + +:::tip +You don't need a lawyer or anyone special to write out a privacy policy for you, nor do you need +it approved by some official entity. Simply writing out how you are going to use Discord user +information neatly is all you need to do. +::: + +Providing a Terms of Service for your bot is optional, though usually a best practice. It tells users +what they can and cannot do with your service, and makes it easier to settle disputes if someone +disagrees with you. + +Read more in Discord's official [Legal Docs](https://discord.com/developers/docs/legal). + +### Developer Policy + +We could list almost every rule about using Discord's API here. _Or_ we could simply link Discord's +Developer Policy to make it easier on us. You can find Discord's Developer Policy +[here](https://discord.com/developers/docs/policy). This outlines what you can and cannot do with +Discord's Developer API. And, don't worry, it's completely readable and understandable. + +## Best Practices + +Now, here's something we _can't_ simply link an article for. We're going to discuss the best practices +of creating a Discord bot with Pycord. + +### Bot Sharding + +To any new or maybe even experienced bot developer, sharding a bot sounds beneficial once you hear +about it. I'm here to tell you that it isn't a good idea to shard your bot. + +_Wait a minute, why would it be an option if it wasn't a good idea?_ It's simple. I lied. Sort of. +I'm not going to go into the details of sharding a bot, so you can read about it on +[this page](../Popular-Topics/sharding). Sharding is the process of taking your bot +and breaking it up into small pieces, so it's easier to perform tasks. This is very useful for large +bots, as it makes them faster and more reliable. Sharding is not a good practice for small bots. + +:::note +Discord will notify you once it is time to shard your bot, and will eventually force you to do so. +::: + +At the very least, wait for one thousand servers to shard your bot. If you shard your bot while it's +small, you'll just be wasting resources and possibly making your bot slower. + +### [Verification](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting) + +Verifying your Discord bot is something every developer would like to achieve. It shows that your bot +is in more than 75 servers. It's generally a good idea to try to get your bot verified as soon as +possible. We're talking at 76 servers soon. This is because Discord can be somewhat slow in terms of +bot verification, so verifying as soon as possible gives them enough time to verify before your bot +reaches the 100 server cap. If a bot is not verified, it cannot grow beyond 100 servers. + +It's also a good idea to only apply for the privileged intents that you need. Applying for intents +your bot doesn't use wastes both your time and Discord's time, as your privileged intent request +will be denied simply because you applied for an intent you didn't need. + +### Subclassing + +While it may take some time, subclassing a bot is very worth it. Once again, this was explained +elsewhere, so I won't go into the details, but I felt it fit here, so I put it here. + +Subclassing a bot makes it more flexible and allows it to do a lot more. Read more about subclassing +bots [here](../Popular-Topics/subclassing-bots) + +### Your Bot's Token + +Your bot is only able to be run for one reason: its token. If you followed the +[guide for creating your first bot](creating-your-first-bot), you should already know a bit about +keeping that token safe. That's exactly what you want to do. + +Sharing your token is never good. If someone evil gets a hold of your token, they can do terrible things, +such as making your bot leave all of its servers, spamming all the members the bot has contact with, +and even manipulating the servers the bot is in, if given the permissions. That's why it's very important +to keep your token safe. To learn how to do so, read [this part](creating-your-first-bot#tokens) of +the Creating Your First Bot guide. + +### Backups + +You always want to back up your bot's data. This includes both its code _and_ its databases. This way, +if something tragic happens, such as your host failing a data migration or you breaking your Raspberry +Pi's SD card that held your bot, you'll still have its precious user data. I have a small program for +my bot that uploads its databases to a remote GitHub repository periodically to not lose any data. +It may be smarter to find a bit more of a reliable way to do so, though. + +Public or private, having a local Git repository connected to a remote one is a good idea for making +almost any application. For a lot of developers, it's like saving your work. If you do this, all of +your bot's code won't be lost if your computer spontaneously combusts, or you smash it to bits from +anger. You can simply grab the backup computer that everyone has lying around, and you're back +in business. + +### Organization and Cleanliness + +It is _extremely_ important to have organized code. This includes commands, objects, functions, +and classes. If you don't have organized code, it will get progressively harder for you to recognize +it, and others won't be able to decipher it. + +Make sure you utilize indents and spaces, as these are very important in making your code readable. + +```py title="Bad Spacing" +class MyClass: + async def add(self,num1,num2): + return num1+num2 + async def sub(self,num1,num2): + return num1-num2 +``` + +```py title="Good Spacing" +class MyClass: + async def add(self, num1, num2): + return num1 + num2 + + async def sub(self, num1, num2): + return num1 - num2 +``` + +See the difference? Now, which one looks more readable? Hopefully, you answered the second example. +Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is a PEP (**Python Enhancement Proposal**) +style guide for Python. It is the style guide that is used by most Python developers and programmers, +providing a universal way to write and read code. + +### Databases + +As your bot grows, you'll inevitably have to store data for your bot. Now, most people would probably just load up some +JSON file on boot into a `dict`, modify it in memory then write to the file. However, JSON files aren't the solution. +When you write to a JSON file, it rewrites the entire file instead of just rewriting the section that changed. It's also +a configuration file format, not a storage file format. + +Instead of using a JSON file or some other related format, you should instead use a database. There are many databases +out there, like MongoDB, SQLite, and PostgreSQL to name a few. + +All of these databases I named do the job well, and which one you use depends on what features you want out of a database. + +<>{/* Maybe clarify these/add more options */} + +#### MongoDB + +MongoDB is a JSON-like format and if you already use JSON files, it shouldn't be too hard to migrate over to. + +#### SQLite + +SQLite is based on SQL, a common relational data model. It's a lightweight, easy-to-use, portable database solution that +works entirely on files. However, if for some reason you cannot read/write to and from a file, and you need to manage +lots of data, SQLite might not be for you. + +While SQLite is a part of the Python Standard Library as the `sqlite3` package, we recommend not using it as it is +synchronous and blocking. You should use an asynchronous alternative, such as [`aiosqlite`](https://pypi.org/project/aiosqlite/). + +#### PostgreSQL + +PostgreSQL is also based on SQL, but it also has more features than SQLite. It's compliant with the SQL standard, +open-source, and extensible. However, it's not that fast or simple compared to SQLite. + +#### MariaDB + +MariaDB is also based on SQL and is a fork of the MySQL project. It's compliant with the SQL standard, it's also open +source and is a complete drop-in replacement for any code with MySQL. You don't even need to change what package you're +using! diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/installation.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/installation.mdx new file mode 100644 index 00000000..521c69cd --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/installation.mdx @@ -0,0 +1,80 @@ +--- +title: Installation +sidebar_position: 2 +--- + +Before you can start using Pycord, you need to install the library. + +:::note +Python **3.8 or above** is required to use Pycord. +::: + +:::tip +Before you start installing python packages globally, it's recommended you set up a virtual environment. +You can find instructions for that [here](More/virtual-environments). +::: + +## Fresh Installation + +To install Pycord, you can use the following command in your terminal: + +``` +pip install py-cord +``` + +:::tip +Remember that you need to install `py-cord`, not `pycord`. +Also, the `pip` command varies depending on your installation. For example, it might be `python3 -m pip` on macOS/Linux or `py3 -m pip` on some versions of Windows. +::: + +If you need voice support for your bot, you should run: + +``` +pip install "py-cord[voice]" +``` + +## Migration + +### Updating Pycord + +If you are upgrading from a previous version of Pycord, you can use the following command in your terminal to upgrade to the latest version: + +``` +pip install -U py-cord +``` + +### Migrating from other libraries + +If you are migrating from another library, say, `discord.py`, first of all, you need to uninstall it. + +``` +pip uninstall discord.py +``` + +Then, you can install Pycord, it's as simple as that!: + +``` +pip install py-cord +``` + +:::caution +Uninstalling `discord.py` _after_ installing `py-cord` can cause issues. Make sure to uninstall it first! +::: + +## Installing Other Builds + +### Development Build + +:::caution +The development build comes with cutting edge features and new functionality, but as it isn't a stable build you may encounter bugs. +::: + +To install the development build, you can use the following command in your terminal: + +``` +pip install -U git+https://github.com/Pycord-Development/pycord +``` + +:::important +Git is required to install this build. [Learn how you can install Git](./more/git). +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/interactions/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/_category_.json new file mode 100644 index 00000000..ea28be60 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 4, + "label": "Interactions" +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json new file mode 100644 index 00000000..6dcafe83 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Application Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx new file mode 100644 index 00000000..b4ffeade --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx @@ -0,0 +1,85 @@ +--- +title: Context Menus +description: Learn all about Context Menus (User Commands & Message Commands) and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +When you right-click a message, you may see an option called "Apps". Hover over it, and you can see +commands a bot can run with that message. These are called message commands. + +When you right-click a user in the user list, you can once again see an option called "Apps". +Hover over it, and you can see commands a bot can run with that message. These are called user commands. + +Together, these two are called Context Menus or Context Menu Commands. These commands work very much like normal commands, except they take a member or message. + +:::note + +A bot can have up to 5 global Context Menus of each type. + +::: + +## User Commands + +Creating a user command is very simple. + +```python +@bot.user_command(name="Account Creation Date", guild_ids=[...]) # create a user command for the supplied guilds +async def account_creation_date(ctx, member: discord.Member): # user commands return the member + await ctx.respond(f"{member.name}'s account was created on {member.created_at}") +``` + + + +
+ + Account Creation Date + +
+ {defaultOptions.profiles.bob.author}'s account was created on 2020-01-01 +
+
+ +## Message Commands + +```python +@bot.message_command(name="Get Message ID") # creates a global message command. use guild_ids=[] to create guild-specific commands. +async def get_message_id(ctx, message: discord.Message): # message commands return the message + await ctx.respond(f"Message ID: `{message.id}`") +``` + + + + Do. Or do not. There is no try. + + +
+ + Get Message ID + +
+ Message ID: 930650407917748286 +
+
+ +
+ +:::info Related Topics + +- [Slash Commands](./slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx new file mode 100644 index 00000000..edac55b3 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx @@ -0,0 +1,56 @@ +--- +title: Localizations +description: Localizations are a way to make your bot more accessible to your users. Learn all about localizations now! +--- + +Localizations are a way to make your bot more accessible to your users. You can localize the command +name, the names of any arguments, and any text that is displayed to the user. + +## Syntax + +```python +@bot.slash_command( + name="ping", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + }, + options=[ + Option( + name="Example", + name_localizations={ + "en-GB": "British Example" + }, + description="Example option that does nothing", + description_localizations={ + "en-GB": "British example option that does nothing" + } + ) + ] +) +async def ping(ctx, example): + responses = {"en-US": "Pong!", + "en-GB": "British Pong!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +@bot.slash_command( + name="ping2", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + } +) +async def ping2(ctx, example: Option(str, "example", name_localizations={"en-GB": "British Example"}, description="Example option that does nothing", description_localizations={"en-GB": "British example option that does nothing"})): + responses = {"en-US": "Pong2!", + "en-GB": "British Pong2!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +``` + +- [`Locales`](https://discord.com/developers/docs/reference#locales) - List of valid locales recognized by Discord diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx new file mode 100644 index 00000000..ed454dad --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx @@ -0,0 +1,292 @@ +--- +title: Slash Commands +description: Learn all about Slash Commands and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On March 24, 2021, Discord added Slash Commands to Discord as an easier, more efficient, and better way of using bot commands. Pycord has implemented Slash Commands into the library, so it's simple, efficient, and familiar. + +:::important + +Remember that Slash Commands require your bot to be invited with the `application.commands` scope or Slash Commands will not show up. Bots already in the guild can simply be invited again with the scope; there is no need to kick the bot. + +::: + +## Syntax + +Let's create a simple Slash Command. + +```py +import discord + +bot = discord.Bot() + +# we need to limit the guilds for testing purposes +# so other users wouldn't see the command that we're testing + +@bot.command(description="Sends the bot's latency.") # this decorator makes a slash command +async def ping(ctx): # a slash command will be created with the name "ping" + await ctx.respond(f"Pong! Latency is {bot.latency}") + +bot.run("TOKEN") +``` + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +Let's go through the code. + +First, we import Pycord's `discord` package. + +Next, we create a [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot) object and assign it to a variable `bot`. + +We then go ahead and use the [`@bot.command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.command) decorator, which registers a new Slash Command. We pass a `description` parameter to give a description to the Slash Command. We can also pass a `name` parameter to change the Slash Command's name. By default, the name of the Slash Command will be the name of the function, in this case, `/ping`. + +We create an async function called `ping` with parameters `ctx`, which, when called, sends the bot's ping/latency using [`ctx.respond`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext.respond). + +## Subcommand Groups + +You might want to group certain commands together to make them more organised. A command group is exactly what it sounds like, a group of individual Slash Commands together. + +In order to make a Slash Command group, you can use the `bot.create_group` function. + +```python +import discord + +bot = discord.Bot() + +# create Slash Command group with bot.create_group +greetings = bot.create_group("greetings", "Greet people") + +@greetings.command() +async def hello(ctx): + await ctx.respond(f"Hello, {ctx.author}!") + +@greetings.command() +async def bye(ctx): + await ctx.respond(f"Bye, {ctx.author}!") + +bot.run("TOKEN") +``` + +Or, you can instead manually make a `SlashCommandGroup` class like so: + +```python +import discord + +math = discord.SlashCommandGroup("math", "Math related commands") + +@math.command() +async def add(ctx, num1: int, num2: int): + sum = num1 + num2 + await ctx.respond(f"{num1} plus {num2} is {sum}.") + +@math.command() +async def subtract(ctx, num1: int, num2: int): + sum = num1 - num2 + await ctx.respond(f"{num1} minus {num2} is {sum}.") + +# you'll have to manually add the manually created Slash Command group +bot.add_application_command(math) +``` + +Here's what the registered subcommands will look like in the Slash Command Menu: + +![Picture of the subcommands in the Slash Command Menu](../../assets/interactions/groups-and-subcommands.jpg) + +You'll notice that there's the name of the Slash Command Group and then the name of the subcommand separated by a space. + +::: + +:::info Cogs + +If you are looking to add Slash Command Groups to cogs, please look at our [Cogs page](../../popular-topics/cogs)! + +::: + +## Sub-groups + +We've made a subcommand group, but did you know that you could create a group inside another? + +```python +from discord import SlashCommandGroup +from math import sqrt + +math = SlashCommandGroup("math", "Math related commands") +advanced = math.create_subgroup("advanced", "Advanced math commands") + +@advanced.command() +async def square_root(ctx, x: int): + await ctx.respond(sqrt(x)) + +bot.add_application_command(math) +``` + +The command created above can be invoked by typing `/math advanced square_root`. + +## Options & Option Types + +Whenever you're using Slash Commands, you might notice that you can specify parameters that the user has to set or can optionally set. These are called Options. + +Options can also include a description to provide more information. [You can learn more about Options in our documentation!](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.Option) + +Since you want different inputs from Options, you'll have to specify the type for that Option; there are a few ways of doing this. + + + + +You could use Type Annotations and let Pycord figure out the option type or explicitly specified using the [`SlashCommandOptionType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.SlashCommandOptionType) enum. + +```python +import discord + +bot = discord.Bot() + +@bot.command() +# pycord will figure out the types for you +async def add(ctx, first: discord.Option(int), second: discord.Option(int)): + # you can use them as they were actual integers + sum = first + second + await ctx.respond(f"The sum of {first} and {second} is {sum}.") + +@bot.command() +# this explicitly tells pycord what types the options are instead +async def join( + ctx, + first: discord.Option(discord.SlashCommandOptionType.string), + second: discord.Option(discord.SlashCommandOptionType.string) +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + add + +
+ The sum of 1 and 1 is 2. +
+ +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+ + +Instead of Type Annotations, you can also use the option decorator. This is usually done to have type-hinting. + +```python title="Slash Command Type" +import discord + +bot = discord.Bot() + +@bot.command() +@discord.option("first", type=discord.SlashCommandOptionType.string) # type = str also works +@discord.option("second", type=discord.SlashCommandOptionType.string) # type = str also works +async def join( + ctx, + first: str, + second: str, +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+
+ +## Autocomplete + +Discord's autocomplete allows developers to determine option choices that are used in a slash command option. You can do this by defining a function: + +```py +async def get_animal_types(ctx: discord.AutocompleteContext): + """ + Here we will check if 'ctx.options['animal_type']' is a marine or land animal and return respective option choices + """ + animal_type = ctx.options['animal_type'] + if animal_type == 'Marine': + return ['Whale', 'Shark', 'Fish', 'Octopus', 'Turtle'] + else: # is land animal + return ['Snake', 'Wolf', 'Lizard', 'Lion', 'Bird'] + +@bot.slash_command(name="animal") +async def animal_command( + ctx: discord.ApplicationContext, + animal_type: discord.Option(str, choices=['Marine', 'Land']), + animal: discord.Option(str, autocomplete=discord.utils.basic_autocomplete(get_animal_types)) +): + await ctx.respond(f'You picked an animal type of `{animal_type}` that led you to pick `{animal}`!') +``` + + + +
+ + animal + +
+ You picked an animal type of Marine that led you to pick Shark! +
+
+ +:::warning + +Autocomplete can **only** be used with slash commands. + +::: + +:::info Related Topics + +- [Interactions Index](../../interactions) +- [Rules and Common Practices](../../getting-started/rules-and-common-practices) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/interactions/index.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/index.mdx new file mode 100644 index 00000000..8603437f --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/index.mdx @@ -0,0 +1,242 @@ +--- +title: Discord Interactions +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +In December 2020, Discord released their first Interaction: the +[Slash Command](https://discord.com/developers/docs/interactions/application-commands#slash-commands). +Since then, Discord has added many types of Interactions, including: + +[**Application Commands**](https://discord.com/developers/docs/interactions/application-commands) + +- [**Slash Commands**](https://discord.com/developers/docs/interactions/application-commands#slash-commands): + Commands that can be used with the `/` prefix. +- **Context Menu Commands**: Commands that can be used from the right-click menu. + - [**User Commands**](https://discord.com/developers/docs/interactions/application-commands#user-commands): + Commands that can be used on a user by alt-clicking/selecting them. + - [**Message Commands**](https://discord.com/developers/docs/interactions/application-commands#message-commands): + Commands that can be used on a message by alt-clicking/selecting it. + +[**UI Components**](https://discord.com/developers/docs/interactions/message-components) + +- [**Buttons**](https://discord.com/developers/docs/interactions/message-components#buttons): + Buttons are attached to a message and can be clicked on to perform an action. +- [**Select Menus**](https://discord.com/developers/docs/interactions/message-components#select-menus): + Drop-down menus are used to select a number of options from a list. +- [**Modals**](https://discord.com/developers/docs/interactions/message-components#text-inputs): + Form-like modals can be used to ask for input from a user. + +## Application Commands + +Application Commands are another set of new features that are intended to avoid compromising users' safety and privacy. +They're relatively easy to add to your bot, and give people a simpler and safer way to use commands. + +### [Slash Commands](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.SlashCommand) + +Slash Commands were the first Interaction added to Discord. They're easy to use and create, and +is the only prefix commands alternative that does not need Message Content intent. + +:::note + +Preferring prefix commands over Application Commands is **not** a valid reason to apply for the +Message Content intent. Using that as a reason will get your application denied. + +::: + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +This is what a Slash Command looks like. Not too different from a prefix command, +apart from the note telling you who invoked it. A Slash Command's fields can accept any of the following: + +- Members +- Roles +- Channels +- Attachments +- Text + +Just about as good as it gets. + +### [Message](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.MessageCommand) and [User](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.UserCommand) Commands + +Message Commands and User Commands were both introduced at around the same time, and are very similar to each other, so we'll be +introducing them together. These commands can be found in the `Apps` tab when alt-clicking. The only difference between the two is that +Message Commands only appear in the `Apps` tab of a message, while User Commands are found in the `Apps` tab of a user. Message Commands +can be used to quickly report a message, warn a user for a message, and other functions. Likewise, User Commands can be used to add a +user to a ticket, warn a user, and more. + +Here's an example of a Message Command: + + + + Hello World! + + +
+ + Reverse Message + +
+ Message 930650407917748286 reversed is "!dlroW olleH" +
+
+ +
+ +And here's an example of a User Command: + + + + {defaultOptions.profiles.dorukyum.author} has been on Discord for a long time + + +
+ + User Age + +
+ {defaultOptions.profiles.dorukyum.author} is 1 week old. +
+ +
+ + User Age + +
+ {defaultOptions.profiles.bob.author} is 40 years old. +
+ + 🤔 + +
+ +
+ +Pretty cool, right? To learn more about these two, please read the [Context Menus guide](./application-commands/context-menus.mdx). + +## [Application Commands](#application-commands) vs. [Prefix Commands](../extensions/commands/prefixed-commands) + +Ever since Discord was created, apps on it have used prefix commands. Using prefixes meant that you would have to put a +certain character (or string of characters) in front of your command, such as the exclamation mark in `!ping`. The way this +worked was that your bot would listen for messages, pick out the ones that had their specific prefix, and then respond to the command. +Now, Discord is encouraging developers to switch their bots over to Application Commands, which is a new system meant to preserve the +privacy and safety of their users. But why exactly is Discord making us switch? What's the better option, Application Commands or prefix +commands? Below, we'll discuss everything you need to know. + +### Discord's Decision + +Application Commands were conceptualized partly due to privacy concerns. When Discord first began, they weren't entirely concerned about bots +having access to the content of every message that was being sent. However, as Discord grew, this became more of a problem. Hypothetically, bots +could simply log every message they're able to receive via the Discord API and hand their contents over to a company or other third party. This is +a problem, since that data is meant to be used only by Discord. As such, they locked down Message Content, and introduced Application Commands for +bot developers to use instead. + +Prefix commands work by reading messages, as described before. Application Commands, however, don't +work this way; instead, they work by having your bot get information from Discord about when a command was used. This way, Discord can limit +Message Content only to bots that _absolutely_ depend on it, such as auto-moderation bots. + +### Who has to Use Application Commands + +Any verified bot that does not have the Message Content intent must use Application Commands. Discord is allowing developers to submit +applications for the ability to use the intent; however, since they don't want to keep supporting prefix commands due to privacy concerns, +they will automatically decline any application that includes only that as a reason. So, if your bot doesn't have an auto-moderation feature +(or any other functionality that requires Message Content), you're out of luck. + +Unverified bots, however, don't have to use Application Commands. This is because the Message Content intent is a `Privileged Intent`, meaning that +it must be applied for only if your bot is verified or about to be verified. Unverified bots don't have to apply for Privileged Intents, so they can +use them freely. + +So, if your bot is made only for a couple of servers, you can choose between prefix commands and Application Commands. However, if you plan on expanding +your bot's reach, it'll have to use Application Commands. + +### What's the Better Option + +Choosing which is the better option is up to you, if you're starting small. If +you plan on growing your bot, however, you will have to use Application Commands. Since prefix commands are slowly being phased out by Discord, +there isn't much of a choice for developers of larger bots. + +## Message Components + +Message Components are fairly new features in Discord, allowing developers to give their bots a fast +and understandable user interface. Message Components are easy to use and make your bot look modern, +sleek, and downright awesome. + +### [Views](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View) + +Views are not an Application Command nor are they a Message Component. Views are the invisible placeholders, or grid, +that Message Components lie in. Views can have up to 5 [`Action Rows`](https://docs.pycord.dev/en/stable/api/models.html#discord.ActionRow), +and Action Rows can have a maximum of 5 slots. Below, you can find a table showing how many slots a Message Interaction takes up. + +| Component | Slots | +| ------------ | ----------------------------------------------- | +| Buttons | 1 Slot | +| Select Menus | 5 Slots | +| Text Modals | 1 Slot (opened via a Button) | + +So, based on this, you could have a maximum of 25 Buttons in a View with no Select Menus, and 5 Select +Menus in a View with no Buttons. This doesn't mean you can't have them both in a View, however. You can have +a combination of them, such as 20 Buttons and a Select Menu or 10 Buttons and 3 Select Menus. + +### [Buttons](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button) + +Buttons are the first of the Message Components. They allow for quick responses to prompts, such as for canceling or continuing an action. +Of course, these aren't their only uses; people have created awesome things with Buttons, such as calculators, games, and more! + + + + Discord Buttons are awesome! +
+ + Click me! + +
+
+
+ +
+ +This is what a Button looks like, very simple and modern. To learn more about Buttons, refer to our +[Buttons page](./ui-components/buttons.mdx). + +### [Select Menus](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Select) + +Select Menus are the second of Discord's Message Components. They allow users to select from a list of choices, which your bot can then use. +Select Menus are good for things such as choosing features, pages of a help menu, and more. + +![Select Menu Example Image](../assets/interactions/select-menus-example.png) + +This is what a Select Menu looks like. While not looking as good as Buttons, they still look great +and have even greater possibilities. To learn more about Select Menus, please refer to our [Select +Menus page](./ui-components/dropdowns.mdx). + +### [Modal Dialogs](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal) + +Text Modals are the most recently added Message Component in Discord. They're useful for text input and filling out forms, such as a +sign-up for your bot's service. These are meant to replace long bot setup processes by allowing users to fill out multiple text fields, +which avoids having the user send multiple messages for the bot. Modals can be accessed by either invoking an Application Command or by +interacting with another UI Component. + +![Text Modal Example Image](../assets/interactions/modal-example.png) + +This is what a Text Modal looks like, easy to use and one of the most useful Message Components yet. To learn more about Text Modals, +please visit our [Modal Dialogs page](./ui-components/modal-dialogs.mdx). diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json new file mode 100644 index 00000000..7b0a72fe --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "UI Components", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx new file mode 100644 index 00000000..046b36c7 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx @@ -0,0 +1,314 @@ +--- +title: Buttons +description: Learn all about implementing buttons in your Discord Bot using Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On May 26, 2021, Discord added a new interaction called buttons. Instead of reactions, bots could now +send buttons and users could use them to interact with bots. This opened up a whole new world of +possibilities for bots. Soon after, developers made calculators, polls, and games like blackjack, UNO, +and even Minecraft! Buttons provided a clear and easy to use interface for interacting with bots. + +So, let's learn how you can add buttons to your bot! + +## Concept + +Buttons weren't the only update to the interactions system in Discord. Discord also added [Select Menus](./dropdowns) and [Modal Dialogs](./modal-dialogs), both of which work very similarly to buttons. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive button. + +```python +import discord + +bot = discord.Bot() # Create a bot object + +class MyView(discord.ui.View): # Create a class called MyView that subclasses discord.ui.View + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.primary, emoji="😎") # Create a button with the label "😎 Click me!" with color Blurple + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") # Send a message when the button is clicked + +@bot.slash_command() # Create a slash command +async def button(ctx): + await ctx.respond("This is a button!", view=MyView()) # Send a message with our View class that contains the button + +bot.run("TOKEN") # Run the bot +``` + +Using this command should return the following message: + + + +
+ + button + +
+ This is a button! +
+ + Click me! + +
+
+
+ +
+ +As you can see, we create a class called `MyView` that [subclasses](#oop) +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `button_callback` to the `MyView` class with the decorator +[`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button). +This decorator adds a button to a component. This function takes two arguments: the button that was +clicked and the interaction. These arguments are passed to the function when the button is clicked +by the module. We use the [`interaction.response.send_message`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse.send_message) +function to send a message to the channel where the interaction was sent. + +Finally, we create a global slash command called `button` that sends the message, along with the view +that contains a button. + +This is the basic syntax of creating a button. What you create with it is up to you. You can worry +about making your button do amazing things, while Pycord handles the rest! + +## Button Styles + + + +| Name | Usage | Color | +| --------- | ----------------------------------------------------------------------------------------- | ------- | +| Primary | `discord.ButtonStyle.primary` / `discord.ButtonStyle.blurple` | Blurple | +| Secondary | `discord.ButtonStyle.secondary` / `discord.ButtonStyle.grey` / `discord.ButtonStyle.gray` | Grey | +| Success | `discord.ButtonStyle.success` / `discord.ButtonStyle.green` | Green | +| Danger | `discord.ButtonStyle.danger` / `discord.ButtonStyle.red` | Red | +| Link | `discord.ButtonStyle.link` / `discord.ButtonStyle.url` | Grey | + +Check out the [`discord.ButtonStyle`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ButtonStyle) class for more information. + +![Different Button Styles](../../assets/interactions/button-styles.png) + +You can set a button's style by adding the `style` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) decorator. + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.success) + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots, and each button takes up 1 slot. +So, how do we move the buttons to another row? + +This can be done by specifying the `row` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) +decorator. + +:::info The `row` argument + +The row argument specifies the relative row this button belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=1, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") +``` + +## Disabling Buttons + +### Pre-Disabled Buttons + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary, disabled=True) # pass `disabled=True` to make the button pre-disabled + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView()) +``` + +### Disabling Buttons on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + button.disabled = True # set button.disabled to True to disable the button + button.label = "No more pressing!" # change the button's label to something else + await interaction.response.edit_message(view=self) # edit the message's view +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(emoji="😀", label="Button 1", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) + + @discord.ui.button(label="Button 2", style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +Sometimes, you want to have a button that is disabled after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView(timeout=30)) +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a button that is disabled after a certain amount of time, you want to have a +button that is always working. + +Normally, when the bot goes offline, all of its buttons stop working. You will be able to see the +buttons, but nothing will happen when you press them. This is a problem +if you are trying to create a self-role system with buttons, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons will stop working. When the bot comes back online, however, the buttons will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view must have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.button(label="A button", custom_id="button-1", style=discord.ButtonStyle.primary, emoji="😎") # the button has a custom_id set + async def button_callback(self, button, interaction): + await interaction.response.send_message("Button was pressed", ephemeral=True) + +@bot.command() +async def button(ctx): + await ctx.send(f"Press the button! View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many buttons can I have in a message? + +Each message can have a maximum of 25 buttons. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do buttons need any special permissions? + +No new permissions are needed for either the bot or the server to allow bots to use buttons. + +#### Should I replace reactions with buttons for my bot? + +That is up to you. Buttons do provide a cleaner interface for your bot and are easier to use. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx new file mode 100644 index 00000000..8320f25d --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx @@ -0,0 +1,339 @@ +--- +title: Select Menus +description: Learn all about implementing Select Menus or Dropdowns in your Discord Bot with Pycord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Shortly after the buttons were added, Discord added their second message component: Select Menus. Select Menus allow users to choose from a list of items sent by a bot. These are a great substitute for having a user send a number that corresponds to an option. You can even allow users to select multiple options from the Select Menus. This guide will show you the easy and painless ways of using them with Pycord. + +## Concept + +Select Menus aren't the only message component in Discord. There's also [Buttons](./buttons) and [Modal Dialogs](./modal-dialogs). Select Menus make it easy for users to pick one or multiple options from a list provided by a bot. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive select menu. + +```python +import discord + +bot = discord.Bot() + +class MyView(discord.ui.View): + @discord.ui.select( # the decorator that lets you specify the properties of the select menu + placeholder = "Choose a Flavor!", # the placeholder text that will be displayed if nothing is selected + min_values = 1, # the minimum number of values that must be selected by the users + max_values = 1, # the maximum number of values that can be selected by the users + options = [ # the list of options from which users can choose, a required field + discord.SelectOption( + label="Vanilla", + description="Pick this if you like vanilla!" + ), + discord.SelectOption( + label="Chocolate", + description="Pick this if you like chocolate!" + ), + discord.SelectOption( + label="Strawberry", + description="Pick this if you like strawberry!" + ) + ] + ) + async def select_callback(self, select, interaction): # the function called when the user is done selecting options + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") + +@bot.command() +async def flavor(ctx): + await ctx.respond("Choose a flavor!", view=MyView()) + +bot.run("TOKEN") +``` + +There's a lot going on over here! Don't worry, we will go over the code and explain it. + +As you can see, we create a class called `MyView` that subclasses +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `select_callback` to the `View` class with the decorator +[`discord.ui.select`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.select). +This decorator adds a select menu to the view. This decorator takes a few arguments to customize your select menu. Read them in the [Customization section](#customization). + +That was the decorator. Now, the function itself is pretty simple. It takes two parameters, not including `self`. The parameters are `select`: The select menu, and `interaction`: a [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object. Both of these are passed by Pycord, so you just need to specify them in the function! + + + +In the callback, you could do anything you want. You get the two parameters `select` and `interaction` to play around with. Here, we send a message using `await interaction.response.send_message` (where interaction is [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse)) with content `select.values[0]`, which sends the label of the first/only option the user selected. Obviously, this is only an example, and you could do just about anything you want. + +Finally, we create a global slash command called `flavour` that sends a message "Choose a flavor!" along with the view +that contains our select menu. + +This is the basic syntax of creating a select menu. What you create with it is up to you. You can worry +about making your code do amazing things, while Pycord handles the rest! + +## Customization + +#### Select Menu Properties + +- `select_type`: The type of select to create. This must be a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. +- `channel_types`: A list of channel types that can be selected in the menu. This is only valid for selects of `select_type` [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType). +- `options`: A list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. These are the options that can be selected in this menu. +- `placeholder` is the placeholder text shown in the select menu if no option is selected. +- `custom_id`: The ID of the select menu that gets received during an interaction. It is recommended not to set this to anything unless you are trying to create a persistent view. +- `row`: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). +- `min_values`: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `max_values`: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `disabled`: Whether the select is disabled or not. Defaults to False. + +#### Select Option Properties + +In the `options` parameter, you pass a list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. This class also has a few parameters: + +- `default` (whether the option is selected by default) +- `description` (an additional description, if any) +- `emoji` (a string or an emoji object, if any) +- `label` (the name displayed to users, can be up to 100 characters) +- `value` (a special value of the option, defaults to the label). + +## Select Types + +In addition to regular string selects, you can also have your select menu contain users, roles, mentionables, and channels as its options. You can use these alternative select types by passing a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value for the `select_type` parameter when creating the Select. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.user_select + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +Additionally, you can use shortcut decorators to create a [`discord.ui.Select`](https://docs.pycord.dev/en/master/api/ui_kit.html#discord.ui.select) with a predetermined [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. Using a shortcut decorator, the above code can be rewritten like this: + +```python +class MyView(discord.ui.View): + @discord.ui.user_select() + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +### Specifying Channel Types + +When using a [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType.channel_select) type select menu, you can pass in a list of [`discord.ChannelType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ChannelType) values to limit which types of channels users can choose when interacting with the select menu. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.channel_select, + channel_types=[discord.ChannelType.text, discord.ChannelType.voice] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"You selected {select.values[0].mention}") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots. A button takes a single slot, while a select menu takes up all 5 of them. This means a view can have a maximum of 5 select menus, or any possible combination of select menus and buttons. + +The arrangement of buttons and select menus is generally adjusted by Pycord. However, it is possible to move them to specific relative rows. This is done by specifying the `row` argument. + +:::info The `row` argument + +The row argument specifies the relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero-indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=0, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.select( + row = 1, + options = [...] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") +``` + +## Disabling Select Menus + +### Pre-Disabled Menus + +```python +class MyView(discord.ui.View): + @discord.ui.select( + disabled = True, # pass disabled=True to set the menu as disabled + options = [...] + ) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send("Select and option from the menu!", view=MyView()) +``` + +### Disabling Menus on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + select.disabled = True # set the status of the select as disabled + await interaction.response.edit_message(view=self) # edit the message to show the changes +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def first_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) # edit the message to show the changes + + @discord.ui.select(options = [...]) + async def second_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +You may want a select menu to automatically stop working after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select(ctx): + await ctx.send(view=MyView(timeout=30)) # specify the timeout here +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a select menu that is disabled after a certain amount of time, you want to have a +select menu that is always working. + +Normally, when the bot goes offline, all of its views stop working, even if they don't have a timeout. You will be able to see the +views, but nothing will happen when you try to interact with them. This is a problem +if you are trying to create a self-role system, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons and select menus will stop working. However, when the bot comes back online, the buttons and select menus will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view much have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.select(custom_id="select-1", options = [...]) # a custom_id must be set + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send(f"View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many select menus can I have in a message? + +Each message can have a maximum of 5 select menus. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do select menus need any special permissions? + +No new permissions are needed in the bot or in the server. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx new file mode 100644 index 00000000..bd585c77 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx @@ -0,0 +1,107 @@ +--- +title: Modal Dialogs +description: Learn how you can implement Modals in your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Modal Dialogs, also known as "modals", provide a form-like structure for bots to receive input from users. No extra permissions are needed for bots to send modal dialogs, so it becomes a convenient workaround for bots to receive longer input without needing the Message Content [intent](../../popular-topics/intents). + +## Concept + +Modal Dialogs consist of a title, custom ID, and up to 5 [`discord.ui.InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) components. While creating modals, we generally subclass [`discord.ui.Modal`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal), as we'll see later. + +Unlike other UI Components, Modals cannot be sent with messages. They must be invoked by an Application Command or another UI Component. + +## Usage Syntax + +```py +class MyModal(discord.ui.Modal): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.add_item(discord.ui.InputText(label="Short Input")) + self.add_item(discord.ui.InputText(label="Long Input", style=discord.InputTextStyle.long)) + + async def callback(self, interaction: discord.Interaction): + embed = discord.Embed(title="Modal Results") + embed.add_field(name="Short Input", value=self.children[0].value) + embed.add_field(name="Long Input", value=self.children[1].value) + await interaction.response.send_message(embeds=[embed]) +``` + + + + +The `ctx` parameter we define in Application Commands receives an [`ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext) object. Using its `send_modal()` coroutine, you can send a Modal dialog to the user invoking the Application Command. + +```py +@bot.slash_command() +async def modal_slash(ctx: discord.ApplicationContext): + """Shows an example of a modal dialog being invoked from a slash command.""" + modal = MyModal(title="Modal via Slash Command") + await ctx.send_modal(modal) +``` + + + + +The `interaction` parameter we define in UI Components receives an [`Interaction`](https://docs.pycord.dev/en/stable/api/models.html#discord.Interaction) object. The `response` attribute of the object contains an [`InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object, with various coroutines such as `send_message()` and `send_modal()`, which we utilize. + +```py +class MyView(discord.ui.View): + @discord.ui.button(label="Send Modal") + async def button_callback(self, button, interaction): + await interaction.response.send_modal(MyModal(title="Modal via Button")) + +@bot.slash_command() +async def send_modal(ctx): + await ctx.respond(view=MyView()) +``` + + + + +The above example uses an embed to display the results of the modal submission, but you can do anything you want with the text provided by the user. +Each input field can be accessed in the order it was added to the modal dialog, via `Modal.children`. + +## Customization + +A Modal can have up to 5 [`InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) fields. These fields offer some customization. + +Each field has a label which is shown to the user. This is defined with `label`. + +The `style` parameter is used to determine whether it should be a short (single-line) or long (multi-line) input field. + +There are a number of aliases that can be used: + +```x title="Single-line InputTextStyle values:" +short +singleline +``` + +```x title="Multi-line InputTextStyle values:" +paragraph = 2 +multiline = 2 +long = 2 +``` + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Buttons](./buttons) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/introduction.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/introduction.mdx new file mode 100644 index 00000000..3262c632 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/introduction.mdx @@ -0,0 +1,50 @@ +--- +title: Introduction +description: Pycord Guide is a complete guide for Pycord. Learn how to create Discord Bots today! +sidebar_position: 1 +--- + +Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord, written in Python. Pycord is a maintained fork of [discord.py](https://github.com/Rapptz/discord.py). + +## Before you begin + +Pycord is an advanced and complex Python library. To take advantage of the full capabilities of Pycord, you will need to have a good understanding of Python. You should know the basics of Python and have an understanding of the following concepts: + +- Variables +- Data Types +- Functions +- Packages +- Conditionals +- Loops +- Classes +- Object-Oriented Programming +- Inheritance +- Exception Handling +- Iterators +- Coroutines +- Async/Await + +This list is not exhaustive, but it should give you a good idea of what you need to know to get started. + +When you see an ellipsis - that's the three dots - in this guide, it is a placeholder for code that you need to fill in. Sometimes, it may be code for a command, while other times it could be something simple like a Guild ID. Make sure to replace them before running your bot! + +## Learning Resources + +Here are some good resources to get started or to freshen up your Python knowledge: + +- [Official Beginner's Guide](https://wiki.python.org/moin/BeginnersGuide) +- [Official Tutorial](https://docs.python.org/3/tutorial/) +- [Automate the Boring Stuff, a free online book for complete beginners to programming](https://automatetheboringstuff.com/) +- [Learn Python in y Minutes, complete cheat sheet for people who know programming already](https://learnxinyminutes.com/docs/python3/) +- [Swaroopch's free Python book](http://python.swaroopch.com/) +- [Codeabbey, exercises for beginners](http://www.codeabbey.com/) + +## Credits + +First of all, we would like to thank [Rapptz](https://github.com/Rapptz) for the original [discord.py](https://pypi.org/project/discord.py) library. Pycord is a maintained fork of this library. + +We would also like to thank the [discord.js guide](https://discordjs.guide), which inspired this guide style-wise, and the [original Pycord Guide](https://namantech.me/pycord), which inspired some content in this guide. + +We created this guide using [Docusaurus v2](https://docusaurus.io), a modern static site generator for React. We would also like to thank Danktuary for his [`@discord-message-components/react`](https://www.npmjs.com/package/@discord-message-components/react) package, from which we took the Discord message components. + +And finally, we would like to thank the amazing and loving community of Pycord users, contributors and developers. diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/more/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/more/_category_.json new file mode 100644 index 00000000..2cbe2c56 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/more/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 8, + "label": "More", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/more/community-resources.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/more/community-resources.mdx new file mode 100644 index 00000000..ed3075bd --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/more/community-resources.mdx @@ -0,0 +1,23 @@ +--- +title: Community Resources +--- + +This page showcases the amazing things created by the Pycord community, including bots, Plugins, and more. + +## Plugins + +| Name | Type | GitHub | +| --------------- | ------------ | --------------------------------------------------------------- | +| Music Cord | Music | [NixonXC/cord-music](https://github.com/NixonXC/cord-music) | +| pycord-i18n | Localization | [Dorukyum-pycord-i18n](https://github.com/Dorukyum/pycord-i18n) | +| pycord-multicog | Cogs | [pycord-multicog](https://github.com/Dorukyum/pycord-multicog) | +| EzCord | Utilities | [EzCord](https://github.com/tibue99/ezcord) | + +## Bots + +| Name | Type | Link | +| ------------------------ | ------------ | ----------------------------------------------------------------------------------- | +| Discord-Multipurpose-Bot | Multipurpose | [github](https://github.com/pogrammar/Discord-multipurpose-bot/tree/master/Python) | +| inconnu | Fun & QOL | [github](https://github.com/tiltowait/inconnu) | +| Mai | Multipurpose | [github](https://github.com/TeamMai/Mai) & [website](https://xfghoul.github.io/Mai) | +| Toolkit | Multipurpose | [github](https://github.com/Dorukyum/Toolkit) | diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/more/contributing.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/more/contributing.mdx new file mode 100644 index 00000000..469ea3ee --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/more/contributing.mdx @@ -0,0 +1,463 @@ +--- +title: Contributing to the Guide +description: Learn how to contribute to the Pycord Guide. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +This page outlines some of the basic syntax you need to know to contribute to the guide. We recommend you also check out: + +- [Docusaurus's Docs](https://docusaurus.io/docs/) +- [Contributing Rules](https://github.com/Pycord-Development/guide/blob/master/.github/CONTRIBUTING.md) + +## Info + +We use [Docusaurus v2](https://docusaurus.io/) to generate our guide. All the guide pages are generated +from `mdx` files in the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory. +MDX allows you to use JSX in your markdown content. + +## Structure + +Let's visit the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory and check its file structure. + +We can see various folders and a few files in it. Let's talk a bit about the `introduction.mdx` file. At the top, you can see something like: + +```md +--- +title: Introduction +description: ... +sidebar_position: 1 +--- +``` + +Most pages have this at the top. The `title` defaults to the file name. Since the titles need to be Capitalized according to need while the file names are lowercased (sometimes, the file names are shorter than the title!), we set a title ourselves. + +The `description` field is also important. This is the text shown in an embed when the page's link is shared on Discord, Twitter or other websites that support embedded links. Make sure to give a nice an interesting description! + +The `sidebar_position` field is pretty self-explanatory. It sets the position of the page in the sidebar. Most files in categories do not need this since they are sorted alphabetically. + +## Markdown Syntax + +This page quickly outlines some of the syntax that is used in markdown. + +````mdx +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + + ```python + print("We can use code blocks like this.") + ``` + +You can add [links to other websites](https://pycord.dev). You can add images like this: ![alternate text that describes the image](https://pycord.dev/image.png). + +- You can create +- unordered lists like this + +1. Or ordered lists +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` +4. Like this + +# Headers + +## Go + +### Like + +#### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet +```` + +
+Preview +
+ +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + +```python +print("We can use code blocks like this.") +``` + +You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](@site/static/img/favicon.ico). + +- You can create +- unordered lists like this + +1. Or ordered lists + +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` + +4. Like this + + # Headers + + ## Go + + ### Like + + #### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet + +
+
+ +## Admonitions + +We can add warnings, notes, etc. with the following syntax: + +```md +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: +``` + +
+Preview +
+ +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: + +
+ +
+ +## Discord Message Components + +As most files already have the imports for these, it's not that hard to add them. + +First, import the necessary components: + +```tsx +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; +``` + +The div starts like so: + +```tsx + + + + +
+``` + +This is where you list a `DiscordMessage`. + +```tsx + + + Hello! + + + +
+``` + + + + Hello! + + + +
+ +It has a pretty straightforward syntax. + +:::tip + +Add a `
` to the end of a component to make the content below it look better. + +::: + +### Slash Commands + +To make a message authored by a slash command, do the following: + +```tsx + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+``` + + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+ +### Buttons + +To make a message with buttons, do the following: + +```tsx + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+``` + + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+ +## Page Format + +There are a few things you need to take care of: + +1. Make sure that the spelling and grammar is perfect. We have a GitHub action configured that will warn you about spelling errors when you start a pull request. Make sure to commit your changes accordingly. + + As for the grammar, you should try reading the changes you have done and wait for reviews from others. + +2. A common mistake people make is incorrect header style. People often think that the less the important the topic is, the lower it's heading style should be. + + ```md + [PAGE STARTS] + # Topic + ## Less Important Topic + ## Subtopic + ``` + + ```md + [PAGE STARTS] + # About + [Introduction] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + That's VERY wrong. Here's the correct example: + + ```md + [PAGE STARTS] + [Introduction] + ## Topic + ## Less Important Topic + ### Subtopic + ``` + + ```md + [PAGE STARTS] + [Introduction] + + ## About + [More Information] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + Note that the `---`s at the beginning have been skipped here. diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/more/git.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/more/git.mdx new file mode 100644 index 00000000..0f929d6d --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/more/git.mdx @@ -0,0 +1,55 @@ +--- +title: Installing Git +description: Learn how you can install Git on your system. +--- + +Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Let's see how to install Git on different platforms. + +## Windows + +On Windows, Git can be installed via: + +- [Git for Windows](https://gitforwindows.org) +- [Git Scm](https://git-scm.com/download/windows) + +## Linux + +On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. + +## Mac + +You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: + +``` +xcode-select --install +``` + +## Using Package Managers + +You can also install Git using package managers. + +### Chocolatey + +If you use the Chocolatey package manager, you can install Git using: + +``` +choco install git +``` + +### Scoop + +If you use Scoop, you can install Git using: + +``` +scoop install git +``` + +### Brew + +If you're on macOS or Linux, you can install Git using: + +``` +brew install git +``` diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx new file mode 100644 index 00000000..b0b8c7ea --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx @@ -0,0 +1,62 @@ +--- +title: Virtual Environments +description: Learn how to set up a virtual environment for Pycord. +--- + +## Setup + +Sometimes you want to keep libraries from polluting system installs or use a different version of libraries than the ones installed on the system. You might also not have permissions to install libraries system-wide. For this purpose, the standard library as of Python 3.3 comes with a concept called “Virtual Environment”s to help maintain these separate versions. + +A more in-depth tutorial is found on [Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html). + +However, for the quick and dirty: + +Go to your project’s working directory: + +```bash +$ cd your-bot-source +$ python3 -m venv venv +``` + +Activate the virtual environment: + +```bash +$ source venv/bin/activate +``` + +On Windows you activate it with: + +```batch +$ venv\Scripts\activate.bat +``` + +Use pip like usual: + +```bash +$ pip install -U py-cord +``` + +Congratulations. You now have a virtual environment all set up. + +## Additional info + +It can be useful to set up a requirements.txt, so you can just put all of your dependencies in there and have pip install it. +For instance, if you wanted to have the latest 2.0 version of pycord and [pytz](https://github.com/stub42/pytz/blob/master/src/README.rst), just create a file named requirements.txt with the following contents: + +``` +py-cord>=2.0.0 +pytz +``` + +And then (in your virtual environment) you can just execute + +```bash +pip install -r requirements.txt +``` + +To keep from committing your virtual environment to git, you can set up a .gitignore file with the following line +(assuming you named your virtual environment venv like the above example): + +``` +venv/ +``` diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/_category_.json new file mode 100644 index 00000000..c38ea014 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 7, + "label": "Popular Topics", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx new file mode 100644 index 00000000..5377a6c3 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx @@ -0,0 +1,140 @@ +--- +title: Cogs +--- + +Cogs, often known as modules or extensions, are used to organize commands into groups. This is useful +for grouping commands that have the same general idea (such as moderation commands). This also helps +to avoid making your bot's files messy and cluttered. + +## Getting Started + +First, you'll need to create a folder to store your cogs, e.g. `cogs/`. + +Then, create a file inside the folder, e.g. `cogs/greetings.py`. By convention, the file name should +be the same as the name of the cog or module. + +We can then create the cog. + +```python title="./cogs/greetings.py" +import discord +from discord.ext import commands + +class Greetings(commands.Cog): # create a class for our cog that inherits from commands.Cog + # this class is used to create a cog, which is a module that can be added to the bot + + def __init__(self, bot): # this is a special method that is called when the cog is loaded + self.bot = bot + + @commands.command() # creates a prefixed command + async def hello(self, ctx): # all methods now must have both self and ctx parameters + await ctx.send('Hello!') + + @discord.slash_command() # we can also add application commands + async def goodbye(self, ctx): + await ctx.respond('Goodbye!') + + @discord.user_command() + async def greet(self, ctx, member: discord.Member): + await ctx.respond(f'{ctx.author.mention} says hello to {member.mention}!') + + math = discord.SlashCommandGroup("math", "Spooky math stuff") # create a Slash Command Group called "math" + advanced_math = math.create_subgroup( + "advanced", + "super hard math commands!" + ) + + @math.command() + async def add(self, a: int, b: int): + c = a + b + await ctx.respond(f"{a} + {b} is {c}.") + + @advanced_math.command() + async def midpoint(self, x1: float, y1: float, x2: float, y2: float): + mid_x = (x1 + x2)/2 + mid_y = (y1 + y2)/2 + await ctx.respond(f"The midpoint between those coordinates is ({mid_x}, {mid_y}).") + + @commands.Cog.listener() # we can add event listeners to our cog + async def on_member_join(self, member): # this is called when a member joins the server + # you must enable the proper intents + # to access this event. + # See the Popular-Topics/Intents page for more info + await member.send('Welcome to the server!') + +def setup(bot): # this is called by Pycord to setup the cog + bot.add_cog(Greetings(bot)) # add the cog to the bot +``` + +You can add any number of commands to your cog, as well as event listeners. However, this code will +not work on its own. In your main bot file, you must add the following code: + +```python +bot.load_extension('cogs.greetings') +``` + +This loads the file `cogs/greetings.py` and adds it to the bot. +The argument of `load_extension` should be your cog's path (e.g. cogs/greetings.py) without the file +extension and with the `/` replaced with `.` + +If you have multiple cogs, you can add them all at once by adding the following code: + +```python +cogs_list = [ + 'greetings', + 'moderation', + 'fun', + 'owner' +] + +for cog in cogs_list: + bot.load_extension(f'cogs.{cog}') +``` + +## Cog Rules + +When using a cog instead of the main file, there are some changes you have to make to your code. This +is because cogs work slightly different from a regular file. + +### The `self` variable + +The self variable is a variable that represents a class. In the case of cogs, `self` represents +the cog. In the `__init__` function, you can see that we have `self.bot = bot`. `bot` represents your +`discord.Bot` or `discord.ext.commands.Bot` instance, which is used for some functions. + +This means that instead of using functions that would usually be accessed via `bot`, you now need +to access them via `self.bot` + +Because we're in a class, all of our commands are methods of that class. Because of this, all of our +functions need to have `self` as the first parameter, where `self` is the cog. Without this, we +wouldn't be able to access our bot instance. + +### Creating Commands + +When creating prefixed commands, your decorator would usually be something like `@bot.command()`. If you're using +cogs, this isn't the case. In a cog, you can't access the bot instance outside of functions, so to +register a function as a command, you must instead use `@commands.command()`. + +Similar to prefixed commands, you'll have to use either the `@discord.slash_command()`, `@discord.user_command()`, +or `@discord.message_command()` decorators for Application Commands. + +Also, when creating a command, make sure that it is indented. If we want a command to be actually +inside a cog, it has to be inside your cog's class. If the command is not inside the cog, +your command becomes useless. + +### Events + +When creating events, you can no longer use `@bot.event` as a decorator. This is because we cannot +access the `bot` variable outside a function. To make an event, you have to use the `ext.commands` +method, `@commands.Cog.listener()`. Events also need `self` as their first parameter. + +And that's it! Cogs are a simple and easy way of organizing your code. Now you can check out how to +create a help command [here](../extensions/commands/help-command). + +:::info Related Topics + +- [Creating a Help Command](../extensions/commands/help-command) +- [Rules and Common Practices](../getting-started/rules-and-common-practices) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Application Commands](../interactions#application-commands) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx new file mode 100644 index 00000000..6c19dd29 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx @@ -0,0 +1,383 @@ +--- +title: Error Handling +description: All about handling errors. +--- + +import { + DiscordEmbed, + DiscordInteraction, + DiscordMessage, +} from "discord-message-components/packages/react"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +## About + +When using the library, errors are frequently raised due to various reasons. These reasons range from the Discord API +failing your bot's request due to missing permissions or an invalid syntax error. + +Before going into error handling, it's best that you learn the basic ways of handling errors. A good resource is: + +- [W3Schools' Guide to Python Try-Except Statements](https://www.w3schools.com/python/python_try_except.asp) + +## Basic Handling + +The most basic way to handle errors is to tackle it at the source. This can be done like so: + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +import asyncio + +import discord + +intents = discord.Intents.default() +intents.message_content = True + +bot = discord.Bot(intents=intents) + + +@bot.slash_command(description="Gets some feedback.") +@discord.option("name", description="Enter your name.") +async def feedback(ctx: discord.ApplicationContext, name: str): + try: + await ctx.respond(f"Hey, {name}! Send your feedback within the next 30 seconds please!") + + def is_author(m: discord.Message): + return m.author.id == ctx.author.id + + feedback_message = await bot.wait_for("message", check=is_author, timeout=30.0) + await ctx.send(f"Thanks for the feedback!\nReceived feedback: `{feedback_message.content}`") + except asyncio.TimeoutError: + await ctx.send("Timed out, please try again!") + + +bot.run("TOKEN") +``` + +If you respond within 30 seconds, the interaction will look like so: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Great bot! + + + Thanks for the feedback! +
+ Received feedback: Great bot! +
+
+
+ +Otherwise, if you don't respond in time, the interaction will go as follows: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Timed out, please try again! + +
+
+ +This basic method of error handling can be extended to handle +many other errors including ones raised directly by py-cord. + +## Per-Command Handling + +This type of error handling allows you to handle errors per each command you have on your bot. +Each and every command can have it's own error handler made to handle specific errors that each command may raise! + +An example of per-command error handling is as follows: + +:::note Bridge Commands + +For these types of commands, it is recommended to utilize global error handling +until [the feature](https://github.com/Pycord-Development/pycord/issues/1388) is added. +::: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot(owner_id=...) # Your Discord user ID goes in owner_id + + +@bot.slash_command(description="A private command...") +@commands.is_owner() # This decorator will raise commands.NotOwner if the invoking user doesn't have the owner_id +async def secret(ctx: discord.ApplicationContext): + await ctx.respond(f"Hey {ctx.author.name}! This is a secret command!") + + +@secret.error +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.NotOwner): + await ctx.respond("Sorry, only the bot owner can use this command!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If your ID is registered as the owner ID, you'll get the following: + + + +
+ + secret + +
+ Hey Dorukyum! This is a secret command! +
+
+
+ +Any other user whose ID doesn't match the bot owner's will get the following: + + + +
+ + secret + +
+ Sorry, only the bot owner can use this command! +
+
+
+ +This local (per-command) error handler can also be used to handle the same types of errors that standard try-except +statements can handle. This is done by using the same method as above with the `isinstance` built-in function. + +## Per-Cog Handling + +Adding error handlers per-command can be quite the task in terms of work if you have a lot. If you have happened to +group your commands in cogs, then you're in luck! You can create an error handler that is specific to a cog and +handles all errors raised by commands inside that cog. + +Here's an example of a bot with a cog that implements its own error handling: + +```python title="./cogs/dm.py" +# This cog is for DM only commands! Sadly, we only have 1 command here right now... + +import discord +from discord.ext import commands + + +class DM(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.command() + @commands.dm_only() # This decorator will raise commands.PrivateMessageOnly if invoked in a guild context. + async def avatar(self, ctx: commands.Context): + embed = discord.Embed( + title="Avatar", + description=f"Here's your enlarged avatar, {ctx.author.name}!", + color=ctx.author.top_role.color + ) + embed.set_image(url=ctx.author.display_avatar.url) + await ctx.send(embed=embed, reference=ctx.message) + + async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): + if isinstance(error, commands.PrivateMessageOnly): + await ctx.send("Sorry, you can only use this in private messages!", reference=ctx.message) + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +def setup(bot: commands.Bot): + bot.add_cog(DM(bot)) +``` + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +# This is the main file where we load the DM cog and run the bot. + +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix=commands.when_mentioned_or("!")) +bot.load_extension("cogs.dm") +bot.run("TOKEN") +``` + +If you use this command in a DM context, you'll get the following: + + + + !avatar + + +
+ + !avatar + +
+ + Here's your enlarged avatar, BobDotCom! + +
+
+
+ +Otherwise, if used in a guild context: + + + + !avatar + + +
+ + !avatar + +
+ Sorry, you can only use this in private messages! +
+
+
+ +Per-cog error handling comes in very handy as you can relegate all of your error handling to a single function instead +of spreading it out across several per-command error handlers or inside the commands themselves. + +## Global Handling + +If separating your error handling is not how you would like to handle errors, then global error handling is the way to +go. This method of handling allows you to relegate all handling to a single function that resides within your bot +instance. + +A non-subclassed bot would implement this like so: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot() + + +@bot.slash_command(description="Get the bot's current latency!") +@commands.cooldown(1, 30, commands.BucketType.user) +# ^ This decorator allows one usage of the command every 30 seconds and raises commands.CommandOnCooldown if exceeded +async def ping(ctx: discord.ApplicationContext): + await ctx.respond(f"Pong! `{int(bot.latency*1000)} ms`.") + + +@bot.event +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.CommandOnCooldown): + await ctx.respond("This command is currently on cooldown!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If you've subclassed your bot, the `on_application_command_error` event will be placed inside the subclass without a +`bot.event` decorator and `bot.slash_command` will be replaced with `discord.slash_command`. + +The error handling used above will yield this interaction if the command is used again too quickly: + + + +
+ + ping + +
+ Pong! 49 ms. +
+ +
+ + ping + +
+ This command is currently on cooldown! +
+
+
+ +The only issue regarding global error handling is that, if you have a large amount of commands, the global handler may +start to get crammed with a lot of code. This is where all the previously mentioned handlers can take their place! + +## FAQ + +#### Why does the example in per-cog handling have self at the start of its function signatures? + +This is a feature of classes and allows you to reference the cog object as `self` and get access to the bot object +passed at initialization through `self.bot`. + +If this is new to you, we recommend checking out these helpful resources to learn more about classes and cogs: + +- [W3Schools' Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [Our Cogs Guide Page](./cogs) + +#### How many errors can I handle in a single error handler? + +While all the examples in this guide page only handle one specific error and re-raise all others, all of these +error handlers can be extended to catch many errors. + +In [basic handling](#basic) (i.e. try/except statements) you can do one of two things: + +- Explicitly handle the errors you know might get raised and then have a broad `except Exception as exc:` statement + as a catch-all. +- Catch any and all errors via the catch-all statement mentioned above. + +In [per-command](#percommand), [per-cog](#percog), and [global handling](#global), you can use elif clauses with the +built-in isinstance function to catch specific errors. Atop of this, an else clause can be used to catch any other +errors you either don't want to handle or want to relegate to a different error handler. + +#### Can I use more than one type of error handler at once? + +Thankfully, all of these different ways of error handling can be mixed together, so you don't have to pick just one! +For commands that raise specific errors that no other commands will raise, you can use [per-command](#percommand). +For cogs that raise specific errors that no other cogs will raise, use [per-cog](#percog)! Lastly, for errors that +occur frequently across all commands and cogs, use [global handling](#global)! + +However, one important note to remember is that you should always raise the error again in an error handler if it +isn't handled there! If you don't do this, the error will go ignored and your other handlers won't have a chance to +do their work! + +#### What's the difference between slash and prefixed command error handling? + +Although most examples shown here use slash commands, the [per-cog handling](#percog) section presents a prefixed +command. The main difference you may notice is the change in command signature. + +To make the distinguishing features apparent: + +- Slash commands use `on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException)` + as presented in the [per-command](#percommand) and [global handling](#global) examples. +- Prefixed commands use `on_command_error(ctx: commands.Context, error: commands.CommandError)` as presented in the + [per-cog handling](#percog) example. + +This distinction is made as both types of commands need their own system for handling errors that are specific to +themselves. + +:::info Related Topics + +- [Slash Commands](../interactions/application-commands/slash-commands) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Cogs](./cogs) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx new file mode 100644 index 00000000..9f4210af --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx @@ -0,0 +1,62 @@ +--- +title: Intents +description: All about intents in Discord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +## What are Intents? + +Intents allow bot developers to "subscribe" to specific events in Discord. This is useful for bots that need to respond to specific events, such as when a user joins a server or sends a message. You could choose to enable all intents or to enable only specific intents that your bot requires. + +## How do I enable intents? + +:::important + +Remember that [Privileged Intents](#what-are-privileged-intents) require you to enable them in the Discord Developer Portal. Verified Discord Bots that don't already have access to them will need to request Discord to allow access. + +::: + + + + +```python +import discord + +bot = discord.Bot(intents=discord.Intents.all()) +``` + + + + + +You can view a list of intents and the events they subscribe to [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```python title="Enabling Intents" +import discord + +bot = discord.Bot(intents=discord.intents.members(bans=True, guilds=True)) +``` + + + + +## What are Privileged Intents? + +Discord defines some intents as "privileged" because of the sensitive information they contain. Currently, there are three privileged intents: `members`, `presences`, and `message_content`. These intents must be enabled in your bot's Developer Portal. Once your bot reaches 100 servers, you will need to verify your bot for these intents to keep working and for your bot to be able to be invited to more guilds. + +:::tip + +Only enable these intents if you need them. These intents give your bot access to quite sensitive information about the users in your guild. These intents are privileged to respect the privacy of users, and you should do that as well. + +Not enabling these intents doesn't mean you won't be able to ban users, but you will be unable to detect when a new user joins a guild, or what game they are playing. The majority of bots won't need all intents. + +::: + +:::info Related Topics + +- [Sharding Bots](sharding) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx new file mode 100644 index 00000000..c3d17197 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx @@ -0,0 +1,48 @@ +--- +title: Sharding +description: All about Sharding Discord Bots. +--- + +# Sharding + +## What is Sharding? + +Sharding is the process of breaking up your bot into smaller pieces so that it has a better time handling +events. As [Discord's Documentation](https://discord.com/developers/docs/topics/gateway#sharding) puts +it, sharding is "a method of user-controlled guild sharding which allows for splitting events across +several gateway connections." + +Sharding is used only for large bots and takes up additional resources for managing the new processes. +Pycord automatically shards your bot, so the only thing you need to do is use an `AutoShardedClient` +or `AutoShardedBot` class instead of a plain `Client` or `Bot` class. Pretty cool, right? + +Just because you _can_ shard your bot doesn't mean you _should_. While Pycord makes it easy to shard +your bot, it isn't necessary to shard unless your bot is large. Sharding a small bot isn't +just useless, but _harmful_, as it uses extra resources and may slow down your bot. Discord +themselves will let you know when your bot needs sharding, so you won't need to worry about this until they contact you. + +## How Do I Shard in Pycord? + +Sharding in Pycord is straightforward. + +Just replace your `discord.Client`, `discord.Bot`, `commands.Bot` objects +with `discord.AutoShardedClient`, `discord.AutoShardedBot`, `commands.AutoShardedBot` respectively. + +These new objects have been inherited from the original objects, so all the functions from those other types should be present. + +If you want to specify the number of shards your bot uses, +just add the `shards` parameter, along with the number of shards you want. + +## Why Should I Shard my Bot? + +Sharding is very necessary for big bots. While your bot grows, it gets harder for your bot to control +how many guilds it is in and what parts of your code should do what. This is exactly what sharding +handles, it makes all of this easier for your bot. Remember, though, only shard your bot once it's +big enough, and that's at _least_ 1,000 guilds. + +:::info Related Topics + +- [Hosting your Bot](../Getting-Started/hosting-your-bot) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx new file mode 100644 index 00000000..bd2969c1 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx @@ -0,0 +1,115 @@ +--- +title: Subclassing Bots +description: Subclassing is a popular way of creating Discord Bots. Explore how you can create a Discord bot by subclassing. +--- + +## About + +Subclassing is another popular way of creating Discord Bots. Here, you create a bot by extending a bot class. To some advanced users, this is preferable to creating a bot instance with `bot = discord.Bot()`. + +Subclassing is an intermediate python concept, so we recommend you learn about it before continuing. Some good resources are: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +## Why Subclassing? + +Many developers prefer to subclass their bots for many reasons, some of them being: + +#### Skeletal Frameworks for Bots + +Developers often share their bots code on open-source platforms, mostly GitHub, and allow users to self-host the bot (running their own instance of the bot with the code provided by the developer. Permissions vary in accordance to licences). Here, users find it easier and more convenient to have a small file that imports the custom bot class and runs it, rather than having to go through the code of the bot and find out which file to run. This makes it easier for people not familiar with programming to run and customize the bot, since it often brings down the code to: + +```python title="./main.py" +from src import Bot + +bot = Bot() + +bot.run("TOKEN") +``` + +Here, all the commands are inside the `/src` folder that the user need not bother with. + +#### Running Multiple Instances + +Some developers may need to run multiple instances of their bot (perhaps on different bot accounts). For example, a developer might have a second bot for testing alpha features. This system makes it simpler for the developer, and allows them to maintain multiple versions of the bot in the same directory: + +```python title="./alpha_bot.py" +from src import Bot + +class AlphaBot(Bot): # subclasses Bot + ... # insert any custom configuration + +bot = AlphaBot() + +@bot.slash_command() # adds a new slash command to this subclassed bot +async def alpha_feature(ctx): + await ctx.respond("Alpha Feature!") + +bot.run("TOKEN") +``` + +There are many more reasons to subclass! It's not required, and won't affect the speed of the bot, but it may affect your development process, for the good or for the worse. You don't miss out on any features when you subclass, either. Some developers want the OOP feel, while some just prefer that method and find it easier. + +## Basic Example + +```python +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override the on_ready event + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') + +bot = MyBot() + +@bot.slash_command() # create a slash command +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run('token') +``` + +As you can see, instead of creating a bot object with `bot = discord.Bot()`, we subclass [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). We then create an instance of our new bot class and run it. Notice how we don't need to use the `@event` decorator. + +Here's another example: + +```python title="./src/bot.py" +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override on_ready + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') +``` + +```python title="./src/\_\_init\_\_.py" +from .bot import MyBot # import the MyBot class from the bot.py file +``` + +```python title="./main.py" +from src import MyBot # import MyBot from /src + +bot = MyBot() # create an instance of MyBot + +@bot.slash_command() +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run("TOKEN") # run the bot +``` + +These are just two ways you could do it. There are ton of other structures you can implement. It's up to you. + +So, should you subclass? There are no limitations you face if you decide to subclass your bot, but, once again, it's up to you. + +:::info Related Topics + +- [Making a Help Command](../Extensions/Commands/help-command) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx new file mode 100644 index 00000000..23220b0e --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx @@ -0,0 +1,105 @@ +--- +title: Threads +description: Threads with Pycord +--- + +In programming, threads are a way to run multiple processes at the same time. In Discord, threads are +a way to keep multiple conversations going at the same time. Let's take a brief look at how to use threads in Pycord. + +:::tip + +Not all the methods and attributes will be covered in this guide, but you can find them in our documentation! +[Check it out!](https://docs.pycord.dev/en/stable/api/models.html#discord.Thread) + +::: + +## Creating a thread + +With a few simple lines of code, we can create threads in Pycord. + +:::important + +All public threads need a starting message. This message will start the thread. However, private threads +(which are unlocked with having your server boosted to Level 2), do not require a starting message. + +::: + +### Creating thread from a message + +```python title="Creating a Thread from a Message" +message = await ctx.send("My Starting Message") +await message.create_thread(name="thread name", auto_archive_duration=60) +``` + +You may also use other ways to create the thread, for example, by using `on_message` events or by commands. + +### Creating thread in a channel + +```python title="Creating a Thread from a Channel" +channel = bot.get_channel(...) # define this! +await channel.create_thread(name="Thread Name", message=None, auto_archive_duration=60, type=None, reason=None) +``` + +A thread type could be `news_thread`, `public_thread`, `private_thread`. You may use it by passing `type=discord.ChannelType.news_thread`. + +## Deleting Threads + +Deleting Threads is simple. You need to get a thread and then use the `delete` method. + +```python title="Deleting a Thread" +thread = bot.get_channel(thread_id) # you could use other ways to get a thread +await thread.delete() +``` + +## Editing Threads + +**Parameters** + +- `name` (str) – The new name of the thread + +- `archived` (bool) – Whether to archive the thread or not. + +- `locked` (bool) – Whether to lock the thread or not. + +- `invitable` (bool) – Whether non-moderators can add other non-moderators to this thread. Only available for private threads. + +- `auto_archive_duration` (int) – The new duration in minutes before a thread gets automatically archived for inactivity. Must be one of 60, 1440, 4320, or 10080. + +- `slowmode_delay` (int) – Specifies the slow-mode rate limit for users in the thread, in seconds. A value of 0 disables slow-mode. The maximum value possible is 21600. + +```python title="Editing a Thread" +thread = bot.get_channel(id) +await thread.edit( + name="New Name", + archived=True, + locked=True, + slowmode_delay=10, + auto_archive_duration=60, +) +``` + +As you can see, threads are very simple. Once you learn how to use them, it's easy to create whatever you want. + +## FAQ + +### Why am I getting a `Forbidden` error when I try to create a thread? + +A `Forbidden` error occurs when the bot does not have the correct permissions to create threads. + +### Why am I getting an Unknown Message error when I try to create a thread? + +Getting an error looking something like `discord.ext.commands.errors.CommandInvokeError: Command +raised an exception: HTTPException: 400 Bad Request (error code: 10008): Unknown Message`? + +There could be multiple reasons, some of them being: + +- The message does not exist +- The message already has a thread +- The message is in channel x, you are trying to start a thread in channel y. +- The message was deleted. + +:::info Related Topics + +<>{/* I can't think of any related topics for this at the moment. */} + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/voice/_category_.json b/i18n/hi/docusaurus-plugin-content-docs/current/voice/_category_.json new file mode 100644 index 00000000..8baf3da8 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/voice/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 6, + "label": "Voice" +} \ No newline at end of file diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/voice/index.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/voice/index.mdx new file mode 100644 index 00000000..835838c6 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/voice/index.mdx @@ -0,0 +1,24 @@ +--- +title: Voice +--- + +Welcome to the guide for voice features in Pycord. + +:::caution +This guide requires previous experience with Pycord and Python. +::: + +## Requirements + +The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). +The following features are optional: + +:::tip +Opus is also a required library, but this comes with Pycord. +Some hosts may not come with it, though, so remember to always check if required dependencies are installed. +::: + +- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` +- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), + [`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), + [`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/voice/playing.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/voice/playing.mdx new file mode 100644 index 00000000..fe14c52a --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/voice/playing.mdx @@ -0,0 +1,149 @@ +--- +title: Wavelink Audio Player +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { + defaultOptions, +} from "@site/src/components/DiscordComponent"; + +# About + +Pycord and Wavelink try to keep the playing of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio playing feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/). + +## Starting out + +First you need to run a [Lavalink Server](https://github.com/freyacodes/Lavalink) to connect with. +There a multiple documentations to do this, so we are not covering that here. + +You also need to install the [wavelink](https://github.com/PythonistaGuild/Wavelink) library. + +```py title="Installing wavelink" +python3 -m pip install wavelink +``` + +You will now want to connect to your server via a node. + +```py title="Connect Node with Lavalink" +import discord +import wavelink + +bot = discord.Bot() + +async def connect_nodes(): + """Connect to our Lavalink nodes.""" + await bot.wait_until_ready() # wait until the bot is ready + + nodes = [ + wavelink.Node( + identifier="Node1", # This identifier must be unique for all the nodes you are going to use + uri="http://0.0.0.0:443", # Protocol (http/s) is required, port must be 443 as it is the one lavalink uses + password="youshallnotpass" + ) + ] + + await wavelink.Pool.connect(nodes=nodes, client=bot) # Connect our nodes +``` + +
+ +Now you are finished making your node! Next, you will want to: + +1. Making a play command +2. Adding connect events + +### Making a play command + +To make a play command, you will need to make a function to connect and play audio in a voice channel. + +```py title="Play Command Example" +import typing + +@bot.slash_command(name="play") +async def play(ctx, search: str): + # First we may define our voice client, + # for this, we are going to use typing.cast() + # function just for the type checker know that + # `ctx.voice_client` is going to be from type + # `wavelink.Player` + vc = typing.cast(wavelink.Player, ctx.voice_client) + + if not vc: # We firstly check if there is a voice client + vc = await ctx.author.voice.channel.connect(cls=wavelink.Player) # If there isn't, we connect it to the channel + + # Now we are going to check if the invoker of the command + # is in the same voice channel than the voice client, when defined. + # If not, we return an error message. + if ctx.author.voice.channel.id != vc.channel.id: + return await ctx.respond("You must be in the same voice channel as the bot.") + + # Now we search for the song. You can optionally + # pass the "source" keyword, of type "wavelink.TrackSource" + song = await wavelink.Playable.search(search) + + if not song: # In case the song is not found + return await ctx.respond("No song found.") # we return an error message + + await vc.play(song) # Else, we play it + await ctx.respond(f"Now playing: `{song.title}`") # and return a success message +``` + + + +
+ + play + +
+ Now playing: Never Gonna Give You Up +
+
+ +
+ +Now that you've done this, the only thing left to do is make your connect events. + +### Adding connect events + +The final step to this guide is connecting the node to your server when the bot goes online. + +To make it, you will want to do the following: + +```py title="Adding connect events" +@bot.event +async def on_ready(): + await connect_nodes() # connect to the server + +@bot.event +async def on_wavelink_node_ready(payload: wavelink.NodeReadyEventPayload): + # Everytime a node is successfully connected, we + # will print a message letting it know. + print(f"Node with ID {payload.session_id} has connected") + print(f"Resumed session: {payload.resumed}") + +bot.run("token") +``` + +Congratulations! You have now implemented voice playing into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-docs/current/voice/receiving.mdx b/i18n/hi/docusaurus-plugin-content-docs/current/voice/receiving.mdx new file mode 100644 index 00000000..1bc364e1 --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-docs/current/voice/receiving.mdx @@ -0,0 +1,130 @@ +--- +title: Receiving Voice Samples +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +# About + +Pycord tries to keep the recording of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio recording feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/audio_recording.py). + +## Starting out + +The first thing you want to do is make a cache of your voice connections. This is fairly easy; as +it's just putting a variable with an empty dictionary in our code, such as `connections = {}`. + +You will now want to create your command for recording. + +```py title="Record Command Example" +import discord + +bot = discord.Bot() +connections = {} + +@bot.command() +async def record(ctx): # If you're using commands.Bot, this will also work. + voice = ctx.author.voice + + if not voice: + await ctx.respond("You aren't in a voice channel!") + + vc = await voice.channel.connect() # Connect to the voice channel the author is in. + connections.update({ctx.guild.id: vc}) # Updating the cache with the guild and channel. + + vc.start_recording( + discord.sinks.WaveSink(), # The sink type to use. + once_done, # What to do once done. + ctx.channel # The channel to disconnect from. + ) + await ctx.respond("Started recording!") +``` + + + +
+ + record + +
+ Started recording! +
+
+ +
+ +Now you are finished making your command for voice receiving! Next, you will want to: + +1. Make your finished callback +2. Make a stop command + +### Making a Callback + +To make a callback, you will want to define the currently undefined `once_done` function inside +our command, like so: + +```py title="Recorder Callback" +async def once_done(sink: discord.sinks, channel: discord.TextChannel, *args): # Our voice client already passes these in. + recorded_users = [ # A list of recorded users + f"<@{user_id}>" + for user_id, audio in sink.audio_data.items() + ] + await sink.vc.disconnect() # Disconnect from the voice channel. + files = [discord.File(audio.file, f"{user_id}.{sink.encoding}") for user_id, audio in sink.audio_data.items()] # List down the files. + await channel.send(f"finished recording audio for: {', '.join(recorded_users)}.", files=files) # Send a message with the accumulated files. +``` + + + + finished recording audio for:{" "} + {defaultOptions.profiles.bob.author} + + + +
+ +Now that you've done this, the only thing left to do is make your stop command. + +### Making a Stop Command + +The final step to this guide is stopping the audio recording. This is the easiest step by far. + +To make it, you will want to do the following: + +```py title="Stop Recording Command" +@bot.command() +async def stop_recording(ctx): + if ctx.guild.id in connections: # Check if the guild is in the cache. + vc = connections[ctx.guild.id] + vc.stop_recording() # Stop recording, and call the callback (once_done). + del connections[ctx.guild.id] # Remove the guild from the cache. + await ctx.delete() # And delete. + else: + await ctx.respond("I am currently not recording here.") # Respond with this if we aren't recording. + +bot.run("token") +``` + +Congratulations! You have now implemented voice recording into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/hi/docusaurus-plugin-content-pagesindex.tsx b/i18n/hi/docusaurus-plugin-content-pagesindex.tsx new file mode 100644 index 00000000..84df3a9c --- /dev/null +++ b/i18n/hi/docusaurus-plugin-content-pagesindex.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import DefaultLayout from "../layouts/DefaultLayout"; +import PYCHero from "@site/src/components/PYCHero"; +import PYCButton from "@site/src/components/PYCButton"; + +export default function Home(): JSX.Element { + return ( + + +
+ Imagine a place where you can learn how to create an awesome Discord + bot, equip it with Pycord, and have it running in less than a minute. + Imagine a place where you can learn everything about Pycord. Imagine a + guide. A Pycord Guide! +

+ Whether you are a newbie or an experienced developer, you will find + everything you need to know about Pycord here. This guide will teach + you: +
    +
  • How to get a brand new bot running from scratch;
  • +
  • How to create Interactions, Context Menus and Commands;
  • +
  • In-depth concepts such as Embeds, Reactions, Help Commands, Paginators, etc;
  • +
  • Popular Topics such as working with Databases, Sharding, etc;
  • +
  • Ways to handle and manage common errors and best practices for bots;
  • +
  • And Much More!
  • +
+
+
+ ); +} diff --git a/i18n/hi/docusaurus-theme-classic/footer.json b/i18n/hi/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..ffb8a652 --- /dev/null +++ b/i18n/hi/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Pycord Development, All rights reserved.", + "description": "The footer copyright" + } +} diff --git a/i18n/hi/docusaurus-theme-classic/navbar.json b/i18n/hi/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..473b847e --- /dev/null +++ b/i18n/hi/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "Pycord Guide", + "description": "The title in the navbar" + }, + "item.label.Home": { + "message": "Home", + "description": "Navbar item with label Home" + }, + "item.label.Docs": { + "message": "Docs", + "description": "Navbar item with label Docs" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + }, + "item.label.Source": { + "message": "Source", + "description": "Navbar item with label Source" + } +} diff --git a/i18n/it/code.json b/i18n/it/code.json new file mode 100644 index 00000000..9cce6148 --- /dev/null +++ b/i18n/it/code.json @@ -0,0 +1,404 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { + "message": "Toggle the collapsible sidebar category '{label}'", + "description": "The ARIA label to toggle the collapsible sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search here", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.algoliaLabel": { + "message": "Search by Algolia", + "description": "The ARIA label for Algolia mention" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorite", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "You might want to check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Algolia" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Try searching for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Believe this query should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/i18n/it/docusaurus-plugin-content-blog/options.json b/i18n/it/docusaurus-plugin-content-blog/options.json new file mode 100644 index 00000000..9239ff70 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/it/docusaurus-plugin-content-docs/current.json b/i18n/it/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..36b4849a --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,46 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.defaultSidebar.category.Getting Started": { + "message": "Getting Started", + "description": "The label for category Getting Started in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Interactions": { + "message": "Interactions", + "description": "The label for category Interactions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Application Commands": { + "message": "Application Commands", + "description": "The label for category Application Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.UI Components": { + "message": "UI Components", + "description": "The label for category UI Components in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Extensions": { + "message": "Extensions", + "description": "The label for category Extensions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Commands": { + "message": "Commands", + "description": "The label for category Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Pages": { + "message": "Pages", + "description": "The label for category Pages in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Voice": { + "message": "Voice", + "description": "The label for category Voice in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Popular Topics": { + "message": "Popular Topics", + "description": "The label for category Popular Topics in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.More": { + "message": "More", + "description": "The label for category More in sidebar defaultSidebar" + } +} diff --git a/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png b/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png new file mode 100644 index 00000000..7480e1da Binary files /dev/null and b/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png differ diff --git a/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg b/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg new file mode 100644 index 00000000..ce6b5110 Binary files /dev/null and b/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg differ diff --git a/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png b/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png new file mode 100644 index 00000000..846eee15 Binary files /dev/null and b/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png differ diff --git a/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png b/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png new file mode 100644 index 00000000..32a47d04 Binary files /dev/null and b/i18n/it/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png differ diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/extensions/_category_.json new file mode 100644 index 00000000..309b494a --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 5, + "label": "Extensions", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json new file mode 100644 index 00000000..652aa4ee --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Bridge" +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx b/i18n/it/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx new file mode 100644 index 00000000..81545fa2 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx @@ -0,0 +1,190 @@ +--- +title: Bridge +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +## Concept + +Let's say that you want to make a command that is both a Slash Command and a Prefixed Command. Now, you could just copy and paste the code from the first command callback to the other and make some adjustments, but that's not very efficient. + +This is where the `ext.bridge` module comes in. It allows you to use one callback to make both a Slash Command and a Prefixed Command. + +### Example Usage + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def hello(ctx): + await ctx.respond("Hello!") + +bot.run("TOKEN") +``` + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+
+ +## Syntax + +First, instead of using `discord.Bot` or `commands.Bot`, we use `bridge.Bot`. `bridge.Bot` does inherit from `commands.Bot`, so you can do anything with `bridge.Bot` that `commands.Bot` can do. +Then, we define a command with `@bot.bridge_command()`. This makes a Bridge Command, which has both a Prefixed Command counterpart and a Slash Command counterpart. +Next, the callback has access to a `ctx` object, which is the context of the command. This context is either of `BridgeApplicationContext` type or `BridgeExtContext`. Because of that, it makes detecting how the function was called easier. + +### Using Bridge Commands in a Cog + +Like Slash Commands and Prefixed Commands, you can use Bridge Commands in a Cog. You can do this by using the `bridge_command` decorator. Here's an example: + +```python +import discord +from discord.ext import bridge, commands + +class Greetings(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @bridge.bridge_command() + async def hello(self, ctx): + await ctx.respond("Hello!") + + @bridge.bridge_command() + async def bye(self, ctx): + await ctx.respond("Bye!") + +def setup(bot): + bot.add_cog(Greetings(bot)) +``` + +The cog will automatically split the Bridge Command into their Slash Command and Prefixed Command counterparts. + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+ + +
+ + bye + +
+ Bye! +
+ + + !bye + + + +
+ + !bye + +
+ Bye! +
+
+ +### Deferring + +You can defer if you want to communicate to the user that your bot is busy processing the command. This is done by using `ctx.defer()`. For the Slash Command implementation, `ctx.defer()` calls the function that gives out a "Bot is thinking" message. For the Prefixed Command implementation, `ctx.defer()` enables the typing indicator. + + + +### Options + +Options are pretty straightforward. You just specify them like you do with prefixed commands, and you're all set! + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def sum(ctx, a: int, b: int): + await ctx.respond(a + b) + +bot.run("TOKEN") +``` + + + +
+ + sum + +
+ 4 +
+ + + !sum 2 2 + + + +
+ + !sum 2 2 + +
+ 4 +
+
diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json new file mode 100644 index 00000000..63f8e08e --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx b/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx new file mode 100644 index 00000000..bf345c07 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx @@ -0,0 +1,56 @@ +--- +title: Command Groups +--- + +Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk +remove`. + +## Syntax + +Creating a command group is very simple. + +```python title="Command Groups Example" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!') + +@bot.group() +async def afk(): + pass + +@afk.command() +async def set(): + ... + +@afk.command() +async def remove(): + ... + +# Another command group + +@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. +async def math(ctx): + await ctx.send('Subcommand not found') + +@math.command() +async def add(ctx, a: int, b: int): + ... + +@math.command() +async def subtract(ctx, a: int, b: int): + ... +``` + +To create a command group, the command's decorator must be `@bot.group`. Once you have a command with +that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand +groups! + + + +:::info Related Topics + +- [Prefixed Commands](./prefixed-commands.mdx) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx b/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx new file mode 100644 index 00000000..acbdc0a8 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx @@ -0,0 +1,481 @@ +--- +title: Help Command +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Pycord's `commands` extension comes with a built-in help command. In this guide, we will take a look at them as well as learn how to create your own. Let's dive in! + +:::note + +This guide demonstrates using object-oriented programming and subclassing to make a help command for your +Pycord bot. It is important to understand these two concepts before continuing. + +**Learning Resources**: + +- [W3Schools - Python Subclassing](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools - Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +::: + +## The Wrong Way + +A popular way to create a help command is to disable the built-in help command and create your own. This is not recommended as it will lead to a lot of confusion. + +```python title="The Wrong Way" +bot = commands.Bot(command_prefix='!', help_command=None) +# OR +bot.help_command = None +# OR +bot.remove_command("help") + +@bot.command() +async def help(ctx, *, argument=None): + ... +``` + +While it's possible to create a help command this way, doing so does not utilize the full capabilities +of making one with Pycord. Making a help command with subclassing and OOP will save time and effort. + +## Types of Help Commands + +There are two types of built-in help commands: + +- [`DefaultHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand) +- [`MinimalHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand) + +`DefaultHelpCommand` is the command enabled by default. It isn't the best looking, but `MinimalHelpCommand` can help make it look a bit better. + + + + +```python title="Default Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.DefaultHelpCommand()) # help_command is DefaultHelpCommand by default so it isn't necessary to enable it like this +# We enable it here for the sake of understanding + +... + +bot.run("token") +``` + + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ + +```python title="Minimal Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.MinimalHelpCommand()) + +... + +bot.run("token") +``` + + + + !help + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+ +
+ +
+ +## Updating Built-in Help Commands + +Let's try to make the `MinimalHelpCommand` look better. We can do this by putting its content in an +embed. + +```python title="Minimal Help Command Example" +bot = commands.Bot(command_prefix='!') + + +class MyNewHelp(commands.MinimalHelpCommand): + async def send_pages(self): + destination = self.get_destination() + for page in self.paginator.pages: + emby = discord.Embed(description=page) + await destination.send(embed=emby) + +bot.help_command = MyNewHelp() +``` + +Let's go through the code. + +First, we create a new class called `MyNewHelp`. This class is a subclass of `MinimalHelpCommand`. + +Next, we override the `send_pages` method. This method is responsible for sending the help command to +the user. We override this method because we don't want to change the content of the pages, just how +they are sent. + +We use the `get_destination` method to get the destination of the message. This is the channel or use that the help +command is to be sent to. + +We use the `paginator.pages` property to get the different pages of the help command. We put the page +in an embed, and then send the embed to the destination channel. + +Finally, we set this as our new help command using `bot.help_command = MyNewHelp()`. + + + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a + category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+
+ +## Creating Your Help Command + +Not satisfied with the built-in help commands? You can create your own! + +For this, we will subclass the `HelpCommand` class. + +There are 4 methods that we need to override: + +- `HelpCommand.send_bot_help(mapping)` that gets called with `help` +- `HelpCommand.send_command_help(command)` that gets called with `help ` +- `HelpCommand.send_group_help(group)` that gets called with `help ` +- `HelpCommand.send_cog_help(cog)` that gets called with `help ` + +### Bot Help + +```python title="Bot Help Example" +class MyHelp(commands.HelpCommand): + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help") + for cog, commands in mapping.items(): + command_signatures = [self.get_command_signature(c) for c in commands] + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's go through the code. + +- First, we create a new class called `MyHelp`. This class is a subclass of `HelpCommand`. + +- Next, we override the `send_bot_help` method. This method is responsible for sending the main help + command to the user. + +- We create an embed with the title "Help". + +- We iterate through `mapping.items()`, which returns a list of tuples, the first element being the + cog and the second element being a list of commands. + +- By using `self.get_command_signature(c)` we get the signature of the command, also known as the + `parameters` or `arguments`. + +- There is a chance that the cog is empty, so we use `if command_signatures:`. + +- We get the name of the cog using `getattr(cog, "qualified_name", "No Category")`. This calls the + cog's attribute `qualified_name` which returns "No Category" if the cog has no name. + +- We add a field to the embed with the name of the cog and the value of the command signatures. + +- Finally, we send the embed to the channel. + +Let's improve the code a little. + +```python title="Improved Bot Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + command_signatures = [self.get_command_signature(c) for c in filtered] + + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Now the help command won't show commands that the user can't use, as well as aliases for commands. +Let's get the help command to show command aliases. + +### Command Help + +This function is called when the user uses `help `. + +```python title="Command Help Example" +class MyHelp(commands.HelpCommand): + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command), color=discord.Color.random()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's quickly go through the code we haven't discussed yet. + +- In line 3, we create an embed with a title the signature of the command (so that the title of the + embed looks like ` [parameter]`), and a random color. + +- In lines 4 and 5, we get the command's `help` description and add it to the embed. The help description + of a command can be specified in the docstrings of a command function. For example: + + ```` + ```python + @bot.command() + async def ping(ctx): + """Returns the latency of the bot.""" + await ctx.send(f"Pong! {round(bot.latency * 1000)}ms") + ``` + ```` + +- Line 6 is shorthand for + + ```python + alias = command.aliases + if alias: + ... + + # is the same as + + if alias := command.aliases: + ... + ``` + + A very helpful (but not well-known) Python shorthand! + +- In line 7, we get the aliases of the command and add them to the embed. + +### Cog Help + +This is pretty easy! + +```python title="Custom Cog Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_cog_help(self, cog): + embed = discord.Embed(title=cog.qualified_name or "No Category", description=cog.description, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(cog.get_commands()): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Once again, we create an embed, get the commands that the user can use, and add them to the embed. + +### Group Help + +Similar to the cog help, this is pretty easy! + +```python title = "Custom Group Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_group_help(self, group): + embed = discord.Embed(title=self.get_command_signature(group), description=group.help, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(group.commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Add all of these methods together, and you have a fully functioning help command! + +
+Click to see the final code for this section +
+ +:::note + +The following code has been slightly edited from the tutorial version. + +::: + +```python title="Custom Help Command Example" +class SupremeHelpCommand(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + if command_signatures := [ + self.get_command_signature(c) for c in filtered + ]: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command) , color=discord.Color.blurple()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_help_embed(self, title, description, commands): # a helper function to add commands to an embed + embed = discord.Embed(title=title, description=description or "No help found...") + + if filtered_commands := await self.filter_commands(commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No help found...") + + await self.get_destination().send(embed=embed) + + async def send_group_help(self, group): + title = self.get_command_signature(group) + await self.send_help_embed(title, group.help, group.commands) + + async def send_cog_help(self, cog): + title = cog.qualified_name or "No" + await self.send_help_embed(f'{title} Category', cog.description, cog.get_commands()) + +bot.help_command = SupremeHelpCommand() +``` + +
+
+ +## Command Attributes + +How can you add cooldowns, set aliases, and change the name of help commands? Command attributes can +help you do all of that, and more! + +```python title="Help Command Attributes" +attributes = { + 'name': "help", + 'aliases': ["helpme"], + 'cooldown': commands.CooldownMapping.from_cooldown(3, 5, commands.BucketType.user), +} + +# You need to use CooldownMapping.from_cooldown(rate, per, type) + +bot.help_command = MyHelp(command_attrs=attributes) +``` + +## Error Handling + +When a user attempts to use a command that does not exist, we need to inform the user. +We can do this by overriding the `send_error_message` function. + +```python title="Custom Help Error Example" +class MyHelp(commands.HelpCommand): + async def send_error_message(self, error): + embed = discord.Embed(title="Error", description=error, color=discord.Color.red()) + channel = self.get_destination() + + await channel.send(embed=embed) +``` + + + + !help update_pycord + + + + Command 'update_pycord' not found. + + + + +## Credits + +Most of the content from this guide is from +[InterStella0's walkthrough guide on subclassing HelpCommand](https://gist.github.com/InterStella0/b78488fb28cadf279dfd3164b9f0cf96). +Thanks to InterStella0 for making this guide amazing. + +:::info Related Topics + +- [Subclassing Bots](../../Popular-Topics/subclassing-bots) +- [Prefixed Commands](./prefixed-commands) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx b/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx new file mode 100644 index 00000000..b8f567fd --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx @@ -0,0 +1,324 @@ +--- +title: Prefixed Commands +description: Learn how to use the commands extension for Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Before Discord added slash commands, all bots had prefixed commands. A user would type the bot's prefix +followed by a word or phrase to invoke a command, such as `?help` or `!help`. +However, this prefixed commands system isn't native to Discord! Developers made use of an `on_message` +event to check if the message began with a certain character, then invoke the command. Every time a +message was sent, the bot would see the message and check for its "prefix" + +The syntax becomes a little more complicated when you want to have multiple commands. There are several +disadvantages to this system. This is where the commands extension comes in. `ext.commands` has +various advantages, such as: + +- Simpler syntax +- Easier to use +- Easier to parse user input +- Comes with built-in help commands +- Comes with a built-in system for categorizing commands + + + + +```python title="Prefixed Commands with Events" +import discord + +client = discord.Client() + +@client.event +async def on_message(message): + if message.content.startswith("!ping"): + await message.channel.send("Pong!") + + elif message.content.startswith("!announce"): + if len(message.content.split(" ")) < 3: + await message.channel.send("You need to specify a title and a message. Correct usage: `!announce Hello Hello everyone!`") + return + + msg = message.content.split(" ", 2) + title = msg[1] + content = msg[2] + + await message.channel.send("**{}**\n{}".format(title, content)) + + elif message.content.startswith("!"): + await message.channel.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !help + + + Unknown Command. + +
+ +
+ + +```python title="The Commands Extension" +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix="!", intents=intents) + +@bot.command() +async def ping(ctx): + await ctx.send("Pong!") + +@bot.command() +async def announce(ctx, title, *, message): + await ctx.send("**{}**\n{}".format(title, message)) + +@bot.event +async def on_command_error(ctx, error): + if isinstance(error, commands.CommandNotFound): + await ctx.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !pycord + + + Unknown command. + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+ !announce +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The commands extension has many more uses. This example only showcases the basic features mentioned +in the previous example. Other things you can do with the commands extension include using a different +built-in help command and creating your own. The following tutorials showcase these. + +::: + +
+
+ +## Syntax + +Before we check out the syntax, let's take a look at the bot classes. + +> `discord.Client` - Contains only events. +> +> `discord.Bot` - Subclasses `discord.Client`, adds commands. +> +> `discord.ext.commands.Bot` - Subclasses `discord.Bot`, adds prefixed commands, cogs, and more. + +This means that `discord.ext.commands.Bot` has both slash commands and prefixed commands, as well as +events, cogs and more. + +Now let's look at the syntax. + +```python title="A Simple Prefixed Bot" +import discord +from discord.ext import commands # Import the commands extension +# discord.ext.commands are not the same as discord.commands! + +intents = discord.Intents.default() #Defining intents +intents.message_content = True # Adding the message_content intent so that the bot can read user messages + +bot = commands.Bot(command_prefix="!", intents=intents) # You can change the command prefix to whatever you want. + +@bot.command() # This is the decorator we use to create a prefixed command. +async def ping(ctx): # This is the function we will use to create the command. + await ctx.send("Pong!") # This is the response the bot will send. + + +bot.run("token") # Run the bot with your token. +``` + + + + !ping + + + Pong! + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The help command is a built-in command and is enabled by default. You will learn more about it in the +following guides. + +::: + +## Parameters + +Prefixed commands can take parameters, just like slash commands. You can specify the parameters in +the function itself. + +```python title="Parameters Example 1" +@bot.command() +async def echo(ctx, *, message): + await ctx.send(message) +``` + +`ctx` is the context of the message. `*` means that the parameter can be any number of words. `message` +is the parameter. If you had not passed `*`, `message` would only have been one word. + +For example, if a user had used `!echo hello world`, `message` would have been `hello`. Since we +passed `*`, `message` is `hello world`, or the rest of the message. + +We can pass multiple parameters too! + +```python title="Parameters Example 2" +@bot.command() +async def echo(ctx, channel:discord.TextChannel, title, *, message): + await channel.send("**{}**\n{}".format(title, message)) +``` + +In the example above, `channel` is a parameter that is of type `discord.TextChannel`. When you +specify the type of the parameter, Pycord will automatically try to convert the parameter to that type. +That is why you can use `channel.send` directly without needing to convert it first. + +We also have a new parameter, `title`. This does not have a type, so it will be a string. `*` means +that the rest of the message belongs to the next parameter, in this case, `message`. + +When a user types `!echo #general Greetings! Hello World!`, `channel` will be the text channel +`#general`, `title` will be `Greetings!` and `message` will be `Hello World!`. + +Let's take an example where the user passes `!echo #general Holiday Greetings! Greetings to you all!`. +Here, the user wants the title to be "Holiday Greetings!" and the message to be "Greetings to you all!". +However, since Pycord parses the message at whitespaces, the title will end up being "Holiday" and the +message "Greetings! Greetings to you all!". The user can prevent this by typing `!echo "Holiday +Greetings!" Greetings to you all!`. + + + + + + !echo #general Holiday Greetings! Greetings to you all! + + + Holiday +
+ Greetings! Greetings to you all! +
+ + !echo #general "Holiday Greetings!" Greetings to you all! + + + Holiday Greetings! +
+ Greetings to you all! +
+
+ +Let's check out another example for parameters and parameter types. + +```python title="Parameters Example 3" +import random + +@bot.command() +async def gtn(ctx, guess:int): + number = random.randint(1, 10) + if guess == number: + await ctx.send("You guessed it!") + else: + await ctx.send("Nope! Better luck next time :)") +``` + +If you had not specified the type of the parameter, it would have been a string. And since `"5"` is not +the same as `5` in python, the bot would have responded with "Nope! Better luck next time :)". +Even if you do not specify the type of the parameter, you can still convert it later on, in this case, +with `int(guess)`. + +:::info Related Topics + +- [Command Groups](groups) +- [Rules and Common Practices](../../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json new file mode 100644 index 00000000..baeba701 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Pages", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx b/i18n/it/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx new file mode 100644 index 00000000..be90b035 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx @@ -0,0 +1,168 @@ +--- +title: Paginator Basics +--- + +# Paginator Basics + +## [Page](https://docs.pycord.dev/en/stable/ext/pages/index.html#page) + +This class contains two attributes: `content` and `embeds`, which correspond to the attributes of the same name on the +`discord.Message` class. +To create a new Page, use the following syntax: + +```py +import discord +page = Page(content="My Page Content", embeds=[discord.Embed(title="My First Embed Title")]) +``` + +## [PageGroup](https://docs.pycord.dev/en/stable/ext/pages/index.html#pagegroup) + +This class represents a group of pages. It uses most of the same parameters as `Paginator`, which allows each +`PageGroup` to effectively have its own settings and behaviours. + +## [Paginator](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator) + +This is the main class for `ext.pages`, and is used to control most of the functionality of the extension. + +In its most basic form, with no arguments provided (default values listed below), a paginator can be created like so: + +```py title="Paginator Example" +import discord +from discord.ext.pages import Paginator, Page + +my_pages = [ + Page( + content="This is my first page. It has a list of embeds and message content.", + embeds=[ + discord.Embed(title="My First Embed Title"), + discord.Embed(title="My Second Embed Title"), + ], + ), + Page( + content="This is my second page. It only has message content.", + ), + Page( + embeds=[ + discord.Embed( + title="This is my third page.", + description="It has no message content, and one embed.", + ) + ], + ), +] +paginator = Paginator(pages=my_pages) +``` + +The only required parameter for `Paginator` is the `pages` parameter, which is usually a list of `Page` objects. + +You can also pass in a list of `PageGroup` objects, a list of strings, a list of embeds, or a list of lists of embeds. + +Once the `Paginator` instance is created, you can call either +[`Paginator.send()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.send) +or [`Paginator.respond()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.respond) +to send a message or response with the paginator's contents. + +#### Depending on what's being passed to the `pages` parameter, the behaviour of the paginator may differ: + +- Passing a list of `PageGroup` objects will essentially treat each `PageGroup` as its own Paginator, with most + `Paginator` attributes able to be set independently for each `PageGroup`. + \- Each `PageGroup` accepts its own `pages` parameter, which inherits the same behaviour as the `pages` parameter + of `Paginator`, except it cannot contain other `PageGroup` objects. +- If a page is a `Page` object, this will allow you to specify both the `discord.Message.content` and + `discord.Message.embeds` attributes for a page. + \- **This is the preferred method of defining a page.** +- If a page is a string, this will be used for the `discord.Message.content` attribute. This type of page cannot have + any embeds. +- If a page is a list of embeds, this will be used for the `discord.Message.embeds` attribute. This type of page + cannot have any message content. +- If a page is a list of lists of embeds, each parent list item will create a page containing all embeds from its + child list. This type of page cannot have any message content. + +#### Parameters for the `Paginator` class which have default values: + +- `show_disabled` **:** `True` + - Show buttons that are disabled (i.e. can't be clicked) +- `author_check` **:** `True` + - Only the author can interact with the paginator. +- `timeout` **:** `180` _(seconds)_ + - The paginator will time out and become inactive after this many seconds. +- `disable_on_timeout` **:** `True` + - If the paginator times out, it will be automatically disabled and all buttons will be unusable. +- `use_default_buttons` **:** `True` + - Use the default set of 4 buttons and a page indicator. +- `show_indicator` **:** `True` + - When using the default buttons, shows a middle 5th button with the current/total page numbers. + +**For other parameters that can be set on initialization, please check the +[API Reference](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator)** + +## [PaginatorButton](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatorbutton) + +This class represents a button used to navigate between the pages of a paginator. It's also used to create the page +indicator. + +When creating your own custom buttons, you can either use this class directly or subclass it to add any additional +functionality you may need. + +To add custom buttons to the paginator instead of the default navigation buttons, you have two options to do so: + +1. **Using the `custom_buttons` parameter of `Paginator`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + buttons = [ + PaginatorButton("first", label="<<-", style=discord.ButtonStyle.green), + PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), + PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True), + PaginatorButton("next", label="->", style=discord.ButtonStyle.green), + PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), + ] + paginator = Paginator( + pages=["Page 1", "Page 2", "Page 3"], + show_indicator=True, + use_default_buttons=False, + custom_buttons=buttons, + ) + ``` +2. **Using `Paginator.add_button()`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"], use_default_buttons=False) + paginator.add_button(PaginatorButton("prev", label="<", style=discord.ButtonStyle.green)) + paginator.add_button(PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True)) + paginator.add_button(PaginatorButton("next", label=">", style=discord.ButtonStyle.green)) + ``` + +If you want to use the default navigation buttons, but not all of them, you can also use `Paginator.remove_button()` to +selectively remove them: + +```py +from discord.ext.pages import Paginator + +paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"]) +paginator.remove_button("first") +paginator.remove_button("last") +``` + +## [PaginatorMenu](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatormenu) + +This class represents the `discord.Select` menu used to navigate between `PageGroup` instances. In most situations, you +will not need to interact with this class directly. + +If you do subclass it, you'll likely want to call `super()` in your `__init__` method to ensure that the `PageGroup` +navigation functionality is retained. + +## Usage Examples + +For a comprehensive list of examples showing all `Paginator` functionality, please see the +[example in cog form](https://github.com/Pycord-Development/pycord/blob/master/examples/views/paginator.py) in the repo. + +## Support and Feedback + +If you have any questions, suggestions, or feedback for `ext.pages`, please join the +[Discord server](https://discord.gg/pycord). diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx b/i18n/it/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx new file mode 100644 index 00000000..b8d68925 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx @@ -0,0 +1,20 @@ +--- +title: Paginator FAQ +--- + +# Paginator FAQ + +- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** + - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. + - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. + +- **How can the bot send a paginator to a different destination than where it was invoked?** + - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. + - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. + - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. + +- **How can I change the paginator's behavior without re-creating and re-sending it?** + - Use the `Paginator.update()` method. + +- **How can I make the bot actually do something with the contents of a page?** + - Use the (upcoming) `Paginator.page_action()` method. diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json new file mode 100644 index 00000000..36dfb009 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Tasks" +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx b/i18n/it/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx new file mode 100644 index 00000000..848f6066 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx @@ -0,0 +1,216 @@ +--- +title: Tasks +--- + +## Concept + +So you want to run a background task running at some specified interval? Thankfully, that's a common thing to do, whether you're working with some API or handling some background logic don't worry, the Pycord tasks extension is here to make life easier for you! + +With the tasks extension, you can make background tasks without worrying about the asyncio hell and mind bogglers like "what if my internet dies" and "how do I handle reconnecting" with the added benefit of a lot of useful additions that are one line of code away! + +### Example Usage + +```py +import discord +from discord.ext import tasks + +bot = discord.Bot() + +@bot.event +async def on_ready(): + very_useful_task.start() + +@tasks.loop(seconds=5) +async def very_useful_task(): + print('doing very useful stuff.') + +bot.run("TOKEN") +``` + +If you do run this code in your terminal you should see something like this after about 15 seconds: + +``` +doing very useful stuff. +doing very useful stuff. +doing very useful stuff. +``` + +For a more useful example here's a task in a cog context ripped straight from the [docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#recipes): + +```py +from discord.ext import tasks, commands + +class MyCog(commands.Cog): + def __init__(self): + self.index = 0 + self.printer.start() + + def cog_unload(self): + self.printer.cancel() + + @tasks.loop(seconds=5) + async def printer(self): + print(self.index) + self.index += 1 +``` + +As you'd expect this will increment a number and print it out every 5 seconds like so: + +```sh +0 +# 5 seconds later +1 +# 5 more seconds later +2 +# ... +``` + +## [Tasks](https://docs.pycord.dev/en/stable/ext/tasks/index.html) + +Now let's get into the nitty-gritty of tasks. + +As you've seen tasks can work in both outer scope and class contexts and the handle is roughly the same, you define a task using the `tasks.loop` decorator and use the `start` method to start it, the difference is you add the `self` argument when in a class context so since most people have all their bot's code in Cogs all the following code blocks will be in a Cog context to make it easy to copy it then apply whatever modifications you might need! + +### [Creating a task](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop) + +A look at `discord.ext.tasks.loop`'s definition in the documentation reveals that: + +1. As you've seen before it expects the time between each execution, that however doesn't have to be in seconds as + there are `seconds`, `minutes` and `hours` parameters to make it easier for us, they can also be floats in case you want + ultra-precision. +2. You can also pass in a `datetime.time` object or a sequence of them in the `time` parameter which will make it run + at the specified time(s). +3. You can pass in how many times a loop runs before it stops by passing in the `count` parameter, you can use `None` + to make it run forever which is also the default. +4. The loop function **_must_** be a coroutine. + +These are all really useful, and they aren't the only parameters so if you want to know more about them check out the +[docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop)! + +### Attributes + +A task has the following attributes: + +- `current_loop`: The current loop the task is on. +- `hours`, `minutes`, `seconds`: attributes that represent the time between each execution. +- `time`: A list of datetime.time objects that represent the times the task will run, returns `None` if no datetime + objects were passed. +- `next_iteration`: A `datetime.datetime` object that represents the next time the next iteration of the task will + run, can return `None` if the task stopped running. + +These attributes serve as a really powerful asset to get info about your loop. + +### Example + +Now let's create a cog that handles a leaderboard we have in our bot using Tasks then explain what we did after that and +also provide a refresher of how slash commands groups work in cogs. + +For the sake of this example let's pretend that we have a leaderboard module that does all the leaderboard handling for +us and that computing the leaderboard is very expensive computationally wise, so we want to store one version of it that +gets regularly updated instead of generating it every time someone calls the `/leaderboard view` command. + +```py +from discord.ext import tasks, commands +from discord.commands import SlashCommandGroup, CommandPermissions + +from leaderboard import * # Mock leaderboard module. + +class LeaderboardCog(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.update_leaderboard.start() + self.leaderboard_embed = generate_leaderboard_embed() + + leaderboard = SlashCommandGroup(name='leaderboard', description='Leaderboard commands.') + + @tasks.loop(minutes=10) + async def update_leaderboard(self): + print('Updating leaderboard...') + await update_leaderboard() + self.leaderboard_embed = generate_leaderboard_embed() + + @update_leaderboard.before_loop + async def before_update_leaderboard(self): + await self.bot.wait_until_ready() + print("About to start updating leaderboard.") + + @update_leaderboard.after_loop + async def after_update_leaderboard(self): + leaderboard_cleanup() + print("Stopped updating leaderboard.") + + @update_leaderboard.error + async def update_leaderboard_error(self, error): + print(f"Oh no, an error occurred while updating the leaderboard. Error: {error}") + + @leaderboard.command() + async def view(self, ctx): + await ctx.respond(embed=self.leaderboard_embed) + + @leaderboard.command() + async def update_info(self, ctx): + await ctx.respond(f"""***Leaderboard Info***\n + Last update: {(600 - self.update_leaderboard.next_iteration.timestamp())//60} minutes ago.\n + Next update: in {self.update_leaderboard.next_iteration.timestamp() // 60} minutes.\n + Time between loops: {self.update_leaderboard.minutes} minutes.\n + Times updated this session: {self.update_leaderboard.current_loop}. + Running? {self.update_leaderboard.is_running()} + Failed? {self.update_leaderboard.failed()}""", ephemeral=True) + + # Now for the owner only commands: + + leaderboard_config = SlashCommandGroup(name="leaderboard_config", description="Leaderboard configuration commands", permission=[CommandPermissions("owner", 2, True)]) + + @leaderboard_config.command() + async def set_time_between_updates(self, ctx, minutes: int): + self.update_leaderboard.change_interval(minutes=minutes) + await ctx.respond(f"Set time between updates to {minutes} minutes.") + + @leaderboard_config.command() + async def stop(self, ctx): + self.update_leaderboard.stop() + await ctx.respond("Stopped the leaderboard update.") + + @leaderboard_config.command() + async def restart(self, ctx): + self.update_leaderboard.restart() + await ctx.respond("Restarted the leaderboard update.") + +def setup(bot): + bot.add_cog(LeaderboardCog(bot)) +``` + +Phew, that was quite a bit of code. + +Now to explain what's going on: + +First things first we create a cog and in its `__init__` function we start the `update_leaderboard` task and generate +the first instance of our leaderboard's embed. + +After that, we define the `update_leaderboard` task using the `loop` decorator, and we make it run every ten minutes by +passing 10 to the `minutes` parameter. + +Then that we define the `before_update_leaderboard` task using the `before_loop` decorator, and we make it wait until the +bot is ready before starting the task. + +Next up we define the `after_update_leaderboard` task using the `after_loop` decorator, and we make it clean up the +leaderboard when the loop finally stops running. + +Then we define the `update_leaderboard_error` task using the `error` decorator, and we make it print any errors that may +occur while we update our leaderboard to the console. + +Then we get into the fun stuff, we create a slash command group using the `SlashCommandGroup` class and name it +`leaderboard`, we then create the `view` sub-command which sends the embed generated when the leaderboard is updated and +`update_info` which shows a lot of data about the task using some attributes and functions available to us. + +We also create a slash command group called `leaderboard_config` which is only available to the owner of the bot. + +Then we create the `set_time_between_updates` sub-command which takes in the time in minutes and changes the time +between updates of the leaderboard using the `change_interval` method, the `stop` sub-command which stops the task using +the `stop` method and `restart` which restarts the task using the `restart` method. + +Finally, we add the `LeaderboardCog` cog to the bot, and we're done! + +I'd highly recommend you check the tasks extension +[documentation](https://docs.pycord.dev/en/stable/ext/tasks/index.html) for more info on how to use them and what other +functions they have. diff --git a/i18n/it/docusaurus-plugin-content-docs/current/getting-started/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/getting-started/_category_.json new file mode 100644 index 00000000..9d6255f5 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 3, + "label": "Getting Started", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx b/i18n/it/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx new file mode 100644 index 00000000..864206a6 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx @@ -0,0 +1,262 @@ +--- +title: Creating Your First Bot +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +Excited to create your first bot? Once you [install Pycord](../installation.mdx), you can start right +away! + +## Creating the Bot Application + +Just like how you need to sign up to use Discord, your bot also has to be signed up. To do this, +you should: + +1. Go to the [Discord Developer Portal](https://discord.com/developers/applications) and click + on . +2. Give your bot a name, and click . +3. Now, you should see a page like this. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdW3OQnwUhacopqSWw%2F-Mjd_-mxrJCrzmaXrAg8%2Fimage.png?alt=media&token=b8e2ae6c-2290-4d37-ad7c-eb412f3fb00e) +4. Click on the tab on the left side of the screen. +5. Click on . +6. You can give it a name, change the Avatar, etc. + +## Inviting the bot + +Now, lets get the bot added to some servers. Go to the tab +in the left pane and select `bot` and `applications.commands` as scopes. + +You may want your bot to have application commands, which is what the `application.commands` scope +allows your bot to make. + +Next, you want to choose what permissions the bot will have and select them. For now, you can just +give your bot the `administrator` permission, which gives your bot every permission. Once you select +your bot's permissions, click on to get the bot invite link. + +:::tip + +When your bot is all ready to go, make sure that administrator permissions aren't selected unless +your bot truly needs them. Try selecting only permissions the bot will need. For testing, +Administrator permissions are fine. + +::: + +![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-Mk6tNY3LfDkjd6pqdpL%2F-Mk6tkdpddEWoa2jczZk%2Fimage.png?alt=media&token=52c8a29f-a798-48f8-a8c7-4ecca2681f79) + +You can use this link to invite the bot. + +## Tokens + +Now that you have an account for your bot, you need to log in. To log in, we need the bot's +password. All users and bots have a "token." You may think of this token as a password, as this allows +us to log our bot into Discord. + +Tokens are "snowflakes." Not actual snowflakes, though. Just like how no two snowflakes in real life have the same +pattern, snowflakes in computers are unique things - no two bots have the same token - so a token is +considered a snowflake. A Discord user ID is also a snowflake. + +Now, lets get your bot's token. To do this, you want to: + +1. Go back to the tab. +2. Click on the button in the "Token" section. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdbU12JISJorAZxrKH%2F-MjdbpUsapzb5n15Po5P%2Fimage.png?alt=media&token=118e259f-940a-4f6c-b3a3-c29f3a54100d) + +Now, you have your bot's token copied to your clipboard. + +:::danger + +Do not, under any circumstances, give your token to anyone. Even if you are contacted by someone +claiming to be Discord staff, do not give them your bot's token. They are lying to you to try and +gain access to your bot. If an unauthorized user gains access to your bot's token, they can access +your bot and use it in malicious ways. + +Never push your token to GitHub or include it in your code. One way to prevent your token from +getting leaked is to store it in `.env` files. + +::: + +### Protecting Tokens + +#### Using dotenv + +You can store your tokens in `.env` files. This is a simple way to store sensitive information. + +1. Create a file with the name `.env` (only the extension, with a dot/period at the start and without a name before it). +2. Define the token in the `.env` file (replace the example value with your token). + ```env title=".env" + TOKEN = NzkyNzE1NDU0MTk2MDg4ODQy.X-hvzA.Ovy4MCQywSkoMRRclStW4xAYK7I + ``` +3. Install [`python-dotenv`](https://pypi.org/project/python-dotenv/). + ```bash + python -m pip install python-dotenv + ``` +4. Load the token from the `.env` file. + ```python + import dotenv + dotenv.load_dotenv() + token = str(os.getenv("TOKEN")) + ``` +5. Pass your token as parameter when running the bot. + ```python + client.run(token) + ``` + +:::tip + +If you are using Git to track your bot's changes, you should create a file called `.gitignore` and add +`.env` to it. This stops your `.env` file from getting tracked along with the rest of your code, and +will not be pushed to a remote Git repository. As a consequence, it will stay secure on your local machine. + +::: + +## Coding the Basics + +Here's an example of code you'll write with Pycord: + +```py +import discord +import os # default module +from dotenv import load_dotenv + +load_dotenv() # load all the variables from the env file +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") + +bot.run(os.getenv('TOKEN')) # run the bot with the token +``` + + + +
+ + hello + +
+ Hey! +
+
+
+ +Let's go through the code. First, the imports. + +```py +import discord +import os +from dotenv import load_dotenv +``` + +In the first line, `import discord`, we import Pycord. Although you install Pycord with `pip install py-cord`, you +import it with `import discord`. This is so it's as easy as possible when switching from Discord.py to Pycord. + +We then import `os` and `dotenv`. `os` is a default module that we will use to get the token from the env file. `dotenv` +is a module that we will use to load the env file. You installed this with `pip install python-dotenv`. + +Next, we load the env file with `load_dotenv()`. + +```py +bot = discord.Bot() +``` + +In this line, we create a new instance of [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). +In this object, we can pass various parameters for configuration purposes, such as `owner_ids` +and [`intents`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```py +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") +``` + +We use the [`event`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) decorator to override +the [`on_ready`](https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready) function to define an +event that is automatically called when the bot is ready to use. + +```py +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") +``` + +Here, we use the [`slash_command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.slash_command) +decorator to define a slash command. We specify the `name` and `description` arguments. If not +specified, the name of the slash command would be the function name and the command description would +be empty. + +Optional: We type-hint the context parameter (`ctx`) as [`discord.ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext). In modern IDEs, type-hinting allows access to autocompletion and docstrings. You can read more about type-hinting [here](https://docs.python.org/3/library/typing.html). + +Finally, you want to run the bot using the token specified in the `.env` file. + +Now you have finished creating your first Pycord bot! What we have shown you is just the basic structure +of a bot. You can do a lot more with Python and Pycord knowledge, as well as your imagination! Pycord +will not limit your bot's abilities. + +:::note + +The part where we load the token from the environmental variables is not required. You may use another way to keep your token secure, or, although not recommended, simply specify the token normally as a string, as shown below. + +
+A Basic Bot without securing the token +
+ +```py +import discord + +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.send("Hey!") + +bot.run("TOKEN") +``` + +
+
+ +::: + +## FAQ + +### How do I make prefixed commands? + +Prefixed commands are an older method of creating bot commands that listen for messages and replies +if the message starts with a certain character. You can read [this page](../extensions/commands/prefixed-commands.mdx) +to learn more about prefixed commands. + +### How do I setup modules/cogs? + +[Cogs](../popular-topics/cogs) are a great way to organize your commands by putting them into +groups called cogs. Cogs are separate files that your bot loads to get the commands inside. +You can read more about cogs, as well as learn how to use them and their benefits, +[here](../popular-topics/cogs). + +### How do I add components, such as buttons and dropdown menus, to my bot? + +Pycord makes it very easy to use Message Commands with your bot by using the `discord.ui` module. +To learn more, read about Message Commands in our [interactions directory](../interactions). + +:::info Related Topics + +- [Prefixed Commands](../extensions/commands/prefixed-commands) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx b/i18n/it/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx new file mode 100644 index 00000000..2a68677b --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx @@ -0,0 +1,109 @@ +--- +title: Hosting Your Pycord Bot +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Hosting Your Pycord Bot + +If you're completely new to this, you might have thought something along the lines of "Yay! I got my +bot working," after following our [Creating your First Bot](creating-your-first-bot) guide, only +to close your IDE or shut down your computer to find your bot offline. + +The reason for this is that programs have to be hosted somewhere, meaning some machine somewhere has +to constantly run your bot. There are tons of hosting services that can help you host your bot for +little to no cost. + +## Can I get a Clear Explanation? + +Sure thing. When you run your bot, it first makes a connection to Discord's API. Once that's done, +Pycord sends "heartbeats" to Discord. "heartbeats" are small packets sent at a set interval telling +Discord that your bot is indeed still alive. If Discord doesn't receive a heartbeat after a certain +amount of time, your bot is pronounced dead and buried in the graveyard (not really). It is, though, +taken offline and its connection with Discord is terminated. + +Once you close the terminal that you've run your program on, the program is no longer running, and +the bot stops sending heartbeats and can no longer process commands. This is why you have to constantly +keep the process running. + +This goes for all programs, in a different nature. If the code isn't compiled/built/assembled/interpreted, +it can't be running. + +## What is a Host? + +A host is a server or container for running code offered by a **hosting provider.** There are a lot +of hosting providers, such as bigger ones like Amazon Web Services (AWS) and Google Cloud, and smaller +ones like GalaxyGate and DigitalOcean. + +There are three types of hosts. + + + + Shared hosting is a type of hosting where multiple people share one VPS. Getting a spot on + a shared host is usually cheap, sometimes even free. Shared hosts do not give you a lot of + resources, from less than a gigabyte of RAM (usually 512MB on free hosts) and half of a CPU + with very little storage. Shared hosting is usually used for website hosting and is not + recommended for hosting a Discord bot. + + + A virtual private server (VPS) is a virtual computer (virtual machine) that is rented out to + customers. Most people use a VPS for hosting their projects such as Discord bots. You can get + anywhere from less than a gigabyte of RAM and a less powerful CPU to just under one hundred + gigabytes of RAM, a (or multiple) powerful CPU(s), and a fair amount of storage. A VPS is the + best choice for most users and can be fairly cheap. + + + A dedicated host is a physical computer. You can buy these yourself or rent one from a hosting + provider. Dedicated hosts are often very expensive, but are also very powerful, having a + few hundred gigabytes of RAM and a few very powerful CPUs, along with a good amount of storage. + Dedicated hosts are usually used for very large projects and are overkill for something like + a Discord bot. + + +
+ +:::danger + +Make sure you choose a hosting provider you trust. Also make +sure the hosting provider you're looking at has good reviews on public forums. Googling along the +lines of "[host] review" should do the trick. A provider you don't trust can compromise your token. + +::: + +Most hosting providers rent their services to you for a monthly or yearly fee. These can be anywhere +from a few dollars to hundreds or thousands of dollars. + +## How to Host Your Bot + +Once you rent or buy a VPS, you can get to work. Most hosting providers allow you to choose from a +wide range of operating systems, most allow you to choose one but some allow you to choose +multiple. Once that's ready, you have to SSH into the system. We won't get into SSH here, but you can +read [this article from DigitalOcean](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys). +You can also use VNC, which is remote desktop software. If you are using an OS that does not have a +GUI, and is only a command line (a "server" OS), such as Ubuntu Server or most Linux Server Operating Servers, you will most +likely use SSH. If you are using an OS that has a GUI, such as Windows Server, you will most likely use VNC. + +Once you've decided on your operating system, you'll want to set it up and install Python. Once that's +done, you can copy your bot's files to your remote system, install the required packages, and run +the bot. + +:::warning + +If you are using SSH to run the file, your bot will not stay running. This is because the file is +only told to run during your session. You can use a command like [nohup](https://en.wikipedia.org/wiki/Nohup) +to make sure your file stays running after you disconnect. + +::: + +Now your bot is hosted, but that doesn't mean it can't go offline. If your bot encounters an error, +it can often go offline or stop its process. For this, make sure you have proper error handling. +Also be sure to pay attention to your hosting provider's updates or news, as they usually notify +users of when they plan on doing maintenance to their servers, making their services unavailable for +a short time. + +:::info Related Topics + +- [Creating Your First Bot](creating-your-first-bot) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx b/i18n/it/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx new file mode 100644 index 00000000..ee6b9417 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx @@ -0,0 +1,379 @@ +--- +title: More Features +description: More features to make your bot cool and snazzy. +--- + +import { + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, + DiscordEmbedField, + DiscordEmbedFields, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +So, you just created your first Pycord bot! Now, let's add some more features to it. This will include adding event handlers, waiting for user response, styling the messages, and more. + +## Events + +### Event Handlers + +Events in Discord are a way to listen for certain actions. For example, if you want to know when a user joins your server, so you could send a welcome message, you can use the `on_member_join` event. + +First, you need to ask Discord to send you events. This is done via "Intents". Read up the [Intents](../Popular-Topics/intents) page for more information. + +Once you understand what intents are, you can enable the events you need, or just use the default ones with `discord.Intents.all()`. + +Now that that's done, let's add an event handler for when a user joins the server. We will use the [`on_member_join` event](https://docs.pycord.dev/en/stable/api/events.html#discord.on_member_join). We will send a private message to the user welcoming them to the server. + +```python +@bot.event +async def on_member_join(member): + await member.send( + f'Welcome to the server, {member.mention}! Enjoy your stay here.' + ) +``` + +We use the [`discord.Bot.event` decorator](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) to add the event handler. + +The `on_member_join` event is called when a user joins the server. The `member` parameter is the user that joined. Different events have different names and parameters. You can find all of them [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +So, that's how you add event handlers! + +### Waiting for User Response + +Let's say you want to create a Guess-the-Number game (where the user has to guess a number between 1-10). You need to send a message to a user and wait for them to respond. You can do this with the [`wait_for`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.wait_for) method. + +```python +@bot.command() +async def gtn(ctx): + """A Slash Command to play a Guess-the-Number game.""" + + await ctx.respond('Guess a number between 1 and 10.') + guess = await bot.wait_for('message', check=lambda message: message.author == ctx.author) + + if int(guess.content) == 5: + await ctx.send('You guessed it!') + else: + await ctx.send('Nope, try again.') +``` + +`wait_for` takes one argument, which is the event type. The event type is the name of the event you want to wait for. In this case, it's `message`. It could also be `reaction` to wait for a reaction to be added. + +We pass a keyword argument to `wait_for` called `check`. The function may look complicated if you're a beginner. We pass a `lambda` function, which simplifies the code a bit. + +The lambda function takes one parameter, `message`. When Pycord receives a message, it passes it to the `check` function. If the function returns `True`, the message is returned. If the function returns `False`, the message is ignored and the bot waits for another message. + +Here, we check if the message is from the user that sent the command. We simply use `message.author == ctx.author`. This will check if the author of the message was the person who invoked the command. + +## Styling Messages + +### Embeds + +Embeds are a Discord feature that allows applications to format their messages in cool embedded format, +enabling your bot to lay out messages with a lot of text into neat fields. + + + + + The Pycord Guide is a detailed guide that explains how to use Pycord and all of its features. + + + The Getting Started section explains how you can get a brand new bot created and running from scratch. + + + Interactions with Pycord + + + Pycord's various Extensions + + + Other Popular Topics + + + We have so much more! Just explore, and you will find everything you need. If you want another page added, open an issue on the GitHub. + + + Created with 💖 by the Pycord Team & Contributors + + + + +
+ +Creating embeds is simple! Just create an instance of [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) and edit it to your liking. Once you're done, send it! + +```python +import discord + +bot = discord.Bot() + +@bot.command() +async def hello(ctx): + embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from + ) + embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") + + embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) + embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) + embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) + + embed.set_footer(text="Footer! No markdown here.") # footers can have icons too + embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") + embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") + embed.set_image(url="https://example.com/link-to-my-banner.png") + + await ctx.respond("Hello! Here's a cool embed.", embed=embed) # Send the embed with some text + +bot.run("TOKEN") +``` + + + +
+ hello +
+ Hello! Here's a cool embed. + + Embeds are super easy, barely an inconvenience. + + + A really nice field with some information. The description as well as the fields support markdown! + + Inline Field 1 + Inline Field 2 + Inline Field 3 + + Footer! No markdown here. + +
+
+ +
+ +This simple command sends replies to a [slash command](../interactions/application-commands/slash-commands) with an embed. +Let's break it down: + +```py +embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), + ) +``` + +This command creates an embed. We use the [`Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) +class to create an embed object with the title "My Amazing Embed", the description "Embeds are super easy, barely an inconvenience.", and the color `blurple`, Discord's main theme color. + +[discord.Colour](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Colour) is a class full of [classmethods](https://docs.python.org/3/library/functions.html#classmethod) +that return color values. While the official, documented name of this is `discord.Colour`, `discord.Color` +works as well. + +```py +embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") +embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) +embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) +embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) +``` + +This small section shows off embed fields. You can add fields to embeds with the [`add_field` method](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.add_field) +of the [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) class. These consist of three +keyword arguments: `title`, `value`, and `inline`. `title` and `value` are both required arguments, which inline defaults to `False` if it's not defined. The `inline` argument specifies whether space will be divided among the inline fields. There could be a mix of fields where inline has different values too. + +```py +embed.set_footer(text="Footer! No markdown here.") # footers can have icons too +embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") +embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") +embed.set_image(url="https://example.com/link-to-my-banner.png") +``` + +In this section, we're adding unique items to the embed. These items are: + +- Footer - With the [`set_footer()`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_footer) + method, you can set a small footer that holds a message. This has `text` and `icon_url` kwargs. +- Author - With the [`set_author`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_author) + method, you can set an author for the embed. This is a small text field at the top of the embed. This + includes `name`, `url` and `icon_url` kwargs. +- Thumbnail - With the [`set_thumbnail`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_thumbnail) + method, you can set a small image to reside at the top-right of the embed. This has a single `url` kwarg. +- Image - With the [`set_image`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_image) + method, you can set an image to sit at the bottom of an embed. This has a single `url` kwarg. + +There are a lot more methods and attributes you can use to configure embeds. Here, we just covered the basics. Also, remember that all of these values are not necessary in an embed. An embed may only contain a few of these. For example, only a description, a title and a description, and so on. + +### Markdown + +Markdown is a type of markup language that's limited in terms of formatting yet simple. Discord allows +for a watered-down version of markdown to be in their messages. + +#### Text Markdown + +Text formatting can be used in messages and in most embed parts, +as explained in the dedicated section below. + + + + + + + + + + + + + + + + + + + + +
*italics*__*underlined italics*__
**bold**__**underlined bold**__
***bold italics***__***underlined bold italics***__
__underlined__~~strikethrough~~
+ +#### Code Markdown + +To create a single-line code block without syntax highlight, wrap the text between single backticks. +This code block will only add a dark background to the text. + +``` +`print("Hello world!")` +``` + +To create a multi-line code block without syntax highlight, wrap the text between triple backticks +on first and last line. This type of code block will encase the code inside a box. + +```` +``` +message = "Hello world!" +print(message) +``` +```` + +To create a multi-line block with syntax highlight, add the name of the language you are using right after +the triple backticks on the first line. For example, for Python you can write either "python" or "py". + +```` +```python +message = "Hello world!" +print(message) +``` +```` + +If you want to use syntax highlight for a single line of code, you still have to format it +like a multi-line block but the code must be on a separate line than the triple backticks. + +#### Quote Markdown + +To create a single-line quote block, start the line with `>` followed by a space. + +``` +> This is a single-line quote. +``` + +To create a multi-line quote block, write `>>>` followed by a space. All text +from that point onwards will be included in that quote block. + +``` +>>> This is a +multi-line quote. +``` + +#### Spoiler Markdown + +To hide a spoiler, encase the text between double pipes. The users +will have to click on it before being able to see the text contained in it. + +``` +||spoiler|| +``` + +#### Link Markdown + +Link formatting only works in embeds and messages sent through webhooks, +by using the following syntax: + +``` +[Pycord](https://pycord.dev/) +``` + +Inside the supported elements that have just been mentioned, +the example above will look like this: [`Pycord`](https://pycord.dev/) + +Outside them, the link will still be clickable but the formatting will be ignored, +therefore the example above will look similarly to this: `[Pycord](https://pycord.dev/)` + +#### Embed Markdown + +Adding markdown to your embeds or messages will give your bot the sparkle it needs, +however, markdown is limited inside embeds. Use the following table as a reference +and keep in mind that embed title and filed names will always show in **bold**. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PartTextLink
Embed AuthorNoNo
Embed TitleYesNo
Embed DescriptionYesYes
Field NameYesNo
Field ValueYesYes
Embed FooterNoNo
diff --git a/i18n/it/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx b/i18n/it/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx new file mode 100644 index 00000000..e44b7c49 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx @@ -0,0 +1,184 @@ +--- +title: Rules and Common Practices +description: All about the rules and common practices for coding a Discord bot +--- + +# Rules and Common Practices of Creating a Bot + +When creating almost anything, there's always a certain set of rules to follow or common practices, +such as [PEP8](https://www.python.org/dev/peps/pep-0008/) for Python. This applies to creating bots +with Pycord as well. + +:::note + +Most of these rules and common practices are only applicable for +[verified bots](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting), +but it's good to follow them nonetheless. + +::: + +## Rules + +There are rules for creating bots, and most of these are required by Discord themselves, not us at +Pycord. Not following these rules may get your bot denied for verification. + +### Terms of Service and Privacy Policy + +Starting at some point in time, Discord has made providing a privacy policy with your bot a requirement. +This is so that Discord knows exactly what you are doing with its users' data. + +:::tip +You don't need a lawyer or anyone special to write out a privacy policy for you, nor do you need +it approved by some official entity. Simply writing out how you are going to use Discord user +information neatly is all you need to do. +::: + +Providing a Terms of Service for your bot is optional, though usually a best practice. It tells users +what they can and cannot do with your service, and makes it easier to settle disputes if someone +disagrees with you. + +Read more in Discord's official [Legal Docs](https://discord.com/developers/docs/legal). + +### Developer Policy + +We could list almost every rule about using Discord's API here. _Or_ we could simply link Discord's +Developer Policy to make it easier on us. You can find Discord's Developer Policy +[here](https://discord.com/developers/docs/policy). This outlines what you can and cannot do with +Discord's Developer API. And, don't worry, it's completely readable and understandable. + +## Best Practices + +Now, here's something we _can't_ simply link an article for. We're going to discuss the best practices +of creating a Discord bot with Pycord. + +### Bot Sharding + +To any new or maybe even experienced bot developer, sharding a bot sounds beneficial once you hear +about it. I'm here to tell you that it isn't a good idea to shard your bot. + +_Wait a minute, why would it be an option if it wasn't a good idea?_ It's simple. I lied. Sort of. +I'm not going to go into the details of sharding a bot, so you can read about it on +[this page](../Popular-Topics/sharding). Sharding is the process of taking your bot +and breaking it up into small pieces, so it's easier to perform tasks. This is very useful for large +bots, as it makes them faster and more reliable. Sharding is not a good practice for small bots. + +:::note +Discord will notify you once it is time to shard your bot, and will eventually force you to do so. +::: + +At the very least, wait for one thousand servers to shard your bot. If you shard your bot while it's +small, you'll just be wasting resources and possibly making your bot slower. + +### [Verification](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting) + +Verifying your Discord bot is something every developer would like to achieve. It shows that your bot +is in more than 75 servers. It's generally a good idea to try to get your bot verified as soon as +possible. We're talking at 76 servers soon. This is because Discord can be somewhat slow in terms of +bot verification, so verifying as soon as possible gives them enough time to verify before your bot +reaches the 100 server cap. If a bot is not verified, it cannot grow beyond 100 servers. + +It's also a good idea to only apply for the privileged intents that you need. Applying for intents +your bot doesn't use wastes both your time and Discord's time, as your privileged intent request +will be denied simply because you applied for an intent you didn't need. + +### Subclassing + +While it may take some time, subclassing a bot is very worth it. Once again, this was explained +elsewhere, so I won't go into the details, but I felt it fit here, so I put it here. + +Subclassing a bot makes it more flexible and allows it to do a lot more. Read more about subclassing +bots [here](../Popular-Topics/subclassing-bots) + +### Your Bot's Token + +Your bot is only able to be run for one reason: its token. If you followed the +[guide for creating your first bot](creating-your-first-bot), you should already know a bit about +keeping that token safe. That's exactly what you want to do. + +Sharing your token is never good. If someone evil gets a hold of your token, they can do terrible things, +such as making your bot leave all of its servers, spamming all the members the bot has contact with, +and even manipulating the servers the bot is in, if given the permissions. That's why it's very important +to keep your token safe. To learn how to do so, read [this part](creating-your-first-bot#tokens) of +the Creating Your First Bot guide. + +### Backups + +You always want to back up your bot's data. This includes both its code _and_ its databases. This way, +if something tragic happens, such as your host failing a data migration or you breaking your Raspberry +Pi's SD card that held your bot, you'll still have its precious user data. I have a small program for +my bot that uploads its databases to a remote GitHub repository periodically to not lose any data. +It may be smarter to find a bit more of a reliable way to do so, though. + +Public or private, having a local Git repository connected to a remote one is a good idea for making +almost any application. For a lot of developers, it's like saving your work. If you do this, all of +your bot's code won't be lost if your computer spontaneously combusts, or you smash it to bits from +anger. You can simply grab the backup computer that everyone has lying around, and you're back +in business. + +### Organization and Cleanliness + +It is _extremely_ important to have organized code. This includes commands, objects, functions, +and classes. If you don't have organized code, it will get progressively harder for you to recognize +it, and others won't be able to decipher it. + +Make sure you utilize indents and spaces, as these are very important in making your code readable. + +```py title="Bad Spacing" +class MyClass: + async def add(self,num1,num2): + return num1+num2 + async def sub(self,num1,num2): + return num1-num2 +``` + +```py title="Good Spacing" +class MyClass: + async def add(self, num1, num2): + return num1 + num2 + + async def sub(self, num1, num2): + return num1 - num2 +``` + +See the difference? Now, which one looks more readable? Hopefully, you answered the second example. +Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is a PEP (**Python Enhancement Proposal**) +style guide for Python. It is the style guide that is used by most Python developers and programmers, +providing a universal way to write and read code. + +### Databases + +As your bot grows, you'll inevitably have to store data for your bot. Now, most people would probably just load up some +JSON file on boot into a `dict`, modify it in memory then write to the file. However, JSON files aren't the solution. +When you write to a JSON file, it rewrites the entire file instead of just rewriting the section that changed. It's also +a configuration file format, not a storage file format. + +Instead of using a JSON file or some other related format, you should instead use a database. There are many databases +out there, like MongoDB, SQLite, and PostgreSQL to name a few. + +All of these databases I named do the job well, and which one you use depends on what features you want out of a database. + +<>{/* Maybe clarify these/add more options */} + +#### MongoDB + +MongoDB is a JSON-like format and if you already use JSON files, it shouldn't be too hard to migrate over to. + +#### SQLite + +SQLite is based on SQL, a common relational data model. It's a lightweight, easy-to-use, portable database solution that +works entirely on files. However, if for some reason you cannot read/write to and from a file, and you need to manage +lots of data, SQLite might not be for you. + +While SQLite is a part of the Python Standard Library as the `sqlite3` package, we recommend not using it as it is +synchronous and blocking. You should use an asynchronous alternative, such as [`aiosqlite`](https://pypi.org/project/aiosqlite/). + +#### PostgreSQL + +PostgreSQL is also based on SQL, but it also has more features than SQLite. It's compliant with the SQL standard, +open-source, and extensible. However, it's not that fast or simple compared to SQLite. + +#### MariaDB + +MariaDB is also based on SQL and is a fork of the MySQL project. It's compliant with the SQL standard, it's also open +source and is a complete drop-in replacement for any code with MySQL. You don't even need to change what package you're +using! diff --git a/i18n/it/docusaurus-plugin-content-docs/current/installation.mdx b/i18n/it/docusaurus-plugin-content-docs/current/installation.mdx new file mode 100644 index 00000000..521c69cd --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/installation.mdx @@ -0,0 +1,80 @@ +--- +title: Installation +sidebar_position: 2 +--- + +Before you can start using Pycord, you need to install the library. + +:::note +Python **3.8 or above** is required to use Pycord. +::: + +:::tip +Before you start installing python packages globally, it's recommended you set up a virtual environment. +You can find instructions for that [here](More/virtual-environments). +::: + +## Fresh Installation + +To install Pycord, you can use the following command in your terminal: + +``` +pip install py-cord +``` + +:::tip +Remember that you need to install `py-cord`, not `pycord`. +Also, the `pip` command varies depending on your installation. For example, it might be `python3 -m pip` on macOS/Linux or `py3 -m pip` on some versions of Windows. +::: + +If you need voice support for your bot, you should run: + +``` +pip install "py-cord[voice]" +``` + +## Migration + +### Updating Pycord + +If you are upgrading from a previous version of Pycord, you can use the following command in your terminal to upgrade to the latest version: + +``` +pip install -U py-cord +``` + +### Migrating from other libraries + +If you are migrating from another library, say, `discord.py`, first of all, you need to uninstall it. + +``` +pip uninstall discord.py +``` + +Then, you can install Pycord, it's as simple as that!: + +``` +pip install py-cord +``` + +:::caution +Uninstalling `discord.py` _after_ installing `py-cord` can cause issues. Make sure to uninstall it first! +::: + +## Installing Other Builds + +### Development Build + +:::caution +The development build comes with cutting edge features and new functionality, but as it isn't a stable build you may encounter bugs. +::: + +To install the development build, you can use the following command in your terminal: + +``` +pip install -U git+https://github.com/Pycord-Development/pycord +``` + +:::important +Git is required to install this build. [Learn how you can install Git](./more/git). +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/interactions/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/interactions/_category_.json new file mode 100644 index 00000000..ea28be60 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/interactions/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 4, + "label": "Interactions" +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json new file mode 100644 index 00000000..6dcafe83 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Application Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx b/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx new file mode 100644 index 00000000..b4ffeade --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx @@ -0,0 +1,85 @@ +--- +title: Context Menus +description: Learn all about Context Menus (User Commands & Message Commands) and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +When you right-click a message, you may see an option called "Apps". Hover over it, and you can see +commands a bot can run with that message. These are called message commands. + +When you right-click a user in the user list, you can once again see an option called "Apps". +Hover over it, and you can see commands a bot can run with that message. These are called user commands. + +Together, these two are called Context Menus or Context Menu Commands. These commands work very much like normal commands, except they take a member or message. + +:::note + +A bot can have up to 5 global Context Menus of each type. + +::: + +## User Commands + +Creating a user command is very simple. + +```python +@bot.user_command(name="Account Creation Date", guild_ids=[...]) # create a user command for the supplied guilds +async def account_creation_date(ctx, member: discord.Member): # user commands return the member + await ctx.respond(f"{member.name}'s account was created on {member.created_at}") +``` + + + +
+ + Account Creation Date + +
+ {defaultOptions.profiles.bob.author}'s account was created on 2020-01-01 +
+
+ +## Message Commands + +```python +@bot.message_command(name="Get Message ID") # creates a global message command. use guild_ids=[] to create guild-specific commands. +async def get_message_id(ctx, message: discord.Message): # message commands return the message + await ctx.respond(f"Message ID: `{message.id}`") +``` + + + + Do. Or do not. There is no try. + + +
+ + Get Message ID + +
+ Message ID: 930650407917748286 +
+
+ +
+ +:::info Related Topics + +- [Slash Commands](./slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx b/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx new file mode 100644 index 00000000..edac55b3 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx @@ -0,0 +1,56 @@ +--- +title: Localizations +description: Localizations are a way to make your bot more accessible to your users. Learn all about localizations now! +--- + +Localizations are a way to make your bot more accessible to your users. You can localize the command +name, the names of any arguments, and any text that is displayed to the user. + +## Syntax + +```python +@bot.slash_command( + name="ping", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + }, + options=[ + Option( + name="Example", + name_localizations={ + "en-GB": "British Example" + }, + description="Example option that does nothing", + description_localizations={ + "en-GB": "British example option that does nothing" + } + ) + ] +) +async def ping(ctx, example): + responses = {"en-US": "Pong!", + "en-GB": "British Pong!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +@bot.slash_command( + name="ping2", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + } +) +async def ping2(ctx, example: Option(str, "example", name_localizations={"en-GB": "British Example"}, description="Example option that does nothing", description_localizations={"en-GB": "British example option that does nothing"})): + responses = {"en-US": "Pong2!", + "en-GB": "British Pong2!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +``` + +- [`Locales`](https://discord.com/developers/docs/reference#locales) - List of valid locales recognized by Discord diff --git a/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx b/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx new file mode 100644 index 00000000..ed454dad --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx @@ -0,0 +1,292 @@ +--- +title: Slash Commands +description: Learn all about Slash Commands and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On March 24, 2021, Discord added Slash Commands to Discord as an easier, more efficient, and better way of using bot commands. Pycord has implemented Slash Commands into the library, so it's simple, efficient, and familiar. + +:::important + +Remember that Slash Commands require your bot to be invited with the `application.commands` scope or Slash Commands will not show up. Bots already in the guild can simply be invited again with the scope; there is no need to kick the bot. + +::: + +## Syntax + +Let's create a simple Slash Command. + +```py +import discord + +bot = discord.Bot() + +# we need to limit the guilds for testing purposes +# so other users wouldn't see the command that we're testing + +@bot.command(description="Sends the bot's latency.") # this decorator makes a slash command +async def ping(ctx): # a slash command will be created with the name "ping" + await ctx.respond(f"Pong! Latency is {bot.latency}") + +bot.run("TOKEN") +``` + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +Let's go through the code. + +First, we import Pycord's `discord` package. + +Next, we create a [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot) object and assign it to a variable `bot`. + +We then go ahead and use the [`@bot.command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.command) decorator, which registers a new Slash Command. We pass a `description` parameter to give a description to the Slash Command. We can also pass a `name` parameter to change the Slash Command's name. By default, the name of the Slash Command will be the name of the function, in this case, `/ping`. + +We create an async function called `ping` with parameters `ctx`, which, when called, sends the bot's ping/latency using [`ctx.respond`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext.respond). + +## Subcommand Groups + +You might want to group certain commands together to make them more organised. A command group is exactly what it sounds like, a group of individual Slash Commands together. + +In order to make a Slash Command group, you can use the `bot.create_group` function. + +```python +import discord + +bot = discord.Bot() + +# create Slash Command group with bot.create_group +greetings = bot.create_group("greetings", "Greet people") + +@greetings.command() +async def hello(ctx): + await ctx.respond(f"Hello, {ctx.author}!") + +@greetings.command() +async def bye(ctx): + await ctx.respond(f"Bye, {ctx.author}!") + +bot.run("TOKEN") +``` + +Or, you can instead manually make a `SlashCommandGroup` class like so: + +```python +import discord + +math = discord.SlashCommandGroup("math", "Math related commands") + +@math.command() +async def add(ctx, num1: int, num2: int): + sum = num1 + num2 + await ctx.respond(f"{num1} plus {num2} is {sum}.") + +@math.command() +async def subtract(ctx, num1: int, num2: int): + sum = num1 - num2 + await ctx.respond(f"{num1} minus {num2} is {sum}.") + +# you'll have to manually add the manually created Slash Command group +bot.add_application_command(math) +``` + +Here's what the registered subcommands will look like in the Slash Command Menu: + +![Picture of the subcommands in the Slash Command Menu](../../assets/interactions/groups-and-subcommands.jpg) + +You'll notice that there's the name of the Slash Command Group and then the name of the subcommand separated by a space. + +::: + +:::info Cogs + +If you are looking to add Slash Command Groups to cogs, please look at our [Cogs page](../../popular-topics/cogs)! + +::: + +## Sub-groups + +We've made a subcommand group, but did you know that you could create a group inside another? + +```python +from discord import SlashCommandGroup +from math import sqrt + +math = SlashCommandGroup("math", "Math related commands") +advanced = math.create_subgroup("advanced", "Advanced math commands") + +@advanced.command() +async def square_root(ctx, x: int): + await ctx.respond(sqrt(x)) + +bot.add_application_command(math) +``` + +The command created above can be invoked by typing `/math advanced square_root`. + +## Options & Option Types + +Whenever you're using Slash Commands, you might notice that you can specify parameters that the user has to set or can optionally set. These are called Options. + +Options can also include a description to provide more information. [You can learn more about Options in our documentation!](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.Option) + +Since you want different inputs from Options, you'll have to specify the type for that Option; there are a few ways of doing this. + + + + +You could use Type Annotations and let Pycord figure out the option type or explicitly specified using the [`SlashCommandOptionType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.SlashCommandOptionType) enum. + +```python +import discord + +bot = discord.Bot() + +@bot.command() +# pycord will figure out the types for you +async def add(ctx, first: discord.Option(int), second: discord.Option(int)): + # you can use them as they were actual integers + sum = first + second + await ctx.respond(f"The sum of {first} and {second} is {sum}.") + +@bot.command() +# this explicitly tells pycord what types the options are instead +async def join( + ctx, + first: discord.Option(discord.SlashCommandOptionType.string), + second: discord.Option(discord.SlashCommandOptionType.string) +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + add + +
+ The sum of 1 and 1 is 2. +
+ +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+ + +Instead of Type Annotations, you can also use the option decorator. This is usually done to have type-hinting. + +```python title="Slash Command Type" +import discord + +bot = discord.Bot() + +@bot.command() +@discord.option("first", type=discord.SlashCommandOptionType.string) # type = str also works +@discord.option("second", type=discord.SlashCommandOptionType.string) # type = str also works +async def join( + ctx, + first: str, + second: str, +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+
+ +## Autocomplete + +Discord's autocomplete allows developers to determine option choices that are used in a slash command option. You can do this by defining a function: + +```py +async def get_animal_types(ctx: discord.AutocompleteContext): + """ + Here we will check if 'ctx.options['animal_type']' is a marine or land animal and return respective option choices + """ + animal_type = ctx.options['animal_type'] + if animal_type == 'Marine': + return ['Whale', 'Shark', 'Fish', 'Octopus', 'Turtle'] + else: # is land animal + return ['Snake', 'Wolf', 'Lizard', 'Lion', 'Bird'] + +@bot.slash_command(name="animal") +async def animal_command( + ctx: discord.ApplicationContext, + animal_type: discord.Option(str, choices=['Marine', 'Land']), + animal: discord.Option(str, autocomplete=discord.utils.basic_autocomplete(get_animal_types)) +): + await ctx.respond(f'You picked an animal type of `{animal_type}` that led you to pick `{animal}`!') +``` + + + +
+ + animal + +
+ You picked an animal type of Marine that led you to pick Shark! +
+
+ +:::warning + +Autocomplete can **only** be used with slash commands. + +::: + +:::info Related Topics + +- [Interactions Index](../../interactions) +- [Rules and Common Practices](../../getting-started/rules-and-common-practices) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/interactions/index.mdx b/i18n/it/docusaurus-plugin-content-docs/current/interactions/index.mdx new file mode 100644 index 00000000..8603437f --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/interactions/index.mdx @@ -0,0 +1,242 @@ +--- +title: Discord Interactions +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +In December 2020, Discord released their first Interaction: the +[Slash Command](https://discord.com/developers/docs/interactions/application-commands#slash-commands). +Since then, Discord has added many types of Interactions, including: + +[**Application Commands**](https://discord.com/developers/docs/interactions/application-commands) + +- [**Slash Commands**](https://discord.com/developers/docs/interactions/application-commands#slash-commands): + Commands that can be used with the `/` prefix. +- **Context Menu Commands**: Commands that can be used from the right-click menu. + - [**User Commands**](https://discord.com/developers/docs/interactions/application-commands#user-commands): + Commands that can be used on a user by alt-clicking/selecting them. + - [**Message Commands**](https://discord.com/developers/docs/interactions/application-commands#message-commands): + Commands that can be used on a message by alt-clicking/selecting it. + +[**UI Components**](https://discord.com/developers/docs/interactions/message-components) + +- [**Buttons**](https://discord.com/developers/docs/interactions/message-components#buttons): + Buttons are attached to a message and can be clicked on to perform an action. +- [**Select Menus**](https://discord.com/developers/docs/interactions/message-components#select-menus): + Drop-down menus are used to select a number of options from a list. +- [**Modals**](https://discord.com/developers/docs/interactions/message-components#text-inputs): + Form-like modals can be used to ask for input from a user. + +## Application Commands + +Application Commands are another set of new features that are intended to avoid compromising users' safety and privacy. +They're relatively easy to add to your bot, and give people a simpler and safer way to use commands. + +### [Slash Commands](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.SlashCommand) + +Slash Commands were the first Interaction added to Discord. They're easy to use and create, and +is the only prefix commands alternative that does not need Message Content intent. + +:::note + +Preferring prefix commands over Application Commands is **not** a valid reason to apply for the +Message Content intent. Using that as a reason will get your application denied. + +::: + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +This is what a Slash Command looks like. Not too different from a prefix command, +apart from the note telling you who invoked it. A Slash Command's fields can accept any of the following: + +- Members +- Roles +- Channels +- Attachments +- Text + +Just about as good as it gets. + +### [Message](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.MessageCommand) and [User](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.UserCommand) Commands + +Message Commands and User Commands were both introduced at around the same time, and are very similar to each other, so we'll be +introducing them together. These commands can be found in the `Apps` tab when alt-clicking. The only difference between the two is that +Message Commands only appear in the `Apps` tab of a message, while User Commands are found in the `Apps` tab of a user. Message Commands +can be used to quickly report a message, warn a user for a message, and other functions. Likewise, User Commands can be used to add a +user to a ticket, warn a user, and more. + +Here's an example of a Message Command: + + + + Hello World! + + +
+ + Reverse Message + +
+ Message 930650407917748286 reversed is "!dlroW olleH" +
+
+ +
+ +And here's an example of a User Command: + + + + {defaultOptions.profiles.dorukyum.author} has been on Discord for a long time + + +
+ + User Age + +
+ {defaultOptions.profiles.dorukyum.author} is 1 week old. +
+ +
+ + User Age + +
+ {defaultOptions.profiles.bob.author} is 40 years old. +
+ + 🤔 + +
+ +
+ +Pretty cool, right? To learn more about these two, please read the [Context Menus guide](./application-commands/context-menus.mdx). + +## [Application Commands](#application-commands) vs. [Prefix Commands](../extensions/commands/prefixed-commands) + +Ever since Discord was created, apps on it have used prefix commands. Using prefixes meant that you would have to put a +certain character (or string of characters) in front of your command, such as the exclamation mark in `!ping`. The way this +worked was that your bot would listen for messages, pick out the ones that had their specific prefix, and then respond to the command. +Now, Discord is encouraging developers to switch their bots over to Application Commands, which is a new system meant to preserve the +privacy and safety of their users. But why exactly is Discord making us switch? What's the better option, Application Commands or prefix +commands? Below, we'll discuss everything you need to know. + +### Discord's Decision + +Application Commands were conceptualized partly due to privacy concerns. When Discord first began, they weren't entirely concerned about bots +having access to the content of every message that was being sent. However, as Discord grew, this became more of a problem. Hypothetically, bots +could simply log every message they're able to receive via the Discord API and hand their contents over to a company or other third party. This is +a problem, since that data is meant to be used only by Discord. As such, they locked down Message Content, and introduced Application Commands for +bot developers to use instead. + +Prefix commands work by reading messages, as described before. Application Commands, however, don't +work this way; instead, they work by having your bot get information from Discord about when a command was used. This way, Discord can limit +Message Content only to bots that _absolutely_ depend on it, such as auto-moderation bots. + +### Who has to Use Application Commands + +Any verified bot that does not have the Message Content intent must use Application Commands. Discord is allowing developers to submit +applications for the ability to use the intent; however, since they don't want to keep supporting prefix commands due to privacy concerns, +they will automatically decline any application that includes only that as a reason. So, if your bot doesn't have an auto-moderation feature +(or any other functionality that requires Message Content), you're out of luck. + +Unverified bots, however, don't have to use Application Commands. This is because the Message Content intent is a `Privileged Intent`, meaning that +it must be applied for only if your bot is verified or about to be verified. Unverified bots don't have to apply for Privileged Intents, so they can +use them freely. + +So, if your bot is made only for a couple of servers, you can choose between prefix commands and Application Commands. However, if you plan on expanding +your bot's reach, it'll have to use Application Commands. + +### What's the Better Option + +Choosing which is the better option is up to you, if you're starting small. If +you plan on growing your bot, however, you will have to use Application Commands. Since prefix commands are slowly being phased out by Discord, +there isn't much of a choice for developers of larger bots. + +## Message Components + +Message Components are fairly new features in Discord, allowing developers to give their bots a fast +and understandable user interface. Message Components are easy to use and make your bot look modern, +sleek, and downright awesome. + +### [Views](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View) + +Views are not an Application Command nor are they a Message Component. Views are the invisible placeholders, or grid, +that Message Components lie in. Views can have up to 5 [`Action Rows`](https://docs.pycord.dev/en/stable/api/models.html#discord.ActionRow), +and Action Rows can have a maximum of 5 slots. Below, you can find a table showing how many slots a Message Interaction takes up. + +| Component | Slots | +| ------------ | ----------------------------------------------- | +| Buttons | 1 Slot | +| Select Menus | 5 Slots | +| Text Modals | 1 Slot (opened via a Button) | + +So, based on this, you could have a maximum of 25 Buttons in a View with no Select Menus, and 5 Select +Menus in a View with no Buttons. This doesn't mean you can't have them both in a View, however. You can have +a combination of them, such as 20 Buttons and a Select Menu or 10 Buttons and 3 Select Menus. + +### [Buttons](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button) + +Buttons are the first of the Message Components. They allow for quick responses to prompts, such as for canceling or continuing an action. +Of course, these aren't their only uses; people have created awesome things with Buttons, such as calculators, games, and more! + + + + Discord Buttons are awesome! +
+ + Click me! + +
+
+
+ +
+ +This is what a Button looks like, very simple and modern. To learn more about Buttons, refer to our +[Buttons page](./ui-components/buttons.mdx). + +### [Select Menus](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Select) + +Select Menus are the second of Discord's Message Components. They allow users to select from a list of choices, which your bot can then use. +Select Menus are good for things such as choosing features, pages of a help menu, and more. + +![Select Menu Example Image](../assets/interactions/select-menus-example.png) + +This is what a Select Menu looks like. While not looking as good as Buttons, they still look great +and have even greater possibilities. To learn more about Select Menus, please refer to our [Select +Menus page](./ui-components/dropdowns.mdx). + +### [Modal Dialogs](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal) + +Text Modals are the most recently added Message Component in Discord. They're useful for text input and filling out forms, such as a +sign-up for your bot's service. These are meant to replace long bot setup processes by allowing users to fill out multiple text fields, +which avoids having the user send multiple messages for the bot. Modals can be accessed by either invoking an Application Command or by +interacting with another UI Component. + +![Text Modal Example Image](../assets/interactions/modal-example.png) + +This is what a Text Modal looks like, easy to use and one of the most useful Message Components yet. To learn more about Text Modals, +please visit our [Modal Dialogs page](./ui-components/modal-dialogs.mdx). diff --git a/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json new file mode 100644 index 00000000..7b0a72fe --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "UI Components", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx b/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx new file mode 100644 index 00000000..046b36c7 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx @@ -0,0 +1,314 @@ +--- +title: Buttons +description: Learn all about implementing buttons in your Discord Bot using Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On May 26, 2021, Discord added a new interaction called buttons. Instead of reactions, bots could now +send buttons and users could use them to interact with bots. This opened up a whole new world of +possibilities for bots. Soon after, developers made calculators, polls, and games like blackjack, UNO, +and even Minecraft! Buttons provided a clear and easy to use interface for interacting with bots. + +So, let's learn how you can add buttons to your bot! + +## Concept + +Buttons weren't the only update to the interactions system in Discord. Discord also added [Select Menus](./dropdowns) and [Modal Dialogs](./modal-dialogs), both of which work very similarly to buttons. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive button. + +```python +import discord + +bot = discord.Bot() # Create a bot object + +class MyView(discord.ui.View): # Create a class called MyView that subclasses discord.ui.View + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.primary, emoji="😎") # Create a button with the label "😎 Click me!" with color Blurple + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") # Send a message when the button is clicked + +@bot.slash_command() # Create a slash command +async def button(ctx): + await ctx.respond("This is a button!", view=MyView()) # Send a message with our View class that contains the button + +bot.run("TOKEN") # Run the bot +``` + +Using this command should return the following message: + + + +
+ + button + +
+ This is a button! +
+ + Click me! + +
+
+
+ +
+ +As you can see, we create a class called `MyView` that [subclasses](#oop) +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `button_callback` to the `MyView` class with the decorator +[`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button). +This decorator adds a button to a component. This function takes two arguments: the button that was +clicked and the interaction. These arguments are passed to the function when the button is clicked +by the module. We use the [`interaction.response.send_message`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse.send_message) +function to send a message to the channel where the interaction was sent. + +Finally, we create a global slash command called `button` that sends the message, along with the view +that contains a button. + +This is the basic syntax of creating a button. What you create with it is up to you. You can worry +about making your button do amazing things, while Pycord handles the rest! + +## Button Styles + + + +| Name | Usage | Color | +| --------- | ----------------------------------------------------------------------------------------- | ------- | +| Primary | `discord.ButtonStyle.primary` / `discord.ButtonStyle.blurple` | Blurple | +| Secondary | `discord.ButtonStyle.secondary` / `discord.ButtonStyle.grey` / `discord.ButtonStyle.gray` | Grey | +| Success | `discord.ButtonStyle.success` / `discord.ButtonStyle.green` | Green | +| Danger | `discord.ButtonStyle.danger` / `discord.ButtonStyle.red` | Red | +| Link | `discord.ButtonStyle.link` / `discord.ButtonStyle.url` | Grey | + +Check out the [`discord.ButtonStyle`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ButtonStyle) class for more information. + +![Different Button Styles](../../assets/interactions/button-styles.png) + +You can set a button's style by adding the `style` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) decorator. + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.success) + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots, and each button takes up 1 slot. +So, how do we move the buttons to another row? + +This can be done by specifying the `row` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) +decorator. + +:::info The `row` argument + +The row argument specifies the relative row this button belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=1, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") +``` + +## Disabling Buttons + +### Pre-Disabled Buttons + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary, disabled=True) # pass `disabled=True` to make the button pre-disabled + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView()) +``` + +### Disabling Buttons on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + button.disabled = True # set button.disabled to True to disable the button + button.label = "No more pressing!" # change the button's label to something else + await interaction.response.edit_message(view=self) # edit the message's view +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(emoji="😀", label="Button 1", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) + + @discord.ui.button(label="Button 2", style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +Sometimes, you want to have a button that is disabled after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView(timeout=30)) +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a button that is disabled after a certain amount of time, you want to have a +button that is always working. + +Normally, when the bot goes offline, all of its buttons stop working. You will be able to see the +buttons, but nothing will happen when you press them. This is a problem +if you are trying to create a self-role system with buttons, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons will stop working. When the bot comes back online, however, the buttons will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view must have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.button(label="A button", custom_id="button-1", style=discord.ButtonStyle.primary, emoji="😎") # the button has a custom_id set + async def button_callback(self, button, interaction): + await interaction.response.send_message("Button was pressed", ephemeral=True) + +@bot.command() +async def button(ctx): + await ctx.send(f"Press the button! View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many buttons can I have in a message? + +Each message can have a maximum of 25 buttons. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do buttons need any special permissions? + +No new permissions are needed for either the bot or the server to allow bots to use buttons. + +#### Should I replace reactions with buttons for my bot? + +That is up to you. Buttons do provide a cleaner interface for your bot and are easier to use. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx b/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx new file mode 100644 index 00000000..8320f25d --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx @@ -0,0 +1,339 @@ +--- +title: Select Menus +description: Learn all about implementing Select Menus or Dropdowns in your Discord Bot with Pycord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Shortly after the buttons were added, Discord added their second message component: Select Menus. Select Menus allow users to choose from a list of items sent by a bot. These are a great substitute for having a user send a number that corresponds to an option. You can even allow users to select multiple options from the Select Menus. This guide will show you the easy and painless ways of using them with Pycord. + +## Concept + +Select Menus aren't the only message component in Discord. There's also [Buttons](./buttons) and [Modal Dialogs](./modal-dialogs). Select Menus make it easy for users to pick one or multiple options from a list provided by a bot. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive select menu. + +```python +import discord + +bot = discord.Bot() + +class MyView(discord.ui.View): + @discord.ui.select( # the decorator that lets you specify the properties of the select menu + placeholder = "Choose a Flavor!", # the placeholder text that will be displayed if nothing is selected + min_values = 1, # the minimum number of values that must be selected by the users + max_values = 1, # the maximum number of values that can be selected by the users + options = [ # the list of options from which users can choose, a required field + discord.SelectOption( + label="Vanilla", + description="Pick this if you like vanilla!" + ), + discord.SelectOption( + label="Chocolate", + description="Pick this if you like chocolate!" + ), + discord.SelectOption( + label="Strawberry", + description="Pick this if you like strawberry!" + ) + ] + ) + async def select_callback(self, select, interaction): # the function called when the user is done selecting options + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") + +@bot.command() +async def flavor(ctx): + await ctx.respond("Choose a flavor!", view=MyView()) + +bot.run("TOKEN") +``` + +There's a lot going on over here! Don't worry, we will go over the code and explain it. + +As you can see, we create a class called `MyView` that subclasses +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `select_callback` to the `View` class with the decorator +[`discord.ui.select`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.select). +This decorator adds a select menu to the view. This decorator takes a few arguments to customize your select menu. Read them in the [Customization section](#customization). + +That was the decorator. Now, the function itself is pretty simple. It takes two parameters, not including `self`. The parameters are `select`: The select menu, and `interaction`: a [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object. Both of these are passed by Pycord, so you just need to specify them in the function! + + + +In the callback, you could do anything you want. You get the two parameters `select` and `interaction` to play around with. Here, we send a message using `await interaction.response.send_message` (where interaction is [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse)) with content `select.values[0]`, which sends the label of the first/only option the user selected. Obviously, this is only an example, and you could do just about anything you want. + +Finally, we create a global slash command called `flavour` that sends a message "Choose a flavor!" along with the view +that contains our select menu. + +This is the basic syntax of creating a select menu. What you create with it is up to you. You can worry +about making your code do amazing things, while Pycord handles the rest! + +## Customization + +#### Select Menu Properties + +- `select_type`: The type of select to create. This must be a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. +- `channel_types`: A list of channel types that can be selected in the menu. This is only valid for selects of `select_type` [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType). +- `options`: A list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. These are the options that can be selected in this menu. +- `placeholder` is the placeholder text shown in the select menu if no option is selected. +- `custom_id`: The ID of the select menu that gets received during an interaction. It is recommended not to set this to anything unless you are trying to create a persistent view. +- `row`: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). +- `min_values`: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `max_values`: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `disabled`: Whether the select is disabled or not. Defaults to False. + +#### Select Option Properties + +In the `options` parameter, you pass a list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. This class also has a few parameters: + +- `default` (whether the option is selected by default) +- `description` (an additional description, if any) +- `emoji` (a string or an emoji object, if any) +- `label` (the name displayed to users, can be up to 100 characters) +- `value` (a special value of the option, defaults to the label). + +## Select Types + +In addition to regular string selects, you can also have your select menu contain users, roles, mentionables, and channels as its options. You can use these alternative select types by passing a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value for the `select_type` parameter when creating the Select. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.user_select + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +Additionally, you can use shortcut decorators to create a [`discord.ui.Select`](https://docs.pycord.dev/en/master/api/ui_kit.html#discord.ui.select) with a predetermined [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. Using a shortcut decorator, the above code can be rewritten like this: + +```python +class MyView(discord.ui.View): + @discord.ui.user_select() + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +### Specifying Channel Types + +When using a [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType.channel_select) type select menu, you can pass in a list of [`discord.ChannelType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ChannelType) values to limit which types of channels users can choose when interacting with the select menu. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.channel_select, + channel_types=[discord.ChannelType.text, discord.ChannelType.voice] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"You selected {select.values[0].mention}") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots. A button takes a single slot, while a select menu takes up all 5 of them. This means a view can have a maximum of 5 select menus, or any possible combination of select menus and buttons. + +The arrangement of buttons and select menus is generally adjusted by Pycord. However, it is possible to move them to specific relative rows. This is done by specifying the `row` argument. + +:::info The `row` argument + +The row argument specifies the relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero-indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=0, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.select( + row = 1, + options = [...] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") +``` + +## Disabling Select Menus + +### Pre-Disabled Menus + +```python +class MyView(discord.ui.View): + @discord.ui.select( + disabled = True, # pass disabled=True to set the menu as disabled + options = [...] + ) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send("Select and option from the menu!", view=MyView()) +``` + +### Disabling Menus on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + select.disabled = True # set the status of the select as disabled + await interaction.response.edit_message(view=self) # edit the message to show the changes +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def first_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) # edit the message to show the changes + + @discord.ui.select(options = [...]) + async def second_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +You may want a select menu to automatically stop working after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select(ctx): + await ctx.send(view=MyView(timeout=30)) # specify the timeout here +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a select menu that is disabled after a certain amount of time, you want to have a +select menu that is always working. + +Normally, when the bot goes offline, all of its views stop working, even if they don't have a timeout. You will be able to see the +views, but nothing will happen when you try to interact with them. This is a problem +if you are trying to create a self-role system, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons and select menus will stop working. However, when the bot comes back online, the buttons and select menus will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view much have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.select(custom_id="select-1", options = [...]) # a custom_id must be set + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send(f"View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many select menus can I have in a message? + +Each message can have a maximum of 5 select menus. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do select menus need any special permissions? + +No new permissions are needed in the bot or in the server. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx b/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx new file mode 100644 index 00000000..bd585c77 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx @@ -0,0 +1,107 @@ +--- +title: Modal Dialogs +description: Learn how you can implement Modals in your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Modal Dialogs, also known as "modals", provide a form-like structure for bots to receive input from users. No extra permissions are needed for bots to send modal dialogs, so it becomes a convenient workaround for bots to receive longer input without needing the Message Content [intent](../../popular-topics/intents). + +## Concept + +Modal Dialogs consist of a title, custom ID, and up to 5 [`discord.ui.InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) components. While creating modals, we generally subclass [`discord.ui.Modal`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal), as we'll see later. + +Unlike other UI Components, Modals cannot be sent with messages. They must be invoked by an Application Command or another UI Component. + +## Usage Syntax + +```py +class MyModal(discord.ui.Modal): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.add_item(discord.ui.InputText(label="Short Input")) + self.add_item(discord.ui.InputText(label="Long Input", style=discord.InputTextStyle.long)) + + async def callback(self, interaction: discord.Interaction): + embed = discord.Embed(title="Modal Results") + embed.add_field(name="Short Input", value=self.children[0].value) + embed.add_field(name="Long Input", value=self.children[1].value) + await interaction.response.send_message(embeds=[embed]) +``` + + + + +The `ctx` parameter we define in Application Commands receives an [`ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext) object. Using its `send_modal()` coroutine, you can send a Modal dialog to the user invoking the Application Command. + +```py +@bot.slash_command() +async def modal_slash(ctx: discord.ApplicationContext): + """Shows an example of a modal dialog being invoked from a slash command.""" + modal = MyModal(title="Modal via Slash Command") + await ctx.send_modal(modal) +``` + + + + +The `interaction` parameter we define in UI Components receives an [`Interaction`](https://docs.pycord.dev/en/stable/api/models.html#discord.Interaction) object. The `response` attribute of the object contains an [`InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object, with various coroutines such as `send_message()` and `send_modal()`, which we utilize. + +```py +class MyView(discord.ui.View): + @discord.ui.button(label="Send Modal") + async def button_callback(self, button, interaction): + await interaction.response.send_modal(MyModal(title="Modal via Button")) + +@bot.slash_command() +async def send_modal(ctx): + await ctx.respond(view=MyView()) +``` + + + + +The above example uses an embed to display the results of the modal submission, but you can do anything you want with the text provided by the user. +Each input field can be accessed in the order it was added to the modal dialog, via `Modal.children`. + +## Customization + +A Modal can have up to 5 [`InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) fields. These fields offer some customization. + +Each field has a label which is shown to the user. This is defined with `label`. + +The `style` parameter is used to determine whether it should be a short (single-line) or long (multi-line) input field. + +There are a number of aliases that can be used: + +```x title="Single-line InputTextStyle values:" +short +singleline +``` + +```x title="Multi-line InputTextStyle values:" +paragraph = 2 +multiline = 2 +long = 2 +``` + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Buttons](./buttons) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/introduction.mdx b/i18n/it/docusaurus-plugin-content-docs/current/introduction.mdx new file mode 100644 index 00000000..3262c632 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/introduction.mdx @@ -0,0 +1,50 @@ +--- +title: Introduction +description: Pycord Guide is a complete guide for Pycord. Learn how to create Discord Bots today! +sidebar_position: 1 +--- + +Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord, written in Python. Pycord is a maintained fork of [discord.py](https://github.com/Rapptz/discord.py). + +## Before you begin + +Pycord is an advanced and complex Python library. To take advantage of the full capabilities of Pycord, you will need to have a good understanding of Python. You should know the basics of Python and have an understanding of the following concepts: + +- Variables +- Data Types +- Functions +- Packages +- Conditionals +- Loops +- Classes +- Object-Oriented Programming +- Inheritance +- Exception Handling +- Iterators +- Coroutines +- Async/Await + +This list is not exhaustive, but it should give you a good idea of what you need to know to get started. + +When you see an ellipsis - that's the three dots - in this guide, it is a placeholder for code that you need to fill in. Sometimes, it may be code for a command, while other times it could be something simple like a Guild ID. Make sure to replace them before running your bot! + +## Learning Resources + +Here are some good resources to get started or to freshen up your Python knowledge: + +- [Official Beginner's Guide](https://wiki.python.org/moin/BeginnersGuide) +- [Official Tutorial](https://docs.python.org/3/tutorial/) +- [Automate the Boring Stuff, a free online book for complete beginners to programming](https://automatetheboringstuff.com/) +- [Learn Python in y Minutes, complete cheat sheet for people who know programming already](https://learnxinyminutes.com/docs/python3/) +- [Swaroopch's free Python book](http://python.swaroopch.com/) +- [Codeabbey, exercises for beginners](http://www.codeabbey.com/) + +## Credits + +First of all, we would like to thank [Rapptz](https://github.com/Rapptz) for the original [discord.py](https://pypi.org/project/discord.py) library. Pycord is a maintained fork of this library. + +We would also like to thank the [discord.js guide](https://discordjs.guide), which inspired this guide style-wise, and the [original Pycord Guide](https://namantech.me/pycord), which inspired some content in this guide. + +We created this guide using [Docusaurus v2](https://docusaurus.io), a modern static site generator for React. We would also like to thank Danktuary for his [`@discord-message-components/react`](https://www.npmjs.com/package/@discord-message-components/react) package, from which we took the Discord message components. + +And finally, we would like to thank the amazing and loving community of Pycord users, contributors and developers. diff --git a/i18n/it/docusaurus-plugin-content-docs/current/more/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/more/_category_.json new file mode 100644 index 00000000..2cbe2c56 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/more/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 8, + "label": "More", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/more/community-resources.mdx b/i18n/it/docusaurus-plugin-content-docs/current/more/community-resources.mdx new file mode 100644 index 00000000..ed3075bd --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/more/community-resources.mdx @@ -0,0 +1,23 @@ +--- +title: Community Resources +--- + +This page showcases the amazing things created by the Pycord community, including bots, Plugins, and more. + +## Plugins + +| Name | Type | GitHub | +| --------------- | ------------ | --------------------------------------------------------------- | +| Music Cord | Music | [NixonXC/cord-music](https://github.com/NixonXC/cord-music) | +| pycord-i18n | Localization | [Dorukyum-pycord-i18n](https://github.com/Dorukyum/pycord-i18n) | +| pycord-multicog | Cogs | [pycord-multicog](https://github.com/Dorukyum/pycord-multicog) | +| EzCord | Utilities | [EzCord](https://github.com/tibue99/ezcord) | + +## Bots + +| Name | Type | Link | +| ------------------------ | ------------ | ----------------------------------------------------------------------------------- | +| Discord-Multipurpose-Bot | Multipurpose | [github](https://github.com/pogrammar/Discord-multipurpose-bot/tree/master/Python) | +| inconnu | Fun & QOL | [github](https://github.com/tiltowait/inconnu) | +| Mai | Multipurpose | [github](https://github.com/TeamMai/Mai) & [website](https://xfghoul.github.io/Mai) | +| Toolkit | Multipurpose | [github](https://github.com/Dorukyum/Toolkit) | diff --git a/i18n/it/docusaurus-plugin-content-docs/current/more/contributing.mdx b/i18n/it/docusaurus-plugin-content-docs/current/more/contributing.mdx new file mode 100644 index 00000000..469ea3ee --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/more/contributing.mdx @@ -0,0 +1,463 @@ +--- +title: Contributing to the Guide +description: Learn how to contribute to the Pycord Guide. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +This page outlines some of the basic syntax you need to know to contribute to the guide. We recommend you also check out: + +- [Docusaurus's Docs](https://docusaurus.io/docs/) +- [Contributing Rules](https://github.com/Pycord-Development/guide/blob/master/.github/CONTRIBUTING.md) + +## Info + +We use [Docusaurus v2](https://docusaurus.io/) to generate our guide. All the guide pages are generated +from `mdx` files in the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory. +MDX allows you to use JSX in your markdown content. + +## Structure + +Let's visit the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory and check its file structure. + +We can see various folders and a few files in it. Let's talk a bit about the `introduction.mdx` file. At the top, you can see something like: + +```md +--- +title: Introduction +description: ... +sidebar_position: 1 +--- +``` + +Most pages have this at the top. The `title` defaults to the file name. Since the titles need to be Capitalized according to need while the file names are lowercased (sometimes, the file names are shorter than the title!), we set a title ourselves. + +The `description` field is also important. This is the text shown in an embed when the page's link is shared on Discord, Twitter or other websites that support embedded links. Make sure to give a nice an interesting description! + +The `sidebar_position` field is pretty self-explanatory. It sets the position of the page in the sidebar. Most files in categories do not need this since they are sorted alphabetically. + +## Markdown Syntax + +This page quickly outlines some of the syntax that is used in markdown. + +````mdx +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + + ```python + print("We can use code blocks like this.") + ``` + +You can add [links to other websites](https://pycord.dev). You can add images like this: ![alternate text that describes the image](https://pycord.dev/image.png). + +- You can create +- unordered lists like this + +1. Or ordered lists +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` +4. Like this + +# Headers + +## Go + +### Like + +#### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet +```` + +
+Preview +
+ +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + +```python +print("We can use code blocks like this.") +``` + +You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](@site/static/img/favicon.ico). + +- You can create +- unordered lists like this + +1. Or ordered lists + +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` + +4. Like this + + # Headers + + ## Go + + ### Like + + #### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet + +
+
+ +## Admonitions + +We can add warnings, notes, etc. with the following syntax: + +```md +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: +``` + +
+Preview +
+ +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: + +
+ +
+ +## Discord Message Components + +As most files already have the imports for these, it's not that hard to add them. + +First, import the necessary components: + +```tsx +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; +``` + +The div starts like so: + +```tsx + + + + +
+``` + +This is where you list a `DiscordMessage`. + +```tsx + + + Hello! + + + +
+``` + + + + Hello! + + + +
+ +It has a pretty straightforward syntax. + +:::tip + +Add a `
` to the end of a component to make the content below it look better. + +::: + +### Slash Commands + +To make a message authored by a slash command, do the following: + +```tsx + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+``` + + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+ +### Buttons + +To make a message with buttons, do the following: + +```tsx + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+``` + + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+ +## Page Format + +There are a few things you need to take care of: + +1. Make sure that the spelling and grammar is perfect. We have a GitHub action configured that will warn you about spelling errors when you start a pull request. Make sure to commit your changes accordingly. + + As for the grammar, you should try reading the changes you have done and wait for reviews from others. + +2. A common mistake people make is incorrect header style. People often think that the less the important the topic is, the lower it's heading style should be. + + ```md + [PAGE STARTS] + # Topic + ## Less Important Topic + ## Subtopic + ``` + + ```md + [PAGE STARTS] + # About + [Introduction] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + That's VERY wrong. Here's the correct example: + + ```md + [PAGE STARTS] + [Introduction] + ## Topic + ## Less Important Topic + ### Subtopic + ``` + + ```md + [PAGE STARTS] + [Introduction] + + ## About + [More Information] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + Note that the `---`s at the beginning have been skipped here. diff --git a/i18n/it/docusaurus-plugin-content-docs/current/more/git.mdx b/i18n/it/docusaurus-plugin-content-docs/current/more/git.mdx new file mode 100644 index 00000000..0f929d6d --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/more/git.mdx @@ -0,0 +1,55 @@ +--- +title: Installing Git +description: Learn how you can install Git on your system. +--- + +Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Let's see how to install Git on different platforms. + +## Windows + +On Windows, Git can be installed via: + +- [Git for Windows](https://gitforwindows.org) +- [Git Scm](https://git-scm.com/download/windows) + +## Linux + +On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. + +## Mac + +You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: + +``` +xcode-select --install +``` + +## Using Package Managers + +You can also install Git using package managers. + +### Chocolatey + +If you use the Chocolatey package manager, you can install Git using: + +``` +choco install git +``` + +### Scoop + +If you use Scoop, you can install Git using: + +``` +scoop install git +``` + +### Brew + +If you're on macOS or Linux, you can install Git using: + +``` +brew install git +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx b/i18n/it/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx new file mode 100644 index 00000000..b0b8c7ea --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx @@ -0,0 +1,62 @@ +--- +title: Virtual Environments +description: Learn how to set up a virtual environment for Pycord. +--- + +## Setup + +Sometimes you want to keep libraries from polluting system installs or use a different version of libraries than the ones installed on the system. You might also not have permissions to install libraries system-wide. For this purpose, the standard library as of Python 3.3 comes with a concept called “Virtual Environment”s to help maintain these separate versions. + +A more in-depth tutorial is found on [Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html). + +However, for the quick and dirty: + +Go to your project’s working directory: + +```bash +$ cd your-bot-source +$ python3 -m venv venv +``` + +Activate the virtual environment: + +```bash +$ source venv/bin/activate +``` + +On Windows you activate it with: + +```batch +$ venv\Scripts\activate.bat +``` + +Use pip like usual: + +```bash +$ pip install -U py-cord +``` + +Congratulations. You now have a virtual environment all set up. + +## Additional info + +It can be useful to set up a requirements.txt, so you can just put all of your dependencies in there and have pip install it. +For instance, if you wanted to have the latest 2.0 version of pycord and [pytz](https://github.com/stub42/pytz/blob/master/src/README.rst), just create a file named requirements.txt with the following contents: + +``` +py-cord>=2.0.0 +pytz +``` + +And then (in your virtual environment) you can just execute + +```bash +pip install -r requirements.txt +``` + +To keep from committing your virtual environment to git, you can set up a .gitignore file with the following line +(assuming you named your virtual environment venv like the above example): + +``` +venv/ +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/_category_.json new file mode 100644 index 00000000..c38ea014 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 7, + "label": "Popular Topics", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx new file mode 100644 index 00000000..5377a6c3 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx @@ -0,0 +1,140 @@ +--- +title: Cogs +--- + +Cogs, often known as modules or extensions, are used to organize commands into groups. This is useful +for grouping commands that have the same general idea (such as moderation commands). This also helps +to avoid making your bot's files messy and cluttered. + +## Getting Started + +First, you'll need to create a folder to store your cogs, e.g. `cogs/`. + +Then, create a file inside the folder, e.g. `cogs/greetings.py`. By convention, the file name should +be the same as the name of the cog or module. + +We can then create the cog. + +```python title="./cogs/greetings.py" +import discord +from discord.ext import commands + +class Greetings(commands.Cog): # create a class for our cog that inherits from commands.Cog + # this class is used to create a cog, which is a module that can be added to the bot + + def __init__(self, bot): # this is a special method that is called when the cog is loaded + self.bot = bot + + @commands.command() # creates a prefixed command + async def hello(self, ctx): # all methods now must have both self and ctx parameters + await ctx.send('Hello!') + + @discord.slash_command() # we can also add application commands + async def goodbye(self, ctx): + await ctx.respond('Goodbye!') + + @discord.user_command() + async def greet(self, ctx, member: discord.Member): + await ctx.respond(f'{ctx.author.mention} says hello to {member.mention}!') + + math = discord.SlashCommandGroup("math", "Spooky math stuff") # create a Slash Command Group called "math" + advanced_math = math.create_subgroup( + "advanced", + "super hard math commands!" + ) + + @math.command() + async def add(self, a: int, b: int): + c = a + b + await ctx.respond(f"{a} + {b} is {c}.") + + @advanced_math.command() + async def midpoint(self, x1: float, y1: float, x2: float, y2: float): + mid_x = (x1 + x2)/2 + mid_y = (y1 + y2)/2 + await ctx.respond(f"The midpoint between those coordinates is ({mid_x}, {mid_y}).") + + @commands.Cog.listener() # we can add event listeners to our cog + async def on_member_join(self, member): # this is called when a member joins the server + # you must enable the proper intents + # to access this event. + # See the Popular-Topics/Intents page for more info + await member.send('Welcome to the server!') + +def setup(bot): # this is called by Pycord to setup the cog + bot.add_cog(Greetings(bot)) # add the cog to the bot +``` + +You can add any number of commands to your cog, as well as event listeners. However, this code will +not work on its own. In your main bot file, you must add the following code: + +```python +bot.load_extension('cogs.greetings') +``` + +This loads the file `cogs/greetings.py` and adds it to the bot. +The argument of `load_extension` should be your cog's path (e.g. cogs/greetings.py) without the file +extension and with the `/` replaced with `.` + +If you have multiple cogs, you can add them all at once by adding the following code: + +```python +cogs_list = [ + 'greetings', + 'moderation', + 'fun', + 'owner' +] + +for cog in cogs_list: + bot.load_extension(f'cogs.{cog}') +``` + +## Cog Rules + +When using a cog instead of the main file, there are some changes you have to make to your code. This +is because cogs work slightly different from a regular file. + +### The `self` variable + +The self variable is a variable that represents a class. In the case of cogs, `self` represents +the cog. In the `__init__` function, you can see that we have `self.bot = bot`. `bot` represents your +`discord.Bot` or `discord.ext.commands.Bot` instance, which is used for some functions. + +This means that instead of using functions that would usually be accessed via `bot`, you now need +to access them via `self.bot` + +Because we're in a class, all of our commands are methods of that class. Because of this, all of our +functions need to have `self` as the first parameter, where `self` is the cog. Without this, we +wouldn't be able to access our bot instance. + +### Creating Commands + +When creating prefixed commands, your decorator would usually be something like `@bot.command()`. If you're using +cogs, this isn't the case. In a cog, you can't access the bot instance outside of functions, so to +register a function as a command, you must instead use `@commands.command()`. + +Similar to prefixed commands, you'll have to use either the `@discord.slash_command()`, `@discord.user_command()`, +or `@discord.message_command()` decorators for Application Commands. + +Also, when creating a command, make sure that it is indented. If we want a command to be actually +inside a cog, it has to be inside your cog's class. If the command is not inside the cog, +your command becomes useless. + +### Events + +When creating events, you can no longer use `@bot.event` as a decorator. This is because we cannot +access the `bot` variable outside a function. To make an event, you have to use the `ext.commands` +method, `@commands.Cog.listener()`. Events also need `self` as their first parameter. + +And that's it! Cogs are a simple and easy way of organizing your code. Now you can check out how to +create a help command [here](../extensions/commands/help-command). + +:::info Related Topics + +- [Creating a Help Command](../extensions/commands/help-command) +- [Rules and Common Practices](../getting-started/rules-and-common-practices) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Application Commands](../interactions#application-commands) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx new file mode 100644 index 00000000..6c19dd29 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx @@ -0,0 +1,383 @@ +--- +title: Error Handling +description: All about handling errors. +--- + +import { + DiscordEmbed, + DiscordInteraction, + DiscordMessage, +} from "discord-message-components/packages/react"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +## About + +When using the library, errors are frequently raised due to various reasons. These reasons range from the Discord API +failing your bot's request due to missing permissions or an invalid syntax error. + +Before going into error handling, it's best that you learn the basic ways of handling errors. A good resource is: + +- [W3Schools' Guide to Python Try-Except Statements](https://www.w3schools.com/python/python_try_except.asp) + +## Basic Handling + +The most basic way to handle errors is to tackle it at the source. This can be done like so: + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +import asyncio + +import discord + +intents = discord.Intents.default() +intents.message_content = True + +bot = discord.Bot(intents=intents) + + +@bot.slash_command(description="Gets some feedback.") +@discord.option("name", description="Enter your name.") +async def feedback(ctx: discord.ApplicationContext, name: str): + try: + await ctx.respond(f"Hey, {name}! Send your feedback within the next 30 seconds please!") + + def is_author(m: discord.Message): + return m.author.id == ctx.author.id + + feedback_message = await bot.wait_for("message", check=is_author, timeout=30.0) + await ctx.send(f"Thanks for the feedback!\nReceived feedback: `{feedback_message.content}`") + except asyncio.TimeoutError: + await ctx.send("Timed out, please try again!") + + +bot.run("TOKEN") +``` + +If you respond within 30 seconds, the interaction will look like so: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Great bot! + + + Thanks for the feedback! +
+ Received feedback: Great bot! +
+
+
+ +Otherwise, if you don't respond in time, the interaction will go as follows: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Timed out, please try again! + +
+
+ +This basic method of error handling can be extended to handle +many other errors including ones raised directly by py-cord. + +## Per-Command Handling + +This type of error handling allows you to handle errors per each command you have on your bot. +Each and every command can have it's own error handler made to handle specific errors that each command may raise! + +An example of per-command error handling is as follows: + +:::note Bridge Commands + +For these types of commands, it is recommended to utilize global error handling +until [the feature](https://github.com/Pycord-Development/pycord/issues/1388) is added. +::: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot(owner_id=...) # Your Discord user ID goes in owner_id + + +@bot.slash_command(description="A private command...") +@commands.is_owner() # This decorator will raise commands.NotOwner if the invoking user doesn't have the owner_id +async def secret(ctx: discord.ApplicationContext): + await ctx.respond(f"Hey {ctx.author.name}! This is a secret command!") + + +@secret.error +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.NotOwner): + await ctx.respond("Sorry, only the bot owner can use this command!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If your ID is registered as the owner ID, you'll get the following: + + + +
+ + secret + +
+ Hey Dorukyum! This is a secret command! +
+
+
+ +Any other user whose ID doesn't match the bot owner's will get the following: + + + +
+ + secret + +
+ Sorry, only the bot owner can use this command! +
+
+
+ +This local (per-command) error handler can also be used to handle the same types of errors that standard try-except +statements can handle. This is done by using the same method as above with the `isinstance` built-in function. + +## Per-Cog Handling + +Adding error handlers per-command can be quite the task in terms of work if you have a lot. If you have happened to +group your commands in cogs, then you're in luck! You can create an error handler that is specific to a cog and +handles all errors raised by commands inside that cog. + +Here's an example of a bot with a cog that implements its own error handling: + +```python title="./cogs/dm.py" +# This cog is for DM only commands! Sadly, we only have 1 command here right now... + +import discord +from discord.ext import commands + + +class DM(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.command() + @commands.dm_only() # This decorator will raise commands.PrivateMessageOnly if invoked in a guild context. + async def avatar(self, ctx: commands.Context): + embed = discord.Embed( + title="Avatar", + description=f"Here's your enlarged avatar, {ctx.author.name}!", + color=ctx.author.top_role.color + ) + embed.set_image(url=ctx.author.display_avatar.url) + await ctx.send(embed=embed, reference=ctx.message) + + async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): + if isinstance(error, commands.PrivateMessageOnly): + await ctx.send("Sorry, you can only use this in private messages!", reference=ctx.message) + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +def setup(bot: commands.Bot): + bot.add_cog(DM(bot)) +``` + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +# This is the main file where we load the DM cog and run the bot. + +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix=commands.when_mentioned_or("!")) +bot.load_extension("cogs.dm") +bot.run("TOKEN") +``` + +If you use this command in a DM context, you'll get the following: + + + + !avatar + + +
+ + !avatar + +
+ + Here's your enlarged avatar, BobDotCom! + +
+
+
+ +Otherwise, if used in a guild context: + + + + !avatar + + +
+ + !avatar + +
+ Sorry, you can only use this in private messages! +
+
+
+ +Per-cog error handling comes in very handy as you can relegate all of your error handling to a single function instead +of spreading it out across several per-command error handlers or inside the commands themselves. + +## Global Handling + +If separating your error handling is not how you would like to handle errors, then global error handling is the way to +go. This method of handling allows you to relegate all handling to a single function that resides within your bot +instance. + +A non-subclassed bot would implement this like so: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot() + + +@bot.slash_command(description="Get the bot's current latency!") +@commands.cooldown(1, 30, commands.BucketType.user) +# ^ This decorator allows one usage of the command every 30 seconds and raises commands.CommandOnCooldown if exceeded +async def ping(ctx: discord.ApplicationContext): + await ctx.respond(f"Pong! `{int(bot.latency*1000)} ms`.") + + +@bot.event +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.CommandOnCooldown): + await ctx.respond("This command is currently on cooldown!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If you've subclassed your bot, the `on_application_command_error` event will be placed inside the subclass without a +`bot.event` decorator and `bot.slash_command` will be replaced with `discord.slash_command`. + +The error handling used above will yield this interaction if the command is used again too quickly: + + + +
+ + ping + +
+ Pong! 49 ms. +
+ +
+ + ping + +
+ This command is currently on cooldown! +
+
+
+ +The only issue regarding global error handling is that, if you have a large amount of commands, the global handler may +start to get crammed with a lot of code. This is where all the previously mentioned handlers can take their place! + +## FAQ + +#### Why does the example in per-cog handling have self at the start of its function signatures? + +This is a feature of classes and allows you to reference the cog object as `self` and get access to the bot object +passed at initialization through `self.bot`. + +If this is new to you, we recommend checking out these helpful resources to learn more about classes and cogs: + +- [W3Schools' Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [Our Cogs Guide Page](./cogs) + +#### How many errors can I handle in a single error handler? + +While all the examples in this guide page only handle one specific error and re-raise all others, all of these +error handlers can be extended to catch many errors. + +In [basic handling](#basic) (i.e. try/except statements) you can do one of two things: + +- Explicitly handle the errors you know might get raised and then have a broad `except Exception as exc:` statement + as a catch-all. +- Catch any and all errors via the catch-all statement mentioned above. + +In [per-command](#percommand), [per-cog](#percog), and [global handling](#global), you can use elif clauses with the +built-in isinstance function to catch specific errors. Atop of this, an else clause can be used to catch any other +errors you either don't want to handle or want to relegate to a different error handler. + +#### Can I use more than one type of error handler at once? + +Thankfully, all of these different ways of error handling can be mixed together, so you don't have to pick just one! +For commands that raise specific errors that no other commands will raise, you can use [per-command](#percommand). +For cogs that raise specific errors that no other cogs will raise, use [per-cog](#percog)! Lastly, for errors that +occur frequently across all commands and cogs, use [global handling](#global)! + +However, one important note to remember is that you should always raise the error again in an error handler if it +isn't handled there! If you don't do this, the error will go ignored and your other handlers won't have a chance to +do their work! + +#### What's the difference between slash and prefixed command error handling? + +Although most examples shown here use slash commands, the [per-cog handling](#percog) section presents a prefixed +command. The main difference you may notice is the change in command signature. + +To make the distinguishing features apparent: + +- Slash commands use `on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException)` + as presented in the [per-command](#percommand) and [global handling](#global) examples. +- Prefixed commands use `on_command_error(ctx: commands.Context, error: commands.CommandError)` as presented in the + [per-cog handling](#percog) example. + +This distinction is made as both types of commands need their own system for handling errors that are specific to +themselves. + +:::info Related Topics + +- [Slash Commands](../interactions/application-commands/slash-commands) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Cogs](./cogs) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx new file mode 100644 index 00000000..9f4210af --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx @@ -0,0 +1,62 @@ +--- +title: Intents +description: All about intents in Discord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +## What are Intents? + +Intents allow bot developers to "subscribe" to specific events in Discord. This is useful for bots that need to respond to specific events, such as when a user joins a server or sends a message. You could choose to enable all intents or to enable only specific intents that your bot requires. + +## How do I enable intents? + +:::important + +Remember that [Privileged Intents](#what-are-privileged-intents) require you to enable them in the Discord Developer Portal. Verified Discord Bots that don't already have access to them will need to request Discord to allow access. + +::: + + + + +```python +import discord + +bot = discord.Bot(intents=discord.Intents.all()) +``` + + + + + +You can view a list of intents and the events they subscribe to [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```python title="Enabling Intents" +import discord + +bot = discord.Bot(intents=discord.intents.members(bans=True, guilds=True)) +``` + + + + +## What are Privileged Intents? + +Discord defines some intents as "privileged" because of the sensitive information they contain. Currently, there are three privileged intents: `members`, `presences`, and `message_content`. These intents must be enabled in your bot's Developer Portal. Once your bot reaches 100 servers, you will need to verify your bot for these intents to keep working and for your bot to be able to be invited to more guilds. + +:::tip + +Only enable these intents if you need them. These intents give your bot access to quite sensitive information about the users in your guild. These intents are privileged to respect the privacy of users, and you should do that as well. + +Not enabling these intents doesn't mean you won't be able to ban users, but you will be unable to detect when a new user joins a guild, or what game they are playing. The majority of bots won't need all intents. + +::: + +:::info Related Topics + +- [Sharding Bots](sharding) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx new file mode 100644 index 00000000..c3d17197 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx @@ -0,0 +1,48 @@ +--- +title: Sharding +description: All about Sharding Discord Bots. +--- + +# Sharding + +## What is Sharding? + +Sharding is the process of breaking up your bot into smaller pieces so that it has a better time handling +events. As [Discord's Documentation](https://discord.com/developers/docs/topics/gateway#sharding) puts +it, sharding is "a method of user-controlled guild sharding which allows for splitting events across +several gateway connections." + +Sharding is used only for large bots and takes up additional resources for managing the new processes. +Pycord automatically shards your bot, so the only thing you need to do is use an `AutoShardedClient` +or `AutoShardedBot` class instead of a plain `Client` or `Bot` class. Pretty cool, right? + +Just because you _can_ shard your bot doesn't mean you _should_. While Pycord makes it easy to shard +your bot, it isn't necessary to shard unless your bot is large. Sharding a small bot isn't +just useless, but _harmful_, as it uses extra resources and may slow down your bot. Discord +themselves will let you know when your bot needs sharding, so you won't need to worry about this until they contact you. + +## How Do I Shard in Pycord? + +Sharding in Pycord is straightforward. + +Just replace your `discord.Client`, `discord.Bot`, `commands.Bot` objects +with `discord.AutoShardedClient`, `discord.AutoShardedBot`, `commands.AutoShardedBot` respectively. + +These new objects have been inherited from the original objects, so all the functions from those other types should be present. + +If you want to specify the number of shards your bot uses, +just add the `shards` parameter, along with the number of shards you want. + +## Why Should I Shard my Bot? + +Sharding is very necessary for big bots. While your bot grows, it gets harder for your bot to control +how many guilds it is in and what parts of your code should do what. This is exactly what sharding +handles, it makes all of this easier for your bot. Remember, though, only shard your bot once it's +big enough, and that's at _least_ 1,000 guilds. + +:::info Related Topics + +- [Hosting your Bot](../Getting-Started/hosting-your-bot) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx new file mode 100644 index 00000000..bd2969c1 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx @@ -0,0 +1,115 @@ +--- +title: Subclassing Bots +description: Subclassing is a popular way of creating Discord Bots. Explore how you can create a Discord bot by subclassing. +--- + +## About + +Subclassing is another popular way of creating Discord Bots. Here, you create a bot by extending a bot class. To some advanced users, this is preferable to creating a bot instance with `bot = discord.Bot()`. + +Subclassing is an intermediate python concept, so we recommend you learn about it before continuing. Some good resources are: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +## Why Subclassing? + +Many developers prefer to subclass their bots for many reasons, some of them being: + +#### Skeletal Frameworks for Bots + +Developers often share their bots code on open-source platforms, mostly GitHub, and allow users to self-host the bot (running their own instance of the bot with the code provided by the developer. Permissions vary in accordance to licences). Here, users find it easier and more convenient to have a small file that imports the custom bot class and runs it, rather than having to go through the code of the bot and find out which file to run. This makes it easier for people not familiar with programming to run and customize the bot, since it often brings down the code to: + +```python title="./main.py" +from src import Bot + +bot = Bot() + +bot.run("TOKEN") +``` + +Here, all the commands are inside the `/src` folder that the user need not bother with. + +#### Running Multiple Instances + +Some developers may need to run multiple instances of their bot (perhaps on different bot accounts). For example, a developer might have a second bot for testing alpha features. This system makes it simpler for the developer, and allows them to maintain multiple versions of the bot in the same directory: + +```python title="./alpha_bot.py" +from src import Bot + +class AlphaBot(Bot): # subclasses Bot + ... # insert any custom configuration + +bot = AlphaBot() + +@bot.slash_command() # adds a new slash command to this subclassed bot +async def alpha_feature(ctx): + await ctx.respond("Alpha Feature!") + +bot.run("TOKEN") +``` + +There are many more reasons to subclass! It's not required, and won't affect the speed of the bot, but it may affect your development process, for the good or for the worse. You don't miss out on any features when you subclass, either. Some developers want the OOP feel, while some just prefer that method and find it easier. + +## Basic Example + +```python +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override the on_ready event + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') + +bot = MyBot() + +@bot.slash_command() # create a slash command +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run('token') +``` + +As you can see, instead of creating a bot object with `bot = discord.Bot()`, we subclass [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). We then create an instance of our new bot class and run it. Notice how we don't need to use the `@event` decorator. + +Here's another example: + +```python title="./src/bot.py" +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override on_ready + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') +``` + +```python title="./src/\_\_init\_\_.py" +from .bot import MyBot # import the MyBot class from the bot.py file +``` + +```python title="./main.py" +from src import MyBot # import MyBot from /src + +bot = MyBot() # create an instance of MyBot + +@bot.slash_command() +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run("TOKEN") # run the bot +``` + +These are just two ways you could do it. There are ton of other structures you can implement. It's up to you. + +So, should you subclass? There are no limitations you face if you decide to subclass your bot, but, once again, it's up to you. + +:::info Related Topics + +- [Making a Help Command](../Extensions/Commands/help-command) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx new file mode 100644 index 00000000..23220b0e --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx @@ -0,0 +1,105 @@ +--- +title: Threads +description: Threads with Pycord +--- + +In programming, threads are a way to run multiple processes at the same time. In Discord, threads are +a way to keep multiple conversations going at the same time. Let's take a brief look at how to use threads in Pycord. + +:::tip + +Not all the methods and attributes will be covered in this guide, but you can find them in our documentation! +[Check it out!](https://docs.pycord.dev/en/stable/api/models.html#discord.Thread) + +::: + +## Creating a thread + +With a few simple lines of code, we can create threads in Pycord. + +:::important + +All public threads need a starting message. This message will start the thread. However, private threads +(which are unlocked with having your server boosted to Level 2), do not require a starting message. + +::: + +### Creating thread from a message + +```python title="Creating a Thread from a Message" +message = await ctx.send("My Starting Message") +await message.create_thread(name="thread name", auto_archive_duration=60) +``` + +You may also use other ways to create the thread, for example, by using `on_message` events or by commands. + +### Creating thread in a channel + +```python title="Creating a Thread from a Channel" +channel = bot.get_channel(...) # define this! +await channel.create_thread(name="Thread Name", message=None, auto_archive_duration=60, type=None, reason=None) +``` + +A thread type could be `news_thread`, `public_thread`, `private_thread`. You may use it by passing `type=discord.ChannelType.news_thread`. + +## Deleting Threads + +Deleting Threads is simple. You need to get a thread and then use the `delete` method. + +```python title="Deleting a Thread" +thread = bot.get_channel(thread_id) # you could use other ways to get a thread +await thread.delete() +``` + +## Editing Threads + +**Parameters** + +- `name` (str) – The new name of the thread + +- `archived` (bool) – Whether to archive the thread or not. + +- `locked` (bool) – Whether to lock the thread or not. + +- `invitable` (bool) – Whether non-moderators can add other non-moderators to this thread. Only available for private threads. + +- `auto_archive_duration` (int) – The new duration in minutes before a thread gets automatically archived for inactivity. Must be one of 60, 1440, 4320, or 10080. + +- `slowmode_delay` (int) – Specifies the slow-mode rate limit for users in the thread, in seconds. A value of 0 disables slow-mode. The maximum value possible is 21600. + +```python title="Editing a Thread" +thread = bot.get_channel(id) +await thread.edit( + name="New Name", + archived=True, + locked=True, + slowmode_delay=10, + auto_archive_duration=60, +) +``` + +As you can see, threads are very simple. Once you learn how to use them, it's easy to create whatever you want. + +## FAQ + +### Why am I getting a `Forbidden` error when I try to create a thread? + +A `Forbidden` error occurs when the bot does not have the correct permissions to create threads. + +### Why am I getting an Unknown Message error when I try to create a thread? + +Getting an error looking something like `discord.ext.commands.errors.CommandInvokeError: Command +raised an exception: HTTPException: 400 Bad Request (error code: 10008): Unknown Message`? + +There could be multiple reasons, some of them being: + +- The message does not exist +- The message already has a thread +- The message is in channel x, you are trying to start a thread in channel y. +- The message was deleted. + +:::info Related Topics + +<>{/* I can't think of any related topics for this at the moment. */} + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/voice/_category_.json b/i18n/it/docusaurus-plugin-content-docs/current/voice/_category_.json new file mode 100644 index 00000000..8baf3da8 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/voice/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 6, + "label": "Voice" +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/voice/index.mdx b/i18n/it/docusaurus-plugin-content-docs/current/voice/index.mdx new file mode 100644 index 00000000..835838c6 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/voice/index.mdx @@ -0,0 +1,24 @@ +--- +title: Voice +--- + +Welcome to the guide for voice features in Pycord. + +:::caution +This guide requires previous experience with Pycord and Python. +::: + +## Requirements + +The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). +The following features are optional: + +:::tip +Opus is also a required library, but this comes with Pycord. +Some hosts may not come with it, though, so remember to always check if required dependencies are installed. +::: + +- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` +- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), + [`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), + [`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. diff --git a/i18n/it/docusaurus-plugin-content-docs/current/voice/playing.mdx b/i18n/it/docusaurus-plugin-content-docs/current/voice/playing.mdx new file mode 100644 index 00000000..fe14c52a --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/voice/playing.mdx @@ -0,0 +1,149 @@ +--- +title: Wavelink Audio Player +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { + defaultOptions, +} from "@site/src/components/DiscordComponent"; + +# About + +Pycord and Wavelink try to keep the playing of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio playing feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/). + +## Starting out + +First you need to run a [Lavalink Server](https://github.com/freyacodes/Lavalink) to connect with. +There a multiple documentations to do this, so we are not covering that here. + +You also need to install the [wavelink](https://github.com/PythonistaGuild/Wavelink) library. + +```py title="Installing wavelink" +python3 -m pip install wavelink +``` + +You will now want to connect to your server via a node. + +```py title="Connect Node with Lavalink" +import discord +import wavelink + +bot = discord.Bot() + +async def connect_nodes(): + """Connect to our Lavalink nodes.""" + await bot.wait_until_ready() # wait until the bot is ready + + nodes = [ + wavelink.Node( + identifier="Node1", # This identifier must be unique for all the nodes you are going to use + uri="http://0.0.0.0:443", # Protocol (http/s) is required, port must be 443 as it is the one lavalink uses + password="youshallnotpass" + ) + ] + + await wavelink.Pool.connect(nodes=nodes, client=bot) # Connect our nodes +``` + +
+ +Now you are finished making your node! Next, you will want to: + +1. Making a play command +2. Adding connect events + +### Making a play command + +To make a play command, you will need to make a function to connect and play audio in a voice channel. + +```py title="Play Command Example" +import typing + +@bot.slash_command(name="play") +async def play(ctx, search: str): + # First we may define our voice client, + # for this, we are going to use typing.cast() + # function just for the type checker know that + # `ctx.voice_client` is going to be from type + # `wavelink.Player` + vc = typing.cast(wavelink.Player, ctx.voice_client) + + if not vc: # We firstly check if there is a voice client + vc = await ctx.author.voice.channel.connect(cls=wavelink.Player) # If there isn't, we connect it to the channel + + # Now we are going to check if the invoker of the command + # is in the same voice channel than the voice client, when defined. + # If not, we return an error message. + if ctx.author.voice.channel.id != vc.channel.id: + return await ctx.respond("You must be in the same voice channel as the bot.") + + # Now we search for the song. You can optionally + # pass the "source" keyword, of type "wavelink.TrackSource" + song = await wavelink.Playable.search(search) + + if not song: # In case the song is not found + return await ctx.respond("No song found.") # we return an error message + + await vc.play(song) # Else, we play it + await ctx.respond(f"Now playing: `{song.title}`") # and return a success message +``` + + + +
+ + play + +
+ Now playing: Never Gonna Give You Up +
+
+ +
+ +Now that you've done this, the only thing left to do is make your connect events. + +### Adding connect events + +The final step to this guide is connecting the node to your server when the bot goes online. + +To make it, you will want to do the following: + +```py title="Adding connect events" +@bot.event +async def on_ready(): + await connect_nodes() # connect to the server + +@bot.event +async def on_wavelink_node_ready(payload: wavelink.NodeReadyEventPayload): + # Everytime a node is successfully connected, we + # will print a message letting it know. + print(f"Node with ID {payload.session_id} has connected") + print(f"Resumed session: {payload.resumed}") + +bot.run("token") +``` + +Congratulations! You have now implemented voice playing into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/voice/receiving.mdx b/i18n/it/docusaurus-plugin-content-docs/current/voice/receiving.mdx new file mode 100644 index 00000000..1bc364e1 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/voice/receiving.mdx @@ -0,0 +1,130 @@ +--- +title: Receiving Voice Samples +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +# About + +Pycord tries to keep the recording of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio recording feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/audio_recording.py). + +## Starting out + +The first thing you want to do is make a cache of your voice connections. This is fairly easy; as +it's just putting a variable with an empty dictionary in our code, such as `connections = {}`. + +You will now want to create your command for recording. + +```py title="Record Command Example" +import discord + +bot = discord.Bot() +connections = {} + +@bot.command() +async def record(ctx): # If you're using commands.Bot, this will also work. + voice = ctx.author.voice + + if not voice: + await ctx.respond("You aren't in a voice channel!") + + vc = await voice.channel.connect() # Connect to the voice channel the author is in. + connections.update({ctx.guild.id: vc}) # Updating the cache with the guild and channel. + + vc.start_recording( + discord.sinks.WaveSink(), # The sink type to use. + once_done, # What to do once done. + ctx.channel # The channel to disconnect from. + ) + await ctx.respond("Started recording!") +``` + + + +
+ + record + +
+ Started recording! +
+
+ +
+ +Now you are finished making your command for voice receiving! Next, you will want to: + +1. Make your finished callback +2. Make a stop command + +### Making a Callback + +To make a callback, you will want to define the currently undefined `once_done` function inside +our command, like so: + +```py title="Recorder Callback" +async def once_done(sink: discord.sinks, channel: discord.TextChannel, *args): # Our voice client already passes these in. + recorded_users = [ # A list of recorded users + f"<@{user_id}>" + for user_id, audio in sink.audio_data.items() + ] + await sink.vc.disconnect() # Disconnect from the voice channel. + files = [discord.File(audio.file, f"{user_id}.{sink.encoding}") for user_id, audio in sink.audio_data.items()] # List down the files. + await channel.send(f"finished recording audio for: {', '.join(recorded_users)}.", files=files) # Send a message with the accumulated files. +``` + + + + finished recording audio for:{" "} + {defaultOptions.profiles.bob.author} + + + +
+ +Now that you've done this, the only thing left to do is make your stop command. + +### Making a Stop Command + +The final step to this guide is stopping the audio recording. This is the easiest step by far. + +To make it, you will want to do the following: + +```py title="Stop Recording Command" +@bot.command() +async def stop_recording(ctx): + if ctx.guild.id in connections: # Check if the guild is in the cache. + vc = connections[ctx.guild.id] + vc.stop_recording() # Stop recording, and call the callback (once_done). + del connections[ctx.guild.id] # Remove the guild from the cache. + await ctx.delete() # And delete. + else: + await ctx.respond("I am currently not recording here.") # Respond with this if we aren't recording. + +bot.run("token") +``` + +Congratulations! You have now implemented voice recording into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/it/docusaurus-plugin-content-pagesindex.tsx b/i18n/it/docusaurus-plugin-content-pagesindex.tsx new file mode 100644 index 00000000..84df3a9c --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-pagesindex.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import DefaultLayout from "../layouts/DefaultLayout"; +import PYCHero from "@site/src/components/PYCHero"; +import PYCButton from "@site/src/components/PYCButton"; + +export default function Home(): JSX.Element { + return ( + + +
+ Imagine a place where you can learn how to create an awesome Discord + bot, equip it with Pycord, and have it running in less than a minute. + Imagine a place where you can learn everything about Pycord. Imagine a + guide. A Pycord Guide! +

+ Whether you are a newbie or an experienced developer, you will find + everything you need to know about Pycord here. This guide will teach + you: +
    +
  • How to get a brand new bot running from scratch;
  • +
  • How to create Interactions, Context Menus and Commands;
  • +
  • In-depth concepts such as Embeds, Reactions, Help Commands, Paginators, etc;
  • +
  • Popular Topics such as working with Databases, Sharding, etc;
  • +
  • Ways to handle and manage common errors and best practices for bots;
  • +
  • And Much More!
  • +
+
+
+ ); +} diff --git a/i18n/it/docusaurus-theme-classic/footer.json b/i18n/it/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..ffb8a652 --- /dev/null +++ b/i18n/it/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Pycord Development, All rights reserved.", + "description": "The footer copyright" + } +} diff --git a/i18n/it/docusaurus-theme-classic/navbar.json b/i18n/it/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..473b847e --- /dev/null +++ b/i18n/it/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "Pycord Guide", + "description": "The title in the navbar" + }, + "item.label.Home": { + "message": "Home", + "description": "Navbar item with label Home" + }, + "item.label.Docs": { + "message": "Docs", + "description": "Navbar item with label Docs" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + }, + "item.label.Source": { + "message": "Source", + "description": "Navbar item with label Source" + } +} diff --git a/i18n/ja/code.json b/i18n/ja/code.json new file mode 100644 index 00000000..9cce6148 --- /dev/null +++ b/i18n/ja/code.json @@ -0,0 +1,404 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { + "message": "Toggle the collapsible sidebar category '{label}'", + "description": "The ARIA label to toggle the collapsible sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search here", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.algoliaLabel": { + "message": "Search by Algolia", + "description": "The ARIA label for Algolia mention" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorite", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "You might want to check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Algolia" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Try searching for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Believe this query should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/i18n/ja/docusaurus-plugin-content-blog/options.json b/i18n/ja/docusaurus-plugin-content-blog/options.json new file mode 100644 index 00000000..9239ff70 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/ja/docusaurus-plugin-content-docs/current.json b/i18n/ja/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..36b4849a --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,46 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.defaultSidebar.category.Getting Started": { + "message": "Getting Started", + "description": "The label for category Getting Started in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Interactions": { + "message": "Interactions", + "description": "The label for category Interactions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Application Commands": { + "message": "Application Commands", + "description": "The label for category Application Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.UI Components": { + "message": "UI Components", + "description": "The label for category UI Components in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Extensions": { + "message": "Extensions", + "description": "The label for category Extensions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Commands": { + "message": "Commands", + "description": "The label for category Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Pages": { + "message": "Pages", + "description": "The label for category Pages in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Voice": { + "message": "Voice", + "description": "The label for category Voice in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Popular Topics": { + "message": "Popular Topics", + "description": "The label for category Popular Topics in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.More": { + "message": "More", + "description": "The label for category More in sidebar defaultSidebar" + } +} diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png b/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png new file mode 100644 index 00000000..7480e1da Binary files /dev/null and b/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png differ diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg b/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg new file mode 100644 index 00000000..ce6b5110 Binary files /dev/null and b/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg differ diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png b/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png new file mode 100644 index 00000000..846eee15 Binary files /dev/null and b/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png differ diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png b/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png new file mode 100644 index 00000000..32a47d04 Binary files /dev/null and b/i18n/ja/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png differ diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/_category_.json new file mode 100644 index 00000000..309b494a --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 5, + "label": "Extensions", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json new file mode 100644 index 00000000..652aa4ee --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Bridge" +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx new file mode 100644 index 00000000..81545fa2 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx @@ -0,0 +1,190 @@ +--- +title: Bridge +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +## Concept + +Let's say that you want to make a command that is both a Slash Command and a Prefixed Command. Now, you could just copy and paste the code from the first command callback to the other and make some adjustments, but that's not very efficient. + +This is where the `ext.bridge` module comes in. It allows you to use one callback to make both a Slash Command and a Prefixed Command. + +### Example Usage + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def hello(ctx): + await ctx.respond("Hello!") + +bot.run("TOKEN") +``` + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+
+ +## Syntax + +First, instead of using `discord.Bot` or `commands.Bot`, we use `bridge.Bot`. `bridge.Bot` does inherit from `commands.Bot`, so you can do anything with `bridge.Bot` that `commands.Bot` can do. +Then, we define a command with `@bot.bridge_command()`. This makes a Bridge Command, which has both a Prefixed Command counterpart and a Slash Command counterpart. +Next, the callback has access to a `ctx` object, which is the context of the command. This context is either of `BridgeApplicationContext` type or `BridgeExtContext`. Because of that, it makes detecting how the function was called easier. + +### Using Bridge Commands in a Cog + +Like Slash Commands and Prefixed Commands, you can use Bridge Commands in a Cog. You can do this by using the `bridge_command` decorator. Here's an example: + +```python +import discord +from discord.ext import bridge, commands + +class Greetings(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @bridge.bridge_command() + async def hello(self, ctx): + await ctx.respond("Hello!") + + @bridge.bridge_command() + async def bye(self, ctx): + await ctx.respond("Bye!") + +def setup(bot): + bot.add_cog(Greetings(bot)) +``` + +The cog will automatically split the Bridge Command into their Slash Command and Prefixed Command counterparts. + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+ + +
+ + bye + +
+ Bye! +
+ + + !bye + + + +
+ + !bye + +
+ Bye! +
+
+ +### Deferring + +You can defer if you want to communicate to the user that your bot is busy processing the command. This is done by using `ctx.defer()`. For the Slash Command implementation, `ctx.defer()` calls the function that gives out a "Bot is thinking" message. For the Prefixed Command implementation, `ctx.defer()` enables the typing indicator. + + + +### Options + +Options are pretty straightforward. You just specify them like you do with prefixed commands, and you're all set! + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def sum(ctx, a: int, b: int): + await ctx.respond(a + b) + +bot.run("TOKEN") +``` + + + +
+ + sum + +
+ 4 +
+ + + !sum 2 2 + + + +
+ + !sum 2 2 + +
+ 4 +
+
diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json new file mode 100644 index 00000000..63f8e08e --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx new file mode 100644 index 00000000..bf345c07 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx @@ -0,0 +1,56 @@ +--- +title: Command Groups +--- + +Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk +remove`. + +## Syntax + +Creating a command group is very simple. + +```python title="Command Groups Example" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!') + +@bot.group() +async def afk(): + pass + +@afk.command() +async def set(): + ... + +@afk.command() +async def remove(): + ... + +# Another command group + +@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. +async def math(ctx): + await ctx.send('Subcommand not found') + +@math.command() +async def add(ctx, a: int, b: int): + ... + +@math.command() +async def subtract(ctx, a: int, b: int): + ... +``` + +To create a command group, the command's decorator must be `@bot.group`. Once you have a command with +that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand +groups! + + + +:::info Related Topics + +- [Prefixed Commands](./prefixed-commands.mdx) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx new file mode 100644 index 00000000..acbdc0a8 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx @@ -0,0 +1,481 @@ +--- +title: Help Command +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Pycord's `commands` extension comes with a built-in help command. In this guide, we will take a look at them as well as learn how to create your own. Let's dive in! + +:::note + +This guide demonstrates using object-oriented programming and subclassing to make a help command for your +Pycord bot. It is important to understand these two concepts before continuing. + +**Learning Resources**: + +- [W3Schools - Python Subclassing](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools - Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +::: + +## The Wrong Way + +A popular way to create a help command is to disable the built-in help command and create your own. This is not recommended as it will lead to a lot of confusion. + +```python title="The Wrong Way" +bot = commands.Bot(command_prefix='!', help_command=None) +# OR +bot.help_command = None +# OR +bot.remove_command("help") + +@bot.command() +async def help(ctx, *, argument=None): + ... +``` + +While it's possible to create a help command this way, doing so does not utilize the full capabilities +of making one with Pycord. Making a help command with subclassing and OOP will save time and effort. + +## Types of Help Commands + +There are two types of built-in help commands: + +- [`DefaultHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand) +- [`MinimalHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand) + +`DefaultHelpCommand` is the command enabled by default. It isn't the best looking, but `MinimalHelpCommand` can help make it look a bit better. + + + + +```python title="Default Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.DefaultHelpCommand()) # help_command is DefaultHelpCommand by default so it isn't necessary to enable it like this +# We enable it here for the sake of understanding + +... + +bot.run("token") +``` + + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ + +```python title="Minimal Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.MinimalHelpCommand()) + +... + +bot.run("token") +``` + + + + !help + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+ +
+ +
+ +## Updating Built-in Help Commands + +Let's try to make the `MinimalHelpCommand` look better. We can do this by putting its content in an +embed. + +```python title="Minimal Help Command Example" +bot = commands.Bot(command_prefix='!') + + +class MyNewHelp(commands.MinimalHelpCommand): + async def send_pages(self): + destination = self.get_destination() + for page in self.paginator.pages: + emby = discord.Embed(description=page) + await destination.send(embed=emby) + +bot.help_command = MyNewHelp() +``` + +Let's go through the code. + +First, we create a new class called `MyNewHelp`. This class is a subclass of `MinimalHelpCommand`. + +Next, we override the `send_pages` method. This method is responsible for sending the help command to +the user. We override this method because we don't want to change the content of the pages, just how +they are sent. + +We use the `get_destination` method to get the destination of the message. This is the channel or use that the help +command is to be sent to. + +We use the `paginator.pages` property to get the different pages of the help command. We put the page +in an embed, and then send the embed to the destination channel. + +Finally, we set this as our new help command using `bot.help_command = MyNewHelp()`. + + + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a + category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+
+ +## Creating Your Help Command + +Not satisfied with the built-in help commands? You can create your own! + +For this, we will subclass the `HelpCommand` class. + +There are 4 methods that we need to override: + +- `HelpCommand.send_bot_help(mapping)` that gets called with `help` +- `HelpCommand.send_command_help(command)` that gets called with `help ` +- `HelpCommand.send_group_help(group)` that gets called with `help ` +- `HelpCommand.send_cog_help(cog)` that gets called with `help ` + +### Bot Help + +```python title="Bot Help Example" +class MyHelp(commands.HelpCommand): + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help") + for cog, commands in mapping.items(): + command_signatures = [self.get_command_signature(c) for c in commands] + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's go through the code. + +- First, we create a new class called `MyHelp`. This class is a subclass of `HelpCommand`. + +- Next, we override the `send_bot_help` method. This method is responsible for sending the main help + command to the user. + +- We create an embed with the title "Help". + +- We iterate through `mapping.items()`, which returns a list of tuples, the first element being the + cog and the second element being a list of commands. + +- By using `self.get_command_signature(c)` we get the signature of the command, also known as the + `parameters` or `arguments`. + +- There is a chance that the cog is empty, so we use `if command_signatures:`. + +- We get the name of the cog using `getattr(cog, "qualified_name", "No Category")`. This calls the + cog's attribute `qualified_name` which returns "No Category" if the cog has no name. + +- We add a field to the embed with the name of the cog and the value of the command signatures. + +- Finally, we send the embed to the channel. + +Let's improve the code a little. + +```python title="Improved Bot Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + command_signatures = [self.get_command_signature(c) for c in filtered] + + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Now the help command won't show commands that the user can't use, as well as aliases for commands. +Let's get the help command to show command aliases. + +### Command Help + +This function is called when the user uses `help `. + +```python title="Command Help Example" +class MyHelp(commands.HelpCommand): + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command), color=discord.Color.random()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's quickly go through the code we haven't discussed yet. + +- In line 3, we create an embed with a title the signature of the command (so that the title of the + embed looks like ` [parameter]`), and a random color. + +- In lines 4 and 5, we get the command's `help` description and add it to the embed. The help description + of a command can be specified in the docstrings of a command function. For example: + + ```` + ```python + @bot.command() + async def ping(ctx): + """Returns the latency of the bot.""" + await ctx.send(f"Pong! {round(bot.latency * 1000)}ms") + ``` + ```` + +- Line 6 is shorthand for + + ```python + alias = command.aliases + if alias: + ... + + # is the same as + + if alias := command.aliases: + ... + ``` + + A very helpful (but not well-known) Python shorthand! + +- In line 7, we get the aliases of the command and add them to the embed. + +### Cog Help + +This is pretty easy! + +```python title="Custom Cog Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_cog_help(self, cog): + embed = discord.Embed(title=cog.qualified_name or "No Category", description=cog.description, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(cog.get_commands()): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Once again, we create an embed, get the commands that the user can use, and add them to the embed. + +### Group Help + +Similar to the cog help, this is pretty easy! + +```python title = "Custom Group Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_group_help(self, group): + embed = discord.Embed(title=self.get_command_signature(group), description=group.help, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(group.commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Add all of these methods together, and you have a fully functioning help command! + +
+Click to see the final code for this section +
+ +:::note + +The following code has been slightly edited from the tutorial version. + +::: + +```python title="Custom Help Command Example" +class SupremeHelpCommand(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + if command_signatures := [ + self.get_command_signature(c) for c in filtered + ]: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command) , color=discord.Color.blurple()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_help_embed(self, title, description, commands): # a helper function to add commands to an embed + embed = discord.Embed(title=title, description=description or "No help found...") + + if filtered_commands := await self.filter_commands(commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No help found...") + + await self.get_destination().send(embed=embed) + + async def send_group_help(self, group): + title = self.get_command_signature(group) + await self.send_help_embed(title, group.help, group.commands) + + async def send_cog_help(self, cog): + title = cog.qualified_name or "No" + await self.send_help_embed(f'{title} Category', cog.description, cog.get_commands()) + +bot.help_command = SupremeHelpCommand() +``` + +
+
+ +## Command Attributes + +How can you add cooldowns, set aliases, and change the name of help commands? Command attributes can +help you do all of that, and more! + +```python title="Help Command Attributes" +attributes = { + 'name': "help", + 'aliases': ["helpme"], + 'cooldown': commands.CooldownMapping.from_cooldown(3, 5, commands.BucketType.user), +} + +# You need to use CooldownMapping.from_cooldown(rate, per, type) + +bot.help_command = MyHelp(command_attrs=attributes) +``` + +## Error Handling + +When a user attempts to use a command that does not exist, we need to inform the user. +We can do this by overriding the `send_error_message` function. + +```python title="Custom Help Error Example" +class MyHelp(commands.HelpCommand): + async def send_error_message(self, error): + embed = discord.Embed(title="Error", description=error, color=discord.Color.red()) + channel = self.get_destination() + + await channel.send(embed=embed) +``` + + + + !help update_pycord + + + + Command 'update_pycord' not found. + + + + +## Credits + +Most of the content from this guide is from +[InterStella0's walkthrough guide on subclassing HelpCommand](https://gist.github.com/InterStella0/b78488fb28cadf279dfd3164b9f0cf96). +Thanks to InterStella0 for making this guide amazing. + +:::info Related Topics + +- [Subclassing Bots](../../Popular-Topics/subclassing-bots) +- [Prefixed Commands](./prefixed-commands) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx new file mode 100644 index 00000000..b8f567fd --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx @@ -0,0 +1,324 @@ +--- +title: Prefixed Commands +description: Learn how to use the commands extension for Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Before Discord added slash commands, all bots had prefixed commands. A user would type the bot's prefix +followed by a word or phrase to invoke a command, such as `?help` or `!help`. +However, this prefixed commands system isn't native to Discord! Developers made use of an `on_message` +event to check if the message began with a certain character, then invoke the command. Every time a +message was sent, the bot would see the message and check for its "prefix" + +The syntax becomes a little more complicated when you want to have multiple commands. There are several +disadvantages to this system. This is where the commands extension comes in. `ext.commands` has +various advantages, such as: + +- Simpler syntax +- Easier to use +- Easier to parse user input +- Comes with built-in help commands +- Comes with a built-in system for categorizing commands + + + + +```python title="Prefixed Commands with Events" +import discord + +client = discord.Client() + +@client.event +async def on_message(message): + if message.content.startswith("!ping"): + await message.channel.send("Pong!") + + elif message.content.startswith("!announce"): + if len(message.content.split(" ")) < 3: + await message.channel.send("You need to specify a title and a message. Correct usage: `!announce Hello Hello everyone!`") + return + + msg = message.content.split(" ", 2) + title = msg[1] + content = msg[2] + + await message.channel.send("**{}**\n{}".format(title, content)) + + elif message.content.startswith("!"): + await message.channel.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !help + + + Unknown Command. + +
+ +
+ + +```python title="The Commands Extension" +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix="!", intents=intents) + +@bot.command() +async def ping(ctx): + await ctx.send("Pong!") + +@bot.command() +async def announce(ctx, title, *, message): + await ctx.send("**{}**\n{}".format(title, message)) + +@bot.event +async def on_command_error(ctx, error): + if isinstance(error, commands.CommandNotFound): + await ctx.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !pycord + + + Unknown command. + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+ !announce +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The commands extension has many more uses. This example only showcases the basic features mentioned +in the previous example. Other things you can do with the commands extension include using a different +built-in help command and creating your own. The following tutorials showcase these. + +::: + +
+
+ +## Syntax + +Before we check out the syntax, let's take a look at the bot classes. + +> `discord.Client` - Contains only events. +> +> `discord.Bot` - Subclasses `discord.Client`, adds commands. +> +> `discord.ext.commands.Bot` - Subclasses `discord.Bot`, adds prefixed commands, cogs, and more. + +This means that `discord.ext.commands.Bot` has both slash commands and prefixed commands, as well as +events, cogs and more. + +Now let's look at the syntax. + +```python title="A Simple Prefixed Bot" +import discord +from discord.ext import commands # Import the commands extension +# discord.ext.commands are not the same as discord.commands! + +intents = discord.Intents.default() #Defining intents +intents.message_content = True # Adding the message_content intent so that the bot can read user messages + +bot = commands.Bot(command_prefix="!", intents=intents) # You can change the command prefix to whatever you want. + +@bot.command() # This is the decorator we use to create a prefixed command. +async def ping(ctx): # This is the function we will use to create the command. + await ctx.send("Pong!") # This is the response the bot will send. + + +bot.run("token") # Run the bot with your token. +``` + + + + !ping + + + Pong! + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The help command is a built-in command and is enabled by default. You will learn more about it in the +following guides. + +::: + +## Parameters + +Prefixed commands can take parameters, just like slash commands. You can specify the parameters in +the function itself. + +```python title="Parameters Example 1" +@bot.command() +async def echo(ctx, *, message): + await ctx.send(message) +``` + +`ctx` is the context of the message. `*` means that the parameter can be any number of words. `message` +is the parameter. If you had not passed `*`, `message` would only have been one word. + +For example, if a user had used `!echo hello world`, `message` would have been `hello`. Since we +passed `*`, `message` is `hello world`, or the rest of the message. + +We can pass multiple parameters too! + +```python title="Parameters Example 2" +@bot.command() +async def echo(ctx, channel:discord.TextChannel, title, *, message): + await channel.send("**{}**\n{}".format(title, message)) +``` + +In the example above, `channel` is a parameter that is of type `discord.TextChannel`. When you +specify the type of the parameter, Pycord will automatically try to convert the parameter to that type. +That is why you can use `channel.send` directly without needing to convert it first. + +We also have a new parameter, `title`. This does not have a type, so it will be a string. `*` means +that the rest of the message belongs to the next parameter, in this case, `message`. + +When a user types `!echo #general Greetings! Hello World!`, `channel` will be the text channel +`#general`, `title` will be `Greetings!` and `message` will be `Hello World!`. + +Let's take an example where the user passes `!echo #general Holiday Greetings! Greetings to you all!`. +Here, the user wants the title to be "Holiday Greetings!" and the message to be "Greetings to you all!". +However, since Pycord parses the message at whitespaces, the title will end up being "Holiday" and the +message "Greetings! Greetings to you all!". The user can prevent this by typing `!echo "Holiday +Greetings!" Greetings to you all!`. + + + + + + !echo #general Holiday Greetings! Greetings to you all! + + + Holiday +
+ Greetings! Greetings to you all! +
+ + !echo #general "Holiday Greetings!" Greetings to you all! + + + Holiday Greetings! +
+ Greetings to you all! +
+
+ +Let's check out another example for parameters and parameter types. + +```python title="Parameters Example 3" +import random + +@bot.command() +async def gtn(ctx, guess:int): + number = random.randint(1, 10) + if guess == number: + await ctx.send("You guessed it!") + else: + await ctx.send("Nope! Better luck next time :)") +``` + +If you had not specified the type of the parameter, it would have been a string. And since `"5"` is not +the same as `5` in python, the bot would have responded with "Nope! Better luck next time :)". +Even if you do not specify the type of the parameter, you can still convert it later on, in this case, +with `int(guess)`. + +:::info Related Topics + +- [Command Groups](groups) +- [Rules and Common Practices](../../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json new file mode 100644 index 00000000..baeba701 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Pages", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx new file mode 100644 index 00000000..be90b035 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx @@ -0,0 +1,168 @@ +--- +title: Paginator Basics +--- + +# Paginator Basics + +## [Page](https://docs.pycord.dev/en/stable/ext/pages/index.html#page) + +This class contains two attributes: `content` and `embeds`, which correspond to the attributes of the same name on the +`discord.Message` class. +To create a new Page, use the following syntax: + +```py +import discord +page = Page(content="My Page Content", embeds=[discord.Embed(title="My First Embed Title")]) +``` + +## [PageGroup](https://docs.pycord.dev/en/stable/ext/pages/index.html#pagegroup) + +This class represents a group of pages. It uses most of the same parameters as `Paginator`, which allows each +`PageGroup` to effectively have its own settings and behaviours. + +## [Paginator](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator) + +This is the main class for `ext.pages`, and is used to control most of the functionality of the extension. + +In its most basic form, with no arguments provided (default values listed below), a paginator can be created like so: + +```py title="Paginator Example" +import discord +from discord.ext.pages import Paginator, Page + +my_pages = [ + Page( + content="This is my first page. It has a list of embeds and message content.", + embeds=[ + discord.Embed(title="My First Embed Title"), + discord.Embed(title="My Second Embed Title"), + ], + ), + Page( + content="This is my second page. It only has message content.", + ), + Page( + embeds=[ + discord.Embed( + title="This is my third page.", + description="It has no message content, and one embed.", + ) + ], + ), +] +paginator = Paginator(pages=my_pages) +``` + +The only required parameter for `Paginator` is the `pages` parameter, which is usually a list of `Page` objects. + +You can also pass in a list of `PageGroup` objects, a list of strings, a list of embeds, or a list of lists of embeds. + +Once the `Paginator` instance is created, you can call either +[`Paginator.send()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.send) +or [`Paginator.respond()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.respond) +to send a message or response with the paginator's contents. + +#### Depending on what's being passed to the `pages` parameter, the behaviour of the paginator may differ: + +- Passing a list of `PageGroup` objects will essentially treat each `PageGroup` as its own Paginator, with most + `Paginator` attributes able to be set independently for each `PageGroup`. + \- Each `PageGroup` accepts its own `pages` parameter, which inherits the same behaviour as the `pages` parameter + of `Paginator`, except it cannot contain other `PageGroup` objects. +- If a page is a `Page` object, this will allow you to specify both the `discord.Message.content` and + `discord.Message.embeds` attributes for a page. + \- **This is the preferred method of defining a page.** +- If a page is a string, this will be used for the `discord.Message.content` attribute. This type of page cannot have + any embeds. +- If a page is a list of embeds, this will be used for the `discord.Message.embeds` attribute. This type of page + cannot have any message content. +- If a page is a list of lists of embeds, each parent list item will create a page containing all embeds from its + child list. This type of page cannot have any message content. + +#### Parameters for the `Paginator` class which have default values: + +- `show_disabled` **:** `True` + - Show buttons that are disabled (i.e. can't be clicked) +- `author_check` **:** `True` + - Only the author can interact with the paginator. +- `timeout` **:** `180` _(seconds)_ + - The paginator will time out and become inactive after this many seconds. +- `disable_on_timeout` **:** `True` + - If the paginator times out, it will be automatically disabled and all buttons will be unusable. +- `use_default_buttons` **:** `True` + - Use the default set of 4 buttons and a page indicator. +- `show_indicator` **:** `True` + - When using the default buttons, shows a middle 5th button with the current/total page numbers. + +**For other parameters that can be set on initialization, please check the +[API Reference](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator)** + +## [PaginatorButton](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatorbutton) + +This class represents a button used to navigate between the pages of a paginator. It's also used to create the page +indicator. + +When creating your own custom buttons, you can either use this class directly or subclass it to add any additional +functionality you may need. + +To add custom buttons to the paginator instead of the default navigation buttons, you have two options to do so: + +1. **Using the `custom_buttons` parameter of `Paginator`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + buttons = [ + PaginatorButton("first", label="<<-", style=discord.ButtonStyle.green), + PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), + PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True), + PaginatorButton("next", label="->", style=discord.ButtonStyle.green), + PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), + ] + paginator = Paginator( + pages=["Page 1", "Page 2", "Page 3"], + show_indicator=True, + use_default_buttons=False, + custom_buttons=buttons, + ) + ``` +2. **Using `Paginator.add_button()`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"], use_default_buttons=False) + paginator.add_button(PaginatorButton("prev", label="<", style=discord.ButtonStyle.green)) + paginator.add_button(PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True)) + paginator.add_button(PaginatorButton("next", label=">", style=discord.ButtonStyle.green)) + ``` + +If you want to use the default navigation buttons, but not all of them, you can also use `Paginator.remove_button()` to +selectively remove them: + +```py +from discord.ext.pages import Paginator + +paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"]) +paginator.remove_button("first") +paginator.remove_button("last") +``` + +## [PaginatorMenu](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatormenu) + +This class represents the `discord.Select` menu used to navigate between `PageGroup` instances. In most situations, you +will not need to interact with this class directly. + +If you do subclass it, you'll likely want to call `super()` in your `__init__` method to ensure that the `PageGroup` +navigation functionality is retained. + +## Usage Examples + +For a comprehensive list of examples showing all `Paginator` functionality, please see the +[example in cog form](https://github.com/Pycord-Development/pycord/blob/master/examples/views/paginator.py) in the repo. + +## Support and Feedback + +If you have any questions, suggestions, or feedback for `ext.pages`, please join the +[Discord server](https://discord.gg/pycord). diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx new file mode 100644 index 00000000..b8d68925 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx @@ -0,0 +1,20 @@ +--- +title: Paginator FAQ +--- + +# Paginator FAQ + +- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** + - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. + - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. + +- **How can the bot send a paginator to a different destination than where it was invoked?** + - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. + - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. + - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. + +- **How can I change the paginator's behavior without re-creating and re-sending it?** + - Use the `Paginator.update()` method. + +- **How can I make the bot actually do something with the contents of a page?** + - Use the (upcoming) `Paginator.page_action()` method. diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json new file mode 100644 index 00000000..36dfb009 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Tasks" +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx new file mode 100644 index 00000000..848f6066 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx @@ -0,0 +1,216 @@ +--- +title: Tasks +--- + +## Concept + +So you want to run a background task running at some specified interval? Thankfully, that's a common thing to do, whether you're working with some API or handling some background logic don't worry, the Pycord tasks extension is here to make life easier for you! + +With the tasks extension, you can make background tasks without worrying about the asyncio hell and mind bogglers like "what if my internet dies" and "how do I handle reconnecting" with the added benefit of a lot of useful additions that are one line of code away! + +### Example Usage + +```py +import discord +from discord.ext import tasks + +bot = discord.Bot() + +@bot.event +async def on_ready(): + very_useful_task.start() + +@tasks.loop(seconds=5) +async def very_useful_task(): + print('doing very useful stuff.') + +bot.run("TOKEN") +``` + +If you do run this code in your terminal you should see something like this after about 15 seconds: + +``` +doing very useful stuff. +doing very useful stuff. +doing very useful stuff. +``` + +For a more useful example here's a task in a cog context ripped straight from the [docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#recipes): + +```py +from discord.ext import tasks, commands + +class MyCog(commands.Cog): + def __init__(self): + self.index = 0 + self.printer.start() + + def cog_unload(self): + self.printer.cancel() + + @tasks.loop(seconds=5) + async def printer(self): + print(self.index) + self.index += 1 +``` + +As you'd expect this will increment a number and print it out every 5 seconds like so: + +```sh +0 +# 5 seconds later +1 +# 5 more seconds later +2 +# ... +``` + +## [Tasks](https://docs.pycord.dev/en/stable/ext/tasks/index.html) + +Now let's get into the nitty-gritty of tasks. + +As you've seen tasks can work in both outer scope and class contexts and the handle is roughly the same, you define a task using the `tasks.loop` decorator and use the `start` method to start it, the difference is you add the `self` argument when in a class context so since most people have all their bot's code in Cogs all the following code blocks will be in a Cog context to make it easy to copy it then apply whatever modifications you might need! + +### [Creating a task](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop) + +A look at `discord.ext.tasks.loop`'s definition in the documentation reveals that: + +1. As you've seen before it expects the time between each execution, that however doesn't have to be in seconds as + there are `seconds`, `minutes` and `hours` parameters to make it easier for us, they can also be floats in case you want + ultra-precision. +2. You can also pass in a `datetime.time` object or a sequence of them in the `time` parameter which will make it run + at the specified time(s). +3. You can pass in how many times a loop runs before it stops by passing in the `count` parameter, you can use `None` + to make it run forever which is also the default. +4. The loop function **_must_** be a coroutine. + +These are all really useful, and they aren't the only parameters so if you want to know more about them check out the +[docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop)! + +### Attributes + +A task has the following attributes: + +- `current_loop`: The current loop the task is on. +- `hours`, `minutes`, `seconds`: attributes that represent the time between each execution. +- `time`: A list of datetime.time objects that represent the times the task will run, returns `None` if no datetime + objects were passed. +- `next_iteration`: A `datetime.datetime` object that represents the next time the next iteration of the task will + run, can return `None` if the task stopped running. + +These attributes serve as a really powerful asset to get info about your loop. + +### Example + +Now let's create a cog that handles a leaderboard we have in our bot using Tasks then explain what we did after that and +also provide a refresher of how slash commands groups work in cogs. + +For the sake of this example let's pretend that we have a leaderboard module that does all the leaderboard handling for +us and that computing the leaderboard is very expensive computationally wise, so we want to store one version of it that +gets regularly updated instead of generating it every time someone calls the `/leaderboard view` command. + +```py +from discord.ext import tasks, commands +from discord.commands import SlashCommandGroup, CommandPermissions + +from leaderboard import * # Mock leaderboard module. + +class LeaderboardCog(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.update_leaderboard.start() + self.leaderboard_embed = generate_leaderboard_embed() + + leaderboard = SlashCommandGroup(name='leaderboard', description='Leaderboard commands.') + + @tasks.loop(minutes=10) + async def update_leaderboard(self): + print('Updating leaderboard...') + await update_leaderboard() + self.leaderboard_embed = generate_leaderboard_embed() + + @update_leaderboard.before_loop + async def before_update_leaderboard(self): + await self.bot.wait_until_ready() + print("About to start updating leaderboard.") + + @update_leaderboard.after_loop + async def after_update_leaderboard(self): + leaderboard_cleanup() + print("Stopped updating leaderboard.") + + @update_leaderboard.error + async def update_leaderboard_error(self, error): + print(f"Oh no, an error occurred while updating the leaderboard. Error: {error}") + + @leaderboard.command() + async def view(self, ctx): + await ctx.respond(embed=self.leaderboard_embed) + + @leaderboard.command() + async def update_info(self, ctx): + await ctx.respond(f"""***Leaderboard Info***\n + Last update: {(600 - self.update_leaderboard.next_iteration.timestamp())//60} minutes ago.\n + Next update: in {self.update_leaderboard.next_iteration.timestamp() // 60} minutes.\n + Time between loops: {self.update_leaderboard.minutes} minutes.\n + Times updated this session: {self.update_leaderboard.current_loop}. + Running? {self.update_leaderboard.is_running()} + Failed? {self.update_leaderboard.failed()}""", ephemeral=True) + + # Now for the owner only commands: + + leaderboard_config = SlashCommandGroup(name="leaderboard_config", description="Leaderboard configuration commands", permission=[CommandPermissions("owner", 2, True)]) + + @leaderboard_config.command() + async def set_time_between_updates(self, ctx, minutes: int): + self.update_leaderboard.change_interval(minutes=minutes) + await ctx.respond(f"Set time between updates to {minutes} minutes.") + + @leaderboard_config.command() + async def stop(self, ctx): + self.update_leaderboard.stop() + await ctx.respond("Stopped the leaderboard update.") + + @leaderboard_config.command() + async def restart(self, ctx): + self.update_leaderboard.restart() + await ctx.respond("Restarted the leaderboard update.") + +def setup(bot): + bot.add_cog(LeaderboardCog(bot)) +``` + +Phew, that was quite a bit of code. + +Now to explain what's going on: + +First things first we create a cog and in its `__init__` function we start the `update_leaderboard` task and generate +the first instance of our leaderboard's embed. + +After that, we define the `update_leaderboard` task using the `loop` decorator, and we make it run every ten minutes by +passing 10 to the `minutes` parameter. + +Then that we define the `before_update_leaderboard` task using the `before_loop` decorator, and we make it wait until the +bot is ready before starting the task. + +Next up we define the `after_update_leaderboard` task using the `after_loop` decorator, and we make it clean up the +leaderboard when the loop finally stops running. + +Then we define the `update_leaderboard_error` task using the `error` decorator, and we make it print any errors that may +occur while we update our leaderboard to the console. + +Then we get into the fun stuff, we create a slash command group using the `SlashCommandGroup` class and name it +`leaderboard`, we then create the `view` sub-command which sends the embed generated when the leaderboard is updated and +`update_info` which shows a lot of data about the task using some attributes and functions available to us. + +We also create a slash command group called `leaderboard_config` which is only available to the owner of the bot. + +Then we create the `set_time_between_updates` sub-command which takes in the time in minutes and changes the time +between updates of the leaderboard using the `change_interval` method, the `stop` sub-command which stops the task using +the `stop` method and `restart` which restarts the task using the `restart` method. + +Finally, we add the `LeaderboardCog` cog to the bot, and we're done! + +I'd highly recommend you check the tasks extension +[documentation](https://docs.pycord.dev/en/stable/ext/tasks/index.html) for more info on how to use them and what other +functions they have. diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/_category_.json new file mode 100644 index 00000000..9d6255f5 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 3, + "label": "Getting Started", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx new file mode 100644 index 00000000..864206a6 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx @@ -0,0 +1,262 @@ +--- +title: Creating Your First Bot +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +Excited to create your first bot? Once you [install Pycord](../installation.mdx), you can start right +away! + +## Creating the Bot Application + +Just like how you need to sign up to use Discord, your bot also has to be signed up. To do this, +you should: + +1. Go to the [Discord Developer Portal](https://discord.com/developers/applications) and click + on . +2. Give your bot a name, and click . +3. Now, you should see a page like this. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdW3OQnwUhacopqSWw%2F-Mjd_-mxrJCrzmaXrAg8%2Fimage.png?alt=media&token=b8e2ae6c-2290-4d37-ad7c-eb412f3fb00e) +4. Click on the tab on the left side of the screen. +5. Click on . +6. You can give it a name, change the Avatar, etc. + +## Inviting the bot + +Now, lets get the bot added to some servers. Go to the tab +in the left pane and select `bot` and `applications.commands` as scopes. + +You may want your bot to have application commands, which is what the `application.commands` scope +allows your bot to make. + +Next, you want to choose what permissions the bot will have and select them. For now, you can just +give your bot the `administrator` permission, which gives your bot every permission. Once you select +your bot's permissions, click on to get the bot invite link. + +:::tip + +When your bot is all ready to go, make sure that administrator permissions aren't selected unless +your bot truly needs them. Try selecting only permissions the bot will need. For testing, +Administrator permissions are fine. + +::: + +![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-Mk6tNY3LfDkjd6pqdpL%2F-Mk6tkdpddEWoa2jczZk%2Fimage.png?alt=media&token=52c8a29f-a798-48f8-a8c7-4ecca2681f79) + +You can use this link to invite the bot. + +## Tokens + +Now that you have an account for your bot, you need to log in. To log in, we need the bot's +password. All users and bots have a "token." You may think of this token as a password, as this allows +us to log our bot into Discord. + +Tokens are "snowflakes." Not actual snowflakes, though. Just like how no two snowflakes in real life have the same +pattern, snowflakes in computers are unique things - no two bots have the same token - so a token is +considered a snowflake. A Discord user ID is also a snowflake. + +Now, lets get your bot's token. To do this, you want to: + +1. Go back to the tab. +2. Click on the button in the "Token" section. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdbU12JISJorAZxrKH%2F-MjdbpUsapzb5n15Po5P%2Fimage.png?alt=media&token=118e259f-940a-4f6c-b3a3-c29f3a54100d) + +Now, you have your bot's token copied to your clipboard. + +:::danger + +Do not, under any circumstances, give your token to anyone. Even if you are contacted by someone +claiming to be Discord staff, do not give them your bot's token. They are lying to you to try and +gain access to your bot. If an unauthorized user gains access to your bot's token, they can access +your bot and use it in malicious ways. + +Never push your token to GitHub or include it in your code. One way to prevent your token from +getting leaked is to store it in `.env` files. + +::: + +### Protecting Tokens + +#### Using dotenv + +You can store your tokens in `.env` files. This is a simple way to store sensitive information. + +1. Create a file with the name `.env` (only the extension, with a dot/period at the start and without a name before it). +2. Define the token in the `.env` file (replace the example value with your token). + ```env title=".env" + TOKEN = NzkyNzE1NDU0MTk2MDg4ODQy.X-hvzA.Ovy4MCQywSkoMRRclStW4xAYK7I + ``` +3. Install [`python-dotenv`](https://pypi.org/project/python-dotenv/). + ```bash + python -m pip install python-dotenv + ``` +4. Load the token from the `.env` file. + ```python + import dotenv + dotenv.load_dotenv() + token = str(os.getenv("TOKEN")) + ``` +5. Pass your token as parameter when running the bot. + ```python + client.run(token) + ``` + +:::tip + +If you are using Git to track your bot's changes, you should create a file called `.gitignore` and add +`.env` to it. This stops your `.env` file from getting tracked along with the rest of your code, and +will not be pushed to a remote Git repository. As a consequence, it will stay secure on your local machine. + +::: + +## Coding the Basics + +Here's an example of code you'll write with Pycord: + +```py +import discord +import os # default module +from dotenv import load_dotenv + +load_dotenv() # load all the variables from the env file +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") + +bot.run(os.getenv('TOKEN')) # run the bot with the token +``` + + + +
+ + hello + +
+ Hey! +
+
+
+ +Let's go through the code. First, the imports. + +```py +import discord +import os +from dotenv import load_dotenv +``` + +In the first line, `import discord`, we import Pycord. Although you install Pycord with `pip install py-cord`, you +import it with `import discord`. This is so it's as easy as possible when switching from Discord.py to Pycord. + +We then import `os` and `dotenv`. `os` is a default module that we will use to get the token from the env file. `dotenv` +is a module that we will use to load the env file. You installed this with `pip install python-dotenv`. + +Next, we load the env file with `load_dotenv()`. + +```py +bot = discord.Bot() +``` + +In this line, we create a new instance of [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). +In this object, we can pass various parameters for configuration purposes, such as `owner_ids` +and [`intents`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```py +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") +``` + +We use the [`event`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) decorator to override +the [`on_ready`](https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready) function to define an +event that is automatically called when the bot is ready to use. + +```py +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") +``` + +Here, we use the [`slash_command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.slash_command) +decorator to define a slash command. We specify the `name` and `description` arguments. If not +specified, the name of the slash command would be the function name and the command description would +be empty. + +Optional: We type-hint the context parameter (`ctx`) as [`discord.ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext). In modern IDEs, type-hinting allows access to autocompletion and docstrings. You can read more about type-hinting [here](https://docs.python.org/3/library/typing.html). + +Finally, you want to run the bot using the token specified in the `.env` file. + +Now you have finished creating your first Pycord bot! What we have shown you is just the basic structure +of a bot. You can do a lot more with Python and Pycord knowledge, as well as your imagination! Pycord +will not limit your bot's abilities. + +:::note + +The part where we load the token from the environmental variables is not required. You may use another way to keep your token secure, or, although not recommended, simply specify the token normally as a string, as shown below. + +
+A Basic Bot without securing the token +
+ +```py +import discord + +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.send("Hey!") + +bot.run("TOKEN") +``` + +
+
+ +::: + +## FAQ + +### How do I make prefixed commands? + +Prefixed commands are an older method of creating bot commands that listen for messages and replies +if the message starts with a certain character. You can read [this page](../extensions/commands/prefixed-commands.mdx) +to learn more about prefixed commands. + +### How do I setup modules/cogs? + +[Cogs](../popular-topics/cogs) are a great way to organize your commands by putting them into +groups called cogs. Cogs are separate files that your bot loads to get the commands inside. +You can read more about cogs, as well as learn how to use them and their benefits, +[here](../popular-topics/cogs). + +### How do I add components, such as buttons and dropdown menus, to my bot? + +Pycord makes it very easy to use Message Commands with your bot by using the `discord.ui` module. +To learn more, read about Message Commands in our [interactions directory](../interactions). + +:::info Related Topics + +- [Prefixed Commands](../extensions/commands/prefixed-commands) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx new file mode 100644 index 00000000..2a68677b --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx @@ -0,0 +1,109 @@ +--- +title: Hosting Your Pycord Bot +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Hosting Your Pycord Bot + +If you're completely new to this, you might have thought something along the lines of "Yay! I got my +bot working," after following our [Creating your First Bot](creating-your-first-bot) guide, only +to close your IDE or shut down your computer to find your bot offline. + +The reason for this is that programs have to be hosted somewhere, meaning some machine somewhere has +to constantly run your bot. There are tons of hosting services that can help you host your bot for +little to no cost. + +## Can I get a Clear Explanation? + +Sure thing. When you run your bot, it first makes a connection to Discord's API. Once that's done, +Pycord sends "heartbeats" to Discord. "heartbeats" are small packets sent at a set interval telling +Discord that your bot is indeed still alive. If Discord doesn't receive a heartbeat after a certain +amount of time, your bot is pronounced dead and buried in the graveyard (not really). It is, though, +taken offline and its connection with Discord is terminated. + +Once you close the terminal that you've run your program on, the program is no longer running, and +the bot stops sending heartbeats and can no longer process commands. This is why you have to constantly +keep the process running. + +This goes for all programs, in a different nature. If the code isn't compiled/built/assembled/interpreted, +it can't be running. + +## What is a Host? + +A host is a server or container for running code offered by a **hosting provider.** There are a lot +of hosting providers, such as bigger ones like Amazon Web Services (AWS) and Google Cloud, and smaller +ones like GalaxyGate and DigitalOcean. + +There are three types of hosts. + + + + Shared hosting is a type of hosting where multiple people share one VPS. Getting a spot on + a shared host is usually cheap, sometimes even free. Shared hosts do not give you a lot of + resources, from less than a gigabyte of RAM (usually 512MB on free hosts) and half of a CPU + with very little storage. Shared hosting is usually used for website hosting and is not + recommended for hosting a Discord bot. + + + A virtual private server (VPS) is a virtual computer (virtual machine) that is rented out to + customers. Most people use a VPS for hosting their projects such as Discord bots. You can get + anywhere from less than a gigabyte of RAM and a less powerful CPU to just under one hundred + gigabytes of RAM, a (or multiple) powerful CPU(s), and a fair amount of storage. A VPS is the + best choice for most users and can be fairly cheap. + + + A dedicated host is a physical computer. You can buy these yourself or rent one from a hosting + provider. Dedicated hosts are often very expensive, but are also very powerful, having a + few hundred gigabytes of RAM and a few very powerful CPUs, along with a good amount of storage. + Dedicated hosts are usually used for very large projects and are overkill for something like + a Discord bot. + + +
+ +:::danger + +Make sure you choose a hosting provider you trust. Also make +sure the hosting provider you're looking at has good reviews on public forums. Googling along the +lines of "[host] review" should do the trick. A provider you don't trust can compromise your token. + +::: + +Most hosting providers rent their services to you for a monthly or yearly fee. These can be anywhere +from a few dollars to hundreds or thousands of dollars. + +## How to Host Your Bot + +Once you rent or buy a VPS, you can get to work. Most hosting providers allow you to choose from a +wide range of operating systems, most allow you to choose one but some allow you to choose +multiple. Once that's ready, you have to SSH into the system. We won't get into SSH here, but you can +read [this article from DigitalOcean](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys). +You can also use VNC, which is remote desktop software. If you are using an OS that does not have a +GUI, and is only a command line (a "server" OS), such as Ubuntu Server or most Linux Server Operating Servers, you will most +likely use SSH. If you are using an OS that has a GUI, such as Windows Server, you will most likely use VNC. + +Once you've decided on your operating system, you'll want to set it up and install Python. Once that's +done, you can copy your bot's files to your remote system, install the required packages, and run +the bot. + +:::warning + +If you are using SSH to run the file, your bot will not stay running. This is because the file is +only told to run during your session. You can use a command like [nohup](https://en.wikipedia.org/wiki/Nohup) +to make sure your file stays running after you disconnect. + +::: + +Now your bot is hosted, but that doesn't mean it can't go offline. If your bot encounters an error, +it can often go offline or stop its process. For this, make sure you have proper error handling. +Also be sure to pay attention to your hosting provider's updates or news, as they usually notify +users of when they plan on doing maintenance to their servers, making their services unavailable for +a short time. + +:::info Related Topics + +- [Creating Your First Bot](creating-your-first-bot) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx new file mode 100644 index 00000000..ee6b9417 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx @@ -0,0 +1,379 @@ +--- +title: More Features +description: More features to make your bot cool and snazzy. +--- + +import { + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, + DiscordEmbedField, + DiscordEmbedFields, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +So, you just created your first Pycord bot! Now, let's add some more features to it. This will include adding event handlers, waiting for user response, styling the messages, and more. + +## Events + +### Event Handlers + +Events in Discord are a way to listen for certain actions. For example, if you want to know when a user joins your server, so you could send a welcome message, you can use the `on_member_join` event. + +First, you need to ask Discord to send you events. This is done via "Intents". Read up the [Intents](../Popular-Topics/intents) page for more information. + +Once you understand what intents are, you can enable the events you need, or just use the default ones with `discord.Intents.all()`. + +Now that that's done, let's add an event handler for when a user joins the server. We will use the [`on_member_join` event](https://docs.pycord.dev/en/stable/api/events.html#discord.on_member_join). We will send a private message to the user welcoming them to the server. + +```python +@bot.event +async def on_member_join(member): + await member.send( + f'Welcome to the server, {member.mention}! Enjoy your stay here.' + ) +``` + +We use the [`discord.Bot.event` decorator](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) to add the event handler. + +The `on_member_join` event is called when a user joins the server. The `member` parameter is the user that joined. Different events have different names and parameters. You can find all of them [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +So, that's how you add event handlers! + +### Waiting for User Response + +Let's say you want to create a Guess-the-Number game (where the user has to guess a number between 1-10). You need to send a message to a user and wait for them to respond. You can do this with the [`wait_for`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.wait_for) method. + +```python +@bot.command() +async def gtn(ctx): + """A Slash Command to play a Guess-the-Number game.""" + + await ctx.respond('Guess a number between 1 and 10.') + guess = await bot.wait_for('message', check=lambda message: message.author == ctx.author) + + if int(guess.content) == 5: + await ctx.send('You guessed it!') + else: + await ctx.send('Nope, try again.') +``` + +`wait_for` takes one argument, which is the event type. The event type is the name of the event you want to wait for. In this case, it's `message`. It could also be `reaction` to wait for a reaction to be added. + +We pass a keyword argument to `wait_for` called `check`. The function may look complicated if you're a beginner. We pass a `lambda` function, which simplifies the code a bit. + +The lambda function takes one parameter, `message`. When Pycord receives a message, it passes it to the `check` function. If the function returns `True`, the message is returned. If the function returns `False`, the message is ignored and the bot waits for another message. + +Here, we check if the message is from the user that sent the command. We simply use `message.author == ctx.author`. This will check if the author of the message was the person who invoked the command. + +## Styling Messages + +### Embeds + +Embeds are a Discord feature that allows applications to format their messages in cool embedded format, +enabling your bot to lay out messages with a lot of text into neat fields. + + + + + The Pycord Guide is a detailed guide that explains how to use Pycord and all of its features. + + + The Getting Started section explains how you can get a brand new bot created and running from scratch. + + + Interactions with Pycord + + + Pycord's various Extensions + + + Other Popular Topics + + + We have so much more! Just explore, and you will find everything you need. If you want another page added, open an issue on the GitHub. + + + Created with 💖 by the Pycord Team & Contributors + + + + +
+ +Creating embeds is simple! Just create an instance of [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) and edit it to your liking. Once you're done, send it! + +```python +import discord + +bot = discord.Bot() + +@bot.command() +async def hello(ctx): + embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from + ) + embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") + + embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) + embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) + embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) + + embed.set_footer(text="Footer! No markdown here.") # footers can have icons too + embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") + embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") + embed.set_image(url="https://example.com/link-to-my-banner.png") + + await ctx.respond("Hello! Here's a cool embed.", embed=embed) # Send the embed with some text + +bot.run("TOKEN") +``` + + + +
+ hello +
+ Hello! Here's a cool embed. + + Embeds are super easy, barely an inconvenience. + + + A really nice field with some information. The description as well as the fields support markdown! + + Inline Field 1 + Inline Field 2 + Inline Field 3 + + Footer! No markdown here. + +
+
+ +
+ +This simple command sends replies to a [slash command](../interactions/application-commands/slash-commands) with an embed. +Let's break it down: + +```py +embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), + ) +``` + +This command creates an embed. We use the [`Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) +class to create an embed object with the title "My Amazing Embed", the description "Embeds are super easy, barely an inconvenience.", and the color `blurple`, Discord's main theme color. + +[discord.Colour](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Colour) is a class full of [classmethods](https://docs.python.org/3/library/functions.html#classmethod) +that return color values. While the official, documented name of this is `discord.Colour`, `discord.Color` +works as well. + +```py +embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") +embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) +embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) +embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) +``` + +This small section shows off embed fields. You can add fields to embeds with the [`add_field` method](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.add_field) +of the [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) class. These consist of three +keyword arguments: `title`, `value`, and `inline`. `title` and `value` are both required arguments, which inline defaults to `False` if it's not defined. The `inline` argument specifies whether space will be divided among the inline fields. There could be a mix of fields where inline has different values too. + +```py +embed.set_footer(text="Footer! No markdown here.") # footers can have icons too +embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") +embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") +embed.set_image(url="https://example.com/link-to-my-banner.png") +``` + +In this section, we're adding unique items to the embed. These items are: + +- Footer - With the [`set_footer()`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_footer) + method, you can set a small footer that holds a message. This has `text` and `icon_url` kwargs. +- Author - With the [`set_author`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_author) + method, you can set an author for the embed. This is a small text field at the top of the embed. This + includes `name`, `url` and `icon_url` kwargs. +- Thumbnail - With the [`set_thumbnail`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_thumbnail) + method, you can set a small image to reside at the top-right of the embed. This has a single `url` kwarg. +- Image - With the [`set_image`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_image) + method, you can set an image to sit at the bottom of an embed. This has a single `url` kwarg. + +There are a lot more methods and attributes you can use to configure embeds. Here, we just covered the basics. Also, remember that all of these values are not necessary in an embed. An embed may only contain a few of these. For example, only a description, a title and a description, and so on. + +### Markdown + +Markdown is a type of markup language that's limited in terms of formatting yet simple. Discord allows +for a watered-down version of markdown to be in their messages. + +#### Text Markdown + +Text formatting can be used in messages and in most embed parts, +as explained in the dedicated section below. + + + + + + + + + + + + + + + + + + + + +
*italics*__*underlined italics*__
**bold**__**underlined bold**__
***bold italics***__***underlined bold italics***__
__underlined__~~strikethrough~~
+ +#### Code Markdown + +To create a single-line code block without syntax highlight, wrap the text between single backticks. +This code block will only add a dark background to the text. + +``` +`print("Hello world!")` +``` + +To create a multi-line code block without syntax highlight, wrap the text between triple backticks +on first and last line. This type of code block will encase the code inside a box. + +```` +``` +message = "Hello world!" +print(message) +``` +```` + +To create a multi-line block with syntax highlight, add the name of the language you are using right after +the triple backticks on the first line. For example, for Python you can write either "python" or "py". + +```` +```python +message = "Hello world!" +print(message) +``` +```` + +If you want to use syntax highlight for a single line of code, you still have to format it +like a multi-line block but the code must be on a separate line than the triple backticks. + +#### Quote Markdown + +To create a single-line quote block, start the line with `>` followed by a space. + +``` +> This is a single-line quote. +``` + +To create a multi-line quote block, write `>>>` followed by a space. All text +from that point onwards will be included in that quote block. + +``` +>>> This is a +multi-line quote. +``` + +#### Spoiler Markdown + +To hide a spoiler, encase the text between double pipes. The users +will have to click on it before being able to see the text contained in it. + +``` +||spoiler|| +``` + +#### Link Markdown + +Link formatting only works in embeds and messages sent through webhooks, +by using the following syntax: + +``` +[Pycord](https://pycord.dev/) +``` + +Inside the supported elements that have just been mentioned, +the example above will look like this: [`Pycord`](https://pycord.dev/) + +Outside them, the link will still be clickable but the formatting will be ignored, +therefore the example above will look similarly to this: `[Pycord](https://pycord.dev/)` + +#### Embed Markdown + +Adding markdown to your embeds or messages will give your bot the sparkle it needs, +however, markdown is limited inside embeds. Use the following table as a reference +and keep in mind that embed title and filed names will always show in **bold**. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PartTextLink
Embed AuthorNoNo
Embed TitleYesNo
Embed DescriptionYesYes
Field NameYesNo
Field ValueYesYes
Embed FooterNoNo
diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx new file mode 100644 index 00000000..e44b7c49 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx @@ -0,0 +1,184 @@ +--- +title: Rules and Common Practices +description: All about the rules and common practices for coding a Discord bot +--- + +# Rules and Common Practices of Creating a Bot + +When creating almost anything, there's always a certain set of rules to follow or common practices, +such as [PEP8](https://www.python.org/dev/peps/pep-0008/) for Python. This applies to creating bots +with Pycord as well. + +:::note + +Most of these rules and common practices are only applicable for +[verified bots](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting), +but it's good to follow them nonetheless. + +::: + +## Rules + +There are rules for creating bots, and most of these are required by Discord themselves, not us at +Pycord. Not following these rules may get your bot denied for verification. + +### Terms of Service and Privacy Policy + +Starting at some point in time, Discord has made providing a privacy policy with your bot a requirement. +This is so that Discord knows exactly what you are doing with its users' data. + +:::tip +You don't need a lawyer or anyone special to write out a privacy policy for you, nor do you need +it approved by some official entity. Simply writing out how you are going to use Discord user +information neatly is all you need to do. +::: + +Providing a Terms of Service for your bot is optional, though usually a best practice. It tells users +what they can and cannot do with your service, and makes it easier to settle disputes if someone +disagrees with you. + +Read more in Discord's official [Legal Docs](https://discord.com/developers/docs/legal). + +### Developer Policy + +We could list almost every rule about using Discord's API here. _Or_ we could simply link Discord's +Developer Policy to make it easier on us. You can find Discord's Developer Policy +[here](https://discord.com/developers/docs/policy). This outlines what you can and cannot do with +Discord's Developer API. And, don't worry, it's completely readable and understandable. + +## Best Practices + +Now, here's something we _can't_ simply link an article for. We're going to discuss the best practices +of creating a Discord bot with Pycord. + +### Bot Sharding + +To any new or maybe even experienced bot developer, sharding a bot sounds beneficial once you hear +about it. I'm here to tell you that it isn't a good idea to shard your bot. + +_Wait a minute, why would it be an option if it wasn't a good idea?_ It's simple. I lied. Sort of. +I'm not going to go into the details of sharding a bot, so you can read about it on +[this page](../Popular-Topics/sharding). Sharding is the process of taking your bot +and breaking it up into small pieces, so it's easier to perform tasks. This is very useful for large +bots, as it makes them faster and more reliable. Sharding is not a good practice for small bots. + +:::note +Discord will notify you once it is time to shard your bot, and will eventually force you to do so. +::: + +At the very least, wait for one thousand servers to shard your bot. If you shard your bot while it's +small, you'll just be wasting resources and possibly making your bot slower. + +### [Verification](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting) + +Verifying your Discord bot is something every developer would like to achieve. It shows that your bot +is in more than 75 servers. It's generally a good idea to try to get your bot verified as soon as +possible. We're talking at 76 servers soon. This is because Discord can be somewhat slow in terms of +bot verification, so verifying as soon as possible gives them enough time to verify before your bot +reaches the 100 server cap. If a bot is not verified, it cannot grow beyond 100 servers. + +It's also a good idea to only apply for the privileged intents that you need. Applying for intents +your bot doesn't use wastes both your time and Discord's time, as your privileged intent request +will be denied simply because you applied for an intent you didn't need. + +### Subclassing + +While it may take some time, subclassing a bot is very worth it. Once again, this was explained +elsewhere, so I won't go into the details, but I felt it fit here, so I put it here. + +Subclassing a bot makes it more flexible and allows it to do a lot more. Read more about subclassing +bots [here](../Popular-Topics/subclassing-bots) + +### Your Bot's Token + +Your bot is only able to be run for one reason: its token. If you followed the +[guide for creating your first bot](creating-your-first-bot), you should already know a bit about +keeping that token safe. That's exactly what you want to do. + +Sharing your token is never good. If someone evil gets a hold of your token, they can do terrible things, +such as making your bot leave all of its servers, spamming all the members the bot has contact with, +and even manipulating the servers the bot is in, if given the permissions. That's why it's very important +to keep your token safe. To learn how to do so, read [this part](creating-your-first-bot#tokens) of +the Creating Your First Bot guide. + +### Backups + +You always want to back up your bot's data. This includes both its code _and_ its databases. This way, +if something tragic happens, such as your host failing a data migration or you breaking your Raspberry +Pi's SD card that held your bot, you'll still have its precious user data. I have a small program for +my bot that uploads its databases to a remote GitHub repository periodically to not lose any data. +It may be smarter to find a bit more of a reliable way to do so, though. + +Public or private, having a local Git repository connected to a remote one is a good idea for making +almost any application. For a lot of developers, it's like saving your work. If you do this, all of +your bot's code won't be lost if your computer spontaneously combusts, or you smash it to bits from +anger. You can simply grab the backup computer that everyone has lying around, and you're back +in business. + +### Organization and Cleanliness + +It is _extremely_ important to have organized code. This includes commands, objects, functions, +and classes. If you don't have organized code, it will get progressively harder for you to recognize +it, and others won't be able to decipher it. + +Make sure you utilize indents and spaces, as these are very important in making your code readable. + +```py title="Bad Spacing" +class MyClass: + async def add(self,num1,num2): + return num1+num2 + async def sub(self,num1,num2): + return num1-num2 +``` + +```py title="Good Spacing" +class MyClass: + async def add(self, num1, num2): + return num1 + num2 + + async def sub(self, num1, num2): + return num1 - num2 +``` + +See the difference? Now, which one looks more readable? Hopefully, you answered the second example. +Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is a PEP (**Python Enhancement Proposal**) +style guide for Python. It is the style guide that is used by most Python developers and programmers, +providing a universal way to write and read code. + +### Databases + +As your bot grows, you'll inevitably have to store data for your bot. Now, most people would probably just load up some +JSON file on boot into a `dict`, modify it in memory then write to the file. However, JSON files aren't the solution. +When you write to a JSON file, it rewrites the entire file instead of just rewriting the section that changed. It's also +a configuration file format, not a storage file format. + +Instead of using a JSON file or some other related format, you should instead use a database. There are many databases +out there, like MongoDB, SQLite, and PostgreSQL to name a few. + +All of these databases I named do the job well, and which one you use depends on what features you want out of a database. + +<>{/* Maybe clarify these/add more options */} + +#### MongoDB + +MongoDB is a JSON-like format and if you already use JSON files, it shouldn't be too hard to migrate over to. + +#### SQLite + +SQLite is based on SQL, a common relational data model. It's a lightweight, easy-to-use, portable database solution that +works entirely on files. However, if for some reason you cannot read/write to and from a file, and you need to manage +lots of data, SQLite might not be for you. + +While SQLite is a part of the Python Standard Library as the `sqlite3` package, we recommend not using it as it is +synchronous and blocking. You should use an asynchronous alternative, such as [`aiosqlite`](https://pypi.org/project/aiosqlite/). + +#### PostgreSQL + +PostgreSQL is also based on SQL, but it also has more features than SQLite. It's compliant with the SQL standard, +open-source, and extensible. However, it's not that fast or simple compared to SQLite. + +#### MariaDB + +MariaDB is also based on SQL and is a fork of the MySQL project. It's compliant with the SQL standard, it's also open +source and is a complete drop-in replacement for any code with MySQL. You don't even need to change what package you're +using! diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/installation.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/installation.mdx new file mode 100644 index 00000000..521c69cd --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/installation.mdx @@ -0,0 +1,80 @@ +--- +title: Installation +sidebar_position: 2 +--- + +Before you can start using Pycord, you need to install the library. + +:::note +Python **3.8 or above** is required to use Pycord. +::: + +:::tip +Before you start installing python packages globally, it's recommended you set up a virtual environment. +You can find instructions for that [here](More/virtual-environments). +::: + +## Fresh Installation + +To install Pycord, you can use the following command in your terminal: + +``` +pip install py-cord +``` + +:::tip +Remember that you need to install `py-cord`, not `pycord`. +Also, the `pip` command varies depending on your installation. For example, it might be `python3 -m pip` on macOS/Linux or `py3 -m pip` on some versions of Windows. +::: + +If you need voice support for your bot, you should run: + +``` +pip install "py-cord[voice]" +``` + +## Migration + +### Updating Pycord + +If you are upgrading from a previous version of Pycord, you can use the following command in your terminal to upgrade to the latest version: + +``` +pip install -U py-cord +``` + +### Migrating from other libraries + +If you are migrating from another library, say, `discord.py`, first of all, you need to uninstall it. + +``` +pip uninstall discord.py +``` + +Then, you can install Pycord, it's as simple as that!: + +``` +pip install py-cord +``` + +:::caution +Uninstalling `discord.py` _after_ installing `py-cord` can cause issues. Make sure to uninstall it first! +::: + +## Installing Other Builds + +### Development Build + +:::caution +The development build comes with cutting edge features and new functionality, but as it isn't a stable build you may encounter bugs. +::: + +To install the development build, you can use the following command in your terminal: + +``` +pip install -U git+https://github.com/Pycord-Development/pycord +``` + +:::important +Git is required to install this build. [Learn how you can install Git](./more/git). +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/interactions/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/_category_.json new file mode 100644 index 00000000..ea28be60 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 4, + "label": "Interactions" +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json new file mode 100644 index 00000000..6dcafe83 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Application Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx new file mode 100644 index 00000000..b4ffeade --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx @@ -0,0 +1,85 @@ +--- +title: Context Menus +description: Learn all about Context Menus (User Commands & Message Commands) and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +When you right-click a message, you may see an option called "Apps". Hover over it, and you can see +commands a bot can run with that message. These are called message commands. + +When you right-click a user in the user list, you can once again see an option called "Apps". +Hover over it, and you can see commands a bot can run with that message. These are called user commands. + +Together, these two are called Context Menus or Context Menu Commands. These commands work very much like normal commands, except they take a member or message. + +:::note + +A bot can have up to 5 global Context Menus of each type. + +::: + +## User Commands + +Creating a user command is very simple. + +```python +@bot.user_command(name="Account Creation Date", guild_ids=[...]) # create a user command for the supplied guilds +async def account_creation_date(ctx, member: discord.Member): # user commands return the member + await ctx.respond(f"{member.name}'s account was created on {member.created_at}") +``` + + + +
+ + Account Creation Date + +
+ {defaultOptions.profiles.bob.author}'s account was created on 2020-01-01 +
+
+ +## Message Commands + +```python +@bot.message_command(name="Get Message ID") # creates a global message command. use guild_ids=[] to create guild-specific commands. +async def get_message_id(ctx, message: discord.Message): # message commands return the message + await ctx.respond(f"Message ID: `{message.id}`") +``` + + + + Do. Or do not. There is no try. + + +
+ + Get Message ID + +
+ Message ID: 930650407917748286 +
+
+ +
+ +:::info Related Topics + +- [Slash Commands](./slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx new file mode 100644 index 00000000..edac55b3 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx @@ -0,0 +1,56 @@ +--- +title: Localizations +description: Localizations are a way to make your bot more accessible to your users. Learn all about localizations now! +--- + +Localizations are a way to make your bot more accessible to your users. You can localize the command +name, the names of any arguments, and any text that is displayed to the user. + +## Syntax + +```python +@bot.slash_command( + name="ping", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + }, + options=[ + Option( + name="Example", + name_localizations={ + "en-GB": "British Example" + }, + description="Example option that does nothing", + description_localizations={ + "en-GB": "British example option that does nothing" + } + ) + ] +) +async def ping(ctx, example): + responses = {"en-US": "Pong!", + "en-GB": "British Pong!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +@bot.slash_command( + name="ping2", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + } +) +async def ping2(ctx, example: Option(str, "example", name_localizations={"en-GB": "British Example"}, description="Example option that does nothing", description_localizations={"en-GB": "British example option that does nothing"})): + responses = {"en-US": "Pong2!", + "en-GB": "British Pong2!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +``` + +- [`Locales`](https://discord.com/developers/docs/reference#locales) - List of valid locales recognized by Discord diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx new file mode 100644 index 00000000..ed454dad --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx @@ -0,0 +1,292 @@ +--- +title: Slash Commands +description: Learn all about Slash Commands and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On March 24, 2021, Discord added Slash Commands to Discord as an easier, more efficient, and better way of using bot commands. Pycord has implemented Slash Commands into the library, so it's simple, efficient, and familiar. + +:::important + +Remember that Slash Commands require your bot to be invited with the `application.commands` scope or Slash Commands will not show up. Bots already in the guild can simply be invited again with the scope; there is no need to kick the bot. + +::: + +## Syntax + +Let's create a simple Slash Command. + +```py +import discord + +bot = discord.Bot() + +# we need to limit the guilds for testing purposes +# so other users wouldn't see the command that we're testing + +@bot.command(description="Sends the bot's latency.") # this decorator makes a slash command +async def ping(ctx): # a slash command will be created with the name "ping" + await ctx.respond(f"Pong! Latency is {bot.latency}") + +bot.run("TOKEN") +``` + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +Let's go through the code. + +First, we import Pycord's `discord` package. + +Next, we create a [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot) object and assign it to a variable `bot`. + +We then go ahead and use the [`@bot.command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.command) decorator, which registers a new Slash Command. We pass a `description` parameter to give a description to the Slash Command. We can also pass a `name` parameter to change the Slash Command's name. By default, the name of the Slash Command will be the name of the function, in this case, `/ping`. + +We create an async function called `ping` with parameters `ctx`, which, when called, sends the bot's ping/latency using [`ctx.respond`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext.respond). + +## Subcommand Groups + +You might want to group certain commands together to make them more organised. A command group is exactly what it sounds like, a group of individual Slash Commands together. + +In order to make a Slash Command group, you can use the `bot.create_group` function. + +```python +import discord + +bot = discord.Bot() + +# create Slash Command group with bot.create_group +greetings = bot.create_group("greetings", "Greet people") + +@greetings.command() +async def hello(ctx): + await ctx.respond(f"Hello, {ctx.author}!") + +@greetings.command() +async def bye(ctx): + await ctx.respond(f"Bye, {ctx.author}!") + +bot.run("TOKEN") +``` + +Or, you can instead manually make a `SlashCommandGroup` class like so: + +```python +import discord + +math = discord.SlashCommandGroup("math", "Math related commands") + +@math.command() +async def add(ctx, num1: int, num2: int): + sum = num1 + num2 + await ctx.respond(f"{num1} plus {num2} is {sum}.") + +@math.command() +async def subtract(ctx, num1: int, num2: int): + sum = num1 - num2 + await ctx.respond(f"{num1} minus {num2} is {sum}.") + +# you'll have to manually add the manually created Slash Command group +bot.add_application_command(math) +``` + +Here's what the registered subcommands will look like in the Slash Command Menu: + +![Picture of the subcommands in the Slash Command Menu](../../assets/interactions/groups-and-subcommands.jpg) + +You'll notice that there's the name of the Slash Command Group and then the name of the subcommand separated by a space. + +::: + +:::info Cogs + +If you are looking to add Slash Command Groups to cogs, please look at our [Cogs page](../../popular-topics/cogs)! + +::: + +## Sub-groups + +We've made a subcommand group, but did you know that you could create a group inside another? + +```python +from discord import SlashCommandGroup +from math import sqrt + +math = SlashCommandGroup("math", "Math related commands") +advanced = math.create_subgroup("advanced", "Advanced math commands") + +@advanced.command() +async def square_root(ctx, x: int): + await ctx.respond(sqrt(x)) + +bot.add_application_command(math) +``` + +The command created above can be invoked by typing `/math advanced square_root`. + +## Options & Option Types + +Whenever you're using Slash Commands, you might notice that you can specify parameters that the user has to set or can optionally set. These are called Options. + +Options can also include a description to provide more information. [You can learn more about Options in our documentation!](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.Option) + +Since you want different inputs from Options, you'll have to specify the type for that Option; there are a few ways of doing this. + + + + +You could use Type Annotations and let Pycord figure out the option type or explicitly specified using the [`SlashCommandOptionType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.SlashCommandOptionType) enum. + +```python +import discord + +bot = discord.Bot() + +@bot.command() +# pycord will figure out the types for you +async def add(ctx, first: discord.Option(int), second: discord.Option(int)): + # you can use them as they were actual integers + sum = first + second + await ctx.respond(f"The sum of {first} and {second} is {sum}.") + +@bot.command() +# this explicitly tells pycord what types the options are instead +async def join( + ctx, + first: discord.Option(discord.SlashCommandOptionType.string), + second: discord.Option(discord.SlashCommandOptionType.string) +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + add + +
+ The sum of 1 and 1 is 2. +
+ +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+ + +Instead of Type Annotations, you can also use the option decorator. This is usually done to have type-hinting. + +```python title="Slash Command Type" +import discord + +bot = discord.Bot() + +@bot.command() +@discord.option("first", type=discord.SlashCommandOptionType.string) # type = str also works +@discord.option("second", type=discord.SlashCommandOptionType.string) # type = str also works +async def join( + ctx, + first: str, + second: str, +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+
+ +## Autocomplete + +Discord's autocomplete allows developers to determine option choices that are used in a slash command option. You can do this by defining a function: + +```py +async def get_animal_types(ctx: discord.AutocompleteContext): + """ + Here we will check if 'ctx.options['animal_type']' is a marine or land animal and return respective option choices + """ + animal_type = ctx.options['animal_type'] + if animal_type == 'Marine': + return ['Whale', 'Shark', 'Fish', 'Octopus', 'Turtle'] + else: # is land animal + return ['Snake', 'Wolf', 'Lizard', 'Lion', 'Bird'] + +@bot.slash_command(name="animal") +async def animal_command( + ctx: discord.ApplicationContext, + animal_type: discord.Option(str, choices=['Marine', 'Land']), + animal: discord.Option(str, autocomplete=discord.utils.basic_autocomplete(get_animal_types)) +): + await ctx.respond(f'You picked an animal type of `{animal_type}` that led you to pick `{animal}`!') +``` + + + +
+ + animal + +
+ You picked an animal type of Marine that led you to pick Shark! +
+
+ +:::warning + +Autocomplete can **only** be used with slash commands. + +::: + +:::info Related Topics + +- [Interactions Index](../../interactions) +- [Rules and Common Practices](../../getting-started/rules-and-common-practices) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/interactions/index.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/index.mdx new file mode 100644 index 00000000..8603437f --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/index.mdx @@ -0,0 +1,242 @@ +--- +title: Discord Interactions +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +In December 2020, Discord released their first Interaction: the +[Slash Command](https://discord.com/developers/docs/interactions/application-commands#slash-commands). +Since then, Discord has added many types of Interactions, including: + +[**Application Commands**](https://discord.com/developers/docs/interactions/application-commands) + +- [**Slash Commands**](https://discord.com/developers/docs/interactions/application-commands#slash-commands): + Commands that can be used with the `/` prefix. +- **Context Menu Commands**: Commands that can be used from the right-click menu. + - [**User Commands**](https://discord.com/developers/docs/interactions/application-commands#user-commands): + Commands that can be used on a user by alt-clicking/selecting them. + - [**Message Commands**](https://discord.com/developers/docs/interactions/application-commands#message-commands): + Commands that can be used on a message by alt-clicking/selecting it. + +[**UI Components**](https://discord.com/developers/docs/interactions/message-components) + +- [**Buttons**](https://discord.com/developers/docs/interactions/message-components#buttons): + Buttons are attached to a message and can be clicked on to perform an action. +- [**Select Menus**](https://discord.com/developers/docs/interactions/message-components#select-menus): + Drop-down menus are used to select a number of options from a list. +- [**Modals**](https://discord.com/developers/docs/interactions/message-components#text-inputs): + Form-like modals can be used to ask for input from a user. + +## Application Commands + +Application Commands are another set of new features that are intended to avoid compromising users' safety and privacy. +They're relatively easy to add to your bot, and give people a simpler and safer way to use commands. + +### [Slash Commands](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.SlashCommand) + +Slash Commands were the first Interaction added to Discord. They're easy to use and create, and +is the only prefix commands alternative that does not need Message Content intent. + +:::note + +Preferring prefix commands over Application Commands is **not** a valid reason to apply for the +Message Content intent. Using that as a reason will get your application denied. + +::: + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +This is what a Slash Command looks like. Not too different from a prefix command, +apart from the note telling you who invoked it. A Slash Command's fields can accept any of the following: + +- Members +- Roles +- Channels +- Attachments +- Text + +Just about as good as it gets. + +### [Message](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.MessageCommand) and [User](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.UserCommand) Commands + +Message Commands and User Commands were both introduced at around the same time, and are very similar to each other, so we'll be +introducing them together. These commands can be found in the `Apps` tab when alt-clicking. The only difference between the two is that +Message Commands only appear in the `Apps` tab of a message, while User Commands are found in the `Apps` tab of a user. Message Commands +can be used to quickly report a message, warn a user for a message, and other functions. Likewise, User Commands can be used to add a +user to a ticket, warn a user, and more. + +Here's an example of a Message Command: + + + + Hello World! + + +
+ + Reverse Message + +
+ Message 930650407917748286 reversed is "!dlroW olleH" +
+
+ +
+ +And here's an example of a User Command: + + + + {defaultOptions.profiles.dorukyum.author} has been on Discord for a long time + + +
+ + User Age + +
+ {defaultOptions.profiles.dorukyum.author} is 1 week old. +
+ +
+ + User Age + +
+ {defaultOptions.profiles.bob.author} is 40 years old. +
+ + 🤔 + +
+ +
+ +Pretty cool, right? To learn more about these two, please read the [Context Menus guide](./application-commands/context-menus.mdx). + +## [Application Commands](#application-commands) vs. [Prefix Commands](../extensions/commands/prefixed-commands) + +Ever since Discord was created, apps on it have used prefix commands. Using prefixes meant that you would have to put a +certain character (or string of characters) in front of your command, such as the exclamation mark in `!ping`. The way this +worked was that your bot would listen for messages, pick out the ones that had their specific prefix, and then respond to the command. +Now, Discord is encouraging developers to switch their bots over to Application Commands, which is a new system meant to preserve the +privacy and safety of their users. But why exactly is Discord making us switch? What's the better option, Application Commands or prefix +commands? Below, we'll discuss everything you need to know. + +### Discord's Decision + +Application Commands were conceptualized partly due to privacy concerns. When Discord first began, they weren't entirely concerned about bots +having access to the content of every message that was being sent. However, as Discord grew, this became more of a problem. Hypothetically, bots +could simply log every message they're able to receive via the Discord API and hand their contents over to a company or other third party. This is +a problem, since that data is meant to be used only by Discord. As such, they locked down Message Content, and introduced Application Commands for +bot developers to use instead. + +Prefix commands work by reading messages, as described before. Application Commands, however, don't +work this way; instead, they work by having your bot get information from Discord about when a command was used. This way, Discord can limit +Message Content only to bots that _absolutely_ depend on it, such as auto-moderation bots. + +### Who has to Use Application Commands + +Any verified bot that does not have the Message Content intent must use Application Commands. Discord is allowing developers to submit +applications for the ability to use the intent; however, since they don't want to keep supporting prefix commands due to privacy concerns, +they will automatically decline any application that includes only that as a reason. So, if your bot doesn't have an auto-moderation feature +(or any other functionality that requires Message Content), you're out of luck. + +Unverified bots, however, don't have to use Application Commands. This is because the Message Content intent is a `Privileged Intent`, meaning that +it must be applied for only if your bot is verified or about to be verified. Unverified bots don't have to apply for Privileged Intents, so they can +use them freely. + +So, if your bot is made only for a couple of servers, you can choose between prefix commands and Application Commands. However, if you plan on expanding +your bot's reach, it'll have to use Application Commands. + +### What's the Better Option + +Choosing which is the better option is up to you, if you're starting small. If +you plan on growing your bot, however, you will have to use Application Commands. Since prefix commands are slowly being phased out by Discord, +there isn't much of a choice for developers of larger bots. + +## Message Components + +Message Components are fairly new features in Discord, allowing developers to give their bots a fast +and understandable user interface. Message Components are easy to use and make your bot look modern, +sleek, and downright awesome. + +### [Views](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View) + +Views are not an Application Command nor are they a Message Component. Views are the invisible placeholders, or grid, +that Message Components lie in. Views can have up to 5 [`Action Rows`](https://docs.pycord.dev/en/stable/api/models.html#discord.ActionRow), +and Action Rows can have a maximum of 5 slots. Below, you can find a table showing how many slots a Message Interaction takes up. + +| Component | Slots | +| ------------ | ----------------------------------------------- | +| Buttons | 1 Slot | +| Select Menus | 5 Slots | +| Text Modals | 1 Slot (opened via a Button) | + +So, based on this, you could have a maximum of 25 Buttons in a View with no Select Menus, and 5 Select +Menus in a View with no Buttons. This doesn't mean you can't have them both in a View, however. You can have +a combination of them, such as 20 Buttons and a Select Menu or 10 Buttons and 3 Select Menus. + +### [Buttons](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button) + +Buttons are the first of the Message Components. They allow for quick responses to prompts, such as for canceling or continuing an action. +Of course, these aren't their only uses; people have created awesome things with Buttons, such as calculators, games, and more! + + + + Discord Buttons are awesome! +
+ + Click me! + +
+
+
+ +
+ +This is what a Button looks like, very simple and modern. To learn more about Buttons, refer to our +[Buttons page](./ui-components/buttons.mdx). + +### [Select Menus](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Select) + +Select Menus are the second of Discord's Message Components. They allow users to select from a list of choices, which your bot can then use. +Select Menus are good for things such as choosing features, pages of a help menu, and more. + +![Select Menu Example Image](../assets/interactions/select-menus-example.png) + +This is what a Select Menu looks like. While not looking as good as Buttons, they still look great +and have even greater possibilities. To learn more about Select Menus, please refer to our [Select +Menus page](./ui-components/dropdowns.mdx). + +### [Modal Dialogs](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal) + +Text Modals are the most recently added Message Component in Discord. They're useful for text input and filling out forms, such as a +sign-up for your bot's service. These are meant to replace long bot setup processes by allowing users to fill out multiple text fields, +which avoids having the user send multiple messages for the bot. Modals can be accessed by either invoking an Application Command or by +interacting with another UI Component. + +![Text Modal Example Image](../assets/interactions/modal-example.png) + +This is what a Text Modal looks like, easy to use and one of the most useful Message Components yet. To learn more about Text Modals, +please visit our [Modal Dialogs page](./ui-components/modal-dialogs.mdx). diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json new file mode 100644 index 00000000..7b0a72fe --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "UI Components", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx new file mode 100644 index 00000000..046b36c7 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx @@ -0,0 +1,314 @@ +--- +title: Buttons +description: Learn all about implementing buttons in your Discord Bot using Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On May 26, 2021, Discord added a new interaction called buttons. Instead of reactions, bots could now +send buttons and users could use them to interact with bots. This opened up a whole new world of +possibilities for bots. Soon after, developers made calculators, polls, and games like blackjack, UNO, +and even Minecraft! Buttons provided a clear and easy to use interface for interacting with bots. + +So, let's learn how you can add buttons to your bot! + +## Concept + +Buttons weren't the only update to the interactions system in Discord. Discord also added [Select Menus](./dropdowns) and [Modal Dialogs](./modal-dialogs), both of which work very similarly to buttons. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive button. + +```python +import discord + +bot = discord.Bot() # Create a bot object + +class MyView(discord.ui.View): # Create a class called MyView that subclasses discord.ui.View + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.primary, emoji="😎") # Create a button with the label "😎 Click me!" with color Blurple + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") # Send a message when the button is clicked + +@bot.slash_command() # Create a slash command +async def button(ctx): + await ctx.respond("This is a button!", view=MyView()) # Send a message with our View class that contains the button + +bot.run("TOKEN") # Run the bot +``` + +Using this command should return the following message: + + + +
+ + button + +
+ This is a button! +
+ + Click me! + +
+
+
+ +
+ +As you can see, we create a class called `MyView` that [subclasses](#oop) +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `button_callback` to the `MyView` class with the decorator +[`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button). +This decorator adds a button to a component. This function takes two arguments: the button that was +clicked and the interaction. These arguments are passed to the function when the button is clicked +by the module. We use the [`interaction.response.send_message`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse.send_message) +function to send a message to the channel where the interaction was sent. + +Finally, we create a global slash command called `button` that sends the message, along with the view +that contains a button. + +This is the basic syntax of creating a button. What you create with it is up to you. You can worry +about making your button do amazing things, while Pycord handles the rest! + +## Button Styles + + + +| Name | Usage | Color | +| --------- | ----------------------------------------------------------------------------------------- | ------- | +| Primary | `discord.ButtonStyle.primary` / `discord.ButtonStyle.blurple` | Blurple | +| Secondary | `discord.ButtonStyle.secondary` / `discord.ButtonStyle.grey` / `discord.ButtonStyle.gray` | Grey | +| Success | `discord.ButtonStyle.success` / `discord.ButtonStyle.green` | Green | +| Danger | `discord.ButtonStyle.danger` / `discord.ButtonStyle.red` | Red | +| Link | `discord.ButtonStyle.link` / `discord.ButtonStyle.url` | Grey | + +Check out the [`discord.ButtonStyle`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ButtonStyle) class for more information. + +![Different Button Styles](../../assets/interactions/button-styles.png) + +You can set a button's style by adding the `style` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) decorator. + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.success) + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots, and each button takes up 1 slot. +So, how do we move the buttons to another row? + +This can be done by specifying the `row` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) +decorator. + +:::info The `row` argument + +The row argument specifies the relative row this button belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=1, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") +``` + +## Disabling Buttons + +### Pre-Disabled Buttons + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary, disabled=True) # pass `disabled=True` to make the button pre-disabled + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView()) +``` + +### Disabling Buttons on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + button.disabled = True # set button.disabled to True to disable the button + button.label = "No more pressing!" # change the button's label to something else + await interaction.response.edit_message(view=self) # edit the message's view +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(emoji="😀", label="Button 1", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) + + @discord.ui.button(label="Button 2", style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +Sometimes, you want to have a button that is disabled after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView(timeout=30)) +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a button that is disabled after a certain amount of time, you want to have a +button that is always working. + +Normally, when the bot goes offline, all of its buttons stop working. You will be able to see the +buttons, but nothing will happen when you press them. This is a problem +if you are trying to create a self-role system with buttons, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons will stop working. When the bot comes back online, however, the buttons will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view must have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.button(label="A button", custom_id="button-1", style=discord.ButtonStyle.primary, emoji="😎") # the button has a custom_id set + async def button_callback(self, button, interaction): + await interaction.response.send_message("Button was pressed", ephemeral=True) + +@bot.command() +async def button(ctx): + await ctx.send(f"Press the button! View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many buttons can I have in a message? + +Each message can have a maximum of 25 buttons. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do buttons need any special permissions? + +No new permissions are needed for either the bot or the server to allow bots to use buttons. + +#### Should I replace reactions with buttons for my bot? + +That is up to you. Buttons do provide a cleaner interface for your bot and are easier to use. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx new file mode 100644 index 00000000..8320f25d --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx @@ -0,0 +1,339 @@ +--- +title: Select Menus +description: Learn all about implementing Select Menus or Dropdowns in your Discord Bot with Pycord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Shortly after the buttons were added, Discord added their second message component: Select Menus. Select Menus allow users to choose from a list of items sent by a bot. These are a great substitute for having a user send a number that corresponds to an option. You can even allow users to select multiple options from the Select Menus. This guide will show you the easy and painless ways of using them with Pycord. + +## Concept + +Select Menus aren't the only message component in Discord. There's also [Buttons](./buttons) and [Modal Dialogs](./modal-dialogs). Select Menus make it easy for users to pick one or multiple options from a list provided by a bot. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive select menu. + +```python +import discord + +bot = discord.Bot() + +class MyView(discord.ui.View): + @discord.ui.select( # the decorator that lets you specify the properties of the select menu + placeholder = "Choose a Flavor!", # the placeholder text that will be displayed if nothing is selected + min_values = 1, # the minimum number of values that must be selected by the users + max_values = 1, # the maximum number of values that can be selected by the users + options = [ # the list of options from which users can choose, a required field + discord.SelectOption( + label="Vanilla", + description="Pick this if you like vanilla!" + ), + discord.SelectOption( + label="Chocolate", + description="Pick this if you like chocolate!" + ), + discord.SelectOption( + label="Strawberry", + description="Pick this if you like strawberry!" + ) + ] + ) + async def select_callback(self, select, interaction): # the function called when the user is done selecting options + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") + +@bot.command() +async def flavor(ctx): + await ctx.respond("Choose a flavor!", view=MyView()) + +bot.run("TOKEN") +``` + +There's a lot going on over here! Don't worry, we will go over the code and explain it. + +As you can see, we create a class called `MyView` that subclasses +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `select_callback` to the `View` class with the decorator +[`discord.ui.select`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.select). +This decorator adds a select menu to the view. This decorator takes a few arguments to customize your select menu. Read them in the [Customization section](#customization). + +That was the decorator. Now, the function itself is pretty simple. It takes two parameters, not including `self`. The parameters are `select`: The select menu, and `interaction`: a [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object. Both of these are passed by Pycord, so you just need to specify them in the function! + + + +In the callback, you could do anything you want. You get the two parameters `select` and `interaction` to play around with. Here, we send a message using `await interaction.response.send_message` (where interaction is [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse)) with content `select.values[0]`, which sends the label of the first/only option the user selected. Obviously, this is only an example, and you could do just about anything you want. + +Finally, we create a global slash command called `flavour` that sends a message "Choose a flavor!" along with the view +that contains our select menu. + +This is the basic syntax of creating a select menu. What you create with it is up to you. You can worry +about making your code do amazing things, while Pycord handles the rest! + +## Customization + +#### Select Menu Properties + +- `select_type`: The type of select to create. This must be a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. +- `channel_types`: A list of channel types that can be selected in the menu. This is only valid for selects of `select_type` [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType). +- `options`: A list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. These are the options that can be selected in this menu. +- `placeholder` is the placeholder text shown in the select menu if no option is selected. +- `custom_id`: The ID of the select menu that gets received during an interaction. It is recommended not to set this to anything unless you are trying to create a persistent view. +- `row`: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). +- `min_values`: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `max_values`: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `disabled`: Whether the select is disabled or not. Defaults to False. + +#### Select Option Properties + +In the `options` parameter, you pass a list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. This class also has a few parameters: + +- `default` (whether the option is selected by default) +- `description` (an additional description, if any) +- `emoji` (a string or an emoji object, if any) +- `label` (the name displayed to users, can be up to 100 characters) +- `value` (a special value of the option, defaults to the label). + +## Select Types + +In addition to regular string selects, you can also have your select menu contain users, roles, mentionables, and channels as its options. You can use these alternative select types by passing a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value for the `select_type` parameter when creating the Select. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.user_select + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +Additionally, you can use shortcut decorators to create a [`discord.ui.Select`](https://docs.pycord.dev/en/master/api/ui_kit.html#discord.ui.select) with a predetermined [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. Using a shortcut decorator, the above code can be rewritten like this: + +```python +class MyView(discord.ui.View): + @discord.ui.user_select() + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +### Specifying Channel Types + +When using a [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType.channel_select) type select menu, you can pass in a list of [`discord.ChannelType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ChannelType) values to limit which types of channels users can choose when interacting with the select menu. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.channel_select, + channel_types=[discord.ChannelType.text, discord.ChannelType.voice] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"You selected {select.values[0].mention}") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots. A button takes a single slot, while a select menu takes up all 5 of them. This means a view can have a maximum of 5 select menus, or any possible combination of select menus and buttons. + +The arrangement of buttons and select menus is generally adjusted by Pycord. However, it is possible to move them to specific relative rows. This is done by specifying the `row` argument. + +:::info The `row` argument + +The row argument specifies the relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero-indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=0, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.select( + row = 1, + options = [...] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") +``` + +## Disabling Select Menus + +### Pre-Disabled Menus + +```python +class MyView(discord.ui.View): + @discord.ui.select( + disabled = True, # pass disabled=True to set the menu as disabled + options = [...] + ) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send("Select and option from the menu!", view=MyView()) +``` + +### Disabling Menus on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + select.disabled = True # set the status of the select as disabled + await interaction.response.edit_message(view=self) # edit the message to show the changes +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def first_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) # edit the message to show the changes + + @discord.ui.select(options = [...]) + async def second_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +You may want a select menu to automatically stop working after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select(ctx): + await ctx.send(view=MyView(timeout=30)) # specify the timeout here +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a select menu that is disabled after a certain amount of time, you want to have a +select menu that is always working. + +Normally, when the bot goes offline, all of its views stop working, even if they don't have a timeout. You will be able to see the +views, but nothing will happen when you try to interact with them. This is a problem +if you are trying to create a self-role system, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons and select menus will stop working. However, when the bot comes back online, the buttons and select menus will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view much have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.select(custom_id="select-1", options = [...]) # a custom_id must be set + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send(f"View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many select menus can I have in a message? + +Each message can have a maximum of 5 select menus. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do select menus need any special permissions? + +No new permissions are needed in the bot or in the server. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx new file mode 100644 index 00000000..bd585c77 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx @@ -0,0 +1,107 @@ +--- +title: Modal Dialogs +description: Learn how you can implement Modals in your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Modal Dialogs, also known as "modals", provide a form-like structure for bots to receive input from users. No extra permissions are needed for bots to send modal dialogs, so it becomes a convenient workaround for bots to receive longer input without needing the Message Content [intent](../../popular-topics/intents). + +## Concept + +Modal Dialogs consist of a title, custom ID, and up to 5 [`discord.ui.InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) components. While creating modals, we generally subclass [`discord.ui.Modal`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal), as we'll see later. + +Unlike other UI Components, Modals cannot be sent with messages. They must be invoked by an Application Command or another UI Component. + +## Usage Syntax + +```py +class MyModal(discord.ui.Modal): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.add_item(discord.ui.InputText(label="Short Input")) + self.add_item(discord.ui.InputText(label="Long Input", style=discord.InputTextStyle.long)) + + async def callback(self, interaction: discord.Interaction): + embed = discord.Embed(title="Modal Results") + embed.add_field(name="Short Input", value=self.children[0].value) + embed.add_field(name="Long Input", value=self.children[1].value) + await interaction.response.send_message(embeds=[embed]) +``` + + + + +The `ctx` parameter we define in Application Commands receives an [`ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext) object. Using its `send_modal()` coroutine, you can send a Modal dialog to the user invoking the Application Command. + +```py +@bot.slash_command() +async def modal_slash(ctx: discord.ApplicationContext): + """Shows an example of a modal dialog being invoked from a slash command.""" + modal = MyModal(title="Modal via Slash Command") + await ctx.send_modal(modal) +``` + + + + +The `interaction` parameter we define in UI Components receives an [`Interaction`](https://docs.pycord.dev/en/stable/api/models.html#discord.Interaction) object. The `response` attribute of the object contains an [`InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object, with various coroutines such as `send_message()` and `send_modal()`, which we utilize. + +```py +class MyView(discord.ui.View): + @discord.ui.button(label="Send Modal") + async def button_callback(self, button, interaction): + await interaction.response.send_modal(MyModal(title="Modal via Button")) + +@bot.slash_command() +async def send_modal(ctx): + await ctx.respond(view=MyView()) +``` + + + + +The above example uses an embed to display the results of the modal submission, but you can do anything you want with the text provided by the user. +Each input field can be accessed in the order it was added to the modal dialog, via `Modal.children`. + +## Customization + +A Modal can have up to 5 [`InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) fields. These fields offer some customization. + +Each field has a label which is shown to the user. This is defined with `label`. + +The `style` parameter is used to determine whether it should be a short (single-line) or long (multi-line) input field. + +There are a number of aliases that can be used: + +```x title="Single-line InputTextStyle values:" +short +singleline +``` + +```x title="Multi-line InputTextStyle values:" +paragraph = 2 +multiline = 2 +long = 2 +``` + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Buttons](./buttons) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/introduction.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/introduction.mdx new file mode 100644 index 00000000..3262c632 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/introduction.mdx @@ -0,0 +1,50 @@ +--- +title: Introduction +description: Pycord Guide is a complete guide for Pycord. Learn how to create Discord Bots today! +sidebar_position: 1 +--- + +Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord, written in Python. Pycord is a maintained fork of [discord.py](https://github.com/Rapptz/discord.py). + +## Before you begin + +Pycord is an advanced and complex Python library. To take advantage of the full capabilities of Pycord, you will need to have a good understanding of Python. You should know the basics of Python and have an understanding of the following concepts: + +- Variables +- Data Types +- Functions +- Packages +- Conditionals +- Loops +- Classes +- Object-Oriented Programming +- Inheritance +- Exception Handling +- Iterators +- Coroutines +- Async/Await + +This list is not exhaustive, but it should give you a good idea of what you need to know to get started. + +When you see an ellipsis - that's the three dots - in this guide, it is a placeholder for code that you need to fill in. Sometimes, it may be code for a command, while other times it could be something simple like a Guild ID. Make sure to replace them before running your bot! + +## Learning Resources + +Here are some good resources to get started or to freshen up your Python knowledge: + +- [Official Beginner's Guide](https://wiki.python.org/moin/BeginnersGuide) +- [Official Tutorial](https://docs.python.org/3/tutorial/) +- [Automate the Boring Stuff, a free online book for complete beginners to programming](https://automatetheboringstuff.com/) +- [Learn Python in y Minutes, complete cheat sheet for people who know programming already](https://learnxinyminutes.com/docs/python3/) +- [Swaroopch's free Python book](http://python.swaroopch.com/) +- [Codeabbey, exercises for beginners](http://www.codeabbey.com/) + +## Credits + +First of all, we would like to thank [Rapptz](https://github.com/Rapptz) for the original [discord.py](https://pypi.org/project/discord.py) library. Pycord is a maintained fork of this library. + +We would also like to thank the [discord.js guide](https://discordjs.guide), which inspired this guide style-wise, and the [original Pycord Guide](https://namantech.me/pycord), which inspired some content in this guide. + +We created this guide using [Docusaurus v2](https://docusaurus.io), a modern static site generator for React. We would also like to thank Danktuary for his [`@discord-message-components/react`](https://www.npmjs.com/package/@discord-message-components/react) package, from which we took the Discord message components. + +And finally, we would like to thank the amazing and loving community of Pycord users, contributors and developers. diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/more/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/more/_category_.json new file mode 100644 index 00000000..2cbe2c56 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/more/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 8, + "label": "More", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/more/community-resources.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/more/community-resources.mdx new file mode 100644 index 00000000..ed3075bd --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/more/community-resources.mdx @@ -0,0 +1,23 @@ +--- +title: Community Resources +--- + +This page showcases the amazing things created by the Pycord community, including bots, Plugins, and more. + +## Plugins + +| Name | Type | GitHub | +| --------------- | ------------ | --------------------------------------------------------------- | +| Music Cord | Music | [NixonXC/cord-music](https://github.com/NixonXC/cord-music) | +| pycord-i18n | Localization | [Dorukyum-pycord-i18n](https://github.com/Dorukyum/pycord-i18n) | +| pycord-multicog | Cogs | [pycord-multicog](https://github.com/Dorukyum/pycord-multicog) | +| EzCord | Utilities | [EzCord](https://github.com/tibue99/ezcord) | + +## Bots + +| Name | Type | Link | +| ------------------------ | ------------ | ----------------------------------------------------------------------------------- | +| Discord-Multipurpose-Bot | Multipurpose | [github](https://github.com/pogrammar/Discord-multipurpose-bot/tree/master/Python) | +| inconnu | Fun & QOL | [github](https://github.com/tiltowait/inconnu) | +| Mai | Multipurpose | [github](https://github.com/TeamMai/Mai) & [website](https://xfghoul.github.io/Mai) | +| Toolkit | Multipurpose | [github](https://github.com/Dorukyum/Toolkit) | diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/more/contributing.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/more/contributing.mdx new file mode 100644 index 00000000..469ea3ee --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/more/contributing.mdx @@ -0,0 +1,463 @@ +--- +title: Contributing to the Guide +description: Learn how to contribute to the Pycord Guide. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +This page outlines some of the basic syntax you need to know to contribute to the guide. We recommend you also check out: + +- [Docusaurus's Docs](https://docusaurus.io/docs/) +- [Contributing Rules](https://github.com/Pycord-Development/guide/blob/master/.github/CONTRIBUTING.md) + +## Info + +We use [Docusaurus v2](https://docusaurus.io/) to generate our guide. All the guide pages are generated +from `mdx` files in the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory. +MDX allows you to use JSX in your markdown content. + +## Structure + +Let's visit the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory and check its file structure. + +We can see various folders and a few files in it. Let's talk a bit about the `introduction.mdx` file. At the top, you can see something like: + +```md +--- +title: Introduction +description: ... +sidebar_position: 1 +--- +``` + +Most pages have this at the top. The `title` defaults to the file name. Since the titles need to be Capitalized according to need while the file names are lowercased (sometimes, the file names are shorter than the title!), we set a title ourselves. + +The `description` field is also important. This is the text shown in an embed when the page's link is shared on Discord, Twitter or other websites that support embedded links. Make sure to give a nice an interesting description! + +The `sidebar_position` field is pretty self-explanatory. It sets the position of the page in the sidebar. Most files in categories do not need this since they are sorted alphabetically. + +## Markdown Syntax + +This page quickly outlines some of the syntax that is used in markdown. + +````mdx +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + + ```python + print("We can use code blocks like this.") + ``` + +You can add [links to other websites](https://pycord.dev). You can add images like this: ![alternate text that describes the image](https://pycord.dev/image.png). + +- You can create +- unordered lists like this + +1. Or ordered lists +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` +4. Like this + +# Headers + +## Go + +### Like + +#### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet +```` + +
+Preview +
+ +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + +```python +print("We can use code blocks like this.") +``` + +You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](@site/static/img/favicon.ico). + +- You can create +- unordered lists like this + +1. Or ordered lists + +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` + +4. Like this + + # Headers + + ## Go + + ### Like + + #### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet + +
+
+ +## Admonitions + +We can add warnings, notes, etc. with the following syntax: + +```md +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: +``` + +
+Preview +
+ +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: + +
+ +
+ +## Discord Message Components + +As most files already have the imports for these, it's not that hard to add them. + +First, import the necessary components: + +```tsx +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; +``` + +The div starts like so: + +```tsx + + + + +
+``` + +This is where you list a `DiscordMessage`. + +```tsx + + + Hello! + + + +
+``` + + + + Hello! + + + +
+ +It has a pretty straightforward syntax. + +:::tip + +Add a `
` to the end of a component to make the content below it look better. + +::: + +### Slash Commands + +To make a message authored by a slash command, do the following: + +```tsx + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+``` + + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+ +### Buttons + +To make a message with buttons, do the following: + +```tsx + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+``` + + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+ +## Page Format + +There are a few things you need to take care of: + +1. Make sure that the spelling and grammar is perfect. We have a GitHub action configured that will warn you about spelling errors when you start a pull request. Make sure to commit your changes accordingly. + + As for the grammar, you should try reading the changes you have done and wait for reviews from others. + +2. A common mistake people make is incorrect header style. People often think that the less the important the topic is, the lower it's heading style should be. + + ```md + [PAGE STARTS] + # Topic + ## Less Important Topic + ## Subtopic + ``` + + ```md + [PAGE STARTS] + # About + [Introduction] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + That's VERY wrong. Here's the correct example: + + ```md + [PAGE STARTS] + [Introduction] + ## Topic + ## Less Important Topic + ### Subtopic + ``` + + ```md + [PAGE STARTS] + [Introduction] + + ## About + [More Information] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + Note that the `---`s at the beginning have been skipped here. diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/more/git.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/more/git.mdx new file mode 100644 index 00000000..0f929d6d --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/more/git.mdx @@ -0,0 +1,55 @@ +--- +title: Installing Git +description: Learn how you can install Git on your system. +--- + +Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Let's see how to install Git on different platforms. + +## Windows + +On Windows, Git can be installed via: + +- [Git for Windows](https://gitforwindows.org) +- [Git Scm](https://git-scm.com/download/windows) + +## Linux + +On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. + +## Mac + +You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: + +``` +xcode-select --install +``` + +## Using Package Managers + +You can also install Git using package managers. + +### Chocolatey + +If you use the Chocolatey package manager, you can install Git using: + +``` +choco install git +``` + +### Scoop + +If you use Scoop, you can install Git using: + +``` +scoop install git +``` + +### Brew + +If you're on macOS or Linux, you can install Git using: + +``` +brew install git +``` diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx new file mode 100644 index 00000000..b0b8c7ea --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx @@ -0,0 +1,62 @@ +--- +title: Virtual Environments +description: Learn how to set up a virtual environment for Pycord. +--- + +## Setup + +Sometimes you want to keep libraries from polluting system installs or use a different version of libraries than the ones installed on the system. You might also not have permissions to install libraries system-wide. For this purpose, the standard library as of Python 3.3 comes with a concept called “Virtual Environment”s to help maintain these separate versions. + +A more in-depth tutorial is found on [Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html). + +However, for the quick and dirty: + +Go to your project’s working directory: + +```bash +$ cd your-bot-source +$ python3 -m venv venv +``` + +Activate the virtual environment: + +```bash +$ source venv/bin/activate +``` + +On Windows you activate it with: + +```batch +$ venv\Scripts\activate.bat +``` + +Use pip like usual: + +```bash +$ pip install -U py-cord +``` + +Congratulations. You now have a virtual environment all set up. + +## Additional info + +It can be useful to set up a requirements.txt, so you can just put all of your dependencies in there and have pip install it. +For instance, if you wanted to have the latest 2.0 version of pycord and [pytz](https://github.com/stub42/pytz/blob/master/src/README.rst), just create a file named requirements.txt with the following contents: + +``` +py-cord>=2.0.0 +pytz +``` + +And then (in your virtual environment) you can just execute + +```bash +pip install -r requirements.txt +``` + +To keep from committing your virtual environment to git, you can set up a .gitignore file with the following line +(assuming you named your virtual environment venv like the above example): + +``` +venv/ +``` diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/_category_.json new file mode 100644 index 00000000..c38ea014 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 7, + "label": "Popular Topics", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx new file mode 100644 index 00000000..5377a6c3 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx @@ -0,0 +1,140 @@ +--- +title: Cogs +--- + +Cogs, often known as modules or extensions, are used to organize commands into groups. This is useful +for grouping commands that have the same general idea (such as moderation commands). This also helps +to avoid making your bot's files messy and cluttered. + +## Getting Started + +First, you'll need to create a folder to store your cogs, e.g. `cogs/`. + +Then, create a file inside the folder, e.g. `cogs/greetings.py`. By convention, the file name should +be the same as the name of the cog or module. + +We can then create the cog. + +```python title="./cogs/greetings.py" +import discord +from discord.ext import commands + +class Greetings(commands.Cog): # create a class for our cog that inherits from commands.Cog + # this class is used to create a cog, which is a module that can be added to the bot + + def __init__(self, bot): # this is a special method that is called when the cog is loaded + self.bot = bot + + @commands.command() # creates a prefixed command + async def hello(self, ctx): # all methods now must have both self and ctx parameters + await ctx.send('Hello!') + + @discord.slash_command() # we can also add application commands + async def goodbye(self, ctx): + await ctx.respond('Goodbye!') + + @discord.user_command() + async def greet(self, ctx, member: discord.Member): + await ctx.respond(f'{ctx.author.mention} says hello to {member.mention}!') + + math = discord.SlashCommandGroup("math", "Spooky math stuff") # create a Slash Command Group called "math" + advanced_math = math.create_subgroup( + "advanced", + "super hard math commands!" + ) + + @math.command() + async def add(self, a: int, b: int): + c = a + b + await ctx.respond(f"{a} + {b} is {c}.") + + @advanced_math.command() + async def midpoint(self, x1: float, y1: float, x2: float, y2: float): + mid_x = (x1 + x2)/2 + mid_y = (y1 + y2)/2 + await ctx.respond(f"The midpoint between those coordinates is ({mid_x}, {mid_y}).") + + @commands.Cog.listener() # we can add event listeners to our cog + async def on_member_join(self, member): # this is called when a member joins the server + # you must enable the proper intents + # to access this event. + # See the Popular-Topics/Intents page for more info + await member.send('Welcome to the server!') + +def setup(bot): # this is called by Pycord to setup the cog + bot.add_cog(Greetings(bot)) # add the cog to the bot +``` + +You can add any number of commands to your cog, as well as event listeners. However, this code will +not work on its own. In your main bot file, you must add the following code: + +```python +bot.load_extension('cogs.greetings') +``` + +This loads the file `cogs/greetings.py` and adds it to the bot. +The argument of `load_extension` should be your cog's path (e.g. cogs/greetings.py) without the file +extension and with the `/` replaced with `.` + +If you have multiple cogs, you can add them all at once by adding the following code: + +```python +cogs_list = [ + 'greetings', + 'moderation', + 'fun', + 'owner' +] + +for cog in cogs_list: + bot.load_extension(f'cogs.{cog}') +``` + +## Cog Rules + +When using a cog instead of the main file, there are some changes you have to make to your code. This +is because cogs work slightly different from a regular file. + +### The `self` variable + +The self variable is a variable that represents a class. In the case of cogs, `self` represents +the cog. In the `__init__` function, you can see that we have `self.bot = bot`. `bot` represents your +`discord.Bot` or `discord.ext.commands.Bot` instance, which is used for some functions. + +This means that instead of using functions that would usually be accessed via `bot`, you now need +to access them via `self.bot` + +Because we're in a class, all of our commands are methods of that class. Because of this, all of our +functions need to have `self` as the first parameter, where `self` is the cog. Without this, we +wouldn't be able to access our bot instance. + +### Creating Commands + +When creating prefixed commands, your decorator would usually be something like `@bot.command()`. If you're using +cogs, this isn't the case. In a cog, you can't access the bot instance outside of functions, so to +register a function as a command, you must instead use `@commands.command()`. + +Similar to prefixed commands, you'll have to use either the `@discord.slash_command()`, `@discord.user_command()`, +or `@discord.message_command()` decorators for Application Commands. + +Also, when creating a command, make sure that it is indented. If we want a command to be actually +inside a cog, it has to be inside your cog's class. If the command is not inside the cog, +your command becomes useless. + +### Events + +When creating events, you can no longer use `@bot.event` as a decorator. This is because we cannot +access the `bot` variable outside a function. To make an event, you have to use the `ext.commands` +method, `@commands.Cog.listener()`. Events also need `self` as their first parameter. + +And that's it! Cogs are a simple and easy way of organizing your code. Now you can check out how to +create a help command [here](../extensions/commands/help-command). + +:::info Related Topics + +- [Creating a Help Command](../extensions/commands/help-command) +- [Rules and Common Practices](../getting-started/rules-and-common-practices) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Application Commands](../interactions#application-commands) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx new file mode 100644 index 00000000..6c19dd29 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx @@ -0,0 +1,383 @@ +--- +title: Error Handling +description: All about handling errors. +--- + +import { + DiscordEmbed, + DiscordInteraction, + DiscordMessage, +} from "discord-message-components/packages/react"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +## About + +When using the library, errors are frequently raised due to various reasons. These reasons range from the Discord API +failing your bot's request due to missing permissions or an invalid syntax error. + +Before going into error handling, it's best that you learn the basic ways of handling errors. A good resource is: + +- [W3Schools' Guide to Python Try-Except Statements](https://www.w3schools.com/python/python_try_except.asp) + +## Basic Handling + +The most basic way to handle errors is to tackle it at the source. This can be done like so: + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +import asyncio + +import discord + +intents = discord.Intents.default() +intents.message_content = True + +bot = discord.Bot(intents=intents) + + +@bot.slash_command(description="Gets some feedback.") +@discord.option("name", description="Enter your name.") +async def feedback(ctx: discord.ApplicationContext, name: str): + try: + await ctx.respond(f"Hey, {name}! Send your feedback within the next 30 seconds please!") + + def is_author(m: discord.Message): + return m.author.id == ctx.author.id + + feedback_message = await bot.wait_for("message", check=is_author, timeout=30.0) + await ctx.send(f"Thanks for the feedback!\nReceived feedback: `{feedback_message.content}`") + except asyncio.TimeoutError: + await ctx.send("Timed out, please try again!") + + +bot.run("TOKEN") +``` + +If you respond within 30 seconds, the interaction will look like so: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Great bot! + + + Thanks for the feedback! +
+ Received feedback: Great bot! +
+
+
+ +Otherwise, if you don't respond in time, the interaction will go as follows: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Timed out, please try again! + +
+
+ +This basic method of error handling can be extended to handle +many other errors including ones raised directly by py-cord. + +## Per-Command Handling + +This type of error handling allows you to handle errors per each command you have on your bot. +Each and every command can have it's own error handler made to handle specific errors that each command may raise! + +An example of per-command error handling is as follows: + +:::note Bridge Commands + +For these types of commands, it is recommended to utilize global error handling +until [the feature](https://github.com/Pycord-Development/pycord/issues/1388) is added. +::: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot(owner_id=...) # Your Discord user ID goes in owner_id + + +@bot.slash_command(description="A private command...") +@commands.is_owner() # This decorator will raise commands.NotOwner if the invoking user doesn't have the owner_id +async def secret(ctx: discord.ApplicationContext): + await ctx.respond(f"Hey {ctx.author.name}! This is a secret command!") + + +@secret.error +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.NotOwner): + await ctx.respond("Sorry, only the bot owner can use this command!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If your ID is registered as the owner ID, you'll get the following: + + + +
+ + secret + +
+ Hey Dorukyum! This is a secret command! +
+
+
+ +Any other user whose ID doesn't match the bot owner's will get the following: + + + +
+ + secret + +
+ Sorry, only the bot owner can use this command! +
+
+
+ +This local (per-command) error handler can also be used to handle the same types of errors that standard try-except +statements can handle. This is done by using the same method as above with the `isinstance` built-in function. + +## Per-Cog Handling + +Adding error handlers per-command can be quite the task in terms of work if you have a lot. If you have happened to +group your commands in cogs, then you're in luck! You can create an error handler that is specific to a cog and +handles all errors raised by commands inside that cog. + +Here's an example of a bot with a cog that implements its own error handling: + +```python title="./cogs/dm.py" +# This cog is for DM only commands! Sadly, we only have 1 command here right now... + +import discord +from discord.ext import commands + + +class DM(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.command() + @commands.dm_only() # This decorator will raise commands.PrivateMessageOnly if invoked in a guild context. + async def avatar(self, ctx: commands.Context): + embed = discord.Embed( + title="Avatar", + description=f"Here's your enlarged avatar, {ctx.author.name}!", + color=ctx.author.top_role.color + ) + embed.set_image(url=ctx.author.display_avatar.url) + await ctx.send(embed=embed, reference=ctx.message) + + async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): + if isinstance(error, commands.PrivateMessageOnly): + await ctx.send("Sorry, you can only use this in private messages!", reference=ctx.message) + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +def setup(bot: commands.Bot): + bot.add_cog(DM(bot)) +``` + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +# This is the main file where we load the DM cog and run the bot. + +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix=commands.when_mentioned_or("!")) +bot.load_extension("cogs.dm") +bot.run("TOKEN") +``` + +If you use this command in a DM context, you'll get the following: + + + + !avatar + + +
+ + !avatar + +
+ + Here's your enlarged avatar, BobDotCom! + +
+
+
+ +Otherwise, if used in a guild context: + + + + !avatar + + +
+ + !avatar + +
+ Sorry, you can only use this in private messages! +
+
+
+ +Per-cog error handling comes in very handy as you can relegate all of your error handling to a single function instead +of spreading it out across several per-command error handlers or inside the commands themselves. + +## Global Handling + +If separating your error handling is not how you would like to handle errors, then global error handling is the way to +go. This method of handling allows you to relegate all handling to a single function that resides within your bot +instance. + +A non-subclassed bot would implement this like so: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot() + + +@bot.slash_command(description="Get the bot's current latency!") +@commands.cooldown(1, 30, commands.BucketType.user) +# ^ This decorator allows one usage of the command every 30 seconds and raises commands.CommandOnCooldown if exceeded +async def ping(ctx: discord.ApplicationContext): + await ctx.respond(f"Pong! `{int(bot.latency*1000)} ms`.") + + +@bot.event +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.CommandOnCooldown): + await ctx.respond("This command is currently on cooldown!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If you've subclassed your bot, the `on_application_command_error` event will be placed inside the subclass without a +`bot.event` decorator and `bot.slash_command` will be replaced with `discord.slash_command`. + +The error handling used above will yield this interaction if the command is used again too quickly: + + + +
+ + ping + +
+ Pong! 49 ms. +
+ +
+ + ping + +
+ This command is currently on cooldown! +
+
+
+ +The only issue regarding global error handling is that, if you have a large amount of commands, the global handler may +start to get crammed with a lot of code. This is where all the previously mentioned handlers can take their place! + +## FAQ + +#### Why does the example in per-cog handling have self at the start of its function signatures? + +This is a feature of classes and allows you to reference the cog object as `self` and get access to the bot object +passed at initialization through `self.bot`. + +If this is new to you, we recommend checking out these helpful resources to learn more about classes and cogs: + +- [W3Schools' Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [Our Cogs Guide Page](./cogs) + +#### How many errors can I handle in a single error handler? + +While all the examples in this guide page only handle one specific error and re-raise all others, all of these +error handlers can be extended to catch many errors. + +In [basic handling](#basic) (i.e. try/except statements) you can do one of two things: + +- Explicitly handle the errors you know might get raised and then have a broad `except Exception as exc:` statement + as a catch-all. +- Catch any and all errors via the catch-all statement mentioned above. + +In [per-command](#percommand), [per-cog](#percog), and [global handling](#global), you can use elif clauses with the +built-in isinstance function to catch specific errors. Atop of this, an else clause can be used to catch any other +errors you either don't want to handle or want to relegate to a different error handler. + +#### Can I use more than one type of error handler at once? + +Thankfully, all of these different ways of error handling can be mixed together, so you don't have to pick just one! +For commands that raise specific errors that no other commands will raise, you can use [per-command](#percommand). +For cogs that raise specific errors that no other cogs will raise, use [per-cog](#percog)! Lastly, for errors that +occur frequently across all commands and cogs, use [global handling](#global)! + +However, one important note to remember is that you should always raise the error again in an error handler if it +isn't handled there! If you don't do this, the error will go ignored and your other handlers won't have a chance to +do their work! + +#### What's the difference between slash and prefixed command error handling? + +Although most examples shown here use slash commands, the [per-cog handling](#percog) section presents a prefixed +command. The main difference you may notice is the change in command signature. + +To make the distinguishing features apparent: + +- Slash commands use `on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException)` + as presented in the [per-command](#percommand) and [global handling](#global) examples. +- Prefixed commands use `on_command_error(ctx: commands.Context, error: commands.CommandError)` as presented in the + [per-cog handling](#percog) example. + +This distinction is made as both types of commands need their own system for handling errors that are specific to +themselves. + +:::info Related Topics + +- [Slash Commands](../interactions/application-commands/slash-commands) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Cogs](./cogs) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx new file mode 100644 index 00000000..9f4210af --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx @@ -0,0 +1,62 @@ +--- +title: Intents +description: All about intents in Discord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +## What are Intents? + +Intents allow bot developers to "subscribe" to specific events in Discord. This is useful for bots that need to respond to specific events, such as when a user joins a server or sends a message. You could choose to enable all intents or to enable only specific intents that your bot requires. + +## How do I enable intents? + +:::important + +Remember that [Privileged Intents](#what-are-privileged-intents) require you to enable them in the Discord Developer Portal. Verified Discord Bots that don't already have access to them will need to request Discord to allow access. + +::: + + + + +```python +import discord + +bot = discord.Bot(intents=discord.Intents.all()) +``` + + + + + +You can view a list of intents and the events they subscribe to [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```python title="Enabling Intents" +import discord + +bot = discord.Bot(intents=discord.intents.members(bans=True, guilds=True)) +``` + + + + +## What are Privileged Intents? + +Discord defines some intents as "privileged" because of the sensitive information they contain. Currently, there are three privileged intents: `members`, `presences`, and `message_content`. These intents must be enabled in your bot's Developer Portal. Once your bot reaches 100 servers, you will need to verify your bot for these intents to keep working and for your bot to be able to be invited to more guilds. + +:::tip + +Only enable these intents if you need them. These intents give your bot access to quite sensitive information about the users in your guild. These intents are privileged to respect the privacy of users, and you should do that as well. + +Not enabling these intents doesn't mean you won't be able to ban users, but you will be unable to detect when a new user joins a guild, or what game they are playing. The majority of bots won't need all intents. + +::: + +:::info Related Topics + +- [Sharding Bots](sharding) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx new file mode 100644 index 00000000..c3d17197 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx @@ -0,0 +1,48 @@ +--- +title: Sharding +description: All about Sharding Discord Bots. +--- + +# Sharding + +## What is Sharding? + +Sharding is the process of breaking up your bot into smaller pieces so that it has a better time handling +events. As [Discord's Documentation](https://discord.com/developers/docs/topics/gateway#sharding) puts +it, sharding is "a method of user-controlled guild sharding which allows for splitting events across +several gateway connections." + +Sharding is used only for large bots and takes up additional resources for managing the new processes. +Pycord automatically shards your bot, so the only thing you need to do is use an `AutoShardedClient` +or `AutoShardedBot` class instead of a plain `Client` or `Bot` class. Pretty cool, right? + +Just because you _can_ shard your bot doesn't mean you _should_. While Pycord makes it easy to shard +your bot, it isn't necessary to shard unless your bot is large. Sharding a small bot isn't +just useless, but _harmful_, as it uses extra resources and may slow down your bot. Discord +themselves will let you know when your bot needs sharding, so you won't need to worry about this until they contact you. + +## How Do I Shard in Pycord? + +Sharding in Pycord is straightforward. + +Just replace your `discord.Client`, `discord.Bot`, `commands.Bot` objects +with `discord.AutoShardedClient`, `discord.AutoShardedBot`, `commands.AutoShardedBot` respectively. + +These new objects have been inherited from the original objects, so all the functions from those other types should be present. + +If you want to specify the number of shards your bot uses, +just add the `shards` parameter, along with the number of shards you want. + +## Why Should I Shard my Bot? + +Sharding is very necessary for big bots. While your bot grows, it gets harder for your bot to control +how many guilds it is in and what parts of your code should do what. This is exactly what sharding +handles, it makes all of this easier for your bot. Remember, though, only shard your bot once it's +big enough, and that's at _least_ 1,000 guilds. + +:::info Related Topics + +- [Hosting your Bot](../Getting-Started/hosting-your-bot) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx new file mode 100644 index 00000000..bd2969c1 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx @@ -0,0 +1,115 @@ +--- +title: Subclassing Bots +description: Subclassing is a popular way of creating Discord Bots. Explore how you can create a Discord bot by subclassing. +--- + +## About + +Subclassing is another popular way of creating Discord Bots. Here, you create a bot by extending a bot class. To some advanced users, this is preferable to creating a bot instance with `bot = discord.Bot()`. + +Subclassing is an intermediate python concept, so we recommend you learn about it before continuing. Some good resources are: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +## Why Subclassing? + +Many developers prefer to subclass their bots for many reasons, some of them being: + +#### Skeletal Frameworks for Bots + +Developers often share their bots code on open-source platforms, mostly GitHub, and allow users to self-host the bot (running their own instance of the bot with the code provided by the developer. Permissions vary in accordance to licences). Here, users find it easier and more convenient to have a small file that imports the custom bot class and runs it, rather than having to go through the code of the bot and find out which file to run. This makes it easier for people not familiar with programming to run and customize the bot, since it often brings down the code to: + +```python title="./main.py" +from src import Bot + +bot = Bot() + +bot.run("TOKEN") +``` + +Here, all the commands are inside the `/src` folder that the user need not bother with. + +#### Running Multiple Instances + +Some developers may need to run multiple instances of their bot (perhaps on different bot accounts). For example, a developer might have a second bot for testing alpha features. This system makes it simpler for the developer, and allows them to maintain multiple versions of the bot in the same directory: + +```python title="./alpha_bot.py" +from src import Bot + +class AlphaBot(Bot): # subclasses Bot + ... # insert any custom configuration + +bot = AlphaBot() + +@bot.slash_command() # adds a new slash command to this subclassed bot +async def alpha_feature(ctx): + await ctx.respond("Alpha Feature!") + +bot.run("TOKEN") +``` + +There are many more reasons to subclass! It's not required, and won't affect the speed of the bot, but it may affect your development process, for the good or for the worse. You don't miss out on any features when you subclass, either. Some developers want the OOP feel, while some just prefer that method and find it easier. + +## Basic Example + +```python +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override the on_ready event + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') + +bot = MyBot() + +@bot.slash_command() # create a slash command +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run('token') +``` + +As you can see, instead of creating a bot object with `bot = discord.Bot()`, we subclass [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). We then create an instance of our new bot class and run it. Notice how we don't need to use the `@event` decorator. + +Here's another example: + +```python title="./src/bot.py" +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override on_ready + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') +``` + +```python title="./src/\_\_init\_\_.py" +from .bot import MyBot # import the MyBot class from the bot.py file +``` + +```python title="./main.py" +from src import MyBot # import MyBot from /src + +bot = MyBot() # create an instance of MyBot + +@bot.slash_command() +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run("TOKEN") # run the bot +``` + +These are just two ways you could do it. There are ton of other structures you can implement. It's up to you. + +So, should you subclass? There are no limitations you face if you decide to subclass your bot, but, once again, it's up to you. + +:::info Related Topics + +- [Making a Help Command](../Extensions/Commands/help-command) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx new file mode 100644 index 00000000..23220b0e --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx @@ -0,0 +1,105 @@ +--- +title: Threads +description: Threads with Pycord +--- + +In programming, threads are a way to run multiple processes at the same time. In Discord, threads are +a way to keep multiple conversations going at the same time. Let's take a brief look at how to use threads in Pycord. + +:::tip + +Not all the methods and attributes will be covered in this guide, but you can find them in our documentation! +[Check it out!](https://docs.pycord.dev/en/stable/api/models.html#discord.Thread) + +::: + +## Creating a thread + +With a few simple lines of code, we can create threads in Pycord. + +:::important + +All public threads need a starting message. This message will start the thread. However, private threads +(which are unlocked with having your server boosted to Level 2), do not require a starting message. + +::: + +### Creating thread from a message + +```python title="Creating a Thread from a Message" +message = await ctx.send("My Starting Message") +await message.create_thread(name="thread name", auto_archive_duration=60) +``` + +You may also use other ways to create the thread, for example, by using `on_message` events or by commands. + +### Creating thread in a channel + +```python title="Creating a Thread from a Channel" +channel = bot.get_channel(...) # define this! +await channel.create_thread(name="Thread Name", message=None, auto_archive_duration=60, type=None, reason=None) +``` + +A thread type could be `news_thread`, `public_thread`, `private_thread`. You may use it by passing `type=discord.ChannelType.news_thread`. + +## Deleting Threads + +Deleting Threads is simple. You need to get a thread and then use the `delete` method. + +```python title="Deleting a Thread" +thread = bot.get_channel(thread_id) # you could use other ways to get a thread +await thread.delete() +``` + +## Editing Threads + +**Parameters** + +- `name` (str) – The new name of the thread + +- `archived` (bool) – Whether to archive the thread or not. + +- `locked` (bool) – Whether to lock the thread or not. + +- `invitable` (bool) – Whether non-moderators can add other non-moderators to this thread. Only available for private threads. + +- `auto_archive_duration` (int) – The new duration in minutes before a thread gets automatically archived for inactivity. Must be one of 60, 1440, 4320, or 10080. + +- `slowmode_delay` (int) – Specifies the slow-mode rate limit for users in the thread, in seconds. A value of 0 disables slow-mode. The maximum value possible is 21600. + +```python title="Editing a Thread" +thread = bot.get_channel(id) +await thread.edit( + name="New Name", + archived=True, + locked=True, + slowmode_delay=10, + auto_archive_duration=60, +) +``` + +As you can see, threads are very simple. Once you learn how to use them, it's easy to create whatever you want. + +## FAQ + +### Why am I getting a `Forbidden` error when I try to create a thread? + +A `Forbidden` error occurs when the bot does not have the correct permissions to create threads. + +### Why am I getting an Unknown Message error when I try to create a thread? + +Getting an error looking something like `discord.ext.commands.errors.CommandInvokeError: Command +raised an exception: HTTPException: 400 Bad Request (error code: 10008): Unknown Message`? + +There could be multiple reasons, some of them being: + +- The message does not exist +- The message already has a thread +- The message is in channel x, you are trying to start a thread in channel y. +- The message was deleted. + +:::info Related Topics + +<>{/* I can't think of any related topics for this at the moment. */} + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/voice/_category_.json b/i18n/ja/docusaurus-plugin-content-docs/current/voice/_category_.json new file mode 100644 index 00000000..8baf3da8 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/voice/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 6, + "label": "Voice" +} \ No newline at end of file diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/voice/index.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/voice/index.mdx new file mode 100644 index 00000000..835838c6 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/voice/index.mdx @@ -0,0 +1,24 @@ +--- +title: Voice +--- + +Welcome to the guide for voice features in Pycord. + +:::caution +This guide requires previous experience with Pycord and Python. +::: + +## Requirements + +The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). +The following features are optional: + +:::tip +Opus is also a required library, but this comes with Pycord. +Some hosts may not come with it, though, so remember to always check if required dependencies are installed. +::: + +- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` +- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), + [`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), + [`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/voice/playing.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/voice/playing.mdx new file mode 100644 index 00000000..fe14c52a --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/voice/playing.mdx @@ -0,0 +1,149 @@ +--- +title: Wavelink Audio Player +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { + defaultOptions, +} from "@site/src/components/DiscordComponent"; + +# About + +Pycord and Wavelink try to keep the playing of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio playing feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/). + +## Starting out + +First you need to run a [Lavalink Server](https://github.com/freyacodes/Lavalink) to connect with. +There a multiple documentations to do this, so we are not covering that here. + +You also need to install the [wavelink](https://github.com/PythonistaGuild/Wavelink) library. + +```py title="Installing wavelink" +python3 -m pip install wavelink +``` + +You will now want to connect to your server via a node. + +```py title="Connect Node with Lavalink" +import discord +import wavelink + +bot = discord.Bot() + +async def connect_nodes(): + """Connect to our Lavalink nodes.""" + await bot.wait_until_ready() # wait until the bot is ready + + nodes = [ + wavelink.Node( + identifier="Node1", # This identifier must be unique for all the nodes you are going to use + uri="http://0.0.0.0:443", # Protocol (http/s) is required, port must be 443 as it is the one lavalink uses + password="youshallnotpass" + ) + ] + + await wavelink.Pool.connect(nodes=nodes, client=bot) # Connect our nodes +``` + +
+ +Now you are finished making your node! Next, you will want to: + +1. Making a play command +2. Adding connect events + +### Making a play command + +To make a play command, you will need to make a function to connect and play audio in a voice channel. + +```py title="Play Command Example" +import typing + +@bot.slash_command(name="play") +async def play(ctx, search: str): + # First we may define our voice client, + # for this, we are going to use typing.cast() + # function just for the type checker know that + # `ctx.voice_client` is going to be from type + # `wavelink.Player` + vc = typing.cast(wavelink.Player, ctx.voice_client) + + if not vc: # We firstly check if there is a voice client + vc = await ctx.author.voice.channel.connect(cls=wavelink.Player) # If there isn't, we connect it to the channel + + # Now we are going to check if the invoker of the command + # is in the same voice channel than the voice client, when defined. + # If not, we return an error message. + if ctx.author.voice.channel.id != vc.channel.id: + return await ctx.respond("You must be in the same voice channel as the bot.") + + # Now we search for the song. You can optionally + # pass the "source" keyword, of type "wavelink.TrackSource" + song = await wavelink.Playable.search(search) + + if not song: # In case the song is not found + return await ctx.respond("No song found.") # we return an error message + + await vc.play(song) # Else, we play it + await ctx.respond(f"Now playing: `{song.title}`") # and return a success message +``` + + + +
+ + play + +
+ Now playing: Never Gonna Give You Up +
+
+ +
+ +Now that you've done this, the only thing left to do is make your connect events. + +### Adding connect events + +The final step to this guide is connecting the node to your server when the bot goes online. + +To make it, you will want to do the following: + +```py title="Adding connect events" +@bot.event +async def on_ready(): + await connect_nodes() # connect to the server + +@bot.event +async def on_wavelink_node_ready(payload: wavelink.NodeReadyEventPayload): + # Everytime a node is successfully connected, we + # will print a message letting it know. + print(f"Node with ID {payload.session_id} has connected") + print(f"Resumed session: {payload.resumed}") + +bot.run("token") +``` + +Congratulations! You have now implemented voice playing into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/voice/receiving.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/voice/receiving.mdx new file mode 100644 index 00000000..1bc364e1 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/voice/receiving.mdx @@ -0,0 +1,130 @@ +--- +title: Receiving Voice Samples +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +# About + +Pycord tries to keep the recording of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio recording feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/audio_recording.py). + +## Starting out + +The first thing you want to do is make a cache of your voice connections. This is fairly easy; as +it's just putting a variable with an empty dictionary in our code, such as `connections = {}`. + +You will now want to create your command for recording. + +```py title="Record Command Example" +import discord + +bot = discord.Bot() +connections = {} + +@bot.command() +async def record(ctx): # If you're using commands.Bot, this will also work. + voice = ctx.author.voice + + if not voice: + await ctx.respond("You aren't in a voice channel!") + + vc = await voice.channel.connect() # Connect to the voice channel the author is in. + connections.update({ctx.guild.id: vc}) # Updating the cache with the guild and channel. + + vc.start_recording( + discord.sinks.WaveSink(), # The sink type to use. + once_done, # What to do once done. + ctx.channel # The channel to disconnect from. + ) + await ctx.respond("Started recording!") +``` + + + +
+ + record + +
+ Started recording! +
+
+ +
+ +Now you are finished making your command for voice receiving! Next, you will want to: + +1. Make your finished callback +2. Make a stop command + +### Making a Callback + +To make a callback, you will want to define the currently undefined `once_done` function inside +our command, like so: + +```py title="Recorder Callback" +async def once_done(sink: discord.sinks, channel: discord.TextChannel, *args): # Our voice client already passes these in. + recorded_users = [ # A list of recorded users + f"<@{user_id}>" + for user_id, audio in sink.audio_data.items() + ] + await sink.vc.disconnect() # Disconnect from the voice channel. + files = [discord.File(audio.file, f"{user_id}.{sink.encoding}") for user_id, audio in sink.audio_data.items()] # List down the files. + await channel.send(f"finished recording audio for: {', '.join(recorded_users)}.", files=files) # Send a message with the accumulated files. +``` + + + + finished recording audio for:{" "} + {defaultOptions.profiles.bob.author} + + + +
+ +Now that you've done this, the only thing left to do is make your stop command. + +### Making a Stop Command + +The final step to this guide is stopping the audio recording. This is the easiest step by far. + +To make it, you will want to do the following: + +```py title="Stop Recording Command" +@bot.command() +async def stop_recording(ctx): + if ctx.guild.id in connections: # Check if the guild is in the cache. + vc = connections[ctx.guild.id] + vc.stop_recording() # Stop recording, and call the callback (once_done). + del connections[ctx.guild.id] # Remove the guild from the cache. + await ctx.delete() # And delete. + else: + await ctx.respond("I am currently not recording here.") # Respond with this if we aren't recording. + +bot.run("token") +``` + +Congratulations! You have now implemented voice recording into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/ja/docusaurus-plugin-content-pagesindex.tsx b/i18n/ja/docusaurus-plugin-content-pagesindex.tsx new file mode 100644 index 00000000..84df3a9c --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-pagesindex.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import DefaultLayout from "../layouts/DefaultLayout"; +import PYCHero from "@site/src/components/PYCHero"; +import PYCButton from "@site/src/components/PYCButton"; + +export default function Home(): JSX.Element { + return ( + + +
+ Imagine a place where you can learn how to create an awesome Discord + bot, equip it with Pycord, and have it running in less than a minute. + Imagine a place where you can learn everything about Pycord. Imagine a + guide. A Pycord Guide! +

+ Whether you are a newbie or an experienced developer, you will find + everything you need to know about Pycord here. This guide will teach + you: +
    +
  • How to get a brand new bot running from scratch;
  • +
  • How to create Interactions, Context Menus and Commands;
  • +
  • In-depth concepts such as Embeds, Reactions, Help Commands, Paginators, etc;
  • +
  • Popular Topics such as working with Databases, Sharding, etc;
  • +
  • Ways to handle and manage common errors and best practices for bots;
  • +
  • And Much More!
  • +
+
+
+ ); +} diff --git a/i18n/ja/docusaurus-theme-classic/footer.json b/i18n/ja/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..ffb8a652 --- /dev/null +++ b/i18n/ja/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Pycord Development, All rights reserved.", + "description": "The footer copyright" + } +} diff --git a/i18n/ja/docusaurus-theme-classic/navbar.json b/i18n/ja/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..473b847e --- /dev/null +++ b/i18n/ja/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "Pycord Guide", + "description": "The title in the navbar" + }, + "item.label.Home": { + "message": "Home", + "description": "Navbar item with label Home" + }, + "item.label.Docs": { + "message": "Docs", + "description": "Navbar item with label Docs" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + }, + "item.label.Source": { + "message": "Source", + "description": "Navbar item with label Source" + } +} diff --git a/i18n/ko/code.json b/i18n/ko/code.json new file mode 100644 index 00000000..9cce6148 --- /dev/null +++ b/i18n/ko/code.json @@ -0,0 +1,404 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { + "message": "Toggle the collapsible sidebar category '{label}'", + "description": "The ARIA label to toggle the collapsible sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search here", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.algoliaLabel": { + "message": "Search by Algolia", + "description": "The ARIA label for Algolia mention" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorite", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "You might want to check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Algolia" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Try searching for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Believe this query should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/i18n/ko/docusaurus-plugin-content-blog/options.json b/i18n/ko/docusaurus-plugin-content-blog/options.json new file mode 100644 index 00000000..9239ff70 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/ko/docusaurus-plugin-content-docs/current.json b/i18n/ko/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..36b4849a --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,46 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.defaultSidebar.category.Getting Started": { + "message": "Getting Started", + "description": "The label for category Getting Started in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Interactions": { + "message": "Interactions", + "description": "The label for category Interactions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Application Commands": { + "message": "Application Commands", + "description": "The label for category Application Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.UI Components": { + "message": "UI Components", + "description": "The label for category UI Components in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Extensions": { + "message": "Extensions", + "description": "The label for category Extensions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Commands": { + "message": "Commands", + "description": "The label for category Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Pages": { + "message": "Pages", + "description": "The label for category Pages in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Voice": { + "message": "Voice", + "description": "The label for category Voice in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Popular Topics": { + "message": "Popular Topics", + "description": "The label for category Popular Topics in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.More": { + "message": "More", + "description": "The label for category More in sidebar defaultSidebar" + } +} diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png b/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png new file mode 100644 index 00000000..7480e1da Binary files /dev/null and b/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png differ diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg b/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg new file mode 100644 index 00000000..ce6b5110 Binary files /dev/null and b/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg differ diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png b/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png new file mode 100644 index 00000000..846eee15 Binary files /dev/null and b/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png differ diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png b/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png new file mode 100644 index 00000000..32a47d04 Binary files /dev/null and b/i18n/ko/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png differ diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/_category_.json new file mode 100644 index 00000000..309b494a --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 5, + "label": "Extensions", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json new file mode 100644 index 00000000..652aa4ee --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Bridge" +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx new file mode 100644 index 00000000..81545fa2 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx @@ -0,0 +1,190 @@ +--- +title: Bridge +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +## Concept + +Let's say that you want to make a command that is both a Slash Command and a Prefixed Command. Now, you could just copy and paste the code from the first command callback to the other and make some adjustments, but that's not very efficient. + +This is where the `ext.bridge` module comes in. It allows you to use one callback to make both a Slash Command and a Prefixed Command. + +### Example Usage + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def hello(ctx): + await ctx.respond("Hello!") + +bot.run("TOKEN") +``` + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+
+ +## Syntax + +First, instead of using `discord.Bot` or `commands.Bot`, we use `bridge.Bot`. `bridge.Bot` does inherit from `commands.Bot`, so you can do anything with `bridge.Bot` that `commands.Bot` can do. +Then, we define a command with `@bot.bridge_command()`. This makes a Bridge Command, which has both a Prefixed Command counterpart and a Slash Command counterpart. +Next, the callback has access to a `ctx` object, which is the context of the command. This context is either of `BridgeApplicationContext` type or `BridgeExtContext`. Because of that, it makes detecting how the function was called easier. + +### Using Bridge Commands in a Cog + +Like Slash Commands and Prefixed Commands, you can use Bridge Commands in a Cog. You can do this by using the `bridge_command` decorator. Here's an example: + +```python +import discord +from discord.ext import bridge, commands + +class Greetings(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @bridge.bridge_command() + async def hello(self, ctx): + await ctx.respond("Hello!") + + @bridge.bridge_command() + async def bye(self, ctx): + await ctx.respond("Bye!") + +def setup(bot): + bot.add_cog(Greetings(bot)) +``` + +The cog will automatically split the Bridge Command into their Slash Command and Prefixed Command counterparts. + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+ + +
+ + bye + +
+ Bye! +
+ + + !bye + + + +
+ + !bye + +
+ Bye! +
+
+ +### Deferring + +You can defer if you want to communicate to the user that your bot is busy processing the command. This is done by using `ctx.defer()`. For the Slash Command implementation, `ctx.defer()` calls the function that gives out a "Bot is thinking" message. For the Prefixed Command implementation, `ctx.defer()` enables the typing indicator. + + + +### Options + +Options are pretty straightforward. You just specify them like you do with prefixed commands, and you're all set! + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def sum(ctx, a: int, b: int): + await ctx.respond(a + b) + +bot.run("TOKEN") +``` + + + +
+ + sum + +
+ 4 +
+ + + !sum 2 2 + + + +
+ + !sum 2 2 + +
+ 4 +
+
diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json new file mode 100644 index 00000000..63f8e08e --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx new file mode 100644 index 00000000..bf345c07 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx @@ -0,0 +1,56 @@ +--- +title: Command Groups +--- + +Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk +remove`. + +## Syntax + +Creating a command group is very simple. + +```python title="Command Groups Example" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!') + +@bot.group() +async def afk(): + pass + +@afk.command() +async def set(): + ... + +@afk.command() +async def remove(): + ... + +# Another command group + +@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. +async def math(ctx): + await ctx.send('Subcommand not found') + +@math.command() +async def add(ctx, a: int, b: int): + ... + +@math.command() +async def subtract(ctx, a: int, b: int): + ... +``` + +To create a command group, the command's decorator must be `@bot.group`. Once you have a command with +that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand +groups! + + + +:::info Related Topics + +- [Prefixed Commands](./prefixed-commands.mdx) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx new file mode 100644 index 00000000..acbdc0a8 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx @@ -0,0 +1,481 @@ +--- +title: Help Command +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Pycord's `commands` extension comes with a built-in help command. In this guide, we will take a look at them as well as learn how to create your own. Let's dive in! + +:::note + +This guide demonstrates using object-oriented programming and subclassing to make a help command for your +Pycord bot. It is important to understand these two concepts before continuing. + +**Learning Resources**: + +- [W3Schools - Python Subclassing](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools - Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +::: + +## The Wrong Way + +A popular way to create a help command is to disable the built-in help command and create your own. This is not recommended as it will lead to a lot of confusion. + +```python title="The Wrong Way" +bot = commands.Bot(command_prefix='!', help_command=None) +# OR +bot.help_command = None +# OR +bot.remove_command("help") + +@bot.command() +async def help(ctx, *, argument=None): + ... +``` + +While it's possible to create a help command this way, doing so does not utilize the full capabilities +of making one with Pycord. Making a help command with subclassing and OOP will save time and effort. + +## Types of Help Commands + +There are two types of built-in help commands: + +- [`DefaultHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand) +- [`MinimalHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand) + +`DefaultHelpCommand` is the command enabled by default. It isn't the best looking, but `MinimalHelpCommand` can help make it look a bit better. + + + + +```python title="Default Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.DefaultHelpCommand()) # help_command is DefaultHelpCommand by default so it isn't necessary to enable it like this +# We enable it here for the sake of understanding + +... + +bot.run("token") +``` + + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ + +```python title="Minimal Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.MinimalHelpCommand()) + +... + +bot.run("token") +``` + + + + !help + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+ +
+ +
+ +## Updating Built-in Help Commands + +Let's try to make the `MinimalHelpCommand` look better. We can do this by putting its content in an +embed. + +```python title="Minimal Help Command Example" +bot = commands.Bot(command_prefix='!') + + +class MyNewHelp(commands.MinimalHelpCommand): + async def send_pages(self): + destination = self.get_destination() + for page in self.paginator.pages: + emby = discord.Embed(description=page) + await destination.send(embed=emby) + +bot.help_command = MyNewHelp() +``` + +Let's go through the code. + +First, we create a new class called `MyNewHelp`. This class is a subclass of `MinimalHelpCommand`. + +Next, we override the `send_pages` method. This method is responsible for sending the help command to +the user. We override this method because we don't want to change the content of the pages, just how +they are sent. + +We use the `get_destination` method to get the destination of the message. This is the channel or use that the help +command is to be sent to. + +We use the `paginator.pages` property to get the different pages of the help command. We put the page +in an embed, and then send the embed to the destination channel. + +Finally, we set this as our new help command using `bot.help_command = MyNewHelp()`. + + + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a + category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+
+ +## Creating Your Help Command + +Not satisfied with the built-in help commands? You can create your own! + +For this, we will subclass the `HelpCommand` class. + +There are 4 methods that we need to override: + +- `HelpCommand.send_bot_help(mapping)` that gets called with `help` +- `HelpCommand.send_command_help(command)` that gets called with `help ` +- `HelpCommand.send_group_help(group)` that gets called with `help ` +- `HelpCommand.send_cog_help(cog)` that gets called with `help ` + +### Bot Help + +```python title="Bot Help Example" +class MyHelp(commands.HelpCommand): + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help") + for cog, commands in mapping.items(): + command_signatures = [self.get_command_signature(c) for c in commands] + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's go through the code. + +- First, we create a new class called `MyHelp`. This class is a subclass of `HelpCommand`. + +- Next, we override the `send_bot_help` method. This method is responsible for sending the main help + command to the user. + +- We create an embed with the title "Help". + +- We iterate through `mapping.items()`, which returns a list of tuples, the first element being the + cog and the second element being a list of commands. + +- By using `self.get_command_signature(c)` we get the signature of the command, also known as the + `parameters` or `arguments`. + +- There is a chance that the cog is empty, so we use `if command_signatures:`. + +- We get the name of the cog using `getattr(cog, "qualified_name", "No Category")`. This calls the + cog's attribute `qualified_name` which returns "No Category" if the cog has no name. + +- We add a field to the embed with the name of the cog and the value of the command signatures. + +- Finally, we send the embed to the channel. + +Let's improve the code a little. + +```python title="Improved Bot Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + command_signatures = [self.get_command_signature(c) for c in filtered] + + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Now the help command won't show commands that the user can't use, as well as aliases for commands. +Let's get the help command to show command aliases. + +### Command Help + +This function is called when the user uses `help `. + +```python title="Command Help Example" +class MyHelp(commands.HelpCommand): + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command), color=discord.Color.random()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's quickly go through the code we haven't discussed yet. + +- In line 3, we create an embed with a title the signature of the command (so that the title of the + embed looks like ` [parameter]`), and a random color. + +- In lines 4 and 5, we get the command's `help` description and add it to the embed. The help description + of a command can be specified in the docstrings of a command function. For example: + + ```` + ```python + @bot.command() + async def ping(ctx): + """Returns the latency of the bot.""" + await ctx.send(f"Pong! {round(bot.latency * 1000)}ms") + ``` + ```` + +- Line 6 is shorthand for + + ```python + alias = command.aliases + if alias: + ... + + # is the same as + + if alias := command.aliases: + ... + ``` + + A very helpful (but not well-known) Python shorthand! + +- In line 7, we get the aliases of the command and add them to the embed. + +### Cog Help + +This is pretty easy! + +```python title="Custom Cog Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_cog_help(self, cog): + embed = discord.Embed(title=cog.qualified_name or "No Category", description=cog.description, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(cog.get_commands()): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Once again, we create an embed, get the commands that the user can use, and add them to the embed. + +### Group Help + +Similar to the cog help, this is pretty easy! + +```python title = "Custom Group Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_group_help(self, group): + embed = discord.Embed(title=self.get_command_signature(group), description=group.help, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(group.commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Add all of these methods together, and you have a fully functioning help command! + +
+Click to see the final code for this section +
+ +:::note + +The following code has been slightly edited from the tutorial version. + +::: + +```python title="Custom Help Command Example" +class SupremeHelpCommand(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + if command_signatures := [ + self.get_command_signature(c) for c in filtered + ]: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command) , color=discord.Color.blurple()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_help_embed(self, title, description, commands): # a helper function to add commands to an embed + embed = discord.Embed(title=title, description=description or "No help found...") + + if filtered_commands := await self.filter_commands(commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No help found...") + + await self.get_destination().send(embed=embed) + + async def send_group_help(self, group): + title = self.get_command_signature(group) + await self.send_help_embed(title, group.help, group.commands) + + async def send_cog_help(self, cog): + title = cog.qualified_name or "No" + await self.send_help_embed(f'{title} Category', cog.description, cog.get_commands()) + +bot.help_command = SupremeHelpCommand() +``` + +
+
+ +## Command Attributes + +How can you add cooldowns, set aliases, and change the name of help commands? Command attributes can +help you do all of that, and more! + +```python title="Help Command Attributes" +attributes = { + 'name': "help", + 'aliases': ["helpme"], + 'cooldown': commands.CooldownMapping.from_cooldown(3, 5, commands.BucketType.user), +} + +# You need to use CooldownMapping.from_cooldown(rate, per, type) + +bot.help_command = MyHelp(command_attrs=attributes) +``` + +## Error Handling + +When a user attempts to use a command that does not exist, we need to inform the user. +We can do this by overriding the `send_error_message` function. + +```python title="Custom Help Error Example" +class MyHelp(commands.HelpCommand): + async def send_error_message(self, error): + embed = discord.Embed(title="Error", description=error, color=discord.Color.red()) + channel = self.get_destination() + + await channel.send(embed=embed) +``` + + + + !help update_pycord + + + + Command 'update_pycord' not found. + + + + +## Credits + +Most of the content from this guide is from +[InterStella0's walkthrough guide on subclassing HelpCommand](https://gist.github.com/InterStella0/b78488fb28cadf279dfd3164b9f0cf96). +Thanks to InterStella0 for making this guide amazing. + +:::info Related Topics + +- [Subclassing Bots](../../Popular-Topics/subclassing-bots) +- [Prefixed Commands](./prefixed-commands) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx new file mode 100644 index 00000000..b8f567fd --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx @@ -0,0 +1,324 @@ +--- +title: Prefixed Commands +description: Learn how to use the commands extension for Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Before Discord added slash commands, all bots had prefixed commands. A user would type the bot's prefix +followed by a word or phrase to invoke a command, such as `?help` or `!help`. +However, this prefixed commands system isn't native to Discord! Developers made use of an `on_message` +event to check if the message began with a certain character, then invoke the command. Every time a +message was sent, the bot would see the message and check for its "prefix" + +The syntax becomes a little more complicated when you want to have multiple commands. There are several +disadvantages to this system. This is where the commands extension comes in. `ext.commands` has +various advantages, such as: + +- Simpler syntax +- Easier to use +- Easier to parse user input +- Comes with built-in help commands +- Comes with a built-in system for categorizing commands + + + + +```python title="Prefixed Commands with Events" +import discord + +client = discord.Client() + +@client.event +async def on_message(message): + if message.content.startswith("!ping"): + await message.channel.send("Pong!") + + elif message.content.startswith("!announce"): + if len(message.content.split(" ")) < 3: + await message.channel.send("You need to specify a title and a message. Correct usage: `!announce Hello Hello everyone!`") + return + + msg = message.content.split(" ", 2) + title = msg[1] + content = msg[2] + + await message.channel.send("**{}**\n{}".format(title, content)) + + elif message.content.startswith("!"): + await message.channel.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !help + + + Unknown Command. + +
+ +
+ + +```python title="The Commands Extension" +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix="!", intents=intents) + +@bot.command() +async def ping(ctx): + await ctx.send("Pong!") + +@bot.command() +async def announce(ctx, title, *, message): + await ctx.send("**{}**\n{}".format(title, message)) + +@bot.event +async def on_command_error(ctx, error): + if isinstance(error, commands.CommandNotFound): + await ctx.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !pycord + + + Unknown command. + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+ !announce +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The commands extension has many more uses. This example only showcases the basic features mentioned +in the previous example. Other things you can do with the commands extension include using a different +built-in help command and creating your own. The following tutorials showcase these. + +::: + +
+
+ +## Syntax + +Before we check out the syntax, let's take a look at the bot classes. + +> `discord.Client` - Contains only events. +> +> `discord.Bot` - Subclasses `discord.Client`, adds commands. +> +> `discord.ext.commands.Bot` - Subclasses `discord.Bot`, adds prefixed commands, cogs, and more. + +This means that `discord.ext.commands.Bot` has both slash commands and prefixed commands, as well as +events, cogs and more. + +Now let's look at the syntax. + +```python title="A Simple Prefixed Bot" +import discord +from discord.ext import commands # Import the commands extension +# discord.ext.commands are not the same as discord.commands! + +intents = discord.Intents.default() #Defining intents +intents.message_content = True # Adding the message_content intent so that the bot can read user messages + +bot = commands.Bot(command_prefix="!", intents=intents) # You can change the command prefix to whatever you want. + +@bot.command() # This is the decorator we use to create a prefixed command. +async def ping(ctx): # This is the function we will use to create the command. + await ctx.send("Pong!") # This is the response the bot will send. + + +bot.run("token") # Run the bot with your token. +``` + + + + !ping + + + Pong! + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The help command is a built-in command and is enabled by default. You will learn more about it in the +following guides. + +::: + +## Parameters + +Prefixed commands can take parameters, just like slash commands. You can specify the parameters in +the function itself. + +```python title="Parameters Example 1" +@bot.command() +async def echo(ctx, *, message): + await ctx.send(message) +``` + +`ctx` is the context of the message. `*` means that the parameter can be any number of words. `message` +is the parameter. If you had not passed `*`, `message` would only have been one word. + +For example, if a user had used `!echo hello world`, `message` would have been `hello`. Since we +passed `*`, `message` is `hello world`, or the rest of the message. + +We can pass multiple parameters too! + +```python title="Parameters Example 2" +@bot.command() +async def echo(ctx, channel:discord.TextChannel, title, *, message): + await channel.send("**{}**\n{}".format(title, message)) +``` + +In the example above, `channel` is a parameter that is of type `discord.TextChannel`. When you +specify the type of the parameter, Pycord will automatically try to convert the parameter to that type. +That is why you can use `channel.send` directly without needing to convert it first. + +We also have a new parameter, `title`. This does not have a type, so it will be a string. `*` means +that the rest of the message belongs to the next parameter, in this case, `message`. + +When a user types `!echo #general Greetings! Hello World!`, `channel` will be the text channel +`#general`, `title` will be `Greetings!` and `message` will be `Hello World!`. + +Let's take an example where the user passes `!echo #general Holiday Greetings! Greetings to you all!`. +Here, the user wants the title to be "Holiday Greetings!" and the message to be "Greetings to you all!". +However, since Pycord parses the message at whitespaces, the title will end up being "Holiday" and the +message "Greetings! Greetings to you all!". The user can prevent this by typing `!echo "Holiday +Greetings!" Greetings to you all!`. + + + + + + !echo #general Holiday Greetings! Greetings to you all! + + + Holiday +
+ Greetings! Greetings to you all! +
+ + !echo #general "Holiday Greetings!" Greetings to you all! + + + Holiday Greetings! +
+ Greetings to you all! +
+
+ +Let's check out another example for parameters and parameter types. + +```python title="Parameters Example 3" +import random + +@bot.command() +async def gtn(ctx, guess:int): + number = random.randint(1, 10) + if guess == number: + await ctx.send("You guessed it!") + else: + await ctx.send("Nope! Better luck next time :)") +``` + +If you had not specified the type of the parameter, it would have been a string. And since `"5"` is not +the same as `5` in python, the bot would have responded with "Nope! Better luck next time :)". +Even if you do not specify the type of the parameter, you can still convert it later on, in this case, +with `int(guess)`. + +:::info Related Topics + +- [Command Groups](groups) +- [Rules and Common Practices](../../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json new file mode 100644 index 00000000..baeba701 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Pages", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx new file mode 100644 index 00000000..be90b035 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx @@ -0,0 +1,168 @@ +--- +title: Paginator Basics +--- + +# Paginator Basics + +## [Page](https://docs.pycord.dev/en/stable/ext/pages/index.html#page) + +This class contains two attributes: `content` and `embeds`, which correspond to the attributes of the same name on the +`discord.Message` class. +To create a new Page, use the following syntax: + +```py +import discord +page = Page(content="My Page Content", embeds=[discord.Embed(title="My First Embed Title")]) +``` + +## [PageGroup](https://docs.pycord.dev/en/stable/ext/pages/index.html#pagegroup) + +This class represents a group of pages. It uses most of the same parameters as `Paginator`, which allows each +`PageGroup` to effectively have its own settings and behaviours. + +## [Paginator](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator) + +This is the main class for `ext.pages`, and is used to control most of the functionality of the extension. + +In its most basic form, with no arguments provided (default values listed below), a paginator can be created like so: + +```py title="Paginator Example" +import discord +from discord.ext.pages import Paginator, Page + +my_pages = [ + Page( + content="This is my first page. It has a list of embeds and message content.", + embeds=[ + discord.Embed(title="My First Embed Title"), + discord.Embed(title="My Second Embed Title"), + ], + ), + Page( + content="This is my second page. It only has message content.", + ), + Page( + embeds=[ + discord.Embed( + title="This is my third page.", + description="It has no message content, and one embed.", + ) + ], + ), +] +paginator = Paginator(pages=my_pages) +``` + +The only required parameter for `Paginator` is the `pages` parameter, which is usually a list of `Page` objects. + +You can also pass in a list of `PageGroup` objects, a list of strings, a list of embeds, or a list of lists of embeds. + +Once the `Paginator` instance is created, you can call either +[`Paginator.send()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.send) +or [`Paginator.respond()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.respond) +to send a message or response with the paginator's contents. + +#### Depending on what's being passed to the `pages` parameter, the behaviour of the paginator may differ: + +- Passing a list of `PageGroup` objects will essentially treat each `PageGroup` as its own Paginator, with most + `Paginator` attributes able to be set independently for each `PageGroup`. + \- Each `PageGroup` accepts its own `pages` parameter, which inherits the same behaviour as the `pages` parameter + of `Paginator`, except it cannot contain other `PageGroup` objects. +- If a page is a `Page` object, this will allow you to specify both the `discord.Message.content` and + `discord.Message.embeds` attributes for a page. + \- **This is the preferred method of defining a page.** +- If a page is a string, this will be used for the `discord.Message.content` attribute. This type of page cannot have + any embeds. +- If a page is a list of embeds, this will be used for the `discord.Message.embeds` attribute. This type of page + cannot have any message content. +- If a page is a list of lists of embeds, each parent list item will create a page containing all embeds from its + child list. This type of page cannot have any message content. + +#### Parameters for the `Paginator` class which have default values: + +- `show_disabled` **:** `True` + - Show buttons that are disabled (i.e. can't be clicked) +- `author_check` **:** `True` + - Only the author can interact with the paginator. +- `timeout` **:** `180` _(seconds)_ + - The paginator will time out and become inactive after this many seconds. +- `disable_on_timeout` **:** `True` + - If the paginator times out, it will be automatically disabled and all buttons will be unusable. +- `use_default_buttons` **:** `True` + - Use the default set of 4 buttons and a page indicator. +- `show_indicator` **:** `True` + - When using the default buttons, shows a middle 5th button with the current/total page numbers. + +**For other parameters that can be set on initialization, please check the +[API Reference](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator)** + +## [PaginatorButton](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatorbutton) + +This class represents a button used to navigate between the pages of a paginator. It's also used to create the page +indicator. + +When creating your own custom buttons, you can either use this class directly or subclass it to add any additional +functionality you may need. + +To add custom buttons to the paginator instead of the default navigation buttons, you have two options to do so: + +1. **Using the `custom_buttons` parameter of `Paginator`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + buttons = [ + PaginatorButton("first", label="<<-", style=discord.ButtonStyle.green), + PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), + PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True), + PaginatorButton("next", label="->", style=discord.ButtonStyle.green), + PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), + ] + paginator = Paginator( + pages=["Page 1", "Page 2", "Page 3"], + show_indicator=True, + use_default_buttons=False, + custom_buttons=buttons, + ) + ``` +2. **Using `Paginator.add_button()`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"], use_default_buttons=False) + paginator.add_button(PaginatorButton("prev", label="<", style=discord.ButtonStyle.green)) + paginator.add_button(PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True)) + paginator.add_button(PaginatorButton("next", label=">", style=discord.ButtonStyle.green)) + ``` + +If you want to use the default navigation buttons, but not all of them, you can also use `Paginator.remove_button()` to +selectively remove them: + +```py +from discord.ext.pages import Paginator + +paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"]) +paginator.remove_button("first") +paginator.remove_button("last") +``` + +## [PaginatorMenu](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatormenu) + +This class represents the `discord.Select` menu used to navigate between `PageGroup` instances. In most situations, you +will not need to interact with this class directly. + +If you do subclass it, you'll likely want to call `super()` in your `__init__` method to ensure that the `PageGroup` +navigation functionality is retained. + +## Usage Examples + +For a comprehensive list of examples showing all `Paginator` functionality, please see the +[example in cog form](https://github.com/Pycord-Development/pycord/blob/master/examples/views/paginator.py) in the repo. + +## Support and Feedback + +If you have any questions, suggestions, or feedback for `ext.pages`, please join the +[Discord server](https://discord.gg/pycord). diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx new file mode 100644 index 00000000..b8d68925 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx @@ -0,0 +1,20 @@ +--- +title: Paginator FAQ +--- + +# Paginator FAQ + +- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** + - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. + - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. + +- **How can the bot send a paginator to a different destination than where it was invoked?** + - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. + - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. + - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. + +- **How can I change the paginator's behavior without re-creating and re-sending it?** + - Use the `Paginator.update()` method. + +- **How can I make the bot actually do something with the contents of a page?** + - Use the (upcoming) `Paginator.page_action()` method. diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json new file mode 100644 index 00000000..36dfb009 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Tasks" +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx new file mode 100644 index 00000000..848f6066 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx @@ -0,0 +1,216 @@ +--- +title: Tasks +--- + +## Concept + +So you want to run a background task running at some specified interval? Thankfully, that's a common thing to do, whether you're working with some API or handling some background logic don't worry, the Pycord tasks extension is here to make life easier for you! + +With the tasks extension, you can make background tasks without worrying about the asyncio hell and mind bogglers like "what if my internet dies" and "how do I handle reconnecting" with the added benefit of a lot of useful additions that are one line of code away! + +### Example Usage + +```py +import discord +from discord.ext import tasks + +bot = discord.Bot() + +@bot.event +async def on_ready(): + very_useful_task.start() + +@tasks.loop(seconds=5) +async def very_useful_task(): + print('doing very useful stuff.') + +bot.run("TOKEN") +``` + +If you do run this code in your terminal you should see something like this after about 15 seconds: + +``` +doing very useful stuff. +doing very useful stuff. +doing very useful stuff. +``` + +For a more useful example here's a task in a cog context ripped straight from the [docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#recipes): + +```py +from discord.ext import tasks, commands + +class MyCog(commands.Cog): + def __init__(self): + self.index = 0 + self.printer.start() + + def cog_unload(self): + self.printer.cancel() + + @tasks.loop(seconds=5) + async def printer(self): + print(self.index) + self.index += 1 +``` + +As you'd expect this will increment a number and print it out every 5 seconds like so: + +```sh +0 +# 5 seconds later +1 +# 5 more seconds later +2 +# ... +``` + +## [Tasks](https://docs.pycord.dev/en/stable/ext/tasks/index.html) + +Now let's get into the nitty-gritty of tasks. + +As you've seen tasks can work in both outer scope and class contexts and the handle is roughly the same, you define a task using the `tasks.loop` decorator and use the `start` method to start it, the difference is you add the `self` argument when in a class context so since most people have all their bot's code in Cogs all the following code blocks will be in a Cog context to make it easy to copy it then apply whatever modifications you might need! + +### [Creating a task](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop) + +A look at `discord.ext.tasks.loop`'s definition in the documentation reveals that: + +1. As you've seen before it expects the time between each execution, that however doesn't have to be in seconds as + there are `seconds`, `minutes` and `hours` parameters to make it easier for us, they can also be floats in case you want + ultra-precision. +2. You can also pass in a `datetime.time` object or a sequence of them in the `time` parameter which will make it run + at the specified time(s). +3. You can pass in how many times a loop runs before it stops by passing in the `count` parameter, you can use `None` + to make it run forever which is also the default. +4. The loop function **_must_** be a coroutine. + +These are all really useful, and they aren't the only parameters so if you want to know more about them check out the +[docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop)! + +### Attributes + +A task has the following attributes: + +- `current_loop`: The current loop the task is on. +- `hours`, `minutes`, `seconds`: attributes that represent the time between each execution. +- `time`: A list of datetime.time objects that represent the times the task will run, returns `None` if no datetime + objects were passed. +- `next_iteration`: A `datetime.datetime` object that represents the next time the next iteration of the task will + run, can return `None` if the task stopped running. + +These attributes serve as a really powerful asset to get info about your loop. + +### Example + +Now let's create a cog that handles a leaderboard we have in our bot using Tasks then explain what we did after that and +also provide a refresher of how slash commands groups work in cogs. + +For the sake of this example let's pretend that we have a leaderboard module that does all the leaderboard handling for +us and that computing the leaderboard is very expensive computationally wise, so we want to store one version of it that +gets regularly updated instead of generating it every time someone calls the `/leaderboard view` command. + +```py +from discord.ext import tasks, commands +from discord.commands import SlashCommandGroup, CommandPermissions + +from leaderboard import * # Mock leaderboard module. + +class LeaderboardCog(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.update_leaderboard.start() + self.leaderboard_embed = generate_leaderboard_embed() + + leaderboard = SlashCommandGroup(name='leaderboard', description='Leaderboard commands.') + + @tasks.loop(minutes=10) + async def update_leaderboard(self): + print('Updating leaderboard...') + await update_leaderboard() + self.leaderboard_embed = generate_leaderboard_embed() + + @update_leaderboard.before_loop + async def before_update_leaderboard(self): + await self.bot.wait_until_ready() + print("About to start updating leaderboard.") + + @update_leaderboard.after_loop + async def after_update_leaderboard(self): + leaderboard_cleanup() + print("Stopped updating leaderboard.") + + @update_leaderboard.error + async def update_leaderboard_error(self, error): + print(f"Oh no, an error occurred while updating the leaderboard. Error: {error}") + + @leaderboard.command() + async def view(self, ctx): + await ctx.respond(embed=self.leaderboard_embed) + + @leaderboard.command() + async def update_info(self, ctx): + await ctx.respond(f"""***Leaderboard Info***\n + Last update: {(600 - self.update_leaderboard.next_iteration.timestamp())//60} minutes ago.\n + Next update: in {self.update_leaderboard.next_iteration.timestamp() // 60} minutes.\n + Time between loops: {self.update_leaderboard.minutes} minutes.\n + Times updated this session: {self.update_leaderboard.current_loop}. + Running? {self.update_leaderboard.is_running()} + Failed? {self.update_leaderboard.failed()}""", ephemeral=True) + + # Now for the owner only commands: + + leaderboard_config = SlashCommandGroup(name="leaderboard_config", description="Leaderboard configuration commands", permission=[CommandPermissions("owner", 2, True)]) + + @leaderboard_config.command() + async def set_time_between_updates(self, ctx, minutes: int): + self.update_leaderboard.change_interval(minutes=minutes) + await ctx.respond(f"Set time between updates to {minutes} minutes.") + + @leaderboard_config.command() + async def stop(self, ctx): + self.update_leaderboard.stop() + await ctx.respond("Stopped the leaderboard update.") + + @leaderboard_config.command() + async def restart(self, ctx): + self.update_leaderboard.restart() + await ctx.respond("Restarted the leaderboard update.") + +def setup(bot): + bot.add_cog(LeaderboardCog(bot)) +``` + +Phew, that was quite a bit of code. + +Now to explain what's going on: + +First things first we create a cog and in its `__init__` function we start the `update_leaderboard` task and generate +the first instance of our leaderboard's embed. + +After that, we define the `update_leaderboard` task using the `loop` decorator, and we make it run every ten minutes by +passing 10 to the `minutes` parameter. + +Then that we define the `before_update_leaderboard` task using the `before_loop` decorator, and we make it wait until the +bot is ready before starting the task. + +Next up we define the `after_update_leaderboard` task using the `after_loop` decorator, and we make it clean up the +leaderboard when the loop finally stops running. + +Then we define the `update_leaderboard_error` task using the `error` decorator, and we make it print any errors that may +occur while we update our leaderboard to the console. + +Then we get into the fun stuff, we create a slash command group using the `SlashCommandGroup` class and name it +`leaderboard`, we then create the `view` sub-command which sends the embed generated when the leaderboard is updated and +`update_info` which shows a lot of data about the task using some attributes and functions available to us. + +We also create a slash command group called `leaderboard_config` which is only available to the owner of the bot. + +Then we create the `set_time_between_updates` sub-command which takes in the time in minutes and changes the time +between updates of the leaderboard using the `change_interval` method, the `stop` sub-command which stops the task using +the `stop` method and `restart` which restarts the task using the `restart` method. + +Finally, we add the `LeaderboardCog` cog to the bot, and we're done! + +I'd highly recommend you check the tasks extension +[documentation](https://docs.pycord.dev/en/stable/ext/tasks/index.html) for more info on how to use them and what other +functions they have. diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/_category_.json new file mode 100644 index 00000000..9d6255f5 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 3, + "label": "Getting Started", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx new file mode 100644 index 00000000..864206a6 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx @@ -0,0 +1,262 @@ +--- +title: Creating Your First Bot +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +Excited to create your first bot? Once you [install Pycord](../installation.mdx), you can start right +away! + +## Creating the Bot Application + +Just like how you need to sign up to use Discord, your bot also has to be signed up. To do this, +you should: + +1. Go to the [Discord Developer Portal](https://discord.com/developers/applications) and click + on . +2. Give your bot a name, and click . +3. Now, you should see a page like this. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdW3OQnwUhacopqSWw%2F-Mjd_-mxrJCrzmaXrAg8%2Fimage.png?alt=media&token=b8e2ae6c-2290-4d37-ad7c-eb412f3fb00e) +4. Click on the tab on the left side of the screen. +5. Click on . +6. You can give it a name, change the Avatar, etc. + +## Inviting the bot + +Now, lets get the bot added to some servers. Go to the tab +in the left pane and select `bot` and `applications.commands` as scopes. + +You may want your bot to have application commands, which is what the `application.commands` scope +allows your bot to make. + +Next, you want to choose what permissions the bot will have and select them. For now, you can just +give your bot the `administrator` permission, which gives your bot every permission. Once you select +your bot's permissions, click on to get the bot invite link. + +:::tip + +When your bot is all ready to go, make sure that administrator permissions aren't selected unless +your bot truly needs them. Try selecting only permissions the bot will need. For testing, +Administrator permissions are fine. + +::: + +![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-Mk6tNY3LfDkjd6pqdpL%2F-Mk6tkdpddEWoa2jczZk%2Fimage.png?alt=media&token=52c8a29f-a798-48f8-a8c7-4ecca2681f79) + +You can use this link to invite the bot. + +## Tokens + +Now that you have an account for your bot, you need to log in. To log in, we need the bot's +password. All users and bots have a "token." You may think of this token as a password, as this allows +us to log our bot into Discord. + +Tokens are "snowflakes." Not actual snowflakes, though. Just like how no two snowflakes in real life have the same +pattern, snowflakes in computers are unique things - no two bots have the same token - so a token is +considered a snowflake. A Discord user ID is also a snowflake. + +Now, lets get your bot's token. To do this, you want to: + +1. Go back to the tab. +2. Click on the button in the "Token" section. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdbU12JISJorAZxrKH%2F-MjdbpUsapzb5n15Po5P%2Fimage.png?alt=media&token=118e259f-940a-4f6c-b3a3-c29f3a54100d) + +Now, you have your bot's token copied to your clipboard. + +:::danger + +Do not, under any circumstances, give your token to anyone. Even if you are contacted by someone +claiming to be Discord staff, do not give them your bot's token. They are lying to you to try and +gain access to your bot. If an unauthorized user gains access to your bot's token, they can access +your bot and use it in malicious ways. + +Never push your token to GitHub or include it in your code. One way to prevent your token from +getting leaked is to store it in `.env` files. + +::: + +### Protecting Tokens + +#### Using dotenv + +You can store your tokens in `.env` files. This is a simple way to store sensitive information. + +1. Create a file with the name `.env` (only the extension, with a dot/period at the start and without a name before it). +2. Define the token in the `.env` file (replace the example value with your token). + ```env title=".env" + TOKEN = NzkyNzE1NDU0MTk2MDg4ODQy.X-hvzA.Ovy4MCQywSkoMRRclStW4xAYK7I + ``` +3. Install [`python-dotenv`](https://pypi.org/project/python-dotenv/). + ```bash + python -m pip install python-dotenv + ``` +4. Load the token from the `.env` file. + ```python + import dotenv + dotenv.load_dotenv() + token = str(os.getenv("TOKEN")) + ``` +5. Pass your token as parameter when running the bot. + ```python + client.run(token) + ``` + +:::tip + +If you are using Git to track your bot's changes, you should create a file called `.gitignore` and add +`.env` to it. This stops your `.env` file from getting tracked along with the rest of your code, and +will not be pushed to a remote Git repository. As a consequence, it will stay secure on your local machine. + +::: + +## Coding the Basics + +Here's an example of code you'll write with Pycord: + +```py +import discord +import os # default module +from dotenv import load_dotenv + +load_dotenv() # load all the variables from the env file +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") + +bot.run(os.getenv('TOKEN')) # run the bot with the token +``` + + + +
+ + hello + +
+ Hey! +
+
+
+ +Let's go through the code. First, the imports. + +```py +import discord +import os +from dotenv import load_dotenv +``` + +In the first line, `import discord`, we import Pycord. Although you install Pycord with `pip install py-cord`, you +import it with `import discord`. This is so it's as easy as possible when switching from Discord.py to Pycord. + +We then import `os` and `dotenv`. `os` is a default module that we will use to get the token from the env file. `dotenv` +is a module that we will use to load the env file. You installed this with `pip install python-dotenv`. + +Next, we load the env file with `load_dotenv()`. + +```py +bot = discord.Bot() +``` + +In this line, we create a new instance of [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). +In this object, we can pass various parameters for configuration purposes, such as `owner_ids` +and [`intents`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```py +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") +``` + +We use the [`event`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) decorator to override +the [`on_ready`](https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready) function to define an +event that is automatically called when the bot is ready to use. + +```py +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") +``` + +Here, we use the [`slash_command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.slash_command) +decorator to define a slash command. We specify the `name` and `description` arguments. If not +specified, the name of the slash command would be the function name and the command description would +be empty. + +Optional: We type-hint the context parameter (`ctx`) as [`discord.ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext). In modern IDEs, type-hinting allows access to autocompletion and docstrings. You can read more about type-hinting [here](https://docs.python.org/3/library/typing.html). + +Finally, you want to run the bot using the token specified in the `.env` file. + +Now you have finished creating your first Pycord bot! What we have shown you is just the basic structure +of a bot. You can do a lot more with Python and Pycord knowledge, as well as your imagination! Pycord +will not limit your bot's abilities. + +:::note + +The part where we load the token from the environmental variables is not required. You may use another way to keep your token secure, or, although not recommended, simply specify the token normally as a string, as shown below. + +
+A Basic Bot without securing the token +
+ +```py +import discord + +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.send("Hey!") + +bot.run("TOKEN") +``` + +
+
+ +::: + +## FAQ + +### How do I make prefixed commands? + +Prefixed commands are an older method of creating bot commands that listen for messages and replies +if the message starts with a certain character. You can read [this page](../extensions/commands/prefixed-commands.mdx) +to learn more about prefixed commands. + +### How do I setup modules/cogs? + +[Cogs](../popular-topics/cogs) are a great way to organize your commands by putting them into +groups called cogs. Cogs are separate files that your bot loads to get the commands inside. +You can read more about cogs, as well as learn how to use them and their benefits, +[here](../popular-topics/cogs). + +### How do I add components, such as buttons and dropdown menus, to my bot? + +Pycord makes it very easy to use Message Commands with your bot by using the `discord.ui` module. +To learn more, read about Message Commands in our [interactions directory](../interactions). + +:::info Related Topics + +- [Prefixed Commands](../extensions/commands/prefixed-commands) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx new file mode 100644 index 00000000..2a68677b --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx @@ -0,0 +1,109 @@ +--- +title: Hosting Your Pycord Bot +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Hosting Your Pycord Bot + +If you're completely new to this, you might have thought something along the lines of "Yay! I got my +bot working," after following our [Creating your First Bot](creating-your-first-bot) guide, only +to close your IDE or shut down your computer to find your bot offline. + +The reason for this is that programs have to be hosted somewhere, meaning some machine somewhere has +to constantly run your bot. There are tons of hosting services that can help you host your bot for +little to no cost. + +## Can I get a Clear Explanation? + +Sure thing. When you run your bot, it first makes a connection to Discord's API. Once that's done, +Pycord sends "heartbeats" to Discord. "heartbeats" are small packets sent at a set interval telling +Discord that your bot is indeed still alive. If Discord doesn't receive a heartbeat after a certain +amount of time, your bot is pronounced dead and buried in the graveyard (not really). It is, though, +taken offline and its connection with Discord is terminated. + +Once you close the terminal that you've run your program on, the program is no longer running, and +the bot stops sending heartbeats and can no longer process commands. This is why you have to constantly +keep the process running. + +This goes for all programs, in a different nature. If the code isn't compiled/built/assembled/interpreted, +it can't be running. + +## What is a Host? + +A host is a server or container for running code offered by a **hosting provider.** There are a lot +of hosting providers, such as bigger ones like Amazon Web Services (AWS) and Google Cloud, and smaller +ones like GalaxyGate and DigitalOcean. + +There are three types of hosts. + + + + Shared hosting is a type of hosting where multiple people share one VPS. Getting a spot on + a shared host is usually cheap, sometimes even free. Shared hosts do not give you a lot of + resources, from less than a gigabyte of RAM (usually 512MB on free hosts) and half of a CPU + with very little storage. Shared hosting is usually used for website hosting and is not + recommended for hosting a Discord bot. + + + A virtual private server (VPS) is a virtual computer (virtual machine) that is rented out to + customers. Most people use a VPS for hosting their projects such as Discord bots. You can get + anywhere from less than a gigabyte of RAM and a less powerful CPU to just under one hundred + gigabytes of RAM, a (or multiple) powerful CPU(s), and a fair amount of storage. A VPS is the + best choice for most users and can be fairly cheap. + + + A dedicated host is a physical computer. You can buy these yourself or rent one from a hosting + provider. Dedicated hosts are often very expensive, but are also very powerful, having a + few hundred gigabytes of RAM and a few very powerful CPUs, along with a good amount of storage. + Dedicated hosts are usually used for very large projects and are overkill for something like + a Discord bot. + + +
+ +:::danger + +Make sure you choose a hosting provider you trust. Also make +sure the hosting provider you're looking at has good reviews on public forums. Googling along the +lines of "[host] review" should do the trick. A provider you don't trust can compromise your token. + +::: + +Most hosting providers rent their services to you for a monthly or yearly fee. These can be anywhere +from a few dollars to hundreds or thousands of dollars. + +## How to Host Your Bot + +Once you rent or buy a VPS, you can get to work. Most hosting providers allow you to choose from a +wide range of operating systems, most allow you to choose one but some allow you to choose +multiple. Once that's ready, you have to SSH into the system. We won't get into SSH here, but you can +read [this article from DigitalOcean](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys). +You can also use VNC, which is remote desktop software. If you are using an OS that does not have a +GUI, and is only a command line (a "server" OS), such as Ubuntu Server or most Linux Server Operating Servers, you will most +likely use SSH. If you are using an OS that has a GUI, such as Windows Server, you will most likely use VNC. + +Once you've decided on your operating system, you'll want to set it up and install Python. Once that's +done, you can copy your bot's files to your remote system, install the required packages, and run +the bot. + +:::warning + +If you are using SSH to run the file, your bot will not stay running. This is because the file is +only told to run during your session. You can use a command like [nohup](https://en.wikipedia.org/wiki/Nohup) +to make sure your file stays running after you disconnect. + +::: + +Now your bot is hosted, but that doesn't mean it can't go offline. If your bot encounters an error, +it can often go offline or stop its process. For this, make sure you have proper error handling. +Also be sure to pay attention to your hosting provider's updates or news, as they usually notify +users of when they plan on doing maintenance to their servers, making their services unavailable for +a short time. + +:::info Related Topics + +- [Creating Your First Bot](creating-your-first-bot) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx new file mode 100644 index 00000000..ee6b9417 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx @@ -0,0 +1,379 @@ +--- +title: More Features +description: More features to make your bot cool and snazzy. +--- + +import { + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, + DiscordEmbedField, + DiscordEmbedFields, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +So, you just created your first Pycord bot! Now, let's add some more features to it. This will include adding event handlers, waiting for user response, styling the messages, and more. + +## Events + +### Event Handlers + +Events in Discord are a way to listen for certain actions. For example, if you want to know when a user joins your server, so you could send a welcome message, you can use the `on_member_join` event. + +First, you need to ask Discord to send you events. This is done via "Intents". Read up the [Intents](../Popular-Topics/intents) page for more information. + +Once you understand what intents are, you can enable the events you need, or just use the default ones with `discord.Intents.all()`. + +Now that that's done, let's add an event handler for when a user joins the server. We will use the [`on_member_join` event](https://docs.pycord.dev/en/stable/api/events.html#discord.on_member_join). We will send a private message to the user welcoming them to the server. + +```python +@bot.event +async def on_member_join(member): + await member.send( + f'Welcome to the server, {member.mention}! Enjoy your stay here.' + ) +``` + +We use the [`discord.Bot.event` decorator](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) to add the event handler. + +The `on_member_join` event is called when a user joins the server. The `member` parameter is the user that joined. Different events have different names and parameters. You can find all of them [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +So, that's how you add event handlers! + +### Waiting for User Response + +Let's say you want to create a Guess-the-Number game (where the user has to guess a number between 1-10). You need to send a message to a user and wait for them to respond. You can do this with the [`wait_for`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.wait_for) method. + +```python +@bot.command() +async def gtn(ctx): + """A Slash Command to play a Guess-the-Number game.""" + + await ctx.respond('Guess a number between 1 and 10.') + guess = await bot.wait_for('message', check=lambda message: message.author == ctx.author) + + if int(guess.content) == 5: + await ctx.send('You guessed it!') + else: + await ctx.send('Nope, try again.') +``` + +`wait_for` takes one argument, which is the event type. The event type is the name of the event you want to wait for. In this case, it's `message`. It could also be `reaction` to wait for a reaction to be added. + +We pass a keyword argument to `wait_for` called `check`. The function may look complicated if you're a beginner. We pass a `lambda` function, which simplifies the code a bit. + +The lambda function takes one parameter, `message`. When Pycord receives a message, it passes it to the `check` function. If the function returns `True`, the message is returned. If the function returns `False`, the message is ignored and the bot waits for another message. + +Here, we check if the message is from the user that sent the command. We simply use `message.author == ctx.author`. This will check if the author of the message was the person who invoked the command. + +## Styling Messages + +### Embeds + +Embeds are a Discord feature that allows applications to format their messages in cool embedded format, +enabling your bot to lay out messages with a lot of text into neat fields. + + + + + The Pycord Guide is a detailed guide that explains how to use Pycord and all of its features. + + + The Getting Started section explains how you can get a brand new bot created and running from scratch. + + + Interactions with Pycord + + + Pycord's various Extensions + + + Other Popular Topics + + + We have so much more! Just explore, and you will find everything you need. If you want another page added, open an issue on the GitHub. + + + Created with 💖 by the Pycord Team & Contributors + + + + +
+ +Creating embeds is simple! Just create an instance of [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) and edit it to your liking. Once you're done, send it! + +```python +import discord + +bot = discord.Bot() + +@bot.command() +async def hello(ctx): + embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from + ) + embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") + + embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) + embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) + embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) + + embed.set_footer(text="Footer! No markdown here.") # footers can have icons too + embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") + embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") + embed.set_image(url="https://example.com/link-to-my-banner.png") + + await ctx.respond("Hello! Here's a cool embed.", embed=embed) # Send the embed with some text + +bot.run("TOKEN") +``` + + + +
+ hello +
+ Hello! Here's a cool embed. + + Embeds are super easy, barely an inconvenience. + + + A really nice field with some information. The description as well as the fields support markdown! + + Inline Field 1 + Inline Field 2 + Inline Field 3 + + Footer! No markdown here. + +
+
+ +
+ +This simple command sends replies to a [slash command](../interactions/application-commands/slash-commands) with an embed. +Let's break it down: + +```py +embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), + ) +``` + +This command creates an embed. We use the [`Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) +class to create an embed object with the title "My Amazing Embed", the description "Embeds are super easy, barely an inconvenience.", and the color `blurple`, Discord's main theme color. + +[discord.Colour](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Colour) is a class full of [classmethods](https://docs.python.org/3/library/functions.html#classmethod) +that return color values. While the official, documented name of this is `discord.Colour`, `discord.Color` +works as well. + +```py +embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") +embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) +embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) +embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) +``` + +This small section shows off embed fields. You can add fields to embeds with the [`add_field` method](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.add_field) +of the [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) class. These consist of three +keyword arguments: `title`, `value`, and `inline`. `title` and `value` are both required arguments, which inline defaults to `False` if it's not defined. The `inline` argument specifies whether space will be divided among the inline fields. There could be a mix of fields where inline has different values too. + +```py +embed.set_footer(text="Footer! No markdown here.") # footers can have icons too +embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") +embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") +embed.set_image(url="https://example.com/link-to-my-banner.png") +``` + +In this section, we're adding unique items to the embed. These items are: + +- Footer - With the [`set_footer()`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_footer) + method, you can set a small footer that holds a message. This has `text` and `icon_url` kwargs. +- Author - With the [`set_author`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_author) + method, you can set an author for the embed. This is a small text field at the top of the embed. This + includes `name`, `url` and `icon_url` kwargs. +- Thumbnail - With the [`set_thumbnail`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_thumbnail) + method, you can set a small image to reside at the top-right of the embed. This has a single `url` kwarg. +- Image - With the [`set_image`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_image) + method, you can set an image to sit at the bottom of an embed. This has a single `url` kwarg. + +There are a lot more methods and attributes you can use to configure embeds. Here, we just covered the basics. Also, remember that all of these values are not necessary in an embed. An embed may only contain a few of these. For example, only a description, a title and a description, and so on. + +### Markdown + +Markdown is a type of markup language that's limited in terms of formatting yet simple. Discord allows +for a watered-down version of markdown to be in their messages. + +#### Text Markdown + +Text formatting can be used in messages and in most embed parts, +as explained in the dedicated section below. + + + + + + + + + + + + + + + + + + + + +
*italics*__*underlined italics*__
**bold**__**underlined bold**__
***bold italics***__***underlined bold italics***__
__underlined__~~strikethrough~~
+ +#### Code Markdown + +To create a single-line code block without syntax highlight, wrap the text between single backticks. +This code block will only add a dark background to the text. + +``` +`print("Hello world!")` +``` + +To create a multi-line code block without syntax highlight, wrap the text between triple backticks +on first and last line. This type of code block will encase the code inside a box. + +```` +``` +message = "Hello world!" +print(message) +``` +```` + +To create a multi-line block with syntax highlight, add the name of the language you are using right after +the triple backticks on the first line. For example, for Python you can write either "python" or "py". + +```` +```python +message = "Hello world!" +print(message) +``` +```` + +If you want to use syntax highlight for a single line of code, you still have to format it +like a multi-line block but the code must be on a separate line than the triple backticks. + +#### Quote Markdown + +To create a single-line quote block, start the line with `>` followed by a space. + +``` +> This is a single-line quote. +``` + +To create a multi-line quote block, write `>>>` followed by a space. All text +from that point onwards will be included in that quote block. + +``` +>>> This is a +multi-line quote. +``` + +#### Spoiler Markdown + +To hide a spoiler, encase the text between double pipes. The users +will have to click on it before being able to see the text contained in it. + +``` +||spoiler|| +``` + +#### Link Markdown + +Link formatting only works in embeds and messages sent through webhooks, +by using the following syntax: + +``` +[Pycord](https://pycord.dev/) +``` + +Inside the supported elements that have just been mentioned, +the example above will look like this: [`Pycord`](https://pycord.dev/) + +Outside them, the link will still be clickable but the formatting will be ignored, +therefore the example above will look similarly to this: `[Pycord](https://pycord.dev/)` + +#### Embed Markdown + +Adding markdown to your embeds or messages will give your bot the sparkle it needs, +however, markdown is limited inside embeds. Use the following table as a reference +and keep in mind that embed title and filed names will always show in **bold**. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PartTextLink
Embed AuthorNoNo
Embed TitleYesNo
Embed DescriptionYesYes
Field NameYesNo
Field ValueYesYes
Embed FooterNoNo
diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx new file mode 100644 index 00000000..e44b7c49 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx @@ -0,0 +1,184 @@ +--- +title: Rules and Common Practices +description: All about the rules and common practices for coding a Discord bot +--- + +# Rules and Common Practices of Creating a Bot + +When creating almost anything, there's always a certain set of rules to follow or common practices, +such as [PEP8](https://www.python.org/dev/peps/pep-0008/) for Python. This applies to creating bots +with Pycord as well. + +:::note + +Most of these rules and common practices are only applicable for +[verified bots](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting), +but it's good to follow them nonetheless. + +::: + +## Rules + +There are rules for creating bots, and most of these are required by Discord themselves, not us at +Pycord. Not following these rules may get your bot denied for verification. + +### Terms of Service and Privacy Policy + +Starting at some point in time, Discord has made providing a privacy policy with your bot a requirement. +This is so that Discord knows exactly what you are doing with its users' data. + +:::tip +You don't need a lawyer or anyone special to write out a privacy policy for you, nor do you need +it approved by some official entity. Simply writing out how you are going to use Discord user +information neatly is all you need to do. +::: + +Providing a Terms of Service for your bot is optional, though usually a best practice. It tells users +what they can and cannot do with your service, and makes it easier to settle disputes if someone +disagrees with you. + +Read more in Discord's official [Legal Docs](https://discord.com/developers/docs/legal). + +### Developer Policy + +We could list almost every rule about using Discord's API here. _Or_ we could simply link Discord's +Developer Policy to make it easier on us. You can find Discord's Developer Policy +[here](https://discord.com/developers/docs/policy). This outlines what you can and cannot do with +Discord's Developer API. And, don't worry, it's completely readable and understandable. + +## Best Practices + +Now, here's something we _can't_ simply link an article for. We're going to discuss the best practices +of creating a Discord bot with Pycord. + +### Bot Sharding + +To any new or maybe even experienced bot developer, sharding a bot sounds beneficial once you hear +about it. I'm here to tell you that it isn't a good idea to shard your bot. + +_Wait a minute, why would it be an option if it wasn't a good idea?_ It's simple. I lied. Sort of. +I'm not going to go into the details of sharding a bot, so you can read about it on +[this page](../Popular-Topics/sharding). Sharding is the process of taking your bot +and breaking it up into small pieces, so it's easier to perform tasks. This is very useful for large +bots, as it makes them faster and more reliable. Sharding is not a good practice for small bots. + +:::note +Discord will notify you once it is time to shard your bot, and will eventually force you to do so. +::: + +At the very least, wait for one thousand servers to shard your bot. If you shard your bot while it's +small, you'll just be wasting resources and possibly making your bot slower. + +### [Verification](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting) + +Verifying your Discord bot is something every developer would like to achieve. It shows that your bot +is in more than 75 servers. It's generally a good idea to try to get your bot verified as soon as +possible. We're talking at 76 servers soon. This is because Discord can be somewhat slow in terms of +bot verification, so verifying as soon as possible gives them enough time to verify before your bot +reaches the 100 server cap. If a bot is not verified, it cannot grow beyond 100 servers. + +It's also a good idea to only apply for the privileged intents that you need. Applying for intents +your bot doesn't use wastes both your time and Discord's time, as your privileged intent request +will be denied simply because you applied for an intent you didn't need. + +### Subclassing + +While it may take some time, subclassing a bot is very worth it. Once again, this was explained +elsewhere, so I won't go into the details, but I felt it fit here, so I put it here. + +Subclassing a bot makes it more flexible and allows it to do a lot more. Read more about subclassing +bots [here](../Popular-Topics/subclassing-bots) + +### Your Bot's Token + +Your bot is only able to be run for one reason: its token. If you followed the +[guide for creating your first bot](creating-your-first-bot), you should already know a bit about +keeping that token safe. That's exactly what you want to do. + +Sharing your token is never good. If someone evil gets a hold of your token, they can do terrible things, +such as making your bot leave all of its servers, spamming all the members the bot has contact with, +and even manipulating the servers the bot is in, if given the permissions. That's why it's very important +to keep your token safe. To learn how to do so, read [this part](creating-your-first-bot#tokens) of +the Creating Your First Bot guide. + +### Backups + +You always want to back up your bot's data. This includes both its code _and_ its databases. This way, +if something tragic happens, such as your host failing a data migration or you breaking your Raspberry +Pi's SD card that held your bot, you'll still have its precious user data. I have a small program for +my bot that uploads its databases to a remote GitHub repository periodically to not lose any data. +It may be smarter to find a bit more of a reliable way to do so, though. + +Public or private, having a local Git repository connected to a remote one is a good idea for making +almost any application. For a lot of developers, it's like saving your work. If you do this, all of +your bot's code won't be lost if your computer spontaneously combusts, or you smash it to bits from +anger. You can simply grab the backup computer that everyone has lying around, and you're back +in business. + +### Organization and Cleanliness + +It is _extremely_ important to have organized code. This includes commands, objects, functions, +and classes. If you don't have organized code, it will get progressively harder for you to recognize +it, and others won't be able to decipher it. + +Make sure you utilize indents and spaces, as these are very important in making your code readable. + +```py title="Bad Spacing" +class MyClass: + async def add(self,num1,num2): + return num1+num2 + async def sub(self,num1,num2): + return num1-num2 +``` + +```py title="Good Spacing" +class MyClass: + async def add(self, num1, num2): + return num1 + num2 + + async def sub(self, num1, num2): + return num1 - num2 +``` + +See the difference? Now, which one looks more readable? Hopefully, you answered the second example. +Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is a PEP (**Python Enhancement Proposal**) +style guide for Python. It is the style guide that is used by most Python developers and programmers, +providing a universal way to write and read code. + +### Databases + +As your bot grows, you'll inevitably have to store data for your bot. Now, most people would probably just load up some +JSON file on boot into a `dict`, modify it in memory then write to the file. However, JSON files aren't the solution. +When you write to a JSON file, it rewrites the entire file instead of just rewriting the section that changed. It's also +a configuration file format, not a storage file format. + +Instead of using a JSON file or some other related format, you should instead use a database. There are many databases +out there, like MongoDB, SQLite, and PostgreSQL to name a few. + +All of these databases I named do the job well, and which one you use depends on what features you want out of a database. + +<>{/* Maybe clarify these/add more options */} + +#### MongoDB + +MongoDB is a JSON-like format and if you already use JSON files, it shouldn't be too hard to migrate over to. + +#### SQLite + +SQLite is based on SQL, a common relational data model. It's a lightweight, easy-to-use, portable database solution that +works entirely on files. However, if for some reason you cannot read/write to and from a file, and you need to manage +lots of data, SQLite might not be for you. + +While SQLite is a part of the Python Standard Library as the `sqlite3` package, we recommend not using it as it is +synchronous and blocking. You should use an asynchronous alternative, such as [`aiosqlite`](https://pypi.org/project/aiosqlite/). + +#### PostgreSQL + +PostgreSQL is also based on SQL, but it also has more features than SQLite. It's compliant with the SQL standard, +open-source, and extensible. However, it's not that fast or simple compared to SQLite. + +#### MariaDB + +MariaDB is also based on SQL and is a fork of the MySQL project. It's compliant with the SQL standard, it's also open +source and is a complete drop-in replacement for any code with MySQL. You don't even need to change what package you're +using! diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/installation.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/installation.mdx new file mode 100644 index 00000000..521c69cd --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/installation.mdx @@ -0,0 +1,80 @@ +--- +title: Installation +sidebar_position: 2 +--- + +Before you can start using Pycord, you need to install the library. + +:::note +Python **3.8 or above** is required to use Pycord. +::: + +:::tip +Before you start installing python packages globally, it's recommended you set up a virtual environment. +You can find instructions for that [here](More/virtual-environments). +::: + +## Fresh Installation + +To install Pycord, you can use the following command in your terminal: + +``` +pip install py-cord +``` + +:::tip +Remember that you need to install `py-cord`, not `pycord`. +Also, the `pip` command varies depending on your installation. For example, it might be `python3 -m pip` on macOS/Linux or `py3 -m pip` on some versions of Windows. +::: + +If you need voice support for your bot, you should run: + +``` +pip install "py-cord[voice]" +``` + +## Migration + +### Updating Pycord + +If you are upgrading from a previous version of Pycord, you can use the following command in your terminal to upgrade to the latest version: + +``` +pip install -U py-cord +``` + +### Migrating from other libraries + +If you are migrating from another library, say, `discord.py`, first of all, you need to uninstall it. + +``` +pip uninstall discord.py +``` + +Then, you can install Pycord, it's as simple as that!: + +``` +pip install py-cord +``` + +:::caution +Uninstalling `discord.py` _after_ installing `py-cord` can cause issues. Make sure to uninstall it first! +::: + +## Installing Other Builds + +### Development Build + +:::caution +The development build comes with cutting edge features and new functionality, but as it isn't a stable build you may encounter bugs. +::: + +To install the development build, you can use the following command in your terminal: + +``` +pip install -U git+https://github.com/Pycord-Development/pycord +``` + +:::important +Git is required to install this build. [Learn how you can install Git](./more/git). +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/interactions/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/_category_.json new file mode 100644 index 00000000..ea28be60 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 4, + "label": "Interactions" +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json new file mode 100644 index 00000000..6dcafe83 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Application Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx new file mode 100644 index 00000000..b4ffeade --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx @@ -0,0 +1,85 @@ +--- +title: Context Menus +description: Learn all about Context Menus (User Commands & Message Commands) and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +When you right-click a message, you may see an option called "Apps". Hover over it, and you can see +commands a bot can run with that message. These are called message commands. + +When you right-click a user in the user list, you can once again see an option called "Apps". +Hover over it, and you can see commands a bot can run with that message. These are called user commands. + +Together, these two are called Context Menus or Context Menu Commands. These commands work very much like normal commands, except they take a member or message. + +:::note + +A bot can have up to 5 global Context Menus of each type. + +::: + +## User Commands + +Creating a user command is very simple. + +```python +@bot.user_command(name="Account Creation Date", guild_ids=[...]) # create a user command for the supplied guilds +async def account_creation_date(ctx, member: discord.Member): # user commands return the member + await ctx.respond(f"{member.name}'s account was created on {member.created_at}") +``` + + + +
+ + Account Creation Date + +
+ {defaultOptions.profiles.bob.author}'s account was created on 2020-01-01 +
+
+ +## Message Commands + +```python +@bot.message_command(name="Get Message ID") # creates a global message command. use guild_ids=[] to create guild-specific commands. +async def get_message_id(ctx, message: discord.Message): # message commands return the message + await ctx.respond(f"Message ID: `{message.id}`") +``` + + + + Do. Or do not. There is no try. + + +
+ + Get Message ID + +
+ Message ID: 930650407917748286 +
+
+ +
+ +:::info Related Topics + +- [Slash Commands](./slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx new file mode 100644 index 00000000..edac55b3 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx @@ -0,0 +1,56 @@ +--- +title: Localizations +description: Localizations are a way to make your bot more accessible to your users. Learn all about localizations now! +--- + +Localizations are a way to make your bot more accessible to your users. You can localize the command +name, the names of any arguments, and any text that is displayed to the user. + +## Syntax + +```python +@bot.slash_command( + name="ping", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + }, + options=[ + Option( + name="Example", + name_localizations={ + "en-GB": "British Example" + }, + description="Example option that does nothing", + description_localizations={ + "en-GB": "British example option that does nothing" + } + ) + ] +) +async def ping(ctx, example): + responses = {"en-US": "Pong!", + "en-GB": "British Pong!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +@bot.slash_command( + name="ping2", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + } +) +async def ping2(ctx, example: Option(str, "example", name_localizations={"en-GB": "British Example"}, description="Example option that does nothing", description_localizations={"en-GB": "British example option that does nothing"})): + responses = {"en-US": "Pong2!", + "en-GB": "British Pong2!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +``` + +- [`Locales`](https://discord.com/developers/docs/reference#locales) - List of valid locales recognized by Discord diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx new file mode 100644 index 00000000..ed454dad --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx @@ -0,0 +1,292 @@ +--- +title: Slash Commands +description: Learn all about Slash Commands and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On March 24, 2021, Discord added Slash Commands to Discord as an easier, more efficient, and better way of using bot commands. Pycord has implemented Slash Commands into the library, so it's simple, efficient, and familiar. + +:::important + +Remember that Slash Commands require your bot to be invited with the `application.commands` scope or Slash Commands will not show up. Bots already in the guild can simply be invited again with the scope; there is no need to kick the bot. + +::: + +## Syntax + +Let's create a simple Slash Command. + +```py +import discord + +bot = discord.Bot() + +# we need to limit the guilds for testing purposes +# so other users wouldn't see the command that we're testing + +@bot.command(description="Sends the bot's latency.") # this decorator makes a slash command +async def ping(ctx): # a slash command will be created with the name "ping" + await ctx.respond(f"Pong! Latency is {bot.latency}") + +bot.run("TOKEN") +``` + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +Let's go through the code. + +First, we import Pycord's `discord` package. + +Next, we create a [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot) object and assign it to a variable `bot`. + +We then go ahead and use the [`@bot.command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.command) decorator, which registers a new Slash Command. We pass a `description` parameter to give a description to the Slash Command. We can also pass a `name` parameter to change the Slash Command's name. By default, the name of the Slash Command will be the name of the function, in this case, `/ping`. + +We create an async function called `ping` with parameters `ctx`, which, when called, sends the bot's ping/latency using [`ctx.respond`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext.respond). + +## Subcommand Groups + +You might want to group certain commands together to make them more organised. A command group is exactly what it sounds like, a group of individual Slash Commands together. + +In order to make a Slash Command group, you can use the `bot.create_group` function. + +```python +import discord + +bot = discord.Bot() + +# create Slash Command group with bot.create_group +greetings = bot.create_group("greetings", "Greet people") + +@greetings.command() +async def hello(ctx): + await ctx.respond(f"Hello, {ctx.author}!") + +@greetings.command() +async def bye(ctx): + await ctx.respond(f"Bye, {ctx.author}!") + +bot.run("TOKEN") +``` + +Or, you can instead manually make a `SlashCommandGroup` class like so: + +```python +import discord + +math = discord.SlashCommandGroup("math", "Math related commands") + +@math.command() +async def add(ctx, num1: int, num2: int): + sum = num1 + num2 + await ctx.respond(f"{num1} plus {num2} is {sum}.") + +@math.command() +async def subtract(ctx, num1: int, num2: int): + sum = num1 - num2 + await ctx.respond(f"{num1} minus {num2} is {sum}.") + +# you'll have to manually add the manually created Slash Command group +bot.add_application_command(math) +``` + +Here's what the registered subcommands will look like in the Slash Command Menu: + +![Picture of the subcommands in the Slash Command Menu](../../assets/interactions/groups-and-subcommands.jpg) + +You'll notice that there's the name of the Slash Command Group and then the name of the subcommand separated by a space. + +::: + +:::info Cogs + +If you are looking to add Slash Command Groups to cogs, please look at our [Cogs page](../../popular-topics/cogs)! + +::: + +## Sub-groups + +We've made a subcommand group, but did you know that you could create a group inside another? + +```python +from discord import SlashCommandGroup +from math import sqrt + +math = SlashCommandGroup("math", "Math related commands") +advanced = math.create_subgroup("advanced", "Advanced math commands") + +@advanced.command() +async def square_root(ctx, x: int): + await ctx.respond(sqrt(x)) + +bot.add_application_command(math) +``` + +The command created above can be invoked by typing `/math advanced square_root`. + +## Options & Option Types + +Whenever you're using Slash Commands, you might notice that you can specify parameters that the user has to set or can optionally set. These are called Options. + +Options can also include a description to provide more information. [You can learn more about Options in our documentation!](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.Option) + +Since you want different inputs from Options, you'll have to specify the type for that Option; there are a few ways of doing this. + + + + +You could use Type Annotations and let Pycord figure out the option type or explicitly specified using the [`SlashCommandOptionType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.SlashCommandOptionType) enum. + +```python +import discord + +bot = discord.Bot() + +@bot.command() +# pycord will figure out the types for you +async def add(ctx, first: discord.Option(int), second: discord.Option(int)): + # you can use them as they were actual integers + sum = first + second + await ctx.respond(f"The sum of {first} and {second} is {sum}.") + +@bot.command() +# this explicitly tells pycord what types the options are instead +async def join( + ctx, + first: discord.Option(discord.SlashCommandOptionType.string), + second: discord.Option(discord.SlashCommandOptionType.string) +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + add + +
+ The sum of 1 and 1 is 2. +
+ +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+ + +Instead of Type Annotations, you can also use the option decorator. This is usually done to have type-hinting. + +```python title="Slash Command Type" +import discord + +bot = discord.Bot() + +@bot.command() +@discord.option("first", type=discord.SlashCommandOptionType.string) # type = str also works +@discord.option("second", type=discord.SlashCommandOptionType.string) # type = str also works +async def join( + ctx, + first: str, + second: str, +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+
+ +## Autocomplete + +Discord's autocomplete allows developers to determine option choices that are used in a slash command option. You can do this by defining a function: + +```py +async def get_animal_types(ctx: discord.AutocompleteContext): + """ + Here we will check if 'ctx.options['animal_type']' is a marine or land animal and return respective option choices + """ + animal_type = ctx.options['animal_type'] + if animal_type == 'Marine': + return ['Whale', 'Shark', 'Fish', 'Octopus', 'Turtle'] + else: # is land animal + return ['Snake', 'Wolf', 'Lizard', 'Lion', 'Bird'] + +@bot.slash_command(name="animal") +async def animal_command( + ctx: discord.ApplicationContext, + animal_type: discord.Option(str, choices=['Marine', 'Land']), + animal: discord.Option(str, autocomplete=discord.utils.basic_autocomplete(get_animal_types)) +): + await ctx.respond(f'You picked an animal type of `{animal_type}` that led you to pick `{animal}`!') +``` + + + +
+ + animal + +
+ You picked an animal type of Marine that led you to pick Shark! +
+
+ +:::warning + +Autocomplete can **only** be used with slash commands. + +::: + +:::info Related Topics + +- [Interactions Index](../../interactions) +- [Rules and Common Practices](../../getting-started/rules-and-common-practices) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/interactions/index.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/index.mdx new file mode 100644 index 00000000..8603437f --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/index.mdx @@ -0,0 +1,242 @@ +--- +title: Discord Interactions +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +In December 2020, Discord released their first Interaction: the +[Slash Command](https://discord.com/developers/docs/interactions/application-commands#slash-commands). +Since then, Discord has added many types of Interactions, including: + +[**Application Commands**](https://discord.com/developers/docs/interactions/application-commands) + +- [**Slash Commands**](https://discord.com/developers/docs/interactions/application-commands#slash-commands): + Commands that can be used with the `/` prefix. +- **Context Menu Commands**: Commands that can be used from the right-click menu. + - [**User Commands**](https://discord.com/developers/docs/interactions/application-commands#user-commands): + Commands that can be used on a user by alt-clicking/selecting them. + - [**Message Commands**](https://discord.com/developers/docs/interactions/application-commands#message-commands): + Commands that can be used on a message by alt-clicking/selecting it. + +[**UI Components**](https://discord.com/developers/docs/interactions/message-components) + +- [**Buttons**](https://discord.com/developers/docs/interactions/message-components#buttons): + Buttons are attached to a message and can be clicked on to perform an action. +- [**Select Menus**](https://discord.com/developers/docs/interactions/message-components#select-menus): + Drop-down menus are used to select a number of options from a list. +- [**Modals**](https://discord.com/developers/docs/interactions/message-components#text-inputs): + Form-like modals can be used to ask for input from a user. + +## Application Commands + +Application Commands are another set of new features that are intended to avoid compromising users' safety and privacy. +They're relatively easy to add to your bot, and give people a simpler and safer way to use commands. + +### [Slash Commands](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.SlashCommand) + +Slash Commands were the first Interaction added to Discord. They're easy to use and create, and +is the only prefix commands alternative that does not need Message Content intent. + +:::note + +Preferring prefix commands over Application Commands is **not** a valid reason to apply for the +Message Content intent. Using that as a reason will get your application denied. + +::: + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +This is what a Slash Command looks like. Not too different from a prefix command, +apart from the note telling you who invoked it. A Slash Command's fields can accept any of the following: + +- Members +- Roles +- Channels +- Attachments +- Text + +Just about as good as it gets. + +### [Message](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.MessageCommand) and [User](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.UserCommand) Commands + +Message Commands and User Commands were both introduced at around the same time, and are very similar to each other, so we'll be +introducing them together. These commands can be found in the `Apps` tab when alt-clicking. The only difference between the two is that +Message Commands only appear in the `Apps` tab of a message, while User Commands are found in the `Apps` tab of a user. Message Commands +can be used to quickly report a message, warn a user for a message, and other functions. Likewise, User Commands can be used to add a +user to a ticket, warn a user, and more. + +Here's an example of a Message Command: + + + + Hello World! + + +
+ + Reverse Message + +
+ Message 930650407917748286 reversed is "!dlroW olleH" +
+
+ +
+ +And here's an example of a User Command: + + + + {defaultOptions.profiles.dorukyum.author} has been on Discord for a long time + + +
+ + User Age + +
+ {defaultOptions.profiles.dorukyum.author} is 1 week old. +
+ +
+ + User Age + +
+ {defaultOptions.profiles.bob.author} is 40 years old. +
+ + 🤔 + +
+ +
+ +Pretty cool, right? To learn more about these two, please read the [Context Menus guide](./application-commands/context-menus.mdx). + +## [Application Commands](#application-commands) vs. [Prefix Commands](../extensions/commands/prefixed-commands) + +Ever since Discord was created, apps on it have used prefix commands. Using prefixes meant that you would have to put a +certain character (or string of characters) in front of your command, such as the exclamation mark in `!ping`. The way this +worked was that your bot would listen for messages, pick out the ones that had their specific prefix, and then respond to the command. +Now, Discord is encouraging developers to switch their bots over to Application Commands, which is a new system meant to preserve the +privacy and safety of their users. But why exactly is Discord making us switch? What's the better option, Application Commands or prefix +commands? Below, we'll discuss everything you need to know. + +### Discord's Decision + +Application Commands were conceptualized partly due to privacy concerns. When Discord first began, they weren't entirely concerned about bots +having access to the content of every message that was being sent. However, as Discord grew, this became more of a problem. Hypothetically, bots +could simply log every message they're able to receive via the Discord API and hand their contents over to a company or other third party. This is +a problem, since that data is meant to be used only by Discord. As such, they locked down Message Content, and introduced Application Commands for +bot developers to use instead. + +Prefix commands work by reading messages, as described before. Application Commands, however, don't +work this way; instead, they work by having your bot get information from Discord about when a command was used. This way, Discord can limit +Message Content only to bots that _absolutely_ depend on it, such as auto-moderation bots. + +### Who has to Use Application Commands + +Any verified bot that does not have the Message Content intent must use Application Commands. Discord is allowing developers to submit +applications for the ability to use the intent; however, since they don't want to keep supporting prefix commands due to privacy concerns, +they will automatically decline any application that includes only that as a reason. So, if your bot doesn't have an auto-moderation feature +(or any other functionality that requires Message Content), you're out of luck. + +Unverified bots, however, don't have to use Application Commands. This is because the Message Content intent is a `Privileged Intent`, meaning that +it must be applied for only if your bot is verified or about to be verified. Unverified bots don't have to apply for Privileged Intents, so they can +use them freely. + +So, if your bot is made only for a couple of servers, you can choose between prefix commands and Application Commands. However, if you plan on expanding +your bot's reach, it'll have to use Application Commands. + +### What's the Better Option + +Choosing which is the better option is up to you, if you're starting small. If +you plan on growing your bot, however, you will have to use Application Commands. Since prefix commands are slowly being phased out by Discord, +there isn't much of a choice for developers of larger bots. + +## Message Components + +Message Components are fairly new features in Discord, allowing developers to give their bots a fast +and understandable user interface. Message Components are easy to use and make your bot look modern, +sleek, and downright awesome. + +### [Views](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View) + +Views are not an Application Command nor are they a Message Component. Views are the invisible placeholders, or grid, +that Message Components lie in. Views can have up to 5 [`Action Rows`](https://docs.pycord.dev/en/stable/api/models.html#discord.ActionRow), +and Action Rows can have a maximum of 5 slots. Below, you can find a table showing how many slots a Message Interaction takes up. + +| Component | Slots | +| ------------ | ----------------------------------------------- | +| Buttons | 1 Slot | +| Select Menus | 5 Slots | +| Text Modals | 1 Slot (opened via a Button) | + +So, based on this, you could have a maximum of 25 Buttons in a View with no Select Menus, and 5 Select +Menus in a View with no Buttons. This doesn't mean you can't have them both in a View, however. You can have +a combination of them, such as 20 Buttons and a Select Menu or 10 Buttons and 3 Select Menus. + +### [Buttons](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button) + +Buttons are the first of the Message Components. They allow for quick responses to prompts, such as for canceling or continuing an action. +Of course, these aren't their only uses; people have created awesome things with Buttons, such as calculators, games, and more! + + + + Discord Buttons are awesome! +
+ + Click me! + +
+
+
+ +
+ +This is what a Button looks like, very simple and modern. To learn more about Buttons, refer to our +[Buttons page](./ui-components/buttons.mdx). + +### [Select Menus](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Select) + +Select Menus are the second of Discord's Message Components. They allow users to select from a list of choices, which your bot can then use. +Select Menus are good for things such as choosing features, pages of a help menu, and more. + +![Select Menu Example Image](../assets/interactions/select-menus-example.png) + +This is what a Select Menu looks like. While not looking as good as Buttons, they still look great +and have even greater possibilities. To learn more about Select Menus, please refer to our [Select +Menus page](./ui-components/dropdowns.mdx). + +### [Modal Dialogs](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal) + +Text Modals are the most recently added Message Component in Discord. They're useful for text input and filling out forms, such as a +sign-up for your bot's service. These are meant to replace long bot setup processes by allowing users to fill out multiple text fields, +which avoids having the user send multiple messages for the bot. Modals can be accessed by either invoking an Application Command or by +interacting with another UI Component. + +![Text Modal Example Image](../assets/interactions/modal-example.png) + +This is what a Text Modal looks like, easy to use and one of the most useful Message Components yet. To learn more about Text Modals, +please visit our [Modal Dialogs page](./ui-components/modal-dialogs.mdx). diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json new file mode 100644 index 00000000..7b0a72fe --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "UI Components", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx new file mode 100644 index 00000000..046b36c7 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx @@ -0,0 +1,314 @@ +--- +title: Buttons +description: Learn all about implementing buttons in your Discord Bot using Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On May 26, 2021, Discord added a new interaction called buttons. Instead of reactions, bots could now +send buttons and users could use them to interact with bots. This opened up a whole new world of +possibilities for bots. Soon after, developers made calculators, polls, and games like blackjack, UNO, +and even Minecraft! Buttons provided a clear and easy to use interface for interacting with bots. + +So, let's learn how you can add buttons to your bot! + +## Concept + +Buttons weren't the only update to the interactions system in Discord. Discord also added [Select Menus](./dropdowns) and [Modal Dialogs](./modal-dialogs), both of which work very similarly to buttons. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive button. + +```python +import discord + +bot = discord.Bot() # Create a bot object + +class MyView(discord.ui.View): # Create a class called MyView that subclasses discord.ui.View + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.primary, emoji="😎") # Create a button with the label "😎 Click me!" with color Blurple + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") # Send a message when the button is clicked + +@bot.slash_command() # Create a slash command +async def button(ctx): + await ctx.respond("This is a button!", view=MyView()) # Send a message with our View class that contains the button + +bot.run("TOKEN") # Run the bot +``` + +Using this command should return the following message: + + + +
+ + button + +
+ This is a button! +
+ + Click me! + +
+
+
+ +
+ +As you can see, we create a class called `MyView` that [subclasses](#oop) +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `button_callback` to the `MyView` class with the decorator +[`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button). +This decorator adds a button to a component. This function takes two arguments: the button that was +clicked and the interaction. These arguments are passed to the function when the button is clicked +by the module. We use the [`interaction.response.send_message`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse.send_message) +function to send a message to the channel where the interaction was sent. + +Finally, we create a global slash command called `button` that sends the message, along with the view +that contains a button. + +This is the basic syntax of creating a button. What you create with it is up to you. You can worry +about making your button do amazing things, while Pycord handles the rest! + +## Button Styles + + + +| Name | Usage | Color | +| --------- | ----------------------------------------------------------------------------------------- | ------- | +| Primary | `discord.ButtonStyle.primary` / `discord.ButtonStyle.blurple` | Blurple | +| Secondary | `discord.ButtonStyle.secondary` / `discord.ButtonStyle.grey` / `discord.ButtonStyle.gray` | Grey | +| Success | `discord.ButtonStyle.success` / `discord.ButtonStyle.green` | Green | +| Danger | `discord.ButtonStyle.danger` / `discord.ButtonStyle.red` | Red | +| Link | `discord.ButtonStyle.link` / `discord.ButtonStyle.url` | Grey | + +Check out the [`discord.ButtonStyle`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ButtonStyle) class for more information. + +![Different Button Styles](../../assets/interactions/button-styles.png) + +You can set a button's style by adding the `style` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) decorator. + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.success) + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots, and each button takes up 1 slot. +So, how do we move the buttons to another row? + +This can be done by specifying the `row` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) +decorator. + +:::info The `row` argument + +The row argument specifies the relative row this button belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=1, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") +``` + +## Disabling Buttons + +### Pre-Disabled Buttons + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary, disabled=True) # pass `disabled=True` to make the button pre-disabled + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView()) +``` + +### Disabling Buttons on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + button.disabled = True # set button.disabled to True to disable the button + button.label = "No more pressing!" # change the button's label to something else + await interaction.response.edit_message(view=self) # edit the message's view +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(emoji="😀", label="Button 1", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) + + @discord.ui.button(label="Button 2", style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +Sometimes, you want to have a button that is disabled after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView(timeout=30)) +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a button that is disabled after a certain amount of time, you want to have a +button that is always working. + +Normally, when the bot goes offline, all of its buttons stop working. You will be able to see the +buttons, but nothing will happen when you press them. This is a problem +if you are trying to create a self-role system with buttons, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons will stop working. When the bot comes back online, however, the buttons will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view must have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.button(label="A button", custom_id="button-1", style=discord.ButtonStyle.primary, emoji="😎") # the button has a custom_id set + async def button_callback(self, button, interaction): + await interaction.response.send_message("Button was pressed", ephemeral=True) + +@bot.command() +async def button(ctx): + await ctx.send(f"Press the button! View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many buttons can I have in a message? + +Each message can have a maximum of 25 buttons. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do buttons need any special permissions? + +No new permissions are needed for either the bot or the server to allow bots to use buttons. + +#### Should I replace reactions with buttons for my bot? + +That is up to you. Buttons do provide a cleaner interface for your bot and are easier to use. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx new file mode 100644 index 00000000..8320f25d --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx @@ -0,0 +1,339 @@ +--- +title: Select Menus +description: Learn all about implementing Select Menus or Dropdowns in your Discord Bot with Pycord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Shortly after the buttons were added, Discord added their second message component: Select Menus. Select Menus allow users to choose from a list of items sent by a bot. These are a great substitute for having a user send a number that corresponds to an option. You can even allow users to select multiple options from the Select Menus. This guide will show you the easy and painless ways of using them with Pycord. + +## Concept + +Select Menus aren't the only message component in Discord. There's also [Buttons](./buttons) and [Modal Dialogs](./modal-dialogs). Select Menus make it easy for users to pick one or multiple options from a list provided by a bot. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive select menu. + +```python +import discord + +bot = discord.Bot() + +class MyView(discord.ui.View): + @discord.ui.select( # the decorator that lets you specify the properties of the select menu + placeholder = "Choose a Flavor!", # the placeholder text that will be displayed if nothing is selected + min_values = 1, # the minimum number of values that must be selected by the users + max_values = 1, # the maximum number of values that can be selected by the users + options = [ # the list of options from which users can choose, a required field + discord.SelectOption( + label="Vanilla", + description="Pick this if you like vanilla!" + ), + discord.SelectOption( + label="Chocolate", + description="Pick this if you like chocolate!" + ), + discord.SelectOption( + label="Strawberry", + description="Pick this if you like strawberry!" + ) + ] + ) + async def select_callback(self, select, interaction): # the function called when the user is done selecting options + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") + +@bot.command() +async def flavor(ctx): + await ctx.respond("Choose a flavor!", view=MyView()) + +bot.run("TOKEN") +``` + +There's a lot going on over here! Don't worry, we will go over the code and explain it. + +As you can see, we create a class called `MyView` that subclasses +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `select_callback` to the `View` class with the decorator +[`discord.ui.select`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.select). +This decorator adds a select menu to the view. This decorator takes a few arguments to customize your select menu. Read them in the [Customization section](#customization). + +That was the decorator. Now, the function itself is pretty simple. It takes two parameters, not including `self`. The parameters are `select`: The select menu, and `interaction`: a [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object. Both of these are passed by Pycord, so you just need to specify them in the function! + + + +In the callback, you could do anything you want. You get the two parameters `select` and `interaction` to play around with. Here, we send a message using `await interaction.response.send_message` (where interaction is [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse)) with content `select.values[0]`, which sends the label of the first/only option the user selected. Obviously, this is only an example, and you could do just about anything you want. + +Finally, we create a global slash command called `flavour` that sends a message "Choose a flavor!" along with the view +that contains our select menu. + +This is the basic syntax of creating a select menu. What you create with it is up to you. You can worry +about making your code do amazing things, while Pycord handles the rest! + +## Customization + +#### Select Menu Properties + +- `select_type`: The type of select to create. This must be a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. +- `channel_types`: A list of channel types that can be selected in the menu. This is only valid for selects of `select_type` [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType). +- `options`: A list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. These are the options that can be selected in this menu. +- `placeholder` is the placeholder text shown in the select menu if no option is selected. +- `custom_id`: The ID of the select menu that gets received during an interaction. It is recommended not to set this to anything unless you are trying to create a persistent view. +- `row`: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). +- `min_values`: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `max_values`: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `disabled`: Whether the select is disabled or not. Defaults to False. + +#### Select Option Properties + +In the `options` parameter, you pass a list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. This class also has a few parameters: + +- `default` (whether the option is selected by default) +- `description` (an additional description, if any) +- `emoji` (a string or an emoji object, if any) +- `label` (the name displayed to users, can be up to 100 characters) +- `value` (a special value of the option, defaults to the label). + +## Select Types + +In addition to regular string selects, you can also have your select menu contain users, roles, mentionables, and channels as its options. You can use these alternative select types by passing a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value for the `select_type` parameter when creating the Select. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.user_select + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +Additionally, you can use shortcut decorators to create a [`discord.ui.Select`](https://docs.pycord.dev/en/master/api/ui_kit.html#discord.ui.select) with a predetermined [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. Using a shortcut decorator, the above code can be rewritten like this: + +```python +class MyView(discord.ui.View): + @discord.ui.user_select() + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +### Specifying Channel Types + +When using a [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType.channel_select) type select menu, you can pass in a list of [`discord.ChannelType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ChannelType) values to limit which types of channels users can choose when interacting with the select menu. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.channel_select, + channel_types=[discord.ChannelType.text, discord.ChannelType.voice] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"You selected {select.values[0].mention}") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots. A button takes a single slot, while a select menu takes up all 5 of them. This means a view can have a maximum of 5 select menus, or any possible combination of select menus and buttons. + +The arrangement of buttons and select menus is generally adjusted by Pycord. However, it is possible to move them to specific relative rows. This is done by specifying the `row` argument. + +:::info The `row` argument + +The row argument specifies the relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero-indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=0, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.select( + row = 1, + options = [...] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") +``` + +## Disabling Select Menus + +### Pre-Disabled Menus + +```python +class MyView(discord.ui.View): + @discord.ui.select( + disabled = True, # pass disabled=True to set the menu as disabled + options = [...] + ) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send("Select and option from the menu!", view=MyView()) +``` + +### Disabling Menus on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + select.disabled = True # set the status of the select as disabled + await interaction.response.edit_message(view=self) # edit the message to show the changes +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def first_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) # edit the message to show the changes + + @discord.ui.select(options = [...]) + async def second_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +You may want a select menu to automatically stop working after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select(ctx): + await ctx.send(view=MyView(timeout=30)) # specify the timeout here +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a select menu that is disabled after a certain amount of time, you want to have a +select menu that is always working. + +Normally, when the bot goes offline, all of its views stop working, even if they don't have a timeout. You will be able to see the +views, but nothing will happen when you try to interact with them. This is a problem +if you are trying to create a self-role system, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons and select menus will stop working. However, when the bot comes back online, the buttons and select menus will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view much have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.select(custom_id="select-1", options = [...]) # a custom_id must be set + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send(f"View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many select menus can I have in a message? + +Each message can have a maximum of 5 select menus. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do select menus need any special permissions? + +No new permissions are needed in the bot or in the server. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx new file mode 100644 index 00000000..bd585c77 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx @@ -0,0 +1,107 @@ +--- +title: Modal Dialogs +description: Learn how you can implement Modals in your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Modal Dialogs, also known as "modals", provide a form-like structure for bots to receive input from users. No extra permissions are needed for bots to send modal dialogs, so it becomes a convenient workaround for bots to receive longer input without needing the Message Content [intent](../../popular-topics/intents). + +## Concept + +Modal Dialogs consist of a title, custom ID, and up to 5 [`discord.ui.InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) components. While creating modals, we generally subclass [`discord.ui.Modal`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal), as we'll see later. + +Unlike other UI Components, Modals cannot be sent with messages. They must be invoked by an Application Command or another UI Component. + +## Usage Syntax + +```py +class MyModal(discord.ui.Modal): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.add_item(discord.ui.InputText(label="Short Input")) + self.add_item(discord.ui.InputText(label="Long Input", style=discord.InputTextStyle.long)) + + async def callback(self, interaction: discord.Interaction): + embed = discord.Embed(title="Modal Results") + embed.add_field(name="Short Input", value=self.children[0].value) + embed.add_field(name="Long Input", value=self.children[1].value) + await interaction.response.send_message(embeds=[embed]) +``` + + + + +The `ctx` parameter we define in Application Commands receives an [`ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext) object. Using its `send_modal()` coroutine, you can send a Modal dialog to the user invoking the Application Command. + +```py +@bot.slash_command() +async def modal_slash(ctx: discord.ApplicationContext): + """Shows an example of a modal dialog being invoked from a slash command.""" + modal = MyModal(title="Modal via Slash Command") + await ctx.send_modal(modal) +``` + + + + +The `interaction` parameter we define in UI Components receives an [`Interaction`](https://docs.pycord.dev/en/stable/api/models.html#discord.Interaction) object. The `response` attribute of the object contains an [`InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object, with various coroutines such as `send_message()` and `send_modal()`, which we utilize. + +```py +class MyView(discord.ui.View): + @discord.ui.button(label="Send Modal") + async def button_callback(self, button, interaction): + await interaction.response.send_modal(MyModal(title="Modal via Button")) + +@bot.slash_command() +async def send_modal(ctx): + await ctx.respond(view=MyView()) +``` + + + + +The above example uses an embed to display the results of the modal submission, but you can do anything you want with the text provided by the user. +Each input field can be accessed in the order it was added to the modal dialog, via `Modal.children`. + +## Customization + +A Modal can have up to 5 [`InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) fields. These fields offer some customization. + +Each field has a label which is shown to the user. This is defined with `label`. + +The `style` parameter is used to determine whether it should be a short (single-line) or long (multi-line) input field. + +There are a number of aliases that can be used: + +```x title="Single-line InputTextStyle values:" +short +singleline +``` + +```x title="Multi-line InputTextStyle values:" +paragraph = 2 +multiline = 2 +long = 2 +``` + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Buttons](./buttons) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/introduction.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/introduction.mdx new file mode 100644 index 00000000..3262c632 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/introduction.mdx @@ -0,0 +1,50 @@ +--- +title: Introduction +description: Pycord Guide is a complete guide for Pycord. Learn how to create Discord Bots today! +sidebar_position: 1 +--- + +Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord, written in Python. Pycord is a maintained fork of [discord.py](https://github.com/Rapptz/discord.py). + +## Before you begin + +Pycord is an advanced and complex Python library. To take advantage of the full capabilities of Pycord, you will need to have a good understanding of Python. You should know the basics of Python and have an understanding of the following concepts: + +- Variables +- Data Types +- Functions +- Packages +- Conditionals +- Loops +- Classes +- Object-Oriented Programming +- Inheritance +- Exception Handling +- Iterators +- Coroutines +- Async/Await + +This list is not exhaustive, but it should give you a good idea of what you need to know to get started. + +When you see an ellipsis - that's the three dots - in this guide, it is a placeholder for code that you need to fill in. Sometimes, it may be code for a command, while other times it could be something simple like a Guild ID. Make sure to replace them before running your bot! + +## Learning Resources + +Here are some good resources to get started or to freshen up your Python knowledge: + +- [Official Beginner's Guide](https://wiki.python.org/moin/BeginnersGuide) +- [Official Tutorial](https://docs.python.org/3/tutorial/) +- [Automate the Boring Stuff, a free online book for complete beginners to programming](https://automatetheboringstuff.com/) +- [Learn Python in y Minutes, complete cheat sheet for people who know programming already](https://learnxinyminutes.com/docs/python3/) +- [Swaroopch's free Python book](http://python.swaroopch.com/) +- [Codeabbey, exercises for beginners](http://www.codeabbey.com/) + +## Credits + +First of all, we would like to thank [Rapptz](https://github.com/Rapptz) for the original [discord.py](https://pypi.org/project/discord.py) library. Pycord is a maintained fork of this library. + +We would also like to thank the [discord.js guide](https://discordjs.guide), which inspired this guide style-wise, and the [original Pycord Guide](https://namantech.me/pycord), which inspired some content in this guide. + +We created this guide using [Docusaurus v2](https://docusaurus.io), a modern static site generator for React. We would also like to thank Danktuary for his [`@discord-message-components/react`](https://www.npmjs.com/package/@discord-message-components/react) package, from which we took the Discord message components. + +And finally, we would like to thank the amazing and loving community of Pycord users, contributors and developers. diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/more/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/more/_category_.json new file mode 100644 index 00000000..2cbe2c56 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/more/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 8, + "label": "More", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/more/community-resources.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/more/community-resources.mdx new file mode 100644 index 00000000..ed3075bd --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/more/community-resources.mdx @@ -0,0 +1,23 @@ +--- +title: Community Resources +--- + +This page showcases the amazing things created by the Pycord community, including bots, Plugins, and more. + +## Plugins + +| Name | Type | GitHub | +| --------------- | ------------ | --------------------------------------------------------------- | +| Music Cord | Music | [NixonXC/cord-music](https://github.com/NixonXC/cord-music) | +| pycord-i18n | Localization | [Dorukyum-pycord-i18n](https://github.com/Dorukyum/pycord-i18n) | +| pycord-multicog | Cogs | [pycord-multicog](https://github.com/Dorukyum/pycord-multicog) | +| EzCord | Utilities | [EzCord](https://github.com/tibue99/ezcord) | + +## Bots + +| Name | Type | Link | +| ------------------------ | ------------ | ----------------------------------------------------------------------------------- | +| Discord-Multipurpose-Bot | Multipurpose | [github](https://github.com/pogrammar/Discord-multipurpose-bot/tree/master/Python) | +| inconnu | Fun & QOL | [github](https://github.com/tiltowait/inconnu) | +| Mai | Multipurpose | [github](https://github.com/TeamMai/Mai) & [website](https://xfghoul.github.io/Mai) | +| Toolkit | Multipurpose | [github](https://github.com/Dorukyum/Toolkit) | diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/more/contributing.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/more/contributing.mdx new file mode 100644 index 00000000..469ea3ee --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/more/contributing.mdx @@ -0,0 +1,463 @@ +--- +title: Contributing to the Guide +description: Learn how to contribute to the Pycord Guide. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +This page outlines some of the basic syntax you need to know to contribute to the guide. We recommend you also check out: + +- [Docusaurus's Docs](https://docusaurus.io/docs/) +- [Contributing Rules](https://github.com/Pycord-Development/guide/blob/master/.github/CONTRIBUTING.md) + +## Info + +We use [Docusaurus v2](https://docusaurus.io/) to generate our guide. All the guide pages are generated +from `mdx` files in the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory. +MDX allows you to use JSX in your markdown content. + +## Structure + +Let's visit the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory and check its file structure. + +We can see various folders and a few files in it. Let's talk a bit about the `introduction.mdx` file. At the top, you can see something like: + +```md +--- +title: Introduction +description: ... +sidebar_position: 1 +--- +``` + +Most pages have this at the top. The `title` defaults to the file name. Since the titles need to be Capitalized according to need while the file names are lowercased (sometimes, the file names are shorter than the title!), we set a title ourselves. + +The `description` field is also important. This is the text shown in an embed when the page's link is shared on Discord, Twitter or other websites that support embedded links. Make sure to give a nice an interesting description! + +The `sidebar_position` field is pretty self-explanatory. It sets the position of the page in the sidebar. Most files in categories do not need this since they are sorted alphabetically. + +## Markdown Syntax + +This page quickly outlines some of the syntax that is used in markdown. + +````mdx +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + + ```python + print("We can use code blocks like this.") + ``` + +You can add [links to other websites](https://pycord.dev). You can add images like this: ![alternate text that describes the image](https://pycord.dev/image.png). + +- You can create +- unordered lists like this + +1. Or ordered lists +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` +4. Like this + +# Headers + +## Go + +### Like + +#### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet +```` + +
+Preview +
+ +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + +```python +print("We can use code blocks like this.") +``` + +You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](@site/static/img/favicon.ico). + +- You can create +- unordered lists like this + +1. Or ordered lists + +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` + +4. Like this + + # Headers + + ## Go + + ### Like + + #### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet + +
+
+ +## Admonitions + +We can add warnings, notes, etc. with the following syntax: + +```md +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: +``` + +
+Preview +
+ +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: + +
+ +
+ +## Discord Message Components + +As most files already have the imports for these, it's not that hard to add them. + +First, import the necessary components: + +```tsx +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; +``` + +The div starts like so: + +```tsx + + + + +
+``` + +This is where you list a `DiscordMessage`. + +```tsx + + + Hello! + + + +
+``` + + + + Hello! + + + +
+ +It has a pretty straightforward syntax. + +:::tip + +Add a `
` to the end of a component to make the content below it look better. + +::: + +### Slash Commands + +To make a message authored by a slash command, do the following: + +```tsx + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+``` + + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+ +### Buttons + +To make a message with buttons, do the following: + +```tsx + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+``` + + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+ +## Page Format + +There are a few things you need to take care of: + +1. Make sure that the spelling and grammar is perfect. We have a GitHub action configured that will warn you about spelling errors when you start a pull request. Make sure to commit your changes accordingly. + + As for the grammar, you should try reading the changes you have done and wait for reviews from others. + +2. A common mistake people make is incorrect header style. People often think that the less the important the topic is, the lower it's heading style should be. + + ```md + [PAGE STARTS] + # Topic + ## Less Important Topic + ## Subtopic + ``` + + ```md + [PAGE STARTS] + # About + [Introduction] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + That's VERY wrong. Here's the correct example: + + ```md + [PAGE STARTS] + [Introduction] + ## Topic + ## Less Important Topic + ### Subtopic + ``` + + ```md + [PAGE STARTS] + [Introduction] + + ## About + [More Information] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + Note that the `---`s at the beginning have been skipped here. diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/more/git.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/more/git.mdx new file mode 100644 index 00000000..0f929d6d --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/more/git.mdx @@ -0,0 +1,55 @@ +--- +title: Installing Git +description: Learn how you can install Git on your system. +--- + +Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Let's see how to install Git on different platforms. + +## Windows + +On Windows, Git can be installed via: + +- [Git for Windows](https://gitforwindows.org) +- [Git Scm](https://git-scm.com/download/windows) + +## Linux + +On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. + +## Mac + +You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: + +``` +xcode-select --install +``` + +## Using Package Managers + +You can also install Git using package managers. + +### Chocolatey + +If you use the Chocolatey package manager, you can install Git using: + +``` +choco install git +``` + +### Scoop + +If you use Scoop, you can install Git using: + +``` +scoop install git +``` + +### Brew + +If you're on macOS or Linux, you can install Git using: + +``` +brew install git +``` diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx new file mode 100644 index 00000000..b0b8c7ea --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx @@ -0,0 +1,62 @@ +--- +title: Virtual Environments +description: Learn how to set up a virtual environment for Pycord. +--- + +## Setup + +Sometimes you want to keep libraries from polluting system installs or use a different version of libraries than the ones installed on the system. You might also not have permissions to install libraries system-wide. For this purpose, the standard library as of Python 3.3 comes with a concept called “Virtual Environment”s to help maintain these separate versions. + +A more in-depth tutorial is found on [Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html). + +However, for the quick and dirty: + +Go to your project’s working directory: + +```bash +$ cd your-bot-source +$ python3 -m venv venv +``` + +Activate the virtual environment: + +```bash +$ source venv/bin/activate +``` + +On Windows you activate it with: + +```batch +$ venv\Scripts\activate.bat +``` + +Use pip like usual: + +```bash +$ pip install -U py-cord +``` + +Congratulations. You now have a virtual environment all set up. + +## Additional info + +It can be useful to set up a requirements.txt, so you can just put all of your dependencies in there and have pip install it. +For instance, if you wanted to have the latest 2.0 version of pycord and [pytz](https://github.com/stub42/pytz/blob/master/src/README.rst), just create a file named requirements.txt with the following contents: + +``` +py-cord>=2.0.0 +pytz +``` + +And then (in your virtual environment) you can just execute + +```bash +pip install -r requirements.txt +``` + +To keep from committing your virtual environment to git, you can set up a .gitignore file with the following line +(assuming you named your virtual environment venv like the above example): + +``` +venv/ +``` diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/_category_.json new file mode 100644 index 00000000..c38ea014 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 7, + "label": "Popular Topics", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx new file mode 100644 index 00000000..5377a6c3 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx @@ -0,0 +1,140 @@ +--- +title: Cogs +--- + +Cogs, often known as modules or extensions, are used to organize commands into groups. This is useful +for grouping commands that have the same general idea (such as moderation commands). This also helps +to avoid making your bot's files messy and cluttered. + +## Getting Started + +First, you'll need to create a folder to store your cogs, e.g. `cogs/`. + +Then, create a file inside the folder, e.g. `cogs/greetings.py`. By convention, the file name should +be the same as the name of the cog or module. + +We can then create the cog. + +```python title="./cogs/greetings.py" +import discord +from discord.ext import commands + +class Greetings(commands.Cog): # create a class for our cog that inherits from commands.Cog + # this class is used to create a cog, which is a module that can be added to the bot + + def __init__(self, bot): # this is a special method that is called when the cog is loaded + self.bot = bot + + @commands.command() # creates a prefixed command + async def hello(self, ctx): # all methods now must have both self and ctx parameters + await ctx.send('Hello!') + + @discord.slash_command() # we can also add application commands + async def goodbye(self, ctx): + await ctx.respond('Goodbye!') + + @discord.user_command() + async def greet(self, ctx, member: discord.Member): + await ctx.respond(f'{ctx.author.mention} says hello to {member.mention}!') + + math = discord.SlashCommandGroup("math", "Spooky math stuff") # create a Slash Command Group called "math" + advanced_math = math.create_subgroup( + "advanced", + "super hard math commands!" + ) + + @math.command() + async def add(self, a: int, b: int): + c = a + b + await ctx.respond(f"{a} + {b} is {c}.") + + @advanced_math.command() + async def midpoint(self, x1: float, y1: float, x2: float, y2: float): + mid_x = (x1 + x2)/2 + mid_y = (y1 + y2)/2 + await ctx.respond(f"The midpoint between those coordinates is ({mid_x}, {mid_y}).") + + @commands.Cog.listener() # we can add event listeners to our cog + async def on_member_join(self, member): # this is called when a member joins the server + # you must enable the proper intents + # to access this event. + # See the Popular-Topics/Intents page for more info + await member.send('Welcome to the server!') + +def setup(bot): # this is called by Pycord to setup the cog + bot.add_cog(Greetings(bot)) # add the cog to the bot +``` + +You can add any number of commands to your cog, as well as event listeners. However, this code will +not work on its own. In your main bot file, you must add the following code: + +```python +bot.load_extension('cogs.greetings') +``` + +This loads the file `cogs/greetings.py` and adds it to the bot. +The argument of `load_extension` should be your cog's path (e.g. cogs/greetings.py) without the file +extension and with the `/` replaced with `.` + +If you have multiple cogs, you can add them all at once by adding the following code: + +```python +cogs_list = [ + 'greetings', + 'moderation', + 'fun', + 'owner' +] + +for cog in cogs_list: + bot.load_extension(f'cogs.{cog}') +``` + +## Cog Rules + +When using a cog instead of the main file, there are some changes you have to make to your code. This +is because cogs work slightly different from a regular file. + +### The `self` variable + +The self variable is a variable that represents a class. In the case of cogs, `self` represents +the cog. In the `__init__` function, you can see that we have `self.bot = bot`. `bot` represents your +`discord.Bot` or `discord.ext.commands.Bot` instance, which is used for some functions. + +This means that instead of using functions that would usually be accessed via `bot`, you now need +to access them via `self.bot` + +Because we're in a class, all of our commands are methods of that class. Because of this, all of our +functions need to have `self` as the first parameter, where `self` is the cog. Without this, we +wouldn't be able to access our bot instance. + +### Creating Commands + +When creating prefixed commands, your decorator would usually be something like `@bot.command()`. If you're using +cogs, this isn't the case. In a cog, you can't access the bot instance outside of functions, so to +register a function as a command, you must instead use `@commands.command()`. + +Similar to prefixed commands, you'll have to use either the `@discord.slash_command()`, `@discord.user_command()`, +or `@discord.message_command()` decorators for Application Commands. + +Also, when creating a command, make sure that it is indented. If we want a command to be actually +inside a cog, it has to be inside your cog's class. If the command is not inside the cog, +your command becomes useless. + +### Events + +When creating events, you can no longer use `@bot.event` as a decorator. This is because we cannot +access the `bot` variable outside a function. To make an event, you have to use the `ext.commands` +method, `@commands.Cog.listener()`. Events also need `self` as their first parameter. + +And that's it! Cogs are a simple and easy way of organizing your code. Now you can check out how to +create a help command [here](../extensions/commands/help-command). + +:::info Related Topics + +- [Creating a Help Command](../extensions/commands/help-command) +- [Rules and Common Practices](../getting-started/rules-and-common-practices) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Application Commands](../interactions#application-commands) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx new file mode 100644 index 00000000..6c19dd29 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx @@ -0,0 +1,383 @@ +--- +title: Error Handling +description: All about handling errors. +--- + +import { + DiscordEmbed, + DiscordInteraction, + DiscordMessage, +} from "discord-message-components/packages/react"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +## About + +When using the library, errors are frequently raised due to various reasons. These reasons range from the Discord API +failing your bot's request due to missing permissions or an invalid syntax error. + +Before going into error handling, it's best that you learn the basic ways of handling errors. A good resource is: + +- [W3Schools' Guide to Python Try-Except Statements](https://www.w3schools.com/python/python_try_except.asp) + +## Basic Handling + +The most basic way to handle errors is to tackle it at the source. This can be done like so: + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +import asyncio + +import discord + +intents = discord.Intents.default() +intents.message_content = True + +bot = discord.Bot(intents=intents) + + +@bot.slash_command(description="Gets some feedback.") +@discord.option("name", description="Enter your name.") +async def feedback(ctx: discord.ApplicationContext, name: str): + try: + await ctx.respond(f"Hey, {name}! Send your feedback within the next 30 seconds please!") + + def is_author(m: discord.Message): + return m.author.id == ctx.author.id + + feedback_message = await bot.wait_for("message", check=is_author, timeout=30.0) + await ctx.send(f"Thanks for the feedback!\nReceived feedback: `{feedback_message.content}`") + except asyncio.TimeoutError: + await ctx.send("Timed out, please try again!") + + +bot.run("TOKEN") +``` + +If you respond within 30 seconds, the interaction will look like so: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Great bot! + + + Thanks for the feedback! +
+ Received feedback: Great bot! +
+
+
+ +Otherwise, if you don't respond in time, the interaction will go as follows: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Timed out, please try again! + +
+
+ +This basic method of error handling can be extended to handle +many other errors including ones raised directly by py-cord. + +## Per-Command Handling + +This type of error handling allows you to handle errors per each command you have on your bot. +Each and every command can have it's own error handler made to handle specific errors that each command may raise! + +An example of per-command error handling is as follows: + +:::note Bridge Commands + +For these types of commands, it is recommended to utilize global error handling +until [the feature](https://github.com/Pycord-Development/pycord/issues/1388) is added. +::: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot(owner_id=...) # Your Discord user ID goes in owner_id + + +@bot.slash_command(description="A private command...") +@commands.is_owner() # This decorator will raise commands.NotOwner if the invoking user doesn't have the owner_id +async def secret(ctx: discord.ApplicationContext): + await ctx.respond(f"Hey {ctx.author.name}! This is a secret command!") + + +@secret.error +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.NotOwner): + await ctx.respond("Sorry, only the bot owner can use this command!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If your ID is registered as the owner ID, you'll get the following: + + + +
+ + secret + +
+ Hey Dorukyum! This is a secret command! +
+
+
+ +Any other user whose ID doesn't match the bot owner's will get the following: + + + +
+ + secret + +
+ Sorry, only the bot owner can use this command! +
+
+
+ +This local (per-command) error handler can also be used to handle the same types of errors that standard try-except +statements can handle. This is done by using the same method as above with the `isinstance` built-in function. + +## Per-Cog Handling + +Adding error handlers per-command can be quite the task in terms of work if you have a lot. If you have happened to +group your commands in cogs, then you're in luck! You can create an error handler that is specific to a cog and +handles all errors raised by commands inside that cog. + +Here's an example of a bot with a cog that implements its own error handling: + +```python title="./cogs/dm.py" +# This cog is for DM only commands! Sadly, we only have 1 command here right now... + +import discord +from discord.ext import commands + + +class DM(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.command() + @commands.dm_only() # This decorator will raise commands.PrivateMessageOnly if invoked in a guild context. + async def avatar(self, ctx: commands.Context): + embed = discord.Embed( + title="Avatar", + description=f"Here's your enlarged avatar, {ctx.author.name}!", + color=ctx.author.top_role.color + ) + embed.set_image(url=ctx.author.display_avatar.url) + await ctx.send(embed=embed, reference=ctx.message) + + async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): + if isinstance(error, commands.PrivateMessageOnly): + await ctx.send("Sorry, you can only use this in private messages!", reference=ctx.message) + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +def setup(bot: commands.Bot): + bot.add_cog(DM(bot)) +``` + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +# This is the main file where we load the DM cog and run the bot. + +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix=commands.when_mentioned_or("!")) +bot.load_extension("cogs.dm") +bot.run("TOKEN") +``` + +If you use this command in a DM context, you'll get the following: + + + + !avatar + + +
+ + !avatar + +
+ + Here's your enlarged avatar, BobDotCom! + +
+
+
+ +Otherwise, if used in a guild context: + + + + !avatar + + +
+ + !avatar + +
+ Sorry, you can only use this in private messages! +
+
+
+ +Per-cog error handling comes in very handy as you can relegate all of your error handling to a single function instead +of spreading it out across several per-command error handlers or inside the commands themselves. + +## Global Handling + +If separating your error handling is not how you would like to handle errors, then global error handling is the way to +go. This method of handling allows you to relegate all handling to a single function that resides within your bot +instance. + +A non-subclassed bot would implement this like so: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot() + + +@bot.slash_command(description="Get the bot's current latency!") +@commands.cooldown(1, 30, commands.BucketType.user) +# ^ This decorator allows one usage of the command every 30 seconds and raises commands.CommandOnCooldown if exceeded +async def ping(ctx: discord.ApplicationContext): + await ctx.respond(f"Pong! `{int(bot.latency*1000)} ms`.") + + +@bot.event +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.CommandOnCooldown): + await ctx.respond("This command is currently on cooldown!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If you've subclassed your bot, the `on_application_command_error` event will be placed inside the subclass without a +`bot.event` decorator and `bot.slash_command` will be replaced with `discord.slash_command`. + +The error handling used above will yield this interaction if the command is used again too quickly: + + + +
+ + ping + +
+ Pong! 49 ms. +
+ +
+ + ping + +
+ This command is currently on cooldown! +
+
+
+ +The only issue regarding global error handling is that, if you have a large amount of commands, the global handler may +start to get crammed with a lot of code. This is where all the previously mentioned handlers can take their place! + +## FAQ + +#### Why does the example in per-cog handling have self at the start of its function signatures? + +This is a feature of classes and allows you to reference the cog object as `self` and get access to the bot object +passed at initialization through `self.bot`. + +If this is new to you, we recommend checking out these helpful resources to learn more about classes and cogs: + +- [W3Schools' Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [Our Cogs Guide Page](./cogs) + +#### How many errors can I handle in a single error handler? + +While all the examples in this guide page only handle one specific error and re-raise all others, all of these +error handlers can be extended to catch many errors. + +In [basic handling](#basic) (i.e. try/except statements) you can do one of two things: + +- Explicitly handle the errors you know might get raised and then have a broad `except Exception as exc:` statement + as a catch-all. +- Catch any and all errors via the catch-all statement mentioned above. + +In [per-command](#percommand), [per-cog](#percog), and [global handling](#global), you can use elif clauses with the +built-in isinstance function to catch specific errors. Atop of this, an else clause can be used to catch any other +errors you either don't want to handle or want to relegate to a different error handler. + +#### Can I use more than one type of error handler at once? + +Thankfully, all of these different ways of error handling can be mixed together, so you don't have to pick just one! +For commands that raise specific errors that no other commands will raise, you can use [per-command](#percommand). +For cogs that raise specific errors that no other cogs will raise, use [per-cog](#percog)! Lastly, for errors that +occur frequently across all commands and cogs, use [global handling](#global)! + +However, one important note to remember is that you should always raise the error again in an error handler if it +isn't handled there! If you don't do this, the error will go ignored and your other handlers won't have a chance to +do their work! + +#### What's the difference between slash and prefixed command error handling? + +Although most examples shown here use slash commands, the [per-cog handling](#percog) section presents a prefixed +command. The main difference you may notice is the change in command signature. + +To make the distinguishing features apparent: + +- Slash commands use `on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException)` + as presented in the [per-command](#percommand) and [global handling](#global) examples. +- Prefixed commands use `on_command_error(ctx: commands.Context, error: commands.CommandError)` as presented in the + [per-cog handling](#percog) example. + +This distinction is made as both types of commands need their own system for handling errors that are specific to +themselves. + +:::info Related Topics + +- [Slash Commands](../interactions/application-commands/slash-commands) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Cogs](./cogs) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx new file mode 100644 index 00000000..9f4210af --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx @@ -0,0 +1,62 @@ +--- +title: Intents +description: All about intents in Discord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +## What are Intents? + +Intents allow bot developers to "subscribe" to specific events in Discord. This is useful for bots that need to respond to specific events, such as when a user joins a server or sends a message. You could choose to enable all intents or to enable only specific intents that your bot requires. + +## How do I enable intents? + +:::important + +Remember that [Privileged Intents](#what-are-privileged-intents) require you to enable them in the Discord Developer Portal. Verified Discord Bots that don't already have access to them will need to request Discord to allow access. + +::: + + + + +```python +import discord + +bot = discord.Bot(intents=discord.Intents.all()) +``` + + + + + +You can view a list of intents and the events they subscribe to [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```python title="Enabling Intents" +import discord + +bot = discord.Bot(intents=discord.intents.members(bans=True, guilds=True)) +``` + + + + +## What are Privileged Intents? + +Discord defines some intents as "privileged" because of the sensitive information they contain. Currently, there are three privileged intents: `members`, `presences`, and `message_content`. These intents must be enabled in your bot's Developer Portal. Once your bot reaches 100 servers, you will need to verify your bot for these intents to keep working and for your bot to be able to be invited to more guilds. + +:::tip + +Only enable these intents if you need them. These intents give your bot access to quite sensitive information about the users in your guild. These intents are privileged to respect the privacy of users, and you should do that as well. + +Not enabling these intents doesn't mean you won't be able to ban users, but you will be unable to detect when a new user joins a guild, or what game they are playing. The majority of bots won't need all intents. + +::: + +:::info Related Topics + +- [Sharding Bots](sharding) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx new file mode 100644 index 00000000..c3d17197 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx @@ -0,0 +1,48 @@ +--- +title: Sharding +description: All about Sharding Discord Bots. +--- + +# Sharding + +## What is Sharding? + +Sharding is the process of breaking up your bot into smaller pieces so that it has a better time handling +events. As [Discord's Documentation](https://discord.com/developers/docs/topics/gateway#sharding) puts +it, sharding is "a method of user-controlled guild sharding which allows for splitting events across +several gateway connections." + +Sharding is used only for large bots and takes up additional resources for managing the new processes. +Pycord automatically shards your bot, so the only thing you need to do is use an `AutoShardedClient` +or `AutoShardedBot` class instead of a plain `Client` or `Bot` class. Pretty cool, right? + +Just because you _can_ shard your bot doesn't mean you _should_. While Pycord makes it easy to shard +your bot, it isn't necessary to shard unless your bot is large. Sharding a small bot isn't +just useless, but _harmful_, as it uses extra resources and may slow down your bot. Discord +themselves will let you know when your bot needs sharding, so you won't need to worry about this until they contact you. + +## How Do I Shard in Pycord? + +Sharding in Pycord is straightforward. + +Just replace your `discord.Client`, `discord.Bot`, `commands.Bot` objects +with `discord.AutoShardedClient`, `discord.AutoShardedBot`, `commands.AutoShardedBot` respectively. + +These new objects have been inherited from the original objects, so all the functions from those other types should be present. + +If you want to specify the number of shards your bot uses, +just add the `shards` parameter, along with the number of shards you want. + +## Why Should I Shard my Bot? + +Sharding is very necessary for big bots. While your bot grows, it gets harder for your bot to control +how many guilds it is in and what parts of your code should do what. This is exactly what sharding +handles, it makes all of this easier for your bot. Remember, though, only shard your bot once it's +big enough, and that's at _least_ 1,000 guilds. + +:::info Related Topics + +- [Hosting your Bot](../Getting-Started/hosting-your-bot) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx new file mode 100644 index 00000000..bd2969c1 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx @@ -0,0 +1,115 @@ +--- +title: Subclassing Bots +description: Subclassing is a popular way of creating Discord Bots. Explore how you can create a Discord bot by subclassing. +--- + +## About + +Subclassing is another popular way of creating Discord Bots. Here, you create a bot by extending a bot class. To some advanced users, this is preferable to creating a bot instance with `bot = discord.Bot()`. + +Subclassing is an intermediate python concept, so we recommend you learn about it before continuing. Some good resources are: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +## Why Subclassing? + +Many developers prefer to subclass their bots for many reasons, some of them being: + +#### Skeletal Frameworks for Bots + +Developers often share their bots code on open-source platforms, mostly GitHub, and allow users to self-host the bot (running their own instance of the bot with the code provided by the developer. Permissions vary in accordance to licences). Here, users find it easier and more convenient to have a small file that imports the custom bot class and runs it, rather than having to go through the code of the bot and find out which file to run. This makes it easier for people not familiar with programming to run and customize the bot, since it often brings down the code to: + +```python title="./main.py" +from src import Bot + +bot = Bot() + +bot.run("TOKEN") +``` + +Here, all the commands are inside the `/src` folder that the user need not bother with. + +#### Running Multiple Instances + +Some developers may need to run multiple instances of their bot (perhaps on different bot accounts). For example, a developer might have a second bot for testing alpha features. This system makes it simpler for the developer, and allows them to maintain multiple versions of the bot in the same directory: + +```python title="./alpha_bot.py" +from src import Bot + +class AlphaBot(Bot): # subclasses Bot + ... # insert any custom configuration + +bot = AlphaBot() + +@bot.slash_command() # adds a new slash command to this subclassed bot +async def alpha_feature(ctx): + await ctx.respond("Alpha Feature!") + +bot.run("TOKEN") +``` + +There are many more reasons to subclass! It's not required, and won't affect the speed of the bot, but it may affect your development process, for the good or for the worse. You don't miss out on any features when you subclass, either. Some developers want the OOP feel, while some just prefer that method and find it easier. + +## Basic Example + +```python +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override the on_ready event + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') + +bot = MyBot() + +@bot.slash_command() # create a slash command +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run('token') +``` + +As you can see, instead of creating a bot object with `bot = discord.Bot()`, we subclass [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). We then create an instance of our new bot class and run it. Notice how we don't need to use the `@event` decorator. + +Here's another example: + +```python title="./src/bot.py" +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override on_ready + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') +``` + +```python title="./src/\_\_init\_\_.py" +from .bot import MyBot # import the MyBot class from the bot.py file +``` + +```python title="./main.py" +from src import MyBot # import MyBot from /src + +bot = MyBot() # create an instance of MyBot + +@bot.slash_command() +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run("TOKEN") # run the bot +``` + +These are just two ways you could do it. There are ton of other structures you can implement. It's up to you. + +So, should you subclass? There are no limitations you face if you decide to subclass your bot, but, once again, it's up to you. + +:::info Related Topics + +- [Making a Help Command](../Extensions/Commands/help-command) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx new file mode 100644 index 00000000..23220b0e --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx @@ -0,0 +1,105 @@ +--- +title: Threads +description: Threads with Pycord +--- + +In programming, threads are a way to run multiple processes at the same time. In Discord, threads are +a way to keep multiple conversations going at the same time. Let's take a brief look at how to use threads in Pycord. + +:::tip + +Not all the methods and attributes will be covered in this guide, but you can find them in our documentation! +[Check it out!](https://docs.pycord.dev/en/stable/api/models.html#discord.Thread) + +::: + +## Creating a thread + +With a few simple lines of code, we can create threads in Pycord. + +:::important + +All public threads need a starting message. This message will start the thread. However, private threads +(which are unlocked with having your server boosted to Level 2), do not require a starting message. + +::: + +### Creating thread from a message + +```python title="Creating a Thread from a Message" +message = await ctx.send("My Starting Message") +await message.create_thread(name="thread name", auto_archive_duration=60) +``` + +You may also use other ways to create the thread, for example, by using `on_message` events or by commands. + +### Creating thread in a channel + +```python title="Creating a Thread from a Channel" +channel = bot.get_channel(...) # define this! +await channel.create_thread(name="Thread Name", message=None, auto_archive_duration=60, type=None, reason=None) +``` + +A thread type could be `news_thread`, `public_thread`, `private_thread`. You may use it by passing `type=discord.ChannelType.news_thread`. + +## Deleting Threads + +Deleting Threads is simple. You need to get a thread and then use the `delete` method. + +```python title="Deleting a Thread" +thread = bot.get_channel(thread_id) # you could use other ways to get a thread +await thread.delete() +``` + +## Editing Threads + +**Parameters** + +- `name` (str) – The new name of the thread + +- `archived` (bool) – Whether to archive the thread or not. + +- `locked` (bool) – Whether to lock the thread or not. + +- `invitable` (bool) – Whether non-moderators can add other non-moderators to this thread. Only available for private threads. + +- `auto_archive_duration` (int) – The new duration in minutes before a thread gets automatically archived for inactivity. Must be one of 60, 1440, 4320, or 10080. + +- `slowmode_delay` (int) – Specifies the slow-mode rate limit for users in the thread, in seconds. A value of 0 disables slow-mode. The maximum value possible is 21600. + +```python title="Editing a Thread" +thread = bot.get_channel(id) +await thread.edit( + name="New Name", + archived=True, + locked=True, + slowmode_delay=10, + auto_archive_duration=60, +) +``` + +As you can see, threads are very simple. Once you learn how to use them, it's easy to create whatever you want. + +## FAQ + +### Why am I getting a `Forbidden` error when I try to create a thread? + +A `Forbidden` error occurs when the bot does not have the correct permissions to create threads. + +### Why am I getting an Unknown Message error when I try to create a thread? + +Getting an error looking something like `discord.ext.commands.errors.CommandInvokeError: Command +raised an exception: HTTPException: 400 Bad Request (error code: 10008): Unknown Message`? + +There could be multiple reasons, some of them being: + +- The message does not exist +- The message already has a thread +- The message is in channel x, you are trying to start a thread in channel y. +- The message was deleted. + +:::info Related Topics + +<>{/* I can't think of any related topics for this at the moment. */} + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/voice/_category_.json b/i18n/ko/docusaurus-plugin-content-docs/current/voice/_category_.json new file mode 100644 index 00000000..8baf3da8 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/voice/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 6, + "label": "Voice" +} \ No newline at end of file diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/voice/index.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/voice/index.mdx new file mode 100644 index 00000000..835838c6 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/voice/index.mdx @@ -0,0 +1,24 @@ +--- +title: Voice +--- + +Welcome to the guide for voice features in Pycord. + +:::caution +This guide requires previous experience with Pycord and Python. +::: + +## Requirements + +The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). +The following features are optional: + +:::tip +Opus is also a required library, but this comes with Pycord. +Some hosts may not come with it, though, so remember to always check if required dependencies are installed. +::: + +- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` +- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), + [`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), + [`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/voice/playing.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/voice/playing.mdx new file mode 100644 index 00000000..fe14c52a --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/voice/playing.mdx @@ -0,0 +1,149 @@ +--- +title: Wavelink Audio Player +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { + defaultOptions, +} from "@site/src/components/DiscordComponent"; + +# About + +Pycord and Wavelink try to keep the playing of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio playing feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/). + +## Starting out + +First you need to run a [Lavalink Server](https://github.com/freyacodes/Lavalink) to connect with. +There a multiple documentations to do this, so we are not covering that here. + +You also need to install the [wavelink](https://github.com/PythonistaGuild/Wavelink) library. + +```py title="Installing wavelink" +python3 -m pip install wavelink +``` + +You will now want to connect to your server via a node. + +```py title="Connect Node with Lavalink" +import discord +import wavelink + +bot = discord.Bot() + +async def connect_nodes(): + """Connect to our Lavalink nodes.""" + await bot.wait_until_ready() # wait until the bot is ready + + nodes = [ + wavelink.Node( + identifier="Node1", # This identifier must be unique for all the nodes you are going to use + uri="http://0.0.0.0:443", # Protocol (http/s) is required, port must be 443 as it is the one lavalink uses + password="youshallnotpass" + ) + ] + + await wavelink.Pool.connect(nodes=nodes, client=bot) # Connect our nodes +``` + +
+ +Now you are finished making your node! Next, you will want to: + +1. Making a play command +2. Adding connect events + +### Making a play command + +To make a play command, you will need to make a function to connect and play audio in a voice channel. + +```py title="Play Command Example" +import typing + +@bot.slash_command(name="play") +async def play(ctx, search: str): + # First we may define our voice client, + # for this, we are going to use typing.cast() + # function just for the type checker know that + # `ctx.voice_client` is going to be from type + # `wavelink.Player` + vc = typing.cast(wavelink.Player, ctx.voice_client) + + if not vc: # We firstly check if there is a voice client + vc = await ctx.author.voice.channel.connect(cls=wavelink.Player) # If there isn't, we connect it to the channel + + # Now we are going to check if the invoker of the command + # is in the same voice channel than the voice client, when defined. + # If not, we return an error message. + if ctx.author.voice.channel.id != vc.channel.id: + return await ctx.respond("You must be in the same voice channel as the bot.") + + # Now we search for the song. You can optionally + # pass the "source" keyword, of type "wavelink.TrackSource" + song = await wavelink.Playable.search(search) + + if not song: # In case the song is not found + return await ctx.respond("No song found.") # we return an error message + + await vc.play(song) # Else, we play it + await ctx.respond(f"Now playing: `{song.title}`") # and return a success message +``` + + + +
+ + play + +
+ Now playing: Never Gonna Give You Up +
+
+ +
+ +Now that you've done this, the only thing left to do is make your connect events. + +### Adding connect events + +The final step to this guide is connecting the node to your server when the bot goes online. + +To make it, you will want to do the following: + +```py title="Adding connect events" +@bot.event +async def on_ready(): + await connect_nodes() # connect to the server + +@bot.event +async def on_wavelink_node_ready(payload: wavelink.NodeReadyEventPayload): + # Everytime a node is successfully connected, we + # will print a message letting it know. + print(f"Node with ID {payload.session_id} has connected") + print(f"Resumed session: {payload.resumed}") + +bot.run("token") +``` + +Congratulations! You have now implemented voice playing into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/voice/receiving.mdx b/i18n/ko/docusaurus-plugin-content-docs/current/voice/receiving.mdx new file mode 100644 index 00000000..1bc364e1 --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-docs/current/voice/receiving.mdx @@ -0,0 +1,130 @@ +--- +title: Receiving Voice Samples +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +# About + +Pycord tries to keep the recording of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio recording feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/audio_recording.py). + +## Starting out + +The first thing you want to do is make a cache of your voice connections. This is fairly easy; as +it's just putting a variable with an empty dictionary in our code, such as `connections = {}`. + +You will now want to create your command for recording. + +```py title="Record Command Example" +import discord + +bot = discord.Bot() +connections = {} + +@bot.command() +async def record(ctx): # If you're using commands.Bot, this will also work. + voice = ctx.author.voice + + if not voice: + await ctx.respond("You aren't in a voice channel!") + + vc = await voice.channel.connect() # Connect to the voice channel the author is in. + connections.update({ctx.guild.id: vc}) # Updating the cache with the guild and channel. + + vc.start_recording( + discord.sinks.WaveSink(), # The sink type to use. + once_done, # What to do once done. + ctx.channel # The channel to disconnect from. + ) + await ctx.respond("Started recording!") +``` + + + +
+ + record + +
+ Started recording! +
+
+ +
+ +Now you are finished making your command for voice receiving! Next, you will want to: + +1. Make your finished callback +2. Make a stop command + +### Making a Callback + +To make a callback, you will want to define the currently undefined `once_done` function inside +our command, like so: + +```py title="Recorder Callback" +async def once_done(sink: discord.sinks, channel: discord.TextChannel, *args): # Our voice client already passes these in. + recorded_users = [ # A list of recorded users + f"<@{user_id}>" + for user_id, audio in sink.audio_data.items() + ] + await sink.vc.disconnect() # Disconnect from the voice channel. + files = [discord.File(audio.file, f"{user_id}.{sink.encoding}") for user_id, audio in sink.audio_data.items()] # List down the files. + await channel.send(f"finished recording audio for: {', '.join(recorded_users)}.", files=files) # Send a message with the accumulated files. +``` + + + + finished recording audio for:{" "} + {defaultOptions.profiles.bob.author} + + + +
+ +Now that you've done this, the only thing left to do is make your stop command. + +### Making a Stop Command + +The final step to this guide is stopping the audio recording. This is the easiest step by far. + +To make it, you will want to do the following: + +```py title="Stop Recording Command" +@bot.command() +async def stop_recording(ctx): + if ctx.guild.id in connections: # Check if the guild is in the cache. + vc = connections[ctx.guild.id] + vc.stop_recording() # Stop recording, and call the callback (once_done). + del connections[ctx.guild.id] # Remove the guild from the cache. + await ctx.delete() # And delete. + else: + await ctx.respond("I am currently not recording here.") # Respond with this if we aren't recording. + +bot.run("token") +``` + +Congratulations! You have now implemented voice recording into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/ko/docusaurus-plugin-content-pagesindex.tsx b/i18n/ko/docusaurus-plugin-content-pagesindex.tsx new file mode 100644 index 00000000..84df3a9c --- /dev/null +++ b/i18n/ko/docusaurus-plugin-content-pagesindex.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import DefaultLayout from "../layouts/DefaultLayout"; +import PYCHero from "@site/src/components/PYCHero"; +import PYCButton from "@site/src/components/PYCButton"; + +export default function Home(): JSX.Element { + return ( + + +
+ Imagine a place where you can learn how to create an awesome Discord + bot, equip it with Pycord, and have it running in less than a minute. + Imagine a place where you can learn everything about Pycord. Imagine a + guide. A Pycord Guide! +

+ Whether you are a newbie or an experienced developer, you will find + everything you need to know about Pycord here. This guide will teach + you: +
    +
  • How to get a brand new bot running from scratch;
  • +
  • How to create Interactions, Context Menus and Commands;
  • +
  • In-depth concepts such as Embeds, Reactions, Help Commands, Paginators, etc;
  • +
  • Popular Topics such as working with Databases, Sharding, etc;
  • +
  • Ways to handle and manage common errors and best practices for bots;
  • +
  • And Much More!
  • +
+
+
+ ); +} diff --git a/i18n/ko/docusaurus-theme-classic/footer.json b/i18n/ko/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..ffb8a652 --- /dev/null +++ b/i18n/ko/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Pycord Development, All rights reserved.", + "description": "The footer copyright" + } +} diff --git a/i18n/ko/docusaurus-theme-classic/navbar.json b/i18n/ko/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..473b847e --- /dev/null +++ b/i18n/ko/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "Pycord Guide", + "description": "The title in the navbar" + }, + "item.label.Home": { + "message": "Home", + "description": "Navbar item with label Home" + }, + "item.label.Docs": { + "message": "Docs", + "description": "Navbar item with label Docs" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + }, + "item.label.Source": { + "message": "Source", + "description": "Navbar item with label Source" + } +} diff --git a/i18n/pt/code.json b/i18n/pt/code.json new file mode 100644 index 00000000..9cce6148 --- /dev/null +++ b/i18n/pt/code.json @@ -0,0 +1,404 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { + "message": "Toggle the collapsible sidebar category '{label}'", + "description": "The ARIA label to toggle the collapsible sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search here", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.algoliaLabel": { + "message": "Search by Algolia", + "description": "The ARIA label for Algolia mention" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorite", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "You might want to check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Algolia" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Try searching for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Believe this query should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/i18n/pt/docusaurus-plugin-content-blog/options.json b/i18n/pt/docusaurus-plugin-content-blog/options.json new file mode 100644 index 00000000..9239ff70 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/pt/docusaurus-plugin-content-docs/current.json b/i18n/pt/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..36b4849a --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,46 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.defaultSidebar.category.Getting Started": { + "message": "Getting Started", + "description": "The label for category Getting Started in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Interactions": { + "message": "Interactions", + "description": "The label for category Interactions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Application Commands": { + "message": "Application Commands", + "description": "The label for category Application Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.UI Components": { + "message": "UI Components", + "description": "The label for category UI Components in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Extensions": { + "message": "Extensions", + "description": "The label for category Extensions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Commands": { + "message": "Commands", + "description": "The label for category Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Pages": { + "message": "Pages", + "description": "The label for category Pages in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Voice": { + "message": "Voice", + "description": "The label for category Voice in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Popular Topics": { + "message": "Popular Topics", + "description": "The label for category Popular Topics in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.More": { + "message": "More", + "description": "The label for category More in sidebar defaultSidebar" + } +} diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png b/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png new file mode 100644 index 00000000..7480e1da Binary files /dev/null and b/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png differ diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg b/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg new file mode 100644 index 00000000..ce6b5110 Binary files /dev/null and b/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg differ diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png b/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png new file mode 100644 index 00000000..846eee15 Binary files /dev/null and b/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png differ diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png b/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png new file mode 100644 index 00000000..32a47d04 Binary files /dev/null and b/i18n/pt/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png differ diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/_category_.json new file mode 100644 index 00000000..309b494a --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 5, + "label": "Extensions", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json new file mode 100644 index 00000000..652aa4ee --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Bridge" +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx new file mode 100644 index 00000000..81545fa2 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx @@ -0,0 +1,190 @@ +--- +title: Bridge +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +## Concept + +Let's say that you want to make a command that is both a Slash Command and a Prefixed Command. Now, you could just copy and paste the code from the first command callback to the other and make some adjustments, but that's not very efficient. + +This is where the `ext.bridge` module comes in. It allows you to use one callback to make both a Slash Command and a Prefixed Command. + +### Example Usage + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def hello(ctx): + await ctx.respond("Hello!") + +bot.run("TOKEN") +``` + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+
+ +## Syntax + +First, instead of using `discord.Bot` or `commands.Bot`, we use `bridge.Bot`. `bridge.Bot` does inherit from `commands.Bot`, so you can do anything with `bridge.Bot` that `commands.Bot` can do. +Then, we define a command with `@bot.bridge_command()`. This makes a Bridge Command, which has both a Prefixed Command counterpart and a Slash Command counterpart. +Next, the callback has access to a `ctx` object, which is the context of the command. This context is either of `BridgeApplicationContext` type or `BridgeExtContext`. Because of that, it makes detecting how the function was called easier. + +### Using Bridge Commands in a Cog + +Like Slash Commands and Prefixed Commands, you can use Bridge Commands in a Cog. You can do this by using the `bridge_command` decorator. Here's an example: + +```python +import discord +from discord.ext import bridge, commands + +class Greetings(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @bridge.bridge_command() + async def hello(self, ctx): + await ctx.respond("Hello!") + + @bridge.bridge_command() + async def bye(self, ctx): + await ctx.respond("Bye!") + +def setup(bot): + bot.add_cog(Greetings(bot)) +``` + +The cog will automatically split the Bridge Command into their Slash Command and Prefixed Command counterparts. + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+ + +
+ + bye + +
+ Bye! +
+ + + !bye + + + +
+ + !bye + +
+ Bye! +
+
+ +### Deferring + +You can defer if you want to communicate to the user that your bot is busy processing the command. This is done by using `ctx.defer()`. For the Slash Command implementation, `ctx.defer()` calls the function that gives out a "Bot is thinking" message. For the Prefixed Command implementation, `ctx.defer()` enables the typing indicator. + + + +### Options + +Options are pretty straightforward. You just specify them like you do with prefixed commands, and you're all set! + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def sum(ctx, a: int, b: int): + await ctx.respond(a + b) + +bot.run("TOKEN") +``` + + + +
+ + sum + +
+ 4 +
+ + + !sum 2 2 + + + +
+ + !sum 2 2 + +
+ 4 +
+
diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json new file mode 100644 index 00000000..63f8e08e --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx new file mode 100644 index 00000000..bf345c07 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx @@ -0,0 +1,56 @@ +--- +title: Command Groups +--- + +Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk +remove`. + +## Syntax + +Creating a command group is very simple. + +```python title="Command Groups Example" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!') + +@bot.group() +async def afk(): + pass + +@afk.command() +async def set(): + ... + +@afk.command() +async def remove(): + ... + +# Another command group + +@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. +async def math(ctx): + await ctx.send('Subcommand not found') + +@math.command() +async def add(ctx, a: int, b: int): + ... + +@math.command() +async def subtract(ctx, a: int, b: int): + ... +``` + +To create a command group, the command's decorator must be `@bot.group`. Once you have a command with +that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand +groups! + + + +:::info Related Topics + +- [Prefixed Commands](./prefixed-commands.mdx) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx new file mode 100644 index 00000000..acbdc0a8 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx @@ -0,0 +1,481 @@ +--- +title: Help Command +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Pycord's `commands` extension comes with a built-in help command. In this guide, we will take a look at them as well as learn how to create your own. Let's dive in! + +:::note + +This guide demonstrates using object-oriented programming and subclassing to make a help command for your +Pycord bot. It is important to understand these two concepts before continuing. + +**Learning Resources**: + +- [W3Schools - Python Subclassing](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools - Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +::: + +## The Wrong Way + +A popular way to create a help command is to disable the built-in help command and create your own. This is not recommended as it will lead to a lot of confusion. + +```python title="The Wrong Way" +bot = commands.Bot(command_prefix='!', help_command=None) +# OR +bot.help_command = None +# OR +bot.remove_command("help") + +@bot.command() +async def help(ctx, *, argument=None): + ... +``` + +While it's possible to create a help command this way, doing so does not utilize the full capabilities +of making one with Pycord. Making a help command with subclassing and OOP will save time and effort. + +## Types of Help Commands + +There are two types of built-in help commands: + +- [`DefaultHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand) +- [`MinimalHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand) + +`DefaultHelpCommand` is the command enabled by default. It isn't the best looking, but `MinimalHelpCommand` can help make it look a bit better. + + + + +```python title="Default Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.DefaultHelpCommand()) # help_command is DefaultHelpCommand by default so it isn't necessary to enable it like this +# We enable it here for the sake of understanding + +... + +bot.run("token") +``` + + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ + +```python title="Minimal Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.MinimalHelpCommand()) + +... + +bot.run("token") +``` + + + + !help + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+ +
+ +
+ +## Updating Built-in Help Commands + +Let's try to make the `MinimalHelpCommand` look better. We can do this by putting its content in an +embed. + +```python title="Minimal Help Command Example" +bot = commands.Bot(command_prefix='!') + + +class MyNewHelp(commands.MinimalHelpCommand): + async def send_pages(self): + destination = self.get_destination() + for page in self.paginator.pages: + emby = discord.Embed(description=page) + await destination.send(embed=emby) + +bot.help_command = MyNewHelp() +``` + +Let's go through the code. + +First, we create a new class called `MyNewHelp`. This class is a subclass of `MinimalHelpCommand`. + +Next, we override the `send_pages` method. This method is responsible for sending the help command to +the user. We override this method because we don't want to change the content of the pages, just how +they are sent. + +We use the `get_destination` method to get the destination of the message. This is the channel or use that the help +command is to be sent to. + +We use the `paginator.pages` property to get the different pages of the help command. We put the page +in an embed, and then send the embed to the destination channel. + +Finally, we set this as our new help command using `bot.help_command = MyNewHelp()`. + + + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a + category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+
+ +## Creating Your Help Command + +Not satisfied with the built-in help commands? You can create your own! + +For this, we will subclass the `HelpCommand` class. + +There are 4 methods that we need to override: + +- `HelpCommand.send_bot_help(mapping)` that gets called with `help` +- `HelpCommand.send_command_help(command)` that gets called with `help ` +- `HelpCommand.send_group_help(group)` that gets called with `help ` +- `HelpCommand.send_cog_help(cog)` that gets called with `help ` + +### Bot Help + +```python title="Bot Help Example" +class MyHelp(commands.HelpCommand): + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help") + for cog, commands in mapping.items(): + command_signatures = [self.get_command_signature(c) for c in commands] + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's go through the code. + +- First, we create a new class called `MyHelp`. This class is a subclass of `HelpCommand`. + +- Next, we override the `send_bot_help` method. This method is responsible for sending the main help + command to the user. + +- We create an embed with the title "Help". + +- We iterate through `mapping.items()`, which returns a list of tuples, the first element being the + cog and the second element being a list of commands. + +- By using `self.get_command_signature(c)` we get the signature of the command, also known as the + `parameters` or `arguments`. + +- There is a chance that the cog is empty, so we use `if command_signatures:`. + +- We get the name of the cog using `getattr(cog, "qualified_name", "No Category")`. This calls the + cog's attribute `qualified_name` which returns "No Category" if the cog has no name. + +- We add a field to the embed with the name of the cog and the value of the command signatures. + +- Finally, we send the embed to the channel. + +Let's improve the code a little. + +```python title="Improved Bot Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + command_signatures = [self.get_command_signature(c) for c in filtered] + + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Now the help command won't show commands that the user can't use, as well as aliases for commands. +Let's get the help command to show command aliases. + +### Command Help + +This function is called when the user uses `help `. + +```python title="Command Help Example" +class MyHelp(commands.HelpCommand): + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command), color=discord.Color.random()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's quickly go through the code we haven't discussed yet. + +- In line 3, we create an embed with a title the signature of the command (so that the title of the + embed looks like ` [parameter]`), and a random color. + +- In lines 4 and 5, we get the command's `help` description and add it to the embed. The help description + of a command can be specified in the docstrings of a command function. For example: + + ```` + ```python + @bot.command() + async def ping(ctx): + """Returns the latency of the bot.""" + await ctx.send(f"Pong! {round(bot.latency * 1000)}ms") + ``` + ```` + +- Line 6 is shorthand for + + ```python + alias = command.aliases + if alias: + ... + + # is the same as + + if alias := command.aliases: + ... + ``` + + A very helpful (but not well-known) Python shorthand! + +- In line 7, we get the aliases of the command and add them to the embed. + +### Cog Help + +This is pretty easy! + +```python title="Custom Cog Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_cog_help(self, cog): + embed = discord.Embed(title=cog.qualified_name or "No Category", description=cog.description, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(cog.get_commands()): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Once again, we create an embed, get the commands that the user can use, and add them to the embed. + +### Group Help + +Similar to the cog help, this is pretty easy! + +```python title = "Custom Group Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_group_help(self, group): + embed = discord.Embed(title=self.get_command_signature(group), description=group.help, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(group.commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Add all of these methods together, and you have a fully functioning help command! + +
+Click to see the final code for this section +
+ +:::note + +The following code has been slightly edited from the tutorial version. + +::: + +```python title="Custom Help Command Example" +class SupremeHelpCommand(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + if command_signatures := [ + self.get_command_signature(c) for c in filtered + ]: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command) , color=discord.Color.blurple()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_help_embed(self, title, description, commands): # a helper function to add commands to an embed + embed = discord.Embed(title=title, description=description or "No help found...") + + if filtered_commands := await self.filter_commands(commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No help found...") + + await self.get_destination().send(embed=embed) + + async def send_group_help(self, group): + title = self.get_command_signature(group) + await self.send_help_embed(title, group.help, group.commands) + + async def send_cog_help(self, cog): + title = cog.qualified_name or "No" + await self.send_help_embed(f'{title} Category', cog.description, cog.get_commands()) + +bot.help_command = SupremeHelpCommand() +``` + +
+
+ +## Command Attributes + +How can you add cooldowns, set aliases, and change the name of help commands? Command attributes can +help you do all of that, and more! + +```python title="Help Command Attributes" +attributes = { + 'name': "help", + 'aliases': ["helpme"], + 'cooldown': commands.CooldownMapping.from_cooldown(3, 5, commands.BucketType.user), +} + +# You need to use CooldownMapping.from_cooldown(rate, per, type) + +bot.help_command = MyHelp(command_attrs=attributes) +``` + +## Error Handling + +When a user attempts to use a command that does not exist, we need to inform the user. +We can do this by overriding the `send_error_message` function. + +```python title="Custom Help Error Example" +class MyHelp(commands.HelpCommand): + async def send_error_message(self, error): + embed = discord.Embed(title="Error", description=error, color=discord.Color.red()) + channel = self.get_destination() + + await channel.send(embed=embed) +``` + + + + !help update_pycord + + + + Command 'update_pycord' not found. + + + + +## Credits + +Most of the content from this guide is from +[InterStella0's walkthrough guide on subclassing HelpCommand](https://gist.github.com/InterStella0/b78488fb28cadf279dfd3164b9f0cf96). +Thanks to InterStella0 for making this guide amazing. + +:::info Related Topics + +- [Subclassing Bots](../../Popular-Topics/subclassing-bots) +- [Prefixed Commands](./prefixed-commands) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx new file mode 100644 index 00000000..b8f567fd --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx @@ -0,0 +1,324 @@ +--- +title: Prefixed Commands +description: Learn how to use the commands extension for Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Before Discord added slash commands, all bots had prefixed commands. A user would type the bot's prefix +followed by a word or phrase to invoke a command, such as `?help` or `!help`. +However, this prefixed commands system isn't native to Discord! Developers made use of an `on_message` +event to check if the message began with a certain character, then invoke the command. Every time a +message was sent, the bot would see the message and check for its "prefix" + +The syntax becomes a little more complicated when you want to have multiple commands. There are several +disadvantages to this system. This is where the commands extension comes in. `ext.commands` has +various advantages, such as: + +- Simpler syntax +- Easier to use +- Easier to parse user input +- Comes with built-in help commands +- Comes with a built-in system for categorizing commands + + + + +```python title="Prefixed Commands with Events" +import discord + +client = discord.Client() + +@client.event +async def on_message(message): + if message.content.startswith("!ping"): + await message.channel.send("Pong!") + + elif message.content.startswith("!announce"): + if len(message.content.split(" ")) < 3: + await message.channel.send("You need to specify a title and a message. Correct usage: `!announce Hello Hello everyone!`") + return + + msg = message.content.split(" ", 2) + title = msg[1] + content = msg[2] + + await message.channel.send("**{}**\n{}".format(title, content)) + + elif message.content.startswith("!"): + await message.channel.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !help + + + Unknown Command. + +
+ +
+ + +```python title="The Commands Extension" +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix="!", intents=intents) + +@bot.command() +async def ping(ctx): + await ctx.send("Pong!") + +@bot.command() +async def announce(ctx, title, *, message): + await ctx.send("**{}**\n{}".format(title, message)) + +@bot.event +async def on_command_error(ctx, error): + if isinstance(error, commands.CommandNotFound): + await ctx.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !pycord + + + Unknown command. + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+ !announce +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The commands extension has many more uses. This example only showcases the basic features mentioned +in the previous example. Other things you can do with the commands extension include using a different +built-in help command and creating your own. The following tutorials showcase these. + +::: + +
+
+ +## Syntax + +Before we check out the syntax, let's take a look at the bot classes. + +> `discord.Client` - Contains only events. +> +> `discord.Bot` - Subclasses `discord.Client`, adds commands. +> +> `discord.ext.commands.Bot` - Subclasses `discord.Bot`, adds prefixed commands, cogs, and more. + +This means that `discord.ext.commands.Bot` has both slash commands and prefixed commands, as well as +events, cogs and more. + +Now let's look at the syntax. + +```python title="A Simple Prefixed Bot" +import discord +from discord.ext import commands # Import the commands extension +# discord.ext.commands are not the same as discord.commands! + +intents = discord.Intents.default() #Defining intents +intents.message_content = True # Adding the message_content intent so that the bot can read user messages + +bot = commands.Bot(command_prefix="!", intents=intents) # You can change the command prefix to whatever you want. + +@bot.command() # This is the decorator we use to create a prefixed command. +async def ping(ctx): # This is the function we will use to create the command. + await ctx.send("Pong!") # This is the response the bot will send. + + +bot.run("token") # Run the bot with your token. +``` + + + + !ping + + + Pong! + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The help command is a built-in command and is enabled by default. You will learn more about it in the +following guides. + +::: + +## Parameters + +Prefixed commands can take parameters, just like slash commands. You can specify the parameters in +the function itself. + +```python title="Parameters Example 1" +@bot.command() +async def echo(ctx, *, message): + await ctx.send(message) +``` + +`ctx` is the context of the message. `*` means that the parameter can be any number of words. `message` +is the parameter. If you had not passed `*`, `message` would only have been one word. + +For example, if a user had used `!echo hello world`, `message` would have been `hello`. Since we +passed `*`, `message` is `hello world`, or the rest of the message. + +We can pass multiple parameters too! + +```python title="Parameters Example 2" +@bot.command() +async def echo(ctx, channel:discord.TextChannel, title, *, message): + await channel.send("**{}**\n{}".format(title, message)) +``` + +In the example above, `channel` is a parameter that is of type `discord.TextChannel`. When you +specify the type of the parameter, Pycord will automatically try to convert the parameter to that type. +That is why you can use `channel.send` directly without needing to convert it first. + +We also have a new parameter, `title`. This does not have a type, so it will be a string. `*` means +that the rest of the message belongs to the next parameter, in this case, `message`. + +When a user types `!echo #general Greetings! Hello World!`, `channel` will be the text channel +`#general`, `title` will be `Greetings!` and `message` will be `Hello World!`. + +Let's take an example where the user passes `!echo #general Holiday Greetings! Greetings to you all!`. +Here, the user wants the title to be "Holiday Greetings!" and the message to be "Greetings to you all!". +However, since Pycord parses the message at whitespaces, the title will end up being "Holiday" and the +message "Greetings! Greetings to you all!". The user can prevent this by typing `!echo "Holiday +Greetings!" Greetings to you all!`. + + + + + + !echo #general Holiday Greetings! Greetings to you all! + + + Holiday +
+ Greetings! Greetings to you all! +
+ + !echo #general "Holiday Greetings!" Greetings to you all! + + + Holiday Greetings! +
+ Greetings to you all! +
+
+ +Let's check out another example for parameters and parameter types. + +```python title="Parameters Example 3" +import random + +@bot.command() +async def gtn(ctx, guess:int): + number = random.randint(1, 10) + if guess == number: + await ctx.send("You guessed it!") + else: + await ctx.send("Nope! Better luck next time :)") +``` + +If you had not specified the type of the parameter, it would have been a string. And since `"5"` is not +the same as `5` in python, the bot would have responded with "Nope! Better luck next time :)". +Even if you do not specify the type of the parameter, you can still convert it later on, in this case, +with `int(guess)`. + +:::info Related Topics + +- [Command Groups](groups) +- [Rules and Common Practices](../../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json new file mode 100644 index 00000000..baeba701 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Pages", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx new file mode 100644 index 00000000..be90b035 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx @@ -0,0 +1,168 @@ +--- +title: Paginator Basics +--- + +# Paginator Basics + +## [Page](https://docs.pycord.dev/en/stable/ext/pages/index.html#page) + +This class contains two attributes: `content` and `embeds`, which correspond to the attributes of the same name on the +`discord.Message` class. +To create a new Page, use the following syntax: + +```py +import discord +page = Page(content="My Page Content", embeds=[discord.Embed(title="My First Embed Title")]) +``` + +## [PageGroup](https://docs.pycord.dev/en/stable/ext/pages/index.html#pagegroup) + +This class represents a group of pages. It uses most of the same parameters as `Paginator`, which allows each +`PageGroup` to effectively have its own settings and behaviours. + +## [Paginator](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator) + +This is the main class for `ext.pages`, and is used to control most of the functionality of the extension. + +In its most basic form, with no arguments provided (default values listed below), a paginator can be created like so: + +```py title="Paginator Example" +import discord +from discord.ext.pages import Paginator, Page + +my_pages = [ + Page( + content="This is my first page. It has a list of embeds and message content.", + embeds=[ + discord.Embed(title="My First Embed Title"), + discord.Embed(title="My Second Embed Title"), + ], + ), + Page( + content="This is my second page. It only has message content.", + ), + Page( + embeds=[ + discord.Embed( + title="This is my third page.", + description="It has no message content, and one embed.", + ) + ], + ), +] +paginator = Paginator(pages=my_pages) +``` + +The only required parameter for `Paginator` is the `pages` parameter, which is usually a list of `Page` objects. + +You can also pass in a list of `PageGroup` objects, a list of strings, a list of embeds, or a list of lists of embeds. + +Once the `Paginator` instance is created, you can call either +[`Paginator.send()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.send) +or [`Paginator.respond()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.respond) +to send a message or response with the paginator's contents. + +#### Depending on what's being passed to the `pages` parameter, the behaviour of the paginator may differ: + +- Passing a list of `PageGroup` objects will essentially treat each `PageGroup` as its own Paginator, with most + `Paginator` attributes able to be set independently for each `PageGroup`. + \- Each `PageGroup` accepts its own `pages` parameter, which inherits the same behaviour as the `pages` parameter + of `Paginator`, except it cannot contain other `PageGroup` objects. +- If a page is a `Page` object, this will allow you to specify both the `discord.Message.content` and + `discord.Message.embeds` attributes for a page. + \- **This is the preferred method of defining a page.** +- If a page is a string, this will be used for the `discord.Message.content` attribute. This type of page cannot have + any embeds. +- If a page is a list of embeds, this will be used for the `discord.Message.embeds` attribute. This type of page + cannot have any message content. +- If a page is a list of lists of embeds, each parent list item will create a page containing all embeds from its + child list. This type of page cannot have any message content. + +#### Parameters for the `Paginator` class which have default values: + +- `show_disabled` **:** `True` + - Show buttons that are disabled (i.e. can't be clicked) +- `author_check` **:** `True` + - Only the author can interact with the paginator. +- `timeout` **:** `180` _(seconds)_ + - The paginator will time out and become inactive after this many seconds. +- `disable_on_timeout` **:** `True` + - If the paginator times out, it will be automatically disabled and all buttons will be unusable. +- `use_default_buttons` **:** `True` + - Use the default set of 4 buttons and a page indicator. +- `show_indicator` **:** `True` + - When using the default buttons, shows a middle 5th button with the current/total page numbers. + +**For other parameters that can be set on initialization, please check the +[API Reference](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator)** + +## [PaginatorButton](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatorbutton) + +This class represents a button used to navigate between the pages of a paginator. It's also used to create the page +indicator. + +When creating your own custom buttons, you can either use this class directly or subclass it to add any additional +functionality you may need. + +To add custom buttons to the paginator instead of the default navigation buttons, you have two options to do so: + +1. **Using the `custom_buttons` parameter of `Paginator`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + buttons = [ + PaginatorButton("first", label="<<-", style=discord.ButtonStyle.green), + PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), + PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True), + PaginatorButton("next", label="->", style=discord.ButtonStyle.green), + PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), + ] + paginator = Paginator( + pages=["Page 1", "Page 2", "Page 3"], + show_indicator=True, + use_default_buttons=False, + custom_buttons=buttons, + ) + ``` +2. **Using `Paginator.add_button()`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"], use_default_buttons=False) + paginator.add_button(PaginatorButton("prev", label="<", style=discord.ButtonStyle.green)) + paginator.add_button(PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True)) + paginator.add_button(PaginatorButton("next", label=">", style=discord.ButtonStyle.green)) + ``` + +If you want to use the default navigation buttons, but not all of them, you can also use `Paginator.remove_button()` to +selectively remove them: + +```py +from discord.ext.pages import Paginator + +paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"]) +paginator.remove_button("first") +paginator.remove_button("last") +``` + +## [PaginatorMenu](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatormenu) + +This class represents the `discord.Select` menu used to navigate between `PageGroup` instances. In most situations, you +will not need to interact with this class directly. + +If you do subclass it, you'll likely want to call `super()` in your `__init__` method to ensure that the `PageGroup` +navigation functionality is retained. + +## Usage Examples + +For a comprehensive list of examples showing all `Paginator` functionality, please see the +[example in cog form](https://github.com/Pycord-Development/pycord/blob/master/examples/views/paginator.py) in the repo. + +## Support and Feedback + +If you have any questions, suggestions, or feedback for `ext.pages`, please join the +[Discord server](https://discord.gg/pycord). diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx new file mode 100644 index 00000000..b8d68925 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx @@ -0,0 +1,20 @@ +--- +title: Paginator FAQ +--- + +# Paginator FAQ + +- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** + - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. + - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. + +- **How can the bot send a paginator to a different destination than where it was invoked?** + - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. + - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. + - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. + +- **How can I change the paginator's behavior without re-creating and re-sending it?** + - Use the `Paginator.update()` method. + +- **How can I make the bot actually do something with the contents of a page?** + - Use the (upcoming) `Paginator.page_action()` method. diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json new file mode 100644 index 00000000..36dfb009 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Tasks" +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx new file mode 100644 index 00000000..848f6066 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx @@ -0,0 +1,216 @@ +--- +title: Tasks +--- + +## Concept + +So you want to run a background task running at some specified interval? Thankfully, that's a common thing to do, whether you're working with some API or handling some background logic don't worry, the Pycord tasks extension is here to make life easier for you! + +With the tasks extension, you can make background tasks without worrying about the asyncio hell and mind bogglers like "what if my internet dies" and "how do I handle reconnecting" with the added benefit of a lot of useful additions that are one line of code away! + +### Example Usage + +```py +import discord +from discord.ext import tasks + +bot = discord.Bot() + +@bot.event +async def on_ready(): + very_useful_task.start() + +@tasks.loop(seconds=5) +async def very_useful_task(): + print('doing very useful stuff.') + +bot.run("TOKEN") +``` + +If you do run this code in your terminal you should see something like this after about 15 seconds: + +``` +doing very useful stuff. +doing very useful stuff. +doing very useful stuff. +``` + +For a more useful example here's a task in a cog context ripped straight from the [docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#recipes): + +```py +from discord.ext import tasks, commands + +class MyCog(commands.Cog): + def __init__(self): + self.index = 0 + self.printer.start() + + def cog_unload(self): + self.printer.cancel() + + @tasks.loop(seconds=5) + async def printer(self): + print(self.index) + self.index += 1 +``` + +As you'd expect this will increment a number and print it out every 5 seconds like so: + +```sh +0 +# 5 seconds later +1 +# 5 more seconds later +2 +# ... +``` + +## [Tasks](https://docs.pycord.dev/en/stable/ext/tasks/index.html) + +Now let's get into the nitty-gritty of tasks. + +As you've seen tasks can work in both outer scope and class contexts and the handle is roughly the same, you define a task using the `tasks.loop` decorator and use the `start` method to start it, the difference is you add the `self` argument when in a class context so since most people have all their bot's code in Cogs all the following code blocks will be in a Cog context to make it easy to copy it then apply whatever modifications you might need! + +### [Creating a task](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop) + +A look at `discord.ext.tasks.loop`'s definition in the documentation reveals that: + +1. As you've seen before it expects the time between each execution, that however doesn't have to be in seconds as + there are `seconds`, `minutes` and `hours` parameters to make it easier for us, they can also be floats in case you want + ultra-precision. +2. You can also pass in a `datetime.time` object or a sequence of them in the `time` parameter which will make it run + at the specified time(s). +3. You can pass in how many times a loop runs before it stops by passing in the `count` parameter, you can use `None` + to make it run forever which is also the default. +4. The loop function **_must_** be a coroutine. + +These are all really useful, and they aren't the only parameters so if you want to know more about them check out the +[docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop)! + +### Attributes + +A task has the following attributes: + +- `current_loop`: The current loop the task is on. +- `hours`, `minutes`, `seconds`: attributes that represent the time between each execution. +- `time`: A list of datetime.time objects that represent the times the task will run, returns `None` if no datetime + objects were passed. +- `next_iteration`: A `datetime.datetime` object that represents the next time the next iteration of the task will + run, can return `None` if the task stopped running. + +These attributes serve as a really powerful asset to get info about your loop. + +### Example + +Now let's create a cog that handles a leaderboard we have in our bot using Tasks then explain what we did after that and +also provide a refresher of how slash commands groups work in cogs. + +For the sake of this example let's pretend that we have a leaderboard module that does all the leaderboard handling for +us and that computing the leaderboard is very expensive computationally wise, so we want to store one version of it that +gets regularly updated instead of generating it every time someone calls the `/leaderboard view` command. + +```py +from discord.ext import tasks, commands +from discord.commands import SlashCommandGroup, CommandPermissions + +from leaderboard import * # Mock leaderboard module. + +class LeaderboardCog(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.update_leaderboard.start() + self.leaderboard_embed = generate_leaderboard_embed() + + leaderboard = SlashCommandGroup(name='leaderboard', description='Leaderboard commands.') + + @tasks.loop(minutes=10) + async def update_leaderboard(self): + print('Updating leaderboard...') + await update_leaderboard() + self.leaderboard_embed = generate_leaderboard_embed() + + @update_leaderboard.before_loop + async def before_update_leaderboard(self): + await self.bot.wait_until_ready() + print("About to start updating leaderboard.") + + @update_leaderboard.after_loop + async def after_update_leaderboard(self): + leaderboard_cleanup() + print("Stopped updating leaderboard.") + + @update_leaderboard.error + async def update_leaderboard_error(self, error): + print(f"Oh no, an error occurred while updating the leaderboard. Error: {error}") + + @leaderboard.command() + async def view(self, ctx): + await ctx.respond(embed=self.leaderboard_embed) + + @leaderboard.command() + async def update_info(self, ctx): + await ctx.respond(f"""***Leaderboard Info***\n + Last update: {(600 - self.update_leaderboard.next_iteration.timestamp())//60} minutes ago.\n + Next update: in {self.update_leaderboard.next_iteration.timestamp() // 60} minutes.\n + Time between loops: {self.update_leaderboard.minutes} minutes.\n + Times updated this session: {self.update_leaderboard.current_loop}. + Running? {self.update_leaderboard.is_running()} + Failed? {self.update_leaderboard.failed()}""", ephemeral=True) + + # Now for the owner only commands: + + leaderboard_config = SlashCommandGroup(name="leaderboard_config", description="Leaderboard configuration commands", permission=[CommandPermissions("owner", 2, True)]) + + @leaderboard_config.command() + async def set_time_between_updates(self, ctx, minutes: int): + self.update_leaderboard.change_interval(minutes=minutes) + await ctx.respond(f"Set time between updates to {minutes} minutes.") + + @leaderboard_config.command() + async def stop(self, ctx): + self.update_leaderboard.stop() + await ctx.respond("Stopped the leaderboard update.") + + @leaderboard_config.command() + async def restart(self, ctx): + self.update_leaderboard.restart() + await ctx.respond("Restarted the leaderboard update.") + +def setup(bot): + bot.add_cog(LeaderboardCog(bot)) +``` + +Phew, that was quite a bit of code. + +Now to explain what's going on: + +First things first we create a cog and in its `__init__` function we start the `update_leaderboard` task and generate +the first instance of our leaderboard's embed. + +After that, we define the `update_leaderboard` task using the `loop` decorator, and we make it run every ten minutes by +passing 10 to the `minutes` parameter. + +Then that we define the `before_update_leaderboard` task using the `before_loop` decorator, and we make it wait until the +bot is ready before starting the task. + +Next up we define the `after_update_leaderboard` task using the `after_loop` decorator, and we make it clean up the +leaderboard when the loop finally stops running. + +Then we define the `update_leaderboard_error` task using the `error` decorator, and we make it print any errors that may +occur while we update our leaderboard to the console. + +Then we get into the fun stuff, we create a slash command group using the `SlashCommandGroup` class and name it +`leaderboard`, we then create the `view` sub-command which sends the embed generated when the leaderboard is updated and +`update_info` which shows a lot of data about the task using some attributes and functions available to us. + +We also create a slash command group called `leaderboard_config` which is only available to the owner of the bot. + +Then we create the `set_time_between_updates` sub-command which takes in the time in minutes and changes the time +between updates of the leaderboard using the `change_interval` method, the `stop` sub-command which stops the task using +the `stop` method and `restart` which restarts the task using the `restart` method. + +Finally, we add the `LeaderboardCog` cog to the bot, and we're done! + +I'd highly recommend you check the tasks extension +[documentation](https://docs.pycord.dev/en/stable/ext/tasks/index.html) for more info on how to use them and what other +functions they have. diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/_category_.json new file mode 100644 index 00000000..9d6255f5 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 3, + "label": "Getting Started", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx new file mode 100644 index 00000000..864206a6 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx @@ -0,0 +1,262 @@ +--- +title: Creating Your First Bot +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +Excited to create your first bot? Once you [install Pycord](../installation.mdx), you can start right +away! + +## Creating the Bot Application + +Just like how you need to sign up to use Discord, your bot also has to be signed up. To do this, +you should: + +1. Go to the [Discord Developer Portal](https://discord.com/developers/applications) and click + on . +2. Give your bot a name, and click . +3. Now, you should see a page like this. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdW3OQnwUhacopqSWw%2F-Mjd_-mxrJCrzmaXrAg8%2Fimage.png?alt=media&token=b8e2ae6c-2290-4d37-ad7c-eb412f3fb00e) +4. Click on the tab on the left side of the screen. +5. Click on . +6. You can give it a name, change the Avatar, etc. + +## Inviting the bot + +Now, lets get the bot added to some servers. Go to the tab +in the left pane and select `bot` and `applications.commands` as scopes. + +You may want your bot to have application commands, which is what the `application.commands` scope +allows your bot to make. + +Next, you want to choose what permissions the bot will have and select them. For now, you can just +give your bot the `administrator` permission, which gives your bot every permission. Once you select +your bot's permissions, click on to get the bot invite link. + +:::tip + +When your bot is all ready to go, make sure that administrator permissions aren't selected unless +your bot truly needs them. Try selecting only permissions the bot will need. For testing, +Administrator permissions are fine. + +::: + +![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-Mk6tNY3LfDkjd6pqdpL%2F-Mk6tkdpddEWoa2jczZk%2Fimage.png?alt=media&token=52c8a29f-a798-48f8-a8c7-4ecca2681f79) + +You can use this link to invite the bot. + +## Tokens + +Now that you have an account for your bot, you need to log in. To log in, we need the bot's +password. All users and bots have a "token." You may think of this token as a password, as this allows +us to log our bot into Discord. + +Tokens are "snowflakes." Not actual snowflakes, though. Just like how no two snowflakes in real life have the same +pattern, snowflakes in computers are unique things - no two bots have the same token - so a token is +considered a snowflake. A Discord user ID is also a snowflake. + +Now, lets get your bot's token. To do this, you want to: + +1. Go back to the tab. +2. Click on the button in the "Token" section. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdbU12JISJorAZxrKH%2F-MjdbpUsapzb5n15Po5P%2Fimage.png?alt=media&token=118e259f-940a-4f6c-b3a3-c29f3a54100d) + +Now, you have your bot's token copied to your clipboard. + +:::danger + +Do not, under any circumstances, give your token to anyone. Even if you are contacted by someone +claiming to be Discord staff, do not give them your bot's token. They are lying to you to try and +gain access to your bot. If an unauthorized user gains access to your bot's token, they can access +your bot and use it in malicious ways. + +Never push your token to GitHub or include it in your code. One way to prevent your token from +getting leaked is to store it in `.env` files. + +::: + +### Protecting Tokens + +#### Using dotenv + +You can store your tokens in `.env` files. This is a simple way to store sensitive information. + +1. Create a file with the name `.env` (only the extension, with a dot/period at the start and without a name before it). +2. Define the token in the `.env` file (replace the example value with your token). + ```env title=".env" + TOKEN = NzkyNzE1NDU0MTk2MDg4ODQy.X-hvzA.Ovy4MCQywSkoMRRclStW4xAYK7I + ``` +3. Install [`python-dotenv`](https://pypi.org/project/python-dotenv/). + ```bash + python -m pip install python-dotenv + ``` +4. Load the token from the `.env` file. + ```python + import dotenv + dotenv.load_dotenv() + token = str(os.getenv("TOKEN")) + ``` +5. Pass your token as parameter when running the bot. + ```python + client.run(token) + ``` + +:::tip + +If you are using Git to track your bot's changes, you should create a file called `.gitignore` and add +`.env` to it. This stops your `.env` file from getting tracked along with the rest of your code, and +will not be pushed to a remote Git repository. As a consequence, it will stay secure on your local machine. + +::: + +## Coding the Basics + +Here's an example of code you'll write with Pycord: + +```py +import discord +import os # default module +from dotenv import load_dotenv + +load_dotenv() # load all the variables from the env file +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") + +bot.run(os.getenv('TOKEN')) # run the bot with the token +``` + + + +
+ + hello + +
+ Hey! +
+
+
+ +Let's go through the code. First, the imports. + +```py +import discord +import os +from dotenv import load_dotenv +``` + +In the first line, `import discord`, we import Pycord. Although you install Pycord with `pip install py-cord`, you +import it with `import discord`. This is so it's as easy as possible when switching from Discord.py to Pycord. + +We then import `os` and `dotenv`. `os` is a default module that we will use to get the token from the env file. `dotenv` +is a module that we will use to load the env file. You installed this with `pip install python-dotenv`. + +Next, we load the env file with `load_dotenv()`. + +```py +bot = discord.Bot() +``` + +In this line, we create a new instance of [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). +In this object, we can pass various parameters for configuration purposes, such as `owner_ids` +and [`intents`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```py +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") +``` + +We use the [`event`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) decorator to override +the [`on_ready`](https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready) function to define an +event that is automatically called when the bot is ready to use. + +```py +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") +``` + +Here, we use the [`slash_command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.slash_command) +decorator to define a slash command. We specify the `name` and `description` arguments. If not +specified, the name of the slash command would be the function name and the command description would +be empty. + +Optional: We type-hint the context parameter (`ctx`) as [`discord.ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext). In modern IDEs, type-hinting allows access to autocompletion and docstrings. You can read more about type-hinting [here](https://docs.python.org/3/library/typing.html). + +Finally, you want to run the bot using the token specified in the `.env` file. + +Now you have finished creating your first Pycord bot! What we have shown you is just the basic structure +of a bot. You can do a lot more with Python and Pycord knowledge, as well as your imagination! Pycord +will not limit your bot's abilities. + +:::note + +The part where we load the token from the environmental variables is not required. You may use another way to keep your token secure, or, although not recommended, simply specify the token normally as a string, as shown below. + +
+A Basic Bot without securing the token +
+ +```py +import discord + +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.send("Hey!") + +bot.run("TOKEN") +``` + +
+
+ +::: + +## FAQ + +### How do I make prefixed commands? + +Prefixed commands are an older method of creating bot commands that listen for messages and replies +if the message starts with a certain character. You can read [this page](../extensions/commands/prefixed-commands.mdx) +to learn more about prefixed commands. + +### How do I setup modules/cogs? + +[Cogs](../popular-topics/cogs) are a great way to organize your commands by putting them into +groups called cogs. Cogs are separate files that your bot loads to get the commands inside. +You can read more about cogs, as well as learn how to use them and their benefits, +[here](../popular-topics/cogs). + +### How do I add components, such as buttons and dropdown menus, to my bot? + +Pycord makes it very easy to use Message Commands with your bot by using the `discord.ui` module. +To learn more, read about Message Commands in our [interactions directory](../interactions). + +:::info Related Topics + +- [Prefixed Commands](../extensions/commands/prefixed-commands) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx new file mode 100644 index 00000000..2a68677b --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx @@ -0,0 +1,109 @@ +--- +title: Hosting Your Pycord Bot +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Hosting Your Pycord Bot + +If you're completely new to this, you might have thought something along the lines of "Yay! I got my +bot working," after following our [Creating your First Bot](creating-your-first-bot) guide, only +to close your IDE or shut down your computer to find your bot offline. + +The reason for this is that programs have to be hosted somewhere, meaning some machine somewhere has +to constantly run your bot. There are tons of hosting services that can help you host your bot for +little to no cost. + +## Can I get a Clear Explanation? + +Sure thing. When you run your bot, it first makes a connection to Discord's API. Once that's done, +Pycord sends "heartbeats" to Discord. "heartbeats" are small packets sent at a set interval telling +Discord that your bot is indeed still alive. If Discord doesn't receive a heartbeat after a certain +amount of time, your bot is pronounced dead and buried in the graveyard (not really). It is, though, +taken offline and its connection with Discord is terminated. + +Once you close the terminal that you've run your program on, the program is no longer running, and +the bot stops sending heartbeats and can no longer process commands. This is why you have to constantly +keep the process running. + +This goes for all programs, in a different nature. If the code isn't compiled/built/assembled/interpreted, +it can't be running. + +## What is a Host? + +A host is a server or container for running code offered by a **hosting provider.** There are a lot +of hosting providers, such as bigger ones like Amazon Web Services (AWS) and Google Cloud, and smaller +ones like GalaxyGate and DigitalOcean. + +There are three types of hosts. + + + + Shared hosting is a type of hosting where multiple people share one VPS. Getting a spot on + a shared host is usually cheap, sometimes even free. Shared hosts do not give you a lot of + resources, from less than a gigabyte of RAM (usually 512MB on free hosts) and half of a CPU + with very little storage. Shared hosting is usually used for website hosting and is not + recommended for hosting a Discord bot. + + + A virtual private server (VPS) is a virtual computer (virtual machine) that is rented out to + customers. Most people use a VPS for hosting their projects such as Discord bots. You can get + anywhere from less than a gigabyte of RAM and a less powerful CPU to just under one hundred + gigabytes of RAM, a (or multiple) powerful CPU(s), and a fair amount of storage. A VPS is the + best choice for most users and can be fairly cheap. + + + A dedicated host is a physical computer. You can buy these yourself or rent one from a hosting + provider. Dedicated hosts are often very expensive, but are also very powerful, having a + few hundred gigabytes of RAM and a few very powerful CPUs, along with a good amount of storage. + Dedicated hosts are usually used for very large projects and are overkill for something like + a Discord bot. + + +
+ +:::danger + +Make sure you choose a hosting provider you trust. Also make +sure the hosting provider you're looking at has good reviews on public forums. Googling along the +lines of "[host] review" should do the trick. A provider you don't trust can compromise your token. + +::: + +Most hosting providers rent their services to you for a monthly or yearly fee. These can be anywhere +from a few dollars to hundreds or thousands of dollars. + +## How to Host Your Bot + +Once you rent or buy a VPS, you can get to work. Most hosting providers allow you to choose from a +wide range of operating systems, most allow you to choose one but some allow you to choose +multiple. Once that's ready, you have to SSH into the system. We won't get into SSH here, but you can +read [this article from DigitalOcean](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys). +You can also use VNC, which is remote desktop software. If you are using an OS that does not have a +GUI, and is only a command line (a "server" OS), such as Ubuntu Server or most Linux Server Operating Servers, you will most +likely use SSH. If you are using an OS that has a GUI, such as Windows Server, you will most likely use VNC. + +Once you've decided on your operating system, you'll want to set it up and install Python. Once that's +done, you can copy your bot's files to your remote system, install the required packages, and run +the bot. + +:::warning + +If you are using SSH to run the file, your bot will not stay running. This is because the file is +only told to run during your session. You can use a command like [nohup](https://en.wikipedia.org/wiki/Nohup) +to make sure your file stays running after you disconnect. + +::: + +Now your bot is hosted, but that doesn't mean it can't go offline. If your bot encounters an error, +it can often go offline or stop its process. For this, make sure you have proper error handling. +Also be sure to pay attention to your hosting provider's updates or news, as they usually notify +users of when they plan on doing maintenance to their servers, making their services unavailable for +a short time. + +:::info Related Topics + +- [Creating Your First Bot](creating-your-first-bot) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx new file mode 100644 index 00000000..ee6b9417 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx @@ -0,0 +1,379 @@ +--- +title: More Features +description: More features to make your bot cool and snazzy. +--- + +import { + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, + DiscordEmbedField, + DiscordEmbedFields, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +So, you just created your first Pycord bot! Now, let's add some more features to it. This will include adding event handlers, waiting for user response, styling the messages, and more. + +## Events + +### Event Handlers + +Events in Discord are a way to listen for certain actions. For example, if you want to know when a user joins your server, so you could send a welcome message, you can use the `on_member_join` event. + +First, you need to ask Discord to send you events. This is done via "Intents". Read up the [Intents](../Popular-Topics/intents) page for more information. + +Once you understand what intents are, you can enable the events you need, or just use the default ones with `discord.Intents.all()`. + +Now that that's done, let's add an event handler for when a user joins the server. We will use the [`on_member_join` event](https://docs.pycord.dev/en/stable/api/events.html#discord.on_member_join). We will send a private message to the user welcoming them to the server. + +```python +@bot.event +async def on_member_join(member): + await member.send( + f'Welcome to the server, {member.mention}! Enjoy your stay here.' + ) +``` + +We use the [`discord.Bot.event` decorator](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) to add the event handler. + +The `on_member_join` event is called when a user joins the server. The `member` parameter is the user that joined. Different events have different names and parameters. You can find all of them [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +So, that's how you add event handlers! + +### Waiting for User Response + +Let's say you want to create a Guess-the-Number game (where the user has to guess a number between 1-10). You need to send a message to a user and wait for them to respond. You can do this with the [`wait_for`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.wait_for) method. + +```python +@bot.command() +async def gtn(ctx): + """A Slash Command to play a Guess-the-Number game.""" + + await ctx.respond('Guess a number between 1 and 10.') + guess = await bot.wait_for('message', check=lambda message: message.author == ctx.author) + + if int(guess.content) == 5: + await ctx.send('You guessed it!') + else: + await ctx.send('Nope, try again.') +``` + +`wait_for` takes one argument, which is the event type. The event type is the name of the event you want to wait for. In this case, it's `message`. It could also be `reaction` to wait for a reaction to be added. + +We pass a keyword argument to `wait_for` called `check`. The function may look complicated if you're a beginner. We pass a `lambda` function, which simplifies the code a bit. + +The lambda function takes one parameter, `message`. When Pycord receives a message, it passes it to the `check` function. If the function returns `True`, the message is returned. If the function returns `False`, the message is ignored and the bot waits for another message. + +Here, we check if the message is from the user that sent the command. We simply use `message.author == ctx.author`. This will check if the author of the message was the person who invoked the command. + +## Styling Messages + +### Embeds + +Embeds are a Discord feature that allows applications to format their messages in cool embedded format, +enabling your bot to lay out messages with a lot of text into neat fields. + + + + + The Pycord Guide is a detailed guide that explains how to use Pycord and all of its features. + + + The Getting Started section explains how you can get a brand new bot created and running from scratch. + + + Interactions with Pycord + + + Pycord's various Extensions + + + Other Popular Topics + + + We have so much more! Just explore, and you will find everything you need. If you want another page added, open an issue on the GitHub. + + + Created with 💖 by the Pycord Team & Contributors + + + + +
+ +Creating embeds is simple! Just create an instance of [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) and edit it to your liking. Once you're done, send it! + +```python +import discord + +bot = discord.Bot() + +@bot.command() +async def hello(ctx): + embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from + ) + embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") + + embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) + embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) + embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) + + embed.set_footer(text="Footer! No markdown here.") # footers can have icons too + embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") + embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") + embed.set_image(url="https://example.com/link-to-my-banner.png") + + await ctx.respond("Hello! Here's a cool embed.", embed=embed) # Send the embed with some text + +bot.run("TOKEN") +``` + + + +
+ hello +
+ Hello! Here's a cool embed. + + Embeds are super easy, barely an inconvenience. + + + A really nice field with some information. The description as well as the fields support markdown! + + Inline Field 1 + Inline Field 2 + Inline Field 3 + + Footer! No markdown here. + +
+
+ +
+ +This simple command sends replies to a [slash command](../interactions/application-commands/slash-commands) with an embed. +Let's break it down: + +```py +embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), + ) +``` + +This command creates an embed. We use the [`Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) +class to create an embed object with the title "My Amazing Embed", the description "Embeds are super easy, barely an inconvenience.", and the color `blurple`, Discord's main theme color. + +[discord.Colour](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Colour) is a class full of [classmethods](https://docs.python.org/3/library/functions.html#classmethod) +that return color values. While the official, documented name of this is `discord.Colour`, `discord.Color` +works as well. + +```py +embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") +embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) +embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) +embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) +``` + +This small section shows off embed fields. You can add fields to embeds with the [`add_field` method](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.add_field) +of the [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) class. These consist of three +keyword arguments: `title`, `value`, and `inline`. `title` and `value` are both required arguments, which inline defaults to `False` if it's not defined. The `inline` argument specifies whether space will be divided among the inline fields. There could be a mix of fields where inline has different values too. + +```py +embed.set_footer(text="Footer! No markdown here.") # footers can have icons too +embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") +embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") +embed.set_image(url="https://example.com/link-to-my-banner.png") +``` + +In this section, we're adding unique items to the embed. These items are: + +- Footer - With the [`set_footer()`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_footer) + method, you can set a small footer that holds a message. This has `text` and `icon_url` kwargs. +- Author - With the [`set_author`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_author) + method, you can set an author for the embed. This is a small text field at the top of the embed. This + includes `name`, `url` and `icon_url` kwargs. +- Thumbnail - With the [`set_thumbnail`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_thumbnail) + method, you can set a small image to reside at the top-right of the embed. This has a single `url` kwarg. +- Image - With the [`set_image`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_image) + method, you can set an image to sit at the bottom of an embed. This has a single `url` kwarg. + +There are a lot more methods and attributes you can use to configure embeds. Here, we just covered the basics. Also, remember that all of these values are not necessary in an embed. An embed may only contain a few of these. For example, only a description, a title and a description, and so on. + +### Markdown + +Markdown is a type of markup language that's limited in terms of formatting yet simple. Discord allows +for a watered-down version of markdown to be in their messages. + +#### Text Markdown + +Text formatting can be used in messages and in most embed parts, +as explained in the dedicated section below. + + + + + + + + + + + + + + + + + + + + +
*italics*__*underlined italics*__
**bold**__**underlined bold**__
***bold italics***__***underlined bold italics***__
__underlined__~~strikethrough~~
+ +#### Code Markdown + +To create a single-line code block without syntax highlight, wrap the text between single backticks. +This code block will only add a dark background to the text. + +``` +`print("Hello world!")` +``` + +To create a multi-line code block without syntax highlight, wrap the text between triple backticks +on first and last line. This type of code block will encase the code inside a box. + +```` +``` +message = "Hello world!" +print(message) +``` +```` + +To create a multi-line block with syntax highlight, add the name of the language you are using right after +the triple backticks on the first line. For example, for Python you can write either "python" or "py". + +```` +```python +message = "Hello world!" +print(message) +``` +```` + +If you want to use syntax highlight for a single line of code, you still have to format it +like a multi-line block but the code must be on a separate line than the triple backticks. + +#### Quote Markdown + +To create a single-line quote block, start the line with `>` followed by a space. + +``` +> This is a single-line quote. +``` + +To create a multi-line quote block, write `>>>` followed by a space. All text +from that point onwards will be included in that quote block. + +``` +>>> This is a +multi-line quote. +``` + +#### Spoiler Markdown + +To hide a spoiler, encase the text between double pipes. The users +will have to click on it before being able to see the text contained in it. + +``` +||spoiler|| +``` + +#### Link Markdown + +Link formatting only works in embeds and messages sent through webhooks, +by using the following syntax: + +``` +[Pycord](https://pycord.dev/) +``` + +Inside the supported elements that have just been mentioned, +the example above will look like this: [`Pycord`](https://pycord.dev/) + +Outside them, the link will still be clickable but the formatting will be ignored, +therefore the example above will look similarly to this: `[Pycord](https://pycord.dev/)` + +#### Embed Markdown + +Adding markdown to your embeds or messages will give your bot the sparkle it needs, +however, markdown is limited inside embeds. Use the following table as a reference +and keep in mind that embed title and filed names will always show in **bold**. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PartTextLink
Embed AuthorNoNo
Embed TitleYesNo
Embed DescriptionYesYes
Field NameYesNo
Field ValueYesYes
Embed FooterNoNo
diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx new file mode 100644 index 00000000..e44b7c49 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx @@ -0,0 +1,184 @@ +--- +title: Rules and Common Practices +description: All about the rules and common practices for coding a Discord bot +--- + +# Rules and Common Practices of Creating a Bot + +When creating almost anything, there's always a certain set of rules to follow or common practices, +such as [PEP8](https://www.python.org/dev/peps/pep-0008/) for Python. This applies to creating bots +with Pycord as well. + +:::note + +Most of these rules and common practices are only applicable for +[verified bots](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting), +but it's good to follow them nonetheless. + +::: + +## Rules + +There are rules for creating bots, and most of these are required by Discord themselves, not us at +Pycord. Not following these rules may get your bot denied for verification. + +### Terms of Service and Privacy Policy + +Starting at some point in time, Discord has made providing a privacy policy with your bot a requirement. +This is so that Discord knows exactly what you are doing with its users' data. + +:::tip +You don't need a lawyer or anyone special to write out a privacy policy for you, nor do you need +it approved by some official entity. Simply writing out how you are going to use Discord user +information neatly is all you need to do. +::: + +Providing a Terms of Service for your bot is optional, though usually a best practice. It tells users +what they can and cannot do with your service, and makes it easier to settle disputes if someone +disagrees with you. + +Read more in Discord's official [Legal Docs](https://discord.com/developers/docs/legal). + +### Developer Policy + +We could list almost every rule about using Discord's API here. _Or_ we could simply link Discord's +Developer Policy to make it easier on us. You can find Discord's Developer Policy +[here](https://discord.com/developers/docs/policy). This outlines what you can and cannot do with +Discord's Developer API. And, don't worry, it's completely readable and understandable. + +## Best Practices + +Now, here's something we _can't_ simply link an article for. We're going to discuss the best practices +of creating a Discord bot with Pycord. + +### Bot Sharding + +To any new or maybe even experienced bot developer, sharding a bot sounds beneficial once you hear +about it. I'm here to tell you that it isn't a good idea to shard your bot. + +_Wait a minute, why would it be an option if it wasn't a good idea?_ It's simple. I lied. Sort of. +I'm not going to go into the details of sharding a bot, so you can read about it on +[this page](../Popular-Topics/sharding). Sharding is the process of taking your bot +and breaking it up into small pieces, so it's easier to perform tasks. This is very useful for large +bots, as it makes them faster and more reliable. Sharding is not a good practice for small bots. + +:::note +Discord will notify you once it is time to shard your bot, and will eventually force you to do so. +::: + +At the very least, wait for one thousand servers to shard your bot. If you shard your bot while it's +small, you'll just be wasting resources and possibly making your bot slower. + +### [Verification](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting) + +Verifying your Discord bot is something every developer would like to achieve. It shows that your bot +is in more than 75 servers. It's generally a good idea to try to get your bot verified as soon as +possible. We're talking at 76 servers soon. This is because Discord can be somewhat slow in terms of +bot verification, so verifying as soon as possible gives them enough time to verify before your bot +reaches the 100 server cap. If a bot is not verified, it cannot grow beyond 100 servers. + +It's also a good idea to only apply for the privileged intents that you need. Applying for intents +your bot doesn't use wastes both your time and Discord's time, as your privileged intent request +will be denied simply because you applied for an intent you didn't need. + +### Subclassing + +While it may take some time, subclassing a bot is very worth it. Once again, this was explained +elsewhere, so I won't go into the details, but I felt it fit here, so I put it here. + +Subclassing a bot makes it more flexible and allows it to do a lot more. Read more about subclassing +bots [here](../Popular-Topics/subclassing-bots) + +### Your Bot's Token + +Your bot is only able to be run for one reason: its token. If you followed the +[guide for creating your first bot](creating-your-first-bot), you should already know a bit about +keeping that token safe. That's exactly what you want to do. + +Sharing your token is never good. If someone evil gets a hold of your token, they can do terrible things, +such as making your bot leave all of its servers, spamming all the members the bot has contact with, +and even manipulating the servers the bot is in, if given the permissions. That's why it's very important +to keep your token safe. To learn how to do so, read [this part](creating-your-first-bot#tokens) of +the Creating Your First Bot guide. + +### Backups + +You always want to back up your bot's data. This includes both its code _and_ its databases. This way, +if something tragic happens, such as your host failing a data migration or you breaking your Raspberry +Pi's SD card that held your bot, you'll still have its precious user data. I have a small program for +my bot that uploads its databases to a remote GitHub repository periodically to not lose any data. +It may be smarter to find a bit more of a reliable way to do so, though. + +Public or private, having a local Git repository connected to a remote one is a good idea for making +almost any application. For a lot of developers, it's like saving your work. If you do this, all of +your bot's code won't be lost if your computer spontaneously combusts, or you smash it to bits from +anger. You can simply grab the backup computer that everyone has lying around, and you're back +in business. + +### Organization and Cleanliness + +It is _extremely_ important to have organized code. This includes commands, objects, functions, +and classes. If you don't have organized code, it will get progressively harder for you to recognize +it, and others won't be able to decipher it. + +Make sure you utilize indents and spaces, as these are very important in making your code readable. + +```py title="Bad Spacing" +class MyClass: + async def add(self,num1,num2): + return num1+num2 + async def sub(self,num1,num2): + return num1-num2 +``` + +```py title="Good Spacing" +class MyClass: + async def add(self, num1, num2): + return num1 + num2 + + async def sub(self, num1, num2): + return num1 - num2 +``` + +See the difference? Now, which one looks more readable? Hopefully, you answered the second example. +Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is a PEP (**Python Enhancement Proposal**) +style guide for Python. It is the style guide that is used by most Python developers and programmers, +providing a universal way to write and read code. + +### Databases + +As your bot grows, you'll inevitably have to store data for your bot. Now, most people would probably just load up some +JSON file on boot into a `dict`, modify it in memory then write to the file. However, JSON files aren't the solution. +When you write to a JSON file, it rewrites the entire file instead of just rewriting the section that changed. It's also +a configuration file format, not a storage file format. + +Instead of using a JSON file or some other related format, you should instead use a database. There are many databases +out there, like MongoDB, SQLite, and PostgreSQL to name a few. + +All of these databases I named do the job well, and which one you use depends on what features you want out of a database. + +<>{/* Maybe clarify these/add more options */} + +#### MongoDB + +MongoDB is a JSON-like format and if you already use JSON files, it shouldn't be too hard to migrate over to. + +#### SQLite + +SQLite is based on SQL, a common relational data model. It's a lightweight, easy-to-use, portable database solution that +works entirely on files. However, if for some reason you cannot read/write to and from a file, and you need to manage +lots of data, SQLite might not be for you. + +While SQLite is a part of the Python Standard Library as the `sqlite3` package, we recommend not using it as it is +synchronous and blocking. You should use an asynchronous alternative, such as [`aiosqlite`](https://pypi.org/project/aiosqlite/). + +#### PostgreSQL + +PostgreSQL is also based on SQL, but it also has more features than SQLite. It's compliant with the SQL standard, +open-source, and extensible. However, it's not that fast or simple compared to SQLite. + +#### MariaDB + +MariaDB is also based on SQL and is a fork of the MySQL project. It's compliant with the SQL standard, it's also open +source and is a complete drop-in replacement for any code with MySQL. You don't even need to change what package you're +using! diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/installation.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/installation.mdx new file mode 100644 index 00000000..521c69cd --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/installation.mdx @@ -0,0 +1,80 @@ +--- +title: Installation +sidebar_position: 2 +--- + +Before you can start using Pycord, you need to install the library. + +:::note +Python **3.8 or above** is required to use Pycord. +::: + +:::tip +Before you start installing python packages globally, it's recommended you set up a virtual environment. +You can find instructions for that [here](More/virtual-environments). +::: + +## Fresh Installation + +To install Pycord, you can use the following command in your terminal: + +``` +pip install py-cord +``` + +:::tip +Remember that you need to install `py-cord`, not `pycord`. +Also, the `pip` command varies depending on your installation. For example, it might be `python3 -m pip` on macOS/Linux or `py3 -m pip` on some versions of Windows. +::: + +If you need voice support for your bot, you should run: + +``` +pip install "py-cord[voice]" +``` + +## Migration + +### Updating Pycord + +If you are upgrading from a previous version of Pycord, you can use the following command in your terminal to upgrade to the latest version: + +``` +pip install -U py-cord +``` + +### Migrating from other libraries + +If you are migrating from another library, say, `discord.py`, first of all, you need to uninstall it. + +``` +pip uninstall discord.py +``` + +Then, you can install Pycord, it's as simple as that!: + +``` +pip install py-cord +``` + +:::caution +Uninstalling `discord.py` _after_ installing `py-cord` can cause issues. Make sure to uninstall it first! +::: + +## Installing Other Builds + +### Development Build + +:::caution +The development build comes with cutting edge features and new functionality, but as it isn't a stable build you may encounter bugs. +::: + +To install the development build, you can use the following command in your terminal: + +``` +pip install -U git+https://github.com/Pycord-Development/pycord +``` + +:::important +Git is required to install this build. [Learn how you can install Git](./more/git). +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/interactions/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/_category_.json new file mode 100644 index 00000000..ea28be60 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 4, + "label": "Interactions" +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json new file mode 100644 index 00000000..6dcafe83 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Application Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx new file mode 100644 index 00000000..b4ffeade --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx @@ -0,0 +1,85 @@ +--- +title: Context Menus +description: Learn all about Context Menus (User Commands & Message Commands) and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +When you right-click a message, you may see an option called "Apps". Hover over it, and you can see +commands a bot can run with that message. These are called message commands. + +When you right-click a user in the user list, you can once again see an option called "Apps". +Hover over it, and you can see commands a bot can run with that message. These are called user commands. + +Together, these two are called Context Menus or Context Menu Commands. These commands work very much like normal commands, except they take a member or message. + +:::note + +A bot can have up to 5 global Context Menus of each type. + +::: + +## User Commands + +Creating a user command is very simple. + +```python +@bot.user_command(name="Account Creation Date", guild_ids=[...]) # create a user command for the supplied guilds +async def account_creation_date(ctx, member: discord.Member): # user commands return the member + await ctx.respond(f"{member.name}'s account was created on {member.created_at}") +``` + + + +
+ + Account Creation Date + +
+ {defaultOptions.profiles.bob.author}'s account was created on 2020-01-01 +
+
+ +## Message Commands + +```python +@bot.message_command(name="Get Message ID") # creates a global message command. use guild_ids=[] to create guild-specific commands. +async def get_message_id(ctx, message: discord.Message): # message commands return the message + await ctx.respond(f"Message ID: `{message.id}`") +``` + + + + Do. Or do not. There is no try. + + +
+ + Get Message ID + +
+ Message ID: 930650407917748286 +
+
+ +
+ +:::info Related Topics + +- [Slash Commands](./slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx new file mode 100644 index 00000000..edac55b3 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx @@ -0,0 +1,56 @@ +--- +title: Localizations +description: Localizations are a way to make your bot more accessible to your users. Learn all about localizations now! +--- + +Localizations are a way to make your bot more accessible to your users. You can localize the command +name, the names of any arguments, and any text that is displayed to the user. + +## Syntax + +```python +@bot.slash_command( + name="ping", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + }, + options=[ + Option( + name="Example", + name_localizations={ + "en-GB": "British Example" + }, + description="Example option that does nothing", + description_localizations={ + "en-GB": "British example option that does nothing" + } + ) + ] +) +async def ping(ctx, example): + responses = {"en-US": "Pong!", + "en-GB": "British Pong!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +@bot.slash_command( + name="ping2", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + } +) +async def ping2(ctx, example: Option(str, "example", name_localizations={"en-GB": "British Example"}, description="Example option that does nothing", description_localizations={"en-GB": "British example option that does nothing"})): + responses = {"en-US": "Pong2!", + "en-GB": "British Pong2!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +``` + +- [`Locales`](https://discord.com/developers/docs/reference#locales) - List of valid locales recognized by Discord diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx new file mode 100644 index 00000000..ed454dad --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx @@ -0,0 +1,292 @@ +--- +title: Slash Commands +description: Learn all about Slash Commands and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On March 24, 2021, Discord added Slash Commands to Discord as an easier, more efficient, and better way of using bot commands. Pycord has implemented Slash Commands into the library, so it's simple, efficient, and familiar. + +:::important + +Remember that Slash Commands require your bot to be invited with the `application.commands` scope or Slash Commands will not show up. Bots already in the guild can simply be invited again with the scope; there is no need to kick the bot. + +::: + +## Syntax + +Let's create a simple Slash Command. + +```py +import discord + +bot = discord.Bot() + +# we need to limit the guilds for testing purposes +# so other users wouldn't see the command that we're testing + +@bot.command(description="Sends the bot's latency.") # this decorator makes a slash command +async def ping(ctx): # a slash command will be created with the name "ping" + await ctx.respond(f"Pong! Latency is {bot.latency}") + +bot.run("TOKEN") +``` + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +Let's go through the code. + +First, we import Pycord's `discord` package. + +Next, we create a [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot) object and assign it to a variable `bot`. + +We then go ahead and use the [`@bot.command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.command) decorator, which registers a new Slash Command. We pass a `description` parameter to give a description to the Slash Command. We can also pass a `name` parameter to change the Slash Command's name. By default, the name of the Slash Command will be the name of the function, in this case, `/ping`. + +We create an async function called `ping` with parameters `ctx`, which, when called, sends the bot's ping/latency using [`ctx.respond`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext.respond). + +## Subcommand Groups + +You might want to group certain commands together to make them more organised. A command group is exactly what it sounds like, a group of individual Slash Commands together. + +In order to make a Slash Command group, you can use the `bot.create_group` function. + +```python +import discord + +bot = discord.Bot() + +# create Slash Command group with bot.create_group +greetings = bot.create_group("greetings", "Greet people") + +@greetings.command() +async def hello(ctx): + await ctx.respond(f"Hello, {ctx.author}!") + +@greetings.command() +async def bye(ctx): + await ctx.respond(f"Bye, {ctx.author}!") + +bot.run("TOKEN") +``` + +Or, you can instead manually make a `SlashCommandGroup` class like so: + +```python +import discord + +math = discord.SlashCommandGroup("math", "Math related commands") + +@math.command() +async def add(ctx, num1: int, num2: int): + sum = num1 + num2 + await ctx.respond(f"{num1} plus {num2} is {sum}.") + +@math.command() +async def subtract(ctx, num1: int, num2: int): + sum = num1 - num2 + await ctx.respond(f"{num1} minus {num2} is {sum}.") + +# you'll have to manually add the manually created Slash Command group +bot.add_application_command(math) +``` + +Here's what the registered subcommands will look like in the Slash Command Menu: + +![Picture of the subcommands in the Slash Command Menu](../../assets/interactions/groups-and-subcommands.jpg) + +You'll notice that there's the name of the Slash Command Group and then the name of the subcommand separated by a space. + +::: + +:::info Cogs + +If you are looking to add Slash Command Groups to cogs, please look at our [Cogs page](../../popular-topics/cogs)! + +::: + +## Sub-groups + +We've made a subcommand group, but did you know that you could create a group inside another? + +```python +from discord import SlashCommandGroup +from math import sqrt + +math = SlashCommandGroup("math", "Math related commands") +advanced = math.create_subgroup("advanced", "Advanced math commands") + +@advanced.command() +async def square_root(ctx, x: int): + await ctx.respond(sqrt(x)) + +bot.add_application_command(math) +``` + +The command created above can be invoked by typing `/math advanced square_root`. + +## Options & Option Types + +Whenever you're using Slash Commands, you might notice that you can specify parameters that the user has to set or can optionally set. These are called Options. + +Options can also include a description to provide more information. [You can learn more about Options in our documentation!](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.Option) + +Since you want different inputs from Options, you'll have to specify the type for that Option; there are a few ways of doing this. + + + + +You could use Type Annotations and let Pycord figure out the option type or explicitly specified using the [`SlashCommandOptionType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.SlashCommandOptionType) enum. + +```python +import discord + +bot = discord.Bot() + +@bot.command() +# pycord will figure out the types for you +async def add(ctx, first: discord.Option(int), second: discord.Option(int)): + # you can use them as they were actual integers + sum = first + second + await ctx.respond(f"The sum of {first} and {second} is {sum}.") + +@bot.command() +# this explicitly tells pycord what types the options are instead +async def join( + ctx, + first: discord.Option(discord.SlashCommandOptionType.string), + second: discord.Option(discord.SlashCommandOptionType.string) +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + add + +
+ The sum of 1 and 1 is 2. +
+ +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+ + +Instead of Type Annotations, you can also use the option decorator. This is usually done to have type-hinting. + +```python title="Slash Command Type" +import discord + +bot = discord.Bot() + +@bot.command() +@discord.option("first", type=discord.SlashCommandOptionType.string) # type = str also works +@discord.option("second", type=discord.SlashCommandOptionType.string) # type = str also works +async def join( + ctx, + first: str, + second: str, +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+
+ +## Autocomplete + +Discord's autocomplete allows developers to determine option choices that are used in a slash command option. You can do this by defining a function: + +```py +async def get_animal_types(ctx: discord.AutocompleteContext): + """ + Here we will check if 'ctx.options['animal_type']' is a marine or land animal and return respective option choices + """ + animal_type = ctx.options['animal_type'] + if animal_type == 'Marine': + return ['Whale', 'Shark', 'Fish', 'Octopus', 'Turtle'] + else: # is land animal + return ['Snake', 'Wolf', 'Lizard', 'Lion', 'Bird'] + +@bot.slash_command(name="animal") +async def animal_command( + ctx: discord.ApplicationContext, + animal_type: discord.Option(str, choices=['Marine', 'Land']), + animal: discord.Option(str, autocomplete=discord.utils.basic_autocomplete(get_animal_types)) +): + await ctx.respond(f'You picked an animal type of `{animal_type}` that led you to pick `{animal}`!') +``` + + + +
+ + animal + +
+ You picked an animal type of Marine that led you to pick Shark! +
+
+ +:::warning + +Autocomplete can **only** be used with slash commands. + +::: + +:::info Related Topics + +- [Interactions Index](../../interactions) +- [Rules and Common Practices](../../getting-started/rules-and-common-practices) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/interactions/index.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/index.mdx new file mode 100644 index 00000000..8603437f --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/index.mdx @@ -0,0 +1,242 @@ +--- +title: Discord Interactions +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +In December 2020, Discord released their first Interaction: the +[Slash Command](https://discord.com/developers/docs/interactions/application-commands#slash-commands). +Since then, Discord has added many types of Interactions, including: + +[**Application Commands**](https://discord.com/developers/docs/interactions/application-commands) + +- [**Slash Commands**](https://discord.com/developers/docs/interactions/application-commands#slash-commands): + Commands that can be used with the `/` prefix. +- **Context Menu Commands**: Commands that can be used from the right-click menu. + - [**User Commands**](https://discord.com/developers/docs/interactions/application-commands#user-commands): + Commands that can be used on a user by alt-clicking/selecting them. + - [**Message Commands**](https://discord.com/developers/docs/interactions/application-commands#message-commands): + Commands that can be used on a message by alt-clicking/selecting it. + +[**UI Components**](https://discord.com/developers/docs/interactions/message-components) + +- [**Buttons**](https://discord.com/developers/docs/interactions/message-components#buttons): + Buttons are attached to a message and can be clicked on to perform an action. +- [**Select Menus**](https://discord.com/developers/docs/interactions/message-components#select-menus): + Drop-down menus are used to select a number of options from a list. +- [**Modals**](https://discord.com/developers/docs/interactions/message-components#text-inputs): + Form-like modals can be used to ask for input from a user. + +## Application Commands + +Application Commands are another set of new features that are intended to avoid compromising users' safety and privacy. +They're relatively easy to add to your bot, and give people a simpler and safer way to use commands. + +### [Slash Commands](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.SlashCommand) + +Slash Commands were the first Interaction added to Discord. They're easy to use and create, and +is the only prefix commands alternative that does not need Message Content intent. + +:::note + +Preferring prefix commands over Application Commands is **not** a valid reason to apply for the +Message Content intent. Using that as a reason will get your application denied. + +::: + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +This is what a Slash Command looks like. Not too different from a prefix command, +apart from the note telling you who invoked it. A Slash Command's fields can accept any of the following: + +- Members +- Roles +- Channels +- Attachments +- Text + +Just about as good as it gets. + +### [Message](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.MessageCommand) and [User](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.UserCommand) Commands + +Message Commands and User Commands were both introduced at around the same time, and are very similar to each other, so we'll be +introducing them together. These commands can be found in the `Apps` tab when alt-clicking. The only difference between the two is that +Message Commands only appear in the `Apps` tab of a message, while User Commands are found in the `Apps` tab of a user. Message Commands +can be used to quickly report a message, warn a user for a message, and other functions. Likewise, User Commands can be used to add a +user to a ticket, warn a user, and more. + +Here's an example of a Message Command: + + + + Hello World! + + +
+ + Reverse Message + +
+ Message 930650407917748286 reversed is "!dlroW olleH" +
+
+ +
+ +And here's an example of a User Command: + + + + {defaultOptions.profiles.dorukyum.author} has been on Discord for a long time + + +
+ + User Age + +
+ {defaultOptions.profiles.dorukyum.author} is 1 week old. +
+ +
+ + User Age + +
+ {defaultOptions.profiles.bob.author} is 40 years old. +
+ + 🤔 + +
+ +
+ +Pretty cool, right? To learn more about these two, please read the [Context Menus guide](./application-commands/context-menus.mdx). + +## [Application Commands](#application-commands) vs. [Prefix Commands](../extensions/commands/prefixed-commands) + +Ever since Discord was created, apps on it have used prefix commands. Using prefixes meant that you would have to put a +certain character (or string of characters) in front of your command, such as the exclamation mark in `!ping`. The way this +worked was that your bot would listen for messages, pick out the ones that had their specific prefix, and then respond to the command. +Now, Discord is encouraging developers to switch their bots over to Application Commands, which is a new system meant to preserve the +privacy and safety of their users. But why exactly is Discord making us switch? What's the better option, Application Commands or prefix +commands? Below, we'll discuss everything you need to know. + +### Discord's Decision + +Application Commands were conceptualized partly due to privacy concerns. When Discord first began, they weren't entirely concerned about bots +having access to the content of every message that was being sent. However, as Discord grew, this became more of a problem. Hypothetically, bots +could simply log every message they're able to receive via the Discord API and hand their contents over to a company or other third party. This is +a problem, since that data is meant to be used only by Discord. As such, they locked down Message Content, and introduced Application Commands for +bot developers to use instead. + +Prefix commands work by reading messages, as described before. Application Commands, however, don't +work this way; instead, they work by having your bot get information from Discord about when a command was used. This way, Discord can limit +Message Content only to bots that _absolutely_ depend on it, such as auto-moderation bots. + +### Who has to Use Application Commands + +Any verified bot that does not have the Message Content intent must use Application Commands. Discord is allowing developers to submit +applications for the ability to use the intent; however, since they don't want to keep supporting prefix commands due to privacy concerns, +they will automatically decline any application that includes only that as a reason. So, if your bot doesn't have an auto-moderation feature +(or any other functionality that requires Message Content), you're out of luck. + +Unverified bots, however, don't have to use Application Commands. This is because the Message Content intent is a `Privileged Intent`, meaning that +it must be applied for only if your bot is verified or about to be verified. Unverified bots don't have to apply for Privileged Intents, so they can +use them freely. + +So, if your bot is made only for a couple of servers, you can choose between prefix commands and Application Commands. However, if you plan on expanding +your bot's reach, it'll have to use Application Commands. + +### What's the Better Option + +Choosing which is the better option is up to you, if you're starting small. If +you plan on growing your bot, however, you will have to use Application Commands. Since prefix commands are slowly being phased out by Discord, +there isn't much of a choice for developers of larger bots. + +## Message Components + +Message Components are fairly new features in Discord, allowing developers to give their bots a fast +and understandable user interface. Message Components are easy to use and make your bot look modern, +sleek, and downright awesome. + +### [Views](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View) + +Views are not an Application Command nor are they a Message Component. Views are the invisible placeholders, or grid, +that Message Components lie in. Views can have up to 5 [`Action Rows`](https://docs.pycord.dev/en/stable/api/models.html#discord.ActionRow), +and Action Rows can have a maximum of 5 slots. Below, you can find a table showing how many slots a Message Interaction takes up. + +| Component | Slots | +| ------------ | ----------------------------------------------- | +| Buttons | 1 Slot | +| Select Menus | 5 Slots | +| Text Modals | 1 Slot (opened via a Button) | + +So, based on this, you could have a maximum of 25 Buttons in a View with no Select Menus, and 5 Select +Menus in a View with no Buttons. This doesn't mean you can't have them both in a View, however. You can have +a combination of them, such as 20 Buttons and a Select Menu or 10 Buttons and 3 Select Menus. + +### [Buttons](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button) + +Buttons are the first of the Message Components. They allow for quick responses to prompts, such as for canceling or continuing an action. +Of course, these aren't their only uses; people have created awesome things with Buttons, such as calculators, games, and more! + + + + Discord Buttons are awesome! +
+ + Click me! + +
+
+
+ +
+ +This is what a Button looks like, very simple and modern. To learn more about Buttons, refer to our +[Buttons page](./ui-components/buttons.mdx). + +### [Select Menus](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Select) + +Select Menus are the second of Discord's Message Components. They allow users to select from a list of choices, which your bot can then use. +Select Menus are good for things such as choosing features, pages of a help menu, and more. + +![Select Menu Example Image](../assets/interactions/select-menus-example.png) + +This is what a Select Menu looks like. While not looking as good as Buttons, they still look great +and have even greater possibilities. To learn more about Select Menus, please refer to our [Select +Menus page](./ui-components/dropdowns.mdx). + +### [Modal Dialogs](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal) + +Text Modals are the most recently added Message Component in Discord. They're useful for text input and filling out forms, such as a +sign-up for your bot's service. These are meant to replace long bot setup processes by allowing users to fill out multiple text fields, +which avoids having the user send multiple messages for the bot. Modals can be accessed by either invoking an Application Command or by +interacting with another UI Component. + +![Text Modal Example Image](../assets/interactions/modal-example.png) + +This is what a Text Modal looks like, easy to use and one of the most useful Message Components yet. To learn more about Text Modals, +please visit our [Modal Dialogs page](./ui-components/modal-dialogs.mdx). diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json new file mode 100644 index 00000000..7b0a72fe --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "UI Components", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx new file mode 100644 index 00000000..046b36c7 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx @@ -0,0 +1,314 @@ +--- +title: Buttons +description: Learn all about implementing buttons in your Discord Bot using Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On May 26, 2021, Discord added a new interaction called buttons. Instead of reactions, bots could now +send buttons and users could use them to interact with bots. This opened up a whole new world of +possibilities for bots. Soon after, developers made calculators, polls, and games like blackjack, UNO, +and even Minecraft! Buttons provided a clear and easy to use interface for interacting with bots. + +So, let's learn how you can add buttons to your bot! + +## Concept + +Buttons weren't the only update to the interactions system in Discord. Discord also added [Select Menus](./dropdowns) and [Modal Dialogs](./modal-dialogs), both of which work very similarly to buttons. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive button. + +```python +import discord + +bot = discord.Bot() # Create a bot object + +class MyView(discord.ui.View): # Create a class called MyView that subclasses discord.ui.View + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.primary, emoji="😎") # Create a button with the label "😎 Click me!" with color Blurple + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") # Send a message when the button is clicked + +@bot.slash_command() # Create a slash command +async def button(ctx): + await ctx.respond("This is a button!", view=MyView()) # Send a message with our View class that contains the button + +bot.run("TOKEN") # Run the bot +``` + +Using this command should return the following message: + + + +
+ + button + +
+ This is a button! +
+ + Click me! + +
+
+
+ +
+ +As you can see, we create a class called `MyView` that [subclasses](#oop) +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `button_callback` to the `MyView` class with the decorator +[`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button). +This decorator adds a button to a component. This function takes two arguments: the button that was +clicked and the interaction. These arguments are passed to the function when the button is clicked +by the module. We use the [`interaction.response.send_message`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse.send_message) +function to send a message to the channel where the interaction was sent. + +Finally, we create a global slash command called `button` that sends the message, along with the view +that contains a button. + +This is the basic syntax of creating a button. What you create with it is up to you. You can worry +about making your button do amazing things, while Pycord handles the rest! + +## Button Styles + + + +| Name | Usage | Color | +| --------- | ----------------------------------------------------------------------------------------- | ------- | +| Primary | `discord.ButtonStyle.primary` / `discord.ButtonStyle.blurple` | Blurple | +| Secondary | `discord.ButtonStyle.secondary` / `discord.ButtonStyle.grey` / `discord.ButtonStyle.gray` | Grey | +| Success | `discord.ButtonStyle.success` / `discord.ButtonStyle.green` | Green | +| Danger | `discord.ButtonStyle.danger` / `discord.ButtonStyle.red` | Red | +| Link | `discord.ButtonStyle.link` / `discord.ButtonStyle.url` | Grey | + +Check out the [`discord.ButtonStyle`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ButtonStyle) class for more information. + +![Different Button Styles](../../assets/interactions/button-styles.png) + +You can set a button's style by adding the `style` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) decorator. + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.success) + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots, and each button takes up 1 slot. +So, how do we move the buttons to another row? + +This can be done by specifying the `row` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) +decorator. + +:::info The `row` argument + +The row argument specifies the relative row this button belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=1, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") +``` + +## Disabling Buttons + +### Pre-Disabled Buttons + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary, disabled=True) # pass `disabled=True` to make the button pre-disabled + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView()) +``` + +### Disabling Buttons on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + button.disabled = True # set button.disabled to True to disable the button + button.label = "No more pressing!" # change the button's label to something else + await interaction.response.edit_message(view=self) # edit the message's view +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(emoji="😀", label="Button 1", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) + + @discord.ui.button(label="Button 2", style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +Sometimes, you want to have a button that is disabled after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView(timeout=30)) +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a button that is disabled after a certain amount of time, you want to have a +button that is always working. + +Normally, when the bot goes offline, all of its buttons stop working. You will be able to see the +buttons, but nothing will happen when you press them. This is a problem +if you are trying to create a self-role system with buttons, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons will stop working. When the bot comes back online, however, the buttons will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view must have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.button(label="A button", custom_id="button-1", style=discord.ButtonStyle.primary, emoji="😎") # the button has a custom_id set + async def button_callback(self, button, interaction): + await interaction.response.send_message("Button was pressed", ephemeral=True) + +@bot.command() +async def button(ctx): + await ctx.send(f"Press the button! View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many buttons can I have in a message? + +Each message can have a maximum of 25 buttons. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do buttons need any special permissions? + +No new permissions are needed for either the bot or the server to allow bots to use buttons. + +#### Should I replace reactions with buttons for my bot? + +That is up to you. Buttons do provide a cleaner interface for your bot and are easier to use. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx new file mode 100644 index 00000000..8320f25d --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx @@ -0,0 +1,339 @@ +--- +title: Select Menus +description: Learn all about implementing Select Menus or Dropdowns in your Discord Bot with Pycord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Shortly after the buttons were added, Discord added their second message component: Select Menus. Select Menus allow users to choose from a list of items sent by a bot. These are a great substitute for having a user send a number that corresponds to an option. You can even allow users to select multiple options from the Select Menus. This guide will show you the easy and painless ways of using them with Pycord. + +## Concept + +Select Menus aren't the only message component in Discord. There's also [Buttons](./buttons) and [Modal Dialogs](./modal-dialogs). Select Menus make it easy for users to pick one or multiple options from a list provided by a bot. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive select menu. + +```python +import discord + +bot = discord.Bot() + +class MyView(discord.ui.View): + @discord.ui.select( # the decorator that lets you specify the properties of the select menu + placeholder = "Choose a Flavor!", # the placeholder text that will be displayed if nothing is selected + min_values = 1, # the minimum number of values that must be selected by the users + max_values = 1, # the maximum number of values that can be selected by the users + options = [ # the list of options from which users can choose, a required field + discord.SelectOption( + label="Vanilla", + description="Pick this if you like vanilla!" + ), + discord.SelectOption( + label="Chocolate", + description="Pick this if you like chocolate!" + ), + discord.SelectOption( + label="Strawberry", + description="Pick this if you like strawberry!" + ) + ] + ) + async def select_callback(self, select, interaction): # the function called when the user is done selecting options + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") + +@bot.command() +async def flavor(ctx): + await ctx.respond("Choose a flavor!", view=MyView()) + +bot.run("TOKEN") +``` + +There's a lot going on over here! Don't worry, we will go over the code and explain it. + +As you can see, we create a class called `MyView` that subclasses +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `select_callback` to the `View` class with the decorator +[`discord.ui.select`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.select). +This decorator adds a select menu to the view. This decorator takes a few arguments to customize your select menu. Read them in the [Customization section](#customization). + +That was the decorator. Now, the function itself is pretty simple. It takes two parameters, not including `self`. The parameters are `select`: The select menu, and `interaction`: a [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object. Both of these are passed by Pycord, so you just need to specify them in the function! + + + +In the callback, you could do anything you want. You get the two parameters `select` and `interaction` to play around with. Here, we send a message using `await interaction.response.send_message` (where interaction is [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse)) with content `select.values[0]`, which sends the label of the first/only option the user selected. Obviously, this is only an example, and you could do just about anything you want. + +Finally, we create a global slash command called `flavour` that sends a message "Choose a flavor!" along with the view +that contains our select menu. + +This is the basic syntax of creating a select menu. What you create with it is up to you. You can worry +about making your code do amazing things, while Pycord handles the rest! + +## Customization + +#### Select Menu Properties + +- `select_type`: The type of select to create. This must be a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. +- `channel_types`: A list of channel types that can be selected in the menu. This is only valid for selects of `select_type` [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType). +- `options`: A list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. These are the options that can be selected in this menu. +- `placeholder` is the placeholder text shown in the select menu if no option is selected. +- `custom_id`: The ID of the select menu that gets received during an interaction. It is recommended not to set this to anything unless you are trying to create a persistent view. +- `row`: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). +- `min_values`: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `max_values`: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `disabled`: Whether the select is disabled or not. Defaults to False. + +#### Select Option Properties + +In the `options` parameter, you pass a list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. This class also has a few parameters: + +- `default` (whether the option is selected by default) +- `description` (an additional description, if any) +- `emoji` (a string or an emoji object, if any) +- `label` (the name displayed to users, can be up to 100 characters) +- `value` (a special value of the option, defaults to the label). + +## Select Types + +In addition to regular string selects, you can also have your select menu contain users, roles, mentionables, and channels as its options. You can use these alternative select types by passing a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value for the `select_type` parameter when creating the Select. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.user_select + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +Additionally, you can use shortcut decorators to create a [`discord.ui.Select`](https://docs.pycord.dev/en/master/api/ui_kit.html#discord.ui.select) with a predetermined [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. Using a shortcut decorator, the above code can be rewritten like this: + +```python +class MyView(discord.ui.View): + @discord.ui.user_select() + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +### Specifying Channel Types + +When using a [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType.channel_select) type select menu, you can pass in a list of [`discord.ChannelType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ChannelType) values to limit which types of channels users can choose when interacting with the select menu. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.channel_select, + channel_types=[discord.ChannelType.text, discord.ChannelType.voice] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"You selected {select.values[0].mention}") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots. A button takes a single slot, while a select menu takes up all 5 of them. This means a view can have a maximum of 5 select menus, or any possible combination of select menus and buttons. + +The arrangement of buttons and select menus is generally adjusted by Pycord. However, it is possible to move them to specific relative rows. This is done by specifying the `row` argument. + +:::info The `row` argument + +The row argument specifies the relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero-indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=0, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.select( + row = 1, + options = [...] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") +``` + +## Disabling Select Menus + +### Pre-Disabled Menus + +```python +class MyView(discord.ui.View): + @discord.ui.select( + disabled = True, # pass disabled=True to set the menu as disabled + options = [...] + ) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send("Select and option from the menu!", view=MyView()) +``` + +### Disabling Menus on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + select.disabled = True # set the status of the select as disabled + await interaction.response.edit_message(view=self) # edit the message to show the changes +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def first_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) # edit the message to show the changes + + @discord.ui.select(options = [...]) + async def second_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +You may want a select menu to automatically stop working after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select(ctx): + await ctx.send(view=MyView(timeout=30)) # specify the timeout here +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a select menu that is disabled after a certain amount of time, you want to have a +select menu that is always working. + +Normally, when the bot goes offline, all of its views stop working, even if they don't have a timeout. You will be able to see the +views, but nothing will happen when you try to interact with them. This is a problem +if you are trying to create a self-role system, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons and select menus will stop working. However, when the bot comes back online, the buttons and select menus will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view much have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.select(custom_id="select-1", options = [...]) # a custom_id must be set + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send(f"View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many select menus can I have in a message? + +Each message can have a maximum of 5 select menus. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do select menus need any special permissions? + +No new permissions are needed in the bot or in the server. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx new file mode 100644 index 00000000..bd585c77 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx @@ -0,0 +1,107 @@ +--- +title: Modal Dialogs +description: Learn how you can implement Modals in your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Modal Dialogs, also known as "modals", provide a form-like structure for bots to receive input from users. No extra permissions are needed for bots to send modal dialogs, so it becomes a convenient workaround for bots to receive longer input without needing the Message Content [intent](../../popular-topics/intents). + +## Concept + +Modal Dialogs consist of a title, custom ID, and up to 5 [`discord.ui.InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) components. While creating modals, we generally subclass [`discord.ui.Modal`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal), as we'll see later. + +Unlike other UI Components, Modals cannot be sent with messages. They must be invoked by an Application Command or another UI Component. + +## Usage Syntax + +```py +class MyModal(discord.ui.Modal): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.add_item(discord.ui.InputText(label="Short Input")) + self.add_item(discord.ui.InputText(label="Long Input", style=discord.InputTextStyle.long)) + + async def callback(self, interaction: discord.Interaction): + embed = discord.Embed(title="Modal Results") + embed.add_field(name="Short Input", value=self.children[0].value) + embed.add_field(name="Long Input", value=self.children[1].value) + await interaction.response.send_message(embeds=[embed]) +``` + + + + +The `ctx` parameter we define in Application Commands receives an [`ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext) object. Using its `send_modal()` coroutine, you can send a Modal dialog to the user invoking the Application Command. + +```py +@bot.slash_command() +async def modal_slash(ctx: discord.ApplicationContext): + """Shows an example of a modal dialog being invoked from a slash command.""" + modal = MyModal(title="Modal via Slash Command") + await ctx.send_modal(modal) +``` + + + + +The `interaction` parameter we define in UI Components receives an [`Interaction`](https://docs.pycord.dev/en/stable/api/models.html#discord.Interaction) object. The `response` attribute of the object contains an [`InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object, with various coroutines such as `send_message()` and `send_modal()`, which we utilize. + +```py +class MyView(discord.ui.View): + @discord.ui.button(label="Send Modal") + async def button_callback(self, button, interaction): + await interaction.response.send_modal(MyModal(title="Modal via Button")) + +@bot.slash_command() +async def send_modal(ctx): + await ctx.respond(view=MyView()) +``` + + + + +The above example uses an embed to display the results of the modal submission, but you can do anything you want with the text provided by the user. +Each input field can be accessed in the order it was added to the modal dialog, via `Modal.children`. + +## Customization + +A Modal can have up to 5 [`InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) fields. These fields offer some customization. + +Each field has a label which is shown to the user. This is defined with `label`. + +The `style` parameter is used to determine whether it should be a short (single-line) or long (multi-line) input field. + +There are a number of aliases that can be used: + +```x title="Single-line InputTextStyle values:" +short +singleline +``` + +```x title="Multi-line InputTextStyle values:" +paragraph = 2 +multiline = 2 +long = 2 +``` + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Buttons](./buttons) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/introduction.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/introduction.mdx new file mode 100644 index 00000000..3262c632 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/introduction.mdx @@ -0,0 +1,50 @@ +--- +title: Introduction +description: Pycord Guide is a complete guide for Pycord. Learn how to create Discord Bots today! +sidebar_position: 1 +--- + +Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord, written in Python. Pycord is a maintained fork of [discord.py](https://github.com/Rapptz/discord.py). + +## Before you begin + +Pycord is an advanced and complex Python library. To take advantage of the full capabilities of Pycord, you will need to have a good understanding of Python. You should know the basics of Python and have an understanding of the following concepts: + +- Variables +- Data Types +- Functions +- Packages +- Conditionals +- Loops +- Classes +- Object-Oriented Programming +- Inheritance +- Exception Handling +- Iterators +- Coroutines +- Async/Await + +This list is not exhaustive, but it should give you a good idea of what you need to know to get started. + +When you see an ellipsis - that's the three dots - in this guide, it is a placeholder for code that you need to fill in. Sometimes, it may be code for a command, while other times it could be something simple like a Guild ID. Make sure to replace them before running your bot! + +## Learning Resources + +Here are some good resources to get started or to freshen up your Python knowledge: + +- [Official Beginner's Guide](https://wiki.python.org/moin/BeginnersGuide) +- [Official Tutorial](https://docs.python.org/3/tutorial/) +- [Automate the Boring Stuff, a free online book for complete beginners to programming](https://automatetheboringstuff.com/) +- [Learn Python in y Minutes, complete cheat sheet for people who know programming already](https://learnxinyminutes.com/docs/python3/) +- [Swaroopch's free Python book](http://python.swaroopch.com/) +- [Codeabbey, exercises for beginners](http://www.codeabbey.com/) + +## Credits + +First of all, we would like to thank [Rapptz](https://github.com/Rapptz) for the original [discord.py](https://pypi.org/project/discord.py) library. Pycord is a maintained fork of this library. + +We would also like to thank the [discord.js guide](https://discordjs.guide), which inspired this guide style-wise, and the [original Pycord Guide](https://namantech.me/pycord), which inspired some content in this guide. + +We created this guide using [Docusaurus v2](https://docusaurus.io), a modern static site generator for React. We would also like to thank Danktuary for his [`@discord-message-components/react`](https://www.npmjs.com/package/@discord-message-components/react) package, from which we took the Discord message components. + +And finally, we would like to thank the amazing and loving community of Pycord users, contributors and developers. diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/more/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/more/_category_.json new file mode 100644 index 00000000..2cbe2c56 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/more/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 8, + "label": "More", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/more/community-resources.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/more/community-resources.mdx new file mode 100644 index 00000000..ed3075bd --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/more/community-resources.mdx @@ -0,0 +1,23 @@ +--- +title: Community Resources +--- + +This page showcases the amazing things created by the Pycord community, including bots, Plugins, and more. + +## Plugins + +| Name | Type | GitHub | +| --------------- | ------------ | --------------------------------------------------------------- | +| Music Cord | Music | [NixonXC/cord-music](https://github.com/NixonXC/cord-music) | +| pycord-i18n | Localization | [Dorukyum-pycord-i18n](https://github.com/Dorukyum/pycord-i18n) | +| pycord-multicog | Cogs | [pycord-multicog](https://github.com/Dorukyum/pycord-multicog) | +| EzCord | Utilities | [EzCord](https://github.com/tibue99/ezcord) | + +## Bots + +| Name | Type | Link | +| ------------------------ | ------------ | ----------------------------------------------------------------------------------- | +| Discord-Multipurpose-Bot | Multipurpose | [github](https://github.com/pogrammar/Discord-multipurpose-bot/tree/master/Python) | +| inconnu | Fun & QOL | [github](https://github.com/tiltowait/inconnu) | +| Mai | Multipurpose | [github](https://github.com/TeamMai/Mai) & [website](https://xfghoul.github.io/Mai) | +| Toolkit | Multipurpose | [github](https://github.com/Dorukyum/Toolkit) | diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/more/contributing.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/more/contributing.mdx new file mode 100644 index 00000000..469ea3ee --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/more/contributing.mdx @@ -0,0 +1,463 @@ +--- +title: Contributing to the Guide +description: Learn how to contribute to the Pycord Guide. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +This page outlines some of the basic syntax you need to know to contribute to the guide. We recommend you also check out: + +- [Docusaurus's Docs](https://docusaurus.io/docs/) +- [Contributing Rules](https://github.com/Pycord-Development/guide/blob/master/.github/CONTRIBUTING.md) + +## Info + +We use [Docusaurus v2](https://docusaurus.io/) to generate our guide. All the guide pages are generated +from `mdx` files in the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory. +MDX allows you to use JSX in your markdown content. + +## Structure + +Let's visit the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory and check its file structure. + +We can see various folders and a few files in it. Let's talk a bit about the `introduction.mdx` file. At the top, you can see something like: + +```md +--- +title: Introduction +description: ... +sidebar_position: 1 +--- +``` + +Most pages have this at the top. The `title` defaults to the file name. Since the titles need to be Capitalized according to need while the file names are lowercased (sometimes, the file names are shorter than the title!), we set a title ourselves. + +The `description` field is also important. This is the text shown in an embed when the page's link is shared on Discord, Twitter or other websites that support embedded links. Make sure to give a nice an interesting description! + +The `sidebar_position` field is pretty self-explanatory. It sets the position of the page in the sidebar. Most files in categories do not need this since they are sorted alphabetically. + +## Markdown Syntax + +This page quickly outlines some of the syntax that is used in markdown. + +````mdx +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + + ```python + print("We can use code blocks like this.") + ``` + +You can add [links to other websites](https://pycord.dev). You can add images like this: ![alternate text that describes the image](https://pycord.dev/image.png). + +- You can create +- unordered lists like this + +1. Or ordered lists +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` +4. Like this + +# Headers + +## Go + +### Like + +#### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet +```` + +
+Preview +
+ +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + +```python +print("We can use code blocks like this.") +``` + +You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](@site/static/img/favicon.ico). + +- You can create +- unordered lists like this + +1. Or ordered lists + +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` + +4. Like this + + # Headers + + ## Go + + ### Like + + #### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet + +
+
+ +## Admonitions + +We can add warnings, notes, etc. with the following syntax: + +```md +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: +``` + +
+Preview +
+ +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: + +
+ +
+ +## Discord Message Components + +As most files already have the imports for these, it's not that hard to add them. + +First, import the necessary components: + +```tsx +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; +``` + +The div starts like so: + +```tsx + + + + +
+``` + +This is where you list a `DiscordMessage`. + +```tsx + + + Hello! + + + +
+``` + + + + Hello! + + + +
+ +It has a pretty straightforward syntax. + +:::tip + +Add a `
` to the end of a component to make the content below it look better. + +::: + +### Slash Commands + +To make a message authored by a slash command, do the following: + +```tsx + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+``` + + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+ +### Buttons + +To make a message with buttons, do the following: + +```tsx + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+``` + + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+ +## Page Format + +There are a few things you need to take care of: + +1. Make sure that the spelling and grammar is perfect. We have a GitHub action configured that will warn you about spelling errors when you start a pull request. Make sure to commit your changes accordingly. + + As for the grammar, you should try reading the changes you have done and wait for reviews from others. + +2. A common mistake people make is incorrect header style. People often think that the less the important the topic is, the lower it's heading style should be. + + ```md + [PAGE STARTS] + # Topic + ## Less Important Topic + ## Subtopic + ``` + + ```md + [PAGE STARTS] + # About + [Introduction] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + That's VERY wrong. Here's the correct example: + + ```md + [PAGE STARTS] + [Introduction] + ## Topic + ## Less Important Topic + ### Subtopic + ``` + + ```md + [PAGE STARTS] + [Introduction] + + ## About + [More Information] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + Note that the `---`s at the beginning have been skipped here. diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/more/git.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/more/git.mdx new file mode 100644 index 00000000..0f929d6d --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/more/git.mdx @@ -0,0 +1,55 @@ +--- +title: Installing Git +description: Learn how you can install Git on your system. +--- + +Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Let's see how to install Git on different platforms. + +## Windows + +On Windows, Git can be installed via: + +- [Git for Windows](https://gitforwindows.org) +- [Git Scm](https://git-scm.com/download/windows) + +## Linux + +On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. + +## Mac + +You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: + +``` +xcode-select --install +``` + +## Using Package Managers + +You can also install Git using package managers. + +### Chocolatey + +If you use the Chocolatey package manager, you can install Git using: + +``` +choco install git +``` + +### Scoop + +If you use Scoop, you can install Git using: + +``` +scoop install git +``` + +### Brew + +If you're on macOS or Linux, you can install Git using: + +``` +brew install git +``` diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx new file mode 100644 index 00000000..b0b8c7ea --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx @@ -0,0 +1,62 @@ +--- +title: Virtual Environments +description: Learn how to set up a virtual environment for Pycord. +--- + +## Setup + +Sometimes you want to keep libraries from polluting system installs or use a different version of libraries than the ones installed on the system. You might also not have permissions to install libraries system-wide. For this purpose, the standard library as of Python 3.3 comes with a concept called “Virtual Environment”s to help maintain these separate versions. + +A more in-depth tutorial is found on [Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html). + +However, for the quick and dirty: + +Go to your project’s working directory: + +```bash +$ cd your-bot-source +$ python3 -m venv venv +``` + +Activate the virtual environment: + +```bash +$ source venv/bin/activate +``` + +On Windows you activate it with: + +```batch +$ venv\Scripts\activate.bat +``` + +Use pip like usual: + +```bash +$ pip install -U py-cord +``` + +Congratulations. You now have a virtual environment all set up. + +## Additional info + +It can be useful to set up a requirements.txt, so you can just put all of your dependencies in there and have pip install it. +For instance, if you wanted to have the latest 2.0 version of pycord and [pytz](https://github.com/stub42/pytz/blob/master/src/README.rst), just create a file named requirements.txt with the following contents: + +``` +py-cord>=2.0.0 +pytz +``` + +And then (in your virtual environment) you can just execute + +```bash +pip install -r requirements.txt +``` + +To keep from committing your virtual environment to git, you can set up a .gitignore file with the following line +(assuming you named your virtual environment venv like the above example): + +``` +venv/ +``` diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/_category_.json new file mode 100644 index 00000000..c38ea014 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 7, + "label": "Popular Topics", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx new file mode 100644 index 00000000..5377a6c3 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx @@ -0,0 +1,140 @@ +--- +title: Cogs +--- + +Cogs, often known as modules or extensions, are used to organize commands into groups. This is useful +for grouping commands that have the same general idea (such as moderation commands). This also helps +to avoid making your bot's files messy and cluttered. + +## Getting Started + +First, you'll need to create a folder to store your cogs, e.g. `cogs/`. + +Then, create a file inside the folder, e.g. `cogs/greetings.py`. By convention, the file name should +be the same as the name of the cog or module. + +We can then create the cog. + +```python title="./cogs/greetings.py" +import discord +from discord.ext import commands + +class Greetings(commands.Cog): # create a class for our cog that inherits from commands.Cog + # this class is used to create a cog, which is a module that can be added to the bot + + def __init__(self, bot): # this is a special method that is called when the cog is loaded + self.bot = bot + + @commands.command() # creates a prefixed command + async def hello(self, ctx): # all methods now must have both self and ctx parameters + await ctx.send('Hello!') + + @discord.slash_command() # we can also add application commands + async def goodbye(self, ctx): + await ctx.respond('Goodbye!') + + @discord.user_command() + async def greet(self, ctx, member: discord.Member): + await ctx.respond(f'{ctx.author.mention} says hello to {member.mention}!') + + math = discord.SlashCommandGroup("math", "Spooky math stuff") # create a Slash Command Group called "math" + advanced_math = math.create_subgroup( + "advanced", + "super hard math commands!" + ) + + @math.command() + async def add(self, a: int, b: int): + c = a + b + await ctx.respond(f"{a} + {b} is {c}.") + + @advanced_math.command() + async def midpoint(self, x1: float, y1: float, x2: float, y2: float): + mid_x = (x1 + x2)/2 + mid_y = (y1 + y2)/2 + await ctx.respond(f"The midpoint between those coordinates is ({mid_x}, {mid_y}).") + + @commands.Cog.listener() # we can add event listeners to our cog + async def on_member_join(self, member): # this is called when a member joins the server + # you must enable the proper intents + # to access this event. + # See the Popular-Topics/Intents page for more info + await member.send('Welcome to the server!') + +def setup(bot): # this is called by Pycord to setup the cog + bot.add_cog(Greetings(bot)) # add the cog to the bot +``` + +You can add any number of commands to your cog, as well as event listeners. However, this code will +not work on its own. In your main bot file, you must add the following code: + +```python +bot.load_extension('cogs.greetings') +``` + +This loads the file `cogs/greetings.py` and adds it to the bot. +The argument of `load_extension` should be your cog's path (e.g. cogs/greetings.py) without the file +extension and with the `/` replaced with `.` + +If you have multiple cogs, you can add them all at once by adding the following code: + +```python +cogs_list = [ + 'greetings', + 'moderation', + 'fun', + 'owner' +] + +for cog in cogs_list: + bot.load_extension(f'cogs.{cog}') +``` + +## Cog Rules + +When using a cog instead of the main file, there are some changes you have to make to your code. This +is because cogs work slightly different from a regular file. + +### The `self` variable + +The self variable is a variable that represents a class. In the case of cogs, `self` represents +the cog. In the `__init__` function, you can see that we have `self.bot = bot`. `bot` represents your +`discord.Bot` or `discord.ext.commands.Bot` instance, which is used for some functions. + +This means that instead of using functions that would usually be accessed via `bot`, you now need +to access them via `self.bot` + +Because we're in a class, all of our commands are methods of that class. Because of this, all of our +functions need to have `self` as the first parameter, where `self` is the cog. Without this, we +wouldn't be able to access our bot instance. + +### Creating Commands + +When creating prefixed commands, your decorator would usually be something like `@bot.command()`. If you're using +cogs, this isn't the case. In a cog, you can't access the bot instance outside of functions, so to +register a function as a command, you must instead use `@commands.command()`. + +Similar to prefixed commands, you'll have to use either the `@discord.slash_command()`, `@discord.user_command()`, +or `@discord.message_command()` decorators for Application Commands. + +Also, when creating a command, make sure that it is indented. If we want a command to be actually +inside a cog, it has to be inside your cog's class. If the command is not inside the cog, +your command becomes useless. + +### Events + +When creating events, you can no longer use `@bot.event` as a decorator. This is because we cannot +access the `bot` variable outside a function. To make an event, you have to use the `ext.commands` +method, `@commands.Cog.listener()`. Events also need `self` as their first parameter. + +And that's it! Cogs are a simple and easy way of organizing your code. Now you can check out how to +create a help command [here](../extensions/commands/help-command). + +:::info Related Topics + +- [Creating a Help Command](../extensions/commands/help-command) +- [Rules and Common Practices](../getting-started/rules-and-common-practices) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Application Commands](../interactions#application-commands) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx new file mode 100644 index 00000000..6c19dd29 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx @@ -0,0 +1,383 @@ +--- +title: Error Handling +description: All about handling errors. +--- + +import { + DiscordEmbed, + DiscordInteraction, + DiscordMessage, +} from "discord-message-components/packages/react"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +## About + +When using the library, errors are frequently raised due to various reasons. These reasons range from the Discord API +failing your bot's request due to missing permissions or an invalid syntax error. + +Before going into error handling, it's best that you learn the basic ways of handling errors. A good resource is: + +- [W3Schools' Guide to Python Try-Except Statements](https://www.w3schools.com/python/python_try_except.asp) + +## Basic Handling + +The most basic way to handle errors is to tackle it at the source. This can be done like so: + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +import asyncio + +import discord + +intents = discord.Intents.default() +intents.message_content = True + +bot = discord.Bot(intents=intents) + + +@bot.slash_command(description="Gets some feedback.") +@discord.option("name", description="Enter your name.") +async def feedback(ctx: discord.ApplicationContext, name: str): + try: + await ctx.respond(f"Hey, {name}! Send your feedback within the next 30 seconds please!") + + def is_author(m: discord.Message): + return m.author.id == ctx.author.id + + feedback_message = await bot.wait_for("message", check=is_author, timeout=30.0) + await ctx.send(f"Thanks for the feedback!\nReceived feedback: `{feedback_message.content}`") + except asyncio.TimeoutError: + await ctx.send("Timed out, please try again!") + + +bot.run("TOKEN") +``` + +If you respond within 30 seconds, the interaction will look like so: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Great bot! + + + Thanks for the feedback! +
+ Received feedback: Great bot! +
+
+
+ +Otherwise, if you don't respond in time, the interaction will go as follows: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Timed out, please try again! + +
+
+ +This basic method of error handling can be extended to handle +many other errors including ones raised directly by py-cord. + +## Per-Command Handling + +This type of error handling allows you to handle errors per each command you have on your bot. +Each and every command can have it's own error handler made to handle specific errors that each command may raise! + +An example of per-command error handling is as follows: + +:::note Bridge Commands + +For these types of commands, it is recommended to utilize global error handling +until [the feature](https://github.com/Pycord-Development/pycord/issues/1388) is added. +::: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot(owner_id=...) # Your Discord user ID goes in owner_id + + +@bot.slash_command(description="A private command...") +@commands.is_owner() # This decorator will raise commands.NotOwner if the invoking user doesn't have the owner_id +async def secret(ctx: discord.ApplicationContext): + await ctx.respond(f"Hey {ctx.author.name}! This is a secret command!") + + +@secret.error +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.NotOwner): + await ctx.respond("Sorry, only the bot owner can use this command!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If your ID is registered as the owner ID, you'll get the following: + + + +
+ + secret + +
+ Hey Dorukyum! This is a secret command! +
+
+
+ +Any other user whose ID doesn't match the bot owner's will get the following: + + + +
+ + secret + +
+ Sorry, only the bot owner can use this command! +
+
+
+ +This local (per-command) error handler can also be used to handle the same types of errors that standard try-except +statements can handle. This is done by using the same method as above with the `isinstance` built-in function. + +## Per-Cog Handling + +Adding error handlers per-command can be quite the task in terms of work if you have a lot. If you have happened to +group your commands in cogs, then you're in luck! You can create an error handler that is specific to a cog and +handles all errors raised by commands inside that cog. + +Here's an example of a bot with a cog that implements its own error handling: + +```python title="./cogs/dm.py" +# This cog is for DM only commands! Sadly, we only have 1 command here right now... + +import discord +from discord.ext import commands + + +class DM(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.command() + @commands.dm_only() # This decorator will raise commands.PrivateMessageOnly if invoked in a guild context. + async def avatar(self, ctx: commands.Context): + embed = discord.Embed( + title="Avatar", + description=f"Here's your enlarged avatar, {ctx.author.name}!", + color=ctx.author.top_role.color + ) + embed.set_image(url=ctx.author.display_avatar.url) + await ctx.send(embed=embed, reference=ctx.message) + + async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): + if isinstance(error, commands.PrivateMessageOnly): + await ctx.send("Sorry, you can only use this in private messages!", reference=ctx.message) + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +def setup(bot: commands.Bot): + bot.add_cog(DM(bot)) +``` + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +# This is the main file where we load the DM cog and run the bot. + +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix=commands.when_mentioned_or("!")) +bot.load_extension("cogs.dm") +bot.run("TOKEN") +``` + +If you use this command in a DM context, you'll get the following: + + + + !avatar + + +
+ + !avatar + +
+ + Here's your enlarged avatar, BobDotCom! + +
+
+
+ +Otherwise, if used in a guild context: + + + + !avatar + + +
+ + !avatar + +
+ Sorry, you can only use this in private messages! +
+
+
+ +Per-cog error handling comes in very handy as you can relegate all of your error handling to a single function instead +of spreading it out across several per-command error handlers or inside the commands themselves. + +## Global Handling + +If separating your error handling is not how you would like to handle errors, then global error handling is the way to +go. This method of handling allows you to relegate all handling to a single function that resides within your bot +instance. + +A non-subclassed bot would implement this like so: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot() + + +@bot.slash_command(description="Get the bot's current latency!") +@commands.cooldown(1, 30, commands.BucketType.user) +# ^ This decorator allows one usage of the command every 30 seconds and raises commands.CommandOnCooldown if exceeded +async def ping(ctx: discord.ApplicationContext): + await ctx.respond(f"Pong! `{int(bot.latency*1000)} ms`.") + + +@bot.event +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.CommandOnCooldown): + await ctx.respond("This command is currently on cooldown!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If you've subclassed your bot, the `on_application_command_error` event will be placed inside the subclass without a +`bot.event` decorator and `bot.slash_command` will be replaced with `discord.slash_command`. + +The error handling used above will yield this interaction if the command is used again too quickly: + + + +
+ + ping + +
+ Pong! 49 ms. +
+ +
+ + ping + +
+ This command is currently on cooldown! +
+
+
+ +The only issue regarding global error handling is that, if you have a large amount of commands, the global handler may +start to get crammed with a lot of code. This is where all the previously mentioned handlers can take their place! + +## FAQ + +#### Why does the example in per-cog handling have self at the start of its function signatures? + +This is a feature of classes and allows you to reference the cog object as `self` and get access to the bot object +passed at initialization through `self.bot`. + +If this is new to you, we recommend checking out these helpful resources to learn more about classes and cogs: + +- [W3Schools' Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [Our Cogs Guide Page](./cogs) + +#### How many errors can I handle in a single error handler? + +While all the examples in this guide page only handle one specific error and re-raise all others, all of these +error handlers can be extended to catch many errors. + +In [basic handling](#basic) (i.e. try/except statements) you can do one of two things: + +- Explicitly handle the errors you know might get raised and then have a broad `except Exception as exc:` statement + as a catch-all. +- Catch any and all errors via the catch-all statement mentioned above. + +In [per-command](#percommand), [per-cog](#percog), and [global handling](#global), you can use elif clauses with the +built-in isinstance function to catch specific errors. Atop of this, an else clause can be used to catch any other +errors you either don't want to handle or want to relegate to a different error handler. + +#### Can I use more than one type of error handler at once? + +Thankfully, all of these different ways of error handling can be mixed together, so you don't have to pick just one! +For commands that raise specific errors that no other commands will raise, you can use [per-command](#percommand). +For cogs that raise specific errors that no other cogs will raise, use [per-cog](#percog)! Lastly, for errors that +occur frequently across all commands and cogs, use [global handling](#global)! + +However, one important note to remember is that you should always raise the error again in an error handler if it +isn't handled there! If you don't do this, the error will go ignored and your other handlers won't have a chance to +do their work! + +#### What's the difference between slash and prefixed command error handling? + +Although most examples shown here use slash commands, the [per-cog handling](#percog) section presents a prefixed +command. The main difference you may notice is the change in command signature. + +To make the distinguishing features apparent: + +- Slash commands use `on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException)` + as presented in the [per-command](#percommand) and [global handling](#global) examples. +- Prefixed commands use `on_command_error(ctx: commands.Context, error: commands.CommandError)` as presented in the + [per-cog handling](#percog) example. + +This distinction is made as both types of commands need their own system for handling errors that are specific to +themselves. + +:::info Related Topics + +- [Slash Commands](../interactions/application-commands/slash-commands) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Cogs](./cogs) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx new file mode 100644 index 00000000..9f4210af --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx @@ -0,0 +1,62 @@ +--- +title: Intents +description: All about intents in Discord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +## What are Intents? + +Intents allow bot developers to "subscribe" to specific events in Discord. This is useful for bots that need to respond to specific events, such as when a user joins a server or sends a message. You could choose to enable all intents or to enable only specific intents that your bot requires. + +## How do I enable intents? + +:::important + +Remember that [Privileged Intents](#what-are-privileged-intents) require you to enable them in the Discord Developer Portal. Verified Discord Bots that don't already have access to them will need to request Discord to allow access. + +::: + + + + +```python +import discord + +bot = discord.Bot(intents=discord.Intents.all()) +``` + + + + + +You can view a list of intents and the events they subscribe to [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```python title="Enabling Intents" +import discord + +bot = discord.Bot(intents=discord.intents.members(bans=True, guilds=True)) +``` + + + + +## What are Privileged Intents? + +Discord defines some intents as "privileged" because of the sensitive information they contain. Currently, there are three privileged intents: `members`, `presences`, and `message_content`. These intents must be enabled in your bot's Developer Portal. Once your bot reaches 100 servers, you will need to verify your bot for these intents to keep working and for your bot to be able to be invited to more guilds. + +:::tip + +Only enable these intents if you need them. These intents give your bot access to quite sensitive information about the users in your guild. These intents are privileged to respect the privacy of users, and you should do that as well. + +Not enabling these intents doesn't mean you won't be able to ban users, but you will be unable to detect when a new user joins a guild, or what game they are playing. The majority of bots won't need all intents. + +::: + +:::info Related Topics + +- [Sharding Bots](sharding) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx new file mode 100644 index 00000000..c3d17197 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx @@ -0,0 +1,48 @@ +--- +title: Sharding +description: All about Sharding Discord Bots. +--- + +# Sharding + +## What is Sharding? + +Sharding is the process of breaking up your bot into smaller pieces so that it has a better time handling +events. As [Discord's Documentation](https://discord.com/developers/docs/topics/gateway#sharding) puts +it, sharding is "a method of user-controlled guild sharding which allows for splitting events across +several gateway connections." + +Sharding is used only for large bots and takes up additional resources for managing the new processes. +Pycord automatically shards your bot, so the only thing you need to do is use an `AutoShardedClient` +or `AutoShardedBot` class instead of a plain `Client` or `Bot` class. Pretty cool, right? + +Just because you _can_ shard your bot doesn't mean you _should_. While Pycord makes it easy to shard +your bot, it isn't necessary to shard unless your bot is large. Sharding a small bot isn't +just useless, but _harmful_, as it uses extra resources and may slow down your bot. Discord +themselves will let you know when your bot needs sharding, so you won't need to worry about this until they contact you. + +## How Do I Shard in Pycord? + +Sharding in Pycord is straightforward. + +Just replace your `discord.Client`, `discord.Bot`, `commands.Bot` objects +with `discord.AutoShardedClient`, `discord.AutoShardedBot`, `commands.AutoShardedBot` respectively. + +These new objects have been inherited from the original objects, so all the functions from those other types should be present. + +If you want to specify the number of shards your bot uses, +just add the `shards` parameter, along with the number of shards you want. + +## Why Should I Shard my Bot? + +Sharding is very necessary for big bots. While your bot grows, it gets harder for your bot to control +how many guilds it is in and what parts of your code should do what. This is exactly what sharding +handles, it makes all of this easier for your bot. Remember, though, only shard your bot once it's +big enough, and that's at _least_ 1,000 guilds. + +:::info Related Topics + +- [Hosting your Bot](../Getting-Started/hosting-your-bot) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx new file mode 100644 index 00000000..bd2969c1 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx @@ -0,0 +1,115 @@ +--- +title: Subclassing Bots +description: Subclassing is a popular way of creating Discord Bots. Explore how you can create a Discord bot by subclassing. +--- + +## About + +Subclassing is another popular way of creating Discord Bots. Here, you create a bot by extending a bot class. To some advanced users, this is preferable to creating a bot instance with `bot = discord.Bot()`. + +Subclassing is an intermediate python concept, so we recommend you learn about it before continuing. Some good resources are: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +## Why Subclassing? + +Many developers prefer to subclass their bots for many reasons, some of them being: + +#### Skeletal Frameworks for Bots + +Developers often share their bots code on open-source platforms, mostly GitHub, and allow users to self-host the bot (running their own instance of the bot with the code provided by the developer. Permissions vary in accordance to licences). Here, users find it easier and more convenient to have a small file that imports the custom bot class and runs it, rather than having to go through the code of the bot and find out which file to run. This makes it easier for people not familiar with programming to run and customize the bot, since it often brings down the code to: + +```python title="./main.py" +from src import Bot + +bot = Bot() + +bot.run("TOKEN") +``` + +Here, all the commands are inside the `/src` folder that the user need not bother with. + +#### Running Multiple Instances + +Some developers may need to run multiple instances of their bot (perhaps on different bot accounts). For example, a developer might have a second bot for testing alpha features. This system makes it simpler for the developer, and allows them to maintain multiple versions of the bot in the same directory: + +```python title="./alpha_bot.py" +from src import Bot + +class AlphaBot(Bot): # subclasses Bot + ... # insert any custom configuration + +bot = AlphaBot() + +@bot.slash_command() # adds a new slash command to this subclassed bot +async def alpha_feature(ctx): + await ctx.respond("Alpha Feature!") + +bot.run("TOKEN") +``` + +There are many more reasons to subclass! It's not required, and won't affect the speed of the bot, but it may affect your development process, for the good or for the worse. You don't miss out on any features when you subclass, either. Some developers want the OOP feel, while some just prefer that method and find it easier. + +## Basic Example + +```python +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override the on_ready event + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') + +bot = MyBot() + +@bot.slash_command() # create a slash command +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run('token') +``` + +As you can see, instead of creating a bot object with `bot = discord.Bot()`, we subclass [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). We then create an instance of our new bot class and run it. Notice how we don't need to use the `@event` decorator. + +Here's another example: + +```python title="./src/bot.py" +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override on_ready + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') +``` + +```python title="./src/\_\_init\_\_.py" +from .bot import MyBot # import the MyBot class from the bot.py file +``` + +```python title="./main.py" +from src import MyBot # import MyBot from /src + +bot = MyBot() # create an instance of MyBot + +@bot.slash_command() +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run("TOKEN") # run the bot +``` + +These are just two ways you could do it. There are ton of other structures you can implement. It's up to you. + +So, should you subclass? There are no limitations you face if you decide to subclass your bot, but, once again, it's up to you. + +:::info Related Topics + +- [Making a Help Command](../Extensions/Commands/help-command) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx new file mode 100644 index 00000000..23220b0e --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx @@ -0,0 +1,105 @@ +--- +title: Threads +description: Threads with Pycord +--- + +In programming, threads are a way to run multiple processes at the same time. In Discord, threads are +a way to keep multiple conversations going at the same time. Let's take a brief look at how to use threads in Pycord. + +:::tip + +Not all the methods and attributes will be covered in this guide, but you can find them in our documentation! +[Check it out!](https://docs.pycord.dev/en/stable/api/models.html#discord.Thread) + +::: + +## Creating a thread + +With a few simple lines of code, we can create threads in Pycord. + +:::important + +All public threads need a starting message. This message will start the thread. However, private threads +(which are unlocked with having your server boosted to Level 2), do not require a starting message. + +::: + +### Creating thread from a message + +```python title="Creating a Thread from a Message" +message = await ctx.send("My Starting Message") +await message.create_thread(name="thread name", auto_archive_duration=60) +``` + +You may also use other ways to create the thread, for example, by using `on_message` events or by commands. + +### Creating thread in a channel + +```python title="Creating a Thread from a Channel" +channel = bot.get_channel(...) # define this! +await channel.create_thread(name="Thread Name", message=None, auto_archive_duration=60, type=None, reason=None) +``` + +A thread type could be `news_thread`, `public_thread`, `private_thread`. You may use it by passing `type=discord.ChannelType.news_thread`. + +## Deleting Threads + +Deleting Threads is simple. You need to get a thread and then use the `delete` method. + +```python title="Deleting a Thread" +thread = bot.get_channel(thread_id) # you could use other ways to get a thread +await thread.delete() +``` + +## Editing Threads + +**Parameters** + +- `name` (str) – The new name of the thread + +- `archived` (bool) – Whether to archive the thread or not. + +- `locked` (bool) – Whether to lock the thread or not. + +- `invitable` (bool) – Whether non-moderators can add other non-moderators to this thread. Only available for private threads. + +- `auto_archive_duration` (int) – The new duration in minutes before a thread gets automatically archived for inactivity. Must be one of 60, 1440, 4320, or 10080. + +- `slowmode_delay` (int) – Specifies the slow-mode rate limit for users in the thread, in seconds. A value of 0 disables slow-mode. The maximum value possible is 21600. + +```python title="Editing a Thread" +thread = bot.get_channel(id) +await thread.edit( + name="New Name", + archived=True, + locked=True, + slowmode_delay=10, + auto_archive_duration=60, +) +``` + +As you can see, threads are very simple. Once you learn how to use them, it's easy to create whatever you want. + +## FAQ + +### Why am I getting a `Forbidden` error when I try to create a thread? + +A `Forbidden` error occurs when the bot does not have the correct permissions to create threads. + +### Why am I getting an Unknown Message error when I try to create a thread? + +Getting an error looking something like `discord.ext.commands.errors.CommandInvokeError: Command +raised an exception: HTTPException: 400 Bad Request (error code: 10008): Unknown Message`? + +There could be multiple reasons, some of them being: + +- The message does not exist +- The message already has a thread +- The message is in channel x, you are trying to start a thread in channel y. +- The message was deleted. + +:::info Related Topics + +<>{/* I can't think of any related topics for this at the moment. */} + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/voice/_category_.json b/i18n/pt/docusaurus-plugin-content-docs/current/voice/_category_.json new file mode 100644 index 00000000..8baf3da8 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/voice/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 6, + "label": "Voice" +} \ No newline at end of file diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/voice/index.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/voice/index.mdx new file mode 100644 index 00000000..835838c6 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/voice/index.mdx @@ -0,0 +1,24 @@ +--- +title: Voice +--- + +Welcome to the guide for voice features in Pycord. + +:::caution +This guide requires previous experience with Pycord and Python. +::: + +## Requirements + +The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). +The following features are optional: + +:::tip +Opus is also a required library, but this comes with Pycord. +Some hosts may not come with it, though, so remember to always check if required dependencies are installed. +::: + +- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` +- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), + [`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), + [`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/voice/playing.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/voice/playing.mdx new file mode 100644 index 00000000..fe14c52a --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/voice/playing.mdx @@ -0,0 +1,149 @@ +--- +title: Wavelink Audio Player +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { + defaultOptions, +} from "@site/src/components/DiscordComponent"; + +# About + +Pycord and Wavelink try to keep the playing of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio playing feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/). + +## Starting out + +First you need to run a [Lavalink Server](https://github.com/freyacodes/Lavalink) to connect with. +There a multiple documentations to do this, so we are not covering that here. + +You also need to install the [wavelink](https://github.com/PythonistaGuild/Wavelink) library. + +```py title="Installing wavelink" +python3 -m pip install wavelink +``` + +You will now want to connect to your server via a node. + +```py title="Connect Node with Lavalink" +import discord +import wavelink + +bot = discord.Bot() + +async def connect_nodes(): + """Connect to our Lavalink nodes.""" + await bot.wait_until_ready() # wait until the bot is ready + + nodes = [ + wavelink.Node( + identifier="Node1", # This identifier must be unique for all the nodes you are going to use + uri="http://0.0.0.0:443", # Protocol (http/s) is required, port must be 443 as it is the one lavalink uses + password="youshallnotpass" + ) + ] + + await wavelink.Pool.connect(nodes=nodes, client=bot) # Connect our nodes +``` + +
+ +Now you are finished making your node! Next, you will want to: + +1. Making a play command +2. Adding connect events + +### Making a play command + +To make a play command, you will need to make a function to connect and play audio in a voice channel. + +```py title="Play Command Example" +import typing + +@bot.slash_command(name="play") +async def play(ctx, search: str): + # First we may define our voice client, + # for this, we are going to use typing.cast() + # function just for the type checker know that + # `ctx.voice_client` is going to be from type + # `wavelink.Player` + vc = typing.cast(wavelink.Player, ctx.voice_client) + + if not vc: # We firstly check if there is a voice client + vc = await ctx.author.voice.channel.connect(cls=wavelink.Player) # If there isn't, we connect it to the channel + + # Now we are going to check if the invoker of the command + # is in the same voice channel than the voice client, when defined. + # If not, we return an error message. + if ctx.author.voice.channel.id != vc.channel.id: + return await ctx.respond("You must be in the same voice channel as the bot.") + + # Now we search for the song. You can optionally + # pass the "source" keyword, of type "wavelink.TrackSource" + song = await wavelink.Playable.search(search) + + if not song: # In case the song is not found + return await ctx.respond("No song found.") # we return an error message + + await vc.play(song) # Else, we play it + await ctx.respond(f"Now playing: `{song.title}`") # and return a success message +``` + + + +
+ + play + +
+ Now playing: Never Gonna Give You Up +
+
+ +
+ +Now that you've done this, the only thing left to do is make your connect events. + +### Adding connect events + +The final step to this guide is connecting the node to your server when the bot goes online. + +To make it, you will want to do the following: + +```py title="Adding connect events" +@bot.event +async def on_ready(): + await connect_nodes() # connect to the server + +@bot.event +async def on_wavelink_node_ready(payload: wavelink.NodeReadyEventPayload): + # Everytime a node is successfully connected, we + # will print a message letting it know. + print(f"Node with ID {payload.session_id} has connected") + print(f"Resumed session: {payload.resumed}") + +bot.run("token") +``` + +Congratulations! You have now implemented voice playing into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-docs/current/voice/receiving.mdx b/i18n/pt/docusaurus-plugin-content-docs/current/voice/receiving.mdx new file mode 100644 index 00000000..1bc364e1 --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-docs/current/voice/receiving.mdx @@ -0,0 +1,130 @@ +--- +title: Receiving Voice Samples +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +# About + +Pycord tries to keep the recording of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio recording feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/audio_recording.py). + +## Starting out + +The first thing you want to do is make a cache of your voice connections. This is fairly easy; as +it's just putting a variable with an empty dictionary in our code, such as `connections = {}`. + +You will now want to create your command for recording. + +```py title="Record Command Example" +import discord + +bot = discord.Bot() +connections = {} + +@bot.command() +async def record(ctx): # If you're using commands.Bot, this will also work. + voice = ctx.author.voice + + if not voice: + await ctx.respond("You aren't in a voice channel!") + + vc = await voice.channel.connect() # Connect to the voice channel the author is in. + connections.update({ctx.guild.id: vc}) # Updating the cache with the guild and channel. + + vc.start_recording( + discord.sinks.WaveSink(), # The sink type to use. + once_done, # What to do once done. + ctx.channel # The channel to disconnect from. + ) + await ctx.respond("Started recording!") +``` + + + +
+ + record + +
+ Started recording! +
+
+ +
+ +Now you are finished making your command for voice receiving! Next, you will want to: + +1. Make your finished callback +2. Make a stop command + +### Making a Callback + +To make a callback, you will want to define the currently undefined `once_done` function inside +our command, like so: + +```py title="Recorder Callback" +async def once_done(sink: discord.sinks, channel: discord.TextChannel, *args): # Our voice client already passes these in. + recorded_users = [ # A list of recorded users + f"<@{user_id}>" + for user_id, audio in sink.audio_data.items() + ] + await sink.vc.disconnect() # Disconnect from the voice channel. + files = [discord.File(audio.file, f"{user_id}.{sink.encoding}") for user_id, audio in sink.audio_data.items()] # List down the files. + await channel.send(f"finished recording audio for: {', '.join(recorded_users)}.", files=files) # Send a message with the accumulated files. +``` + + + + finished recording audio for:{" "} + {defaultOptions.profiles.bob.author} + + + +
+ +Now that you've done this, the only thing left to do is make your stop command. + +### Making a Stop Command + +The final step to this guide is stopping the audio recording. This is the easiest step by far. + +To make it, you will want to do the following: + +```py title="Stop Recording Command" +@bot.command() +async def stop_recording(ctx): + if ctx.guild.id in connections: # Check if the guild is in the cache. + vc = connections[ctx.guild.id] + vc.stop_recording() # Stop recording, and call the callback (once_done). + del connections[ctx.guild.id] # Remove the guild from the cache. + await ctx.delete() # And delete. + else: + await ctx.respond("I am currently not recording here.") # Respond with this if we aren't recording. + +bot.run("token") +``` + +Congratulations! You have now implemented voice recording into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/pt/docusaurus-plugin-content-pagesindex.tsx b/i18n/pt/docusaurus-plugin-content-pagesindex.tsx new file mode 100644 index 00000000..84df3a9c --- /dev/null +++ b/i18n/pt/docusaurus-plugin-content-pagesindex.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import DefaultLayout from "../layouts/DefaultLayout"; +import PYCHero from "@site/src/components/PYCHero"; +import PYCButton from "@site/src/components/PYCButton"; + +export default function Home(): JSX.Element { + return ( + + +
+ Imagine a place where you can learn how to create an awesome Discord + bot, equip it with Pycord, and have it running in less than a minute. + Imagine a place where you can learn everything about Pycord. Imagine a + guide. A Pycord Guide! +

+ Whether you are a newbie or an experienced developer, you will find + everything you need to know about Pycord here. This guide will teach + you: +
    +
  • How to get a brand new bot running from scratch;
  • +
  • How to create Interactions, Context Menus and Commands;
  • +
  • In-depth concepts such as Embeds, Reactions, Help Commands, Paginators, etc;
  • +
  • Popular Topics such as working with Databases, Sharding, etc;
  • +
  • Ways to handle and manage common errors and best practices for bots;
  • +
  • And Much More!
  • +
+
+
+ ); +} diff --git a/i18n/pt/docusaurus-theme-classic/footer.json b/i18n/pt/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..ffb8a652 --- /dev/null +++ b/i18n/pt/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Pycord Development, All rights reserved.", + "description": "The footer copyright" + } +} diff --git a/i18n/pt/docusaurus-theme-classic/navbar.json b/i18n/pt/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..473b847e --- /dev/null +++ b/i18n/pt/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "Pycord Guide", + "description": "The title in the navbar" + }, + "item.label.Home": { + "message": "Home", + "description": "Navbar item with label Home" + }, + "item.label.Docs": { + "message": "Docs", + "description": "Navbar item with label Docs" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + }, + "item.label.Source": { + "message": "Source", + "description": "Navbar item with label Source" + } +} diff --git a/i18n/ru/code.json b/i18n/ru/code.json new file mode 100644 index 00000000..9cce6148 --- /dev/null +++ b/i18n/ru/code.json @@ -0,0 +1,404 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { + "message": "Toggle the collapsible sidebar category '{label}'", + "description": "The ARIA label to toggle the collapsible sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search here", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.algoliaLabel": { + "message": "Search by Algolia", + "description": "The ARIA label for Algolia mention" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorite", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "You might want to check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Algolia" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Try searching for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Believe this query should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/i18n/ru/docusaurus-plugin-content-blog/options.json b/i18n/ru/docusaurus-plugin-content-blog/options.json new file mode 100644 index 00000000..9239ff70 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/ru/docusaurus-plugin-content-docs/current.json b/i18n/ru/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..36b4849a --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,46 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.defaultSidebar.category.Getting Started": { + "message": "Getting Started", + "description": "The label for category Getting Started in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Interactions": { + "message": "Interactions", + "description": "The label for category Interactions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Application Commands": { + "message": "Application Commands", + "description": "The label for category Application Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.UI Components": { + "message": "UI Components", + "description": "The label for category UI Components in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Extensions": { + "message": "Extensions", + "description": "The label for category Extensions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Commands": { + "message": "Commands", + "description": "The label for category Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Pages": { + "message": "Pages", + "description": "The label for category Pages in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Voice": { + "message": "Voice", + "description": "The label for category Voice in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Popular Topics": { + "message": "Popular Topics", + "description": "The label for category Popular Topics in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.More": { + "message": "More", + "description": "The label for category More in sidebar defaultSidebar" + } +} diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png b/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png new file mode 100644 index 00000000..7480e1da Binary files /dev/null and b/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png differ diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg b/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg new file mode 100644 index 00000000..ce6b5110 Binary files /dev/null and b/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg differ diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png b/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png new file mode 100644 index 00000000..846eee15 Binary files /dev/null and b/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png differ diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png b/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png new file mode 100644 index 00000000..32a47d04 Binary files /dev/null and b/i18n/ru/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png differ diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/_category_.json new file mode 100644 index 00000000..309b494a --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 5, + "label": "Extensions", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json new file mode 100644 index 00000000..652aa4ee --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Bridge" +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx new file mode 100644 index 00000000..81545fa2 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx @@ -0,0 +1,190 @@ +--- +title: Bridge +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +## Concept + +Let's say that you want to make a command that is both a Slash Command and a Prefixed Command. Now, you could just copy and paste the code from the first command callback to the other and make some adjustments, but that's not very efficient. + +This is where the `ext.bridge` module comes in. It allows you to use one callback to make both a Slash Command and a Prefixed Command. + +### Example Usage + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def hello(ctx): + await ctx.respond("Hello!") + +bot.run("TOKEN") +``` + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+
+ +## Syntax + +First, instead of using `discord.Bot` or `commands.Bot`, we use `bridge.Bot`. `bridge.Bot` does inherit from `commands.Bot`, so you can do anything with `bridge.Bot` that `commands.Bot` can do. +Then, we define a command with `@bot.bridge_command()`. This makes a Bridge Command, which has both a Prefixed Command counterpart and a Slash Command counterpart. +Next, the callback has access to a `ctx` object, which is the context of the command. This context is either of `BridgeApplicationContext` type or `BridgeExtContext`. Because of that, it makes detecting how the function was called easier. + +### Using Bridge Commands in a Cog + +Like Slash Commands and Prefixed Commands, you can use Bridge Commands in a Cog. You can do this by using the `bridge_command` decorator. Here's an example: + +```python +import discord +from discord.ext import bridge, commands + +class Greetings(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @bridge.bridge_command() + async def hello(self, ctx): + await ctx.respond("Hello!") + + @bridge.bridge_command() + async def bye(self, ctx): + await ctx.respond("Bye!") + +def setup(bot): + bot.add_cog(Greetings(bot)) +``` + +The cog will automatically split the Bridge Command into their Slash Command and Prefixed Command counterparts. + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+ + +
+ + bye + +
+ Bye! +
+ + + !bye + + + +
+ + !bye + +
+ Bye! +
+
+ +### Deferring + +You can defer if you want to communicate to the user that your bot is busy processing the command. This is done by using `ctx.defer()`. For the Slash Command implementation, `ctx.defer()` calls the function that gives out a "Bot is thinking" message. For the Prefixed Command implementation, `ctx.defer()` enables the typing indicator. + + + +### Options + +Options are pretty straightforward. You just specify them like you do with prefixed commands, and you're all set! + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def sum(ctx, a: int, b: int): + await ctx.respond(a + b) + +bot.run("TOKEN") +``` + + + +
+ + sum + +
+ 4 +
+ + + !sum 2 2 + + + +
+ + !sum 2 2 + +
+ 4 +
+
diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json new file mode 100644 index 00000000..63f8e08e --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx new file mode 100644 index 00000000..bf345c07 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx @@ -0,0 +1,56 @@ +--- +title: Command Groups +--- + +Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk +remove`. + +## Syntax + +Creating a command group is very simple. + +```python title="Command Groups Example" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!') + +@bot.group() +async def afk(): + pass + +@afk.command() +async def set(): + ... + +@afk.command() +async def remove(): + ... + +# Another command group + +@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. +async def math(ctx): + await ctx.send('Subcommand not found') + +@math.command() +async def add(ctx, a: int, b: int): + ... + +@math.command() +async def subtract(ctx, a: int, b: int): + ... +``` + +To create a command group, the command's decorator must be `@bot.group`. Once you have a command with +that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand +groups! + + + +:::info Related Topics + +- [Prefixed Commands](./prefixed-commands.mdx) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx new file mode 100644 index 00000000..acbdc0a8 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx @@ -0,0 +1,481 @@ +--- +title: Help Command +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Pycord's `commands` extension comes with a built-in help command. In this guide, we will take a look at them as well as learn how to create your own. Let's dive in! + +:::note + +This guide demonstrates using object-oriented programming and subclassing to make a help command for your +Pycord bot. It is important to understand these two concepts before continuing. + +**Learning Resources**: + +- [W3Schools - Python Subclassing](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools - Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +::: + +## The Wrong Way + +A popular way to create a help command is to disable the built-in help command and create your own. This is not recommended as it will lead to a lot of confusion. + +```python title="The Wrong Way" +bot = commands.Bot(command_prefix='!', help_command=None) +# OR +bot.help_command = None +# OR +bot.remove_command("help") + +@bot.command() +async def help(ctx, *, argument=None): + ... +``` + +While it's possible to create a help command this way, doing so does not utilize the full capabilities +of making one with Pycord. Making a help command with subclassing and OOP will save time and effort. + +## Types of Help Commands + +There are two types of built-in help commands: + +- [`DefaultHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand) +- [`MinimalHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand) + +`DefaultHelpCommand` is the command enabled by default. It isn't the best looking, but `MinimalHelpCommand` can help make it look a bit better. + + + + +```python title="Default Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.DefaultHelpCommand()) # help_command is DefaultHelpCommand by default so it isn't necessary to enable it like this +# We enable it here for the sake of understanding + +... + +bot.run("token") +``` + + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ + +```python title="Minimal Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.MinimalHelpCommand()) + +... + +bot.run("token") +``` + + + + !help + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+ +
+ +
+ +## Updating Built-in Help Commands + +Let's try to make the `MinimalHelpCommand` look better. We can do this by putting its content in an +embed. + +```python title="Minimal Help Command Example" +bot = commands.Bot(command_prefix='!') + + +class MyNewHelp(commands.MinimalHelpCommand): + async def send_pages(self): + destination = self.get_destination() + for page in self.paginator.pages: + emby = discord.Embed(description=page) + await destination.send(embed=emby) + +bot.help_command = MyNewHelp() +``` + +Let's go through the code. + +First, we create a new class called `MyNewHelp`. This class is a subclass of `MinimalHelpCommand`. + +Next, we override the `send_pages` method. This method is responsible for sending the help command to +the user. We override this method because we don't want to change the content of the pages, just how +they are sent. + +We use the `get_destination` method to get the destination of the message. This is the channel or use that the help +command is to be sent to. + +We use the `paginator.pages` property to get the different pages of the help command. We put the page +in an embed, and then send the embed to the destination channel. + +Finally, we set this as our new help command using `bot.help_command = MyNewHelp()`. + + + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a + category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+
+ +## Creating Your Help Command + +Not satisfied with the built-in help commands? You can create your own! + +For this, we will subclass the `HelpCommand` class. + +There are 4 methods that we need to override: + +- `HelpCommand.send_bot_help(mapping)` that gets called with `help` +- `HelpCommand.send_command_help(command)` that gets called with `help ` +- `HelpCommand.send_group_help(group)` that gets called with `help ` +- `HelpCommand.send_cog_help(cog)` that gets called with `help ` + +### Bot Help + +```python title="Bot Help Example" +class MyHelp(commands.HelpCommand): + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help") + for cog, commands in mapping.items(): + command_signatures = [self.get_command_signature(c) for c in commands] + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's go through the code. + +- First, we create a new class called `MyHelp`. This class is a subclass of `HelpCommand`. + +- Next, we override the `send_bot_help` method. This method is responsible for sending the main help + command to the user. + +- We create an embed with the title "Help". + +- We iterate through `mapping.items()`, which returns a list of tuples, the first element being the + cog and the second element being a list of commands. + +- By using `self.get_command_signature(c)` we get the signature of the command, also known as the + `parameters` or `arguments`. + +- There is a chance that the cog is empty, so we use `if command_signatures:`. + +- We get the name of the cog using `getattr(cog, "qualified_name", "No Category")`. This calls the + cog's attribute `qualified_name` which returns "No Category" if the cog has no name. + +- We add a field to the embed with the name of the cog and the value of the command signatures. + +- Finally, we send the embed to the channel. + +Let's improve the code a little. + +```python title="Improved Bot Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + command_signatures = [self.get_command_signature(c) for c in filtered] + + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Now the help command won't show commands that the user can't use, as well as aliases for commands. +Let's get the help command to show command aliases. + +### Command Help + +This function is called when the user uses `help `. + +```python title="Command Help Example" +class MyHelp(commands.HelpCommand): + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command), color=discord.Color.random()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's quickly go through the code we haven't discussed yet. + +- In line 3, we create an embed with a title the signature of the command (so that the title of the + embed looks like ` [parameter]`), and a random color. + +- In lines 4 and 5, we get the command's `help` description and add it to the embed. The help description + of a command can be specified in the docstrings of a command function. For example: + + ```` + ```python + @bot.command() + async def ping(ctx): + """Returns the latency of the bot.""" + await ctx.send(f"Pong! {round(bot.latency * 1000)}ms") + ``` + ```` + +- Line 6 is shorthand for + + ```python + alias = command.aliases + if alias: + ... + + # is the same as + + if alias := command.aliases: + ... + ``` + + A very helpful (but not well-known) Python shorthand! + +- In line 7, we get the aliases of the command and add them to the embed. + +### Cog Help + +This is pretty easy! + +```python title="Custom Cog Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_cog_help(self, cog): + embed = discord.Embed(title=cog.qualified_name or "No Category", description=cog.description, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(cog.get_commands()): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Once again, we create an embed, get the commands that the user can use, and add them to the embed. + +### Group Help + +Similar to the cog help, this is pretty easy! + +```python title = "Custom Group Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_group_help(self, group): + embed = discord.Embed(title=self.get_command_signature(group), description=group.help, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(group.commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Add all of these methods together, and you have a fully functioning help command! + +
+Click to see the final code for this section +
+ +:::note + +The following code has been slightly edited from the tutorial version. + +::: + +```python title="Custom Help Command Example" +class SupremeHelpCommand(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + if command_signatures := [ + self.get_command_signature(c) for c in filtered + ]: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command) , color=discord.Color.blurple()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_help_embed(self, title, description, commands): # a helper function to add commands to an embed + embed = discord.Embed(title=title, description=description or "No help found...") + + if filtered_commands := await self.filter_commands(commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No help found...") + + await self.get_destination().send(embed=embed) + + async def send_group_help(self, group): + title = self.get_command_signature(group) + await self.send_help_embed(title, group.help, group.commands) + + async def send_cog_help(self, cog): + title = cog.qualified_name or "No" + await self.send_help_embed(f'{title} Category', cog.description, cog.get_commands()) + +bot.help_command = SupremeHelpCommand() +``` + +
+
+ +## Command Attributes + +How can you add cooldowns, set aliases, and change the name of help commands? Command attributes can +help you do all of that, and more! + +```python title="Help Command Attributes" +attributes = { + 'name': "help", + 'aliases': ["helpme"], + 'cooldown': commands.CooldownMapping.from_cooldown(3, 5, commands.BucketType.user), +} + +# You need to use CooldownMapping.from_cooldown(rate, per, type) + +bot.help_command = MyHelp(command_attrs=attributes) +``` + +## Error Handling + +When a user attempts to use a command that does not exist, we need to inform the user. +We can do this by overriding the `send_error_message` function. + +```python title="Custom Help Error Example" +class MyHelp(commands.HelpCommand): + async def send_error_message(self, error): + embed = discord.Embed(title="Error", description=error, color=discord.Color.red()) + channel = self.get_destination() + + await channel.send(embed=embed) +``` + + + + !help update_pycord + + + + Command 'update_pycord' not found. + + + + +## Credits + +Most of the content from this guide is from +[InterStella0's walkthrough guide on subclassing HelpCommand](https://gist.github.com/InterStella0/b78488fb28cadf279dfd3164b9f0cf96). +Thanks to InterStella0 for making this guide amazing. + +:::info Related Topics + +- [Subclassing Bots](../../Popular-Topics/subclassing-bots) +- [Prefixed Commands](./prefixed-commands) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx new file mode 100644 index 00000000..b8f567fd --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx @@ -0,0 +1,324 @@ +--- +title: Prefixed Commands +description: Learn how to use the commands extension for Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Before Discord added slash commands, all bots had prefixed commands. A user would type the bot's prefix +followed by a word or phrase to invoke a command, such as `?help` or `!help`. +However, this prefixed commands system isn't native to Discord! Developers made use of an `on_message` +event to check if the message began with a certain character, then invoke the command. Every time a +message was sent, the bot would see the message and check for its "prefix" + +The syntax becomes a little more complicated when you want to have multiple commands. There are several +disadvantages to this system. This is where the commands extension comes in. `ext.commands` has +various advantages, such as: + +- Simpler syntax +- Easier to use +- Easier to parse user input +- Comes with built-in help commands +- Comes with a built-in system for categorizing commands + + + + +```python title="Prefixed Commands with Events" +import discord + +client = discord.Client() + +@client.event +async def on_message(message): + if message.content.startswith("!ping"): + await message.channel.send("Pong!") + + elif message.content.startswith("!announce"): + if len(message.content.split(" ")) < 3: + await message.channel.send("You need to specify a title and a message. Correct usage: `!announce Hello Hello everyone!`") + return + + msg = message.content.split(" ", 2) + title = msg[1] + content = msg[2] + + await message.channel.send("**{}**\n{}".format(title, content)) + + elif message.content.startswith("!"): + await message.channel.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !help + + + Unknown Command. + +
+ +
+ + +```python title="The Commands Extension" +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix="!", intents=intents) + +@bot.command() +async def ping(ctx): + await ctx.send("Pong!") + +@bot.command() +async def announce(ctx, title, *, message): + await ctx.send("**{}**\n{}".format(title, message)) + +@bot.event +async def on_command_error(ctx, error): + if isinstance(error, commands.CommandNotFound): + await ctx.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !pycord + + + Unknown command. + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+ !announce +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The commands extension has many more uses. This example only showcases the basic features mentioned +in the previous example. Other things you can do with the commands extension include using a different +built-in help command and creating your own. The following tutorials showcase these. + +::: + +
+
+ +## Syntax + +Before we check out the syntax, let's take a look at the bot classes. + +> `discord.Client` - Contains only events. +> +> `discord.Bot` - Subclasses `discord.Client`, adds commands. +> +> `discord.ext.commands.Bot` - Subclasses `discord.Bot`, adds prefixed commands, cogs, and more. + +This means that `discord.ext.commands.Bot` has both slash commands and prefixed commands, as well as +events, cogs and more. + +Now let's look at the syntax. + +```python title="A Simple Prefixed Bot" +import discord +from discord.ext import commands # Import the commands extension +# discord.ext.commands are not the same as discord.commands! + +intents = discord.Intents.default() #Defining intents +intents.message_content = True # Adding the message_content intent so that the bot can read user messages + +bot = commands.Bot(command_prefix="!", intents=intents) # You can change the command prefix to whatever you want. + +@bot.command() # This is the decorator we use to create a prefixed command. +async def ping(ctx): # This is the function we will use to create the command. + await ctx.send("Pong!") # This is the response the bot will send. + + +bot.run("token") # Run the bot with your token. +``` + + + + !ping + + + Pong! + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The help command is a built-in command and is enabled by default. You will learn more about it in the +following guides. + +::: + +## Parameters + +Prefixed commands can take parameters, just like slash commands. You can specify the parameters in +the function itself. + +```python title="Parameters Example 1" +@bot.command() +async def echo(ctx, *, message): + await ctx.send(message) +``` + +`ctx` is the context of the message. `*` means that the parameter can be any number of words. `message` +is the parameter. If you had not passed `*`, `message` would only have been one word. + +For example, if a user had used `!echo hello world`, `message` would have been `hello`. Since we +passed `*`, `message` is `hello world`, or the rest of the message. + +We can pass multiple parameters too! + +```python title="Parameters Example 2" +@bot.command() +async def echo(ctx, channel:discord.TextChannel, title, *, message): + await channel.send("**{}**\n{}".format(title, message)) +``` + +In the example above, `channel` is a parameter that is of type `discord.TextChannel`. When you +specify the type of the parameter, Pycord will automatically try to convert the parameter to that type. +That is why you can use `channel.send` directly without needing to convert it first. + +We also have a new parameter, `title`. This does not have a type, so it will be a string. `*` means +that the rest of the message belongs to the next parameter, in this case, `message`. + +When a user types `!echo #general Greetings! Hello World!`, `channel` will be the text channel +`#general`, `title` will be `Greetings!` and `message` will be `Hello World!`. + +Let's take an example where the user passes `!echo #general Holiday Greetings! Greetings to you all!`. +Here, the user wants the title to be "Holiday Greetings!" and the message to be "Greetings to you all!". +However, since Pycord parses the message at whitespaces, the title will end up being "Holiday" and the +message "Greetings! Greetings to you all!". The user can prevent this by typing `!echo "Holiday +Greetings!" Greetings to you all!`. + + + + + + !echo #general Holiday Greetings! Greetings to you all! + + + Holiday +
+ Greetings! Greetings to you all! +
+ + !echo #general "Holiday Greetings!" Greetings to you all! + + + Holiday Greetings! +
+ Greetings to you all! +
+
+ +Let's check out another example for parameters and parameter types. + +```python title="Parameters Example 3" +import random + +@bot.command() +async def gtn(ctx, guess:int): + number = random.randint(1, 10) + if guess == number: + await ctx.send("You guessed it!") + else: + await ctx.send("Nope! Better luck next time :)") +``` + +If you had not specified the type of the parameter, it would have been a string. And since `"5"` is not +the same as `5` in python, the bot would have responded with "Nope! Better luck next time :)". +Even if you do not specify the type of the parameter, you can still convert it later on, in this case, +with `int(guess)`. + +:::info Related Topics + +- [Command Groups](groups) +- [Rules and Common Practices](../../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json new file mode 100644 index 00000000..baeba701 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Pages", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx new file mode 100644 index 00000000..be90b035 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx @@ -0,0 +1,168 @@ +--- +title: Paginator Basics +--- + +# Paginator Basics + +## [Page](https://docs.pycord.dev/en/stable/ext/pages/index.html#page) + +This class contains two attributes: `content` and `embeds`, which correspond to the attributes of the same name on the +`discord.Message` class. +To create a new Page, use the following syntax: + +```py +import discord +page = Page(content="My Page Content", embeds=[discord.Embed(title="My First Embed Title")]) +``` + +## [PageGroup](https://docs.pycord.dev/en/stable/ext/pages/index.html#pagegroup) + +This class represents a group of pages. It uses most of the same parameters as `Paginator`, which allows each +`PageGroup` to effectively have its own settings and behaviours. + +## [Paginator](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator) + +This is the main class for `ext.pages`, and is used to control most of the functionality of the extension. + +In its most basic form, with no arguments provided (default values listed below), a paginator can be created like so: + +```py title="Paginator Example" +import discord +from discord.ext.pages import Paginator, Page + +my_pages = [ + Page( + content="This is my first page. It has a list of embeds and message content.", + embeds=[ + discord.Embed(title="My First Embed Title"), + discord.Embed(title="My Second Embed Title"), + ], + ), + Page( + content="This is my second page. It only has message content.", + ), + Page( + embeds=[ + discord.Embed( + title="This is my third page.", + description="It has no message content, and one embed.", + ) + ], + ), +] +paginator = Paginator(pages=my_pages) +``` + +The only required parameter for `Paginator` is the `pages` parameter, which is usually a list of `Page` objects. + +You can also pass in a list of `PageGroup` objects, a list of strings, a list of embeds, or a list of lists of embeds. + +Once the `Paginator` instance is created, you can call either +[`Paginator.send()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.send) +or [`Paginator.respond()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.respond) +to send a message or response with the paginator's contents. + +#### Depending on what's being passed to the `pages` parameter, the behaviour of the paginator may differ: + +- Passing a list of `PageGroup` objects will essentially treat each `PageGroup` as its own Paginator, with most + `Paginator` attributes able to be set independently for each `PageGroup`. + \- Each `PageGroup` accepts its own `pages` parameter, which inherits the same behaviour as the `pages` parameter + of `Paginator`, except it cannot contain other `PageGroup` objects. +- If a page is a `Page` object, this will allow you to specify both the `discord.Message.content` and + `discord.Message.embeds` attributes for a page. + \- **This is the preferred method of defining a page.** +- If a page is a string, this will be used for the `discord.Message.content` attribute. This type of page cannot have + any embeds. +- If a page is a list of embeds, this will be used for the `discord.Message.embeds` attribute. This type of page + cannot have any message content. +- If a page is a list of lists of embeds, each parent list item will create a page containing all embeds from its + child list. This type of page cannot have any message content. + +#### Parameters for the `Paginator` class which have default values: + +- `show_disabled` **:** `True` + - Show buttons that are disabled (i.e. can't be clicked) +- `author_check` **:** `True` + - Only the author can interact with the paginator. +- `timeout` **:** `180` _(seconds)_ + - The paginator will time out and become inactive after this many seconds. +- `disable_on_timeout` **:** `True` + - If the paginator times out, it will be automatically disabled and all buttons will be unusable. +- `use_default_buttons` **:** `True` + - Use the default set of 4 buttons and a page indicator. +- `show_indicator` **:** `True` + - When using the default buttons, shows a middle 5th button with the current/total page numbers. + +**For other parameters that can be set on initialization, please check the +[API Reference](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator)** + +## [PaginatorButton](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatorbutton) + +This class represents a button used to navigate between the pages of a paginator. It's also used to create the page +indicator. + +When creating your own custom buttons, you can either use this class directly or subclass it to add any additional +functionality you may need. + +To add custom buttons to the paginator instead of the default navigation buttons, you have two options to do so: + +1. **Using the `custom_buttons` parameter of `Paginator`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + buttons = [ + PaginatorButton("first", label="<<-", style=discord.ButtonStyle.green), + PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), + PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True), + PaginatorButton("next", label="->", style=discord.ButtonStyle.green), + PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), + ] + paginator = Paginator( + pages=["Page 1", "Page 2", "Page 3"], + show_indicator=True, + use_default_buttons=False, + custom_buttons=buttons, + ) + ``` +2. **Using `Paginator.add_button()`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"], use_default_buttons=False) + paginator.add_button(PaginatorButton("prev", label="<", style=discord.ButtonStyle.green)) + paginator.add_button(PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True)) + paginator.add_button(PaginatorButton("next", label=">", style=discord.ButtonStyle.green)) + ``` + +If you want to use the default navigation buttons, but not all of them, you can also use `Paginator.remove_button()` to +selectively remove them: + +```py +from discord.ext.pages import Paginator + +paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"]) +paginator.remove_button("first") +paginator.remove_button("last") +``` + +## [PaginatorMenu](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatormenu) + +This class represents the `discord.Select` menu used to navigate between `PageGroup` instances. In most situations, you +will not need to interact with this class directly. + +If you do subclass it, you'll likely want to call `super()` in your `__init__` method to ensure that the `PageGroup` +navigation functionality is retained. + +## Usage Examples + +For a comprehensive list of examples showing all `Paginator` functionality, please see the +[example in cog form](https://github.com/Pycord-Development/pycord/blob/master/examples/views/paginator.py) in the repo. + +## Support and Feedback + +If you have any questions, suggestions, or feedback for `ext.pages`, please join the +[Discord server](https://discord.gg/pycord). diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx new file mode 100644 index 00000000..b8d68925 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx @@ -0,0 +1,20 @@ +--- +title: Paginator FAQ +--- + +# Paginator FAQ + +- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** + - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. + - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. + +- **How can the bot send a paginator to a different destination than where it was invoked?** + - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. + - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. + - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. + +- **How can I change the paginator's behavior without re-creating and re-sending it?** + - Use the `Paginator.update()` method. + +- **How can I make the bot actually do something with the contents of a page?** + - Use the (upcoming) `Paginator.page_action()` method. diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json new file mode 100644 index 00000000..36dfb009 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Tasks" +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx new file mode 100644 index 00000000..848f6066 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx @@ -0,0 +1,216 @@ +--- +title: Tasks +--- + +## Concept + +So you want to run a background task running at some specified interval? Thankfully, that's a common thing to do, whether you're working with some API or handling some background logic don't worry, the Pycord tasks extension is here to make life easier for you! + +With the tasks extension, you can make background tasks without worrying about the asyncio hell and mind bogglers like "what if my internet dies" and "how do I handle reconnecting" with the added benefit of a lot of useful additions that are one line of code away! + +### Example Usage + +```py +import discord +from discord.ext import tasks + +bot = discord.Bot() + +@bot.event +async def on_ready(): + very_useful_task.start() + +@tasks.loop(seconds=5) +async def very_useful_task(): + print('doing very useful stuff.') + +bot.run("TOKEN") +``` + +If you do run this code in your terminal you should see something like this after about 15 seconds: + +``` +doing very useful stuff. +doing very useful stuff. +doing very useful stuff. +``` + +For a more useful example here's a task in a cog context ripped straight from the [docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#recipes): + +```py +from discord.ext import tasks, commands + +class MyCog(commands.Cog): + def __init__(self): + self.index = 0 + self.printer.start() + + def cog_unload(self): + self.printer.cancel() + + @tasks.loop(seconds=5) + async def printer(self): + print(self.index) + self.index += 1 +``` + +As you'd expect this will increment a number and print it out every 5 seconds like so: + +```sh +0 +# 5 seconds later +1 +# 5 more seconds later +2 +# ... +``` + +## [Tasks](https://docs.pycord.dev/en/stable/ext/tasks/index.html) + +Now let's get into the nitty-gritty of tasks. + +As you've seen tasks can work in both outer scope and class contexts and the handle is roughly the same, you define a task using the `tasks.loop` decorator and use the `start` method to start it, the difference is you add the `self` argument when in a class context so since most people have all their bot's code in Cogs all the following code blocks will be in a Cog context to make it easy to copy it then apply whatever modifications you might need! + +### [Creating a task](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop) + +A look at `discord.ext.tasks.loop`'s definition in the documentation reveals that: + +1. As you've seen before it expects the time between each execution, that however doesn't have to be in seconds as + there are `seconds`, `minutes` and `hours` parameters to make it easier for us, they can also be floats in case you want + ultra-precision. +2. You can also pass in a `datetime.time` object or a sequence of them in the `time` parameter which will make it run + at the specified time(s). +3. You can pass in how many times a loop runs before it stops by passing in the `count` parameter, you can use `None` + to make it run forever which is also the default. +4. The loop function **_must_** be a coroutine. + +These are all really useful, and they aren't the only parameters so if you want to know more about them check out the +[docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop)! + +### Attributes + +A task has the following attributes: + +- `current_loop`: The current loop the task is on. +- `hours`, `minutes`, `seconds`: attributes that represent the time between each execution. +- `time`: A list of datetime.time objects that represent the times the task will run, returns `None` if no datetime + objects were passed. +- `next_iteration`: A `datetime.datetime` object that represents the next time the next iteration of the task will + run, can return `None` if the task stopped running. + +These attributes serve as a really powerful asset to get info about your loop. + +### Example + +Now let's create a cog that handles a leaderboard we have in our bot using Tasks then explain what we did after that and +also provide a refresher of how slash commands groups work in cogs. + +For the sake of this example let's pretend that we have a leaderboard module that does all the leaderboard handling for +us and that computing the leaderboard is very expensive computationally wise, so we want to store one version of it that +gets regularly updated instead of generating it every time someone calls the `/leaderboard view` command. + +```py +from discord.ext import tasks, commands +from discord.commands import SlashCommandGroup, CommandPermissions + +from leaderboard import * # Mock leaderboard module. + +class LeaderboardCog(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.update_leaderboard.start() + self.leaderboard_embed = generate_leaderboard_embed() + + leaderboard = SlashCommandGroup(name='leaderboard', description='Leaderboard commands.') + + @tasks.loop(minutes=10) + async def update_leaderboard(self): + print('Updating leaderboard...') + await update_leaderboard() + self.leaderboard_embed = generate_leaderboard_embed() + + @update_leaderboard.before_loop + async def before_update_leaderboard(self): + await self.bot.wait_until_ready() + print("About to start updating leaderboard.") + + @update_leaderboard.after_loop + async def after_update_leaderboard(self): + leaderboard_cleanup() + print("Stopped updating leaderboard.") + + @update_leaderboard.error + async def update_leaderboard_error(self, error): + print(f"Oh no, an error occurred while updating the leaderboard. Error: {error}") + + @leaderboard.command() + async def view(self, ctx): + await ctx.respond(embed=self.leaderboard_embed) + + @leaderboard.command() + async def update_info(self, ctx): + await ctx.respond(f"""***Leaderboard Info***\n + Last update: {(600 - self.update_leaderboard.next_iteration.timestamp())//60} minutes ago.\n + Next update: in {self.update_leaderboard.next_iteration.timestamp() // 60} minutes.\n + Time between loops: {self.update_leaderboard.minutes} minutes.\n + Times updated this session: {self.update_leaderboard.current_loop}. + Running? {self.update_leaderboard.is_running()} + Failed? {self.update_leaderboard.failed()}""", ephemeral=True) + + # Now for the owner only commands: + + leaderboard_config = SlashCommandGroup(name="leaderboard_config", description="Leaderboard configuration commands", permission=[CommandPermissions("owner", 2, True)]) + + @leaderboard_config.command() + async def set_time_between_updates(self, ctx, minutes: int): + self.update_leaderboard.change_interval(minutes=minutes) + await ctx.respond(f"Set time between updates to {minutes} minutes.") + + @leaderboard_config.command() + async def stop(self, ctx): + self.update_leaderboard.stop() + await ctx.respond("Stopped the leaderboard update.") + + @leaderboard_config.command() + async def restart(self, ctx): + self.update_leaderboard.restart() + await ctx.respond("Restarted the leaderboard update.") + +def setup(bot): + bot.add_cog(LeaderboardCog(bot)) +``` + +Phew, that was quite a bit of code. + +Now to explain what's going on: + +First things first we create a cog and in its `__init__` function we start the `update_leaderboard` task and generate +the first instance of our leaderboard's embed. + +After that, we define the `update_leaderboard` task using the `loop` decorator, and we make it run every ten minutes by +passing 10 to the `minutes` parameter. + +Then that we define the `before_update_leaderboard` task using the `before_loop` decorator, and we make it wait until the +bot is ready before starting the task. + +Next up we define the `after_update_leaderboard` task using the `after_loop` decorator, and we make it clean up the +leaderboard when the loop finally stops running. + +Then we define the `update_leaderboard_error` task using the `error` decorator, and we make it print any errors that may +occur while we update our leaderboard to the console. + +Then we get into the fun stuff, we create a slash command group using the `SlashCommandGroup` class and name it +`leaderboard`, we then create the `view` sub-command which sends the embed generated when the leaderboard is updated and +`update_info` which shows a lot of data about the task using some attributes and functions available to us. + +We also create a slash command group called `leaderboard_config` which is only available to the owner of the bot. + +Then we create the `set_time_between_updates` sub-command which takes in the time in minutes and changes the time +between updates of the leaderboard using the `change_interval` method, the `stop` sub-command which stops the task using +the `stop` method and `restart` which restarts the task using the `restart` method. + +Finally, we add the `LeaderboardCog` cog to the bot, and we're done! + +I'd highly recommend you check the tasks extension +[documentation](https://docs.pycord.dev/en/stable/ext/tasks/index.html) for more info on how to use them and what other +functions they have. diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/_category_.json new file mode 100644 index 00000000..9d6255f5 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 3, + "label": "Getting Started", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx new file mode 100644 index 00000000..864206a6 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx @@ -0,0 +1,262 @@ +--- +title: Creating Your First Bot +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +Excited to create your first bot? Once you [install Pycord](../installation.mdx), you can start right +away! + +## Creating the Bot Application + +Just like how you need to sign up to use Discord, your bot also has to be signed up. To do this, +you should: + +1. Go to the [Discord Developer Portal](https://discord.com/developers/applications) and click + on . +2. Give your bot a name, and click . +3. Now, you should see a page like this. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdW3OQnwUhacopqSWw%2F-Mjd_-mxrJCrzmaXrAg8%2Fimage.png?alt=media&token=b8e2ae6c-2290-4d37-ad7c-eb412f3fb00e) +4. Click on the tab on the left side of the screen. +5. Click on . +6. You can give it a name, change the Avatar, etc. + +## Inviting the bot + +Now, lets get the bot added to some servers. Go to the tab +in the left pane and select `bot` and `applications.commands` as scopes. + +You may want your bot to have application commands, which is what the `application.commands` scope +allows your bot to make. + +Next, you want to choose what permissions the bot will have and select them. For now, you can just +give your bot the `administrator` permission, which gives your bot every permission. Once you select +your bot's permissions, click on to get the bot invite link. + +:::tip + +When your bot is all ready to go, make sure that administrator permissions aren't selected unless +your bot truly needs them. Try selecting only permissions the bot will need. For testing, +Administrator permissions are fine. + +::: + +![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-Mk6tNY3LfDkjd6pqdpL%2F-Mk6tkdpddEWoa2jczZk%2Fimage.png?alt=media&token=52c8a29f-a798-48f8-a8c7-4ecca2681f79) + +You can use this link to invite the bot. + +## Tokens + +Now that you have an account for your bot, you need to log in. To log in, we need the bot's +password. All users and bots have a "token." You may think of this token as a password, as this allows +us to log our bot into Discord. + +Tokens are "snowflakes." Not actual snowflakes, though. Just like how no two snowflakes in real life have the same +pattern, snowflakes in computers are unique things - no two bots have the same token - so a token is +considered a snowflake. A Discord user ID is also a snowflake. + +Now, lets get your bot's token. To do this, you want to: + +1. Go back to the tab. +2. Click on the button in the "Token" section. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdbU12JISJorAZxrKH%2F-MjdbpUsapzb5n15Po5P%2Fimage.png?alt=media&token=118e259f-940a-4f6c-b3a3-c29f3a54100d) + +Now, you have your bot's token copied to your clipboard. + +:::danger + +Do not, under any circumstances, give your token to anyone. Even if you are contacted by someone +claiming to be Discord staff, do not give them your bot's token. They are lying to you to try and +gain access to your bot. If an unauthorized user gains access to your bot's token, they can access +your bot and use it in malicious ways. + +Never push your token to GitHub or include it in your code. One way to prevent your token from +getting leaked is to store it in `.env` files. + +::: + +### Protecting Tokens + +#### Using dotenv + +You can store your tokens in `.env` files. This is a simple way to store sensitive information. + +1. Create a file with the name `.env` (only the extension, with a dot/period at the start and without a name before it). +2. Define the token in the `.env` file (replace the example value with your token). + ```env title=".env" + TOKEN = NzkyNzE1NDU0MTk2MDg4ODQy.X-hvzA.Ovy4MCQywSkoMRRclStW4xAYK7I + ``` +3. Install [`python-dotenv`](https://pypi.org/project/python-dotenv/). + ```bash + python -m pip install python-dotenv + ``` +4. Load the token from the `.env` file. + ```python + import dotenv + dotenv.load_dotenv() + token = str(os.getenv("TOKEN")) + ``` +5. Pass your token as parameter when running the bot. + ```python + client.run(token) + ``` + +:::tip + +If you are using Git to track your bot's changes, you should create a file called `.gitignore` and add +`.env` to it. This stops your `.env` file from getting tracked along with the rest of your code, and +will not be pushed to a remote Git repository. As a consequence, it will stay secure on your local machine. + +::: + +## Coding the Basics + +Here's an example of code you'll write with Pycord: + +```py +import discord +import os # default module +from dotenv import load_dotenv + +load_dotenv() # load all the variables from the env file +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") + +bot.run(os.getenv('TOKEN')) # run the bot with the token +``` + + + +
+ + hello + +
+ Hey! +
+
+
+ +Let's go through the code. First, the imports. + +```py +import discord +import os +from dotenv import load_dotenv +``` + +In the first line, `import discord`, we import Pycord. Although you install Pycord with `pip install py-cord`, you +import it with `import discord`. This is so it's as easy as possible when switching from Discord.py to Pycord. + +We then import `os` and `dotenv`. `os` is a default module that we will use to get the token from the env file. `dotenv` +is a module that we will use to load the env file. You installed this with `pip install python-dotenv`. + +Next, we load the env file with `load_dotenv()`. + +```py +bot = discord.Bot() +``` + +In this line, we create a new instance of [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). +In this object, we can pass various parameters for configuration purposes, such as `owner_ids` +and [`intents`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```py +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") +``` + +We use the [`event`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) decorator to override +the [`on_ready`](https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready) function to define an +event that is automatically called when the bot is ready to use. + +```py +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") +``` + +Here, we use the [`slash_command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.slash_command) +decorator to define a slash command. We specify the `name` and `description` arguments. If not +specified, the name of the slash command would be the function name and the command description would +be empty. + +Optional: We type-hint the context parameter (`ctx`) as [`discord.ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext). In modern IDEs, type-hinting allows access to autocompletion and docstrings. You can read more about type-hinting [here](https://docs.python.org/3/library/typing.html). + +Finally, you want to run the bot using the token specified in the `.env` file. + +Now you have finished creating your first Pycord bot! What we have shown you is just the basic structure +of a bot. You can do a lot more with Python and Pycord knowledge, as well as your imagination! Pycord +will not limit your bot's abilities. + +:::note + +The part where we load the token from the environmental variables is not required. You may use another way to keep your token secure, or, although not recommended, simply specify the token normally as a string, as shown below. + +
+A Basic Bot without securing the token +
+ +```py +import discord + +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.send("Hey!") + +bot.run("TOKEN") +``` + +
+
+ +::: + +## FAQ + +### How do I make prefixed commands? + +Prefixed commands are an older method of creating bot commands that listen for messages and replies +if the message starts with a certain character. You can read [this page](../extensions/commands/prefixed-commands.mdx) +to learn more about prefixed commands. + +### How do I setup modules/cogs? + +[Cogs](../popular-topics/cogs) are a great way to organize your commands by putting them into +groups called cogs. Cogs are separate files that your bot loads to get the commands inside. +You can read more about cogs, as well as learn how to use them and their benefits, +[here](../popular-topics/cogs). + +### How do I add components, such as buttons and dropdown menus, to my bot? + +Pycord makes it very easy to use Message Commands with your bot by using the `discord.ui` module. +To learn more, read about Message Commands in our [interactions directory](../interactions). + +:::info Related Topics + +- [Prefixed Commands](../extensions/commands/prefixed-commands) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx new file mode 100644 index 00000000..2a68677b --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx @@ -0,0 +1,109 @@ +--- +title: Hosting Your Pycord Bot +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Hosting Your Pycord Bot + +If you're completely new to this, you might have thought something along the lines of "Yay! I got my +bot working," after following our [Creating your First Bot](creating-your-first-bot) guide, only +to close your IDE or shut down your computer to find your bot offline. + +The reason for this is that programs have to be hosted somewhere, meaning some machine somewhere has +to constantly run your bot. There are tons of hosting services that can help you host your bot for +little to no cost. + +## Can I get a Clear Explanation? + +Sure thing. When you run your bot, it first makes a connection to Discord's API. Once that's done, +Pycord sends "heartbeats" to Discord. "heartbeats" are small packets sent at a set interval telling +Discord that your bot is indeed still alive. If Discord doesn't receive a heartbeat after a certain +amount of time, your bot is pronounced dead and buried in the graveyard (not really). It is, though, +taken offline and its connection with Discord is terminated. + +Once you close the terminal that you've run your program on, the program is no longer running, and +the bot stops sending heartbeats and can no longer process commands. This is why you have to constantly +keep the process running. + +This goes for all programs, in a different nature. If the code isn't compiled/built/assembled/interpreted, +it can't be running. + +## What is a Host? + +A host is a server or container for running code offered by a **hosting provider.** There are a lot +of hosting providers, such as bigger ones like Amazon Web Services (AWS) and Google Cloud, and smaller +ones like GalaxyGate and DigitalOcean. + +There are three types of hosts. + + + + Shared hosting is a type of hosting where multiple people share one VPS. Getting a spot on + a shared host is usually cheap, sometimes even free. Shared hosts do not give you a lot of + resources, from less than a gigabyte of RAM (usually 512MB on free hosts) and half of a CPU + with very little storage. Shared hosting is usually used for website hosting and is not + recommended for hosting a Discord bot. + + + A virtual private server (VPS) is a virtual computer (virtual machine) that is rented out to + customers. Most people use a VPS for hosting their projects such as Discord bots. You can get + anywhere from less than a gigabyte of RAM and a less powerful CPU to just under one hundred + gigabytes of RAM, a (or multiple) powerful CPU(s), and a fair amount of storage. A VPS is the + best choice for most users and can be fairly cheap. + + + A dedicated host is a physical computer. You can buy these yourself or rent one from a hosting + provider. Dedicated hosts are often very expensive, but are also very powerful, having a + few hundred gigabytes of RAM and a few very powerful CPUs, along with a good amount of storage. + Dedicated hosts are usually used for very large projects and are overkill for something like + a Discord bot. + + +
+ +:::danger + +Make sure you choose a hosting provider you trust. Also make +sure the hosting provider you're looking at has good reviews on public forums. Googling along the +lines of "[host] review" should do the trick. A provider you don't trust can compromise your token. + +::: + +Most hosting providers rent their services to you for a monthly or yearly fee. These can be anywhere +from a few dollars to hundreds or thousands of dollars. + +## How to Host Your Bot + +Once you rent or buy a VPS, you can get to work. Most hosting providers allow you to choose from a +wide range of operating systems, most allow you to choose one but some allow you to choose +multiple. Once that's ready, you have to SSH into the system. We won't get into SSH here, but you can +read [this article from DigitalOcean](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys). +You can also use VNC, which is remote desktop software. If you are using an OS that does not have a +GUI, and is only a command line (a "server" OS), such as Ubuntu Server or most Linux Server Operating Servers, you will most +likely use SSH. If you are using an OS that has a GUI, such as Windows Server, you will most likely use VNC. + +Once you've decided on your operating system, you'll want to set it up and install Python. Once that's +done, you can copy your bot's files to your remote system, install the required packages, and run +the bot. + +:::warning + +If you are using SSH to run the file, your bot will not stay running. This is because the file is +only told to run during your session. You can use a command like [nohup](https://en.wikipedia.org/wiki/Nohup) +to make sure your file stays running after you disconnect. + +::: + +Now your bot is hosted, but that doesn't mean it can't go offline. If your bot encounters an error, +it can often go offline or stop its process. For this, make sure you have proper error handling. +Also be sure to pay attention to your hosting provider's updates or news, as they usually notify +users of when they plan on doing maintenance to their servers, making their services unavailable for +a short time. + +:::info Related Topics + +- [Creating Your First Bot](creating-your-first-bot) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx new file mode 100644 index 00000000..ee6b9417 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx @@ -0,0 +1,379 @@ +--- +title: More Features +description: More features to make your bot cool and snazzy. +--- + +import { + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, + DiscordEmbedField, + DiscordEmbedFields, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +So, you just created your first Pycord bot! Now, let's add some more features to it. This will include adding event handlers, waiting for user response, styling the messages, and more. + +## Events + +### Event Handlers + +Events in Discord are a way to listen for certain actions. For example, if you want to know when a user joins your server, so you could send a welcome message, you can use the `on_member_join` event. + +First, you need to ask Discord to send you events. This is done via "Intents". Read up the [Intents](../Popular-Topics/intents) page for more information. + +Once you understand what intents are, you can enable the events you need, or just use the default ones with `discord.Intents.all()`. + +Now that that's done, let's add an event handler for when a user joins the server. We will use the [`on_member_join` event](https://docs.pycord.dev/en/stable/api/events.html#discord.on_member_join). We will send a private message to the user welcoming them to the server. + +```python +@bot.event +async def on_member_join(member): + await member.send( + f'Welcome to the server, {member.mention}! Enjoy your stay here.' + ) +``` + +We use the [`discord.Bot.event` decorator](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) to add the event handler. + +The `on_member_join` event is called when a user joins the server. The `member` parameter is the user that joined. Different events have different names and parameters. You can find all of them [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +So, that's how you add event handlers! + +### Waiting for User Response + +Let's say you want to create a Guess-the-Number game (where the user has to guess a number between 1-10). You need to send a message to a user and wait for them to respond. You can do this with the [`wait_for`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.wait_for) method. + +```python +@bot.command() +async def gtn(ctx): + """A Slash Command to play a Guess-the-Number game.""" + + await ctx.respond('Guess a number between 1 and 10.') + guess = await bot.wait_for('message', check=lambda message: message.author == ctx.author) + + if int(guess.content) == 5: + await ctx.send('You guessed it!') + else: + await ctx.send('Nope, try again.') +``` + +`wait_for` takes one argument, which is the event type. The event type is the name of the event you want to wait for. In this case, it's `message`. It could also be `reaction` to wait for a reaction to be added. + +We pass a keyword argument to `wait_for` called `check`. The function may look complicated if you're a beginner. We pass a `lambda` function, which simplifies the code a bit. + +The lambda function takes one parameter, `message`. When Pycord receives a message, it passes it to the `check` function. If the function returns `True`, the message is returned. If the function returns `False`, the message is ignored and the bot waits for another message. + +Here, we check if the message is from the user that sent the command. We simply use `message.author == ctx.author`. This will check if the author of the message was the person who invoked the command. + +## Styling Messages + +### Embeds + +Embeds are a Discord feature that allows applications to format their messages in cool embedded format, +enabling your bot to lay out messages with a lot of text into neat fields. + + + + + The Pycord Guide is a detailed guide that explains how to use Pycord and all of its features. + + + The Getting Started section explains how you can get a brand new bot created and running from scratch. + + + Interactions with Pycord + + + Pycord's various Extensions + + + Other Popular Topics + + + We have so much more! Just explore, and you will find everything you need. If you want another page added, open an issue on the GitHub. + + + Created with 💖 by the Pycord Team & Contributors + + + + +
+ +Creating embeds is simple! Just create an instance of [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) and edit it to your liking. Once you're done, send it! + +```python +import discord + +bot = discord.Bot() + +@bot.command() +async def hello(ctx): + embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from + ) + embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") + + embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) + embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) + embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) + + embed.set_footer(text="Footer! No markdown here.") # footers can have icons too + embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") + embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") + embed.set_image(url="https://example.com/link-to-my-banner.png") + + await ctx.respond("Hello! Here's a cool embed.", embed=embed) # Send the embed with some text + +bot.run("TOKEN") +``` + + + +
+ hello +
+ Hello! Here's a cool embed. + + Embeds are super easy, barely an inconvenience. + + + A really nice field with some information. The description as well as the fields support markdown! + + Inline Field 1 + Inline Field 2 + Inline Field 3 + + Footer! No markdown here. + +
+
+ +
+ +This simple command sends replies to a [slash command](../interactions/application-commands/slash-commands) with an embed. +Let's break it down: + +```py +embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), + ) +``` + +This command creates an embed. We use the [`Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) +class to create an embed object with the title "My Amazing Embed", the description "Embeds are super easy, barely an inconvenience.", and the color `blurple`, Discord's main theme color. + +[discord.Colour](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Colour) is a class full of [classmethods](https://docs.python.org/3/library/functions.html#classmethod) +that return color values. While the official, documented name of this is `discord.Colour`, `discord.Color` +works as well. + +```py +embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") +embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) +embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) +embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) +``` + +This small section shows off embed fields. You can add fields to embeds with the [`add_field` method](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.add_field) +of the [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) class. These consist of three +keyword arguments: `title`, `value`, and `inline`. `title` and `value` are both required arguments, which inline defaults to `False` if it's not defined. The `inline` argument specifies whether space will be divided among the inline fields. There could be a mix of fields where inline has different values too. + +```py +embed.set_footer(text="Footer! No markdown here.") # footers can have icons too +embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") +embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") +embed.set_image(url="https://example.com/link-to-my-banner.png") +``` + +In this section, we're adding unique items to the embed. These items are: + +- Footer - With the [`set_footer()`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_footer) + method, you can set a small footer that holds a message. This has `text` and `icon_url` kwargs. +- Author - With the [`set_author`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_author) + method, you can set an author for the embed. This is a small text field at the top of the embed. This + includes `name`, `url` and `icon_url` kwargs. +- Thumbnail - With the [`set_thumbnail`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_thumbnail) + method, you can set a small image to reside at the top-right of the embed. This has a single `url` kwarg. +- Image - With the [`set_image`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_image) + method, you can set an image to sit at the bottom of an embed. This has a single `url` kwarg. + +There are a lot more methods and attributes you can use to configure embeds. Here, we just covered the basics. Also, remember that all of these values are not necessary in an embed. An embed may only contain a few of these. For example, only a description, a title and a description, and so on. + +### Markdown + +Markdown is a type of markup language that's limited in terms of formatting yet simple. Discord allows +for a watered-down version of markdown to be in their messages. + +#### Text Markdown + +Text formatting can be used in messages and in most embed parts, +as explained in the dedicated section below. + + + + + + + + + + + + + + + + + + + + +
*italics*__*underlined italics*__
**bold**__**underlined bold**__
***bold italics***__***underlined bold italics***__
__underlined__~~strikethrough~~
+ +#### Code Markdown + +To create a single-line code block without syntax highlight, wrap the text between single backticks. +This code block will only add a dark background to the text. + +``` +`print("Hello world!")` +``` + +To create a multi-line code block without syntax highlight, wrap the text between triple backticks +on first and last line. This type of code block will encase the code inside a box. + +```` +``` +message = "Hello world!" +print(message) +``` +```` + +To create a multi-line block with syntax highlight, add the name of the language you are using right after +the triple backticks on the first line. For example, for Python you can write either "python" or "py". + +```` +```python +message = "Hello world!" +print(message) +``` +```` + +If you want to use syntax highlight for a single line of code, you still have to format it +like a multi-line block but the code must be on a separate line than the triple backticks. + +#### Quote Markdown + +To create a single-line quote block, start the line with `>` followed by a space. + +``` +> This is a single-line quote. +``` + +To create a multi-line quote block, write `>>>` followed by a space. All text +from that point onwards will be included in that quote block. + +``` +>>> This is a +multi-line quote. +``` + +#### Spoiler Markdown + +To hide a spoiler, encase the text between double pipes. The users +will have to click on it before being able to see the text contained in it. + +``` +||spoiler|| +``` + +#### Link Markdown + +Link formatting only works in embeds and messages sent through webhooks, +by using the following syntax: + +``` +[Pycord](https://pycord.dev/) +``` + +Inside the supported elements that have just been mentioned, +the example above will look like this: [`Pycord`](https://pycord.dev/) + +Outside them, the link will still be clickable but the formatting will be ignored, +therefore the example above will look similarly to this: `[Pycord](https://pycord.dev/)` + +#### Embed Markdown + +Adding markdown to your embeds or messages will give your bot the sparkle it needs, +however, markdown is limited inside embeds. Use the following table as a reference +and keep in mind that embed title and filed names will always show in **bold**. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PartTextLink
Embed AuthorNoNo
Embed TitleYesNo
Embed DescriptionYesYes
Field NameYesNo
Field ValueYesYes
Embed FooterNoNo
diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx new file mode 100644 index 00000000..e44b7c49 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx @@ -0,0 +1,184 @@ +--- +title: Rules and Common Practices +description: All about the rules and common practices for coding a Discord bot +--- + +# Rules and Common Practices of Creating a Bot + +When creating almost anything, there's always a certain set of rules to follow or common practices, +such as [PEP8](https://www.python.org/dev/peps/pep-0008/) for Python. This applies to creating bots +with Pycord as well. + +:::note + +Most of these rules and common practices are only applicable for +[verified bots](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting), +but it's good to follow them nonetheless. + +::: + +## Rules + +There are rules for creating bots, and most of these are required by Discord themselves, not us at +Pycord. Not following these rules may get your bot denied for verification. + +### Terms of Service and Privacy Policy + +Starting at some point in time, Discord has made providing a privacy policy with your bot a requirement. +This is so that Discord knows exactly what you are doing with its users' data. + +:::tip +You don't need a lawyer or anyone special to write out a privacy policy for you, nor do you need +it approved by some official entity. Simply writing out how you are going to use Discord user +information neatly is all you need to do. +::: + +Providing a Terms of Service for your bot is optional, though usually a best practice. It tells users +what they can and cannot do with your service, and makes it easier to settle disputes if someone +disagrees with you. + +Read more in Discord's official [Legal Docs](https://discord.com/developers/docs/legal). + +### Developer Policy + +We could list almost every rule about using Discord's API here. _Or_ we could simply link Discord's +Developer Policy to make it easier on us. You can find Discord's Developer Policy +[here](https://discord.com/developers/docs/policy). This outlines what you can and cannot do with +Discord's Developer API. And, don't worry, it's completely readable and understandable. + +## Best Practices + +Now, here's something we _can't_ simply link an article for. We're going to discuss the best practices +of creating a Discord bot with Pycord. + +### Bot Sharding + +To any new or maybe even experienced bot developer, sharding a bot sounds beneficial once you hear +about it. I'm here to tell you that it isn't a good idea to shard your bot. + +_Wait a minute, why would it be an option if it wasn't a good idea?_ It's simple. I lied. Sort of. +I'm not going to go into the details of sharding a bot, so you can read about it on +[this page](../Popular-Topics/sharding). Sharding is the process of taking your bot +and breaking it up into small pieces, so it's easier to perform tasks. This is very useful for large +bots, as it makes them faster and more reliable. Sharding is not a good practice for small bots. + +:::note +Discord will notify you once it is time to shard your bot, and will eventually force you to do so. +::: + +At the very least, wait for one thousand servers to shard your bot. If you shard your bot while it's +small, you'll just be wasting resources and possibly making your bot slower. + +### [Verification](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting) + +Verifying your Discord bot is something every developer would like to achieve. It shows that your bot +is in more than 75 servers. It's generally a good idea to try to get your bot verified as soon as +possible. We're talking at 76 servers soon. This is because Discord can be somewhat slow in terms of +bot verification, so verifying as soon as possible gives them enough time to verify before your bot +reaches the 100 server cap. If a bot is not verified, it cannot grow beyond 100 servers. + +It's also a good idea to only apply for the privileged intents that you need. Applying for intents +your bot doesn't use wastes both your time and Discord's time, as your privileged intent request +will be denied simply because you applied for an intent you didn't need. + +### Subclassing + +While it may take some time, subclassing a bot is very worth it. Once again, this was explained +elsewhere, so I won't go into the details, but I felt it fit here, so I put it here. + +Subclassing a bot makes it more flexible and allows it to do a lot more. Read more about subclassing +bots [here](../Popular-Topics/subclassing-bots) + +### Your Bot's Token + +Your bot is only able to be run for one reason: its token. If you followed the +[guide for creating your first bot](creating-your-first-bot), you should already know a bit about +keeping that token safe. That's exactly what you want to do. + +Sharing your token is never good. If someone evil gets a hold of your token, they can do terrible things, +such as making your bot leave all of its servers, spamming all the members the bot has contact with, +and even manipulating the servers the bot is in, if given the permissions. That's why it's very important +to keep your token safe. To learn how to do so, read [this part](creating-your-first-bot#tokens) of +the Creating Your First Bot guide. + +### Backups + +You always want to back up your bot's data. This includes both its code _and_ its databases. This way, +if something tragic happens, such as your host failing a data migration or you breaking your Raspberry +Pi's SD card that held your bot, you'll still have its precious user data. I have a small program for +my bot that uploads its databases to a remote GitHub repository periodically to not lose any data. +It may be smarter to find a bit more of a reliable way to do so, though. + +Public or private, having a local Git repository connected to a remote one is a good idea for making +almost any application. For a lot of developers, it's like saving your work. If you do this, all of +your bot's code won't be lost if your computer spontaneously combusts, or you smash it to bits from +anger. You can simply grab the backup computer that everyone has lying around, and you're back +in business. + +### Organization and Cleanliness + +It is _extremely_ important to have organized code. This includes commands, objects, functions, +and classes. If you don't have organized code, it will get progressively harder for you to recognize +it, and others won't be able to decipher it. + +Make sure you utilize indents and spaces, as these are very important in making your code readable. + +```py title="Bad Spacing" +class MyClass: + async def add(self,num1,num2): + return num1+num2 + async def sub(self,num1,num2): + return num1-num2 +``` + +```py title="Good Spacing" +class MyClass: + async def add(self, num1, num2): + return num1 + num2 + + async def sub(self, num1, num2): + return num1 - num2 +``` + +See the difference? Now, which one looks more readable? Hopefully, you answered the second example. +Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is a PEP (**Python Enhancement Proposal**) +style guide for Python. It is the style guide that is used by most Python developers and programmers, +providing a universal way to write and read code. + +### Databases + +As your bot grows, you'll inevitably have to store data for your bot. Now, most people would probably just load up some +JSON file on boot into a `dict`, modify it in memory then write to the file. However, JSON files aren't the solution. +When you write to a JSON file, it rewrites the entire file instead of just rewriting the section that changed. It's also +a configuration file format, not a storage file format. + +Instead of using a JSON file or some other related format, you should instead use a database. There are many databases +out there, like MongoDB, SQLite, and PostgreSQL to name a few. + +All of these databases I named do the job well, and which one you use depends on what features you want out of a database. + +<>{/* Maybe clarify these/add more options */} + +#### MongoDB + +MongoDB is a JSON-like format and if you already use JSON files, it shouldn't be too hard to migrate over to. + +#### SQLite + +SQLite is based on SQL, a common relational data model. It's a lightweight, easy-to-use, portable database solution that +works entirely on files. However, if for some reason you cannot read/write to and from a file, and you need to manage +lots of data, SQLite might not be for you. + +While SQLite is a part of the Python Standard Library as the `sqlite3` package, we recommend not using it as it is +synchronous and blocking. You should use an asynchronous alternative, such as [`aiosqlite`](https://pypi.org/project/aiosqlite/). + +#### PostgreSQL + +PostgreSQL is also based on SQL, but it also has more features than SQLite. It's compliant with the SQL standard, +open-source, and extensible. However, it's not that fast or simple compared to SQLite. + +#### MariaDB + +MariaDB is also based on SQL and is a fork of the MySQL project. It's compliant with the SQL standard, it's also open +source and is a complete drop-in replacement for any code with MySQL. You don't even need to change what package you're +using! diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/installation.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/installation.mdx new file mode 100644 index 00000000..521c69cd --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/installation.mdx @@ -0,0 +1,80 @@ +--- +title: Installation +sidebar_position: 2 +--- + +Before you can start using Pycord, you need to install the library. + +:::note +Python **3.8 or above** is required to use Pycord. +::: + +:::tip +Before you start installing python packages globally, it's recommended you set up a virtual environment. +You can find instructions for that [here](More/virtual-environments). +::: + +## Fresh Installation + +To install Pycord, you can use the following command in your terminal: + +``` +pip install py-cord +``` + +:::tip +Remember that you need to install `py-cord`, not `pycord`. +Also, the `pip` command varies depending on your installation. For example, it might be `python3 -m pip` on macOS/Linux or `py3 -m pip` on some versions of Windows. +::: + +If you need voice support for your bot, you should run: + +``` +pip install "py-cord[voice]" +``` + +## Migration + +### Updating Pycord + +If you are upgrading from a previous version of Pycord, you can use the following command in your terminal to upgrade to the latest version: + +``` +pip install -U py-cord +``` + +### Migrating from other libraries + +If you are migrating from another library, say, `discord.py`, first of all, you need to uninstall it. + +``` +pip uninstall discord.py +``` + +Then, you can install Pycord, it's as simple as that!: + +``` +pip install py-cord +``` + +:::caution +Uninstalling `discord.py` _after_ installing `py-cord` can cause issues. Make sure to uninstall it first! +::: + +## Installing Other Builds + +### Development Build + +:::caution +The development build comes with cutting edge features and new functionality, but as it isn't a stable build you may encounter bugs. +::: + +To install the development build, you can use the following command in your terminal: + +``` +pip install -U git+https://github.com/Pycord-Development/pycord +``` + +:::important +Git is required to install this build. [Learn how you can install Git](./more/git). +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/interactions/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/_category_.json new file mode 100644 index 00000000..ea28be60 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 4, + "label": "Interactions" +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json new file mode 100644 index 00000000..6dcafe83 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Application Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx new file mode 100644 index 00000000..b4ffeade --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx @@ -0,0 +1,85 @@ +--- +title: Context Menus +description: Learn all about Context Menus (User Commands & Message Commands) and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +When you right-click a message, you may see an option called "Apps". Hover over it, and you can see +commands a bot can run with that message. These are called message commands. + +When you right-click a user in the user list, you can once again see an option called "Apps". +Hover over it, and you can see commands a bot can run with that message. These are called user commands. + +Together, these two are called Context Menus or Context Menu Commands. These commands work very much like normal commands, except they take a member or message. + +:::note + +A bot can have up to 5 global Context Menus of each type. + +::: + +## User Commands + +Creating a user command is very simple. + +```python +@bot.user_command(name="Account Creation Date", guild_ids=[...]) # create a user command for the supplied guilds +async def account_creation_date(ctx, member: discord.Member): # user commands return the member + await ctx.respond(f"{member.name}'s account was created on {member.created_at}") +``` + + + +
+ + Account Creation Date + +
+ {defaultOptions.profiles.bob.author}'s account was created on 2020-01-01 +
+
+ +## Message Commands + +```python +@bot.message_command(name="Get Message ID") # creates a global message command. use guild_ids=[] to create guild-specific commands. +async def get_message_id(ctx, message: discord.Message): # message commands return the message + await ctx.respond(f"Message ID: `{message.id}`") +``` + + + + Do. Or do not. There is no try. + + +
+ + Get Message ID + +
+ Message ID: 930650407917748286 +
+
+ +
+ +:::info Related Topics + +- [Slash Commands](./slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx new file mode 100644 index 00000000..edac55b3 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx @@ -0,0 +1,56 @@ +--- +title: Localizations +description: Localizations are a way to make your bot more accessible to your users. Learn all about localizations now! +--- + +Localizations are a way to make your bot more accessible to your users. You can localize the command +name, the names of any arguments, and any text that is displayed to the user. + +## Syntax + +```python +@bot.slash_command( + name="ping", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + }, + options=[ + Option( + name="Example", + name_localizations={ + "en-GB": "British Example" + }, + description="Example option that does nothing", + description_localizations={ + "en-GB": "British example option that does nothing" + } + ) + ] +) +async def ping(ctx, example): + responses = {"en-US": "Pong!", + "en-GB": "British Pong!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +@bot.slash_command( + name="ping2", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + } +) +async def ping2(ctx, example: Option(str, "example", name_localizations={"en-GB": "British Example"}, description="Example option that does nothing", description_localizations={"en-GB": "British example option that does nothing"})): + responses = {"en-US": "Pong2!", + "en-GB": "British Pong2!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +``` + +- [`Locales`](https://discord.com/developers/docs/reference#locales) - List of valid locales recognized by Discord diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx new file mode 100644 index 00000000..ed454dad --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx @@ -0,0 +1,292 @@ +--- +title: Slash Commands +description: Learn all about Slash Commands and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On March 24, 2021, Discord added Slash Commands to Discord as an easier, more efficient, and better way of using bot commands. Pycord has implemented Slash Commands into the library, so it's simple, efficient, and familiar. + +:::important + +Remember that Slash Commands require your bot to be invited with the `application.commands` scope or Slash Commands will not show up. Bots already in the guild can simply be invited again with the scope; there is no need to kick the bot. + +::: + +## Syntax + +Let's create a simple Slash Command. + +```py +import discord + +bot = discord.Bot() + +# we need to limit the guilds for testing purposes +# so other users wouldn't see the command that we're testing + +@bot.command(description="Sends the bot's latency.") # this decorator makes a slash command +async def ping(ctx): # a slash command will be created with the name "ping" + await ctx.respond(f"Pong! Latency is {bot.latency}") + +bot.run("TOKEN") +``` + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +Let's go through the code. + +First, we import Pycord's `discord` package. + +Next, we create a [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot) object and assign it to a variable `bot`. + +We then go ahead and use the [`@bot.command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.command) decorator, which registers a new Slash Command. We pass a `description` parameter to give a description to the Slash Command. We can also pass a `name` parameter to change the Slash Command's name. By default, the name of the Slash Command will be the name of the function, in this case, `/ping`. + +We create an async function called `ping` with parameters `ctx`, which, when called, sends the bot's ping/latency using [`ctx.respond`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext.respond). + +## Subcommand Groups + +You might want to group certain commands together to make them more organised. A command group is exactly what it sounds like, a group of individual Slash Commands together. + +In order to make a Slash Command group, you can use the `bot.create_group` function. + +```python +import discord + +bot = discord.Bot() + +# create Slash Command group with bot.create_group +greetings = bot.create_group("greetings", "Greet people") + +@greetings.command() +async def hello(ctx): + await ctx.respond(f"Hello, {ctx.author}!") + +@greetings.command() +async def bye(ctx): + await ctx.respond(f"Bye, {ctx.author}!") + +bot.run("TOKEN") +``` + +Or, you can instead manually make a `SlashCommandGroup` class like so: + +```python +import discord + +math = discord.SlashCommandGroup("math", "Math related commands") + +@math.command() +async def add(ctx, num1: int, num2: int): + sum = num1 + num2 + await ctx.respond(f"{num1} plus {num2} is {sum}.") + +@math.command() +async def subtract(ctx, num1: int, num2: int): + sum = num1 - num2 + await ctx.respond(f"{num1} minus {num2} is {sum}.") + +# you'll have to manually add the manually created Slash Command group +bot.add_application_command(math) +``` + +Here's what the registered subcommands will look like in the Slash Command Menu: + +![Picture of the subcommands in the Slash Command Menu](../../assets/interactions/groups-and-subcommands.jpg) + +You'll notice that there's the name of the Slash Command Group and then the name of the subcommand separated by a space. + +::: + +:::info Cogs + +If you are looking to add Slash Command Groups to cogs, please look at our [Cogs page](../../popular-topics/cogs)! + +::: + +## Sub-groups + +We've made a subcommand group, but did you know that you could create a group inside another? + +```python +from discord import SlashCommandGroup +from math import sqrt + +math = SlashCommandGroup("math", "Math related commands") +advanced = math.create_subgroup("advanced", "Advanced math commands") + +@advanced.command() +async def square_root(ctx, x: int): + await ctx.respond(sqrt(x)) + +bot.add_application_command(math) +``` + +The command created above can be invoked by typing `/math advanced square_root`. + +## Options & Option Types + +Whenever you're using Slash Commands, you might notice that you can specify parameters that the user has to set or can optionally set. These are called Options. + +Options can also include a description to provide more information. [You can learn more about Options in our documentation!](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.Option) + +Since you want different inputs from Options, you'll have to specify the type for that Option; there are a few ways of doing this. + + + + +You could use Type Annotations and let Pycord figure out the option type or explicitly specified using the [`SlashCommandOptionType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.SlashCommandOptionType) enum. + +```python +import discord + +bot = discord.Bot() + +@bot.command() +# pycord will figure out the types for you +async def add(ctx, first: discord.Option(int), second: discord.Option(int)): + # you can use them as they were actual integers + sum = first + second + await ctx.respond(f"The sum of {first} and {second} is {sum}.") + +@bot.command() +# this explicitly tells pycord what types the options are instead +async def join( + ctx, + first: discord.Option(discord.SlashCommandOptionType.string), + second: discord.Option(discord.SlashCommandOptionType.string) +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + add + +
+ The sum of 1 and 1 is 2. +
+ +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+ + +Instead of Type Annotations, you can also use the option decorator. This is usually done to have type-hinting. + +```python title="Slash Command Type" +import discord + +bot = discord.Bot() + +@bot.command() +@discord.option("first", type=discord.SlashCommandOptionType.string) # type = str also works +@discord.option("second", type=discord.SlashCommandOptionType.string) # type = str also works +async def join( + ctx, + first: str, + second: str, +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+
+ +## Autocomplete + +Discord's autocomplete allows developers to determine option choices that are used in a slash command option. You can do this by defining a function: + +```py +async def get_animal_types(ctx: discord.AutocompleteContext): + """ + Here we will check if 'ctx.options['animal_type']' is a marine or land animal and return respective option choices + """ + animal_type = ctx.options['animal_type'] + if animal_type == 'Marine': + return ['Whale', 'Shark', 'Fish', 'Octopus', 'Turtle'] + else: # is land animal + return ['Snake', 'Wolf', 'Lizard', 'Lion', 'Bird'] + +@bot.slash_command(name="animal") +async def animal_command( + ctx: discord.ApplicationContext, + animal_type: discord.Option(str, choices=['Marine', 'Land']), + animal: discord.Option(str, autocomplete=discord.utils.basic_autocomplete(get_animal_types)) +): + await ctx.respond(f'You picked an animal type of `{animal_type}` that led you to pick `{animal}`!') +``` + + + +
+ + animal + +
+ You picked an animal type of Marine that led you to pick Shark! +
+
+ +:::warning + +Autocomplete can **only** be used with slash commands. + +::: + +:::info Related Topics + +- [Interactions Index](../../interactions) +- [Rules and Common Practices](../../getting-started/rules-and-common-practices) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/interactions/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/index.mdx new file mode 100644 index 00000000..8603437f --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/index.mdx @@ -0,0 +1,242 @@ +--- +title: Discord Interactions +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +In December 2020, Discord released their first Interaction: the +[Slash Command](https://discord.com/developers/docs/interactions/application-commands#slash-commands). +Since then, Discord has added many types of Interactions, including: + +[**Application Commands**](https://discord.com/developers/docs/interactions/application-commands) + +- [**Slash Commands**](https://discord.com/developers/docs/interactions/application-commands#slash-commands): + Commands that can be used with the `/` prefix. +- **Context Menu Commands**: Commands that can be used from the right-click menu. + - [**User Commands**](https://discord.com/developers/docs/interactions/application-commands#user-commands): + Commands that can be used on a user by alt-clicking/selecting them. + - [**Message Commands**](https://discord.com/developers/docs/interactions/application-commands#message-commands): + Commands that can be used on a message by alt-clicking/selecting it. + +[**UI Components**](https://discord.com/developers/docs/interactions/message-components) + +- [**Buttons**](https://discord.com/developers/docs/interactions/message-components#buttons): + Buttons are attached to a message and can be clicked on to perform an action. +- [**Select Menus**](https://discord.com/developers/docs/interactions/message-components#select-menus): + Drop-down menus are used to select a number of options from a list. +- [**Modals**](https://discord.com/developers/docs/interactions/message-components#text-inputs): + Form-like modals can be used to ask for input from a user. + +## Application Commands + +Application Commands are another set of new features that are intended to avoid compromising users' safety and privacy. +They're relatively easy to add to your bot, and give people a simpler and safer way to use commands. + +### [Slash Commands](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.SlashCommand) + +Slash Commands were the first Interaction added to Discord. They're easy to use and create, and +is the only prefix commands alternative that does not need Message Content intent. + +:::note + +Preferring prefix commands over Application Commands is **not** a valid reason to apply for the +Message Content intent. Using that as a reason will get your application denied. + +::: + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +This is what a Slash Command looks like. Not too different from a prefix command, +apart from the note telling you who invoked it. A Slash Command's fields can accept any of the following: + +- Members +- Roles +- Channels +- Attachments +- Text + +Just about as good as it gets. + +### [Message](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.MessageCommand) and [User](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.UserCommand) Commands + +Message Commands and User Commands were both introduced at around the same time, and are very similar to each other, so we'll be +introducing them together. These commands can be found in the `Apps` tab when alt-clicking. The only difference between the two is that +Message Commands only appear in the `Apps` tab of a message, while User Commands are found in the `Apps` tab of a user. Message Commands +can be used to quickly report a message, warn a user for a message, and other functions. Likewise, User Commands can be used to add a +user to a ticket, warn a user, and more. + +Here's an example of a Message Command: + + + + Hello World! + + +
+ + Reverse Message + +
+ Message 930650407917748286 reversed is "!dlroW olleH" +
+
+ +
+ +And here's an example of a User Command: + + + + {defaultOptions.profiles.dorukyum.author} has been on Discord for a long time + + +
+ + User Age + +
+ {defaultOptions.profiles.dorukyum.author} is 1 week old. +
+ +
+ + User Age + +
+ {defaultOptions.profiles.bob.author} is 40 years old. +
+ + 🤔 + +
+ +
+ +Pretty cool, right? To learn more about these two, please read the [Context Menus guide](./application-commands/context-menus.mdx). + +## [Application Commands](#application-commands) vs. [Prefix Commands](../extensions/commands/prefixed-commands) + +Ever since Discord was created, apps on it have used prefix commands. Using prefixes meant that you would have to put a +certain character (or string of characters) in front of your command, such as the exclamation mark in `!ping`. The way this +worked was that your bot would listen for messages, pick out the ones that had their specific prefix, and then respond to the command. +Now, Discord is encouraging developers to switch their bots over to Application Commands, which is a new system meant to preserve the +privacy and safety of their users. But why exactly is Discord making us switch? What's the better option, Application Commands or prefix +commands? Below, we'll discuss everything you need to know. + +### Discord's Decision + +Application Commands were conceptualized partly due to privacy concerns. When Discord first began, they weren't entirely concerned about bots +having access to the content of every message that was being sent. However, as Discord grew, this became more of a problem. Hypothetically, bots +could simply log every message they're able to receive via the Discord API and hand their contents over to a company or other third party. This is +a problem, since that data is meant to be used only by Discord. As such, they locked down Message Content, and introduced Application Commands for +bot developers to use instead. + +Prefix commands work by reading messages, as described before. Application Commands, however, don't +work this way; instead, they work by having your bot get information from Discord about when a command was used. This way, Discord can limit +Message Content only to bots that _absolutely_ depend on it, such as auto-moderation bots. + +### Who has to Use Application Commands + +Any verified bot that does not have the Message Content intent must use Application Commands. Discord is allowing developers to submit +applications for the ability to use the intent; however, since they don't want to keep supporting prefix commands due to privacy concerns, +they will automatically decline any application that includes only that as a reason. So, if your bot doesn't have an auto-moderation feature +(or any other functionality that requires Message Content), you're out of luck. + +Unverified bots, however, don't have to use Application Commands. This is because the Message Content intent is a `Privileged Intent`, meaning that +it must be applied for only if your bot is verified or about to be verified. Unverified bots don't have to apply for Privileged Intents, so they can +use them freely. + +So, if your bot is made only for a couple of servers, you can choose between prefix commands and Application Commands. However, if you plan on expanding +your bot's reach, it'll have to use Application Commands. + +### What's the Better Option + +Choosing which is the better option is up to you, if you're starting small. If +you plan on growing your bot, however, you will have to use Application Commands. Since prefix commands are slowly being phased out by Discord, +there isn't much of a choice for developers of larger bots. + +## Message Components + +Message Components are fairly new features in Discord, allowing developers to give their bots a fast +and understandable user interface. Message Components are easy to use and make your bot look modern, +sleek, and downright awesome. + +### [Views](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View) + +Views are not an Application Command nor are they a Message Component. Views are the invisible placeholders, or grid, +that Message Components lie in. Views can have up to 5 [`Action Rows`](https://docs.pycord.dev/en/stable/api/models.html#discord.ActionRow), +and Action Rows can have a maximum of 5 slots. Below, you can find a table showing how many slots a Message Interaction takes up. + +| Component | Slots | +| ------------ | ----------------------------------------------- | +| Buttons | 1 Slot | +| Select Menus | 5 Slots | +| Text Modals | 1 Slot (opened via a Button) | + +So, based on this, you could have a maximum of 25 Buttons in a View with no Select Menus, and 5 Select +Menus in a View with no Buttons. This doesn't mean you can't have them both in a View, however. You can have +a combination of them, such as 20 Buttons and a Select Menu or 10 Buttons and 3 Select Menus. + +### [Buttons](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button) + +Buttons are the first of the Message Components. They allow for quick responses to prompts, such as for canceling or continuing an action. +Of course, these aren't their only uses; people have created awesome things with Buttons, such as calculators, games, and more! + + + + Discord Buttons are awesome! +
+ + Click me! + +
+
+
+ +
+ +This is what a Button looks like, very simple and modern. To learn more about Buttons, refer to our +[Buttons page](./ui-components/buttons.mdx). + +### [Select Menus](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Select) + +Select Menus are the second of Discord's Message Components. They allow users to select from a list of choices, which your bot can then use. +Select Menus are good for things such as choosing features, pages of a help menu, and more. + +![Select Menu Example Image](../assets/interactions/select-menus-example.png) + +This is what a Select Menu looks like. While not looking as good as Buttons, they still look great +and have even greater possibilities. To learn more about Select Menus, please refer to our [Select +Menus page](./ui-components/dropdowns.mdx). + +### [Modal Dialogs](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal) + +Text Modals are the most recently added Message Component in Discord. They're useful for text input and filling out forms, such as a +sign-up for your bot's service. These are meant to replace long bot setup processes by allowing users to fill out multiple text fields, +which avoids having the user send multiple messages for the bot. Modals can be accessed by either invoking an Application Command or by +interacting with another UI Component. + +![Text Modal Example Image](../assets/interactions/modal-example.png) + +This is what a Text Modal looks like, easy to use and one of the most useful Message Components yet. To learn more about Text Modals, +please visit our [Modal Dialogs page](./ui-components/modal-dialogs.mdx). diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json new file mode 100644 index 00000000..7b0a72fe --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "UI Components", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx new file mode 100644 index 00000000..046b36c7 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx @@ -0,0 +1,314 @@ +--- +title: Buttons +description: Learn all about implementing buttons in your Discord Bot using Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On May 26, 2021, Discord added a new interaction called buttons. Instead of reactions, bots could now +send buttons and users could use them to interact with bots. This opened up a whole new world of +possibilities for bots. Soon after, developers made calculators, polls, and games like blackjack, UNO, +and even Minecraft! Buttons provided a clear and easy to use interface for interacting with bots. + +So, let's learn how you can add buttons to your bot! + +## Concept + +Buttons weren't the only update to the interactions system in Discord. Discord also added [Select Menus](./dropdowns) and [Modal Dialogs](./modal-dialogs), both of which work very similarly to buttons. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive button. + +```python +import discord + +bot = discord.Bot() # Create a bot object + +class MyView(discord.ui.View): # Create a class called MyView that subclasses discord.ui.View + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.primary, emoji="😎") # Create a button with the label "😎 Click me!" with color Blurple + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") # Send a message when the button is clicked + +@bot.slash_command() # Create a slash command +async def button(ctx): + await ctx.respond("This is a button!", view=MyView()) # Send a message with our View class that contains the button + +bot.run("TOKEN") # Run the bot +``` + +Using this command should return the following message: + + + +
+ + button + +
+ This is a button! +
+ + Click me! + +
+
+
+ +
+ +As you can see, we create a class called `MyView` that [subclasses](#oop) +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `button_callback` to the `MyView` class with the decorator +[`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button). +This decorator adds a button to a component. This function takes two arguments: the button that was +clicked and the interaction. These arguments are passed to the function when the button is clicked +by the module. We use the [`interaction.response.send_message`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse.send_message) +function to send a message to the channel where the interaction was sent. + +Finally, we create a global slash command called `button` that sends the message, along with the view +that contains a button. + +This is the basic syntax of creating a button. What you create with it is up to you. You can worry +about making your button do amazing things, while Pycord handles the rest! + +## Button Styles + + + +| Name | Usage | Color | +| --------- | ----------------------------------------------------------------------------------------- | ------- | +| Primary | `discord.ButtonStyle.primary` / `discord.ButtonStyle.blurple` | Blurple | +| Secondary | `discord.ButtonStyle.secondary` / `discord.ButtonStyle.grey` / `discord.ButtonStyle.gray` | Grey | +| Success | `discord.ButtonStyle.success` / `discord.ButtonStyle.green` | Green | +| Danger | `discord.ButtonStyle.danger` / `discord.ButtonStyle.red` | Red | +| Link | `discord.ButtonStyle.link` / `discord.ButtonStyle.url` | Grey | + +Check out the [`discord.ButtonStyle`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ButtonStyle) class for more information. + +![Different Button Styles](../../assets/interactions/button-styles.png) + +You can set a button's style by adding the `style` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) decorator. + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.success) + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots, and each button takes up 1 slot. +So, how do we move the buttons to another row? + +This can be done by specifying the `row` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) +decorator. + +:::info The `row` argument + +The row argument specifies the relative row this button belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=1, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") +``` + +## Disabling Buttons + +### Pre-Disabled Buttons + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary, disabled=True) # pass `disabled=True` to make the button pre-disabled + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView()) +``` + +### Disabling Buttons on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + button.disabled = True # set button.disabled to True to disable the button + button.label = "No more pressing!" # change the button's label to something else + await interaction.response.edit_message(view=self) # edit the message's view +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(emoji="😀", label="Button 1", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) + + @discord.ui.button(label="Button 2", style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +Sometimes, you want to have a button that is disabled after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView(timeout=30)) +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a button that is disabled after a certain amount of time, you want to have a +button that is always working. + +Normally, when the bot goes offline, all of its buttons stop working. You will be able to see the +buttons, but nothing will happen when you press them. This is a problem +if you are trying to create a self-role system with buttons, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons will stop working. When the bot comes back online, however, the buttons will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view must have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.button(label="A button", custom_id="button-1", style=discord.ButtonStyle.primary, emoji="😎") # the button has a custom_id set + async def button_callback(self, button, interaction): + await interaction.response.send_message("Button was pressed", ephemeral=True) + +@bot.command() +async def button(ctx): + await ctx.send(f"Press the button! View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many buttons can I have in a message? + +Each message can have a maximum of 25 buttons. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do buttons need any special permissions? + +No new permissions are needed for either the bot or the server to allow bots to use buttons. + +#### Should I replace reactions with buttons for my bot? + +That is up to you. Buttons do provide a cleaner interface for your bot and are easier to use. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx new file mode 100644 index 00000000..8320f25d --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx @@ -0,0 +1,339 @@ +--- +title: Select Menus +description: Learn all about implementing Select Menus or Dropdowns in your Discord Bot with Pycord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Shortly after the buttons were added, Discord added their second message component: Select Menus. Select Menus allow users to choose from a list of items sent by a bot. These are a great substitute for having a user send a number that corresponds to an option. You can even allow users to select multiple options from the Select Menus. This guide will show you the easy and painless ways of using them with Pycord. + +## Concept + +Select Menus aren't the only message component in Discord. There's also [Buttons](./buttons) and [Modal Dialogs](./modal-dialogs). Select Menus make it easy for users to pick one or multiple options from a list provided by a bot. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive select menu. + +```python +import discord + +bot = discord.Bot() + +class MyView(discord.ui.View): + @discord.ui.select( # the decorator that lets you specify the properties of the select menu + placeholder = "Choose a Flavor!", # the placeholder text that will be displayed if nothing is selected + min_values = 1, # the minimum number of values that must be selected by the users + max_values = 1, # the maximum number of values that can be selected by the users + options = [ # the list of options from which users can choose, a required field + discord.SelectOption( + label="Vanilla", + description="Pick this if you like vanilla!" + ), + discord.SelectOption( + label="Chocolate", + description="Pick this if you like chocolate!" + ), + discord.SelectOption( + label="Strawberry", + description="Pick this if you like strawberry!" + ) + ] + ) + async def select_callback(self, select, interaction): # the function called when the user is done selecting options + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") + +@bot.command() +async def flavor(ctx): + await ctx.respond("Choose a flavor!", view=MyView()) + +bot.run("TOKEN") +``` + +There's a lot going on over here! Don't worry, we will go over the code and explain it. + +As you can see, we create a class called `MyView` that subclasses +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `select_callback` to the `View` class with the decorator +[`discord.ui.select`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.select). +This decorator adds a select menu to the view. This decorator takes a few arguments to customize your select menu. Read them in the [Customization section](#customization). + +That was the decorator. Now, the function itself is pretty simple. It takes two parameters, not including `self`. The parameters are `select`: The select menu, and `interaction`: a [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object. Both of these are passed by Pycord, so you just need to specify them in the function! + + + +In the callback, you could do anything you want. You get the two parameters `select` and `interaction` to play around with. Here, we send a message using `await interaction.response.send_message` (where interaction is [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse)) with content `select.values[0]`, which sends the label of the first/only option the user selected. Obviously, this is only an example, and you could do just about anything you want. + +Finally, we create a global slash command called `flavour` that sends a message "Choose a flavor!" along with the view +that contains our select menu. + +This is the basic syntax of creating a select menu. What you create with it is up to you. You can worry +about making your code do amazing things, while Pycord handles the rest! + +## Customization + +#### Select Menu Properties + +- `select_type`: The type of select to create. This must be a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. +- `channel_types`: A list of channel types that can be selected in the menu. This is only valid for selects of `select_type` [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType). +- `options`: A list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. These are the options that can be selected in this menu. +- `placeholder` is the placeholder text shown in the select menu if no option is selected. +- `custom_id`: The ID of the select menu that gets received during an interaction. It is recommended not to set this to anything unless you are trying to create a persistent view. +- `row`: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). +- `min_values`: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `max_values`: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `disabled`: Whether the select is disabled or not. Defaults to False. + +#### Select Option Properties + +In the `options` parameter, you pass a list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. This class also has a few parameters: + +- `default` (whether the option is selected by default) +- `description` (an additional description, if any) +- `emoji` (a string or an emoji object, if any) +- `label` (the name displayed to users, can be up to 100 characters) +- `value` (a special value of the option, defaults to the label). + +## Select Types + +In addition to regular string selects, you can also have your select menu contain users, roles, mentionables, and channels as its options. You can use these alternative select types by passing a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value for the `select_type` parameter when creating the Select. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.user_select + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +Additionally, you can use shortcut decorators to create a [`discord.ui.Select`](https://docs.pycord.dev/en/master/api/ui_kit.html#discord.ui.select) with a predetermined [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. Using a shortcut decorator, the above code can be rewritten like this: + +```python +class MyView(discord.ui.View): + @discord.ui.user_select() + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +### Specifying Channel Types + +When using a [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType.channel_select) type select menu, you can pass in a list of [`discord.ChannelType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ChannelType) values to limit which types of channels users can choose when interacting with the select menu. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.channel_select, + channel_types=[discord.ChannelType.text, discord.ChannelType.voice] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"You selected {select.values[0].mention}") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots. A button takes a single slot, while a select menu takes up all 5 of them. This means a view can have a maximum of 5 select menus, or any possible combination of select menus and buttons. + +The arrangement of buttons and select menus is generally adjusted by Pycord. However, it is possible to move them to specific relative rows. This is done by specifying the `row` argument. + +:::info The `row` argument + +The row argument specifies the relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero-indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=0, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.select( + row = 1, + options = [...] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") +``` + +## Disabling Select Menus + +### Pre-Disabled Menus + +```python +class MyView(discord.ui.View): + @discord.ui.select( + disabled = True, # pass disabled=True to set the menu as disabled + options = [...] + ) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send("Select and option from the menu!", view=MyView()) +``` + +### Disabling Menus on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + select.disabled = True # set the status of the select as disabled + await interaction.response.edit_message(view=self) # edit the message to show the changes +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def first_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) # edit the message to show the changes + + @discord.ui.select(options = [...]) + async def second_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +You may want a select menu to automatically stop working after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select(ctx): + await ctx.send(view=MyView(timeout=30)) # specify the timeout here +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a select menu that is disabled after a certain amount of time, you want to have a +select menu that is always working. + +Normally, when the bot goes offline, all of its views stop working, even if they don't have a timeout. You will be able to see the +views, but nothing will happen when you try to interact with them. This is a problem +if you are trying to create a self-role system, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons and select menus will stop working. However, when the bot comes back online, the buttons and select menus will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view much have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.select(custom_id="select-1", options = [...]) # a custom_id must be set + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send(f"View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many select menus can I have in a message? + +Each message can have a maximum of 5 select menus. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do select menus need any special permissions? + +No new permissions are needed in the bot or in the server. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx new file mode 100644 index 00000000..bd585c77 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx @@ -0,0 +1,107 @@ +--- +title: Modal Dialogs +description: Learn how you can implement Modals in your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Modal Dialogs, also known as "modals", provide a form-like structure for bots to receive input from users. No extra permissions are needed for bots to send modal dialogs, so it becomes a convenient workaround for bots to receive longer input without needing the Message Content [intent](../../popular-topics/intents). + +## Concept + +Modal Dialogs consist of a title, custom ID, and up to 5 [`discord.ui.InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) components. While creating modals, we generally subclass [`discord.ui.Modal`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal), as we'll see later. + +Unlike other UI Components, Modals cannot be sent with messages. They must be invoked by an Application Command or another UI Component. + +## Usage Syntax + +```py +class MyModal(discord.ui.Modal): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.add_item(discord.ui.InputText(label="Short Input")) + self.add_item(discord.ui.InputText(label="Long Input", style=discord.InputTextStyle.long)) + + async def callback(self, interaction: discord.Interaction): + embed = discord.Embed(title="Modal Results") + embed.add_field(name="Short Input", value=self.children[0].value) + embed.add_field(name="Long Input", value=self.children[1].value) + await interaction.response.send_message(embeds=[embed]) +``` + + + + +The `ctx` parameter we define in Application Commands receives an [`ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext) object. Using its `send_modal()` coroutine, you can send a Modal dialog to the user invoking the Application Command. + +```py +@bot.slash_command() +async def modal_slash(ctx: discord.ApplicationContext): + """Shows an example of a modal dialog being invoked from a slash command.""" + modal = MyModal(title="Modal via Slash Command") + await ctx.send_modal(modal) +``` + + + + +The `interaction` parameter we define in UI Components receives an [`Interaction`](https://docs.pycord.dev/en/stable/api/models.html#discord.Interaction) object. The `response` attribute of the object contains an [`InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object, with various coroutines such as `send_message()` and `send_modal()`, which we utilize. + +```py +class MyView(discord.ui.View): + @discord.ui.button(label="Send Modal") + async def button_callback(self, button, interaction): + await interaction.response.send_modal(MyModal(title="Modal via Button")) + +@bot.slash_command() +async def send_modal(ctx): + await ctx.respond(view=MyView()) +``` + + + + +The above example uses an embed to display the results of the modal submission, but you can do anything you want with the text provided by the user. +Each input field can be accessed in the order it was added to the modal dialog, via `Modal.children`. + +## Customization + +A Modal can have up to 5 [`InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) fields. These fields offer some customization. + +Each field has a label which is shown to the user. This is defined with `label`. + +The `style` parameter is used to determine whether it should be a short (single-line) or long (multi-line) input field. + +There are a number of aliases that can be used: + +```x title="Single-line InputTextStyle values:" +short +singleline +``` + +```x title="Multi-line InputTextStyle values:" +paragraph = 2 +multiline = 2 +long = 2 +``` + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Buttons](./buttons) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/introduction.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/introduction.mdx new file mode 100644 index 00000000..3262c632 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/introduction.mdx @@ -0,0 +1,50 @@ +--- +title: Introduction +description: Pycord Guide is a complete guide for Pycord. Learn how to create Discord Bots today! +sidebar_position: 1 +--- + +Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord, written in Python. Pycord is a maintained fork of [discord.py](https://github.com/Rapptz/discord.py). + +## Before you begin + +Pycord is an advanced and complex Python library. To take advantage of the full capabilities of Pycord, you will need to have a good understanding of Python. You should know the basics of Python and have an understanding of the following concepts: + +- Variables +- Data Types +- Functions +- Packages +- Conditionals +- Loops +- Classes +- Object-Oriented Programming +- Inheritance +- Exception Handling +- Iterators +- Coroutines +- Async/Await + +This list is not exhaustive, but it should give you a good idea of what you need to know to get started. + +When you see an ellipsis - that's the three dots - in this guide, it is a placeholder for code that you need to fill in. Sometimes, it may be code for a command, while other times it could be something simple like a Guild ID. Make sure to replace them before running your bot! + +## Learning Resources + +Here are some good resources to get started or to freshen up your Python knowledge: + +- [Official Beginner's Guide](https://wiki.python.org/moin/BeginnersGuide) +- [Official Tutorial](https://docs.python.org/3/tutorial/) +- [Automate the Boring Stuff, a free online book for complete beginners to programming](https://automatetheboringstuff.com/) +- [Learn Python in y Minutes, complete cheat sheet for people who know programming already](https://learnxinyminutes.com/docs/python3/) +- [Swaroopch's free Python book](http://python.swaroopch.com/) +- [Codeabbey, exercises for beginners](http://www.codeabbey.com/) + +## Credits + +First of all, we would like to thank [Rapptz](https://github.com/Rapptz) for the original [discord.py](https://pypi.org/project/discord.py) library. Pycord is a maintained fork of this library. + +We would also like to thank the [discord.js guide](https://discordjs.guide), which inspired this guide style-wise, and the [original Pycord Guide](https://namantech.me/pycord), which inspired some content in this guide. + +We created this guide using [Docusaurus v2](https://docusaurus.io), a modern static site generator for React. We would also like to thank Danktuary for his [`@discord-message-components/react`](https://www.npmjs.com/package/@discord-message-components/react) package, from which we took the Discord message components. + +And finally, we would like to thank the amazing and loving community of Pycord users, contributors and developers. diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/more/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/more/_category_.json new file mode 100644 index 00000000..2cbe2c56 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/more/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 8, + "label": "More", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/more/community-resources.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/more/community-resources.mdx new file mode 100644 index 00000000..ed3075bd --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/more/community-resources.mdx @@ -0,0 +1,23 @@ +--- +title: Community Resources +--- + +This page showcases the amazing things created by the Pycord community, including bots, Plugins, and more. + +## Plugins + +| Name | Type | GitHub | +| --------------- | ------------ | --------------------------------------------------------------- | +| Music Cord | Music | [NixonXC/cord-music](https://github.com/NixonXC/cord-music) | +| pycord-i18n | Localization | [Dorukyum-pycord-i18n](https://github.com/Dorukyum/pycord-i18n) | +| pycord-multicog | Cogs | [pycord-multicog](https://github.com/Dorukyum/pycord-multicog) | +| EzCord | Utilities | [EzCord](https://github.com/tibue99/ezcord) | + +## Bots + +| Name | Type | Link | +| ------------------------ | ------------ | ----------------------------------------------------------------------------------- | +| Discord-Multipurpose-Bot | Multipurpose | [github](https://github.com/pogrammar/Discord-multipurpose-bot/tree/master/Python) | +| inconnu | Fun & QOL | [github](https://github.com/tiltowait/inconnu) | +| Mai | Multipurpose | [github](https://github.com/TeamMai/Mai) & [website](https://xfghoul.github.io/Mai) | +| Toolkit | Multipurpose | [github](https://github.com/Dorukyum/Toolkit) | diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/more/contributing.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/more/contributing.mdx new file mode 100644 index 00000000..469ea3ee --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/more/contributing.mdx @@ -0,0 +1,463 @@ +--- +title: Contributing to the Guide +description: Learn how to contribute to the Pycord Guide. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +This page outlines some of the basic syntax you need to know to contribute to the guide. We recommend you also check out: + +- [Docusaurus's Docs](https://docusaurus.io/docs/) +- [Contributing Rules](https://github.com/Pycord-Development/guide/blob/master/.github/CONTRIBUTING.md) + +## Info + +We use [Docusaurus v2](https://docusaurus.io/) to generate our guide. All the guide pages are generated +from `mdx` files in the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory. +MDX allows you to use JSX in your markdown content. + +## Structure + +Let's visit the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory and check its file structure. + +We can see various folders and a few files in it. Let's talk a bit about the `introduction.mdx` file. At the top, you can see something like: + +```md +--- +title: Introduction +description: ... +sidebar_position: 1 +--- +``` + +Most pages have this at the top. The `title` defaults to the file name. Since the titles need to be Capitalized according to need while the file names are lowercased (sometimes, the file names are shorter than the title!), we set a title ourselves. + +The `description` field is also important. This is the text shown in an embed when the page's link is shared on Discord, Twitter or other websites that support embedded links. Make sure to give a nice an interesting description! + +The `sidebar_position` field is pretty self-explanatory. It sets the position of the page in the sidebar. Most files in categories do not need this since they are sorted alphabetically. + +## Markdown Syntax + +This page quickly outlines some of the syntax that is used in markdown. + +````mdx +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + + ```python + print("We can use code blocks like this.") + ``` + +You can add [links to other websites](https://pycord.dev). You can add images like this: ![alternate text that describes the image](https://pycord.dev/image.png). + +- You can create +- unordered lists like this + +1. Or ordered lists +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` +4. Like this + +# Headers + +## Go + +### Like + +#### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet +```` + +
+Preview +
+ +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + +```python +print("We can use code blocks like this.") +``` + +You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](@site/static/img/favicon.ico). + +- You can create +- unordered lists like this + +1. Or ordered lists + +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` + +4. Like this + + # Headers + + ## Go + + ### Like + + #### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet + +
+
+ +## Admonitions + +We can add warnings, notes, etc. with the following syntax: + +```md +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: +``` + +
+Preview +
+ +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: + +
+ +
+ +## Discord Message Components + +As most files already have the imports for these, it's not that hard to add them. + +First, import the necessary components: + +```tsx +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; +``` + +The div starts like so: + +```tsx + + + + +
+``` + +This is where you list a `DiscordMessage`. + +```tsx + + + Hello! + + + +
+``` + + + + Hello! + + + +
+ +It has a pretty straightforward syntax. + +:::tip + +Add a `
` to the end of a component to make the content below it look better. + +::: + +### Slash Commands + +To make a message authored by a slash command, do the following: + +```tsx + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+``` + + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+ +### Buttons + +To make a message with buttons, do the following: + +```tsx + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+``` + + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+ +## Page Format + +There are a few things you need to take care of: + +1. Make sure that the spelling and grammar is perfect. We have a GitHub action configured that will warn you about spelling errors when you start a pull request. Make sure to commit your changes accordingly. + + As for the grammar, you should try reading the changes you have done and wait for reviews from others. + +2. A common mistake people make is incorrect header style. People often think that the less the important the topic is, the lower it's heading style should be. + + ```md + [PAGE STARTS] + # Topic + ## Less Important Topic + ## Subtopic + ``` + + ```md + [PAGE STARTS] + # About + [Introduction] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + That's VERY wrong. Here's the correct example: + + ```md + [PAGE STARTS] + [Introduction] + ## Topic + ## Less Important Topic + ### Subtopic + ``` + + ```md + [PAGE STARTS] + [Introduction] + + ## About + [More Information] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + Note that the `---`s at the beginning have been skipped here. diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/more/git.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/more/git.mdx new file mode 100644 index 00000000..0f929d6d --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/more/git.mdx @@ -0,0 +1,55 @@ +--- +title: Installing Git +description: Learn how you can install Git on your system. +--- + +Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Let's see how to install Git on different platforms. + +## Windows + +On Windows, Git can be installed via: + +- [Git for Windows](https://gitforwindows.org) +- [Git Scm](https://git-scm.com/download/windows) + +## Linux + +On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. + +## Mac + +You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: + +``` +xcode-select --install +``` + +## Using Package Managers + +You can also install Git using package managers. + +### Chocolatey + +If you use the Chocolatey package manager, you can install Git using: + +``` +choco install git +``` + +### Scoop + +If you use Scoop, you can install Git using: + +``` +scoop install git +``` + +### Brew + +If you're on macOS or Linux, you can install Git using: + +``` +brew install git +``` diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx new file mode 100644 index 00000000..b0b8c7ea --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx @@ -0,0 +1,62 @@ +--- +title: Virtual Environments +description: Learn how to set up a virtual environment for Pycord. +--- + +## Setup + +Sometimes you want to keep libraries from polluting system installs or use a different version of libraries than the ones installed on the system. You might also not have permissions to install libraries system-wide. For this purpose, the standard library as of Python 3.3 comes with a concept called “Virtual Environment”s to help maintain these separate versions. + +A more in-depth tutorial is found on [Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html). + +However, for the quick and dirty: + +Go to your project’s working directory: + +```bash +$ cd your-bot-source +$ python3 -m venv venv +``` + +Activate the virtual environment: + +```bash +$ source venv/bin/activate +``` + +On Windows you activate it with: + +```batch +$ venv\Scripts\activate.bat +``` + +Use pip like usual: + +```bash +$ pip install -U py-cord +``` + +Congratulations. You now have a virtual environment all set up. + +## Additional info + +It can be useful to set up a requirements.txt, so you can just put all of your dependencies in there and have pip install it. +For instance, if you wanted to have the latest 2.0 version of pycord and [pytz](https://github.com/stub42/pytz/blob/master/src/README.rst), just create a file named requirements.txt with the following contents: + +``` +py-cord>=2.0.0 +pytz +``` + +And then (in your virtual environment) you can just execute + +```bash +pip install -r requirements.txt +``` + +To keep from committing your virtual environment to git, you can set up a .gitignore file with the following line +(assuming you named your virtual environment venv like the above example): + +``` +venv/ +``` diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/_category_.json new file mode 100644 index 00000000..c38ea014 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 7, + "label": "Popular Topics", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx new file mode 100644 index 00000000..5377a6c3 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx @@ -0,0 +1,140 @@ +--- +title: Cogs +--- + +Cogs, often known as modules or extensions, are used to organize commands into groups. This is useful +for grouping commands that have the same general idea (such as moderation commands). This also helps +to avoid making your bot's files messy and cluttered. + +## Getting Started + +First, you'll need to create a folder to store your cogs, e.g. `cogs/`. + +Then, create a file inside the folder, e.g. `cogs/greetings.py`. By convention, the file name should +be the same as the name of the cog or module. + +We can then create the cog. + +```python title="./cogs/greetings.py" +import discord +from discord.ext import commands + +class Greetings(commands.Cog): # create a class for our cog that inherits from commands.Cog + # this class is used to create a cog, which is a module that can be added to the bot + + def __init__(self, bot): # this is a special method that is called when the cog is loaded + self.bot = bot + + @commands.command() # creates a prefixed command + async def hello(self, ctx): # all methods now must have both self and ctx parameters + await ctx.send('Hello!') + + @discord.slash_command() # we can also add application commands + async def goodbye(self, ctx): + await ctx.respond('Goodbye!') + + @discord.user_command() + async def greet(self, ctx, member: discord.Member): + await ctx.respond(f'{ctx.author.mention} says hello to {member.mention}!') + + math = discord.SlashCommandGroup("math", "Spooky math stuff") # create a Slash Command Group called "math" + advanced_math = math.create_subgroup( + "advanced", + "super hard math commands!" + ) + + @math.command() + async def add(self, a: int, b: int): + c = a + b + await ctx.respond(f"{a} + {b} is {c}.") + + @advanced_math.command() + async def midpoint(self, x1: float, y1: float, x2: float, y2: float): + mid_x = (x1 + x2)/2 + mid_y = (y1 + y2)/2 + await ctx.respond(f"The midpoint between those coordinates is ({mid_x}, {mid_y}).") + + @commands.Cog.listener() # we can add event listeners to our cog + async def on_member_join(self, member): # this is called when a member joins the server + # you must enable the proper intents + # to access this event. + # See the Popular-Topics/Intents page for more info + await member.send('Welcome to the server!') + +def setup(bot): # this is called by Pycord to setup the cog + bot.add_cog(Greetings(bot)) # add the cog to the bot +``` + +You can add any number of commands to your cog, as well as event listeners. However, this code will +not work on its own. In your main bot file, you must add the following code: + +```python +bot.load_extension('cogs.greetings') +``` + +This loads the file `cogs/greetings.py` and adds it to the bot. +The argument of `load_extension` should be your cog's path (e.g. cogs/greetings.py) without the file +extension and with the `/` replaced with `.` + +If you have multiple cogs, you can add them all at once by adding the following code: + +```python +cogs_list = [ + 'greetings', + 'moderation', + 'fun', + 'owner' +] + +for cog in cogs_list: + bot.load_extension(f'cogs.{cog}') +``` + +## Cog Rules + +When using a cog instead of the main file, there are some changes you have to make to your code. This +is because cogs work slightly different from a regular file. + +### The `self` variable + +The self variable is a variable that represents a class. In the case of cogs, `self` represents +the cog. In the `__init__` function, you can see that we have `self.bot = bot`. `bot` represents your +`discord.Bot` or `discord.ext.commands.Bot` instance, which is used for some functions. + +This means that instead of using functions that would usually be accessed via `bot`, you now need +to access them via `self.bot` + +Because we're in a class, all of our commands are methods of that class. Because of this, all of our +functions need to have `self` as the first parameter, where `self` is the cog. Without this, we +wouldn't be able to access our bot instance. + +### Creating Commands + +When creating prefixed commands, your decorator would usually be something like `@bot.command()`. If you're using +cogs, this isn't the case. In a cog, you can't access the bot instance outside of functions, so to +register a function as a command, you must instead use `@commands.command()`. + +Similar to prefixed commands, you'll have to use either the `@discord.slash_command()`, `@discord.user_command()`, +or `@discord.message_command()` decorators for Application Commands. + +Also, when creating a command, make sure that it is indented. If we want a command to be actually +inside a cog, it has to be inside your cog's class. If the command is not inside the cog, +your command becomes useless. + +### Events + +When creating events, you can no longer use `@bot.event` as a decorator. This is because we cannot +access the `bot` variable outside a function. To make an event, you have to use the `ext.commands` +method, `@commands.Cog.listener()`. Events also need `self` as their first parameter. + +And that's it! Cogs are a simple and easy way of organizing your code. Now you can check out how to +create a help command [here](../extensions/commands/help-command). + +:::info Related Topics + +- [Creating a Help Command](../extensions/commands/help-command) +- [Rules and Common Practices](../getting-started/rules-and-common-practices) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Application Commands](../interactions#application-commands) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx new file mode 100644 index 00000000..6c19dd29 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx @@ -0,0 +1,383 @@ +--- +title: Error Handling +description: All about handling errors. +--- + +import { + DiscordEmbed, + DiscordInteraction, + DiscordMessage, +} from "discord-message-components/packages/react"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +## About + +When using the library, errors are frequently raised due to various reasons. These reasons range from the Discord API +failing your bot's request due to missing permissions or an invalid syntax error. + +Before going into error handling, it's best that you learn the basic ways of handling errors. A good resource is: + +- [W3Schools' Guide to Python Try-Except Statements](https://www.w3schools.com/python/python_try_except.asp) + +## Basic Handling + +The most basic way to handle errors is to tackle it at the source. This can be done like so: + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +import asyncio + +import discord + +intents = discord.Intents.default() +intents.message_content = True + +bot = discord.Bot(intents=intents) + + +@bot.slash_command(description="Gets some feedback.") +@discord.option("name", description="Enter your name.") +async def feedback(ctx: discord.ApplicationContext, name: str): + try: + await ctx.respond(f"Hey, {name}! Send your feedback within the next 30 seconds please!") + + def is_author(m: discord.Message): + return m.author.id == ctx.author.id + + feedback_message = await bot.wait_for("message", check=is_author, timeout=30.0) + await ctx.send(f"Thanks for the feedback!\nReceived feedback: `{feedback_message.content}`") + except asyncio.TimeoutError: + await ctx.send("Timed out, please try again!") + + +bot.run("TOKEN") +``` + +If you respond within 30 seconds, the interaction will look like so: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Great bot! + + + Thanks for the feedback! +
+ Received feedback: Great bot! +
+
+
+ +Otherwise, if you don't respond in time, the interaction will go as follows: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Timed out, please try again! + +
+
+ +This basic method of error handling can be extended to handle +many other errors including ones raised directly by py-cord. + +## Per-Command Handling + +This type of error handling allows you to handle errors per each command you have on your bot. +Each and every command can have it's own error handler made to handle specific errors that each command may raise! + +An example of per-command error handling is as follows: + +:::note Bridge Commands + +For these types of commands, it is recommended to utilize global error handling +until [the feature](https://github.com/Pycord-Development/pycord/issues/1388) is added. +::: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot(owner_id=...) # Your Discord user ID goes in owner_id + + +@bot.slash_command(description="A private command...") +@commands.is_owner() # This decorator will raise commands.NotOwner if the invoking user doesn't have the owner_id +async def secret(ctx: discord.ApplicationContext): + await ctx.respond(f"Hey {ctx.author.name}! This is a secret command!") + + +@secret.error +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.NotOwner): + await ctx.respond("Sorry, only the bot owner can use this command!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If your ID is registered as the owner ID, you'll get the following: + + + +
+ + secret + +
+ Hey Dorukyum! This is a secret command! +
+
+
+ +Any other user whose ID doesn't match the bot owner's will get the following: + + + +
+ + secret + +
+ Sorry, only the bot owner can use this command! +
+
+
+ +This local (per-command) error handler can also be used to handle the same types of errors that standard try-except +statements can handle. This is done by using the same method as above with the `isinstance` built-in function. + +## Per-Cog Handling + +Adding error handlers per-command can be quite the task in terms of work if you have a lot. If you have happened to +group your commands in cogs, then you're in luck! You can create an error handler that is specific to a cog and +handles all errors raised by commands inside that cog. + +Here's an example of a bot with a cog that implements its own error handling: + +```python title="./cogs/dm.py" +# This cog is for DM only commands! Sadly, we only have 1 command here right now... + +import discord +from discord.ext import commands + + +class DM(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.command() + @commands.dm_only() # This decorator will raise commands.PrivateMessageOnly if invoked in a guild context. + async def avatar(self, ctx: commands.Context): + embed = discord.Embed( + title="Avatar", + description=f"Here's your enlarged avatar, {ctx.author.name}!", + color=ctx.author.top_role.color + ) + embed.set_image(url=ctx.author.display_avatar.url) + await ctx.send(embed=embed, reference=ctx.message) + + async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): + if isinstance(error, commands.PrivateMessageOnly): + await ctx.send("Sorry, you can only use this in private messages!", reference=ctx.message) + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +def setup(bot: commands.Bot): + bot.add_cog(DM(bot)) +``` + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +# This is the main file where we load the DM cog and run the bot. + +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix=commands.when_mentioned_or("!")) +bot.load_extension("cogs.dm") +bot.run("TOKEN") +``` + +If you use this command in a DM context, you'll get the following: + + + + !avatar + + +
+ + !avatar + +
+ + Here's your enlarged avatar, BobDotCom! + +
+
+
+ +Otherwise, if used in a guild context: + + + + !avatar + + +
+ + !avatar + +
+ Sorry, you can only use this in private messages! +
+
+
+ +Per-cog error handling comes in very handy as you can relegate all of your error handling to a single function instead +of spreading it out across several per-command error handlers or inside the commands themselves. + +## Global Handling + +If separating your error handling is not how you would like to handle errors, then global error handling is the way to +go. This method of handling allows you to relegate all handling to a single function that resides within your bot +instance. + +A non-subclassed bot would implement this like so: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot() + + +@bot.slash_command(description="Get the bot's current latency!") +@commands.cooldown(1, 30, commands.BucketType.user) +# ^ This decorator allows one usage of the command every 30 seconds and raises commands.CommandOnCooldown if exceeded +async def ping(ctx: discord.ApplicationContext): + await ctx.respond(f"Pong! `{int(bot.latency*1000)} ms`.") + + +@bot.event +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.CommandOnCooldown): + await ctx.respond("This command is currently on cooldown!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If you've subclassed your bot, the `on_application_command_error` event will be placed inside the subclass without a +`bot.event` decorator and `bot.slash_command` will be replaced with `discord.slash_command`. + +The error handling used above will yield this interaction if the command is used again too quickly: + + + +
+ + ping + +
+ Pong! 49 ms. +
+ +
+ + ping + +
+ This command is currently on cooldown! +
+
+
+ +The only issue regarding global error handling is that, if you have a large amount of commands, the global handler may +start to get crammed with a lot of code. This is where all the previously mentioned handlers can take their place! + +## FAQ + +#### Why does the example in per-cog handling have self at the start of its function signatures? + +This is a feature of classes and allows you to reference the cog object as `self` and get access to the bot object +passed at initialization through `self.bot`. + +If this is new to you, we recommend checking out these helpful resources to learn more about classes and cogs: + +- [W3Schools' Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [Our Cogs Guide Page](./cogs) + +#### How many errors can I handle in a single error handler? + +While all the examples in this guide page only handle one specific error and re-raise all others, all of these +error handlers can be extended to catch many errors. + +In [basic handling](#basic) (i.e. try/except statements) you can do one of two things: + +- Explicitly handle the errors you know might get raised and then have a broad `except Exception as exc:` statement + as a catch-all. +- Catch any and all errors via the catch-all statement mentioned above. + +In [per-command](#percommand), [per-cog](#percog), and [global handling](#global), you can use elif clauses with the +built-in isinstance function to catch specific errors. Atop of this, an else clause can be used to catch any other +errors you either don't want to handle or want to relegate to a different error handler. + +#### Can I use more than one type of error handler at once? + +Thankfully, all of these different ways of error handling can be mixed together, so you don't have to pick just one! +For commands that raise specific errors that no other commands will raise, you can use [per-command](#percommand). +For cogs that raise specific errors that no other cogs will raise, use [per-cog](#percog)! Lastly, for errors that +occur frequently across all commands and cogs, use [global handling](#global)! + +However, one important note to remember is that you should always raise the error again in an error handler if it +isn't handled there! If you don't do this, the error will go ignored and your other handlers won't have a chance to +do their work! + +#### What's the difference between slash and prefixed command error handling? + +Although most examples shown here use slash commands, the [per-cog handling](#percog) section presents a prefixed +command. The main difference you may notice is the change in command signature. + +To make the distinguishing features apparent: + +- Slash commands use `on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException)` + as presented in the [per-command](#percommand) and [global handling](#global) examples. +- Prefixed commands use `on_command_error(ctx: commands.Context, error: commands.CommandError)` as presented in the + [per-cog handling](#percog) example. + +This distinction is made as both types of commands need their own system for handling errors that are specific to +themselves. + +:::info Related Topics + +- [Slash Commands](../interactions/application-commands/slash-commands) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Cogs](./cogs) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx new file mode 100644 index 00000000..9f4210af --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx @@ -0,0 +1,62 @@ +--- +title: Intents +description: All about intents in Discord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +## What are Intents? + +Intents allow bot developers to "subscribe" to specific events in Discord. This is useful for bots that need to respond to specific events, such as when a user joins a server or sends a message. You could choose to enable all intents or to enable only specific intents that your bot requires. + +## How do I enable intents? + +:::important + +Remember that [Privileged Intents](#what-are-privileged-intents) require you to enable them in the Discord Developer Portal. Verified Discord Bots that don't already have access to them will need to request Discord to allow access. + +::: + + + + +```python +import discord + +bot = discord.Bot(intents=discord.Intents.all()) +``` + + + + + +You can view a list of intents and the events they subscribe to [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```python title="Enabling Intents" +import discord + +bot = discord.Bot(intents=discord.intents.members(bans=True, guilds=True)) +``` + + + + +## What are Privileged Intents? + +Discord defines some intents as "privileged" because of the sensitive information they contain. Currently, there are three privileged intents: `members`, `presences`, and `message_content`. These intents must be enabled in your bot's Developer Portal. Once your bot reaches 100 servers, you will need to verify your bot for these intents to keep working and for your bot to be able to be invited to more guilds. + +:::tip + +Only enable these intents if you need them. These intents give your bot access to quite sensitive information about the users in your guild. These intents are privileged to respect the privacy of users, and you should do that as well. + +Not enabling these intents doesn't mean you won't be able to ban users, but you will be unable to detect when a new user joins a guild, or what game they are playing. The majority of bots won't need all intents. + +::: + +:::info Related Topics + +- [Sharding Bots](sharding) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx new file mode 100644 index 00000000..c3d17197 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx @@ -0,0 +1,48 @@ +--- +title: Sharding +description: All about Sharding Discord Bots. +--- + +# Sharding + +## What is Sharding? + +Sharding is the process of breaking up your bot into smaller pieces so that it has a better time handling +events. As [Discord's Documentation](https://discord.com/developers/docs/topics/gateway#sharding) puts +it, sharding is "a method of user-controlled guild sharding which allows for splitting events across +several gateway connections." + +Sharding is used only for large bots and takes up additional resources for managing the new processes. +Pycord automatically shards your bot, so the only thing you need to do is use an `AutoShardedClient` +or `AutoShardedBot` class instead of a plain `Client` or `Bot` class. Pretty cool, right? + +Just because you _can_ shard your bot doesn't mean you _should_. While Pycord makes it easy to shard +your bot, it isn't necessary to shard unless your bot is large. Sharding a small bot isn't +just useless, but _harmful_, as it uses extra resources and may slow down your bot. Discord +themselves will let you know when your bot needs sharding, so you won't need to worry about this until they contact you. + +## How Do I Shard in Pycord? + +Sharding in Pycord is straightforward. + +Just replace your `discord.Client`, `discord.Bot`, `commands.Bot` objects +with `discord.AutoShardedClient`, `discord.AutoShardedBot`, `commands.AutoShardedBot` respectively. + +These new objects have been inherited from the original objects, so all the functions from those other types should be present. + +If you want to specify the number of shards your bot uses, +just add the `shards` parameter, along with the number of shards you want. + +## Why Should I Shard my Bot? + +Sharding is very necessary for big bots. While your bot grows, it gets harder for your bot to control +how many guilds it is in and what parts of your code should do what. This is exactly what sharding +handles, it makes all of this easier for your bot. Remember, though, only shard your bot once it's +big enough, and that's at _least_ 1,000 guilds. + +:::info Related Topics + +- [Hosting your Bot](../Getting-Started/hosting-your-bot) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx new file mode 100644 index 00000000..bd2969c1 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx @@ -0,0 +1,115 @@ +--- +title: Subclassing Bots +description: Subclassing is a popular way of creating Discord Bots. Explore how you can create a Discord bot by subclassing. +--- + +## About + +Subclassing is another popular way of creating Discord Bots. Here, you create a bot by extending a bot class. To some advanced users, this is preferable to creating a bot instance with `bot = discord.Bot()`. + +Subclassing is an intermediate python concept, so we recommend you learn about it before continuing. Some good resources are: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +## Why Subclassing? + +Many developers prefer to subclass their bots for many reasons, some of them being: + +#### Skeletal Frameworks for Bots + +Developers often share their bots code on open-source platforms, mostly GitHub, and allow users to self-host the bot (running their own instance of the bot with the code provided by the developer. Permissions vary in accordance to licences). Here, users find it easier and more convenient to have a small file that imports the custom bot class and runs it, rather than having to go through the code of the bot and find out which file to run. This makes it easier for people not familiar with programming to run and customize the bot, since it often brings down the code to: + +```python title="./main.py" +from src import Bot + +bot = Bot() + +bot.run("TOKEN") +``` + +Here, all the commands are inside the `/src` folder that the user need not bother with. + +#### Running Multiple Instances + +Some developers may need to run multiple instances of their bot (perhaps on different bot accounts). For example, a developer might have a second bot for testing alpha features. This system makes it simpler for the developer, and allows them to maintain multiple versions of the bot in the same directory: + +```python title="./alpha_bot.py" +from src import Bot + +class AlphaBot(Bot): # subclasses Bot + ... # insert any custom configuration + +bot = AlphaBot() + +@bot.slash_command() # adds a new slash command to this subclassed bot +async def alpha_feature(ctx): + await ctx.respond("Alpha Feature!") + +bot.run("TOKEN") +``` + +There are many more reasons to subclass! It's not required, and won't affect the speed of the bot, but it may affect your development process, for the good or for the worse. You don't miss out on any features when you subclass, either. Some developers want the OOP feel, while some just prefer that method and find it easier. + +## Basic Example + +```python +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override the on_ready event + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') + +bot = MyBot() + +@bot.slash_command() # create a slash command +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run('token') +``` + +As you can see, instead of creating a bot object with `bot = discord.Bot()`, we subclass [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). We then create an instance of our new bot class and run it. Notice how we don't need to use the `@event` decorator. + +Here's another example: + +```python title="./src/bot.py" +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override on_ready + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') +``` + +```python title="./src/\_\_init\_\_.py" +from .bot import MyBot # import the MyBot class from the bot.py file +``` + +```python title="./main.py" +from src import MyBot # import MyBot from /src + +bot = MyBot() # create an instance of MyBot + +@bot.slash_command() +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run("TOKEN") # run the bot +``` + +These are just two ways you could do it. There are ton of other structures you can implement. It's up to you. + +So, should you subclass? There are no limitations you face if you decide to subclass your bot, but, once again, it's up to you. + +:::info Related Topics + +- [Making a Help Command](../Extensions/Commands/help-command) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx new file mode 100644 index 00000000..23220b0e --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx @@ -0,0 +1,105 @@ +--- +title: Threads +description: Threads with Pycord +--- + +In programming, threads are a way to run multiple processes at the same time. In Discord, threads are +a way to keep multiple conversations going at the same time. Let's take a brief look at how to use threads in Pycord. + +:::tip + +Not all the methods and attributes will be covered in this guide, but you can find them in our documentation! +[Check it out!](https://docs.pycord.dev/en/stable/api/models.html#discord.Thread) + +::: + +## Creating a thread + +With a few simple lines of code, we can create threads in Pycord. + +:::important + +All public threads need a starting message. This message will start the thread. However, private threads +(which are unlocked with having your server boosted to Level 2), do not require a starting message. + +::: + +### Creating thread from a message + +```python title="Creating a Thread from a Message" +message = await ctx.send("My Starting Message") +await message.create_thread(name="thread name", auto_archive_duration=60) +``` + +You may also use other ways to create the thread, for example, by using `on_message` events or by commands. + +### Creating thread in a channel + +```python title="Creating a Thread from a Channel" +channel = bot.get_channel(...) # define this! +await channel.create_thread(name="Thread Name", message=None, auto_archive_duration=60, type=None, reason=None) +``` + +A thread type could be `news_thread`, `public_thread`, `private_thread`. You may use it by passing `type=discord.ChannelType.news_thread`. + +## Deleting Threads + +Deleting Threads is simple. You need to get a thread and then use the `delete` method. + +```python title="Deleting a Thread" +thread = bot.get_channel(thread_id) # you could use other ways to get a thread +await thread.delete() +``` + +## Editing Threads + +**Parameters** + +- `name` (str) – The new name of the thread + +- `archived` (bool) – Whether to archive the thread or not. + +- `locked` (bool) – Whether to lock the thread or not. + +- `invitable` (bool) – Whether non-moderators can add other non-moderators to this thread. Only available for private threads. + +- `auto_archive_duration` (int) – The new duration in minutes before a thread gets automatically archived for inactivity. Must be one of 60, 1440, 4320, or 10080. + +- `slowmode_delay` (int) – Specifies the slow-mode rate limit for users in the thread, in seconds. A value of 0 disables slow-mode. The maximum value possible is 21600. + +```python title="Editing a Thread" +thread = bot.get_channel(id) +await thread.edit( + name="New Name", + archived=True, + locked=True, + slowmode_delay=10, + auto_archive_duration=60, +) +``` + +As you can see, threads are very simple. Once you learn how to use them, it's easy to create whatever you want. + +## FAQ + +### Why am I getting a `Forbidden` error when I try to create a thread? + +A `Forbidden` error occurs when the bot does not have the correct permissions to create threads. + +### Why am I getting an Unknown Message error when I try to create a thread? + +Getting an error looking something like `discord.ext.commands.errors.CommandInvokeError: Command +raised an exception: HTTPException: 400 Bad Request (error code: 10008): Unknown Message`? + +There could be multiple reasons, some of them being: + +- The message does not exist +- The message already has a thread +- The message is in channel x, you are trying to start a thread in channel y. +- The message was deleted. + +:::info Related Topics + +<>{/* I can't think of any related topics for this at the moment. */} + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/voice/_category_.json b/i18n/ru/docusaurus-plugin-content-docs/current/voice/_category_.json new file mode 100644 index 00000000..8baf3da8 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/voice/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 6, + "label": "Voice" +} \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/voice/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/voice/index.mdx new file mode 100644 index 00000000..835838c6 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/voice/index.mdx @@ -0,0 +1,24 @@ +--- +title: Voice +--- + +Welcome to the guide for voice features in Pycord. + +:::caution +This guide requires previous experience with Pycord and Python. +::: + +## Requirements + +The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). +The following features are optional: + +:::tip +Opus is also a required library, but this comes with Pycord. +Some hosts may not come with it, though, so remember to always check if required dependencies are installed. +::: + +- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` +- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), + [`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), + [`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/voice/playing.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/voice/playing.mdx new file mode 100644 index 00000000..fe14c52a --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/voice/playing.mdx @@ -0,0 +1,149 @@ +--- +title: Wavelink Audio Player +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { + defaultOptions, +} from "@site/src/components/DiscordComponent"; + +# About + +Pycord and Wavelink try to keep the playing of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio playing feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/). + +## Starting out + +First you need to run a [Lavalink Server](https://github.com/freyacodes/Lavalink) to connect with. +There a multiple documentations to do this, so we are not covering that here. + +You also need to install the [wavelink](https://github.com/PythonistaGuild/Wavelink) library. + +```py title="Installing wavelink" +python3 -m pip install wavelink +``` + +You will now want to connect to your server via a node. + +```py title="Connect Node with Lavalink" +import discord +import wavelink + +bot = discord.Bot() + +async def connect_nodes(): + """Connect to our Lavalink nodes.""" + await bot.wait_until_ready() # wait until the bot is ready + + nodes = [ + wavelink.Node( + identifier="Node1", # This identifier must be unique for all the nodes you are going to use + uri="http://0.0.0.0:443", # Protocol (http/s) is required, port must be 443 as it is the one lavalink uses + password="youshallnotpass" + ) + ] + + await wavelink.Pool.connect(nodes=nodes, client=bot) # Connect our nodes +``` + +
+ +Now you are finished making your node! Next, you will want to: + +1. Making a play command +2. Adding connect events + +### Making a play command + +To make a play command, you will need to make a function to connect and play audio in a voice channel. + +```py title="Play Command Example" +import typing + +@bot.slash_command(name="play") +async def play(ctx, search: str): + # First we may define our voice client, + # for this, we are going to use typing.cast() + # function just for the type checker know that + # `ctx.voice_client` is going to be from type + # `wavelink.Player` + vc = typing.cast(wavelink.Player, ctx.voice_client) + + if not vc: # We firstly check if there is a voice client + vc = await ctx.author.voice.channel.connect(cls=wavelink.Player) # If there isn't, we connect it to the channel + + # Now we are going to check if the invoker of the command + # is in the same voice channel than the voice client, when defined. + # If not, we return an error message. + if ctx.author.voice.channel.id != vc.channel.id: + return await ctx.respond("You must be in the same voice channel as the bot.") + + # Now we search for the song. You can optionally + # pass the "source" keyword, of type "wavelink.TrackSource" + song = await wavelink.Playable.search(search) + + if not song: # In case the song is not found + return await ctx.respond("No song found.") # we return an error message + + await vc.play(song) # Else, we play it + await ctx.respond(f"Now playing: `{song.title}`") # and return a success message +``` + + + +
+ + play + +
+ Now playing: Never Gonna Give You Up +
+
+ +
+ +Now that you've done this, the only thing left to do is make your connect events. + +### Adding connect events + +The final step to this guide is connecting the node to your server when the bot goes online. + +To make it, you will want to do the following: + +```py title="Adding connect events" +@bot.event +async def on_ready(): + await connect_nodes() # connect to the server + +@bot.event +async def on_wavelink_node_ready(payload: wavelink.NodeReadyEventPayload): + # Everytime a node is successfully connected, we + # will print a message letting it know. + print(f"Node with ID {payload.session_id} has connected") + print(f"Resumed session: {payload.resumed}") + +bot.run("token") +``` + +Congratulations! You have now implemented voice playing into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/voice/receiving.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/voice/receiving.mdx new file mode 100644 index 00000000..1bc364e1 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/voice/receiving.mdx @@ -0,0 +1,130 @@ +--- +title: Receiving Voice Samples +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +# About + +Pycord tries to keep the recording of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio recording feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/audio_recording.py). + +## Starting out + +The first thing you want to do is make a cache of your voice connections. This is fairly easy; as +it's just putting a variable with an empty dictionary in our code, such as `connections = {}`. + +You will now want to create your command for recording. + +```py title="Record Command Example" +import discord + +bot = discord.Bot() +connections = {} + +@bot.command() +async def record(ctx): # If you're using commands.Bot, this will also work. + voice = ctx.author.voice + + if not voice: + await ctx.respond("You aren't in a voice channel!") + + vc = await voice.channel.connect() # Connect to the voice channel the author is in. + connections.update({ctx.guild.id: vc}) # Updating the cache with the guild and channel. + + vc.start_recording( + discord.sinks.WaveSink(), # The sink type to use. + once_done, # What to do once done. + ctx.channel # The channel to disconnect from. + ) + await ctx.respond("Started recording!") +``` + + + +
+ + record + +
+ Started recording! +
+
+ +
+ +Now you are finished making your command for voice receiving! Next, you will want to: + +1. Make your finished callback +2. Make a stop command + +### Making a Callback + +To make a callback, you will want to define the currently undefined `once_done` function inside +our command, like so: + +```py title="Recorder Callback" +async def once_done(sink: discord.sinks, channel: discord.TextChannel, *args): # Our voice client already passes these in. + recorded_users = [ # A list of recorded users + f"<@{user_id}>" + for user_id, audio in sink.audio_data.items() + ] + await sink.vc.disconnect() # Disconnect from the voice channel. + files = [discord.File(audio.file, f"{user_id}.{sink.encoding}") for user_id, audio in sink.audio_data.items()] # List down the files. + await channel.send(f"finished recording audio for: {', '.join(recorded_users)}.", files=files) # Send a message with the accumulated files. +``` + + + + finished recording audio for:{" "} + {defaultOptions.profiles.bob.author} + + + +
+ +Now that you've done this, the only thing left to do is make your stop command. + +### Making a Stop Command + +The final step to this guide is stopping the audio recording. This is the easiest step by far. + +To make it, you will want to do the following: + +```py title="Stop Recording Command" +@bot.command() +async def stop_recording(ctx): + if ctx.guild.id in connections: # Check if the guild is in the cache. + vc = connections[ctx.guild.id] + vc.stop_recording() # Stop recording, and call the callback (once_done). + del connections[ctx.guild.id] # Remove the guild from the cache. + await ctx.delete() # And delete. + else: + await ctx.respond("I am currently not recording here.") # Respond with this if we aren't recording. + +bot.run("token") +``` + +Congratulations! You have now implemented voice recording into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/ru/docusaurus-plugin-content-pagesindex.tsx b/i18n/ru/docusaurus-plugin-content-pagesindex.tsx new file mode 100644 index 00000000..84df3a9c --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-pagesindex.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import DefaultLayout from "../layouts/DefaultLayout"; +import PYCHero from "@site/src/components/PYCHero"; +import PYCButton from "@site/src/components/PYCButton"; + +export default function Home(): JSX.Element { + return ( + + +
+ Imagine a place where you can learn how to create an awesome Discord + bot, equip it with Pycord, and have it running in less than a minute. + Imagine a place where you can learn everything about Pycord. Imagine a + guide. A Pycord Guide! +

+ Whether you are a newbie or an experienced developer, you will find + everything you need to know about Pycord here. This guide will teach + you: +
    +
  • How to get a brand new bot running from scratch;
  • +
  • How to create Interactions, Context Menus and Commands;
  • +
  • In-depth concepts such as Embeds, Reactions, Help Commands, Paginators, etc;
  • +
  • Popular Topics such as working with Databases, Sharding, etc;
  • +
  • Ways to handle and manage common errors and best practices for bots;
  • +
  • And Much More!
  • +
+
+
+ ); +} diff --git a/i18n/ru/docusaurus-theme-classic/footer.json b/i18n/ru/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..ffb8a652 --- /dev/null +++ b/i18n/ru/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Pycord Development, All rights reserved.", + "description": "The footer copyright" + } +} diff --git a/i18n/ru/docusaurus-theme-classic/navbar.json b/i18n/ru/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..473b847e --- /dev/null +++ b/i18n/ru/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "Pycord Guide", + "description": "The title in the navbar" + }, + "item.label.Home": { + "message": "Home", + "description": "Navbar item with label Home" + }, + "item.label.Docs": { + "message": "Docs", + "description": "Navbar item with label Docs" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + }, + "item.label.Source": { + "message": "Source", + "description": "Navbar item with label Source" + } +} diff --git a/i18n/zh/code.json b/i18n/zh/code.json new file mode 100644 index 00000000..9cce6148 --- /dev/null +++ b/i18n/zh/code.json @@ -0,0 +1,404 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { + "message": "Toggle the collapsible sidebar category '{label}'", + "description": "The ARIA label to toggle the collapsible sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search here", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.algoliaLabel": { + "message": "Search by Algolia", + "description": "The ARIA label for Algolia mention" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorite", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "You might want to check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Algolia" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Try searching for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Believe this query should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/i18n/zh/docusaurus-plugin-content-blog/options.json b/i18n/zh/docusaurus-plugin-content-blog/options.json new file mode 100644 index 00000000..9239ff70 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/zh/docusaurus-plugin-content-docs/current.json b/i18n/zh/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..36b4849a --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,46 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.defaultSidebar.category.Getting Started": { + "message": "Getting Started", + "description": "The label for category Getting Started in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Interactions": { + "message": "Interactions", + "description": "The label for category Interactions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Application Commands": { + "message": "Application Commands", + "description": "The label for category Application Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.UI Components": { + "message": "UI Components", + "description": "The label for category UI Components in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Extensions": { + "message": "Extensions", + "description": "The label for category Extensions in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Commands": { + "message": "Commands", + "description": "The label for category Commands in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Pages": { + "message": "Pages", + "description": "The label for category Pages in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Voice": { + "message": "Voice", + "description": "The label for category Voice in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.Popular Topics": { + "message": "Popular Topics", + "description": "The label for category Popular Topics in sidebar defaultSidebar" + }, + "sidebar.defaultSidebar.category.More": { + "message": "More", + "description": "The label for category More in sidebar defaultSidebar" + } +} diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png b/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png new file mode 100644 index 00000000..7480e1da Binary files /dev/null and b/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/button-styles.png differ diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg b/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg new file mode 100644 index 00000000..ce6b5110 Binary files /dev/null and b/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/groups-and-subcommands.jpg differ diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png b/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png new file mode 100644 index 00000000..846eee15 Binary files /dev/null and b/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/modal-example.png differ diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png b/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png new file mode 100644 index 00000000..32a47d04 Binary files /dev/null and b/i18n/zh/docusaurus-plugin-content-docs/current/assets/interactions/select-menus-example.png differ diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/_category_.json new file mode 100644 index 00000000..309b494a --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 5, + "label": "Extensions", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json new file mode 100644 index 00000000..652aa4ee --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/bridge/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Bridge" +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx new file mode 100644 index 00000000..81545fa2 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/bridge/index.mdx @@ -0,0 +1,190 @@ +--- +title: Bridge +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +## Concept + +Let's say that you want to make a command that is both a Slash Command and a Prefixed Command. Now, you could just copy and paste the code from the first command callback to the other and make some adjustments, but that's not very efficient. + +This is where the `ext.bridge` module comes in. It allows you to use one callback to make both a Slash Command and a Prefixed Command. + +### Example Usage + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def hello(ctx): + await ctx.respond("Hello!") + +bot.run("TOKEN") +``` + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+
+ +## Syntax + +First, instead of using `discord.Bot` or `commands.Bot`, we use `bridge.Bot`. `bridge.Bot` does inherit from `commands.Bot`, so you can do anything with `bridge.Bot` that `commands.Bot` can do. +Then, we define a command with `@bot.bridge_command()`. This makes a Bridge Command, which has both a Prefixed Command counterpart and a Slash Command counterpart. +Next, the callback has access to a `ctx` object, which is the context of the command. This context is either of `BridgeApplicationContext` type or `BridgeExtContext`. Because of that, it makes detecting how the function was called easier. + +### Using Bridge Commands in a Cog + +Like Slash Commands and Prefixed Commands, you can use Bridge Commands in a Cog. You can do this by using the `bridge_command` decorator. Here's an example: + +```python +import discord +from discord.ext import bridge, commands + +class Greetings(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @bridge.bridge_command() + async def hello(self, ctx): + await ctx.respond("Hello!") + + @bridge.bridge_command() + async def bye(self, ctx): + await ctx.respond("Bye!") + +def setup(bot): + bot.add_cog(Greetings(bot)) +``` + +The cog will automatically split the Bridge Command into their Slash Command and Prefixed Command counterparts. + + + +
+ + hello + +
+ Hello! +
+ + + !hello + + + +
+ + !hello + +
+ Hello! +
+ + +
+ + bye + +
+ Bye! +
+ + + !bye + + + +
+ + !bye + +
+ Bye! +
+
+ +### Deferring + +You can defer if you want to communicate to the user that your bot is busy processing the command. This is done by using `ctx.defer()`. For the Slash Command implementation, `ctx.defer()` calls the function that gives out a "Bot is thinking" message. For the Prefixed Command implementation, `ctx.defer()` enables the typing indicator. + + + +### Options + +Options are pretty straightforward. You just specify them like you do with prefixed commands, and you're all set! + +```python +import discord +from discord.ext import bridge + +intents = discord.Intents() +intents.message_content = True + +bot = bridge.Bot(command_prefix="!", intents=intents) + +@bot.bridge_command() +async def sum(ctx, a: int, b: int): + await ctx.respond(a + b) + +bot.run("TOKEN") +``` + + + +
+ + sum + +
+ 4 +
+ + + !sum 2 2 + + + +
+ + !sum 2 2 + +
+ 4 +
+
diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json new file mode 100644 index 00000000..63f8e08e --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx new file mode 100644 index 00000000..bf345c07 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/groups.mdx @@ -0,0 +1,56 @@ +--- +title: Command Groups +--- + +Command groups are a way to create subcommands for your commands. For example, `!afk set` or `!afk +remove`. + +## Syntax + +Creating a command group is very simple. + +```python title="Command Groups Example" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!') + +@bot.group() +async def afk(): + pass + +@afk.command() +async def set(): + ... + +@afk.command() +async def remove(): + ... + +# Another command group + +@bot.group(invoke_without_command=True) # Indicates if the group callback should begin parsing and invocation only if no subcommand was found. +async def math(ctx): + await ctx.send('Subcommand not found') + +@math.command() +async def add(ctx, a: int, b: int): + ... + +@math.command() +async def subtract(ctx, a: int, b: int): + ... +``` + +To create a command group, the command's decorator must be `@bot.group`. Once you have a command with +that decorator, you can use `@function.command()`, such as `@math.command()`. Now, you have subcommand +groups! + + + +:::info Related Topics + +- [Prefixed Commands](./prefixed-commands.mdx) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx new file mode 100644 index 00000000..acbdc0a8 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/help-command.mdx @@ -0,0 +1,481 @@ +--- +title: Help Command +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Pycord's `commands` extension comes with a built-in help command. In this guide, we will take a look at them as well as learn how to create your own. Let's dive in! + +:::note + +This guide demonstrates using object-oriented programming and subclassing to make a help command for your +Pycord bot. It is important to understand these two concepts before continuing. + +**Learning Resources**: + +- [W3Schools - Python Subclassing](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools - Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +::: + +## The Wrong Way + +A popular way to create a help command is to disable the built-in help command and create your own. This is not recommended as it will lead to a lot of confusion. + +```python title="The Wrong Way" +bot = commands.Bot(command_prefix='!', help_command=None) +# OR +bot.help_command = None +# OR +bot.remove_command("help") + +@bot.command() +async def help(ctx, *, argument=None): + ... +``` + +While it's possible to create a help command this way, doing so does not utilize the full capabilities +of making one with Pycord. Making a help command with subclassing and OOP will save time and effort. + +## Types of Help Commands + +There are two types of built-in help commands: + +- [`DefaultHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand) +- [`MinimalHelpCommand`](https://docs.pycord.dev/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand) + +`DefaultHelpCommand` is the command enabled by default. It isn't the best looking, but `MinimalHelpCommand` can help make it look a bit better. + + + + +```python title="Default Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.DefaultHelpCommand()) # help_command is DefaultHelpCommand by default so it isn't necessary to enable it like this +# We enable it here for the sake of understanding + +... + +bot.run("token") +``` + + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ + +```python title="Minimal Help Command" +import discord +from discord.ext import commands + +bot = commands.Bot(command_prefix='!', help_command=commands.MinimalHelpCommand()) + +... + +bot.run("token") +``` + + + + !help + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+ +
+ +
+ +## Updating Built-in Help Commands + +Let's try to make the `MinimalHelpCommand` look better. We can do this by putting its content in an +embed. + +```python title="Minimal Help Command Example" +bot = commands.Bot(command_prefix='!') + + +class MyNewHelp(commands.MinimalHelpCommand): + async def send_pages(self): + destination = self.get_destination() + for page in self.paginator.pages: + emby = discord.Embed(description=page) + await destination.send(embed=emby) + +bot.help_command = MyNewHelp() +``` + +Let's go through the code. + +First, we create a new class called `MyNewHelp`. This class is a subclass of `MinimalHelpCommand`. + +Next, we override the `send_pages` method. This method is responsible for sending the help command to +the user. We override this method because we don't want to change the content of the pages, just how +they are sent. + +We use the `get_destination` method to get the destination of the message. This is the channel or use that the help +command is to be sent to. + +We use the `paginator.pages` property to get the different pages of the help command. We put the page +in an embed, and then send the embed to the destination channel. + +Finally, we set this as our new help command using `bot.help_command = MyNewHelp()`. + + + + + Use !help \[command] for more info on a command. +
+ You can also use !help \[category] for more info on a + category. +
+
+ + {" "} + No Category{" "} + +
+ help ping +
+
+
+ +## Creating Your Help Command + +Not satisfied with the built-in help commands? You can create your own! + +For this, we will subclass the `HelpCommand` class. + +There are 4 methods that we need to override: + +- `HelpCommand.send_bot_help(mapping)` that gets called with `help` +- `HelpCommand.send_command_help(command)` that gets called with `help ` +- `HelpCommand.send_group_help(group)` that gets called with `help ` +- `HelpCommand.send_cog_help(cog)` that gets called with `help ` + +### Bot Help + +```python title="Bot Help Example" +class MyHelp(commands.HelpCommand): + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help") + for cog, commands in mapping.items(): + command_signatures = [self.get_command_signature(c) for c in commands] + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's go through the code. + +- First, we create a new class called `MyHelp`. This class is a subclass of `HelpCommand`. + +- Next, we override the `send_bot_help` method. This method is responsible for sending the main help + command to the user. + +- We create an embed with the title "Help". + +- We iterate through `mapping.items()`, which returns a list of tuples, the first element being the + cog and the second element being a list of commands. + +- By using `self.get_command_signature(c)` we get the signature of the command, also known as the + `parameters` or `arguments`. + +- There is a chance that the cog is empty, so we use `if command_signatures:`. + +- We get the name of the cog using `getattr(cog, "qualified_name", "No Category")`. This calls the + cog's attribute `qualified_name` which returns "No Category" if the cog has no name. + +- We add a field to the embed with the name of the cog and the value of the command signatures. + +- Finally, we send the embed to the channel. + +Let's improve the code a little. + +```python title="Improved Bot Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + command_signatures = [self.get_command_signature(c) for c in filtered] + + if command_signatures: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Now the help command won't show commands that the user can't use, as well as aliases for commands. +Let's get the help command to show command aliases. + +### Command Help + +This function is called when the user uses `help `. + +```python title="Command Help Example" +class MyHelp(commands.HelpCommand): + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command), color=discord.Color.random()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + +bot.help_command = MyHelp() +``` + +Let's quickly go through the code we haven't discussed yet. + +- In line 3, we create an embed with a title the signature of the command (so that the title of the + embed looks like ` [parameter]`), and a random color. + +- In lines 4 and 5, we get the command's `help` description and add it to the embed. The help description + of a command can be specified in the docstrings of a command function. For example: + + ```` + ```python + @bot.command() + async def ping(ctx): + """Returns the latency of the bot.""" + await ctx.send(f"Pong! {round(bot.latency * 1000)}ms") + ``` + ```` + +- Line 6 is shorthand for + + ```python + alias = command.aliases + if alias: + ... + + # is the same as + + if alias := command.aliases: + ... + ``` + + A very helpful (but not well-known) Python shorthand! + +- In line 7, we get the aliases of the command and add them to the embed. + +### Cog Help + +This is pretty easy! + +```python title="Custom Cog Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_cog_help(self, cog): + embed = discord.Embed(title=cog.qualified_name or "No Category", description=cog.description, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(cog.get_commands()): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Once again, we create an embed, get the commands that the user can use, and add them to the embed. + +### Group Help + +Similar to the cog help, this is pretty easy! + +```python title = "Custom Group Help Example" +class MyHelp(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_group_help(self, group): + embed = discord.Embed(title=self.get_command_signature(group), description=group.help, color=discord.Color.blurple()) + + if filtered_commands := await self.filter_commands(group.commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No Help Message Found... ") + + await self.get_destination().send(embed=embed) +``` + +Add all of these methods together, and you have a fully functioning help command! + +
+Click to see the final code for this section +
+ +:::note + +The following code has been slightly edited from the tutorial version. + +::: + +```python title="Custom Help Command Example" +class SupremeHelpCommand(commands.HelpCommand): + def get_command_signature(self, command): + return '%s%s %s' % (self.context.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Help", color=discord.Color.blurple()) + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort=True) + if command_signatures := [ + self.get_command_signature(c) for c in filtered + ]: + cog_name = getattr(cog, "qualified_name", "No Category") + embed.add_field(name=cog_name, value="\n".join(command_signatures), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_command_help(self, command): + embed = discord.Embed(title=self.get_command_signature(command) , color=discord.Color.blurple()) + if command.help: + embed.description = command.help + if alias := command.aliases: + embed.add_field(name="Aliases", value=", ".join(alias), inline=False) + + channel = self.get_destination() + await channel.send(embed=embed) + + async def send_help_embed(self, title, description, commands): # a helper function to add commands to an embed + embed = discord.Embed(title=title, description=description or "No help found...") + + if filtered_commands := await self.filter_commands(commands): + for command in filtered_commands: + embed.add_field(name=self.get_command_signature(command), value=command.help or "No help found...") + + await self.get_destination().send(embed=embed) + + async def send_group_help(self, group): + title = self.get_command_signature(group) + await self.send_help_embed(title, group.help, group.commands) + + async def send_cog_help(self, cog): + title = cog.qualified_name or "No" + await self.send_help_embed(f'{title} Category', cog.description, cog.get_commands()) + +bot.help_command = SupremeHelpCommand() +``` + +
+
+ +## Command Attributes + +How can you add cooldowns, set aliases, and change the name of help commands? Command attributes can +help you do all of that, and more! + +```python title="Help Command Attributes" +attributes = { + 'name': "help", + 'aliases': ["helpme"], + 'cooldown': commands.CooldownMapping.from_cooldown(3, 5, commands.BucketType.user), +} + +# You need to use CooldownMapping.from_cooldown(rate, per, type) + +bot.help_command = MyHelp(command_attrs=attributes) +``` + +## Error Handling + +When a user attempts to use a command that does not exist, we need to inform the user. +We can do this by overriding the `send_error_message` function. + +```python title="Custom Help Error Example" +class MyHelp(commands.HelpCommand): + async def send_error_message(self, error): + embed = discord.Embed(title="Error", description=error, color=discord.Color.red()) + channel = self.get_destination() + + await channel.send(embed=embed) +``` + + + + !help update_pycord + + + + Command 'update_pycord' not found. + + + + +## Credits + +Most of the content from this guide is from +[InterStella0's walkthrough guide on subclassing HelpCommand](https://gist.github.com/InterStella0/b78488fb28cadf279dfd3164b9f0cf96). +Thanks to InterStella0 for making this guide amazing. + +:::info Related Topics + +- [Subclassing Bots](../../Popular-Topics/subclassing-bots) +- [Prefixed Commands](./prefixed-commands) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx new file mode 100644 index 00000000..b8f567fd --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/commands/prefixed-commands.mdx @@ -0,0 +1,324 @@ +--- +title: Prefixed Commands +description: Learn how to use the commands extension for Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Before Discord added slash commands, all bots had prefixed commands. A user would type the bot's prefix +followed by a word or phrase to invoke a command, such as `?help` or `!help`. +However, this prefixed commands system isn't native to Discord! Developers made use of an `on_message` +event to check if the message began with a certain character, then invoke the command. Every time a +message was sent, the bot would see the message and check for its "prefix" + +The syntax becomes a little more complicated when you want to have multiple commands. There are several +disadvantages to this system. This is where the commands extension comes in. `ext.commands` has +various advantages, such as: + +- Simpler syntax +- Easier to use +- Easier to parse user input +- Comes with built-in help commands +- Comes with a built-in system for categorizing commands + + + + +```python title="Prefixed Commands with Events" +import discord + +client = discord.Client() + +@client.event +async def on_message(message): + if message.content.startswith("!ping"): + await message.channel.send("Pong!") + + elif message.content.startswith("!announce"): + if len(message.content.split(" ")) < 3: + await message.channel.send("You need to specify a title and a message. Correct usage: `!announce Hello Hello everyone!`") + return + + msg = message.content.split(" ", 2) + title = msg[1] + content = msg[2] + + await message.channel.send("**{}**\n{}".format(title, content)) + + elif message.content.startswith("!"): + await message.channel.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !help + + + Unknown Command. + +
+ +
+ + +```python title="The Commands Extension" +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix="!", intents=intents) + +@bot.command() +async def ping(ctx): + await ctx.send("Pong!") + +@bot.command() +async def announce(ctx, title, *, message): + await ctx.send("**{}**\n{}".format(title, message)) + +@bot.event +async def on_command_error(ctx, error): + if isinstance(error, commands.CommandNotFound): + await ctx.send("Unknown command.") +``` + + + + !ping + + + Pong! + + + !announce Hello Hello World! + + + Hello +
+ Hello World! +
+ + !pycord + + + Unknown command. + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+ !announce +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The commands extension has many more uses. This example only showcases the basic features mentioned +in the previous example. Other things you can do with the commands extension include using a different +built-in help command and creating your own. The following tutorials showcase these. + +::: + +
+
+ +## Syntax + +Before we check out the syntax, let's take a look at the bot classes. + +> `discord.Client` - Contains only events. +> +> `discord.Bot` - Subclasses `discord.Client`, adds commands. +> +> `discord.ext.commands.Bot` - Subclasses `discord.Bot`, adds prefixed commands, cogs, and more. + +This means that `discord.ext.commands.Bot` has both slash commands and prefixed commands, as well as +events, cogs and more. + +Now let's look at the syntax. + +```python title="A Simple Prefixed Bot" +import discord +from discord.ext import commands # Import the commands extension +# discord.ext.commands are not the same as discord.commands! + +intents = discord.Intents.default() #Defining intents +intents.message_content = True # Adding the message_content intent so that the bot can read user messages + +bot = commands.Bot(command_prefix="!", intents=intents) # You can change the command prefix to whatever you want. + +@bot.command() # This is the decorator we use to create a prefixed command. +async def ping(ctx): # This is the function we will use to create the command. + await ctx.send("Pong!") # This is the response the bot will send. + + +bot.run("token") # Run the bot with your token. +``` + + + + !ping + + + Pong! + + + !help + + + + No Category: +
+
+ !help Shows this message +
+ !ping +
+
+ Type !help command for more info on a command. +
+ You can also type !help category for more info on a category. +
+
+
+ +
+ +:::tip + +The help command is a built-in command and is enabled by default. You will learn more about it in the +following guides. + +::: + +## Parameters + +Prefixed commands can take parameters, just like slash commands. You can specify the parameters in +the function itself. + +```python title="Parameters Example 1" +@bot.command() +async def echo(ctx, *, message): + await ctx.send(message) +``` + +`ctx` is the context of the message. `*` means that the parameter can be any number of words. `message` +is the parameter. If you had not passed `*`, `message` would only have been one word. + +For example, if a user had used `!echo hello world`, `message` would have been `hello`. Since we +passed `*`, `message` is `hello world`, or the rest of the message. + +We can pass multiple parameters too! + +```python title="Parameters Example 2" +@bot.command() +async def echo(ctx, channel:discord.TextChannel, title, *, message): + await channel.send("**{}**\n{}".format(title, message)) +``` + +In the example above, `channel` is a parameter that is of type `discord.TextChannel`. When you +specify the type of the parameter, Pycord will automatically try to convert the parameter to that type. +That is why you can use `channel.send` directly without needing to convert it first. + +We also have a new parameter, `title`. This does not have a type, so it will be a string. `*` means +that the rest of the message belongs to the next parameter, in this case, `message`. + +When a user types `!echo #general Greetings! Hello World!`, `channel` will be the text channel +`#general`, `title` will be `Greetings!` and `message` will be `Hello World!`. + +Let's take an example where the user passes `!echo #general Holiday Greetings! Greetings to you all!`. +Here, the user wants the title to be "Holiday Greetings!" and the message to be "Greetings to you all!". +However, since Pycord parses the message at whitespaces, the title will end up being "Holiday" and the +message "Greetings! Greetings to you all!". The user can prevent this by typing `!echo "Holiday +Greetings!" Greetings to you all!`. + + + + + + !echo #general Holiday Greetings! Greetings to you all! + + + Holiday +
+ Greetings! Greetings to you all! +
+ + !echo #general "Holiday Greetings!" Greetings to you all! + + + Holiday Greetings! +
+ Greetings to you all! +
+
+ +Let's check out another example for parameters and parameter types. + +```python title="Parameters Example 3" +import random + +@bot.command() +async def gtn(ctx, guess:int): + number = random.randint(1, 10) + if guess == number: + await ctx.send("You guessed it!") + else: + await ctx.send("Nope! Better luck next time :)") +``` + +If you had not specified the type of the parameter, it would have been a string. And since `"5"` is not +the same as `5` in python, the bot would have responded with "Nope! Better luck next time :)". +Even if you do not specify the type of the parameter, you can still convert it later on, in this case, +with `int(guess)`. + +:::info Related Topics + +- [Command Groups](groups) +- [Rules and Common Practices](../../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json new file mode 100644 index 00000000..baeba701 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/pages/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Pages", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx new file mode 100644 index 00000000..be90b035 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/pages/paginator-basics.mdx @@ -0,0 +1,168 @@ +--- +title: Paginator Basics +--- + +# Paginator Basics + +## [Page](https://docs.pycord.dev/en/stable/ext/pages/index.html#page) + +This class contains two attributes: `content` and `embeds`, which correspond to the attributes of the same name on the +`discord.Message` class. +To create a new Page, use the following syntax: + +```py +import discord +page = Page(content="My Page Content", embeds=[discord.Embed(title="My First Embed Title")]) +``` + +## [PageGroup](https://docs.pycord.dev/en/stable/ext/pages/index.html#pagegroup) + +This class represents a group of pages. It uses most of the same parameters as `Paginator`, which allows each +`PageGroup` to effectively have its own settings and behaviours. + +## [Paginator](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator) + +This is the main class for `ext.pages`, and is used to control most of the functionality of the extension. + +In its most basic form, with no arguments provided (default values listed below), a paginator can be created like so: + +```py title="Paginator Example" +import discord +from discord.ext.pages import Paginator, Page + +my_pages = [ + Page( + content="This is my first page. It has a list of embeds and message content.", + embeds=[ + discord.Embed(title="My First Embed Title"), + discord.Embed(title="My Second Embed Title"), + ], + ), + Page( + content="This is my second page. It only has message content.", + ), + Page( + embeds=[ + discord.Embed( + title="This is my third page.", + description="It has no message content, and one embed.", + ) + ], + ), +] +paginator = Paginator(pages=my_pages) +``` + +The only required parameter for `Paginator` is the `pages` parameter, which is usually a list of `Page` objects. + +You can also pass in a list of `PageGroup` objects, a list of strings, a list of embeds, or a list of lists of embeds. + +Once the `Paginator` instance is created, you can call either +[`Paginator.send()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.send) +or [`Paginator.respond()`](https://docs.pycord.dev/en/stable/ext/pages/index.html#discord.ext.pages.Paginator.respond) +to send a message or response with the paginator's contents. + +#### Depending on what's being passed to the `pages` parameter, the behaviour of the paginator may differ: + +- Passing a list of `PageGroup` objects will essentially treat each `PageGroup` as its own Paginator, with most + `Paginator` attributes able to be set independently for each `PageGroup`. + \- Each `PageGroup` accepts its own `pages` parameter, which inherits the same behaviour as the `pages` parameter + of `Paginator`, except it cannot contain other `PageGroup` objects. +- If a page is a `Page` object, this will allow you to specify both the `discord.Message.content` and + `discord.Message.embeds` attributes for a page. + \- **This is the preferred method of defining a page.** +- If a page is a string, this will be used for the `discord.Message.content` attribute. This type of page cannot have + any embeds. +- If a page is a list of embeds, this will be used for the `discord.Message.embeds` attribute. This type of page + cannot have any message content. +- If a page is a list of lists of embeds, each parent list item will create a page containing all embeds from its + child list. This type of page cannot have any message content. + +#### Parameters for the `Paginator` class which have default values: + +- `show_disabled` **:** `True` + - Show buttons that are disabled (i.e. can't be clicked) +- `author_check` **:** `True` + - Only the author can interact with the paginator. +- `timeout` **:** `180` _(seconds)_ + - The paginator will time out and become inactive after this many seconds. +- `disable_on_timeout` **:** `True` + - If the paginator times out, it will be automatically disabled and all buttons will be unusable. +- `use_default_buttons` **:** `True` + - Use the default set of 4 buttons and a page indicator. +- `show_indicator` **:** `True` + - When using the default buttons, shows a middle 5th button with the current/total page numbers. + +**For other parameters that can be set on initialization, please check the +[API Reference](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginator)** + +## [PaginatorButton](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatorbutton) + +This class represents a button used to navigate between the pages of a paginator. It's also used to create the page +indicator. + +When creating your own custom buttons, you can either use this class directly or subclass it to add any additional +functionality you may need. + +To add custom buttons to the paginator instead of the default navigation buttons, you have two options to do so: + +1. **Using the `custom_buttons` parameter of `Paginator`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + buttons = [ + PaginatorButton("first", label="<<-", style=discord.ButtonStyle.green), + PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), + PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True), + PaginatorButton("next", label="->", style=discord.ButtonStyle.green), + PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), + ] + paginator = Paginator( + pages=["Page 1", "Page 2", "Page 3"], + show_indicator=True, + use_default_buttons=False, + custom_buttons=buttons, + ) + ``` +2. **Using `Paginator.add_button()`:** + + ```py + import discord + from discord.ext.pages import PaginatorButton, Paginator + + paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"], use_default_buttons=False) + paginator.add_button(PaginatorButton("prev", label="<", style=discord.ButtonStyle.green)) + paginator.add_button(PaginatorButton("page_indicator", style=discord.ButtonStyle.gray, disabled=True)) + paginator.add_button(PaginatorButton("next", label=">", style=discord.ButtonStyle.green)) + ``` + +If you want to use the default navigation buttons, but not all of them, you can also use `Paginator.remove_button()` to +selectively remove them: + +```py +from discord.ext.pages import Paginator + +paginator = Paginator(pages=["Page 1", "Page 2", "Page 3"]) +paginator.remove_button("first") +paginator.remove_button("last") +``` + +## [PaginatorMenu](https://docs.pycord.dev/en/stable/ext/pages/index.html#paginatormenu) + +This class represents the `discord.Select` menu used to navigate between `PageGroup` instances. In most situations, you +will not need to interact with this class directly. + +If you do subclass it, you'll likely want to call `super()` in your `__init__` method to ensure that the `PageGroup` +navigation functionality is retained. + +## Usage Examples + +For a comprehensive list of examples showing all `Paginator` functionality, please see the +[example in cog form](https://github.com/Pycord-Development/pycord/blob/master/examples/views/paginator.py) in the repo. + +## Support and Feedback + +If you have any questions, suggestions, or feedback for `ext.pages`, please join the +[Discord server](https://discord.gg/pycord). diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx new file mode 100644 index 00000000..b8d68925 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/pages/paginator-faq.mdx @@ -0,0 +1,20 @@ +--- +title: Paginator FAQ +--- + +# Paginator FAQ + +- **What's the difference between `Paginator.send()` and `Paginator.respond()`?** + - `Paginator.send()` is used to send a channel message (DMChannel or TextChannel) with the paginator. + - `Paginator.respond()` is used to send an interaction response (or followup) message with the paginator. + +- **How can the bot send a paginator to a different destination than where it was invoked?** + - Use the `target` parameter in `Paginator.send()` or `Paginator.respond()`. + - You can also set the `target_message` parameter to control what's shown as a response where the paginator was originally invoked. + - For `Paginator.respond()`, this parameter is required if `target` is set, as an interaction requires being responded to. + +- **How can I change the paginator's behavior without re-creating and re-sending it?** + - Use the `Paginator.update()` method. + +- **How can I make the bot actually do something with the contents of a page?** + - Use the (upcoming) `Paginator.page_action()` method. diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json new file mode 100644 index 00000000..36dfb009 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/tasks/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Tasks" +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx new file mode 100644 index 00000000..848f6066 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/extensions/tasks/tasks.mdx @@ -0,0 +1,216 @@ +--- +title: Tasks +--- + +## Concept + +So you want to run a background task running at some specified interval? Thankfully, that's a common thing to do, whether you're working with some API or handling some background logic don't worry, the Pycord tasks extension is here to make life easier for you! + +With the tasks extension, you can make background tasks without worrying about the asyncio hell and mind bogglers like "what if my internet dies" and "how do I handle reconnecting" with the added benefit of a lot of useful additions that are one line of code away! + +### Example Usage + +```py +import discord +from discord.ext import tasks + +bot = discord.Bot() + +@bot.event +async def on_ready(): + very_useful_task.start() + +@tasks.loop(seconds=5) +async def very_useful_task(): + print('doing very useful stuff.') + +bot.run("TOKEN") +``` + +If you do run this code in your terminal you should see something like this after about 15 seconds: + +``` +doing very useful stuff. +doing very useful stuff. +doing very useful stuff. +``` + +For a more useful example here's a task in a cog context ripped straight from the [docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#recipes): + +```py +from discord.ext import tasks, commands + +class MyCog(commands.Cog): + def __init__(self): + self.index = 0 + self.printer.start() + + def cog_unload(self): + self.printer.cancel() + + @tasks.loop(seconds=5) + async def printer(self): + print(self.index) + self.index += 1 +``` + +As you'd expect this will increment a number and print it out every 5 seconds like so: + +```sh +0 +# 5 seconds later +1 +# 5 more seconds later +2 +# ... +``` + +## [Tasks](https://docs.pycord.dev/en/stable/ext/tasks/index.html) + +Now let's get into the nitty-gritty of tasks. + +As you've seen tasks can work in both outer scope and class contexts and the handle is roughly the same, you define a task using the `tasks.loop` decorator and use the `start` method to start it, the difference is you add the `self` argument when in a class context so since most people have all their bot's code in Cogs all the following code blocks will be in a Cog context to make it easy to copy it then apply whatever modifications you might need! + +### [Creating a task](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop) + +A look at `discord.ext.tasks.loop`'s definition in the documentation reveals that: + +1. As you've seen before it expects the time between each execution, that however doesn't have to be in seconds as + there are `seconds`, `minutes` and `hours` parameters to make it easier for us, they can also be floats in case you want + ultra-precision. +2. You can also pass in a `datetime.time` object or a sequence of them in the `time` parameter which will make it run + at the specified time(s). +3. You can pass in how many times a loop runs before it stops by passing in the `count` parameter, you can use `None` + to make it run forever which is also the default. +4. The loop function **_must_** be a coroutine. + +These are all really useful, and they aren't the only parameters so if you want to know more about them check out the +[docs](https://docs.pycord.dev/en/stable/ext/tasks/index.html#discord.ext.tasks.loop)! + +### Attributes + +A task has the following attributes: + +- `current_loop`: The current loop the task is on. +- `hours`, `minutes`, `seconds`: attributes that represent the time between each execution. +- `time`: A list of datetime.time objects that represent the times the task will run, returns `None` if no datetime + objects were passed. +- `next_iteration`: A `datetime.datetime` object that represents the next time the next iteration of the task will + run, can return `None` if the task stopped running. + +These attributes serve as a really powerful asset to get info about your loop. + +### Example + +Now let's create a cog that handles a leaderboard we have in our bot using Tasks then explain what we did after that and +also provide a refresher of how slash commands groups work in cogs. + +For the sake of this example let's pretend that we have a leaderboard module that does all the leaderboard handling for +us and that computing the leaderboard is very expensive computationally wise, so we want to store one version of it that +gets regularly updated instead of generating it every time someone calls the `/leaderboard view` command. + +```py +from discord.ext import tasks, commands +from discord.commands import SlashCommandGroup, CommandPermissions + +from leaderboard import * # Mock leaderboard module. + +class LeaderboardCog(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.update_leaderboard.start() + self.leaderboard_embed = generate_leaderboard_embed() + + leaderboard = SlashCommandGroup(name='leaderboard', description='Leaderboard commands.') + + @tasks.loop(minutes=10) + async def update_leaderboard(self): + print('Updating leaderboard...') + await update_leaderboard() + self.leaderboard_embed = generate_leaderboard_embed() + + @update_leaderboard.before_loop + async def before_update_leaderboard(self): + await self.bot.wait_until_ready() + print("About to start updating leaderboard.") + + @update_leaderboard.after_loop + async def after_update_leaderboard(self): + leaderboard_cleanup() + print("Stopped updating leaderboard.") + + @update_leaderboard.error + async def update_leaderboard_error(self, error): + print(f"Oh no, an error occurred while updating the leaderboard. Error: {error}") + + @leaderboard.command() + async def view(self, ctx): + await ctx.respond(embed=self.leaderboard_embed) + + @leaderboard.command() + async def update_info(self, ctx): + await ctx.respond(f"""***Leaderboard Info***\n + Last update: {(600 - self.update_leaderboard.next_iteration.timestamp())//60} minutes ago.\n + Next update: in {self.update_leaderboard.next_iteration.timestamp() // 60} minutes.\n + Time between loops: {self.update_leaderboard.minutes} minutes.\n + Times updated this session: {self.update_leaderboard.current_loop}. + Running? {self.update_leaderboard.is_running()} + Failed? {self.update_leaderboard.failed()}""", ephemeral=True) + + # Now for the owner only commands: + + leaderboard_config = SlashCommandGroup(name="leaderboard_config", description="Leaderboard configuration commands", permission=[CommandPermissions("owner", 2, True)]) + + @leaderboard_config.command() + async def set_time_between_updates(self, ctx, minutes: int): + self.update_leaderboard.change_interval(minutes=minutes) + await ctx.respond(f"Set time between updates to {minutes} minutes.") + + @leaderboard_config.command() + async def stop(self, ctx): + self.update_leaderboard.stop() + await ctx.respond("Stopped the leaderboard update.") + + @leaderboard_config.command() + async def restart(self, ctx): + self.update_leaderboard.restart() + await ctx.respond("Restarted the leaderboard update.") + +def setup(bot): + bot.add_cog(LeaderboardCog(bot)) +``` + +Phew, that was quite a bit of code. + +Now to explain what's going on: + +First things first we create a cog and in its `__init__` function we start the `update_leaderboard` task and generate +the first instance of our leaderboard's embed. + +After that, we define the `update_leaderboard` task using the `loop` decorator, and we make it run every ten minutes by +passing 10 to the `minutes` parameter. + +Then that we define the `before_update_leaderboard` task using the `before_loop` decorator, and we make it wait until the +bot is ready before starting the task. + +Next up we define the `after_update_leaderboard` task using the `after_loop` decorator, and we make it clean up the +leaderboard when the loop finally stops running. + +Then we define the `update_leaderboard_error` task using the `error` decorator, and we make it print any errors that may +occur while we update our leaderboard to the console. + +Then we get into the fun stuff, we create a slash command group using the `SlashCommandGroup` class and name it +`leaderboard`, we then create the `view` sub-command which sends the embed generated when the leaderboard is updated and +`update_info` which shows a lot of data about the task using some attributes and functions available to us. + +We also create a slash command group called `leaderboard_config` which is only available to the owner of the bot. + +Then we create the `set_time_between_updates` sub-command which takes in the time in minutes and changes the time +between updates of the leaderboard using the `change_interval` method, the `stop` sub-command which stops the task using +the `stop` method and `restart` which restarts the task using the `restart` method. + +Finally, we add the `LeaderboardCog` cog to the bot, and we're done! + +I'd highly recommend you check the tasks extension +[documentation](https://docs.pycord.dev/en/stable/ext/tasks/index.html) for more info on how to use them and what other +functions they have. diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/_category_.json new file mode 100644 index 00000000..9d6255f5 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 3, + "label": "Getting Started", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx new file mode 100644 index 00000000..864206a6 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/creating-your-first-bot.mdx @@ -0,0 +1,262 @@ +--- +title: Creating Your First Bot +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +Excited to create your first bot? Once you [install Pycord](../installation.mdx), you can start right +away! + +## Creating the Bot Application + +Just like how you need to sign up to use Discord, your bot also has to be signed up. To do this, +you should: + +1. Go to the [Discord Developer Portal](https://discord.com/developers/applications) and click + on . +2. Give your bot a name, and click . +3. Now, you should see a page like this. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdW3OQnwUhacopqSWw%2F-Mjd_-mxrJCrzmaXrAg8%2Fimage.png?alt=media&token=b8e2ae6c-2290-4d37-ad7c-eb412f3fb00e) +4. Click on the tab on the left side of the screen. +5. Click on . +6. You can give it a name, change the Avatar, etc. + +## Inviting the bot + +Now, lets get the bot added to some servers. Go to the tab +in the left pane and select `bot` and `applications.commands` as scopes. + +You may want your bot to have application commands, which is what the `application.commands` scope +allows your bot to make. + +Next, you want to choose what permissions the bot will have and select them. For now, you can just +give your bot the `administrator` permission, which gives your bot every permission. Once you select +your bot's permissions, click on to get the bot invite link. + +:::tip + +When your bot is all ready to go, make sure that administrator permissions aren't selected unless +your bot truly needs them. Try selecting only permissions the bot will need. For testing, +Administrator permissions are fine. + +::: + +![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-Mk6tNY3LfDkjd6pqdpL%2F-Mk6tkdpddEWoa2jczZk%2Fimage.png?alt=media&token=52c8a29f-a798-48f8-a8c7-4ecca2681f79) + +You can use this link to invite the bot. + +## Tokens + +Now that you have an account for your bot, you need to log in. To log in, we need the bot's +password. All users and bots have a "token." You may think of this token as a password, as this allows +us to log our bot into Discord. + +Tokens are "snowflakes." Not actual snowflakes, though. Just like how no two snowflakes in real life have the same +pattern, snowflakes in computers are unique things - no two bots have the same token - so a token is +considered a snowflake. A Discord user ID is also a snowflake. + +Now, lets get your bot's token. To do this, you want to: + +1. Go back to the tab. +2. Click on the button in the "Token" section. + ![image](https://gblobscdn.gitbook.com/assets%2F-MjPk-Yu4sOq8KGrr_yG%2F-MjdbU12JISJorAZxrKH%2F-MjdbpUsapzb5n15Po5P%2Fimage.png?alt=media&token=118e259f-940a-4f6c-b3a3-c29f3a54100d) + +Now, you have your bot's token copied to your clipboard. + +:::danger + +Do not, under any circumstances, give your token to anyone. Even if you are contacted by someone +claiming to be Discord staff, do not give them your bot's token. They are lying to you to try and +gain access to your bot. If an unauthorized user gains access to your bot's token, they can access +your bot and use it in malicious ways. + +Never push your token to GitHub or include it in your code. One way to prevent your token from +getting leaked is to store it in `.env` files. + +::: + +### Protecting Tokens + +#### Using dotenv + +You can store your tokens in `.env` files. This is a simple way to store sensitive information. + +1. Create a file with the name `.env` (only the extension, with a dot/period at the start and without a name before it). +2. Define the token in the `.env` file (replace the example value with your token). + ```env title=".env" + TOKEN = NzkyNzE1NDU0MTk2MDg4ODQy.X-hvzA.Ovy4MCQywSkoMRRclStW4xAYK7I + ``` +3. Install [`python-dotenv`](https://pypi.org/project/python-dotenv/). + ```bash + python -m pip install python-dotenv + ``` +4. Load the token from the `.env` file. + ```python + import dotenv + dotenv.load_dotenv() + token = str(os.getenv("TOKEN")) + ``` +5. Pass your token as parameter when running the bot. + ```python + client.run(token) + ``` + +:::tip + +If you are using Git to track your bot's changes, you should create a file called `.gitignore` and add +`.env` to it. This stops your `.env` file from getting tracked along with the rest of your code, and +will not be pushed to a remote Git repository. As a consequence, it will stay secure on your local machine. + +::: + +## Coding the Basics + +Here's an example of code you'll write with Pycord: + +```py +import discord +import os # default module +from dotenv import load_dotenv + +load_dotenv() # load all the variables from the env file +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") + +bot.run(os.getenv('TOKEN')) # run the bot with the token +``` + + + +
+ + hello + +
+ Hey! +
+
+
+ +Let's go through the code. First, the imports. + +```py +import discord +import os +from dotenv import load_dotenv +``` + +In the first line, `import discord`, we import Pycord. Although you install Pycord with `pip install py-cord`, you +import it with `import discord`. This is so it's as easy as possible when switching from Discord.py to Pycord. + +We then import `os` and `dotenv`. `os` is a default module that we will use to get the token from the env file. `dotenv` +is a module that we will use to load the env file. You installed this with `pip install python-dotenv`. + +Next, we load the env file with `load_dotenv()`. + +```py +bot = discord.Bot() +``` + +In this line, we create a new instance of [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). +In this object, we can pass various parameters for configuration purposes, such as `owner_ids` +and [`intents`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```py +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") +``` + +We use the [`event`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) decorator to override +the [`on_ready`](https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready) function to define an +event that is automatically called when the bot is ready to use. + +```py +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.respond("Hey!") +``` + +Here, we use the [`slash_command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.slash_command) +decorator to define a slash command. We specify the `name` and `description` arguments. If not +specified, the name of the slash command would be the function name and the command description would +be empty. + +Optional: We type-hint the context parameter (`ctx`) as [`discord.ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext). In modern IDEs, type-hinting allows access to autocompletion and docstrings. You can read more about type-hinting [here](https://docs.python.org/3/library/typing.html). + +Finally, you want to run the bot using the token specified in the `.env` file. + +Now you have finished creating your first Pycord bot! What we have shown you is just the basic structure +of a bot. You can do a lot more with Python and Pycord knowledge, as well as your imagination! Pycord +will not limit your bot's abilities. + +:::note + +The part where we load the token from the environmental variables is not required. You may use another way to keep your token secure, or, although not recommended, simply specify the token normally as a string, as shown below. + +
+A Basic Bot without securing the token +
+ +```py +import discord + +bot = discord.Bot() + +@bot.event +async def on_ready(): + print(f"{bot.user} is ready and online!") + +@bot.slash_command(name="hello", description="Say hello to the bot") +async def hello(ctx: discord.ApplicationContext): + await ctx.send("Hey!") + +bot.run("TOKEN") +``` + +
+
+ +::: + +## FAQ + +### How do I make prefixed commands? + +Prefixed commands are an older method of creating bot commands that listen for messages and replies +if the message starts with a certain character. You can read [this page](../extensions/commands/prefixed-commands.mdx) +to learn more about prefixed commands. + +### How do I setup modules/cogs? + +[Cogs](../popular-topics/cogs) are a great way to organize your commands by putting them into +groups called cogs. Cogs are separate files that your bot loads to get the commands inside. +You can read more about cogs, as well as learn how to use them and their benefits, +[here](../popular-topics/cogs). + +### How do I add components, such as buttons and dropdown menus, to my bot? + +Pycord makes it very easy to use Message Commands with your bot by using the `discord.ui` module. +To learn more, read about Message Commands in our [interactions directory](../interactions). + +:::info Related Topics + +- [Prefixed Commands](../extensions/commands/prefixed-commands) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx new file mode 100644 index 00000000..2a68677b --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/hosting-your-bot.mdx @@ -0,0 +1,109 @@ +--- +title: Hosting Your Pycord Bot +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Hosting Your Pycord Bot + +If you're completely new to this, you might have thought something along the lines of "Yay! I got my +bot working," after following our [Creating your First Bot](creating-your-first-bot) guide, only +to close your IDE or shut down your computer to find your bot offline. + +The reason for this is that programs have to be hosted somewhere, meaning some machine somewhere has +to constantly run your bot. There are tons of hosting services that can help you host your bot for +little to no cost. + +## Can I get a Clear Explanation? + +Sure thing. When you run your bot, it first makes a connection to Discord's API. Once that's done, +Pycord sends "heartbeats" to Discord. "heartbeats" are small packets sent at a set interval telling +Discord that your bot is indeed still alive. If Discord doesn't receive a heartbeat after a certain +amount of time, your bot is pronounced dead and buried in the graveyard (not really). It is, though, +taken offline and its connection with Discord is terminated. + +Once you close the terminal that you've run your program on, the program is no longer running, and +the bot stops sending heartbeats and can no longer process commands. This is why you have to constantly +keep the process running. + +This goes for all programs, in a different nature. If the code isn't compiled/built/assembled/interpreted, +it can't be running. + +## What is a Host? + +A host is a server or container for running code offered by a **hosting provider.** There are a lot +of hosting providers, such as bigger ones like Amazon Web Services (AWS) and Google Cloud, and smaller +ones like GalaxyGate and DigitalOcean. + +There are three types of hosts. + + + + Shared hosting is a type of hosting where multiple people share one VPS. Getting a spot on + a shared host is usually cheap, sometimes even free. Shared hosts do not give you a lot of + resources, from less than a gigabyte of RAM (usually 512MB on free hosts) and half of a CPU + with very little storage. Shared hosting is usually used for website hosting and is not + recommended for hosting a Discord bot. + + + A virtual private server (VPS) is a virtual computer (virtual machine) that is rented out to + customers. Most people use a VPS for hosting their projects such as Discord bots. You can get + anywhere from less than a gigabyte of RAM and a less powerful CPU to just under one hundred + gigabytes of RAM, a (or multiple) powerful CPU(s), and a fair amount of storage. A VPS is the + best choice for most users and can be fairly cheap. + + + A dedicated host is a physical computer. You can buy these yourself or rent one from a hosting + provider. Dedicated hosts are often very expensive, but are also very powerful, having a + few hundred gigabytes of RAM and a few very powerful CPUs, along with a good amount of storage. + Dedicated hosts are usually used for very large projects and are overkill for something like + a Discord bot. + + +
+ +:::danger + +Make sure you choose a hosting provider you trust. Also make +sure the hosting provider you're looking at has good reviews on public forums. Googling along the +lines of "[host] review" should do the trick. A provider you don't trust can compromise your token. + +::: + +Most hosting providers rent their services to you for a monthly or yearly fee. These can be anywhere +from a few dollars to hundreds or thousands of dollars. + +## How to Host Your Bot + +Once you rent or buy a VPS, you can get to work. Most hosting providers allow you to choose from a +wide range of operating systems, most allow you to choose one but some allow you to choose +multiple. Once that's ready, you have to SSH into the system. We won't get into SSH here, but you can +read [this article from DigitalOcean](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys). +You can also use VNC, which is remote desktop software. If you are using an OS that does not have a +GUI, and is only a command line (a "server" OS), such as Ubuntu Server or most Linux Server Operating Servers, you will most +likely use SSH. If you are using an OS that has a GUI, such as Windows Server, you will most likely use VNC. + +Once you've decided on your operating system, you'll want to set it up and install Python. Once that's +done, you can copy your bot's files to your remote system, install the required packages, and run +the bot. + +:::warning + +If you are using SSH to run the file, your bot will not stay running. This is because the file is +only told to run during your session. You can use a command like [nohup](https://en.wikipedia.org/wiki/Nohup) +to make sure your file stays running after you disconnect. + +::: + +Now your bot is hosted, but that doesn't mean it can't go offline. If your bot encounters an error, +it can often go offline or stop its process. For this, make sure you have proper error handling. +Also be sure to pay attention to your hosting provider's updates or news, as they usually notify +users of when they plan on doing maintenance to their servers, making their services unavailable for +a short time. + +:::info Related Topics + +- [Creating Your First Bot](creating-your-first-bot) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx new file mode 100644 index 00000000..ee6b9417 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/more-features.mdx @@ -0,0 +1,379 @@ +--- +title: More Features +description: More features to make your bot cool and snazzy. +--- + +import { + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordEmbed, + DiscordEmbedField, + DiscordEmbedFields, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +So, you just created your first Pycord bot! Now, let's add some more features to it. This will include adding event handlers, waiting for user response, styling the messages, and more. + +## Events + +### Event Handlers + +Events in Discord are a way to listen for certain actions. For example, if you want to know when a user joins your server, so you could send a welcome message, you can use the `on_member_join` event. + +First, you need to ask Discord to send you events. This is done via "Intents". Read up the [Intents](../Popular-Topics/intents) page for more information. + +Once you understand what intents are, you can enable the events you need, or just use the default ones with `discord.Intents.all()`. + +Now that that's done, let's add an event handler for when a user joins the server. We will use the [`on_member_join` event](https://docs.pycord.dev/en/stable/api/events.html#discord.on_member_join). We will send a private message to the user welcoming them to the server. + +```python +@bot.event +async def on_member_join(member): + await member.send( + f'Welcome to the server, {member.mention}! Enjoy your stay here.' + ) +``` + +We use the [`discord.Bot.event` decorator](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.event) to add the event handler. + +The `on_member_join` event is called when a user joins the server. The `member` parameter is the user that joined. Different events have different names and parameters. You can find all of them [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +So, that's how you add event handlers! + +### Waiting for User Response + +Let's say you want to create a Guess-the-Number game (where the user has to guess a number between 1-10). You need to send a message to a user and wait for them to respond. You can do this with the [`wait_for`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.wait_for) method. + +```python +@bot.command() +async def gtn(ctx): + """A Slash Command to play a Guess-the-Number game.""" + + await ctx.respond('Guess a number between 1 and 10.') + guess = await bot.wait_for('message', check=lambda message: message.author == ctx.author) + + if int(guess.content) == 5: + await ctx.send('You guessed it!') + else: + await ctx.send('Nope, try again.') +``` + +`wait_for` takes one argument, which is the event type. The event type is the name of the event you want to wait for. In this case, it's `message`. It could also be `reaction` to wait for a reaction to be added. + +We pass a keyword argument to `wait_for` called `check`. The function may look complicated if you're a beginner. We pass a `lambda` function, which simplifies the code a bit. + +The lambda function takes one parameter, `message`. When Pycord receives a message, it passes it to the `check` function. If the function returns `True`, the message is returned. If the function returns `False`, the message is ignored and the bot waits for another message. + +Here, we check if the message is from the user that sent the command. We simply use `message.author == ctx.author`. This will check if the author of the message was the person who invoked the command. + +## Styling Messages + +### Embeds + +Embeds are a Discord feature that allows applications to format their messages in cool embedded format, +enabling your bot to lay out messages with a lot of text into neat fields. + + + + + The Pycord Guide is a detailed guide that explains how to use Pycord and all of its features. + + + The Getting Started section explains how you can get a brand new bot created and running from scratch. + + + Interactions with Pycord + + + Pycord's various Extensions + + + Other Popular Topics + + + We have so much more! Just explore, and you will find everything you need. If you want another page added, open an issue on the GitHub. + + + Created with 💖 by the Pycord Team & Contributors + + + + +
+ +Creating embeds is simple! Just create an instance of [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) and edit it to your liking. Once you're done, send it! + +```python +import discord + +bot = discord.Bot() + +@bot.command() +async def hello(ctx): + embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from + ) + embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") + + embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) + embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) + embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) + + embed.set_footer(text="Footer! No markdown here.") # footers can have icons too + embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") + embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") + embed.set_image(url="https://example.com/link-to-my-banner.png") + + await ctx.respond("Hello! Here's a cool embed.", embed=embed) # Send the embed with some text + +bot.run("TOKEN") +``` + + + +
+ hello +
+ Hello! Here's a cool embed. + + Embeds are super easy, barely an inconvenience. + + + A really nice field with some information. The description as well as the fields support markdown! + + Inline Field 1 + Inline Field 2 + Inline Field 3 + + Footer! No markdown here. + +
+
+ +
+ +This simple command sends replies to a [slash command](../interactions/application-commands/slash-commands) with an embed. +Let's break it down: + +```py +embed = discord.Embed( + title="My Amazing Embed", + description="Embeds are super easy, barely an inconvenience.", + color=discord.Colour.blurple(), + ) +``` + +This command creates an embed. We use the [`Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) +class to create an embed object with the title "My Amazing Embed", the description "Embeds are super easy, barely an inconvenience.", and the color `blurple`, Discord's main theme color. + +[discord.Colour](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Colour) is a class full of [classmethods](https://docs.python.org/3/library/functions.html#classmethod) +that return color values. While the official, documented name of this is `discord.Colour`, `discord.Color` +works as well. + +```py +embed.add_field(name="A Normal Field", value="A really nice field with some information. **The description as well as the fields support markdown!**") +embed.add_field(name="Inline Field 1", value="Inline Field 1", inline=True) +embed.add_field(name="Inline Field 2", value="Inline Field 2", inline=True) +embed.add_field(name="Inline Field 3", value="Inline Field 3", inline=True) +``` + +This small section shows off embed fields. You can add fields to embeds with the [`add_field` method](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.add_field) +of the [`discord.Embed`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed) class. These consist of three +keyword arguments: `title`, `value`, and `inline`. `title` and `value` are both required arguments, which inline defaults to `False` if it's not defined. The `inline` argument specifies whether space will be divided among the inline fields. There could be a mix of fields where inline has different values too. + +```py +embed.set_footer(text="Footer! No markdown here.") # footers can have icons too +embed.set_author(name="Pycord Team", icon_url="https://example.com/link-to-my-image.png") +embed.set_thumbnail(url="https://example.com/link-to-my-thumbnail.png") +embed.set_image(url="https://example.com/link-to-my-banner.png") +``` + +In this section, we're adding unique items to the embed. These items are: + +- Footer - With the [`set_footer()`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_footer) + method, you can set a small footer that holds a message. This has `text` and `icon_url` kwargs. +- Author - With the [`set_author`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_author) + method, you can set an author for the embed. This is a small text field at the top of the embed. This + includes `name`, `url` and `icon_url` kwargs. +- Thumbnail - With the [`set_thumbnail`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_thumbnail) + method, you can set a small image to reside at the top-right of the embed. This has a single `url` kwarg. +- Image - With the [`set_image`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Embed.set_image) + method, you can set an image to sit at the bottom of an embed. This has a single `url` kwarg. + +There are a lot more methods and attributes you can use to configure embeds. Here, we just covered the basics. Also, remember that all of these values are not necessary in an embed. An embed may only contain a few of these. For example, only a description, a title and a description, and so on. + +### Markdown + +Markdown is a type of markup language that's limited in terms of formatting yet simple. Discord allows +for a watered-down version of markdown to be in their messages. + +#### Text Markdown + +Text formatting can be used in messages and in most embed parts, +as explained in the dedicated section below. + + + + + + + + + + + + + + + + + + + + +
*italics*__*underlined italics*__
**bold**__**underlined bold**__
***bold italics***__***underlined bold italics***__
__underlined__~~strikethrough~~
+ +#### Code Markdown + +To create a single-line code block without syntax highlight, wrap the text between single backticks. +This code block will only add a dark background to the text. + +``` +`print("Hello world!")` +``` + +To create a multi-line code block without syntax highlight, wrap the text between triple backticks +on first and last line. This type of code block will encase the code inside a box. + +```` +``` +message = "Hello world!" +print(message) +``` +```` + +To create a multi-line block with syntax highlight, add the name of the language you are using right after +the triple backticks on the first line. For example, for Python you can write either "python" or "py". + +```` +```python +message = "Hello world!" +print(message) +``` +```` + +If you want to use syntax highlight for a single line of code, you still have to format it +like a multi-line block but the code must be on a separate line than the triple backticks. + +#### Quote Markdown + +To create a single-line quote block, start the line with `>` followed by a space. + +``` +> This is a single-line quote. +``` + +To create a multi-line quote block, write `>>>` followed by a space. All text +from that point onwards will be included in that quote block. + +``` +>>> This is a +multi-line quote. +``` + +#### Spoiler Markdown + +To hide a spoiler, encase the text between double pipes. The users +will have to click on it before being able to see the text contained in it. + +``` +||spoiler|| +``` + +#### Link Markdown + +Link formatting only works in embeds and messages sent through webhooks, +by using the following syntax: + +``` +[Pycord](https://pycord.dev/) +``` + +Inside the supported elements that have just been mentioned, +the example above will look like this: [`Pycord`](https://pycord.dev/) + +Outside them, the link will still be clickable but the formatting will be ignored, +therefore the example above will look similarly to this: `[Pycord](https://pycord.dev/)` + +#### Embed Markdown + +Adding markdown to your embeds or messages will give your bot the sparkle it needs, +however, markdown is limited inside embeds. Use the following table as a reference +and keep in mind that embed title and filed names will always show in **bold**. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PartTextLink
Embed AuthorNoNo
Embed TitleYesNo
Embed DescriptionYesYes
Field NameYesNo
Field ValueYesYes
Embed FooterNoNo
diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx new file mode 100644 index 00000000..e44b7c49 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/getting-started/rules-and-common-practices.mdx @@ -0,0 +1,184 @@ +--- +title: Rules and Common Practices +description: All about the rules and common practices for coding a Discord bot +--- + +# Rules and Common Practices of Creating a Bot + +When creating almost anything, there's always a certain set of rules to follow or common practices, +such as [PEP8](https://www.python.org/dev/peps/pep-0008/) for Python. This applies to creating bots +with Pycord as well. + +:::note + +Most of these rules and common practices are only applicable for +[verified bots](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting), +but it's good to follow them nonetheless. + +::: + +## Rules + +There are rules for creating bots, and most of these are required by Discord themselves, not us at +Pycord. Not following these rules may get your bot denied for verification. + +### Terms of Service and Privacy Policy + +Starting at some point in time, Discord has made providing a privacy policy with your bot a requirement. +This is so that Discord knows exactly what you are doing with its users' data. + +:::tip +You don't need a lawyer or anyone special to write out a privacy policy for you, nor do you need +it approved by some official entity. Simply writing out how you are going to use Discord user +information neatly is all you need to do. +::: + +Providing a Terms of Service for your bot is optional, though usually a best practice. It tells users +what they can and cannot do with your service, and makes it easier to settle disputes if someone +disagrees with you. + +Read more in Discord's official [Legal Docs](https://discord.com/developers/docs/legal). + +### Developer Policy + +We could list almost every rule about using Discord's API here. _Or_ we could simply link Discord's +Developer Policy to make it easier on us. You can find Discord's Developer Policy +[here](https://discord.com/developers/docs/policy). This outlines what you can and cannot do with +Discord's Developer API. And, don't worry, it's completely readable and understandable. + +## Best Practices + +Now, here's something we _can't_ simply link an article for. We're going to discuss the best practices +of creating a Discord bot with Pycord. + +### Bot Sharding + +To any new or maybe even experienced bot developer, sharding a bot sounds beneficial once you hear +about it. I'm here to tell you that it isn't a good idea to shard your bot. + +_Wait a minute, why would it be an option if it wasn't a good idea?_ It's simple. I lied. Sort of. +I'm not going to go into the details of sharding a bot, so you can read about it on +[this page](../Popular-Topics/sharding). Sharding is the process of taking your bot +and breaking it up into small pieces, so it's easier to perform tasks. This is very useful for large +bots, as it makes them faster and more reliable. Sharding is not a good practice for small bots. + +:::note +Discord will notify you once it is time to shard your bot, and will eventually force you to do so. +::: + +At the very least, wait for one thousand servers to shard your bot. If you shard your bot while it's +small, you'll just be wasting resources and possibly making your bot slower. + +### [Verification](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting) + +Verifying your Discord bot is something every developer would like to achieve. It shows that your bot +is in more than 75 servers. It's generally a good idea to try to get your bot verified as soon as +possible. We're talking at 76 servers soon. This is because Discord can be somewhat slow in terms of +bot verification, so verifying as soon as possible gives them enough time to verify before your bot +reaches the 100 server cap. If a bot is not verified, it cannot grow beyond 100 servers. + +It's also a good idea to only apply for the privileged intents that you need. Applying for intents +your bot doesn't use wastes both your time and Discord's time, as your privileged intent request +will be denied simply because you applied for an intent you didn't need. + +### Subclassing + +While it may take some time, subclassing a bot is very worth it. Once again, this was explained +elsewhere, so I won't go into the details, but I felt it fit here, so I put it here. + +Subclassing a bot makes it more flexible and allows it to do a lot more. Read more about subclassing +bots [here](../Popular-Topics/subclassing-bots) + +### Your Bot's Token + +Your bot is only able to be run for one reason: its token. If you followed the +[guide for creating your first bot](creating-your-first-bot), you should already know a bit about +keeping that token safe. That's exactly what you want to do. + +Sharing your token is never good. If someone evil gets a hold of your token, they can do terrible things, +such as making your bot leave all of its servers, spamming all the members the bot has contact with, +and even manipulating the servers the bot is in, if given the permissions. That's why it's very important +to keep your token safe. To learn how to do so, read [this part](creating-your-first-bot#tokens) of +the Creating Your First Bot guide. + +### Backups + +You always want to back up your bot's data. This includes both its code _and_ its databases. This way, +if something tragic happens, such as your host failing a data migration or you breaking your Raspberry +Pi's SD card that held your bot, you'll still have its precious user data. I have a small program for +my bot that uploads its databases to a remote GitHub repository periodically to not lose any data. +It may be smarter to find a bit more of a reliable way to do so, though. + +Public or private, having a local Git repository connected to a remote one is a good idea for making +almost any application. For a lot of developers, it's like saving your work. If you do this, all of +your bot's code won't be lost if your computer spontaneously combusts, or you smash it to bits from +anger. You can simply grab the backup computer that everyone has lying around, and you're back +in business. + +### Organization and Cleanliness + +It is _extremely_ important to have organized code. This includes commands, objects, functions, +and classes. If you don't have organized code, it will get progressively harder for you to recognize +it, and others won't be able to decipher it. + +Make sure you utilize indents and spaces, as these are very important in making your code readable. + +```py title="Bad Spacing" +class MyClass: + async def add(self,num1,num2): + return num1+num2 + async def sub(self,num1,num2): + return num1-num2 +``` + +```py title="Good Spacing" +class MyClass: + async def add(self, num1, num2): + return num1 + num2 + + async def sub(self, num1, num2): + return num1 - num2 +``` + +See the difference? Now, which one looks more readable? Hopefully, you answered the second example. +Python's [PEP8](https://www.python.org/dev/peps/pep-0008/) is a PEP (**Python Enhancement Proposal**) +style guide for Python. It is the style guide that is used by most Python developers and programmers, +providing a universal way to write and read code. + +### Databases + +As your bot grows, you'll inevitably have to store data for your bot. Now, most people would probably just load up some +JSON file on boot into a `dict`, modify it in memory then write to the file. However, JSON files aren't the solution. +When you write to a JSON file, it rewrites the entire file instead of just rewriting the section that changed. It's also +a configuration file format, not a storage file format. + +Instead of using a JSON file or some other related format, you should instead use a database. There are many databases +out there, like MongoDB, SQLite, and PostgreSQL to name a few. + +All of these databases I named do the job well, and which one you use depends on what features you want out of a database. + +<>{/* Maybe clarify these/add more options */} + +#### MongoDB + +MongoDB is a JSON-like format and if you already use JSON files, it shouldn't be too hard to migrate over to. + +#### SQLite + +SQLite is based on SQL, a common relational data model. It's a lightweight, easy-to-use, portable database solution that +works entirely on files. However, if for some reason you cannot read/write to and from a file, and you need to manage +lots of data, SQLite might not be for you. + +While SQLite is a part of the Python Standard Library as the `sqlite3` package, we recommend not using it as it is +synchronous and blocking. You should use an asynchronous alternative, such as [`aiosqlite`](https://pypi.org/project/aiosqlite/). + +#### PostgreSQL + +PostgreSQL is also based on SQL, but it also has more features than SQLite. It's compliant with the SQL standard, +open-source, and extensible. However, it's not that fast or simple compared to SQLite. + +#### MariaDB + +MariaDB is also based on SQL and is a fork of the MySQL project. It's compliant with the SQL standard, it's also open +source and is a complete drop-in replacement for any code with MySQL. You don't even need to change what package you're +using! diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/installation.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/installation.mdx new file mode 100644 index 00000000..521c69cd --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/installation.mdx @@ -0,0 +1,80 @@ +--- +title: Installation +sidebar_position: 2 +--- + +Before you can start using Pycord, you need to install the library. + +:::note +Python **3.8 or above** is required to use Pycord. +::: + +:::tip +Before you start installing python packages globally, it's recommended you set up a virtual environment. +You can find instructions for that [here](More/virtual-environments). +::: + +## Fresh Installation + +To install Pycord, you can use the following command in your terminal: + +``` +pip install py-cord +``` + +:::tip +Remember that you need to install `py-cord`, not `pycord`. +Also, the `pip` command varies depending on your installation. For example, it might be `python3 -m pip` on macOS/Linux or `py3 -m pip` on some versions of Windows. +::: + +If you need voice support for your bot, you should run: + +``` +pip install "py-cord[voice]" +``` + +## Migration + +### Updating Pycord + +If you are upgrading from a previous version of Pycord, you can use the following command in your terminal to upgrade to the latest version: + +``` +pip install -U py-cord +``` + +### Migrating from other libraries + +If you are migrating from another library, say, `discord.py`, first of all, you need to uninstall it. + +``` +pip uninstall discord.py +``` + +Then, you can install Pycord, it's as simple as that!: + +``` +pip install py-cord +``` + +:::caution +Uninstalling `discord.py` _after_ installing `py-cord` can cause issues. Make sure to uninstall it first! +::: + +## Installing Other Builds + +### Development Build + +:::caution +The development build comes with cutting edge features and new functionality, but as it isn't a stable build you may encounter bugs. +::: + +To install the development build, you can use the following command in your terminal: + +``` +pip install -U git+https://github.com/Pycord-Development/pycord +``` + +:::important +Git is required to install this build. [Learn how you can install Git](./more/git). +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/interactions/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/_category_.json new file mode 100644 index 00000000..ea28be60 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 4, + "label": "Interactions" +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json new file mode 100644 index 00000000..6dcafe83 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Application Commands", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx new file mode 100644 index 00000000..b4ffeade --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/context-menus.mdx @@ -0,0 +1,85 @@ +--- +title: Context Menus +description: Learn all about Context Menus (User Commands & Message Commands) and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +When you right-click a message, you may see an option called "Apps". Hover over it, and you can see +commands a bot can run with that message. These are called message commands. + +When you right-click a user in the user list, you can once again see an option called "Apps". +Hover over it, and you can see commands a bot can run with that message. These are called user commands. + +Together, these two are called Context Menus or Context Menu Commands. These commands work very much like normal commands, except they take a member or message. + +:::note + +A bot can have up to 5 global Context Menus of each type. + +::: + +## User Commands + +Creating a user command is very simple. + +```python +@bot.user_command(name="Account Creation Date", guild_ids=[...]) # create a user command for the supplied guilds +async def account_creation_date(ctx, member: discord.Member): # user commands return the member + await ctx.respond(f"{member.name}'s account was created on {member.created_at}") +``` + + + +
+ + Account Creation Date + +
+ {defaultOptions.profiles.bob.author}'s account was created on 2020-01-01 +
+
+ +## Message Commands + +```python +@bot.message_command(name="Get Message ID") # creates a global message command. use guild_ids=[] to create guild-specific commands. +async def get_message_id(ctx, message: discord.Message): # message commands return the message + await ctx.respond(f"Message ID: `{message.id}`") +``` + + + + Do. Or do not. There is no try. + + +
+ + Get Message ID + +
+ Message ID: 930650407917748286 +
+
+ +
+ +:::info Related Topics + +- [Slash Commands](./slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx new file mode 100644 index 00000000..edac55b3 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/localizations.mdx @@ -0,0 +1,56 @@ +--- +title: Localizations +description: Localizations are a way to make your bot more accessible to your users. Learn all about localizations now! +--- + +Localizations are a way to make your bot more accessible to your users. You can localize the command +name, the names of any arguments, and any text that is displayed to the user. + +## Syntax + +```python +@bot.slash_command( + name="ping", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + }, + options=[ + Option( + name="Example", + name_localizations={ + "en-GB": "British Example" + }, + description="Example option that does nothing", + description_localizations={ + "en-GB": "British example option that does nothing" + } + ) + ] +) +async def ping(ctx, example): + responses = {"en-US": "Pong!", + "en-GB": "British Pong!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +@bot.slash_command( + name="ping2", + name_localizations={ + "en-GB": "British_Ping" + }, + description="Ping the bot", + description_localizations={ + "en-GB": "British ping the bot" + } +) +async def ping2(ctx, example: Option(str, "example", name_localizations={"en-GB": "British Example"}, description="Example option that does nothing", description_localizations={"en-GB": "British example option that does nothing"})): + responses = {"en-US": "Pong2!", + "en-GB": "British Pong2!"} + await ctx.respond(responses.get(ctx.interaction.locale, responses['en-US'])) + +``` + +- [`Locales`](https://discord.com/developers/docs/reference#locales) - List of valid locales recognized by Discord diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx new file mode 100644 index 00000000..ed454dad --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/application-commands/slash-commands.mdx @@ -0,0 +1,292 @@ +--- +title: Slash Commands +description: Learn all about Slash Commands and how to implement them into your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On March 24, 2021, Discord added Slash Commands to Discord as an easier, more efficient, and better way of using bot commands. Pycord has implemented Slash Commands into the library, so it's simple, efficient, and familiar. + +:::important + +Remember that Slash Commands require your bot to be invited with the `application.commands` scope or Slash Commands will not show up. Bots already in the guild can simply be invited again with the scope; there is no need to kick the bot. + +::: + +## Syntax + +Let's create a simple Slash Command. + +```py +import discord + +bot = discord.Bot() + +# we need to limit the guilds for testing purposes +# so other users wouldn't see the command that we're testing + +@bot.command(description="Sends the bot's latency.") # this decorator makes a slash command +async def ping(ctx): # a slash command will be created with the name "ping" + await ctx.respond(f"Pong! Latency is {bot.latency}") + +bot.run("TOKEN") +``` + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +Let's go through the code. + +First, we import Pycord's `discord` package. + +Next, we create a [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot) object and assign it to a variable `bot`. + +We then go ahead and use the [`@bot.command`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot.command) decorator, which registers a new Slash Command. We pass a `description` parameter to give a description to the Slash Command. We can also pass a `name` parameter to change the Slash Command's name. By default, the name of the Slash Command will be the name of the function, in this case, `/ping`. + +We create an async function called `ping` with parameters `ctx`, which, when called, sends the bot's ping/latency using [`ctx.respond`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext.respond). + +## Subcommand Groups + +You might want to group certain commands together to make them more organised. A command group is exactly what it sounds like, a group of individual Slash Commands together. + +In order to make a Slash Command group, you can use the `bot.create_group` function. + +```python +import discord + +bot = discord.Bot() + +# create Slash Command group with bot.create_group +greetings = bot.create_group("greetings", "Greet people") + +@greetings.command() +async def hello(ctx): + await ctx.respond(f"Hello, {ctx.author}!") + +@greetings.command() +async def bye(ctx): + await ctx.respond(f"Bye, {ctx.author}!") + +bot.run("TOKEN") +``` + +Or, you can instead manually make a `SlashCommandGroup` class like so: + +```python +import discord + +math = discord.SlashCommandGroup("math", "Math related commands") + +@math.command() +async def add(ctx, num1: int, num2: int): + sum = num1 + num2 + await ctx.respond(f"{num1} plus {num2} is {sum}.") + +@math.command() +async def subtract(ctx, num1: int, num2: int): + sum = num1 - num2 + await ctx.respond(f"{num1} minus {num2} is {sum}.") + +# you'll have to manually add the manually created Slash Command group +bot.add_application_command(math) +``` + +Here's what the registered subcommands will look like in the Slash Command Menu: + +![Picture of the subcommands in the Slash Command Menu](../../assets/interactions/groups-and-subcommands.jpg) + +You'll notice that there's the name of the Slash Command Group and then the name of the subcommand separated by a space. + +::: + +:::info Cogs + +If you are looking to add Slash Command Groups to cogs, please look at our [Cogs page](../../popular-topics/cogs)! + +::: + +## Sub-groups + +We've made a subcommand group, but did you know that you could create a group inside another? + +```python +from discord import SlashCommandGroup +from math import sqrt + +math = SlashCommandGroup("math", "Math related commands") +advanced = math.create_subgroup("advanced", "Advanced math commands") + +@advanced.command() +async def square_root(ctx, x: int): + await ctx.respond(sqrt(x)) + +bot.add_application_command(math) +``` + +The command created above can be invoked by typing `/math advanced square_root`. + +## Options & Option Types + +Whenever you're using Slash Commands, you might notice that you can specify parameters that the user has to set or can optionally set. These are called Options. + +Options can also include a description to provide more information. [You can learn more about Options in our documentation!](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.Option) + +Since you want different inputs from Options, you'll have to specify the type for that Option; there are a few ways of doing this. + + + + +You could use Type Annotations and let Pycord figure out the option type or explicitly specified using the [`SlashCommandOptionType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.SlashCommandOptionType) enum. + +```python +import discord + +bot = discord.Bot() + +@bot.command() +# pycord will figure out the types for you +async def add(ctx, first: discord.Option(int), second: discord.Option(int)): + # you can use them as they were actual integers + sum = first + second + await ctx.respond(f"The sum of {first} and {second} is {sum}.") + +@bot.command() +# this explicitly tells pycord what types the options are instead +async def join( + ctx, + first: discord.Option(discord.SlashCommandOptionType.string), + second: discord.Option(discord.SlashCommandOptionType.string) +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + add + +
+ The sum of 1 and 1 is 2. +
+ +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+ + +Instead of Type Annotations, you can also use the option decorator. This is usually done to have type-hinting. + +```python title="Slash Command Type" +import discord + +bot = discord.Bot() + +@bot.command() +@discord.option("first", type=discord.SlashCommandOptionType.string) # type = str also works +@discord.option("second", type=discord.SlashCommandOptionType.string) # type = str also works +async def join( + ctx, + first: str, + second: str, +): + joined = first + second + await ctx.respond(f"When you join \"{first}\" and \"{second}\", you get: \"{joined}\".") + +bot.run("TOKEN") +``` + + + +
+ + join + +
+ When you join "Py" and "cord", you get: "Pycord". +
+
+ +
+
+ +## Autocomplete + +Discord's autocomplete allows developers to determine option choices that are used in a slash command option. You can do this by defining a function: + +```py +async def get_animal_types(ctx: discord.AutocompleteContext): + """ + Here we will check if 'ctx.options['animal_type']' is a marine or land animal and return respective option choices + """ + animal_type = ctx.options['animal_type'] + if animal_type == 'Marine': + return ['Whale', 'Shark', 'Fish', 'Octopus', 'Turtle'] + else: # is land animal + return ['Snake', 'Wolf', 'Lizard', 'Lion', 'Bird'] + +@bot.slash_command(name="animal") +async def animal_command( + ctx: discord.ApplicationContext, + animal_type: discord.Option(str, choices=['Marine', 'Land']), + animal: discord.Option(str, autocomplete=discord.utils.basic_autocomplete(get_animal_types)) +): + await ctx.respond(f'You picked an animal type of `{animal_type}` that led you to pick `{animal}`!') +``` + + + +
+ + animal + +
+ You picked an animal type of Marine that led you to pick Shark! +
+
+ +:::warning + +Autocomplete can **only** be used with slash commands. + +::: + +:::info Related Topics + +- [Interactions Index](../../interactions) +- [Rules and Common Practices](../../getting-started/rules-and-common-practices) +- [Cogs](../../popular-topics/cogs) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/interactions/index.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/index.mdx new file mode 100644 index 00000000..8603437f --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/index.mdx @@ -0,0 +1,242 @@ +--- +title: Discord Interactions +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +In December 2020, Discord released their first Interaction: the +[Slash Command](https://discord.com/developers/docs/interactions/application-commands#slash-commands). +Since then, Discord has added many types of Interactions, including: + +[**Application Commands**](https://discord.com/developers/docs/interactions/application-commands) + +- [**Slash Commands**](https://discord.com/developers/docs/interactions/application-commands#slash-commands): + Commands that can be used with the `/` prefix. +- **Context Menu Commands**: Commands that can be used from the right-click menu. + - [**User Commands**](https://discord.com/developers/docs/interactions/application-commands#user-commands): + Commands that can be used on a user by alt-clicking/selecting them. + - [**Message Commands**](https://discord.com/developers/docs/interactions/application-commands#message-commands): + Commands that can be used on a message by alt-clicking/selecting it. + +[**UI Components**](https://discord.com/developers/docs/interactions/message-components) + +- [**Buttons**](https://discord.com/developers/docs/interactions/message-components#buttons): + Buttons are attached to a message and can be clicked on to perform an action. +- [**Select Menus**](https://discord.com/developers/docs/interactions/message-components#select-menus): + Drop-down menus are used to select a number of options from a list. +- [**Modals**](https://discord.com/developers/docs/interactions/message-components#text-inputs): + Form-like modals can be used to ask for input from a user. + +## Application Commands + +Application Commands are another set of new features that are intended to avoid compromising users' safety and privacy. +They're relatively easy to add to your bot, and give people a simpler and safer way to use commands. + +### [Slash Commands](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.SlashCommand) + +Slash Commands were the first Interaction added to Discord. They're easy to use and create, and +is the only prefix commands alternative that does not need Message Content intent. + +:::note + +Preferring prefix commands over Application Commands is **not** a valid reason to apply for the +Message Content intent. Using that as a reason will get your application denied. + +::: + + + +
+ + ping + +
+ Pong! Latency is 335ms. +
+
+ +
+ +This is what a Slash Command looks like. Not too different from a prefix command, +apart from the note telling you who invoked it. A Slash Command's fields can accept any of the following: + +- Members +- Roles +- Channels +- Attachments +- Text + +Just about as good as it gets. + +### [Message](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.MessageCommand) and [User](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.UserCommand) Commands + +Message Commands and User Commands were both introduced at around the same time, and are very similar to each other, so we'll be +introducing them together. These commands can be found in the `Apps` tab when alt-clicking. The only difference between the two is that +Message Commands only appear in the `Apps` tab of a message, while User Commands are found in the `Apps` tab of a user. Message Commands +can be used to quickly report a message, warn a user for a message, and other functions. Likewise, User Commands can be used to add a +user to a ticket, warn a user, and more. + +Here's an example of a Message Command: + + + + Hello World! + + +
+ + Reverse Message + +
+ Message 930650407917748286 reversed is "!dlroW olleH" +
+
+ +
+ +And here's an example of a User Command: + + + + {defaultOptions.profiles.dorukyum.author} has been on Discord for a long time + + +
+ + User Age + +
+ {defaultOptions.profiles.dorukyum.author} is 1 week old. +
+ +
+ + User Age + +
+ {defaultOptions.profiles.bob.author} is 40 years old. +
+ + 🤔 + +
+ +
+ +Pretty cool, right? To learn more about these two, please read the [Context Menus guide](./application-commands/context-menus.mdx). + +## [Application Commands](#application-commands) vs. [Prefix Commands](../extensions/commands/prefixed-commands) + +Ever since Discord was created, apps on it have used prefix commands. Using prefixes meant that you would have to put a +certain character (or string of characters) in front of your command, such as the exclamation mark in `!ping`. The way this +worked was that your bot would listen for messages, pick out the ones that had their specific prefix, and then respond to the command. +Now, Discord is encouraging developers to switch their bots over to Application Commands, which is a new system meant to preserve the +privacy and safety of their users. But why exactly is Discord making us switch? What's the better option, Application Commands or prefix +commands? Below, we'll discuss everything you need to know. + +### Discord's Decision + +Application Commands were conceptualized partly due to privacy concerns. When Discord first began, they weren't entirely concerned about bots +having access to the content of every message that was being sent. However, as Discord grew, this became more of a problem. Hypothetically, bots +could simply log every message they're able to receive via the Discord API and hand their contents over to a company or other third party. This is +a problem, since that data is meant to be used only by Discord. As such, they locked down Message Content, and introduced Application Commands for +bot developers to use instead. + +Prefix commands work by reading messages, as described before. Application Commands, however, don't +work this way; instead, they work by having your bot get information from Discord about when a command was used. This way, Discord can limit +Message Content only to bots that _absolutely_ depend on it, such as auto-moderation bots. + +### Who has to Use Application Commands + +Any verified bot that does not have the Message Content intent must use Application Commands. Discord is allowing developers to submit +applications for the ability to use the intent; however, since they don't want to keep supporting prefix commands due to privacy concerns, +they will automatically decline any application that includes only that as a reason. So, if your bot doesn't have an auto-moderation feature +(or any other functionality that requires Message Content), you're out of luck. + +Unverified bots, however, don't have to use Application Commands. This is because the Message Content intent is a `Privileged Intent`, meaning that +it must be applied for only if your bot is verified or about to be verified. Unverified bots don't have to apply for Privileged Intents, so they can +use them freely. + +So, if your bot is made only for a couple of servers, you can choose between prefix commands and Application Commands. However, if you plan on expanding +your bot's reach, it'll have to use Application Commands. + +### What's the Better Option + +Choosing which is the better option is up to you, if you're starting small. If +you plan on growing your bot, however, you will have to use Application Commands. Since prefix commands are slowly being phased out by Discord, +there isn't much of a choice for developers of larger bots. + +## Message Components + +Message Components are fairly new features in Discord, allowing developers to give their bots a fast +and understandable user interface. Message Components are easy to use and make your bot look modern, +sleek, and downright awesome. + +### [Views](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View) + +Views are not an Application Command nor are they a Message Component. Views are the invisible placeholders, or grid, +that Message Components lie in. Views can have up to 5 [`Action Rows`](https://docs.pycord.dev/en/stable/api/models.html#discord.ActionRow), +and Action Rows can have a maximum of 5 slots. Below, you can find a table showing how many slots a Message Interaction takes up. + +| Component | Slots | +| ------------ | ----------------------------------------------- | +| Buttons | 1 Slot | +| Select Menus | 5 Slots | +| Text Modals | 1 Slot (opened via a Button) | + +So, based on this, you could have a maximum of 25 Buttons in a View with no Select Menus, and 5 Select +Menus in a View with no Buttons. This doesn't mean you can't have them both in a View, however. You can have +a combination of them, such as 20 Buttons and a Select Menu or 10 Buttons and 3 Select Menus. + +### [Buttons](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button) + +Buttons are the first of the Message Components. They allow for quick responses to prompts, such as for canceling or continuing an action. +Of course, these aren't their only uses; people have created awesome things with Buttons, such as calculators, games, and more! + + + + Discord Buttons are awesome! +
+ + Click me! + +
+
+
+ +
+ +This is what a Button looks like, very simple and modern. To learn more about Buttons, refer to our +[Buttons page](./ui-components/buttons.mdx). + +### [Select Menus](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Select) + +Select Menus are the second of Discord's Message Components. They allow users to select from a list of choices, which your bot can then use. +Select Menus are good for things such as choosing features, pages of a help menu, and more. + +![Select Menu Example Image](../assets/interactions/select-menus-example.png) + +This is what a Select Menu looks like. While not looking as good as Buttons, they still look great +and have even greater possibilities. To learn more about Select Menus, please refer to our [Select +Menus page](./ui-components/dropdowns.mdx). + +### [Modal Dialogs](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal) + +Text Modals are the most recently added Message Component in Discord. They're useful for text input and filling out forms, such as a +sign-up for your bot's service. These are meant to replace long bot setup processes by allowing users to fill out multiple text fields, +which avoids having the user send multiple messages for the bot. Modals can be accessed by either invoking an Application Command or by +interacting with another UI Component. + +![Text Modal Example Image](../assets/interactions/modal-example.png) + +This is what a Text Modal looks like, easy to use and one of the most useful Message Components yet. To learn more about Text Modals, +please visit our [Modal Dialogs page](./ui-components/modal-dialogs.mdx). diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json new file mode 100644 index 00000000..7b0a72fe --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "UI Components", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx new file mode 100644 index 00000000..046b36c7 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/buttons.mdx @@ -0,0 +1,314 @@ +--- +title: Buttons +description: Learn all about implementing buttons in your Discord Bot using Pycord. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +On May 26, 2021, Discord added a new interaction called buttons. Instead of reactions, bots could now +send buttons and users could use them to interact with bots. This opened up a whole new world of +possibilities for bots. Soon after, developers made calculators, polls, and games like blackjack, UNO, +and even Minecraft! Buttons provided a clear and easy to use interface for interacting with bots. + +So, let's learn how you can add buttons to your bot! + +## Concept + +Buttons weren't the only update to the interactions system in Discord. Discord also added [Select Menus](./dropdowns) and [Modal Dialogs](./modal-dialogs), both of which work very similarly to buttons. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive button. + +```python +import discord + +bot = discord.Bot() # Create a bot object + +class MyView(discord.ui.View): # Create a class called MyView that subclasses discord.ui.View + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.primary, emoji="😎") # Create a button with the label "😎 Click me!" with color Blurple + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") # Send a message when the button is clicked + +@bot.slash_command() # Create a slash command +async def button(ctx): + await ctx.respond("This is a button!", view=MyView()) # Send a message with our View class that contains the button + +bot.run("TOKEN") # Run the bot +``` + +Using this command should return the following message: + + + +
+ + button + +
+ This is a button! +
+ + Click me! + +
+
+
+ +
+ +As you can see, we create a class called `MyView` that [subclasses](#oop) +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `button_callback` to the `MyView` class with the decorator +[`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Button). +This decorator adds a button to a component. This function takes two arguments: the button that was +clicked and the interaction. These arguments are passed to the function when the button is clicked +by the module. We use the [`interaction.response.send_message`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse.send_message) +function to send a message to the channel where the interaction was sent. + +Finally, we create a global slash command called `button` that sends the message, along with the view +that contains a button. + +This is the basic syntax of creating a button. What you create with it is up to you. You can worry +about making your button do amazing things, while Pycord handles the rest! + +## Button Styles + + + +| Name | Usage | Color | +| --------- | ----------------------------------------------------------------------------------------- | ------- | +| Primary | `discord.ButtonStyle.primary` / `discord.ButtonStyle.blurple` | Blurple | +| Secondary | `discord.ButtonStyle.secondary` / `discord.ButtonStyle.grey` / `discord.ButtonStyle.gray` | Grey | +| Success | `discord.ButtonStyle.success` / `discord.ButtonStyle.green` | Green | +| Danger | `discord.ButtonStyle.danger` / `discord.ButtonStyle.red` | Red | +| Link | `discord.ButtonStyle.link` / `discord.ButtonStyle.url` | Grey | + +Check out the [`discord.ButtonStyle`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ButtonStyle) class for more information. + +![Different Button Styles](../../assets/interactions/button-styles.png) + +You can set a button's style by adding the `style` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) decorator. + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Click me!", style=discord.ButtonStyle.success) + async def button_callback(self, button, interaction): + await interaction.response.send_message("You clicked the button!") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots, and each button takes up 1 slot. +So, how do we move the buttons to another row? + +This can be done by specifying the `row` argument in the [`discord.ui.button`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.button) +decorator. + +:::info The `row` argument + +The row argument specifies the relative row this button belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=1, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") +``` + +## Disabling Buttons + +### Pre-Disabled Buttons + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary, disabled=True) # pass `disabled=True` to make the button pre-disabled + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView()) +``` + +### Disabling Buttons on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="A button", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + button.disabled = True # set button.disabled to True to disable the button + button.label = "No more pressing!" # change the button's label to something else + await interaction.response.edit_message(view=self) # edit the message's view +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.button(emoji="😀", label="Button 1", style=discord.ButtonStyle.primary) + async def button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) + + @discord.ui.button(label="Button 2", style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +Sometimes, you want to have a button that is disabled after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... + +@bot.command() +async def button(ctx): + await ctx.send("Press the button!", view=MyView(timeout=30)) +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.button() + async def button_callback(self, button, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a button that is disabled after a certain amount of time, you want to have a +button that is always working. + +Normally, when the bot goes offline, all of its buttons stop working. You will be able to see the +buttons, but nothing will happen when you press them. This is a problem +if you are trying to create a self-role system with buttons, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons will stop working. When the bot comes back online, however, the buttons will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view must have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.button(label="A button", custom_id="button-1", style=discord.ButtonStyle.primary, emoji="😎") # the button has a custom_id set + async def button_callback(self, button, interaction): + await interaction.response.send_message("Button was pressed", ephemeral=True) + +@bot.command() +async def button(ctx): + await ctx.send(f"Press the button! View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many buttons can I have in a message? + +Each message can have a maximum of 25 buttons. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do buttons need any special permissions? + +No new permissions are needed for either the bot or the server to allow bots to use buttons. + +#### Should I replace reactions with buttons for my bot? + +That is up to you. Buttons do provide a cleaner interface for your bot and are easier to use. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx new file mode 100644 index 00000000..8320f25d --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/dropdowns.mdx @@ -0,0 +1,339 @@ +--- +title: Select Menus +description: Learn all about implementing Select Menus or Dropdowns in your Discord Bot with Pycord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Shortly after the buttons were added, Discord added their second message component: Select Menus. Select Menus allow users to choose from a list of items sent by a bot. These are a great substitute for having a user send a number that corresponds to an option. You can even allow users to select multiple options from the Select Menus. This guide will show you the easy and painless ways of using them with Pycord. + +## Concept + +Select Menus aren't the only message component in Discord. There's also [Buttons](./buttons) and [Modal Dialogs](./modal-dialogs). Select Menus make it easy for users to pick one or multiple options from a list provided by a bot. + +These UI elements reside in a "view". To learn more about views, please refer to the +[interactions page](../../interactions). + +## Usage Syntax + +Let's see how to create a simple responsive select menu. + +```python +import discord + +bot = discord.Bot() + +class MyView(discord.ui.View): + @discord.ui.select( # the decorator that lets you specify the properties of the select menu + placeholder = "Choose a Flavor!", # the placeholder text that will be displayed if nothing is selected + min_values = 1, # the minimum number of values that must be selected by the users + max_values = 1, # the maximum number of values that can be selected by the users + options = [ # the list of options from which users can choose, a required field + discord.SelectOption( + label="Vanilla", + description="Pick this if you like vanilla!" + ), + discord.SelectOption( + label="Chocolate", + description="Pick this if you like chocolate!" + ), + discord.SelectOption( + label="Strawberry", + description="Pick this if you like strawberry!" + ) + ] + ) + async def select_callback(self, select, interaction): # the function called when the user is done selecting options + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") + +@bot.command() +async def flavor(ctx): + await ctx.respond("Choose a flavor!", view=MyView()) + +bot.run("TOKEN") +``` + +There's a lot going on over here! Don't worry, we will go over the code and explain it. + +As you can see, we create a class called `MyView` that subclasses +[`discord.ui.View`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.View). + +Then, we add a function called `select_callback` to the `View` class with the decorator +[`discord.ui.select`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.select). +This decorator adds a select menu to the view. This decorator takes a few arguments to customize your select menu. Read them in the [Customization section](#customization). + +That was the decorator. Now, the function itself is pretty simple. It takes two parameters, not including `self`. The parameters are `select`: The select menu, and `interaction`: a [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object. Both of these are passed by Pycord, so you just need to specify them in the function! + + + +In the callback, you could do anything you want. You get the two parameters `select` and `interaction` to play around with. Here, we send a message using `await interaction.response.send_message` (where interaction is [`discord.InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse)) with content `select.values[0]`, which sends the label of the first/only option the user selected. Obviously, this is only an example, and you could do just about anything you want. + +Finally, we create a global slash command called `flavour` that sends a message "Choose a flavor!" along with the view +that contains our select menu. + +This is the basic syntax of creating a select menu. What you create with it is up to you. You can worry +about making your code do amazing things, while Pycord handles the rest! + +## Customization + +#### Select Menu Properties + +- `select_type`: The type of select to create. This must be a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. +- `channel_types`: A list of channel types that can be selected in the menu. This is only valid for selects of `select_type` [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType). +- `options`: A list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. These are the options that can be selected in this menu. +- `placeholder` is the placeholder text shown in the select menu if no option is selected. +- `custom_id`: The ID of the select menu that gets received during an interaction. It is recommended not to set this to anything unless you are trying to create a persistent view. +- `row`: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed). +- `min_values`: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `max_values`: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25. +- `disabled`: Whether the select is disabled or not. Defaults to False. + +#### Select Option Properties + +In the `options` parameter, you pass a list of [`discord.SelectOption`](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.SelectOption) values. This class also has a few parameters: + +- `default` (whether the option is selected by default) +- `description` (an additional description, if any) +- `emoji` (a string or an emoji object, if any) +- `label` (the name displayed to users, can be up to 100 characters) +- `value` (a special value of the option, defaults to the label). + +## Select Types + +In addition to regular string selects, you can also have your select menu contain users, roles, mentionables, and channels as its options. You can use these alternative select types by passing a [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value for the `select_type` parameter when creating the Select. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.user_select + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +Additionally, you can use shortcut decorators to create a [`discord.ui.Select`](https://docs.pycord.dev/en/master/api/ui_kit.html#discord.ui.select) with a predetermined [`discord.ComponentType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType) value. Using a shortcut decorator, the above code can be rewritten like this: + +```python +class MyView(discord.ui.View): + @discord.ui.user_select() + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Hello, {select.values[0].mention}") +``` + +### Specifying Channel Types + +When using a [`discord.ComponentType.channel_select`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ComponentType.channel_select) type select menu, you can pass in a list of [`discord.ChannelType`](https://docs.pycord.dev/en/stable/api/enums.html#discord.ChannelType) values to limit which types of channels users can choose when interacting with the select menu. + +```python +class MyView(discord.ui.View): + @discord.ui.select( + select_type=discord.ComponentType.channel_select, + channel_types=[discord.ChannelType.text, discord.ChannelType.voice] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"You selected {select.values[0].mention}") +``` + +## Action Rows + +We have discussed that Views can have 5 rows. Each row has 5 slots. A button takes a single slot, while a select menu takes up all 5 of them. This means a view can have a maximum of 5 select menus, or any possible combination of select menus and buttons. + +The arrangement of buttons and select menus is generally adjusted by Pycord. However, it is possible to move them to specific relative rows. This is done by specifying the `row` argument. + +:::info The `row` argument + +The row argument specifies the relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero-indexed). + +::: + +```python +class MyView(discord.ui.View): + @discord.ui.button(label="Button 1", row=0, style=discord.ButtonStyle.primary) + async def first_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.button(label="Button 2", row=0, style=discord.ButtonStyle.primary) + async def second_button_callback(self, button, interaction): + await interaction.response.send_message("You pressed me!") + + @discord.ui.select( + row = 1, + options = [...] + ) + async def select_callback(self, select, interaction): + await interaction.response.send_message(f"Awesome! I like {select.values[0]} too!") +``` + +## Disabling Select Menus + +### Pre-Disabled Menus + +```python +class MyView(discord.ui.View): + @discord.ui.select( + disabled = True, # pass disabled=True to set the menu as disabled + options = [...] + ) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send("Select and option from the menu!", view=MyView()) +``` + +### Disabling Menus on Press + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + select.disabled = True # set the status of the select as disabled + await interaction.response.edit_message(view=self) # edit the message to show the changes +``` + + + + + +```python +class MyView(discord.ui.View): + @discord.ui.select(options = [...]) + async def first_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) # edit the message to show the changes + + @discord.ui.select(options = [...]) + async def second_select_callback(self, select, interaction): + self.disable_all_items() + await interaction.response.edit_message(view=self) +``` + + + + +## Timeouts + +You may want a select menu to automatically stop working after a certain amount of time. This is where timeouts come in. + + + + +```python +class MyView(discord.ui.View): + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select(ctx): + await ctx.send(view=MyView(timeout=30)) # specify the timeout here +``` + + + + +```python +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=10) # specify the timeout here + + async def on_timeout(self): + self.disable_all_items() + await self.message.edit(content="You took too long! Disabled all the components.", view=self) + + @discord.ui.select(options = [...]) + async def select_callback(self, select, interaction): + ... +``` + + + + +Here, we disable all buttons and select menus in the view. Then, we edit the message to show that the timeout was reached. + +:::note + +If the `on_timeout` coroutine is not present, the components will simply stop working after the specified time. + +::: + +## Persistent Views + +Sometimes, instead of a select menu that is disabled after a certain amount of time, you want to have a +select menu that is always working. + +Normally, when the bot goes offline, all of its views stop working, even if they don't have a timeout. You will be able to see the +views, but nothing will happen when you try to interact with them. This is a problem +if you are trying to create a self-role system, for example. This is where persistent views come in. + +Persistent views work forever. When the bot goes offline, the buttons and select menus will stop working. However, when the bot comes back online, the buttons and select menus will start working again. + +In a Persistent View, the timeout must be set to `None` and all the children in the view much have a `custom_id` attribute set. + +```python +@bot.event +async def on_ready(): + bot.add_view(MyView()) # Registers a View for persistent listening + +class MyView(discord.ui.View): + def __init__(self): + super().__init__(timeout=None) # timeout of the view must be set to None + + @discord.ui.select(custom_id="select-1", options = [...]) # a custom_id must be set + async def select_callback(self, select, interaction): + ... + +@bot.command() +async def select_menu(ctx): + await ctx.send(f"View persistence status: {MyView.is_persistent(MyView())}", view=MyView()) +``` + +## FAQ + +#### How many select menus can I have in a message? + +Each message can have a maximum of 5 select menus. Views can have up to 5 rows, and each row has 5 slots. A button takes up one slot, while a select menu takes up all five slots. + +#### Can I add more than one view to a message? + +No. As a Discord limitation, you can only have one view per message. + +#### Why are UI Components so confusing? + +They cannot be simple like commands. This system makes them flexible and doesn't limit your imagination. There are loads of different ways you can use UI Components. For example, you could subclass Buttons or Select Menus and add them to a view using the view's `add_item` function. + +UI Components aren't hard to use if you know Python. We recommend learning [Object-Oriented Programming with Python](#oop). + +#### What is OOP? What is subclassing? + +OOP (object-oriented programming) is a programming paradigm that allows you to create objects that have +their own properties and methods. Almost everything in python is an object or a class. `discord.Embed` and `discord.ui.View` are both classes. When you use `view = discord.ui.View()` to create a view, you are actually creating an object of type `discord.ui.View`. + +Subclassing is a Python OOP concept. It means that you can create a class that inherits from another class. In other words, the class that subclasses another class can inherit all the methods and attributes of that class. + +We highly recommend you learn about basic Python concepts like classes and inheritance before you start learning Pycord. + +**Resources**: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +#### Do select menus need any special permissions? + +No new permissions are needed in the bot or in the server. + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx new file mode 100644 index 00000000..bd585c77 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/interactions/ui-components/modal-dialogs.mdx @@ -0,0 +1,107 @@ +--- +title: Modal Dialogs +description: Learn how you can implement Modals in your Discord Bot with Pycord! +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +Modal Dialogs, also known as "modals", provide a form-like structure for bots to receive input from users. No extra permissions are needed for bots to send modal dialogs, so it becomes a convenient workaround for bots to receive longer input without needing the Message Content [intent](../../popular-topics/intents). + +## Concept + +Modal Dialogs consist of a title, custom ID, and up to 5 [`discord.ui.InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) components. While creating modals, we generally subclass [`discord.ui.Modal`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.Modal), as we'll see later. + +Unlike other UI Components, Modals cannot be sent with messages. They must be invoked by an Application Command or another UI Component. + +## Usage Syntax + +```py +class MyModal(discord.ui.Modal): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.add_item(discord.ui.InputText(label="Short Input")) + self.add_item(discord.ui.InputText(label="Long Input", style=discord.InputTextStyle.long)) + + async def callback(self, interaction: discord.Interaction): + embed = discord.Embed(title="Modal Results") + embed.add_field(name="Short Input", value=self.children[0].value) + embed.add_field(name="Long Input", value=self.children[1].value) + await interaction.response.send_message(embeds=[embed]) +``` + + + + +The `ctx` parameter we define in Application Commands receives an [`ApplicationContext`](https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext) object. Using its `send_modal()` coroutine, you can send a Modal dialog to the user invoking the Application Command. + +```py +@bot.slash_command() +async def modal_slash(ctx: discord.ApplicationContext): + """Shows an example of a modal dialog being invoked from a slash command.""" + modal = MyModal(title="Modal via Slash Command") + await ctx.send_modal(modal) +``` + + + + +The `interaction` parameter we define in UI Components receives an [`Interaction`](https://docs.pycord.dev/en/stable/api/models.html#discord.Interaction) object. The `response` attribute of the object contains an [`InteractionResponse`](https://docs.pycord.dev/en/stable/api/models.html#discord.InteractionResponse) object, with various coroutines such as `send_message()` and `send_modal()`, which we utilize. + +```py +class MyView(discord.ui.View): + @discord.ui.button(label="Send Modal") + async def button_callback(self, button, interaction): + await interaction.response.send_modal(MyModal(title="Modal via Button")) + +@bot.slash_command() +async def send_modal(ctx): + await ctx.respond(view=MyView()) +``` + + + + +The above example uses an embed to display the results of the modal submission, but you can do anything you want with the text provided by the user. +Each input field can be accessed in the order it was added to the modal dialog, via `Modal.children`. + +## Customization + +A Modal can have up to 5 [`InputText`](https://docs.pycord.dev/en/stable/api/ui_kit.html#discord.ui.InputText) fields. These fields offer some customization. + +Each field has a label which is shown to the user. This is defined with `label`. + +The `style` parameter is used to determine whether it should be a short (single-line) or long (multi-line) input field. + +There are a number of aliases that can be used: + +```x title="Single-line InputTextStyle values:" +short +singleline +``` + +```x title="Multi-line InputTextStyle values:" +paragraph = 2 +multiline = 2 +long = 2 +``` + +:::info Related Topics + +- [Slash Commands](../application-commands/slash-commands) +- [Buttons](./buttons) +- [Interactions Index](../../interactions) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/introduction.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/introduction.mdx new file mode 100644 index 00000000..3262c632 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/introduction.mdx @@ -0,0 +1,50 @@ +--- +title: Introduction +description: Pycord Guide is a complete guide for Pycord. Learn how to create Discord Bots today! +sidebar_position: 1 +--- + +Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord, written in Python. Pycord is a maintained fork of [discord.py](https://github.com/Rapptz/discord.py). + +## Before you begin + +Pycord is an advanced and complex Python library. To take advantage of the full capabilities of Pycord, you will need to have a good understanding of Python. You should know the basics of Python and have an understanding of the following concepts: + +- Variables +- Data Types +- Functions +- Packages +- Conditionals +- Loops +- Classes +- Object-Oriented Programming +- Inheritance +- Exception Handling +- Iterators +- Coroutines +- Async/Await + +This list is not exhaustive, but it should give you a good idea of what you need to know to get started. + +When you see an ellipsis - that's the three dots - in this guide, it is a placeholder for code that you need to fill in. Sometimes, it may be code for a command, while other times it could be something simple like a Guild ID. Make sure to replace them before running your bot! + +## Learning Resources + +Here are some good resources to get started or to freshen up your Python knowledge: + +- [Official Beginner's Guide](https://wiki.python.org/moin/BeginnersGuide) +- [Official Tutorial](https://docs.python.org/3/tutorial/) +- [Automate the Boring Stuff, a free online book for complete beginners to programming](https://automatetheboringstuff.com/) +- [Learn Python in y Minutes, complete cheat sheet for people who know programming already](https://learnxinyminutes.com/docs/python3/) +- [Swaroopch's free Python book](http://python.swaroopch.com/) +- [Codeabbey, exercises for beginners](http://www.codeabbey.com/) + +## Credits + +First of all, we would like to thank [Rapptz](https://github.com/Rapptz) for the original [discord.py](https://pypi.org/project/discord.py) library. Pycord is a maintained fork of this library. + +We would also like to thank the [discord.js guide](https://discordjs.guide), which inspired this guide style-wise, and the [original Pycord Guide](https://namantech.me/pycord), which inspired some content in this guide. + +We created this guide using [Docusaurus v2](https://docusaurus.io), a modern static site generator for React. We would also like to thank Danktuary for his [`@discord-message-components/react`](https://www.npmjs.com/package/@discord-message-components/react) package, from which we took the Discord message components. + +And finally, we would like to thank the amazing and loving community of Pycord users, contributors and developers. diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/more/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/more/_category_.json new file mode 100644 index 00000000..2cbe2c56 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/more/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 8, + "label": "More", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/more/community-resources.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/more/community-resources.mdx new file mode 100644 index 00000000..ed3075bd --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/more/community-resources.mdx @@ -0,0 +1,23 @@ +--- +title: Community Resources +--- + +This page showcases the amazing things created by the Pycord community, including bots, Plugins, and more. + +## Plugins + +| Name | Type | GitHub | +| --------------- | ------------ | --------------------------------------------------------------- | +| Music Cord | Music | [NixonXC/cord-music](https://github.com/NixonXC/cord-music) | +| pycord-i18n | Localization | [Dorukyum-pycord-i18n](https://github.com/Dorukyum/pycord-i18n) | +| pycord-multicog | Cogs | [pycord-multicog](https://github.com/Dorukyum/pycord-multicog) | +| EzCord | Utilities | [EzCord](https://github.com/tibue99/ezcord) | + +## Bots + +| Name | Type | Link | +| ------------------------ | ------------ | ----------------------------------------------------------------------------------- | +| Discord-Multipurpose-Bot | Multipurpose | [github](https://github.com/pogrammar/Discord-multipurpose-bot/tree/master/Python) | +| inconnu | Fun & QOL | [github](https://github.com/tiltowait/inconnu) | +| Mai | Multipurpose | [github](https://github.com/TeamMai/Mai) & [website](https://xfghoul.github.io/Mai) | +| Toolkit | Multipurpose | [github](https://github.com/Dorukyum/Toolkit) | diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/more/contributing.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/more/contributing.mdx new file mode 100644 index 00000000..469ea3ee --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/more/contributing.mdx @@ -0,0 +1,463 @@ +--- +title: Contributing to the Guide +description: Learn how to contribute to the Pycord Guide. +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; + +This page outlines some of the basic syntax you need to know to contribute to the guide. We recommend you also check out: + +- [Docusaurus's Docs](https://docusaurus.io/docs/) +- [Contributing Rules](https://github.com/Pycord-Development/guide/blob/master/.github/CONTRIBUTING.md) + +## Info + +We use [Docusaurus v2](https://docusaurus.io/) to generate our guide. All the guide pages are generated +from `mdx` files in the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory. +MDX allows you to use JSX in your markdown content. + +## Structure + +Let's visit the [`docs/`](https://github.com/Pycord-Development/guide/tree/master/docs) directory and check its file structure. + +We can see various folders and a few files in it. Let's talk a bit about the `introduction.mdx` file. At the top, you can see something like: + +```md +--- +title: Introduction +description: ... +sidebar_position: 1 +--- +``` + +Most pages have this at the top. The `title` defaults to the file name. Since the titles need to be Capitalized according to need while the file names are lowercased (sometimes, the file names are shorter than the title!), we set a title ourselves. + +The `description` field is also important. This is the text shown in an embed when the page's link is shared on Discord, Twitter or other websites that support embedded links. Make sure to give a nice an interesting description! + +The `sidebar_position` field is pretty self-explanatory. It sets the position of the page in the sidebar. Most files in categories do not need this since they are sorted alphabetically. + +## Markdown Syntax + +This page quickly outlines some of the syntax that is used in markdown. + +````mdx +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + + ```python + print("We can use code blocks like this.") + ``` + +You can add [links to other websites](https://pycord.dev). You can add images like this: ![alternate text that describes the image](https://pycord.dev/image.png). + +- You can create +- unordered lists like this + +1. Or ordered lists +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` +4. Like this + +# Headers + +## Go + +### Like + +#### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet +```` + +
+Preview +
+ +Markdown syntax is pretty easy. You can add **bold**, _italic_ and _underline_ text. You can use ~~strikethrough~~. You can use `inline code blocks`. + +```python +print("We can use code blocks like this.") +``` + +You can add [links to other websites](https://pycord.dev). You can add images by adding ![alt text](@site/static/img/favicon.ico). + +- You can create +- unordered lists like this + +1. Or ordered lists + +2. Like this + +3. If you want markdown to automatically detect what number you are on, you can use `1.` + +4. Like this + + # Headers + + ## Go + + ### Like + + #### This + +You can even use HTML in Markdown. + +This text is monospaced +Use
to add a break line. + +> We can use blockquotes too. + +2 ways to create tables: + + + + + + + + + + +
HeaderHeader
CellCell
+ +| Header | Header | +| ------ | ------ | +| Cell | Cell | + +Here's a line for us to start with. + +This line is separated from the one above by two new lines, so it will be a _separate paragraph_. + +This line is also a separate paragraph, but... +This line is only separated by a single newline, so it's a separate line in the _same paragraph_. + +We can use emojis too! :joy: + +- [x] We can have task lists too +- [ ] This is a task +- [ ] That's not done yet + +
+
+ +## Admonitions + +We can add warnings, notes, etc. with the following syntax: + +```md +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: +``` + +
+Preview +
+ +:::note + +Some **content** with _markdown_ `syntax`. + +::: + +:::tip + +Some **content** with _markdown_ `syntax`. + +::: + +:::info + +Some **content** with _markdown_ `syntax`. + +::: + +:::caution + +Some **content** with _markdown_ `syntax`. + +::: + +:::danger + +Some **content** with _markdown_ `syntax`. + +::: + +:::important + +Remember that it's `:::important`, not `::: important` with a space! + +::: + +:::tip Cool Stuff + +You can edit an admonition's title by adding text after the `:::` and name, like this! + +::: + +
+ +
+ +## Discord Message Components + +As most files already have the imports for these, it's not that hard to add them. + +First, import the necessary components: + +```tsx +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent from "@site/src/components/DiscordComponent"; +``` + +The div starts like so: + +```tsx + + + + +
+``` + +This is where you list a `DiscordMessage`. + +```tsx + + + Hello! + + + +
+``` + + + + Hello! + + + +
+ +It has a pretty straightforward syntax. + +:::tip + +Add a `
` to the end of a component to make the content below it look better. + +::: + +### Slash Commands + +To make a message authored by a slash command, do the following: + +```tsx + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+``` + + + +
+ + update + +
+ Updated dependencies to the latest version! +
+
+ +### Buttons + +To make a message with buttons, do the following: + +```tsx + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+``` + + + +
+ + work + +
+ Work Done! +
+ + Work More + Sleep + +
+
+
+ +## Page Format + +There are a few things you need to take care of: + +1. Make sure that the spelling and grammar is perfect. We have a GitHub action configured that will warn you about spelling errors when you start a pull request. Make sure to commit your changes accordingly. + + As for the grammar, you should try reading the changes you have done and wait for reviews from others. + +2. A common mistake people make is incorrect header style. People often think that the less the important the topic is, the lower it's heading style should be. + + ```md + [PAGE STARTS] + # Topic + ## Less Important Topic + ## Subtopic + ``` + + ```md + [PAGE STARTS] + # About + [Introduction] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + That's VERY wrong. Here's the correct example: + + ```md + [PAGE STARTS] + [Introduction] + ## Topic + ## Less Important Topic + ### Subtopic + ``` + + ```md + [PAGE STARTS] + [Introduction] + + ## About + [More Information] + + ## Installation + [Content] + + ### Windows + [Content] + ``` + + Note that the `---`s at the beginning have been skipped here. diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/more/git.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/more/git.mdx new file mode 100644 index 00000000..0f929d6d --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/more/git.mdx @@ -0,0 +1,55 @@ +--- +title: Installing Git +description: Learn how you can install Git on your system. +--- + +Git is software for tracking changes in any set of files (also known as a "version control" software), usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Let's see how to install Git on different platforms. + +## Windows + +On Windows, Git can be installed via: + +- [Git for Windows](https://gitforwindows.org) +- [Git Scm](https://git-scm.com/download/windows) + +## Linux + +On Linux, Git is probably already installed in your distribution's repository. If not, you can install it via [Git for Linux](https://git-scm.com/download/linux). You can also install it via the built-in package manager on your Linux distro. + +## Mac + +You can install Git for your macOS computer via [Git for Mac](https://git-scm.com/download/mac). Alternatively, it can be also be installed from the Xcode Command Line Tools by installing Xcode from the App Store, or by running this: + +``` +xcode-select --install +``` + +## Using Package Managers + +You can also install Git using package managers. + +### Chocolatey + +If you use the Chocolatey package manager, you can install Git using: + +``` +choco install git +``` + +### Scoop + +If you use Scoop, you can install Git using: + +``` +scoop install git +``` + +### Brew + +If you're on macOS or Linux, you can install Git using: + +``` +brew install git +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx new file mode 100644 index 00000000..b0b8c7ea --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/more/virtual-environments.mdx @@ -0,0 +1,62 @@ +--- +title: Virtual Environments +description: Learn how to set up a virtual environment for Pycord. +--- + +## Setup + +Sometimes you want to keep libraries from polluting system installs or use a different version of libraries than the ones installed on the system. You might also not have permissions to install libraries system-wide. For this purpose, the standard library as of Python 3.3 comes with a concept called “Virtual Environment”s to help maintain these separate versions. + +A more in-depth tutorial is found on [Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html). + +However, for the quick and dirty: + +Go to your project’s working directory: + +```bash +$ cd your-bot-source +$ python3 -m venv venv +``` + +Activate the virtual environment: + +```bash +$ source venv/bin/activate +``` + +On Windows you activate it with: + +```batch +$ venv\Scripts\activate.bat +``` + +Use pip like usual: + +```bash +$ pip install -U py-cord +``` + +Congratulations. You now have a virtual environment all set up. + +## Additional info + +It can be useful to set up a requirements.txt, so you can just put all of your dependencies in there and have pip install it. +For instance, if you wanted to have the latest 2.0 version of pycord and [pytz](https://github.com/stub42/pytz/blob/master/src/README.rst), just create a file named requirements.txt with the following contents: + +``` +py-cord>=2.0.0 +pytz +``` + +And then (in your virtual environment) you can just execute + +```bash +pip install -r requirements.txt +``` + +To keep from committing your virtual environment to git, you can set up a .gitignore file with the following line +(assuming you named your virtual environment venv like the above example): + +``` +venv/ +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/_category_.json new file mode 100644 index 00000000..c38ea014 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 7, + "label": "Popular Topics", + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx new file mode 100644 index 00000000..5377a6c3 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/cogs.mdx @@ -0,0 +1,140 @@ +--- +title: Cogs +--- + +Cogs, often known as modules or extensions, are used to organize commands into groups. This is useful +for grouping commands that have the same general idea (such as moderation commands). This also helps +to avoid making your bot's files messy and cluttered. + +## Getting Started + +First, you'll need to create a folder to store your cogs, e.g. `cogs/`. + +Then, create a file inside the folder, e.g. `cogs/greetings.py`. By convention, the file name should +be the same as the name of the cog or module. + +We can then create the cog. + +```python title="./cogs/greetings.py" +import discord +from discord.ext import commands + +class Greetings(commands.Cog): # create a class for our cog that inherits from commands.Cog + # this class is used to create a cog, which is a module that can be added to the bot + + def __init__(self, bot): # this is a special method that is called when the cog is loaded + self.bot = bot + + @commands.command() # creates a prefixed command + async def hello(self, ctx): # all methods now must have both self and ctx parameters + await ctx.send('Hello!') + + @discord.slash_command() # we can also add application commands + async def goodbye(self, ctx): + await ctx.respond('Goodbye!') + + @discord.user_command() + async def greet(self, ctx, member: discord.Member): + await ctx.respond(f'{ctx.author.mention} says hello to {member.mention}!') + + math = discord.SlashCommandGroup("math", "Spooky math stuff") # create a Slash Command Group called "math" + advanced_math = math.create_subgroup( + "advanced", + "super hard math commands!" + ) + + @math.command() + async def add(self, a: int, b: int): + c = a + b + await ctx.respond(f"{a} + {b} is {c}.") + + @advanced_math.command() + async def midpoint(self, x1: float, y1: float, x2: float, y2: float): + mid_x = (x1 + x2)/2 + mid_y = (y1 + y2)/2 + await ctx.respond(f"The midpoint between those coordinates is ({mid_x}, {mid_y}).") + + @commands.Cog.listener() # we can add event listeners to our cog + async def on_member_join(self, member): # this is called when a member joins the server + # you must enable the proper intents + # to access this event. + # See the Popular-Topics/Intents page for more info + await member.send('Welcome to the server!') + +def setup(bot): # this is called by Pycord to setup the cog + bot.add_cog(Greetings(bot)) # add the cog to the bot +``` + +You can add any number of commands to your cog, as well as event listeners. However, this code will +not work on its own. In your main bot file, you must add the following code: + +```python +bot.load_extension('cogs.greetings') +``` + +This loads the file `cogs/greetings.py` and adds it to the bot. +The argument of `load_extension` should be your cog's path (e.g. cogs/greetings.py) without the file +extension and with the `/` replaced with `.` + +If you have multiple cogs, you can add them all at once by adding the following code: + +```python +cogs_list = [ + 'greetings', + 'moderation', + 'fun', + 'owner' +] + +for cog in cogs_list: + bot.load_extension(f'cogs.{cog}') +``` + +## Cog Rules + +When using a cog instead of the main file, there are some changes you have to make to your code. This +is because cogs work slightly different from a regular file. + +### The `self` variable + +The self variable is a variable that represents a class. In the case of cogs, `self` represents +the cog. In the `__init__` function, you can see that we have `self.bot = bot`. `bot` represents your +`discord.Bot` or `discord.ext.commands.Bot` instance, which is used for some functions. + +This means that instead of using functions that would usually be accessed via `bot`, you now need +to access them via `self.bot` + +Because we're in a class, all of our commands are methods of that class. Because of this, all of our +functions need to have `self` as the first parameter, where `self` is the cog. Without this, we +wouldn't be able to access our bot instance. + +### Creating Commands + +When creating prefixed commands, your decorator would usually be something like `@bot.command()`. If you're using +cogs, this isn't the case. In a cog, you can't access the bot instance outside of functions, so to +register a function as a command, you must instead use `@commands.command()`. + +Similar to prefixed commands, you'll have to use either the `@discord.slash_command()`, `@discord.user_command()`, +or `@discord.message_command()` decorators for Application Commands. + +Also, when creating a command, make sure that it is indented. If we want a command to be actually +inside a cog, it has to be inside your cog's class. If the command is not inside the cog, +your command becomes useless. + +### Events + +When creating events, you can no longer use `@bot.event` as a decorator. This is because we cannot +access the `bot` variable outside a function. To make an event, you have to use the `ext.commands` +method, `@commands.Cog.listener()`. Events also need `self` as their first parameter. + +And that's it! Cogs are a simple and easy way of organizing your code. Now you can check out how to +create a help command [here](../extensions/commands/help-command). + +:::info Related Topics + +- [Creating a Help Command](../extensions/commands/help-command) +- [Rules and Common Practices](../getting-started/rules-and-common-practices) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Application Commands](../interactions#application-commands) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx new file mode 100644 index 00000000..6c19dd29 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/error-handling.mdx @@ -0,0 +1,383 @@ +--- +title: Error Handling +description: All about handling errors. +--- + +import { + DiscordEmbed, + DiscordInteraction, + DiscordMessage, +} from "discord-message-components/packages/react"; +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +## About + +When using the library, errors are frequently raised due to various reasons. These reasons range from the Discord API +failing your bot's request due to missing permissions or an invalid syntax error. + +Before going into error handling, it's best that you learn the basic ways of handling errors. A good resource is: + +- [W3Schools' Guide to Python Try-Except Statements](https://www.w3schools.com/python/python_try_except.asp) + +## Basic Handling + +The most basic way to handle errors is to tackle it at the source. This can be done like so: + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +import asyncio + +import discord + +intents = discord.Intents.default() +intents.message_content = True + +bot = discord.Bot(intents=intents) + + +@bot.slash_command(description="Gets some feedback.") +@discord.option("name", description="Enter your name.") +async def feedback(ctx: discord.ApplicationContext, name: str): + try: + await ctx.respond(f"Hey, {name}! Send your feedback within the next 30 seconds please!") + + def is_author(m: discord.Message): + return m.author.id == ctx.author.id + + feedback_message = await bot.wait_for("message", check=is_author, timeout=30.0) + await ctx.send(f"Thanks for the feedback!\nReceived feedback: `{feedback_message.content}`") + except asyncio.TimeoutError: + await ctx.send("Timed out, please try again!") + + +bot.run("TOKEN") +``` + +If you respond within 30 seconds, the interaction will look like so: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Great bot! + + + Thanks for the feedback! +
+ Received feedback: Great bot! +
+
+
+ +Otherwise, if you don't respond in time, the interaction will go as follows: + + + +
+ + feedback + +
+ Hey, Dorukyum! Send your feedback within the next 30 seconds please! +
+ + Timed out, please try again! + +
+
+ +This basic method of error handling can be extended to handle +many other errors including ones raised directly by py-cord. + +## Per-Command Handling + +This type of error handling allows you to handle errors per each command you have on your bot. +Each and every command can have it's own error handler made to handle specific errors that each command may raise! + +An example of per-command error handling is as follows: + +:::note Bridge Commands + +For these types of commands, it is recommended to utilize global error handling +until [the feature](https://github.com/Pycord-Development/pycord/issues/1388) is added. +::: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot(owner_id=...) # Your Discord user ID goes in owner_id + + +@bot.slash_command(description="A private command...") +@commands.is_owner() # This decorator will raise commands.NotOwner if the invoking user doesn't have the owner_id +async def secret(ctx: discord.ApplicationContext): + await ctx.respond(f"Hey {ctx.author.name}! This is a secret command!") + + +@secret.error +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.NotOwner): + await ctx.respond("Sorry, only the bot owner can use this command!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If your ID is registered as the owner ID, you'll get the following: + + + +
+ + secret + +
+ Hey Dorukyum! This is a secret command! +
+
+
+ +Any other user whose ID doesn't match the bot owner's will get the following: + + + +
+ + secret + +
+ Sorry, only the bot owner can use this command! +
+
+
+ +This local (per-command) error handler can also be used to handle the same types of errors that standard try-except +statements can handle. This is done by using the same method as above with the `isinstance` built-in function. + +## Per-Cog Handling + +Adding error handlers per-command can be quite the task in terms of work if you have a lot. If you have happened to +group your commands in cogs, then you're in luck! You can create an error handler that is specific to a cog and +handles all errors raised by commands inside that cog. + +Here's an example of a bot with a cog that implements its own error handling: + +```python title="./cogs/dm.py" +# This cog is for DM only commands! Sadly, we only have 1 command here right now... + +import discord +from discord.ext import commands + + +class DM(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.command() + @commands.dm_only() # This decorator will raise commands.PrivateMessageOnly if invoked in a guild context. + async def avatar(self, ctx: commands.Context): + embed = discord.Embed( + title="Avatar", + description=f"Here's your enlarged avatar, {ctx.author.name}!", + color=ctx.author.top_role.color + ) + embed.set_image(url=ctx.author.display_avatar.url) + await ctx.send(embed=embed, reference=ctx.message) + + async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): + if isinstance(error, commands.PrivateMessageOnly): + await ctx.send("Sorry, you can only use this in private messages!", reference=ctx.message) + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +def setup(bot: commands.Bot): + bot.add_cog(DM(bot)) +``` + +```python title="./main.py" +# This code requires the `message_content` privileged intent for prefixed commands. + +# This is the main file where we load the DM cog and run the bot. + +import discord +from discord.ext import commands + +intents = discord.Intents.default() +intents.message_content = True + +bot = commands.Bot(command_prefix=commands.when_mentioned_or("!")) +bot.load_extension("cogs.dm") +bot.run("TOKEN") +``` + +If you use this command in a DM context, you'll get the following: + + + + !avatar + + +
+ + !avatar + +
+ + Here's your enlarged avatar, BobDotCom! + +
+
+
+ +Otherwise, if used in a guild context: + + + + !avatar + + +
+ + !avatar + +
+ Sorry, you can only use this in private messages! +
+
+
+ +Per-cog error handling comes in very handy as you can relegate all of your error handling to a single function instead +of spreading it out across several per-command error handlers or inside the commands themselves. + +## Global Handling + +If separating your error handling is not how you would like to handle errors, then global error handling is the way to +go. This method of handling allows you to relegate all handling to a single function that resides within your bot +instance. + +A non-subclassed bot would implement this like so: + +```python title="./main.py" +import discord +from discord.ext import commands + +bot = discord.Bot() + + +@bot.slash_command(description="Get the bot's current latency!") +@commands.cooldown(1, 30, commands.BucketType.user) +# ^ This decorator allows one usage of the command every 30 seconds and raises commands.CommandOnCooldown if exceeded +async def ping(ctx: discord.ApplicationContext): + await ctx.respond(f"Pong! `{int(bot.latency*1000)} ms`.") + + +@bot.event +async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): + if isinstance(error, commands.CommandOnCooldown): + await ctx.respond("This command is currently on cooldown!") + else: + raise error # Here we raise other errors to ensure they aren't ignored + + +bot.run("TOKEN") +``` + +If you've subclassed your bot, the `on_application_command_error` event will be placed inside the subclass without a +`bot.event` decorator and `bot.slash_command` will be replaced with `discord.slash_command`. + +The error handling used above will yield this interaction if the command is used again too quickly: + + + +
+ + ping + +
+ Pong! 49 ms. +
+ +
+ + ping + +
+ This command is currently on cooldown! +
+
+
+ +The only issue regarding global error handling is that, if you have a large amount of commands, the global handler may +start to get crammed with a lot of code. This is where all the previously mentioned handlers can take their place! + +## FAQ + +#### Why does the example in per-cog handling have self at the start of its function signatures? + +This is a feature of classes and allows you to reference the cog object as `self` and get access to the bot object +passed at initialization through `self.bot`. + +If this is new to you, we recommend checking out these helpful resources to learn more about classes and cogs: + +- [W3Schools' Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [Our Cogs Guide Page](./cogs) + +#### How many errors can I handle in a single error handler? + +While all the examples in this guide page only handle one specific error and re-raise all others, all of these +error handlers can be extended to catch many errors. + +In [basic handling](#basic) (i.e. try/except statements) you can do one of two things: + +- Explicitly handle the errors you know might get raised and then have a broad `except Exception as exc:` statement + as a catch-all. +- Catch any and all errors via the catch-all statement mentioned above. + +In [per-command](#percommand), [per-cog](#percog), and [global handling](#global), you can use elif clauses with the +built-in isinstance function to catch specific errors. Atop of this, an else clause can be used to catch any other +errors you either don't want to handle or want to relegate to a different error handler. + +#### Can I use more than one type of error handler at once? + +Thankfully, all of these different ways of error handling can be mixed together, so you don't have to pick just one! +For commands that raise specific errors that no other commands will raise, you can use [per-command](#percommand). +For cogs that raise specific errors that no other cogs will raise, use [per-cog](#percog)! Lastly, for errors that +occur frequently across all commands and cogs, use [global handling](#global)! + +However, one important note to remember is that you should always raise the error again in an error handler if it +isn't handled there! If you don't do this, the error will go ignored and your other handlers won't have a chance to +do their work! + +#### What's the difference between slash and prefixed command error handling? + +Although most examples shown here use slash commands, the [per-cog handling](#percog) section presents a prefixed +command. The main difference you may notice is the change in command signature. + +To make the distinguishing features apparent: + +- Slash commands use `on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException)` + as presented in the [per-command](#percommand) and [global handling](#global) examples. +- Prefixed commands use `on_command_error(ctx: commands.Context, error: commands.CommandError)` as presented in the + [per-cog handling](#percog) example. + +This distinction is made as both types of commands need their own system for handling errors that are specific to +themselves. + +:::info Related Topics + +- [Slash Commands](../interactions/application-commands/slash-commands) +- [Prefixed Commands](../extensions/commands/prefixed-commands) +- [Cogs](./cogs) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx new file mode 100644 index 00000000..9f4210af --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/intents.mdx @@ -0,0 +1,62 @@ +--- +title: Intents +description: All about intents in Discord. +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +## What are Intents? + +Intents allow bot developers to "subscribe" to specific events in Discord. This is useful for bots that need to respond to specific events, such as when a user joins a server or sends a message. You could choose to enable all intents or to enable only specific intents that your bot requires. + +## How do I enable intents? + +:::important + +Remember that [Privileged Intents](#what-are-privileged-intents) require you to enable them in the Discord Developer Portal. Verified Discord Bots that don't already have access to them will need to request Discord to allow access. + +::: + + + + +```python +import discord + +bot = discord.Bot(intents=discord.Intents.all()) +``` + + + + + +You can view a list of intents and the events they subscribe to [here](https://docs.pycord.dev/en/stable/api/data_classes.html#discord.Intents). + +```python title="Enabling Intents" +import discord + +bot = discord.Bot(intents=discord.intents.members(bans=True, guilds=True)) +``` + + + + +## What are Privileged Intents? + +Discord defines some intents as "privileged" because of the sensitive information they contain. Currently, there are three privileged intents: `members`, `presences`, and `message_content`. These intents must be enabled in your bot's Developer Portal. Once your bot reaches 100 servers, you will need to verify your bot for these intents to keep working and for your bot to be able to be invited to more guilds. + +:::tip + +Only enable these intents if you need them. These intents give your bot access to quite sensitive information about the users in your guild. These intents are privileged to respect the privacy of users, and you should do that as well. + +Not enabling these intents doesn't mean you won't be able to ban users, but you will be unable to detect when a new user joins a guild, or what game they are playing. The majority of bots won't need all intents. + +::: + +:::info Related Topics + +- [Sharding Bots](sharding) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx new file mode 100644 index 00000000..c3d17197 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/sharding.mdx @@ -0,0 +1,48 @@ +--- +title: Sharding +description: All about Sharding Discord Bots. +--- + +# Sharding + +## What is Sharding? + +Sharding is the process of breaking up your bot into smaller pieces so that it has a better time handling +events. As [Discord's Documentation](https://discord.com/developers/docs/topics/gateway#sharding) puts +it, sharding is "a method of user-controlled guild sharding which allows for splitting events across +several gateway connections." + +Sharding is used only for large bots and takes up additional resources for managing the new processes. +Pycord automatically shards your bot, so the only thing you need to do is use an `AutoShardedClient` +or `AutoShardedBot` class instead of a plain `Client` or `Bot` class. Pretty cool, right? + +Just because you _can_ shard your bot doesn't mean you _should_. While Pycord makes it easy to shard +your bot, it isn't necessary to shard unless your bot is large. Sharding a small bot isn't +just useless, but _harmful_, as it uses extra resources and may slow down your bot. Discord +themselves will let you know when your bot needs sharding, so you won't need to worry about this until they contact you. + +## How Do I Shard in Pycord? + +Sharding in Pycord is straightforward. + +Just replace your `discord.Client`, `discord.Bot`, `commands.Bot` objects +with `discord.AutoShardedClient`, `discord.AutoShardedBot`, `commands.AutoShardedBot` respectively. + +These new objects have been inherited from the original objects, so all the functions from those other types should be present. + +If you want to specify the number of shards your bot uses, +just add the `shards` parameter, along with the number of shards you want. + +## Why Should I Shard my Bot? + +Sharding is very necessary for big bots. While your bot grows, it gets harder for your bot to control +how many guilds it is in and what parts of your code should do what. This is exactly what sharding +handles, it makes all of this easier for your bot. Remember, though, only shard your bot once it's +big enough, and that's at _least_ 1,000 guilds. + +:::info Related Topics + +- [Hosting your Bot](../Getting-Started/hosting-your-bot) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx new file mode 100644 index 00000000..bd2969c1 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/subclassing-bots.mdx @@ -0,0 +1,115 @@ +--- +title: Subclassing Bots +description: Subclassing is a popular way of creating Discord Bots. Explore how you can create a Discord bot by subclassing. +--- + +## About + +Subclassing is another popular way of creating Discord Bots. Here, you create a bot by extending a bot class. To some advanced users, this is preferable to creating a bot instance with `bot = discord.Bot()`. + +Subclassing is an intermediate python concept, so we recommend you learn about it before continuing. Some good resources are: + +- [W3Schools's Guide to Python Classes & Objects](https://www.w3schools.com/python/python_classes.asp) +- [W3Schools's Guide to Python Inheritance](https://www.w3schools.com/python/python_inheritance.asp) + +## Why Subclassing? + +Many developers prefer to subclass their bots for many reasons, some of them being: + +#### Skeletal Frameworks for Bots + +Developers often share their bots code on open-source platforms, mostly GitHub, and allow users to self-host the bot (running their own instance of the bot with the code provided by the developer. Permissions vary in accordance to licences). Here, users find it easier and more convenient to have a small file that imports the custom bot class and runs it, rather than having to go through the code of the bot and find out which file to run. This makes it easier for people not familiar with programming to run and customize the bot, since it often brings down the code to: + +```python title="./main.py" +from src import Bot + +bot = Bot() + +bot.run("TOKEN") +``` + +Here, all the commands are inside the `/src` folder that the user need not bother with. + +#### Running Multiple Instances + +Some developers may need to run multiple instances of their bot (perhaps on different bot accounts). For example, a developer might have a second bot for testing alpha features. This system makes it simpler for the developer, and allows them to maintain multiple versions of the bot in the same directory: + +```python title="./alpha_bot.py" +from src import Bot + +class AlphaBot(Bot): # subclasses Bot + ... # insert any custom configuration + +bot = AlphaBot() + +@bot.slash_command() # adds a new slash command to this subclassed bot +async def alpha_feature(ctx): + await ctx.respond("Alpha Feature!") + +bot.run("TOKEN") +``` + +There are many more reasons to subclass! It's not required, and won't affect the speed of the bot, but it may affect your development process, for the good or for the worse. You don't miss out on any features when you subclass, either. Some developers want the OOP feel, while some just prefer that method and find it easier. + +## Basic Example + +```python +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override the on_ready event + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') + +bot = MyBot() + +@bot.slash_command() # create a slash command +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run('token') +``` + +As you can see, instead of creating a bot object with `bot = discord.Bot()`, we subclass [`discord.Bot`](https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot). We then create an instance of our new bot class and run it. Notice how we don't need to use the `@event` decorator. + +Here's another example: + +```python title="./src/bot.py" +import discord + +class MyBot(discord.Bot): # subclass discord.Bot + async def on_ready(self): # override on_ready + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') +``` + +```python title="./src/\_\_init\_\_.py" +from .bot import MyBot # import the MyBot class from the bot.py file +``` + +```python title="./main.py" +from src import MyBot # import MyBot from /src + +bot = MyBot() # create an instance of MyBot + +@bot.slash_command() +async def ping(ctx): + await ctx.respond('Pong!') + +bot.run("TOKEN") # run the bot +``` + +These are just two ways you could do it. There are ton of other structures you can implement. It's up to you. + +So, should you subclass? There are no limitations you face if you decide to subclass your bot, but, once again, it's up to you. + +:::info Related Topics + +- [Making a Help Command](../Extensions/Commands/help-command) +- [Rules and Common Practices](../Getting-Started/rules-and-common-practices) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx new file mode 100644 index 00000000..23220b0e --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/popular-topics/threads.mdx @@ -0,0 +1,105 @@ +--- +title: Threads +description: Threads with Pycord +--- + +In programming, threads are a way to run multiple processes at the same time. In Discord, threads are +a way to keep multiple conversations going at the same time. Let's take a brief look at how to use threads in Pycord. + +:::tip + +Not all the methods and attributes will be covered in this guide, but you can find them in our documentation! +[Check it out!](https://docs.pycord.dev/en/stable/api/models.html#discord.Thread) + +::: + +## Creating a thread + +With a few simple lines of code, we can create threads in Pycord. + +:::important + +All public threads need a starting message. This message will start the thread. However, private threads +(which are unlocked with having your server boosted to Level 2), do not require a starting message. + +::: + +### Creating thread from a message + +```python title="Creating a Thread from a Message" +message = await ctx.send("My Starting Message") +await message.create_thread(name="thread name", auto_archive_duration=60) +``` + +You may also use other ways to create the thread, for example, by using `on_message` events or by commands. + +### Creating thread in a channel + +```python title="Creating a Thread from a Channel" +channel = bot.get_channel(...) # define this! +await channel.create_thread(name="Thread Name", message=None, auto_archive_duration=60, type=None, reason=None) +``` + +A thread type could be `news_thread`, `public_thread`, `private_thread`. You may use it by passing `type=discord.ChannelType.news_thread`. + +## Deleting Threads + +Deleting Threads is simple. You need to get a thread and then use the `delete` method. + +```python title="Deleting a Thread" +thread = bot.get_channel(thread_id) # you could use other ways to get a thread +await thread.delete() +``` + +## Editing Threads + +**Parameters** + +- `name` (str) – The new name of the thread + +- `archived` (bool) – Whether to archive the thread or not. + +- `locked` (bool) – Whether to lock the thread or not. + +- `invitable` (bool) – Whether non-moderators can add other non-moderators to this thread. Only available for private threads. + +- `auto_archive_duration` (int) – The new duration in minutes before a thread gets automatically archived for inactivity. Must be one of 60, 1440, 4320, or 10080. + +- `slowmode_delay` (int) – Specifies the slow-mode rate limit for users in the thread, in seconds. A value of 0 disables slow-mode. The maximum value possible is 21600. + +```python title="Editing a Thread" +thread = bot.get_channel(id) +await thread.edit( + name="New Name", + archived=True, + locked=True, + slowmode_delay=10, + auto_archive_duration=60, +) +``` + +As you can see, threads are very simple. Once you learn how to use them, it's easy to create whatever you want. + +## FAQ + +### Why am I getting a `Forbidden` error when I try to create a thread? + +A `Forbidden` error occurs when the bot does not have the correct permissions to create threads. + +### Why am I getting an Unknown Message error when I try to create a thread? + +Getting an error looking something like `discord.ext.commands.errors.CommandInvokeError: Command +raised an exception: HTTPException: 400 Bad Request (error code: 10008): Unknown Message`? + +There could be multiple reasons, some of them being: + +- The message does not exist +- The message already has a thread +- The message is in channel x, you are trying to start a thread in channel y. +- The message was deleted. + +:::info Related Topics + +<>{/* I can't think of any related topics for this at the moment. */} + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/voice/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/voice/_category_.json new file mode 100644 index 00000000..8baf3da8 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/voice/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 6, + "label": "Voice" +} \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/voice/index.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/voice/index.mdx new file mode 100644 index 00000000..835838c6 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/voice/index.mdx @@ -0,0 +1,24 @@ +--- +title: Voice +--- + +Welcome to the guide for voice features in Pycord. + +:::caution +This guide requires previous experience with Pycord and Python. +::: + +## Requirements + +The only requirement which is required for voice features is [`PyNaCl`](https://pypi.org/project/PyNaCl/). +The following features are optional: + +:::tip +Opus is also a required library, but this comes with Pycord. +Some hosts may not come with it, though, so remember to always check if required dependencies are installed. +::: + +- [`FFmpeg`](https://ffmpeg.org) - used for sending/receiving files other than `.pcm` and `.wav` +- [`Pycord.Wavelink`](https://github.com/Pycord-Development/Pycord.Wavelink), + [`Lavalink.py`](https://github.com/Devoxin/Lavalink.py), + [`Wavelink`](https://github.com/PythonistaGuild/Wavelink) or any other Python LavaLink library for music playback. diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/voice/playing.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/voice/playing.mdx new file mode 100644 index 00000000..fe14c52a --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/voice/playing.mdx @@ -0,0 +1,149 @@ +--- +title: Wavelink Audio Player +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { + defaultOptions, +} from "@site/src/components/DiscordComponent"; + +# About + +Pycord and Wavelink try to keep the playing of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio playing feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/). + +## Starting out + +First you need to run a [Lavalink Server](https://github.com/freyacodes/Lavalink) to connect with. +There a multiple documentations to do this, so we are not covering that here. + +You also need to install the [wavelink](https://github.com/PythonistaGuild/Wavelink) library. + +```py title="Installing wavelink" +python3 -m pip install wavelink +``` + +You will now want to connect to your server via a node. + +```py title="Connect Node with Lavalink" +import discord +import wavelink + +bot = discord.Bot() + +async def connect_nodes(): + """Connect to our Lavalink nodes.""" + await bot.wait_until_ready() # wait until the bot is ready + + nodes = [ + wavelink.Node( + identifier="Node1", # This identifier must be unique for all the nodes you are going to use + uri="http://0.0.0.0:443", # Protocol (http/s) is required, port must be 443 as it is the one lavalink uses + password="youshallnotpass" + ) + ] + + await wavelink.Pool.connect(nodes=nodes, client=bot) # Connect our nodes +``` + +
+ +Now you are finished making your node! Next, you will want to: + +1. Making a play command +2. Adding connect events + +### Making a play command + +To make a play command, you will need to make a function to connect and play audio in a voice channel. + +```py title="Play Command Example" +import typing + +@bot.slash_command(name="play") +async def play(ctx, search: str): + # First we may define our voice client, + # for this, we are going to use typing.cast() + # function just for the type checker know that + # `ctx.voice_client` is going to be from type + # `wavelink.Player` + vc = typing.cast(wavelink.Player, ctx.voice_client) + + if not vc: # We firstly check if there is a voice client + vc = await ctx.author.voice.channel.connect(cls=wavelink.Player) # If there isn't, we connect it to the channel + + # Now we are going to check if the invoker of the command + # is in the same voice channel than the voice client, when defined. + # If not, we return an error message. + if ctx.author.voice.channel.id != vc.channel.id: + return await ctx.respond("You must be in the same voice channel as the bot.") + + # Now we search for the song. You can optionally + # pass the "source" keyword, of type "wavelink.TrackSource" + song = await wavelink.Playable.search(search) + + if not song: # In case the song is not found + return await ctx.respond("No song found.") # we return an error message + + await vc.play(song) # Else, we play it + await ctx.respond(f"Now playing: `{song.title}`") # and return a success message +``` + + + +
+ + play + +
+ Now playing: Never Gonna Give You Up +
+
+ +
+ +Now that you've done this, the only thing left to do is make your connect events. + +### Adding connect events + +The final step to this guide is connecting the node to your server when the bot goes online. + +To make it, you will want to do the following: + +```py title="Adding connect events" +@bot.event +async def on_ready(): + await connect_nodes() # connect to the server + +@bot.event +async def on_wavelink_node_ready(payload: wavelink.NodeReadyEventPayload): + # Everytime a node is successfully connected, we + # will print a message letting it know. + print(f"Node with ID {payload.session_id} has connected") + print(f"Resumed session: {payload.resumed}") + +bot.run("token") +``` + +Congratulations! You have now implemented voice playing into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/voice/receiving.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/voice/receiving.mdx new file mode 100644 index 00000000..1bc364e1 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/voice/receiving.mdx @@ -0,0 +1,130 @@ +--- +title: Receiving Voice Samples +--- + +import { + DiscordButton, + DiscordButtons, + DiscordInteraction, + DiscordMessage, + DiscordMessages, + DiscordMention, +} from "discord-message-components/packages/react"; +import "discord-message-components/packages/react/dist/style.css"; + +import DiscordComponent, { defaultOptions } from "@site/src/components/DiscordComponent"; + +# About + +Pycord tries to keep the recording of audio as simple and easy as possible, to keep making Discord +bots of any kind easy for all audiences. This guide provides simple and easy examples of using the +audio recording feature. + +For users that want extra examples, you can find some in Pycord's +[GitHub repository](https://github.com/Pycord-Development/pycord/blob/master/examples/audio_recording.py). + +## Starting out + +The first thing you want to do is make a cache of your voice connections. This is fairly easy; as +it's just putting a variable with an empty dictionary in our code, such as `connections = {}`. + +You will now want to create your command for recording. + +```py title="Record Command Example" +import discord + +bot = discord.Bot() +connections = {} + +@bot.command() +async def record(ctx): # If you're using commands.Bot, this will also work. + voice = ctx.author.voice + + if not voice: + await ctx.respond("You aren't in a voice channel!") + + vc = await voice.channel.connect() # Connect to the voice channel the author is in. + connections.update({ctx.guild.id: vc}) # Updating the cache with the guild and channel. + + vc.start_recording( + discord.sinks.WaveSink(), # The sink type to use. + once_done, # What to do once done. + ctx.channel # The channel to disconnect from. + ) + await ctx.respond("Started recording!") +``` + + + +
+ + record + +
+ Started recording! +
+
+ +
+ +Now you are finished making your command for voice receiving! Next, you will want to: + +1. Make your finished callback +2. Make a stop command + +### Making a Callback + +To make a callback, you will want to define the currently undefined `once_done` function inside +our command, like so: + +```py title="Recorder Callback" +async def once_done(sink: discord.sinks, channel: discord.TextChannel, *args): # Our voice client already passes these in. + recorded_users = [ # A list of recorded users + f"<@{user_id}>" + for user_id, audio in sink.audio_data.items() + ] + await sink.vc.disconnect() # Disconnect from the voice channel. + files = [discord.File(audio.file, f"{user_id}.{sink.encoding}") for user_id, audio in sink.audio_data.items()] # List down the files. + await channel.send(f"finished recording audio for: {', '.join(recorded_users)}.", files=files) # Send a message with the accumulated files. +``` + + + + finished recording audio for:{" "} + {defaultOptions.profiles.bob.author} + + + +
+ +Now that you've done this, the only thing left to do is make your stop command. + +### Making a Stop Command + +The final step to this guide is stopping the audio recording. This is the easiest step by far. + +To make it, you will want to do the following: + +```py title="Stop Recording Command" +@bot.command() +async def stop_recording(ctx): + if ctx.guild.id in connections: # Check if the guild is in the cache. + vc = connections[ctx.guild.id] + vc.stop_recording() # Stop recording, and call the callback (once_done). + del connections[ctx.guild.id] # Remove the guild from the cache. + await ctx.delete() # And delete. + else: + await ctx.respond("I am currently not recording here.") # Respond with this if we aren't recording. + +bot.run("token") +``` + +Congratulations! You have now implemented voice recording into your bot! Most bots and Discord API +wrappers don't have this as a feature, so this is quite an accomplishment. Thankfully, Pycord makes +it easy to make complex bots so that you can get even the most advanced of ideas down. + +:::info Related Topics + +- [Rules and Common Practices](../getting-started/rules-and-common-practices) + +::: diff --git a/i18n/zh/docusaurus-plugin-content-pagesindex.tsx b/i18n/zh/docusaurus-plugin-content-pagesindex.tsx new file mode 100644 index 00000000..84df3a9c --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-pagesindex.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import DefaultLayout from "../layouts/DefaultLayout"; +import PYCHero from "@site/src/components/PYCHero"; +import PYCButton from "@site/src/components/PYCButton"; + +export default function Home(): JSX.Element { + return ( + + +
+ Imagine a place where you can learn how to create an awesome Discord + bot, equip it with Pycord, and have it running in less than a minute. + Imagine a place where you can learn everything about Pycord. Imagine a + guide. A Pycord Guide! +

+ Whether you are a newbie or an experienced developer, you will find + everything you need to know about Pycord here. This guide will teach + you: +
    +
  • How to get a brand new bot running from scratch;
  • +
  • How to create Interactions, Context Menus and Commands;
  • +
  • In-depth concepts such as Embeds, Reactions, Help Commands, Paginators, etc;
  • +
  • Popular Topics such as working with Databases, Sharding, etc;
  • +
  • Ways to handle and manage common errors and best practices for bots;
  • +
  • And Much More!
  • +
+
+
+ ); +} diff --git a/i18n/zh/docusaurus-theme-classic/footer.json b/i18n/zh/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..ffb8a652 --- /dev/null +++ b/i18n/zh/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Pycord Development, All rights reserved.", + "description": "The footer copyright" + } +} diff --git a/i18n/zh/docusaurus-theme-classic/navbar.json b/i18n/zh/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..473b847e --- /dev/null +++ b/i18n/zh/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "Pycord Guide", + "description": "The title in the navbar" + }, + "item.label.Home": { + "message": "Home", + "description": "Navbar item with label Home" + }, + "item.label.Docs": { + "message": "Docs", + "description": "Navbar item with label Docs" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + }, + "item.label.Source": { + "message": "Source", + "description": "Navbar item with label Source" + } +} diff --git a/package.json b/package.json index 9e9ce1c0..facce394 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "guide.pycord.dev", - "version": "2.0.0-b5", + "version": "3.0.0", "description": "Imagine a place... where you can learn how to add more features to your Pycord bot", "private": true, "repository": "https://github.com/Pycord-Development/guide", @@ -9,6 +9,13 @@ "name": "Matteu", "email": "matteugt@gmail.com" }, + "contributors": [ + { + "name": "Lala Sabathil", + "email": "lala@pycord.dev", + "url": "https://github.com/Lulalaby" + } + ], "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start", @@ -20,41 +27,51 @@ "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", "typecheck": "tsc", - "postinstall": "yarn add react@17.0.2 --ignore-scripts", + "postinstall": "yarn add react@17.0.0 --ignore-scripts", "check": "remark docs/*.mdx docs/**/*.mdx docs/**/**/*.mdx docs/**/**/**/*.mdx --quiet --frail", - "format": "remark docs/*.mdx docs/**/*.mdx docs/**/**/*.mdx docs/**/**/**/*.mdx --quiet -o" + "format": "remark docs/*.mdx docs/**/*.mdx docs/**/**/*.mdx docs/**/**/**/*.mdx --quiet -o", + "crowdin:upload": "docusaurus write-translations && crowdin upload", + "crowdin:download": "crowdin download", + "crowdin:sync": "docusaurus write-translations && crowdin upload && crowdin download" }, "dependencies": { + "@algolia/client-search": "5.0.0", + "@crowdin/cli": "4.1.1", "@discordapp/twemoji": "discord/twemoji", - "@docusaurus/core": "2.4.1", - "@docusaurus/preset-classic": "2.4.1", - "@easyops-cn/docusaurus-search-local": "0.27.1", - "@matteusan/sentro": "0.1.25", + "@docusaurus/core": "^2.4.3", + "@docusaurus/mdx-loader": "2.4.3", + "@docusaurus/preset-classic": "^2.4.3", + "@docusaurus/theme-common": "^2.4.3", + "@easyops-cn/docusaurus-search-local": "^0.36.0", + "@matteusan/sentro": "1.1.0", "@mdx-js/react": "1.6.22", - "@types/react": "17.0.2", - "clsx": "2.0.0", + "@types/react": "17.0.0", + "babel-plugin-module-resolver": "5.0.2", + "clsx": "2.1.1", "discord-message-components": "https://gitpkg.now.sh/Pycord-Development/discord-message-components?aa468ada9b2b52986ae0aee4051660713c1e9095&scripts.postinstall=yarn%20install%20--ignore-scripts%20%26%26%20node%20node_modules%2Fesbuild%2Finstall.js%20%26%26yarn%20build%3Amarkdown%20%26%26%20yarn%20build%3Acore%20%26%26%20yarn%20build%3Areact%20%26%26", "docusaurus-plugin-sass": "0.2.5", - "prism-react-renderer": "1.3.5", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-twemoji": "^0.5.0", - "sass": "1.67.0", - "webpack": "^5.88.2", - "yarn": "^1.22.19" + "prism-react-renderer": "2.3.1", + "react": "17.0.0", + "react-dom": "17.0.0", + "react-loadable": "5.5.0", + "react-twemoji": "^0.6.0", + "sass": "1.77.8", + "search-insights": ">=1 <3", + "webpack": "^5.93.0", + "yarn": "^1.22.22" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.4.1", - "@tsconfig/docusaurus": "2.0.1", + "@docusaurus/module-type-aliases": "^2.4.3", + "@tsconfig/docusaurus": "2.0.3", "micromark-extension-mdx-md": "^2.0.0", - "remark-cli": "^11.0.0", + "remark-cli": "^12.0.1", "remark-comment": "^1.0.0", "remark-frontmatter": "^5.0.0", - "remark-gfm": "^3.0.1", - "remark-mdx": "^2.3.0", - "remark-preset-lint-consistent": "^5.1.2", - "remark-preset-lint-recommended": "^6.1.3", - "typescript": "5.2.2" + "remark-gfm": "^4.0.0", + "remark-mdx": "^3.0.1", + "remark-preset-lint-consistent": "^6.0.0", + "remark-preset-lint-recommended": "^7.0.0", + "typescript": "5.5.4" }, "resolutions": { "@types/react": "17.0.2" diff --git a/src/scss/infima/_overrides.scss b/src/scss/infima/_overrides.scss index b19cd4be..77f5a75e 100644 --- a/src/scss/infima/_overrides.scss +++ b/src/scss/infima/_overrides.scss @@ -1,142 +1,142 @@ -@use '~@matteusan/sentro'; - -@mixin init() { - .navbar { - height: 100%; - background-color: rgba(sentro.token-get-raw('surface'), 97%); - box-shadow: none; - // filter: blur(8px); - - .navbar__toggle { - color: #fff !important; - } - - .navbar__items { - display: flex; - gap: 0.5rem; - - .navbar__title { - font-family: sentro.token-get('title-family'); - font-size: sentro.px-to-rem(24px); - font-weight: sentro.token-get('title-weight'); - } - - .navbar__item { - @extend .pyc-button; - max-width: max-content !important; - font-weight: 400 !important; - - &:hover, - &:focus, - &:active { - --hs-button-ink: #fff; - } - - > span { - font-family: inherit; - font-size: inherit; - font-weight: inherit; - } - } - } - } - - .theme-doc-sidebar-container { - border-right: none !important; - } - - .theme-back-to-top-button { - --ifm-color-emphasis-200: #{sentro.token-get('blurple')} !important; - --ifm-color-emphasis-1000: #{sentro.token-get('blurple-ink')} !important; - - &:hover { - background-color: sentro.token-get('blurple-light') !important; - } - } - - .theme-edit-this-page { - padding: 0.5rem 0.3rem; - border-radius: sentro.token-get('radius-small'); - background-color: sentro.key-create('button-fill', rgba(0 0 0 / 0)); - color: sentro.key-create('button-ink', sentro.token-get('blurple')); - border: 1px solid sentro.key-create('button-border', rgba(0 0 0 / 0)); - @include sentro.prefix(transition, all 0.1s ease); - - &:hover, - &:focus { - @include sentro.key-bind('button-fill', rgba(sentro.token-get-raw('blurple'), 10%)); - @include sentro.key-bind('button-border', rgba(sentro.token-get-raw('blurple'), 1%)); - } - - &:active { - @include sentro.key-bind('button-fill', rgba(sentro.token-get-raw('blurple'), 20%)); - @include sentro.key-bind('button-ink', sentro.token-get('blurple-light')); - @include sentro.key-bind('button-border', rgba(sentro.token-get-raw('blurple'), 2%)); - } - } - - .menu { - padding: 1rem !important; - background-color: rgba(sentro.token-get-raw('surface'), 50%); - - .menu__list, - .menu__list-item { - .menu__link { - padding: 0.7rem 1rem; - border: 1px solid rgba(0 0 0 / 0); - @include sentro.prefix(transition, all 0.1s ease); - - &:hover, - &:focus { - outline: none; - border-color: sentro.token-get('blurple'); - } - - &--active { - background-color: sentro.token-get('blurple'); - color: sentro.token-get('blurple-ink') - } - } - - .menu__caret { - display: grid; - place-items: center; - } - - > * + * { - margin-top: 0.5rem; - } - - + ul { - > * + * { - margin-top: 0.5rem; - } - } - } - } - - .pagination-nav__link { - background-color: rgba(sentro.token-get-raw('blurple'), 0%); - border: 1px solid rgba(sentro.token-get-raw('blurple'), 0%); - @include sentro.prefix(transition, all 0.1s ease); - - &:hover { - background-color: rgba(sentro.token-get-raw('blurple'), 10%); - border: 1px solid rgba(sentro.token-get-raw('blurple'), 1%); - } - - &:active { - background-color: rgba(sentro.token-get-raw('blurple'), 20%); - border: 1px solid rgba(sentro.token-get-raw('blurple'), 7%); - } - - .pagination-nav__sublabel { - display: none !important; - } - } - - .footer { - --ifm-footer-background-color: #{sentro.token-get('surface')}; - --ifm-footer-color: #{sentro.token-get('surface-ink')}; - } -} +@use '~@matteusan/sentro'; + +@mixin init() { + .navbar { + height: 100%; + background-color: rgba(sentro.token-get-raw('surface'), 97%); + box-shadow: none; + // filter: blur(8px); + + .navbar__toggle { + color: #fff !important; + } + + .navbar__items { + display: flex; + gap: 0.5rem; + + .navbar__title { + font-family: sentro.token-get('title-family'); + font-size: sentro.to-rem(24px); + font-weight: sentro.token-get('title-weight'); + } + + .navbar__item { + @extend .pyc-button; + max-width: max-content !important; + font-weight: 400 !important; + + &:hover, + &:focus, + &:active { + --hs-button-ink: #fff; + } + + > span { + font-family: inherit; + font-size: inherit; + font-weight: inherit; + } + } + } + } + + .theme-doc-sidebar-container { + border-right: none !important; + } + + .theme-back-to-top-button { + --ifm-color-emphasis-200: #{sentro.token-get('blurple')} !important; + --ifm-color-emphasis-1000: #{sentro.token-get('blurple-ink')} !important; + + &:hover { + background-color: sentro.token-get('blurple-light') !important; + } + } + + .theme-edit-this-page { + padding: 0.5rem 0.3rem; + border-radius: sentro.token-get('radius-small'); + background-color: sentro.key-create('button-fill', rgba(0 0 0 / 0)); + color: sentro.key-create('button-ink', sentro.token-get('blurple')); + border: 1px solid sentro.key-create('button-border', rgba(0 0 0 / 0)); + @include sentro.prefix(transition, all 0.1s ease); + + &:hover, + &:focus { + @include sentro.key-bind('button-fill', rgba(sentro.token-get-raw('blurple'), 10%)); + @include sentro.key-bind('button-border', rgba(sentro.token-get-raw('blurple'), 1%)); + } + + &:active { + @include sentro.key-bind('button-fill', rgba(sentro.token-get-raw('blurple'), 20%)); + @include sentro.key-bind('button-ink', sentro.token-get('blurple-light')); + @include sentro.key-bind('button-border', rgba(sentro.token-get-raw('blurple'), 2%)); + } + } + + .menu { + padding: 1rem !important; + background-color: rgba(sentro.token-get-raw('surface'), 50%); + + .menu__list, + .menu__list-item { + .menu__link { + padding: 0.7rem 1rem; + border: 1px solid rgba(0 0 0 / 0); + @include sentro.prefix(transition, all 0.1s ease); + + &:hover, + &:focus { + outline: none; + border-color: sentro.token-get('blurple'); + } + + &--active { + background-color: sentro.token-get('blurple'); + color: sentro.token-get('blurple-ink') + } + } + + .menu__caret { + display: grid; + place-items: center; + } + + > * + * { + margin-top: 0.5rem; + } + + + ul { + > * + * { + margin-top: 0.5rem; + } + } + } + } + + .pagination-nav__link { + background-color: rgba(sentro.token-get-raw('blurple'), 0%); + border: 1px solid rgba(sentro.token-get-raw('blurple'), 0%); + @include sentro.prefix(transition, all 0.1s ease); + + &:hover { + background-color: rgba(sentro.token-get-raw('blurple'), 10%); + border: 1px solid rgba(sentro.token-get-raw('blurple'), 1%); + } + + &:active { + background-color: rgba(sentro.token-get-raw('blurple'), 20%); + border: 1px solid rgba(sentro.token-get-raw('blurple'), 7%); + } + + .pagination-nav__sublabel { + display: none !important; + } + } + + .footer { + --ifm-footer-background-color: #{sentro.token-get('surface')}; + --ifm-footer-color: #{sentro.token-get('surface-ink')}; + } +} diff --git a/src/scss/main.scss b/src/scss/main.scss index 85efe5ca..377b51c4 100644 --- a/src/scss/main.scss +++ b/src/scss/main.scss @@ -1,341 +1,343 @@ -@use '~@matteusan/sentro' with ($prefix: 'pyc', $context: 'theme'); -@use 'helpers'; - -@use 'modules/pyc-button'; -@use 'modules/pyc-hero'; -@use 'modules/pyc-icon'; -@use 'modules/pyc-user-card'; -@use 'modules/pyc-title-bar'; - -@use 'infima/overrides'; - -@import url('https://fonts.googleapis.com/css2?family=Saira:wght@700&display=swap'); -@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;700&display=swap'); - -:root { - color-scheme: dark; - @include sentro.token-config( - $blurple: ( - 'light': #909aff, - 'default': #5865f2, - 'dark': #2f3bbe, - 'ink': #fff - ), - $surface: ( - 'light': #33373a, - 'default': #23272a, - 'dark': #17181a, - 'ink': #fff - ), - $error: ( - 'default': #d93333, - 'ink': #fff - ), - $warning: ( - 'default': #ffa012, - 'ink': #000 - ), - $success: ( - 'default': #1ea33c, - 'ink': #fff - ), - $radius: ( - 'small': 0.3rem, - 'medium': 0.5rem, - 'large': 0.7rem - ), - $global: ( - 'family': ('Outfit', sans-serif), - 'weight': 300, - ), - $title: ( - 'family': ('Saira', monospace), - 'weight': 700 - ), - $subtitle: ( - 'family': ('Outfit', sans-serif), - 'weight': 700, - ), - $code: ( - 'family': ('Fira Code', monospace), - 'weight': 400 - ), - $discord: ( - 'font-primary': (Whitney, "Helvetica Neue", Helvetica, Arial, sans-serif), - 'font-display': (Ginto, "Helvetica Neue", Helvetica, Arial, sans-serif), - 'font-code': ( - Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", - "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace), - 'font-headline': (Ginto Nord, Ginto, "Helvetica Neue", Helvetica, Arial, sans-serif) - ) - ); - --ifm-color-primary: #5865f2; - --ifm-color-primary-dark: #3949f0; - --ifm-color-primary-darker: #2a3bee; - --ifm-color-primary-darkest: #1121d6; - --ifm-color-primary-light: #7781f4; - --ifm-color-primary-lighter: #868ff6; - --ifm-color-primary-lightest: #b4baf9; -} - -html { - font-family: sentro.token-get('global-family'); - font-weight: sentro.token-get('global-weight'); -} - -* { - margin: 0; - padding: 0; - color: inherit; - box-sizing: inherit; - - font-family: inherit; - font-weight: inherit; - - &::before, - &::after { - margin: 0; - padding: 0; - color: inherit; - box-sizing: inherit; - } -} - -h1, -h2, -h3 { - margin: 0; - font-family: sentro.token-get('title-family'); - font-weight: sentro.token-get('title-weight'); -} - -h4, -h5, -h6 { - margin: 0; - font-family: sentro.token-get('subtitle-family'); - font-weight: sentro.token-get('subtitle-weight'); -} - -a { - margin: 0; - text-decoration: none; - color: sentro.token-get('blurple'); - - &:hover { - text-decoration: none; - color: sentro.token-get('blurple-light'); - } -} - -code, -code * { - margin: 0; - font-family: sentro.token-get('code-family'); -} - -html { - width: 100%; - height: 100%; - font-size: 100%; - background-color: sentro.token-get('surface-dark'); - box-sizing: border-box; -} - -body { - background-color: sentro.token-get('surface-dark'); - color: sentro.token-get('surface-ink'); -} - -#__next { - height: 100%; - min-height: 100vh; - display: flex; - flex-flow: column nowrap; - justify-content: space-between; -} - -.content-wrap { - width: calc(100% - 30px); - max-width: 1077px; - margin: 0 auto; - padding: #{sentro.px-to-rem(81px)} 0 1.5rem 0; - - &--home-page { - width: calc(100% - 30px); - max-width: 1077px; - margin: 0 auto; - padding: 2rem 0 1.5rem 0; - } -} - -.features { - display: flex; - flex-flow: row wrap; - justify-content: center; - - .feature { - margin: 0 0.7rem; - color: rgba(#b4b4b4, 80%); - cursor: pointer; - border-bottom: 3px solid rgba(0 0 0 / 0); - @include sentro.prefix(transition, all 0.1s ease); - - &.active { - color: #fff; - border-color: #fff; - } - - &:hover, - &:focus { - color: #fff - } - } -} - -.call-to-action { - height: 25vh; - display: grid; - place-items: center; - margin: 2.3rem 0; - text-align: center; - - .call-to-action__buttons { - width: 100%; - display: flex; - justify-content: center; - gap: 0.5rem; - margin-top: 1rem; - } -} - -.grid { - display: grid; - grid-template-columns: repeat(1, 1fr); - grid-gap: 1rem; - - @include helpers.breakpoint('medium') { - grid-template-columns: repeat(2, 1fr); - } - - @include helpers.breakpoint('large') { - grid-template-columns: repeat(3, 1fr); - } -} - -.emoji { - -o-object-fit: contain; - object-fit: contain; - width: 1.375em; - height: 1.375em; - vertical-align: bottom; -} - -.emoji.jumboable { - height: 2.7em; - width: 2.7em; -} - -@font-face { - font-family: Whitney; - font-weight: 300; - src: url(/static/fonts/whitney/whitney300.woff) format('woff'); -} - -@font-face { - font-family: Whitney; - font-weight: 400; - src: url(/static/fonts/whitney/whitney400.woff) format('woff'); -} - -@font-face { - font-family: Whitney; - font-weight: 500; - src: url(/static/fonts/whitney/whitney500.woff) format('woff'); -} - -@font-face { - font-family: Whitney; - font-weight: 600; - src: url(/static/fonts/whitney/whitney600.woff) format('woff'); -} - -@font-face { - font-family: Whitney; - font-weight: 700; - src: url(/static/fonts/whitney/whitney700.woff) format('woff'); -} - -.discord-messages { - font-family: sentro.token-get('discord-font-primary') !important; - // TODO: Figure out why this is necessary, and remove it. - // We Should be able to remove everything below here, but for some reason it doesn't work without it. Also, some - // of it hasn't been added to the component package yet anyways so that needs to be done. - .discord-message { - .discord-author-info { - .discord-author-username { - letter-spacing: unset; - cursor: pointer; - } - &:not(.discord-interaction-author-info) .discord-author-username:hover { - text-decoration: underline; - } - .discord-author-bot-tag { - font-weight: 500; - - } - } - .discord-interaction { - .discord-interaction-reply { - cursor: pointer; - } - .discord-interaction-command { - cursor: default; - .discord-interaction-command-name { - font-weight: 500; - cursor: pointer; - } - } - .discord-interaction-context-menu { - .discord-interaction-command-name { - cursor: unset; - } - .discord-interaction-command-name:hover { - text-decoration: unset; - opacity: 0.65; - } - } - } - .discord-message-timestamp { - font-weight: 500; - cursor: default; - } - .discord-buttons .discord-button { - font-family: inherit; - } - font-weight: 400; - } -} - -@font-face{font-family:Ginto;font-weight:300;src:url(/static/fonts/ginto/ginto300.woff) format("woff")} -@font-face{font-family:Ginto;font-weight:400;src:url(/static/fonts/ginto/ginto400.woff) format("woff")} -@font-face{font-family:Ginto;font-weight:500;src:url(/static/fonts/ginto/ginto500.woff) format("woff")} -@font-face{font-family:Ginto;font-weight:600;src:url(/static/fonts/ginto/ginto600.woff) format("woff")} -@font-face{font-family:Ginto;font-weight:700;src:url(/static/fonts/ginto/ginto700.woff) format("woff")} -@font-face{font-family:Ginto;font-weight:300;font-style:italic;src:url(/static/fonts/ginto/ginto-italic300.woff) format("woff")} -@font-face{font-family:Ginto;font-weight:400;font-style:italic;src:url(/static/fonts/ginto/ginto-italic400.woff) format("woff")} -@font-face{font-family:Ginto;font-weight:500;font-style:italic;src:url(/static/fonts/ginto/ginto-italic500.woff) format("woff")} -@font-face{font-family:Ginto;font-weight:600;font-style:italic;src:url(/static/fonts/ginto/ginto-italic600.woff) format("woff")} -@font-face{font-family:Ginto;font-weight:700;font-style:italic;src:url(/static/fonts/ginto/ginto-italic700.woff) format("woff")} -@font-face{font-family:Ginto Nord;font-weight:500;src:url(/static/fonts/ginto-nord/ginto-nord500.woff2) format("woff2"),url(/static/fonts/ginto-nord/ginto-nord500.woff) format("woff")} -@font-face{font-family:Ginto Nord;font-weight:600;src:url(/static/fonts/ginto-nord/ginto-nord600.woff2) format("woff2"),url(/static/fonts/ginto-nord/ginto-nord600.woff) format("woff")} -@font-face{font-family:Ginto Nord;font-weight:700;src:url(/static/fonts/ginto-nord/ginto-nord700.woff2) format("woff2"),url(/static/fonts/ginto-nord/ginto-nord700.woff) format("woff")} - - -@include overrides.init(); - -@include pyc-button.init(); -@include pyc-hero.init(); -@include pyc-icon.init(); -@include pyc-user-card.init(); -@include pyc-title-bar.init(); +@use '~@matteusan/sentro' with ($prefix: 'pyc', $context: 'theme'); +@use 'helpers'; + +@use 'modules/pyc-button'; +@use 'modules/pyc-hero'; +@use 'modules/pyc-icon'; +@use 'modules/pyc-user-card'; +@use 'modules/pyc-title-bar'; + +@use 'infima/overrides'; + +@import url('https://fonts.googleapis.com/css2?family=Saira:wght@700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;700&display=swap'); + +:root { + color-scheme: dark; + @include sentro.token-config( + $blurple: ( + 'light': #909aff, + 'default': #5865f2, + 'dark': #2f3bbe, + 'ink': #fff + ), + $surface: ( + 'light': #33373a, + 'default': #23272a, + 'dark': #17181a, + 'ink': #fff + ), + $error: ( + 'default': #d93333, + 'ink': #fff + ), + $warning: ( + 'default': #ffa012, + 'ink': #000 + ), + $success: ( + 'default': #1ea33c, + 'ink': #fff + ), + $radius: ( + 'small': 0.3rem, + 'medium': 0.5rem, + 'large': 0.7rem + ), + $global: ( + 'family': ('Outfit', sans-serif), + 'weight': 300, + ), + $title: ( + 'family': ('Saira', monospace), + 'weight': 700 + ), + $subtitle: ( + 'family': ('Outfit', sans-serif), + 'weight': 700, + ), + $code: ( + 'family': ('Fira Code', monospace), + 'weight': 400 + ), + $discord: ( + 'font-primary': (Whitney, "Helvetica Neue", Helvetica, Arial, sans-serif), + 'font-display': (Ginto, "Helvetica Neue", Helvetica, Arial, sans-serif), + 'font-code': ( + Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", + "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace), + 'font-headline': (Ginto Nord, Ginto, "Helvetica Neue", Helvetica, Arial, sans-serif) + ) + ); + --ifm-color-primary: #5865f2; + --ifm-color-primary-dark: #3949f0; + --ifm-color-primary-darker: #2a3bee; + --ifm-color-primary-darkest: #1121d6; + --ifm-color-primary-light: #7781f4; + --ifm-color-primary-lighter: #868ff6; + --ifm-color-primary-lightest: #b4baf9; +} + +html { + font-family: sentro.token-get('global-family'); + font-weight: sentro.token-get('global-weight'); +} + +* { + margin: 0; + padding: 0; + color: inherit; + box-sizing: inherit; + + font-family: inherit; + font-weight: inherit; + + &::before, + &::after { + margin: 0; + padding: 0; + color: inherit; + box-sizing: inherit; + } +} + +h1, +h2, +h3 { + margin: 0; + font-family: sentro.token-get('title-family'); + font-weight: sentro.token-get('title-weight'); +} + +h4, +h5, +h6 { + margin: 0; + font-family: sentro.token-get('subtitle-family'); + font-weight: sentro.token-get('subtitle-weight'); +} + +a { + margin: 0; + text-decoration: none; + color: sentro.token-get('blurple'); + + &:hover { + text-decoration: none; + color: sentro.token-get('blurple-light'); + } +} + +code, +code * { + margin: 0; + font-family: sentro.token-get('code-family'); +} + +html { + width: 100%; + height: 100%; + font-size: 100%; + background-color: sentro.token-get('surface-dark'); + box-sizing: border-box; +} + +body { + background-color: sentro.token-get('surface-dark'); + color: sentro.token-get('surface-ink'); +} + +#__next { + height: 100%; + min-height: 100vh; + display: flex; + flex-flow: column nowrap; + justify-content: space-between; +} + +.content-wrap { + width: calc(100% - 30px); + max-width: 1077px; + margin: 0 auto; + padding: #{sentro.to-rem(81px)} 0 1.5rem 0; + + &--home-page { + width: calc(100% - 30px); + max-width: 1077px; + margin: 0 auto; + padding: 2rem 0 1.5rem 0; + } +} + +.features { + display: flex; + flex-flow: row wrap; + justify-content: center; + + .feature { + margin: 0 0.7rem; + color: rgba(#b4b4b4, 80%); + cursor: pointer; + border-bottom: 3px solid rgba(0 0 0 / 0); + @include sentro.prefix(transition, all 0.1s ease); + + &.active { + color: #fff; + border-color: #fff; + } + + &:hover, + &:focus { + color: #fff + } + } +} + +.call-to-action { + height: 25vh; + display: grid; + place-items: center; + margin: 2.3rem 0; + text-align: center; + + .call-to-action__buttons { + width: 100%; + display: flex; + justify-content: center; + gap: 0.5rem; + margin-top: 1rem; + } +} + +.grid { + display: grid; + grid-template-columns: repeat(1, 1fr); + grid-gap: 1rem; + + @include helpers.breakpoint('medium') { + grid-template-columns: repeat(2, 1fr); + } + + @include helpers.breakpoint('large') { + grid-template-columns: repeat(3, 1fr); + } +} + +.emoji { + -o-object-fit: contain; + object-fit: contain; + width: 1.375em; + height: 1.375em; + vertical-align: bottom; +} + +.emoji.jumboable { + height: 2.7em; + width: 2.7em; +} + +@font-face { + font-family: Whitney; + font-weight: 300; + src: url(/static/fonts/whitney/whitney300.woff) format('woff'); +} + +@font-face { + font-family: Whitney; + font-weight: 400; + src: url(/static/fonts/whitney/whitney400.woff) format('woff'); +} + +@font-face { + font-family: Whitney; + font-weight: 500; + src: url(/static/fonts/whitney/whitney500.woff) format('woff'); +} + +@font-face { + font-family: Whitney; + font-weight: 600; + src: url(/static/fonts/whitney/whitney600.woff) format('woff'); +} + +@font-face { + font-family: Whitney; + font-weight: 700; + src: url(/static/fonts/whitney/whitney700.woff) format('woff'); +} + +.discord-messages { + font-family: sentro.token-get('discord-font-primary') !important; + // TODO: Figure out why this is necessary, and remove it. + // We Should be able to remove everything below here, but for some reason it doesn't work without it. Also, some + // of it hasn't been added to the component package yet anyways so that needs to be done. + .discord-message { + .discord-author-info { + .discord-author-username { + letter-spacing: unset; + cursor: pointer; + } + &:not(.discord-interaction-author-info) .discord-author-username:hover { + text-decoration: underline; + } + .discord-author-bot-tag { + font-weight: 500; + + } + } + .discord-interaction { + .discord-interaction-reply { + cursor: pointer; + } + .discord-interaction-command { + cursor: default; + .discord-interaction-command-name { + font-weight: 500; + cursor: pointer; + } + } + .discord-interaction-context-menu { + .discord-interaction-command-name { + cursor: unset; + } + .discord-interaction-command-name:hover { + text-decoration: unset; + opacity: 0.65; + } + } + } + .discord-message-timestamp { + font-weight: 500; + cursor: default; + } + .discord-buttons .discord-button { + font-family: inherit; + } + & { + font-weight: 400; + } + } +} + +@font-face{font-family:Ginto;font-weight:300;src:url(/static/fonts/ginto/ginto300.woff) format("woff")} +@font-face{font-family:Ginto;font-weight:400;src:url(/static/fonts/ginto/ginto400.woff) format("woff")} +@font-face{font-family:Ginto;font-weight:500;src:url(/static/fonts/ginto/ginto500.woff) format("woff")} +@font-face{font-family:Ginto;font-weight:600;src:url(/static/fonts/ginto/ginto600.woff) format("woff")} +@font-face{font-family:Ginto;font-weight:700;src:url(/static/fonts/ginto/ginto700.woff) format("woff")} +@font-face{font-family:Ginto;font-weight:300;font-style:italic;src:url(/static/fonts/ginto/ginto-italic300.woff) format("woff")} +@font-face{font-family:Ginto;font-weight:400;font-style:italic;src:url(/static/fonts/ginto/ginto-italic400.woff) format("woff")} +@font-face{font-family:Ginto;font-weight:500;font-style:italic;src:url(/static/fonts/ginto/ginto-italic500.woff) format("woff")} +@font-face{font-family:Ginto;font-weight:600;font-style:italic;src:url(/static/fonts/ginto/ginto-italic600.woff) format("woff")} +@font-face{font-family:Ginto;font-weight:700;font-style:italic;src:url(/static/fonts/ginto/ginto-italic700.woff) format("woff")} +@font-face{font-family:Ginto Nord;font-weight:500;src:url(/static/fonts/ginto-nord/ginto-nord500.woff2) format("woff2"),url(/static/fonts/ginto-nord/ginto-nord500.woff) format("woff")} +@font-face{font-family:Ginto Nord;font-weight:600;src:url(/static/fonts/ginto-nord/ginto-nord600.woff2) format("woff2"),url(/static/fonts/ginto-nord/ginto-nord600.woff) format("woff")} +@font-face{font-family:Ginto Nord;font-weight:700;src:url(/static/fonts/ginto-nord/ginto-nord700.woff2) format("woff2"),url(/static/fonts/ginto-nord/ginto-nord700.woff) format("woff")} + + +@include overrides.init(); + +@include pyc-button.init(); +@include pyc-hero.init(); +@include pyc-icon.init(); +@include pyc-user-card.init(); +@include pyc-title-bar.init(); diff --git a/src/scss/modules/_pyc-button.scss b/src/scss/modules/_pyc-button.scss index ada68980..a8f40163 100644 --- a/src/scss/modules/_pyc-button.scss +++ b/src/scss/modules/_pyc-button.scss @@ -1,144 +1,149 @@ -@use '~@matteusan/sentro'; -@use '../helpers'; - -@mixin init($color: 'blurple') { - .pyc-button { - width: 100%; - min-width: 57px; - max-width: max-content; - display: inline-flex; - flex-flow: row nowrap; - justify-content: center; - align-items: center; - padding: 0.4rem 0.6rem; - font-size: clamp(#{sentro.px-to-rem(16px)}, 7vw, #{sentro.px-to-rem(18px)}); - font-weight: 700; - border-radius: sentro.token-get('radius-small'); - cursor: pointer; - user-select: none; - @include sentro.prefix(transition, all 0.1s ease); - - & > * + * { - margin-left: 0.5rem; - } - - @include _text($color); - - &.pyc-button--inverted { - @include _text('surface'); - } - - &.pyc-button--outlined { - @include _outlined($color); - - &.pyc-button--inverted { - @include _outlined('surface'); - } - } - - &.pyc-button--filled { - @include _filled($color); - - &.pyc-button--inverted { - @include _filled('surface'); - } - } - - .pyc-button__icon { - display: grid; - place-items: center; - font-size: sentro.px-to-rem(24px); - vertical-align: center; - - > svg { - vertical-align: center; - width: sentro.px-to-rem(24px); - height: sentro.px-to-rem(24px); - size: sentro.px-to-rem(24px); - } - } - - .pyc-button__label { - font-size: inherit; - font-weight: inherit; - text-align: center; - } - } -} - -@mixin _text($color: 'blurple') { - background-color: sentro.key-create('button-fill', rgba(0 0 0 / 0)); - color: sentro.key-create('button-ink', sentro.token-get('#{$color}')); - border: 1px solid sentro.key-create('button-border', rgba(0 0 0 / 0)); - - &:hover, - &:focus { - @include sentro.key-bind('button-fill', rgba(sentro.token-get-raw('#{$color}'), 10%)); - @include sentro.key-bind('button-border', rgba(sentro.token-get-raw('#{$color}'), 1%)); - } - - &:active { - @include sentro.key-bind('button-fill', rgba(sentro.token-get-raw('#{$color}'), 20%)); - @include sentro.key-bind('button-ink', sentro.token-get('#{$color}-light')); - @include sentro.key-bind('button-border', rgba(sentro.token-get-raw('#{$color}'), 2%)); - } - - &:disabled { - @include sentro.key-bind('button-ink', sentro.token-get('#{$color}-dark')); - @include sentro.key-bind('button-border', sentro.token-get('#{$color}-dark')); - } -} - -@mixin _outlined($color: 'blurple') { - background-color: sentro.key-create('button-fill', rgba(0 0 0 / 0)); - color: sentro.key-create('button-ink', sentro.token-get('#{$color}-ink')); - border: 1px solid sentro.key-create('button-border', sentro.token-get('#{$color}')); - - &:focus { - @include sentro.key-bind('button-fill', rgba(#fff, 10%)); - @include sentro.key-bind('button-border', sentro.token-get('#{$color}')); - } - - &:hover { - @include sentro.key-bind('button-fill', sentro.token-get('#{$color}')); - @include sentro.key-bind('button-border', sentro.token-get('#{$color}')); - } - - &:active { - @include sentro.key-bind('button-fill', sentro.token-get('#{$color}-light')); - @include sentro.key-bind('button-ink', sentro.token-get('#{$color}-ink')); - @include sentro.key-bind('button-border', sentro.token-get('#{$color}-light') !important); - } - - &:disabled { - @include sentro.key-bind('button-ink', sentro.token-get('#{$color}-dark')); - @include sentro.key-bind('button-border', sentro.token-get('#{$color}-dark')); - } -} - -@mixin _filled($color: 'blurple') { - background-color: sentro.key-create('button-fill', sentro.token-get('#{$color}')); - color: sentro.key-create('button-ink', sentro.token-get('#{$color}-ink')); - border: 1px solid sentro.key-create('button-border', sentro.token-get('#{$color}')); - - &:hover { - @include sentro.key-bind('button-fill', sentro.token-get('#{$color}')); - @include sentro.key-bind('button-border', sentro.token-get('#{$color}')); - } - - &:focus { - @include sentro.key-bind('button-fill', sentro.token-get('#{$color}')); - @include sentro.key-bind('button-border', sentro.token-get('#{$color}')); - } - - &:active { - @include sentro.key-bind('button-fill', sentro.token-get('#{$color}-light')); - @include sentro.key-bind('button-ink', sentro.token-get('#{$color}-ink')); - @include sentro.key-bind('button-border', sentro.token-get('#{$color}-light')); - } - - &:disabled { - @include sentro.key-bind('button-fill', sentro.token-get('#{$color}-dark')); - @include sentro.key-bind('button-border', sentro.token-get('#{$color}-dark')); - } -} +@use '~@matteusan/sentro'; +@use '../helpers'; + +@mixin init($color: 'blurple') { + .pyc-button { + width: 100%; + min-width: 57px; + max-width: max-content; + display: inline-flex; + flex-flow: row nowrap; + justify-content: center; + align-items: center; + padding: 0.4rem 0.6rem; + font-size: clamp(#{sentro.to-rem(16px)}, 7vw, #{sentro.to-rem(18px)}); + font-weight: 700; + border-radius: sentro.token-get('radius-small'); + cursor: pointer; + -webkit-user-select: none; + user-select: none; + @include sentro.prefix(transition, all 0.1s ease); + + & > * + * { + margin-left: 0.5rem; + } + + @include _text($color); + + &.pyc-button--inverted { + @include _text('surface'); + } + + &.pyc-button--outlined { + @include _outlined($color); + + &.pyc-button--inverted { + @include _outlined('surface'); + } + } + + &.pyc-button--filled { + @include _filled($color); + + &.pyc-button--inverted { + @include _filled('surface'); + } + } + + .pyc-button__icon { + display: grid; + place-items: center; + font-size: sentro.to-rem(24px); + vertical-align: center; + + > svg { + vertical-align: center; + width: sentro.to-rem(24px); + height: sentro.to-rem(24px); + size: sentro.to-rem(24px); + } + } + + .pyc-button__label { + font-size: inherit; + font-weight: inherit; + text-align: center; + } + } +} + +@mixin _text($color: 'blurple') { + & { + background-color: sentro.key-create('button-fill', rgba(0 0 0 / 0)); + color: sentro.key-create('button-ink', sentro.token-get('#{$color}')); + border: 1px solid sentro.key-create('button-border', rgba(0 0 0 / 0)); + } + + &:hover, + &:focus { + @include sentro.key-bind('button-fill', rgba(sentro.token-get-raw('#{$color}'), 10%)); + @include sentro.key-bind('button-border', rgba(sentro.token-get-raw('#{$color}'), 1%)); + } + + &:active { + @include sentro.key-bind('button-fill', rgba(sentro.token-get-raw('#{$color}'), 20%)); + @include sentro.key-bind('button-ink', sentro.token-get('#{$color}-light')); + @include sentro.key-bind('button-border', rgba(sentro.token-get-raw('#{$color}'), 2%)); + } + + &:disabled { + @include sentro.key-bind('button-ink', sentro.token-get('#{$color}-dark')); + @include sentro.key-bind('button-border', sentro.token-get('#{$color}-dark')); + } +} + +@mixin _outlined($color: 'blurple') { + & { + background-color: sentro.key-create('button-fill', rgba(0 0 0 / 0)); + color: sentro.key-create('button-ink', sentro.token-get('#{$color}-ink')); + border: 1px solid sentro.key-create('button-border', sentro.token-get('#{$color}')); + } + + &:focus { + @include sentro.key-bind('button-fill', rgba(#fff, 10%)); + @include sentro.key-bind('button-border', sentro.token-get('#{$color}')); + } + + &:hover { + @include sentro.key-bind('button-fill', sentro.token-get('#{$color}')); + @include sentro.key-bind('button-border', sentro.token-get('#{$color}')); + } + + &:active { + @include sentro.key-bind('button-fill', sentro.token-get('#{$color}-light')); + @include sentro.key-bind('button-ink', sentro.token-get('#{$color}-ink')); + @include sentro.key-bind('button-border', sentro.token-get('#{$color}-light') !important); + } + + &:disabled { + @include sentro.key-bind('button-ink', sentro.token-get('#{$color}-dark')); + @include sentro.key-bind('button-border', sentro.token-get('#{$color}-dark')); + } +} + +@mixin _filled($color: 'blurple') { + &{background-color: sentro.key-create('button-fill', sentro.token-get('#{$color}')); + color: sentro.key-create('button-ink', sentro.token-get('#{$color}-ink')); + border: 1px solid sentro.key-create('button-border', sentro.token-get('#{$color}'));} + + &:hover { + @include sentro.key-bind('button-fill', sentro.token-get('#{$color}')); + @include sentro.key-bind('button-border', sentro.token-get('#{$color}')); + } + + &:focus { + @include sentro.key-bind('button-fill', sentro.token-get('#{$color}')); + @include sentro.key-bind('button-border', sentro.token-get('#{$color}')); + } + + &:active { + @include sentro.key-bind('button-fill', sentro.token-get('#{$color}-light')); + @include sentro.key-bind('button-ink', sentro.token-get('#{$color}-ink')); + @include sentro.key-bind('button-border', sentro.token-get('#{$color}-light')); + } + + &:disabled { + @include sentro.key-bind('button-fill', sentro.token-get('#{$color}-dark')); + @include sentro.key-bind('button-border', sentro.token-get('#{$color}-dark')); + } +} diff --git a/src/scss/modules/_pyc-hero.scss b/src/scss/modules/_pyc-hero.scss index 1cf0641d..9d249973 100644 --- a/src/scss/modules/_pyc-hero.scss +++ b/src/scss/modules/_pyc-hero.scss @@ -1,82 +1,82 @@ -@use '~@matteusan/sentro'; -@use '../helpers'; - -@mixin init() { - .pyc-hero { - min-height: 47vh; - display: flex; - justify-content: center; - align-items: center; - padding: 5rem 1rem 3rem 1rem; - background: linear-gradient(25deg, #{sentro.token-get('blurple-dark')} 0%, #{sentro.token-get('blurple-light')} 100%); - color: sentro.token-get('blurple-ink'); - - .pyc-hero__wrap { - display: grid; - place-items: center; - width: calc(100% - 40px); - max-width: 1077px; - margin: 0 auto; - - img { - width: 100px; - height: auto; - margin-bottom: 0.7rem; - user-select: none; - } - - h1 { - text-align: center; - font-size: clamp(#{sentro.px-to-rem(28px)}, 10vw, #{sentro.px-to-rem(34px)}); - } - - .pyc-hero__subtitle { - text-align: center; - font-size: clamp(#{sentro.px-to-rem(16px)}, 5.3vw, #{sentro.px-to-rem(18px)}); - font-weight: 300; - font-family: sentro.token-get('subtitle-family'); - } - - .pyc-hero__actions { - width: 100%; - display: flex; - flex-flow: row nowrap; - justify-content: center; - margin-top: 1rem; - - .pyc-code-block { - width: 100%; - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.8rem; - background-color: sentro.token-get('surface'); - color: sentro.token-get('surface-ink'); - border-radius: sentro.token-get('radius-small'); - user-select: text; - - code { - font-size: sentro.px-to-rem(16px); - font-family: sentro.token-get('code-family'); - white-space: nowrap; - - &::before { - content: '$'; - margin-right: 0.7rem; - } - } - - .pyc-button { - min-width: auto; - margin: 0 0.3rem; - padding: 0.3rem; - - .pyc-button__icon { - font-size: sentro.px-to-rem(16px); - } - } - } - } - } - } -} +@use '~@matteusan/sentro'; +@use '../helpers'; + +@mixin init() { + .pyc-hero { + min-height: 47vh; + display: flex; + justify-content: center; + align-items: center; + padding: 5rem 1rem 3rem 1rem; + background: linear-gradient(25deg, #{sentro.token-get('blurple-dark')} 0%, #{sentro.token-get('blurple-light')} 100%); + color: sentro.token-get('blurple-ink'); + + .pyc-hero__wrap { + display: grid; + place-items: center; + width: calc(100% - 40px); + max-width: 1077px; + margin: 0 auto; + + img { + width: 100px; + height: auto; + margin-bottom: 0.7rem; + user-select: none; + } + + h1 { + text-align: center; + font-size: clamp(#{sentro.to-rem(28px)}, 10vw, #{sentro.to-rem(34px)}); + } + + .pyc-hero__subtitle { + text-align: center; + font-size: clamp(#{sentro.to-rem(16px)}, 5.3vw, #{sentro.to-rem(18px)}); + font-weight: 300; + font-family: sentro.token-get('subtitle-family'); + } + + .pyc-hero__actions { + width: 100%; + display: flex; + flex-flow: row nowrap; + justify-content: center; + margin-top: 1rem; + + .pyc-code-block { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.8rem; + background-color: sentro.token-get('surface'); + color: sentro.token-get('surface-ink'); + border-radius: sentro.token-get('radius-small'); + user-select: text; + + code { + font-size: sentro.to-rem(16px); + font-family: sentro.token-get('code-family'); + white-space: nowrap; + + &::before { + content: '$'; + margin-right: 0.7rem; + } + } + + .pyc-button { + min-width: auto; + margin: 0 0.3rem; + padding: 0.3rem; + + .pyc-button__icon { + font-size: sentro.to-rem(16px); + } + } + } + } + } + } +} diff --git a/src/scss/modules/_pyc-title-bar.scss b/src/scss/modules/_pyc-title-bar.scss index 14c2694c..56ada531 100644 --- a/src/scss/modules/_pyc-title-bar.scss +++ b/src/scss/modules/_pyc-title-bar.scss @@ -1,31 +1,31 @@ -@use '~@matteusan/sentro'; - -@mixin init() { - .pyc-title-bar { - display: flex; - flex-flow: row nowrap; - align-items: center; - - > * + * { - margin-left: 0.5rem; - } - - .pyc-title-bar__icon { - display: grid; - place-items: center; - font-size: sentro.px-to-rem(30px); - color: sentro.token-get('blurple'); - user-select: none; - - > svg { - width: sentro.px-to-rem(30px); - height: sentro.px-to-rem(30px); - } - } - - .pyc-title-bar__title { - font-size: sentro.px-to-rem(28px); - line-height: sentro.px-to-rem(50px); - } - } -} +@use '~@matteusan/sentro'; + +@mixin init() { + .pyc-title-bar { + display: flex; + flex-flow: row nowrap; + align-items: center; + + > * + * { + margin-left: 0.5rem; + } + + .pyc-title-bar__icon { + display: grid; + place-items: center; + font-size: sentro.to-rem(30px); + color: sentro.token-get('blurple'); + user-select: none; + + > svg { + width: sentro.to-rem(30px); + height: sentro.to-rem(30px); + } + } + + .pyc-title-bar__title { + font-size: sentro.to-rem(28px); + line-height: sentro.to-rem(50px); + } + } +} diff --git a/src/scss/modules/_pyc-user-card.scss b/src/scss/modules/_pyc-user-card.scss index 541eb412..e646a888 100644 --- a/src/scss/modules/_pyc-user-card.scss +++ b/src/scss/modules/_pyc-user-card.scss @@ -1,99 +1,102 @@ -@use '~@matteusan/sentro'; - -$img-size: 100px; - -@mixin init() { - .pyc-user-card__section { - margin-bottom: 2rem; - - .pyc-user-card { - width: 100%; - padding: 1rem; - background: sentro.token-get('surface'); - border-radius: sentro.token-get('radius-medium'); - display: flex; - flex-direction: column; - @include sentro.elevation-apply(3); - - .pyc-user-card__wrap { - display: grid; - grid-template-columns: $img-size 1fr; - grid-gap: 0.7rem; - - .pyc-user-card__img { - width: $img-size; - height: $img-size; - position: relative; - display: grid; - place-items: center; - overflow: hidden; - border-radius: 50%; - border: 2px solid sentro.token-get('blurple'); - background-color: sentro.token-get('blurple'); // Prevents gap between image and border - user-select: none; - @include sentro.prefix(transition, all 0.1s ease); - - &:hover { - border-color: sentro.token-get('blurple-light'); - background-color: sentro.token-get('blurple-light'); - } - - img { - z-index: 1; - } - } - - .pyc-user-card__info { - .pyc-user-card__name { - font-size: sentro.px-to-rem(20px); - } - - .pyc-user-card__role { - font-size: sentro.px-to-rem(14px); - } - - .pyc-user-card__quote { - margin: 0.5rem 0; - font-size: sentro.px-to-rem(12px); - white-space: pre-line; - - &::before { - content: open-quote; - } - - &::after { - content: close-quote; - } - } - } - } - - .pyc-user-card__links { - margin-top: auto; - - .pyc-user-card__links__wrap { - width: 100%; - display: inline-block; - margin-top: 0.7rem; - float: bottom; - - > * + * { - margin-left: 0.5rem; - } - - .pyc-button { - max-width: calc(calc(100% - 0.5rem) / 2); - } - - .pyc-user-card__link { - @include sentro.prefix(transition, all 0.1s linear); - - &:hover { - color: sentro.token-get('blurple-light'); - } - } - } - } - } - } -} +@use '~@matteusan/sentro'; + +$img-size: 100px; + +@mixin init() { + .pyc-user-card__section { + margin-bottom: 2rem; + + .pyc-user-card { + width: 100%; + padding: 1rem; + background: sentro.token-get('surface'); + border-radius: sentro.token-get('radius-medium'); + display: flex; + flex-direction: column; + box-shadow: + 0px 3px 3px -2px rgba(0, 0, 0, 0.275), + 0px 3px 4px 0px rgba(0, 0, 0, 0.215), + 0px 1px 8px 0px rgba(0, 0, 0, 0.195); + + .pyc-user-card__wrap { + display: grid; + grid-template-columns: $img-size 1fr; + grid-gap: 0.7rem; + + .pyc-user-card__img { + width: $img-size; + height: $img-size; + position: relative; + display: grid; + place-items: center; + overflow: hidden; + border-radius: 50%; + border: 2px solid sentro.token-get('blurple'); + background-color: sentro.token-get('blurple'); // Prevents gap between image and border + user-select: none; + @include sentro.prefix(transition, all 0.1s ease); + + &:hover { + border-color: sentro.token-get('blurple-light'); + background-color: sentro.token-get('blurple-light'); + } + + img { + z-index: 1; + } + } + + .pyc-user-card__info { + .pyc-user-card__name { + font-size: sentro.to-rem(20px); + } + + .pyc-user-card__role { + font-size: sentro.to-rem(14px); + } + + .pyc-user-card__quote { + margin: 0.5rem 0; + font-size: sentro.to-rem(12px); + white-space: pre-line; + + &::before { + content: open-quote; + } + + &::after { + content: close-quote; + } + } + } + } + + .pyc-user-card__links { + margin-top: auto; + + .pyc-user-card__links__wrap { + width: 100%; + display: inline-block; + margin-top: 0.7rem; + float: bottom; + + > * + * { + margin-left: 0.5rem; + } + + .pyc-button { + max-width: calc(calc(100% - 0.5rem) / 2); + } + + .pyc-user-card__link { + @include sentro.prefix(transition, all 0.1s linear); + + &:hover { + color: sentro.token-get('blurple-light'); + } + } + } + } + } + } +} diff --git a/tsconfig.json b/tsconfig.json index 23eeb81d..8c152f25 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,10 +1,12 @@ { - // This file is not used in compilation. It is here just for a nice editor experience. "extends": "@tsconfig/docusaurus/tsconfig.json", "compilerOptions": { - "baseUrl": "." - }, - "paths": { - "react": [ "./node_modules/@types/react" ] + "baseUrl": ".", + "forceConsistentCasingInFileNames": true, + "paths": { + "@site/*": ["./*"], + "react": ["./node_modules/@types/react"] + }, + "strict": true } } diff --git a/yarn.lock b/yarn.lock index df06f1f1..c868a8b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,261 +2,203 @@ # yarn lockfile v1 -"@algolia/autocomplete-core@1.7.1": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.7.1.tgz#025538b8a9564a9f3dd5bcf8a236d6951c76c7d1" - integrity sha512-eiZw+fxMzNQn01S8dA/hcCpoWCOCwcIIEUtHHdzN5TGB3IpzLbuhqFeTfh2OUhhgkE8Uo17+wH+QJ/wYyQmmzg== - dependencies: - "@algolia/autocomplete-shared" "1.7.1" - -"@algolia/autocomplete-preset-algolia@1.7.1": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.1.tgz#7dadc5607097766478014ae2e9e1c9c4b3f957c8" - integrity sha512-pJwmIxeJCymU1M6cGujnaIYcY3QPOVYZOXhFkWVM7IxKzy272BwCvMFMyc5NpG/QmiObBxjo7myd060OeTNJXg== - dependencies: - "@algolia/autocomplete-shared" "1.7.1" - -"@algolia/autocomplete-shared@1.7.1": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.1.tgz#95c3a0b4b78858fed730cf9c755b7d1cd0c82c74" - integrity sha512-eTmGVqY3GeyBTT8IWiB2K5EuURAqhnumfktAEoHxfDY2o7vg2rSnO16ZtIG0fMgt3py28Vwgq42/bVEuaQV7pg== - -"@algolia/cache-browser-local-storage@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.12.1.tgz#23f4f219963b96918d0524acd09d4d646541d888" - integrity sha512-ERFFOnC9740xAkuO0iZTQqm2AzU7Dpz/s+g7o48GlZgx5p9GgNcsuK5eS0GoW/tAK+fnKlizCtlFHNuIWuvfsg== - dependencies: - "@algolia/cache-common" "4.12.1" - -"@algolia/cache-browser-local-storage@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.13.1.tgz#ffacb9230119f77de1a6f163b83680be999110e4" - integrity sha512-UAUVG2PEfwd/FfudsZtYnidJ9eSCpS+LW9cQiesePQLz41NAcddKxBak6eP2GErqyFagSlnVXe/w2E9h2m2ttg== - dependencies: - "@algolia/cache-common" "4.13.1" - -"@algolia/cache-common@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.12.1.tgz#d3f1676ca9c404adce0f78d68f6381bedb44cd9c" - integrity sha512-UugTER3V40jT+e19Dmph5PKMeliYKxycNPwrPNADin0RcWNfT2QksK9Ff2N2W7UKraqMOzoeDb4LAJtxcK1a8Q== - -"@algolia/cache-common@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.13.1.tgz#c933fdec9f73b4f7c69d5751edc92eee4a63d76b" - integrity sha512-7Vaf6IM4L0Jkl3sYXbwK+2beQOgVJ0mKFbz/4qSxKd1iy2Sp77uTAazcX+Dlexekg1fqGUOSO7HS4Sx47ZJmjA== - -"@algolia/cache-in-memory@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.12.1.tgz#0ef6aac2f8feab5b46fc130beb682bbd21b55244" - integrity sha512-U6iaunaxK1lHsAf02UWF58foKFEcrVLsHwN56UkCtwn32nlP9rz52WOcHsgk6TJrL8NDcO5swMjtOQ5XHESFLw== - dependencies: - "@algolia/cache-common" "4.12.1" - -"@algolia/cache-in-memory@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.13.1.tgz#c19baa67b4597e1a93e987350613ab3b88768832" - integrity sha512-pZzybCDGApfA/nutsFK1P0Sbsq6fYJU3DwIvyKg4pURerlJM4qZbB9bfLRef0FkzfQu7W11E4cVLCIOWmyZeuQ== - dependencies: - "@algolia/cache-common" "4.13.1" - -"@algolia/client-account@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.12.1.tgz#e838c9283db2fab32a425dd13c77da321d48fd8b" - integrity sha512-jGo4ConJNoMdTCR2zouO0jO/JcJmzOK6crFxMMLvdnB1JhmMbuIKluOTJVlBWeivnmcsqb7r0v7qTCPW5PAyxQ== - dependencies: - "@algolia/client-common" "4.12.1" - "@algolia/client-search" "4.12.1" - "@algolia/transporter" "4.12.1" - -"@algolia/client-account@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.13.1.tgz#fea591943665477a23922ab31863ad0732e26c66" - integrity sha512-TFLiZ1KqMiir3FNHU+h3b0MArmyaHG+eT8Iojio6TdpeFcAQ1Aiy+2gb3SZk3+pgRJa/BxGmDkRUwE5E/lv3QQ== - dependencies: - "@algolia/client-common" "4.13.1" - "@algolia/client-search" "4.13.1" - "@algolia/transporter" "4.13.1" - -"@algolia/client-analytics@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.12.1.tgz#2976d658655a1590cf84cfb596aa75a204f6dec4" - integrity sha512-h1It7KXzIthlhuhfBk7LteYq72tym9maQDUsyRW0Gft8b6ZQahnRak9gcCvKwhcJ1vJoP7T7JrNYGiYSicTD9g== - dependencies: - "@algolia/client-common" "4.12.1" - "@algolia/client-search" "4.12.1" - "@algolia/requester-common" "4.12.1" - "@algolia/transporter" "4.12.1" - -"@algolia/client-analytics@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.13.1.tgz#5275956b2d0d16997148f2085f1701b6c39ecc32" - integrity sha512-iOS1JBqh7xaL5x00M5zyluZ9+9Uy9GqtYHv/2SMuzNW1qP7/0doz1lbcsP3S7KBbZANJTFHUOfuqyRLPk91iFA== - dependencies: - "@algolia/client-common" "4.13.1" - "@algolia/client-search" "4.13.1" - "@algolia/requester-common" "4.13.1" - "@algolia/transporter" "4.13.1" - -"@algolia/client-common@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.12.1.tgz#104ccefe96bda3ff926bc70c31ff6d17c41b6107" - integrity sha512-obnJ8eSbv+h94Grk83DTGQ3bqhViSWureV6oK1s21/KMGWbb3DkduHm+lcwFrMFkjSUSzosLBHV9EQUIBvueTw== - dependencies: - "@algolia/requester-common" "4.12.1" - "@algolia/transporter" "4.12.1" - -"@algolia/client-common@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.13.1.tgz#3bf9e3586f20ef85bbb56ccca390f7dbe57c8f4f" - integrity sha512-LcDoUE0Zz3YwfXJL6lJ2OMY2soClbjrrAKB6auYVMNJcoKZZ2cbhQoFR24AYoxnGUYBER/8B+9sTBj5bj/Gqbg== - dependencies: - "@algolia/requester-common" "4.13.1" - "@algolia/transporter" "4.13.1" - -"@algolia/client-personalization@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.12.1.tgz#f63d1890f95de850e1c8e41c1d57adda521d9e7f" - integrity sha512-sMSnjjPjRgByGHYygV+5L/E8a6RgU7l2GbpJukSzJ9GRY37tHmBHuvahv8JjdCGJ2p7QDYLnQy5bN5Z02qjc7Q== - dependencies: - "@algolia/client-common" "4.12.1" - "@algolia/requester-common" "4.12.1" - "@algolia/transporter" "4.12.1" - -"@algolia/client-personalization@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.13.1.tgz#438a1f58576ef19c4ad4addb8417bdacfe2fce2e" - integrity sha512-1CqrOW1ypVrB4Lssh02hP//YxluoIYXAQCpg03L+/RiXJlCs+uIqlzC0ctpQPmxSlTK6h07kr50JQoYH/TIM9w== - dependencies: - "@algolia/client-common" "4.13.1" - "@algolia/requester-common" "4.13.1" - "@algolia/transporter" "4.13.1" - -"@algolia/client-search@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.12.1.tgz#fcd7a974be5d39d5c336d7f2e89577ffa66aefdd" - integrity sha512-MwwKKprfY6X2nJ5Ki/ccXM2GDEePvVjZnnoOB2io3dLKW4fTqeSRlC5DRXeFD7UM0vOPPHr4ItV2aj19APKNVQ== - dependencies: - "@algolia/client-common" "4.12.1" - "@algolia/requester-common" "4.12.1" - "@algolia/transporter" "4.12.1" - -"@algolia/client-search@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.13.1.tgz#5501deed01e23c33d4aaa9f9eb96a849f0fce313" - integrity sha512-YQKYA83MNRz3FgTNM+4eRYbSmHi0WWpo019s5SeYcL3HUan/i5R09VO9dk3evELDFJYciiydSjbsmhBzbpPP2A== - dependencies: - "@algolia/client-common" "4.13.1" - "@algolia/requester-common" "4.13.1" - "@algolia/transporter" "4.13.1" +"@algolia/autocomplete-core@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz#1d56482a768c33aae0868c8533049e02e8961be7" + integrity sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw== + dependencies: + "@algolia/autocomplete-plugin-algolia-insights" "1.9.3" + "@algolia/autocomplete-shared" "1.9.3" -"@algolia/events@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@algolia/events/-/events-4.0.1.tgz#fd39e7477e7bc703d7f893b556f676c032af3950" - integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== +"@algolia/autocomplete-plugin-algolia-insights@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz#9b7f8641052c8ead6d66c1623d444cbe19dde587" + integrity sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg== + dependencies: + "@algolia/autocomplete-shared" "1.9.3" -"@algolia/logger-common@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.12.1.tgz#d6501b4d9d242956257ba8e10f6b4bbf6863baa4" - integrity sha512-fCgrzlXGATNqdFTxwx0GsyPXK+Uqrx1SZ3iuY2VGPPqdt1a20clAG2n2OcLHJpvaa6vMFPlJyWvbqAgzxdxBlQ== +"@algolia/autocomplete-preset-algolia@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz#64cca4a4304cfcad2cf730e83067e0c1b2f485da" + integrity sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA== + dependencies: + "@algolia/autocomplete-shared" "1.9.3" -"@algolia/logger-common@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.13.1.tgz#4221378e701e3f1eacaa051bcd4ba1f25ddfaf4d" - integrity sha512-L6slbL/OyZaAXNtS/1A8SAbOJeEXD5JcZeDCPYDqSTYScfHu+2ePRTDMgUTY4gQ7HsYZ39N1LujOd8WBTmM2Aw== +"@algolia/autocomplete-shared@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz#2e22e830d36f0a9cf2c0ccd3c7f6d59435b77dfa" + integrity sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ== -"@algolia/logger-console@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.12.1.tgz#841edd39dd5c5530a69fc66084bfee3254dd0807" - integrity sha512-0owaEnq/davngQMYqxLA4KrhWHiXujQ1CU3FFnyUcMyBR7rGHI48zSOUpqnsAXrMBdSH6rH5BDkSUUFwsh8RkQ== +"@algolia/cache-browser-local-storage@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz#97bc6d067a9fd932b9c922faa6b7fd6e546e1348" + integrity sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww== dependencies: - "@algolia/logger-common" "4.12.1" + "@algolia/cache-common" "4.24.0" + +"@algolia/cache-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.24.0.tgz#81a8d3a82ceb75302abb9b150a52eba9960c9744" + integrity sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g== -"@algolia/logger-console@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.13.1.tgz#423d358e4992dd4bceab0d9a4e99d1fd68107043" - integrity sha512-7jQOTftfeeLlnb3YqF8bNgA2GZht7rdKkJ31OCeSH2/61haO0tWPoNRjZq9XLlgMQZH276pPo0NdiArcYPHjCA== +"@algolia/cache-in-memory@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.24.0.tgz#ffcf8872f3a10cb85c4f4641bdffd307933a6e44" + integrity sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w== dependencies: - "@algolia/logger-common" "4.13.1" + "@algolia/cache-common" "4.24.0" -"@algolia/requester-browser-xhr@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.12.1.tgz#2d0c18ee188d7cae0e4a930e5e89989e3c4a816b" - integrity sha512-OaMxDyG0TZG0oqz1lQh9e3woantAG1bLnuwq3fmypsrQxra4IQZiyn1x+kEb69D2TcXApI5gOgrD4oWhtEVMtw== +"@algolia/client-account@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.24.0.tgz#eba7a921d828e7c8c40a32d4add21206c7fe12f1" + integrity sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA== dependencies: - "@algolia/requester-common" "4.12.1" + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/transporter" "4.24.0" -"@algolia/requester-browser-xhr@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.13.1.tgz#f8ea79233cf6f0392feaf31e35a6b40d68c5bc9e" - integrity sha512-oa0CKr1iH6Nc7CmU6RE7TnXMjHnlyp7S80pP/LvZVABeJHX3p/BcSCKovNYWWltgTxUg0U1o+2uuy8BpMKljwA== +"@algolia/client-analytics@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.24.0.tgz#9d2576c46a9093a14e668833c505ea697a1a3e30" + integrity sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg== dependencies: - "@algolia/requester-common" "4.13.1" + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" -"@algolia/requester-common@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.12.1.tgz#95bb6539da7199da3e205341cea8f27267f7af29" - integrity sha512-XWIrWQNJ1vIrSuL/bUk3ZwNMNxl+aWz6dNboRW6+lGTcMIwc3NBFE90ogbZKhNrFRff8zI4qCF15tjW+Fyhpow== +"@algolia/client-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.24.0.tgz#77c46eee42b9444a1d1c1583a83f7df4398a649d" + integrity sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA== + dependencies: + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" -"@algolia/requester-common@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.13.1.tgz#daea143d15ab6ed3909c4c45877f1b6c36a16179" - integrity sha512-eGVf0ID84apfFEuXsaoSgIxbU3oFsIbz4XiotU3VS8qGCJAaLVUC5BUJEkiFENZIhon7hIB4d0RI13HY4RSA+w== +"@algolia/client-common@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-5.0.0.tgz#ff52d29ed81cdafaa38655fc4ee958ca49f20aaf" + integrity sha512-6N5Qygv/Z/B+rPufnPDLNWgsMf1uubMU7iS52xLcQSLiGlTS4f9eLUrmNXSzHccP33uoFi6xN9craN1sZi5MPQ== -"@algolia/requester-node-http@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.12.1.tgz#c9df97ff1daa7e58c5c2b1f28cf7163005edccb0" - integrity sha512-awBtwaD+s0hxkA1aehYn8F0t9wqGoBVWgY4JPHBmp1ChO3pK7RKnnvnv7QQa9vTlllX29oPt/BBVgMo1Z3n1Qg== +"@algolia/client-personalization@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.24.0.tgz#8b47789fb1cb0f8efbea0f79295b7c5a3850f6ae" + integrity sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w== dependencies: - "@algolia/requester-common" "4.12.1" + "@algolia/client-common" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" -"@algolia/requester-node-http@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.13.1.tgz#32c63d4c009f22d97e396406de7af9b66fb8e89d" - integrity sha512-7C0skwtLdCz5heKTVe/vjvrqgL/eJxmiEjHqXdtypcE5GCQCYI15cb+wC4ytYioZDMiuDGeVYmCYImPoEgUGPw== +"@algolia/client-search@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.24.0.tgz#75e6c02d33ef3e0f34afd9962c085b856fc4a55f" + integrity sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA== dependencies: - "@algolia/requester-common" "4.13.1" + "@algolia/client-common" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" -"@algolia/transporter@4.12.1": - version "4.12.1" - resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.12.1.tgz#61b9829916c474f42e2d4a6eada0d6c138379945" - integrity sha512-BGeNgdEHc6dXIk2g8kdlOoQ6fQ6OIaKQcplEj7HPoi+XZUeAvRi3Pff3QWd7YmybWkjzd9AnTzieTASDWhL+sQ== +"@algolia/client-search@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-5.0.0.tgz#8d58f5daeffe9d19e0e0e9ebcdb5d23525edebe4" + integrity sha512-QdDYMzoxYZ3axzBy6CHe+M+NlOGvHEFTa2actchGnp25Uu0N6lyVNivT7nph+P1XoxgAD08cWbeJD3wWQXnpng== dependencies: - "@algolia/cache-common" "4.12.1" - "@algolia/logger-common" "4.12.1" - "@algolia/requester-common" "4.12.1" + "@algolia/client-common" "5.0.0" + "@algolia/requester-browser-xhr" "5.0.0" + "@algolia/requester-node-http" "5.0.0" + +"@algolia/events@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@algolia/events/-/events-4.0.1.tgz#fd39e7477e7bc703d7f893b556f676c032af3950" + integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== -"@algolia/transporter@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.13.1.tgz#509e03e9145102843d5be4a031c521f692d4e8d6" - integrity sha512-pICnNQN7TtrcYJqqPEXByV8rJ8ZRU2hCiIKLTLRyNpghtQG3VAFk6fVtdzlNfdUGZcehSKGarPIZEHlQXnKjgw== +"@algolia/logger-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.24.0.tgz#28d439976019ec0a46ba7a1a739ef493d4ef8123" + integrity sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA== + +"@algolia/logger-console@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.24.0.tgz#c6ff486036cd90b81d07a95aaba04461da7e1c65" + integrity sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg== + dependencies: + "@algolia/logger-common" "4.24.0" + +"@algolia/recommend@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/recommend/-/recommend-4.24.0.tgz#8a3f78aea471ee0a4836b78fd2aad4e9abcaaf34" + integrity sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw== + dependencies: + "@algolia/cache-browser-local-storage" "4.24.0" + "@algolia/cache-common" "4.24.0" + "@algolia/cache-in-memory" "4.24.0" + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/logger-console" "4.24.0" + "@algolia/requester-browser-xhr" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/requester-node-http" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/requester-browser-xhr@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz#313c5edab4ed73a052e75803855833b62dd19c16" + integrity sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA== + dependencies: + "@algolia/requester-common" "4.24.0" + +"@algolia/requester-browser-xhr@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.0.0.tgz#ddce386fd8635d79a1803c44b749289ff690db80" + integrity sha512-oOoQhSpg/RGiGHjn/cqtYpHBkkd+5M/DCi1jmfW+ZOvLVx21QVt6PbWIJoKJF85moNFo4UG9pMBU35R1MaxUKQ== dependencies: - "@algolia/cache-common" "4.13.1" - "@algolia/logger-common" "4.13.1" - "@algolia/requester-common" "4.13.1" + "@algolia/client-common" "5.0.0" -"@ampproject/remapping@^2.1.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== +"@algolia/requester-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.24.0.tgz#1c60c198031f48fcdb9e34c4057a3ea987b9a436" + integrity sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA== + +"@algolia/requester-node-http@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz#4461593714031d02aa7da221c49df675212f482f" + integrity sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw== dependencies: - "@jridgewell/gen-mapping" "^0.1.0" - "@jridgewell/trace-mapping" "^0.3.9" + "@algolia/requester-common" "4.24.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.8.3": +"@algolia/requester-node-http@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-5.0.0.tgz#708961cb2c069e5ed3bae83aef144ec8b3300b57" + integrity sha512-FwCdugzpnW0wxbgWPauAz5vhmWGQnjZa5DCl9PBbIoDNEy/NIV8DmiL9CEA+LljQdDidG0l0ijojcTNaRRtPvQ== + dependencies: + "@algolia/client-common" "5.0.0" + +"@algolia/transporter@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.24.0.tgz#226bb1f8af62430374c1972b2e5c8580ab275102" + integrity sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA== + dependencies: + "@algolia/cache-common" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/requester-common" "4.24.0" + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.8.3": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== dependencies: "@babel/highlight" "^7.16.7" -"@babel/code-frame@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== - dependencies: - "@babel/highlight" "^7.18.6" - -"@babel/code-frame@^7.24.7": +"@babel/code-frame@^7.10.4", "@babel/code-frame@^7.21.4", "@babel/code-frame@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== @@ -264,15 +206,10 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.10": - version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab" - integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw== - -"@babel/compat-data@^7.18.6": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d" - integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.2.tgz#e41928bd33475305c586f6acbbb7e3ade7a6f7f5" + integrity sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ== "@babel/core@7.12.9": version "7.12.9" @@ -296,53 +233,37 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.15.5", "@babel/core@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.6.tgz#54a107a3c298aee3fe5e1947a6464b9b6faca03d" - integrity sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ== - dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.18.6" - "@babel/helper-compilation-targets" "^7.18.6" - "@babel/helper-module-transforms" "^7.18.6" - "@babel/helpers" "^7.18.6" - "@babel/parser" "^7.18.6" - "@babel/template" "^7.18.6" - "@babel/traverse" "^7.18.6" - "@babel/types" "^7.18.6" - convert-source-map "^1.7.0" +"@babel/core@^7.18.6", "@babel/core@^7.19.6": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" + integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-module-transforms" "^7.25.2" + "@babel/helpers" "^7.25.0" + "@babel/parser" "^7.25.0" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.2" + "@babel/types" "^7.25.2" + convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" - json5 "^2.2.1" - semver "^6.3.0" + json5 "^2.2.3" + semver "^6.3.1" -"@babel/generator@^7.12.5", "@babel/generator@^7.18.6", "@babel/generator@^7.18.7": - version "7.18.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.7.tgz#2aa78da3c05aadfc82dbac16c99552fc802284bd" - integrity sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A== +"@babel/generator@^7.12.5", "@babel/generator@^7.18.7", "@babel/generator@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.0.tgz#f858ddfa984350bc3d3b7f125073c9af6988f18e" + integrity sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw== dependencies: - "@babel/types" "^7.18.7" - "@jridgewell/gen-mapping" "^0.3.2" - jsesc "^2.5.1" - -"@babel/generator@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d" - integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA== - dependencies: - "@babel/types" "^7.24.7" + "@babel/types" "^7.25.0" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-annotate-as-pure@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" - integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== - dependencies: - "@babel/types" "^7.16.7" - "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" @@ -350,54 +271,44 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.6.tgz#f14d640ed1ee9246fb33b8255f08353acfe70e6a" - integrity sha512-KT10c1oWEpmrIRYnthbzHgoOf6B+Xd6a5yhdbNtdhtG7aO1or5HViuf1TQR36xY/QprXA5nvxO6nAjhJ4y38jw== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.18.6" - "@babel/types" "^7.18.6" - -"@babel/helper-compilation-targets@^7.13.0": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz#67a85a10cbd5fc7f1457fec2e7f45441dc6c754b" - integrity sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ== +"@babel/helper-annotate-as-pure@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz#5373c7bc8366b12a033b4be1ac13a206c6656aab" + integrity sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg== dependencies: - "@babel/compat-data" "^7.17.10" - "@babel/helper-validator-option" "^7.16.7" - browserslist "^4.20.2" - semver "^6.3.0" + "@babel/types" "^7.24.7" -"@babel/helper-compilation-targets@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz#18d35bfb9f83b1293c22c55b3d576c1315b6ed96" - integrity sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz#37d66feb012024f2422b762b9b2a7cfe27c7fba3" + integrity sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA== dependencies: - "@babel/compat-data" "^7.18.6" - "@babel/helper-validator-option" "^7.18.6" - browserslist "^4.20.2" - semver "^6.3.0" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" -"@babel/helper-create-class-features-plugin@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.6.tgz#6f15f8459f3b523b39e00a99982e2c040871ed72" - integrity sha512-YfDzdnoxHGV8CzqHGyCbFvXg5QESPFkXlHtvdCkesLjjVMT2Adxe4FGUR5ChIb3DxSaXO12iIOCWoXdsUVwnqw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.6" - "@babel/helper-function-name" "^7.18.6" - "@babel/helper-member-expression-to-functions" "^7.18.6" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-replace-supers" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - -"@babel/helper-create-regexp-features-plugin@^7.16.7", "@babel/helper-create-regexp-features-plugin@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz#bb37ca467f9694bbe55b884ae7a5cc1e0084e4fd" - integrity sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - regexpu-core "^5.0.1" +"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.24.7", "@babel/helper-compilation-targets@^7.24.8", "@babel/helper-compilation-targets@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" + integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== + dependencies: + "@babel/compat-data" "^7.25.2" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.24.7", "@babel/helper-create-class-features-plugin@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz#a109bf9c3d58dfed83aaf42e85633c89f43a6253" + integrity sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-member-expression-to-functions" "^7.24.8" + "@babel/helper-optimise-call-expression" "^7.24.7" + "@babel/helper-replace-supers" "^7.25.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" + "@babel/traverse" "^7.25.0" + semver "^6.3.1" "@babel/helper-create-regexp-features-plugin@^7.18.6": version "7.18.6" @@ -407,201 +318,113 @@ "@babel/helper-annotate-as-pure" "^7.18.6" regexpu-core "^5.1.0" -"@babel/helper-define-polyfill-provider@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" - integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== +"@babel/helper-create-regexp-features-plugin@^7.24.7", "@babel/helper-create-regexp-features-plugin@^7.25.0": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz#24c75974ed74183797ffd5f134169316cd1808d9" + integrity sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g== dependencies: - "@babel/helper-compilation-targets" "^7.13.0" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/traverse" "^7.13.0" + "@babel/helper-annotate-as-pure" "^7.24.7" + regexpu-core "^5.3.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz#18594f789c3594acb24cfdb4a7f7b7d2e8bd912d" + integrity sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ== + dependencies: + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-plugin-utils" "^7.22.5" debug "^4.1.1" lodash.debounce "^4.0.8" resolve "^1.14.2" - semver "^6.1.2" - -"@babel/helper-environment-visitor@^7.16.7": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz#8a6d2dedb53f6bf248e31b4baf38739ee4a637bd" - integrity sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ== -"@babel/helper-environment-visitor@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz#b7eee2b5b9d70602e59d1a6cad7dd24de7ca6cd7" - integrity sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q== - -"@babel/helper-environment-visitor@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" - integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== +"@babel/helper-member-expression-to-functions@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz#6155e079c913357d24a4c20480db7c712a5c3fb6" + integrity sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA== dependencies: - "@babel/types" "^7.24.7" + "@babel/traverse" "^7.24.8" + "@babel/types" "^7.24.8" -"@babel/helper-explode-assignable-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" - integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-function-name@^7.18.6": +"@babel/helper-module-imports@^7.18.6": version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz#8334fecb0afba66e6d87a7e8c6bb7fed79926b83" - integrity sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw== + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== dependencies: - "@babel/template" "^7.18.6" "@babel/types" "^7.18.6" -"@babel/helper-function-name@^7.24.7": +"@babel/helper-module-imports@^7.24.7": version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" - integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" + integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== dependencies: - "@babel/template" "^7.24.7" + "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" -"@babel/helper-hoist-variables@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" - integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== +"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.24.7", "@babel/helper-module-transforms@^7.24.8", "@babel/helper-module-transforms@^7.25.0", "@babel/helper-module-transforms@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" + integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== dependencies: - "@babel/types" "^7.18.6" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/traverse" "^7.25.2" -"@babel/helper-hoist-variables@^7.24.7": +"@babel/helper-optimise-call-expression@^7.24.7": version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" - integrity sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ== + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz#8b0a0456c92f6b323d27cfd00d1d664e76692a0f" + integrity sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A== dependencies: "@babel/types" "^7.24.7" -"@babel/helper-member-expression-to-functions@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.6.tgz#44802d7d602c285e1692db0bad9396d007be2afc" - integrity sha512-CeHxqwwipekotzPDUuJOfIMtcIHBuc7WAzLmTYWctVigqS5RktNMQ5bEwQSuGewzYnCtTWa3BARXeiLxDTv+Ng== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-module-imports@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-module-transforms@^7.12.1": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz#baf05dec7a5875fb9235bd34ca18bad4e21221cd" - integrity sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.0" - "@babel/types" "^7.18.0" - -"@babel/helper-module-transforms@^7.18.6": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.8.tgz#4f8408afead0188cfa48672f9d0e5787b61778c8" - integrity sha512-che3jvZwIcZxrwh63VfnFTUzcAM9v/lznYkkRxIBGMPt1SudOKHAEec0SIRCfiuIzTcF7VGj/CaTT6gY4eWxvA== - dependencies: - "@babel/helper-environment-visitor" "^7.18.6" - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-simple-access" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/helper-validator-identifier" "^7.18.6" - "@babel/template" "^7.18.6" - "@babel/traverse" "^7.18.8" - "@babel/types" "^7.18.8" - -"@babel/helper-optimise-call-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" - integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== - dependencies: - "@babel/types" "^7.18.6" - "@babel/helper-plugin-utils@7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.17.12", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz#9448974dd4fb1d80fefe72e8a0af37809cd30d6d" integrity sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg== -"@babel/helper-remap-async-to-generator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.6.tgz#fa1f81acd19daee9d73de297c0308783cd3cfc23" - integrity sha512-z5wbmV55TveUPZlCLZvxWHtrjuJd+8inFhk7DG0WW87/oJuGDcjDiu7HIvGcpf5464L6xKCg3vNkmlVVz9hwyQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.6" - "@babel/helper-wrap-function" "^7.18.6" - "@babel/types" "^7.18.6" +"@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878" + integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg== -"@babel/helper-replace-supers@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.6.tgz#efedf51cfccea7b7b8c0f00002ab317e7abfe420" - integrity sha512-fTf7zoXnUGl9gF25fXCWE26t7Tvtyn6H4hkLSYhATwJvw2uYxd3aoXplMSe0g9XbwK7bmxNes7+FGO0rB/xC0g== +"@babel/helper-remap-async-to-generator@^7.24.7", "@babel/helper-remap-async-to-generator@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz#d2f0fbba059a42d68e5e378feaf181ef6055365e" + integrity sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw== dependencies: - "@babel/helper-environment-visitor" "^7.18.6" - "@babel/helper-member-expression-to-functions" "^7.18.6" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/traverse" "^7.18.6" - "@babel/types" "^7.18.6" + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-wrap-function" "^7.25.0" + "@babel/traverse" "^7.25.0" -"@babel/helper-simple-access@^7.17.7": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz#4dc473c2169ac3a1c9f4a51cfcd091d1c36fcff9" - integrity sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ== +"@babel/helper-replace-supers@^7.24.7", "@babel/helper-replace-supers@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz#ff44deac1c9f619523fe2ca1fd650773792000a9" + integrity sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg== dependencies: - "@babel/types" "^7.18.2" + "@babel/helper-member-expression-to-functions" "^7.24.8" + "@babel/helper-optimise-call-expression" "^7.24.7" + "@babel/traverse" "^7.25.0" -"@babel/helper-simple-access@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea" - integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-skip-transparent-expression-wrappers@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.6.tgz#7dff00a5320ca4cf63270e5a0eca4b268b7380d9" - integrity sha512-4KoLhwGS9vGethZpAhYnMejWkX64wsnHPDwvOsKWU6Fg4+AlK2Jz3TyjQLMEPvz+1zemi/WBdkYxCD0bAfIkiw== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-split-export-declaration@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" - integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== +"@babel/helper-simple-access@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" + integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== dependencies: - "@babel/types" "^7.18.6" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" -"@babel/helper-split-export-declaration@^7.24.7": +"@babel/helper-skip-transparent-expression-wrappers@^7.24.7": version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856" - integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz#5f8fa83b69ed5c27adc56044f8be2b3ea96669d9" + integrity sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ== dependencies: + "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" "@babel/helper-string-parser@^7.24.7": @@ -609,6 +432,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2" integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg== +"@babel/helper-string-parser@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" + integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== + "@babel/helper-validator-identifier@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" @@ -624,43 +452,32 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== -"@babel/helper-validator-option@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" - integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== - "@babel/helper-validator-option@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== -"@babel/helper-wrap-function@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.18.6.tgz#ec44ea4ad9d8988b90c3e465ba2382f4de81a073" - integrity sha512-I5/LZfozwMNbwr/b1vhhuYD+J/mU+gfGAj5td7l5Rv9WYmH6i3Om69WGKNmlIpsVW/mF6O5bvTKbvDQZVgjqOw== - dependencies: - "@babel/helper-function-name" "^7.18.6" - "@babel/template" "^7.18.6" - "@babel/traverse" "^7.18.6" - "@babel/types" "^7.18.6" +"@babel/helper-validator-option@^7.24.7", "@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== -"@babel/helpers@^7.12.5": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.2.tgz#970d74f0deadc3f5a938bfa250738eb4ac889384" - integrity sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg== +"@babel/helper-wrap-function@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz#dab12f0f593d6ca48c0062c28bcfb14ebe812f81" + integrity sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ== dependencies: - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.2" - "@babel/types" "^7.18.2" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.0" + "@babel/types" "^7.25.0" -"@babel/helpers@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.6.tgz#4c966140eaa1fcaa3d5a8c09d7db61077d4debfd" - integrity sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ== +"@babel/helpers@^7.12.5", "@babel/helpers@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.0.tgz#e69beb7841cb93a6505531ede34f34e6a073650a" + integrity sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw== dependencies: - "@babel/template" "^7.18.6" - "@babel/traverse" "^7.18.6" - "@babel/types" "^7.18.6" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.0" "@babel/highlight@^7.16.7": version "7.17.12" @@ -671,15 +488,6 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== - dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@babel/highlight@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" @@ -690,111 +498,56 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.12.7", "@babel/parser@^7.16.7": - version "7.18.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.4.tgz#6774231779dd700e0af29f6ad8d479582d7ce5ef" - integrity sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow== - -"@babel/parser@^7.18.6", "@babel/parser@^7.18.8": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.8.tgz#822146080ac9c62dac0823bb3489622e0bc1cbdf" - integrity sha512-RSKRfYX20dyH+elbJK2uqAkVyucL+xXzhqlMD5/ZXx+dAAwpyB7HsvnHe/ZUGOF+xLr5Wx9/JoXVTj6BQE2/oA== +"@babel/parser@^7.12.7", "@babel/parser@^7.18.8", "@babel/parser@^7.25.0", "@babel/parser@^7.25.3": + version "7.25.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.3.tgz#91fb126768d944966263f0657ab222a642b82065" + integrity sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw== + dependencies: + "@babel/types" "^7.25.2" "@babel/parser@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" - integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.6.tgz#b4e4dbc2cd1acd0133479918f7c6412961c9adb8" - integrity sha512-Udgu8ZRgrBrttVz6A0EVL0SJ1z+RLbIeqsu632SA1hf0awEppD6TvdznoH+orIF8wtFFAV/Enmw9Y+9oV8TQcw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-skip-transparent-expression-wrappers" "^7.18.6" - "@babel/plugin-proposal-optional-chaining" "^7.18.6" - -"@babel/plugin-proposal-async-generator-functions@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz#aedac81e6fc12bb643374656dd5f2605bf743d17" - integrity sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w== - dependencies: - "@babel/helper-environment-visitor" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-remap-async-to-generator" "^7.18.6" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-class-properties@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" - integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.3": + version "7.25.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz#dca427b45a6c0f5c095a1c639dfe2476a3daba7f" + integrity sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/traverse" "^7.25.3" -"@babel/plugin-proposal-class-static-block@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz#8aa81d403ab72d3962fc06c26e222dacfc9b9020" - integrity sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw== +"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz#cd0c583e01369ef51676bdb3d7b603e17d2b3f73" + integrity sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-proposal-dynamic-import@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94" - integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz#749bde80356b295390954643de7635e0dffabe73" + integrity sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-proposal-export-namespace-from@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.6.tgz#1016f0aa5ab383bbf8b3a85a2dcaedf6c8ee7491" - integrity sha512-zr/QcUlUo7GPo6+X1wC98NJADqmy5QTFWWhqeQWiki4XHafJtLl/YMGkmRB2szDD2IYJCCdBTd4ElwhId9T7Xw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - -"@babel/plugin-proposal-json-strings@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b" - integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-json-strings" "^7.8.3" - -"@babel/plugin-proposal-logical-assignment-operators@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.6.tgz#3b9cac6f1ffc2aa459d111df80c12020dfc6b665" - integrity sha512-zMo66azZth/0tVd7gmkxOkOjs2rpHyhpcFo565PUP37hSp6hSd9uUKIfTDFMz58BwqgQKhJ9YxtM5XddjXVn+Q== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" - integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz#e4eabdd5109acc399b38d7999b2ef66fc2022f89" + integrity sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" + "@babel/plugin-transform-optional-chaining" "^7.24.7" -"@babel/plugin-proposal-numeric-separator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" - integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz#3a82a70e7cb7294ad2559465ebcb871dfbf078fb" + integrity sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/traverse" "^7.25.0" "@babel/plugin-proposal-object-rest-spread@7.12.1": version "7.12.1" @@ -805,67 +558,10 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.0" "@babel/plugin-transform-parameters" "^7.12.1" -"@babel/plugin-proposal-object-rest-spread@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.6.tgz#ec93bba06bfb3e15ebd7da73e953d84b094d5daf" - integrity sha512-9yuM6wr4rIsKa1wlUAbZEazkCrgw2sMPEXCr4Rnwetu7cEW1NydkCWytLuYletbf8vFxdJxFhwEZqMpOx2eZyw== - dependencies: - "@babel/compat-data" "^7.18.6" - "@babel/helper-compilation-targets" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.18.6" - -"@babel/plugin-proposal-optional-catch-binding@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb" - integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.6.tgz#46d4f2ffc20e87fad1d98bc4fa5d466366f6aa0b" - integrity sha512-PatI6elL5eMzoypFAiYDpYQyMtXTn+iMhuxxQt5mAXD4fEmKorpSI3PHd+i3JXBJN3xyA6MvJv7at23HffFHwA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-skip-transparent-expression-wrappers" "^7.18.6" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-proposal-private-methods@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea" - integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-private-property-in-object@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz#a64137b232f0aca3733a67eb1a144c192389c503" - integrity sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - -"@babel/plugin-proposal-unicode-property-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" - integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz#3dbd7a67bd7f94c8238b394da112d86aaf32ad4d" - integrity sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.17.12" - "@babel/helper-plugin-utils" "^7.17.12" +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -902,12 +598,26 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-import-assertions@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz#cd6190500a4fa2fe31990a963ffab4b63e4505e4" - integrity sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ== +"@babel/plugin-syntax-import-assertions@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz#2a0b406b5871a20a841240586b1300ce2088a778" + integrity sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz#b4f9ea95a79e6912480c4b626739f86a076624ca" + integrity sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" @@ -930,6 +640,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" +"@babel/plugin-syntax-jsx@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d" + integrity sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -986,220 +703,338 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz#1c09cd25795c7c2b8a4ba9ae49394576d4133285" - integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA== +"@babel/plugin-syntax-typescript@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz#58d458271b4d3b6bb27ee6ac9525acbb259bad1c" + integrity sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-arrow-functions@^7.18.6": +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz#19063fcf8771ec7b31d742339dac62433d0611fe" - integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ== + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-async-to-generator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz#ccda3d1ab9d5ced5265fdb13f1882d5476c71615" - integrity sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag== +"@babel/plugin-transform-arrow-functions@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz#4f6886c11e423bd69f3ce51dbf42424a5f275514" + integrity sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ== dependencies: - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-remap-async-to-generator" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-block-scoped-functions@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8" - integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== +"@babel/plugin-transform-async-generator-functions@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz#b785cf35d73437f6276b1e30439a57a50747bddf" + integrity sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-remap-async-to-generator" "^7.25.0" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/traverse" "^7.25.0" -"@babel/plugin-transform-block-scoping@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.6.tgz#b5f78318914615397d86a731ef2cc668796a726c" - integrity sha512-pRqwb91C42vs1ahSAWJkxOxU1RHWDn16XAa6ggQ72wjLlWyYeAcLvTtE0aM8ph3KNydy9CQF2nLYcjq1WysgxQ== +"@babel/plugin-transform-async-to-generator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz#72a3af6c451d575842a7e9b5a02863414355bdcc" + integrity sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-remap-async-to-generator" "^7.24.7" -"@babel/plugin-transform-classes@^7.18.6": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.8.tgz#7e85777e622e979c85c701a095280360b818ce49" - integrity sha512-RySDoXdF6hgHSHuAW4aLGyVQdmvEX/iJtjVre52k0pxRq4hzqze+rAVP++NmNv596brBpYmaiKgTZby7ziBnVg== +"@babel/plugin-transform-block-scoped-functions@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz#a4251d98ea0c0f399dafe1a35801eaba455bbf1f" + integrity sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.6" - "@babel/helper-function-name" "^7.18.6" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-replace-supers" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-transform-block-scoping@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz#23a6ed92e6b006d26b1869b1c91d1b917c2ea2ac" + integrity sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.8" + +"@babel/plugin-transform-class-properties@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz#256879467b57b0b68c7ddfc5b76584f398cd6834" + integrity sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-transform-class-static-block@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz#c82027ebb7010bc33c116d4b5044fbbf8c05484d" + integrity sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-transform-classes@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.0.tgz#63122366527d88e0ef61b612554fe3f8c793991e" + integrity sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-compilation-targets" "^7.24.8" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-replace-supers" "^7.25.0" + "@babel/traverse" "^7.25.0" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.6.tgz#5d15eb90e22e69604f3348344c91165c5395d032" - integrity sha512-9repI4BhNrR0KenoR9vm3/cIc1tSBIo+u1WVjKCAynahj25O8zfbiE6JtAtHPGQSs4yZ+bA8mRasRP+qc+2R5A== +"@babel/plugin-transform-computed-properties@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz#4cab3214e80bc71fae3853238d13d097b004c707" + integrity sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/template" "^7.24.7" -"@babel/plugin-transform-destructuring@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.6.tgz#a98b0e42c7ffbf5eefcbcf33280430f230895c6f" - integrity sha512-tgy3u6lRp17ilY8r1kP4i2+HDUwxlVqq3RTc943eAWSzGgpU1qhiKpqZ5CMyHReIYPHdo3Kg8v8edKtDqSVEyQ== +"@babel/plugin-transform-destructuring@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz#c828e814dbe42a2718a838c2a2e16a408e055550" + integrity sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-transform-dotall-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8" - integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== +"@babel/plugin-transform-dotall-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz#5f8bf8a680f2116a7207e16288a5f974ad47a7a0" + integrity sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-create-regexp-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241" - integrity sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ== +"@babel/plugin-transform-duplicate-keys@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz#dd20102897c9a2324e5adfffb67ff3610359a8ee" + integrity sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-duplicate-keys@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.6.tgz#e6c94e8cd3c9dd8a88144f7b78ae22975a7ff473" - integrity sha512-NJU26U/208+sxYszf82nmGYqVF9QN8py2HFTblPT9hbawi8+1C5a9JubODLTGFuT0qlkqVinmkwOD13s0sZktg== +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz#809af7e3339466b49c034c683964ee8afb3e2604" + integrity sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-create-regexp-features-plugin" "^7.25.0" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-transform-exponentiation-operator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd" - integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== +"@babel/plugin-transform-dynamic-import@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz#4d8b95e3bae2b037673091aa09cd33fecd6419f4" + integrity sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-transform-for-of@^7.18.6": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1" - integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ== +"@babel/plugin-transform-exponentiation-operator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz#b629ee22645f412024297d5245bce425c31f9b0d" + integrity sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-function-name@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.6.tgz#6a7e4ae2893d336fd1b8f64c9f92276391d0f1b4" - integrity sha512-kJha/Gbs5RjzIu0CxZwf5e3aTTSlhZnHMT8zPWnJMjNpLOUgqevg+PN5oMH68nMCXnfiMo4Bhgxqj59KHTlAnA== +"@babel/plugin-transform-export-namespace-from@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz#176d52d8d8ed516aeae7013ee9556d540c53f197" + integrity sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA== dependencies: - "@babel/helper-compilation-targets" "^7.18.6" - "@babel/helper-function-name" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-transform-literals@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.6.tgz#9d6af353b5209df72960baf4492722d56f39a205" - integrity sha512-x3HEw0cJZVDoENXOp20HlypIHfl0zMIhMVZEBVTfmqbObIpsMxMbmU5nOEO8R7LYT+z5RORKPlTI5Hj4OsO9/Q== +"@babel/plugin-transform-for-of@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz#f25b33f72df1d8be76399e1b8f3f9d366eb5bc70" + integrity sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" -"@babel/plugin-transform-member-expression-literals@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e" - integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== +"@babel/plugin-transform-function-name@^7.25.1": + version "7.25.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz#b85e773097526c1a4fc4ba27322748643f26fc37" + integrity sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-compilation-targets" "^7.24.8" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/traverse" "^7.25.1" -"@babel/plugin-transform-modules-amd@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz#8c91f8c5115d2202f277549848874027d7172d21" - integrity sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg== +"@babel/plugin-transform-json-strings@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz#f3e9c37c0a373fee86e36880d45b3664cedaf73a" + integrity sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw== dependencies: - "@babel/helper-module-transforms" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - babel-plugin-dynamic-import-node "^2.3.3" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-transform-modules-commonjs@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz#afd243afba166cca69892e24a8fd8c9f2ca87883" - integrity sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q== +"@babel/plugin-transform-literals@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz#deb1ad14fc5490b9a65ed830e025bca849d8b5f3" + integrity sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw== dependencies: - "@babel/helper-module-transforms" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-simple-access" "^7.18.6" - babel-plugin-dynamic-import-node "^2.3.3" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-transform-modules-systemjs@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.6.tgz#026511b7657d63bf5d4cf2fd4aeb963139914a54" - integrity sha512-UbPYpXxLjTw6w6yXX2BYNxF3p6QY225wcTkfQCy3OMnSlS/C3xGtwUjEzGkldb/sy6PWLiCQ3NbYfjWUTI3t4g== +"@babel/plugin-transform-logical-assignment-operators@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz#a58fb6eda16c9dc8f9ff1c7b1ba6deb7f4694cb0" + integrity sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw== dependencies: - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-module-transforms" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-validator-identifier" "^7.18.6" - babel-plugin-dynamic-import-node "^2.3.3" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-transform-modules-umd@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9" - integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== +"@babel/plugin-transform-member-expression-literals@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz#3b4454fb0e302e18ba4945ba3246acb1248315df" + integrity sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw== dependencies: - "@babel/helper-module-transforms" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-named-capturing-groups-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz#c89bfbc7cc6805d692f3a49bc5fc1b630007246d" - integrity sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg== +"@babel/plugin-transform-modules-amd@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz#65090ed493c4a834976a3ca1cde776e6ccff32d7" + integrity sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-module-transforms" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-new-target@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8" - integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw== +"@babel/plugin-transform-modules-commonjs@^7.24.7", "@babel/plugin-transform-modules-commonjs@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz#ab6421e564b717cb475d6fff70ae7f103536ea3c" + integrity sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-module-transforms" "^7.24.8" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-simple-access" "^7.24.7" -"@babel/plugin-transform-object-super@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c" - integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== +"@babel/plugin-transform-modules-systemjs@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz#8f46cdc5f9e5af74f3bd019485a6cbe59685ea33" + integrity sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-replace-supers" "^7.18.6" + "@babel/helper-module-transforms" "^7.25.0" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/traverse" "^7.25.0" -"@babel/plugin-transform-parameters@^7.12.1": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz#eb467cd9586ff5ff115a9880d6fdbd4a846b7766" - integrity sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA== +"@babel/plugin-transform-modules-umd@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz#edd9f43ec549099620df7df24e7ba13b5c76efc8" + integrity sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-module-transforms" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-parameters@^7.18.6": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz#ee9f1a0ce6d78af58d0956a9378ea3427cccb48a" - integrity sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg== +"@babel/plugin-transform-named-capturing-groups-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz#9042e9b856bc6b3688c0c2e4060e9e10b1460923" + integrity sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-create-regexp-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-property-literals@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3" - integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== +"@babel/plugin-transform-new-target@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz#31ff54c4e0555cc549d5816e4ab39241dfb6ab00" + integrity sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-react-constant-elements@^7.14.5": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.17.12.tgz#cc580857696b6dd9e5e3d079e673d060a0657f37" - integrity sha512-maEkX2xs2STuv2Px8QuqxqjhV2LsFobT1elCgyU5704fcyTu9DyD/bJXxD/mrRiVyhpHweOQ00OJ5FKhHq9oEw== +"@babel/plugin-transform-nullish-coalescing-operator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz#1de4534c590af9596f53d67f52a92f12db984120" + integrity sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-transform-numeric-separator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz#bea62b538c80605d8a0fac9b40f48e97efa7de63" + integrity sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-transform-object-rest-spread@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz#d13a2b93435aeb8a197e115221cab266ba6e55d6" + integrity sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q== + dependencies: + "@babel/helper-compilation-targets" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.24.7" + +"@babel/plugin-transform-object-super@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz#66eeaff7830bba945dd8989b632a40c04ed625be" + integrity sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-replace-supers" "^7.24.7" + +"@babel/plugin-transform-optional-catch-binding@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz#00eabd883d0dd6a60c1c557548785919b6e717b4" + integrity sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-transform-optional-chaining@^7.24.7", "@babel/plugin-transform-optional-chaining@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz#bb02a67b60ff0406085c13d104c99a835cdf365d" + integrity sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz#5881f0ae21018400e320fc7eb817e529d1254b68" + integrity sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-transform-private-methods@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz#e6318746b2ae70a59d023d5cc1344a2ba7a75f5e" + integrity sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-transform-private-property-in-object@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz#4eec6bc701288c1fab5f72e6a4bbc9d67faca061" + integrity sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-create-class-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz#f0d2ed8380dfbed949c42d4d790266525d63bbdc" + integrity sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-transform-react-constant-elements@^7.18.12": + version "7.25.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.1.tgz#71a665ed16ce618067d05f4a98130207349d82ae" + integrity sha512-SLV/giH/V4SmloZ6Dt40HjTGTAIkxn33TVIHxNGNvo8ezMhrxBkzisj4op1KZYPIOHFLqhv60OHvX+YRu4xbmQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.8" "@babel/plugin-transform-react-display-name@^7.18.6": version "7.18.6" @@ -1234,125 +1069,134 @@ "@babel/helper-annotate-as-pure" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-regenerator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz#585c66cb84d4b4bf72519a34cfce761b8676ca73" - integrity sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ== +"@babel/plugin-transform-regenerator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz#021562de4534d8b4b1851759fd7af4e05d2c47f8" + integrity sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - regenerator-transform "^0.15.0" + "@babel/helper-plugin-utils" "^7.24.7" + regenerator-transform "^0.15.2" -"@babel/plugin-transform-reserved-words@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a" - integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== +"@babel/plugin-transform-reserved-words@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz#80037fe4fbf031fc1125022178ff3938bb3743a4" + integrity sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-transform-runtime@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.6.tgz#77b14416015ea93367ca06979710f5000ff34ccb" - integrity sha512-8uRHk9ZmRSnWqUgyae249EJZ94b0yAGLBIqzZzl+0iEdbno55Pmlt/32JZsHwXD9k/uZj18Aqqk35wBX4CBTXA== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.7.tgz#00a5bfaf8c43cf5c8703a8a6e82b59d9c58f38ca" + integrity sha512-YqXjrk4C+a1kZjewqt+Mmu2UuV1s07y8kqcUf4qYLnoqemhR4gRQikhdAhSVJioMjVTu6Mo6pAbaypEA3jY6fw== dependencies: - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - babel-plugin-polyfill-corejs2 "^0.3.1" - babel-plugin-polyfill-corejs3 "^0.5.2" - babel-plugin-polyfill-regenerator "^0.3.1" - semver "^6.3.0" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + babel-plugin-polyfill-corejs2 "^0.4.10" + babel-plugin-polyfill-corejs3 "^0.10.1" + babel-plugin-polyfill-regenerator "^0.6.1" + semver "^6.3.1" -"@babel/plugin-transform-shorthand-properties@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" - integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== +"@babel/plugin-transform-shorthand-properties@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz#85448c6b996e122fa9e289746140aaa99da64e73" + integrity sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-spread@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.6.tgz#82b080241965f1689f0a60ecc6f1f6575dbdb9d6" - integrity sha512-ayT53rT/ENF8WWexIRg9AiV9h0aIteyWn5ptfZTZQrjk/+f3WdrJGCY4c9wcgl2+MKkKPhzbYp97FTsquZpDCw== +"@babel/plugin-transform-spread@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz#e8a38c0fde7882e0fb8f160378f74bd885cc7bb3" + integrity sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-skip-transparent-expression-wrappers" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" -"@babel/plugin-transform-sticky-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc" - integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== +"@babel/plugin-transform-sticky-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz#96ae80d7a7e5251f657b5cf18f1ea6bf926f5feb" + integrity sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-template-literals@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.6.tgz#b763f4dc9d11a7cce58cf9a490d82e80547db9c2" - integrity sha512-UuqlRrQmT2SWRvahW46cGSany0uTlcj8NYOS5sRGYi8FxPYPoLd5DDmMd32ZXEj2Jq+06uGVQKHxa/hJx2EzKw== +"@babel/plugin-transform-template-literals@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz#a05debb4a9072ae8f985bcf77f3f215434c8f8c8" + integrity sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-typeof-symbol@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.6.tgz#486bb39d5a18047358e0d04dc0d2f322f0b92e92" - integrity sha512-7m71iS/QhsPk85xSjFPovHPcH3H9qeyzsujhTc+vcdnsXavoWYJ74zx0lP5RhpC5+iDnVLO+PPMHzC11qels1g== +"@babel/plugin-transform-typeof-symbol@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz#383dab37fb073f5bfe6e60c654caac309f92ba1c" + integrity sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-transform-typescript@^7.18.6": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.8.tgz#303feb7a920e650f2213ef37b36bbf327e6fa5a0" - integrity sha512-p2xM8HI83UObjsZGofMV/EdYjamsDm6MoN3hXPYIT0+gxIoopE+B7rPYKAxfrz9K9PK7JafTTjqYC6qipLExYA== +"@babel/plugin-transform-typescript@^7.24.7": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.2.tgz#237c5d10de6d493be31637c6b9fa30b6c5461add" + integrity sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A== dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-typescript" "^7.18.6" + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-create-class-features-plugin" "^7.25.0" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" + "@babel/plugin-syntax-typescript" "^7.24.7" -"@babel/plugin-transform-unicode-escapes@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz#0d01fb7fb2243ae1c033f65f6e3b4be78db75f27" - integrity sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw== +"@babel/plugin-transform-unicode-escapes@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz#2023a82ced1fb4971630a2e079764502c4148e0e" + integrity sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-unicode-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca" - integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== +"@babel/plugin-transform-unicode-property-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz#9073a4cd13b86ea71c3264659590ac086605bbcd" + integrity sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-create-regexp-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/preset-env@^7.15.6", "@babel/preset-env@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.18.6.tgz#953422e98a5f66bc56cd0b9074eaea127ec86ace" - integrity sha512-WrthhuIIYKrEFAwttYzgRNQ5hULGmwTj+D6l7Zdfsv5M7IWV/OZbUfbeL++Qrzx1nVJwWROIFhCHRYQV4xbPNw== +"@babel/plugin-transform-unicode-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz#dfc3d4a51127108099b19817c0963be6a2adf19f" + integrity sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg== dependencies: - "@babel/compat-data" "^7.18.6" - "@babel/helper-compilation-targets" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-validator-option" "^7.18.6" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.6" - "@babel/plugin-proposal-async-generator-functions" "^7.18.6" - "@babel/plugin-proposal-class-properties" "^7.18.6" - "@babel/plugin-proposal-class-static-block" "^7.18.6" - "@babel/plugin-proposal-dynamic-import" "^7.18.6" - "@babel/plugin-proposal-export-namespace-from" "^7.18.6" - "@babel/plugin-proposal-json-strings" "^7.18.6" - "@babel/plugin-proposal-logical-assignment-operators" "^7.18.6" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" - "@babel/plugin-proposal-numeric-separator" "^7.18.6" - "@babel/plugin-proposal-object-rest-spread" "^7.18.6" - "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" - "@babel/plugin-proposal-optional-chaining" "^7.18.6" - "@babel/plugin-proposal-private-methods" "^7.18.6" - "@babel/plugin-proposal-private-property-in-object" "^7.18.6" - "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" + "@babel/helper-create-regexp-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-transform-unicode-sets-regex@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz#d40705d67523803a576e29c63cef6e516b858ed9" + integrity sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/preset-env@^7.18.6", "@babel/preset-env@^7.19.4": + version "7.25.3" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.25.3.tgz#0bf4769d84ac51d1073ab4a86f00f30a3a83c67c" + integrity sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g== + dependencies: + "@babel/compat-data" "^7.25.2" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-validator-option" "^7.24.8" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.25.3" + "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.25.0" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.25.0" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.24.7" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.25.0" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" "@babel/plugin-syntax-class-static-block" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-import-assertions" "^7.18.6" + "@babel/plugin-syntax-import-assertions" "^7.24.7" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" @@ -1362,58 +1206,73 @@ "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.18.6" - "@babel/plugin-transform-async-to-generator" "^7.18.6" - "@babel/plugin-transform-block-scoped-functions" "^7.18.6" - "@babel/plugin-transform-block-scoping" "^7.18.6" - "@babel/plugin-transform-classes" "^7.18.6" - "@babel/plugin-transform-computed-properties" "^7.18.6" - "@babel/plugin-transform-destructuring" "^7.18.6" - "@babel/plugin-transform-dotall-regex" "^7.18.6" - "@babel/plugin-transform-duplicate-keys" "^7.18.6" - "@babel/plugin-transform-exponentiation-operator" "^7.18.6" - "@babel/plugin-transform-for-of" "^7.18.6" - "@babel/plugin-transform-function-name" "^7.18.6" - "@babel/plugin-transform-literals" "^7.18.6" - "@babel/plugin-transform-member-expression-literals" "^7.18.6" - "@babel/plugin-transform-modules-amd" "^7.18.6" - "@babel/plugin-transform-modules-commonjs" "^7.18.6" - "@babel/plugin-transform-modules-systemjs" "^7.18.6" - "@babel/plugin-transform-modules-umd" "^7.18.6" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.18.6" - "@babel/plugin-transform-new-target" "^7.18.6" - "@babel/plugin-transform-object-super" "^7.18.6" - "@babel/plugin-transform-parameters" "^7.18.6" - "@babel/plugin-transform-property-literals" "^7.18.6" - "@babel/plugin-transform-regenerator" "^7.18.6" - "@babel/plugin-transform-reserved-words" "^7.18.6" - "@babel/plugin-transform-shorthand-properties" "^7.18.6" - "@babel/plugin-transform-spread" "^7.18.6" - "@babel/plugin-transform-sticky-regex" "^7.18.6" - "@babel/plugin-transform-template-literals" "^7.18.6" - "@babel/plugin-transform-typeof-symbol" "^7.18.6" - "@babel/plugin-transform-unicode-escapes" "^7.18.6" - "@babel/plugin-transform-unicode-regex" "^7.18.6" - "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.18.6" - babel-plugin-polyfill-corejs2 "^0.3.1" - babel-plugin-polyfill-corejs3 "^0.5.2" - babel-plugin-polyfill-regenerator "^0.3.1" - core-js-compat "^3.22.1" - semver "^6.3.0" - -"@babel/preset-modules@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" - integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.24.7" + "@babel/plugin-transform-async-generator-functions" "^7.25.0" + "@babel/plugin-transform-async-to-generator" "^7.24.7" + "@babel/plugin-transform-block-scoped-functions" "^7.24.7" + "@babel/plugin-transform-block-scoping" "^7.25.0" + "@babel/plugin-transform-class-properties" "^7.24.7" + "@babel/plugin-transform-class-static-block" "^7.24.7" + "@babel/plugin-transform-classes" "^7.25.0" + "@babel/plugin-transform-computed-properties" "^7.24.7" + "@babel/plugin-transform-destructuring" "^7.24.8" + "@babel/plugin-transform-dotall-regex" "^7.24.7" + "@babel/plugin-transform-duplicate-keys" "^7.24.7" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.25.0" + "@babel/plugin-transform-dynamic-import" "^7.24.7" + "@babel/plugin-transform-exponentiation-operator" "^7.24.7" + "@babel/plugin-transform-export-namespace-from" "^7.24.7" + "@babel/plugin-transform-for-of" "^7.24.7" + "@babel/plugin-transform-function-name" "^7.25.1" + "@babel/plugin-transform-json-strings" "^7.24.7" + "@babel/plugin-transform-literals" "^7.25.2" + "@babel/plugin-transform-logical-assignment-operators" "^7.24.7" + "@babel/plugin-transform-member-expression-literals" "^7.24.7" + "@babel/plugin-transform-modules-amd" "^7.24.7" + "@babel/plugin-transform-modules-commonjs" "^7.24.8" + "@babel/plugin-transform-modules-systemjs" "^7.25.0" + "@babel/plugin-transform-modules-umd" "^7.24.7" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.24.7" + "@babel/plugin-transform-new-target" "^7.24.7" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.24.7" + "@babel/plugin-transform-numeric-separator" "^7.24.7" + "@babel/plugin-transform-object-rest-spread" "^7.24.7" + "@babel/plugin-transform-object-super" "^7.24.7" + "@babel/plugin-transform-optional-catch-binding" "^7.24.7" + "@babel/plugin-transform-optional-chaining" "^7.24.8" + "@babel/plugin-transform-parameters" "^7.24.7" + "@babel/plugin-transform-private-methods" "^7.24.7" + "@babel/plugin-transform-private-property-in-object" "^7.24.7" + "@babel/plugin-transform-property-literals" "^7.24.7" + "@babel/plugin-transform-regenerator" "^7.24.7" + "@babel/plugin-transform-reserved-words" "^7.24.7" + "@babel/plugin-transform-shorthand-properties" "^7.24.7" + "@babel/plugin-transform-spread" "^7.24.7" + "@babel/plugin-transform-sticky-regex" "^7.24.7" + "@babel/plugin-transform-template-literals" "^7.24.7" + "@babel/plugin-transform-typeof-symbol" "^7.24.8" + "@babel/plugin-transform-unicode-escapes" "^7.24.7" + "@babel/plugin-transform-unicode-property-regex" "^7.24.7" + "@babel/plugin-transform-unicode-regex" "^7.24.7" + "@babel/plugin-transform-unicode-sets-regex" "^7.24.7" + "@babel/preset-modules" "0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2 "^0.4.10" + babel-plugin-polyfill-corejs3 "^0.10.4" + babel-plugin-polyfill-regenerator "^0.6.1" + core-js-compat "^3.37.1" + semver "^6.3.1" + +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@^7.14.5", "@babel/preset-react@^7.18.6": +"@babel/preset-react@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d" integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg== @@ -1425,47 +1284,52 @@ "@babel/plugin-transform-react-jsx-development" "^7.18.6" "@babel/plugin-transform-react-pure-annotations" "^7.18.6" -"@babel/preset-typescript@^7.15.0", "@babel/preset-typescript@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz#ce64be3e63eddc44240c6358daefac17b3186399" - integrity sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ== +"@babel/preset-typescript@^7.18.6": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz#66cd86ea8f8c014855671d5ea9a737139cbbfef1" + integrity sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-validator-option" "^7.18.6" - "@babel/plugin-transform-typescript" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-validator-option" "^7.24.7" + "@babel/plugin-syntax-jsx" "^7.24.7" + "@babel/plugin-transform-modules-commonjs" "^7.24.7" + "@babel/plugin-transform-typescript" "^7.24.7" + +"@babel/regjsgen@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" + integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== "@babel/runtime-corejs3@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.18.6.tgz#6f02c5536911f4b445946a2179554b95c8838635" - integrity sha512-cOu5wH2JFBgMjje+a+fz2JNIWU4GzYpl05oSob3UDvBEh6EuIn+TXFHMmBbhSb+k/4HMzgKCQfEEDArAWNF9Cw== + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.25.0.tgz#0a318b66dfc765ad10562d829fea372ed7e1eb7d" + integrity sha512-BOehWE7MgQ8W8Qn0CQnMtg2tHPHPulcS/5AVpFvs2KCK1ET+0WqZqPvnpRpFN81gYoFopdIEJX9Sgjw3ZBccPg== dependencies: - core-js-pure "^3.20.2" - regenerator-runtime "^0.13.4" + core-js-pure "^3.30.2" + regenerator-runtime "^0.14.0" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.6", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.12.7", "@babel/template@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== +"@babel/runtime@^7.18.6", "@babel/runtime@^7.20.13": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" + integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" + regenerator-runtime "^0.14.0" -"@babel/template@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31" - integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw== +"@babel/template@^7.12.7", "@babel/template@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" + integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.18.6" - "@babel/types" "^7.18.6" + "@babel/code-frame" "^7.24.7" + "@babel/parser" "^7.25.0" + "@babel/types" "^7.25.0" "@babel/template@^7.24.7": version "7.24.7" @@ -1476,31 +1340,29 @@ "@babel/parser" "^7.24.7" "@babel/types" "^7.24.7" -"@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.18.6", "@babel/traverse@^7.18.8": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.7.tgz#de2b900163fa741721ba382163fe46a936c40cf5" - integrity sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA== +"@babel/traverse@^7.12.9", "@babel/traverse@^7.18.8", "@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.1", "@babel/traverse@^7.25.2", "@babel/traverse@^7.25.3": + version "7.25.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.3.tgz#f1b901951c83eda2f3e29450ce92743783373490" + integrity sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ== dependencies: "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.24.7" - "@babel/helper-environment-visitor" "^7.24.7" - "@babel/helper-function-name" "^7.24.7" - "@babel/helper-hoist-variables" "^7.24.7" - "@babel/helper-split-export-declaration" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/parser" "^7.25.3" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.2" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.12.7", "@babel/types@^7.15.6", "@babel/types@^7.16.7", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.4.4": - version "7.18.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" - integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== +"@babel/types@^7.12.7", "@babel/types@^7.20.0", "@babel/types@^7.24.8", "@babel/types@^7.25.0", "@babel/types@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.2.tgz#55fb231f7dc958cd69ea141a4c2997e819646125" + integrity sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q== dependencies: - "@babel/helper-validator-identifier" "^7.16.7" + "@babel/helper-string-parser" "^7.24.8" + "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" -"@babel/types@^7.18.6", "@babel/types@^7.18.7", "@babel/types@^7.18.8": +"@babel/types@^7.18.6": version "7.18.8" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.8.tgz#c5af199951bf41ba4a6a9a6d0d8ad722b30cd42f" integrity sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw== @@ -1517,39 +1379,63 @@ "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" +"@babel/types@^7.4.4": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" + integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== +"@crowdin/cli@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@crowdin/cli/-/cli-4.1.1.tgz#1a2067e79a53639920121870ae488a38dd2513ff" + integrity sha512-OC5xJgaXM9eC9UgiAV17HZrCDP1gM1gs2yMdSRFjM6ydu9LddybntMKgWU3ffRHjCjK6wDTrC31jo932Czrs+A== + dependencies: + command-exists-promise "^2.0.2" + node-fetch "2.7.0" + shelljs "^0.8.5" + tar "^6.2.0" + yauzl "^3.1.0" + "@discordapp/twemoji@discord/twemoji": - version "14.1.2" - resolved "https://codeload.github.com/discord/twemoji/tar.gz/c9fb242544b5f9068221d3baadb3b5d7ec9727c0" + version "15.1.0" + resolved "https://codeload.github.com/discord/twemoji/tar.gz/55b2a25fa9742c96b0132eccb9241dff869b8562" dependencies: + "@twemoji/parser" "15.1.0" fs-extra "^8.0.1" jsonfile "^5.0.0" - twemoji-parser "14.0.0" universalify "^0.1.2" -"@docsearch/css@3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.1.1.tgz#e0976bf995e383f8ee8657306311b9cb95016330" - integrity sha512-utLgg7E1agqQeqCJn05DWC7XXMk4tMUUnL7MZupcknRu2OzGN13qwey2qA/0NAKkVBGugiWtON0+rlU0QIPojg== +"@discoveryjs/json-ext@0.5.7": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@docsearch/css@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.6.1.tgz#f0a728ecb486c81f2d282650fc1820c914913408" + integrity sha512-VtVb5DS+0hRIprU2CO6ZQjK2Zg4QU5HrDM1+ix6rT0umsYvFvatMAnf97NHZlVWDaaLlx7GRfR/7FikANiM2Fg== "@docsearch/react@^3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.1.1.tgz#3dffb5db8cf9eb95d6e732cf038264bfc10191ed" - integrity sha512-cfoql4qvtsVRqBMYxhlGNpvyy/KlCoPqjIsJSZYqYf9AplZncKjLBTcwBu6RXFMVCe30cIFljniI4OjqAU67pQ== + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.6.1.tgz#0f826df08693293806d64277d6d9c38636211b97" + integrity sha512-qXZkEPvybVhSXj0K7U3bXc233tk5e8PfhoZ6MhPOiik/qUQxYC+Dn9DnoS7CxHQQhHfCvTiN0eY9M12oRghEXw== dependencies: - "@algolia/autocomplete-core" "1.7.1" - "@algolia/autocomplete-preset-algolia" "1.7.1" - "@docsearch/css" "3.1.1" - algoliasearch "^4.0.0" + "@algolia/autocomplete-core" "1.9.3" + "@algolia/autocomplete-preset-algolia" "1.9.3" + "@docsearch/css" "3.6.1" + algoliasearch "^4.19.1" -"@docusaurus/core@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.4.1.tgz#4b8ff5766131ce3fbccaad0b1daf2ad4dc76f62d" - integrity sha512-SNsY7PshK3Ri7vtsLXVeAJGS50nJN3RgF836zkyUfAD01Fq+sAk5EwWgLw+nnm5KVNGDu7PRR2kRGDsWvqpo0g== +"@docusaurus/core@2.4.3", "@docusaurus/core@^2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.4.3.tgz#d86624901386fd8164ce4bff9cc7f16fde57f523" + integrity sha512-dWH5P7cgeNSIg9ufReX6gaCl/TmrGKD38Orbwuz05WPhAQtFXHd5B8Qym1TiXfvUNvwoYKkAJOJuGe8ou0Z7PA== dependencies: "@babel/core" "^7.18.6" "@babel/generator" "^7.18.7" @@ -1561,13 +1447,13 @@ "@babel/runtime" "^7.18.6" "@babel/runtime-corejs3" "^7.18.6" "@babel/traverse" "^7.18.8" - "@docusaurus/cssnano-preset" "2.4.1" - "@docusaurus/logger" "2.4.1" - "@docusaurus/mdx-loader" "2.4.1" + "@docusaurus/cssnano-preset" "2.4.3" + "@docusaurus/logger" "2.4.3" + "@docusaurus/mdx-loader" "2.4.3" "@docusaurus/react-loadable" "5.5.2" - "@docusaurus/utils" "2.4.1" - "@docusaurus/utils-common" "2.4.1" - "@docusaurus/utils-validation" "2.4.1" + "@docusaurus/utils" "2.4.3" + "@docusaurus/utils-common" "2.4.3" + "@docusaurus/utils-validation" "2.4.3" "@slorber/static-site-generator-webpack-plugin" "^4.0.7" "@svgr/webpack" "^6.2.1" autoprefixer "^10.4.7" @@ -1623,33 +1509,33 @@ webpack-merge "^5.8.0" webpackbar "^5.0.2" -"@docusaurus/cssnano-preset@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.1.tgz#eacadefb1e2e0f59df3467a0fe83e4ff79eed163" - integrity sha512-ka+vqXwtcW1NbXxWsh6yA1Ckii1klY9E53cJ4O9J09nkMBgrNX3iEFED1fWdv8wf4mJjvGi5RLZ2p9hJNjsLyQ== +"@docusaurus/cssnano-preset@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.3.tgz#1d7e833c41ce240fcc2812a2ac27f7b862f32de0" + integrity sha512-ZvGSRCi7z9wLnZrXNPG6DmVPHdKGd8dIn9pYbEOFiYihfv4uDR3UtxogmKf+rT8ZlKFf5Lqne8E8nt08zNM8CA== dependencies: cssnano-preset-advanced "^5.3.8" postcss "^8.4.14" postcss-sort-media-queries "^4.2.1" tslib "^2.4.0" -"@docusaurus/logger@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.4.1.tgz#4d2c0626b40752641f9fdd93ad9b5a7a0792f767" - integrity sha512-5h5ysIIWYIDHyTVd8BjheZmQZmEgWDR54aQ1BX9pjFfpyzFo5puKXKYrYJXbjEHGyVhEzmB9UXwbxGfaZhOjcg== +"@docusaurus/logger@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.4.3.tgz#518bbc965fb4ebe8f1d0b14e5f4161607552d34c" + integrity sha512-Zxws7r3yLufk9xM1zq9ged0YHs65mlRmtsobnFkdZTxWXdTYlWWLWdKyNKAsVC+D7zg+pv2fGbyabdOnyZOM3w== dependencies: chalk "^4.1.2" tslib "^2.4.0" -"@docusaurus/mdx-loader@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.4.1.tgz#6425075d7fc136dbfdc121349060cedd64118393" - integrity sha512-4KhUhEavteIAmbBj7LVFnrVYDiU51H5YWW1zY6SmBSte/YLhDutztLTBE0PQl1Grux1jzUJeaSvAzHpTn6JJDQ== +"@docusaurus/mdx-loader@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.4.3.tgz#e8ff37f30a060eaa97b8121c135f74cb531a4a3e" + integrity sha512-b1+fDnWtl3GiqkL0BRjYtc94FZrcDDBV1j8446+4tptB9BAOlePwG2p/pK6vGvfL53lkOsszXMghr2g67M0vCw== dependencies: "@babel/parser" "^7.18.8" "@babel/traverse" "^7.18.8" - "@docusaurus/logger" "2.4.1" - "@docusaurus/utils" "2.4.1" + "@docusaurus/logger" "2.4.3" + "@docusaurus/utils" "2.4.3" "@mdx-js/mdx" "^1.6.22" escape-html "^1.0.3" file-loader "^6.2.0" @@ -1664,13 +1550,13 @@ url-loader "^4.1.1" webpack "^5.73.0" -"@docusaurus/module-type-aliases@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.1.tgz#38b3c2d2ae44bea6d57506eccd84280216f0171c" - integrity sha512-gLBuIFM8Dp2XOCWffUDSjtxY7jQgKvYujt7Mx5s4FCTfoL5dN1EVbnrn+O2Wvh8b0a77D57qoIDY7ghgmatR1A== +"@docusaurus/module-type-aliases@2.4.3", "@docusaurus/module-type-aliases@^2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.3.tgz#d08ef67e4151e02f352a2836bcf9ecde3b9c56ac" + integrity sha512-cwkBkt1UCiduuvEAo7XZY01dJfRn7UR/75mBgOdb1hKknhrabJZ8YH+7savd/y9kLExPyrhe0QwdS9GuzsRRIA== dependencies: "@docusaurus/react-loadable" "5.5.2" - "@docusaurus/types" "2.4.1" + "@docusaurus/types" "2.4.3" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" @@ -1678,18 +1564,18 @@ react-helmet-async "*" react-loadable "npm:@docusaurus/react-loadable@5.5.2" -"@docusaurus/plugin-content-blog@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.1.tgz#c705a8b1a36a34f181dcf43b7770532e4dcdc4a3" - integrity sha512-E2i7Knz5YIbE1XELI6RlTnZnGgS52cUO4BlCiCUCvQHbR+s1xeIWz4C6BtaVnlug0Ccz7nFSksfwDpVlkujg5Q== - dependencies: - "@docusaurus/core" "2.4.1" - "@docusaurus/logger" "2.4.1" - "@docusaurus/mdx-loader" "2.4.1" - "@docusaurus/types" "2.4.1" - "@docusaurus/utils" "2.4.1" - "@docusaurus/utils-common" "2.4.1" - "@docusaurus/utils-validation" "2.4.1" +"@docusaurus/plugin-content-blog@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.3.tgz#6473b974acab98e967414d8bbb0d37e0cedcea14" + integrity sha512-PVhypqaA0t98zVDpOeTqWUTvRqCEjJubtfFUQ7zJNYdbYTbS/E/ytq6zbLVsN/dImvemtO/5JQgjLxsh8XLo8Q== + dependencies: + "@docusaurus/core" "2.4.3" + "@docusaurus/logger" "2.4.3" + "@docusaurus/mdx-loader" "2.4.3" + "@docusaurus/types" "2.4.3" + "@docusaurus/utils" "2.4.3" + "@docusaurus/utils-common" "2.4.3" + "@docusaurus/utils-validation" "2.4.3" cheerio "^1.0.0-rc.12" feed "^4.2.2" fs-extra "^10.1.0" @@ -1700,18 +1586,18 @@ utility-types "^3.10.0" webpack "^5.73.0" -"@docusaurus/plugin-content-docs@2.4.1", "@docusaurus/plugin-content-docs@^2.0.0-beta.20": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.1.tgz#ed94d9721b5ce7a956fb01cc06c40d8eee8dfca7" - integrity sha512-Lo7lSIcpswa2Kv4HEeUcGYqaasMUQNpjTXpV0N8G6jXgZaQurqp7E8NGYeGbDXnb48czmHWbzDL4S3+BbK0VzA== - dependencies: - "@docusaurus/core" "2.4.1" - "@docusaurus/logger" "2.4.1" - "@docusaurus/mdx-loader" "2.4.1" - "@docusaurus/module-type-aliases" "2.4.1" - "@docusaurus/types" "2.4.1" - "@docusaurus/utils" "2.4.1" - "@docusaurus/utils-validation" "2.4.1" +"@docusaurus/plugin-content-docs@2.4.3", "@docusaurus/plugin-content-docs@^2.0.0-rc.1": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.3.tgz#aa224c0512351e81807adf778ca59fd9cd136973" + integrity sha512-N7Po2LSH6UejQhzTCsvuX5NOzlC+HiXOVvofnEPj0WhMu1etpLEXE6a4aTxrtg95lQ5kf0xUIdjX9sh3d3G76A== + dependencies: + "@docusaurus/core" "2.4.3" + "@docusaurus/logger" "2.4.3" + "@docusaurus/mdx-loader" "2.4.3" + "@docusaurus/module-type-aliases" "2.4.3" + "@docusaurus/types" "2.4.3" + "@docusaurus/utils" "2.4.3" + "@docusaurus/utils-validation" "2.4.3" "@types/react-router-config" "^5.0.6" combine-promises "^1.1.0" fs-extra "^10.1.0" @@ -1722,95 +1608,95 @@ utility-types "^3.10.0" webpack "^5.73.0" -"@docusaurus/plugin-content-pages@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.1.tgz#c534f7e49967699a45bbe67050d1605ebbf3d285" - integrity sha512-/UjuH/76KLaUlL+o1OvyORynv6FURzjurSjvn2lbWTFc4tpYY2qLYTlKpTCBVPhlLUQsfyFnshEJDLmPneq2oA== - dependencies: - "@docusaurus/core" "2.4.1" - "@docusaurus/mdx-loader" "2.4.1" - "@docusaurus/types" "2.4.1" - "@docusaurus/utils" "2.4.1" - "@docusaurus/utils-validation" "2.4.1" +"@docusaurus/plugin-content-pages@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.3.tgz#7f285e718b53da8c8d0101e70840c75b9c0a1ac0" + integrity sha512-txtDVz7y3zGk67q0HjG0gRttVPodkHqE0bpJ+7dOaTH40CQFLSh7+aBeGnPOTl+oCPG+hxkim4SndqPqXjQ8Bg== + dependencies: + "@docusaurus/core" "2.4.3" + "@docusaurus/mdx-loader" "2.4.3" + "@docusaurus/types" "2.4.3" + "@docusaurus/utils" "2.4.3" + "@docusaurus/utils-validation" "2.4.3" fs-extra "^10.1.0" tslib "^2.4.0" webpack "^5.73.0" -"@docusaurus/plugin-debug@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.4.1.tgz#461a2c77b0c5a91b2c05257c8f9585412aaa59dc" - integrity sha512-7Yu9UPzRShlrH/G8btOpR0e6INFZr0EegWplMjOqelIwAcx3PKyR8mgPTxGTxcqiYj6hxSCRN0D8R7YrzImwNA== +"@docusaurus/plugin-debug@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.4.3.tgz#2f90eb0c9286a9f225444e3a88315676fe02c245" + integrity sha512-LkUbuq3zCmINlFb+gAd4ZvYr+bPAzMC0hwND4F7V9bZ852dCX8YoWyovVUBKq4er1XsOwSQaHmNGtObtn8Av8Q== dependencies: - "@docusaurus/core" "2.4.1" - "@docusaurus/types" "2.4.1" - "@docusaurus/utils" "2.4.1" + "@docusaurus/core" "2.4.3" + "@docusaurus/types" "2.4.3" + "@docusaurus/utils" "2.4.3" fs-extra "^10.1.0" react-json-view "^1.21.3" tslib "^2.4.0" -"@docusaurus/plugin-google-analytics@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.1.tgz#30de1c35773bf9d52bb2d79b201b23eb98022613" - integrity sha512-dyZJdJiCoL+rcfnm0RPkLt/o732HvLiEwmtoNzOoz9MSZz117UH2J6U2vUDtzUzwtFLIf32KkeyzisbwUCgcaQ== +"@docusaurus/plugin-google-analytics@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.3.tgz#0d19993136ade6f7a7741251b4f617400d92ab45" + integrity sha512-KzBV3k8lDkWOhg/oYGxlK5o9bOwX7KpPc/FTWoB+SfKhlHfhq7qcQdMi1elAaVEIop8tgK6gD1E58Q+XC6otSQ== dependencies: - "@docusaurus/core" "2.4.1" - "@docusaurus/types" "2.4.1" - "@docusaurus/utils-validation" "2.4.1" + "@docusaurus/core" "2.4.3" + "@docusaurus/types" "2.4.3" + "@docusaurus/utils-validation" "2.4.3" tslib "^2.4.0" -"@docusaurus/plugin-google-gtag@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.1.tgz#6a3eb91022714735e625c7ca70ef5188fa7bd0dc" - integrity sha512-mKIefK+2kGTQBYvloNEKtDmnRD7bxHLsBcxgnbt4oZwzi2nxCGjPX6+9SQO2KCN5HZbNrYmGo5GJfMgoRvy6uA== +"@docusaurus/plugin-google-gtag@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.3.tgz#e1a80b0696771b488562e5b60eff21c9932d9e1c" + integrity sha512-5FMg0rT7sDy4i9AGsvJC71MQrqQZwgLNdDetLEGDHLfSHLvJhQbTCUGbGXknUgWXQJckcV/AILYeJy+HhxeIFA== dependencies: - "@docusaurus/core" "2.4.1" - "@docusaurus/types" "2.4.1" - "@docusaurus/utils-validation" "2.4.1" + "@docusaurus/core" "2.4.3" + "@docusaurus/types" "2.4.3" + "@docusaurus/utils-validation" "2.4.3" tslib "^2.4.0" -"@docusaurus/plugin-google-tag-manager@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.1.tgz#b99f71aec00b112bbf509ef2416e404a95eb607e" - integrity sha512-Zg4Ii9CMOLfpeV2nG74lVTWNtisFaH9QNtEw48R5QE1KIwDBdTVaiSA18G1EujZjrzJJzXN79VhINSbOJO/r3g== +"@docusaurus/plugin-google-tag-manager@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.3.tgz#e41fbf79b0ffc2de1cc4013eb77798cff0ad98e3" + integrity sha512-1jTzp71yDGuQiX9Bi0pVp3alArV0LSnHXempvQTxwCGAEzUWWaBg4d8pocAlTpbP9aULQQqhgzrs8hgTRPOM0A== dependencies: - "@docusaurus/core" "2.4.1" - "@docusaurus/types" "2.4.1" - "@docusaurus/utils-validation" "2.4.1" + "@docusaurus/core" "2.4.3" + "@docusaurus/types" "2.4.3" + "@docusaurus/utils-validation" "2.4.3" tslib "^2.4.0" -"@docusaurus/plugin-sitemap@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.1.tgz#8a7a76ed69dc3e6b4474b6abb10bb03336a9de6d" - integrity sha512-lZx+ijt/+atQ3FVE8FOHV/+X3kuok688OydDXrqKRJyXBJZKgGjA2Qa8RjQ4f27V2woaXhtnyrdPop/+OjVMRg== - dependencies: - "@docusaurus/core" "2.4.1" - "@docusaurus/logger" "2.4.1" - "@docusaurus/types" "2.4.1" - "@docusaurus/utils" "2.4.1" - "@docusaurus/utils-common" "2.4.1" - "@docusaurus/utils-validation" "2.4.1" +"@docusaurus/plugin-sitemap@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.3.tgz#1b3930900a8f89670ce7e8f83fb4730cd3298c32" + integrity sha512-LRQYrK1oH1rNfr4YvWBmRzTL0LN9UAPxBbghgeFRBm5yloF6P+zv1tm2pe2hQTX/QP5bSKdnajCvfnScgKXMZQ== + dependencies: + "@docusaurus/core" "2.4.3" + "@docusaurus/logger" "2.4.3" + "@docusaurus/types" "2.4.3" + "@docusaurus/utils" "2.4.3" + "@docusaurus/utils-common" "2.4.3" + "@docusaurus/utils-validation" "2.4.3" fs-extra "^10.1.0" sitemap "^7.1.1" tslib "^2.4.0" -"@docusaurus/preset-classic@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.4.1.tgz#072f22d0332588e9c5f512d4bded8d7c99f91497" - integrity sha512-P4//+I4zDqQJ+UDgoFrjIFaQ1MeS9UD1cvxVQaI6O7iBmiHQm0MGROP1TbE7HlxlDPXFJjZUK3x3cAoK63smGQ== - dependencies: - "@docusaurus/core" "2.4.1" - "@docusaurus/plugin-content-blog" "2.4.1" - "@docusaurus/plugin-content-docs" "2.4.1" - "@docusaurus/plugin-content-pages" "2.4.1" - "@docusaurus/plugin-debug" "2.4.1" - "@docusaurus/plugin-google-analytics" "2.4.1" - "@docusaurus/plugin-google-gtag" "2.4.1" - "@docusaurus/plugin-google-tag-manager" "2.4.1" - "@docusaurus/plugin-sitemap" "2.4.1" - "@docusaurus/theme-classic" "2.4.1" - "@docusaurus/theme-common" "2.4.1" - "@docusaurus/theme-search-algolia" "2.4.1" - "@docusaurus/types" "2.4.1" +"@docusaurus/preset-classic@^2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.4.3.tgz#074c57ebf29fa43d23bd1c8ce691226f542bc262" + integrity sha512-tRyMliepY11Ym6hB1rAFSNGwQDpmszvWYJvlK1E+md4SW8i6ylNHtpZjaYFff9Mdk3i/Pg8ItQq9P0daOJAvQw== + dependencies: + "@docusaurus/core" "2.4.3" + "@docusaurus/plugin-content-blog" "2.4.3" + "@docusaurus/plugin-content-docs" "2.4.3" + "@docusaurus/plugin-content-pages" "2.4.3" + "@docusaurus/plugin-debug" "2.4.3" + "@docusaurus/plugin-google-analytics" "2.4.3" + "@docusaurus/plugin-google-gtag" "2.4.3" + "@docusaurus/plugin-google-tag-manager" "2.4.3" + "@docusaurus/plugin-sitemap" "2.4.3" + "@docusaurus/theme-classic" "2.4.3" + "@docusaurus/theme-common" "2.4.3" + "@docusaurus/theme-search-algolia" "2.4.3" + "@docusaurus/types" "2.4.3" "@docusaurus/react-loadable@5.5.2": version "5.5.2" @@ -1820,23 +1706,23 @@ "@types/react" "*" prop-types "^15.6.2" -"@docusaurus/theme-classic@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.4.1.tgz#0060cb263c1a73a33ac33f79bb6bc2a12a56ad9e" - integrity sha512-Rz0wKUa+LTW1PLXmwnf8mn85EBzaGSt6qamqtmnh9Hflkc+EqiYMhtUJeLdV+wsgYq4aG0ANc+bpUDpsUhdnwg== - dependencies: - "@docusaurus/core" "2.4.1" - "@docusaurus/mdx-loader" "2.4.1" - "@docusaurus/module-type-aliases" "2.4.1" - "@docusaurus/plugin-content-blog" "2.4.1" - "@docusaurus/plugin-content-docs" "2.4.1" - "@docusaurus/plugin-content-pages" "2.4.1" - "@docusaurus/theme-common" "2.4.1" - "@docusaurus/theme-translations" "2.4.1" - "@docusaurus/types" "2.4.1" - "@docusaurus/utils" "2.4.1" - "@docusaurus/utils-common" "2.4.1" - "@docusaurus/utils-validation" "2.4.1" +"@docusaurus/theme-classic@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.4.3.tgz#29360f2eb03a0e1686eb19668633ef313970ee8f" + integrity sha512-QKRAJPSGPfDY2yCiPMIVyr+MqwZCIV2lxNzqbyUW0YkrlmdzzP3WuQJPMGLCjWgQp/5c9kpWMvMxjhpZx1R32Q== + dependencies: + "@docusaurus/core" "2.4.3" + "@docusaurus/mdx-loader" "2.4.3" + "@docusaurus/module-type-aliases" "2.4.3" + "@docusaurus/plugin-content-blog" "2.4.3" + "@docusaurus/plugin-content-docs" "2.4.3" + "@docusaurus/plugin-content-pages" "2.4.3" + "@docusaurus/theme-common" "2.4.3" + "@docusaurus/theme-translations" "2.4.3" + "@docusaurus/types" "2.4.3" + "@docusaurus/utils" "2.4.3" + "@docusaurus/utils-common" "2.4.3" + "@docusaurus/utils-validation" "2.4.3" "@mdx-js/react" "^1.6.22" clsx "^1.2.1" copy-text-to-clipboard "^3.0.1" @@ -1851,18 +1737,18 @@ tslib "^2.4.0" utility-types "^3.10.0" -"@docusaurus/theme-common@2.4.1", "@docusaurus/theme-common@^2.0.0-beta.20": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.4.1.tgz#03e16f7aa96455e952f3243ac99757b01a3c83d4" - integrity sha512-G7Zau1W5rQTaFFB3x3soQoZpkgMbl/SYNG8PfMFIjKa3M3q8n0m/GRf5/H/e5BqOvt8c+ZWIXGCiz+kUCSHovA== - dependencies: - "@docusaurus/mdx-loader" "2.4.1" - "@docusaurus/module-type-aliases" "2.4.1" - "@docusaurus/plugin-content-blog" "2.4.1" - "@docusaurus/plugin-content-docs" "2.4.1" - "@docusaurus/plugin-content-pages" "2.4.1" - "@docusaurus/utils" "2.4.1" - "@docusaurus/utils-common" "2.4.1" +"@docusaurus/theme-common@2.4.3", "@docusaurus/theme-common@^2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.4.3.tgz#bb31d70b6b67d0bdef9baa343192dcec49946a2e" + integrity sha512-7KaDJBXKBVGXw5WOVt84FtN8czGWhM0lbyWEZXGp8AFfL6sZQfRTluFp4QriR97qwzSyOfQb+nzcDZZU4tezUw== + dependencies: + "@docusaurus/mdx-loader" "2.4.3" + "@docusaurus/module-type-aliases" "2.4.3" + "@docusaurus/plugin-content-blog" "2.4.3" + "@docusaurus/plugin-content-docs" "2.4.3" + "@docusaurus/plugin-content-pages" "2.4.3" + "@docusaurus/utils" "2.4.3" + "@docusaurus/utils-common" "2.4.3" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" @@ -1873,19 +1759,19 @@ use-sync-external-store "^1.2.0" utility-types "^3.10.0" -"@docusaurus/theme-search-algolia@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.1.tgz#906bd2cca3fced0241985ef502c892f58ff380fc" - integrity sha512-6BcqW2lnLhZCXuMAvPRezFs1DpmEKzXFKlYjruuas+Xy3AQeFzDJKTJFIm49N77WFCTyxff8d3E4Q9pi/+5McQ== +"@docusaurus/theme-search-algolia@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.3.tgz#32d4cbefc3deba4112068fbdb0bde11ac51ece53" + integrity sha512-jziq4f6YVUB5hZOB85ELATwnxBz/RmSLD3ksGQOLDPKVzat4pmI8tddNWtriPpxR04BNT+ZfpPUMFkNFetSW1Q== dependencies: "@docsearch/react" "^3.1.1" - "@docusaurus/core" "2.4.1" - "@docusaurus/logger" "2.4.1" - "@docusaurus/plugin-content-docs" "2.4.1" - "@docusaurus/theme-common" "2.4.1" - "@docusaurus/theme-translations" "2.4.1" - "@docusaurus/utils" "2.4.1" - "@docusaurus/utils-validation" "2.4.1" + "@docusaurus/core" "2.4.3" + "@docusaurus/logger" "2.4.3" + "@docusaurus/plugin-content-docs" "2.4.3" + "@docusaurus/theme-common" "2.4.3" + "@docusaurus/theme-translations" "2.4.3" + "@docusaurus/utils" "2.4.3" + "@docusaurus/utils-validation" "2.4.3" algoliasearch "^4.13.1" algoliasearch-helper "^3.10.0" clsx "^1.2.1" @@ -1895,26 +1781,18 @@ tslib "^2.4.0" utility-types "^3.10.0" -"@docusaurus/theme-translations@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.4.1.tgz#4d49df5865dae9ef4b98a19284ede62ae6f98726" - integrity sha512-T1RAGP+f86CA1kfE8ejZ3T3pUU3XcyvrGMfC/zxCtc2BsnoexuNI9Vk2CmuKCb+Tacvhxjv5unhxXce0+NKyvA== - dependencies: - fs-extra "^10.1.0" - tslib "^2.4.0" - -"@docusaurus/theme-translations@^2.0.0-beta.20": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.0.0-beta.21.tgz#5da60ffc58de256b96316c5e0fe2733c1e83f22c" - integrity sha512-dLVT9OIIBs6MpzMb1bAy+C0DPJK3e3DNctG+ES0EP45gzEqQxzs4IsghpT+QDaOsuhNnAlosgJpFWX3rqxF9xA== +"@docusaurus/theme-translations@2.4.3", "@docusaurus/theme-translations@^2.0.0-rc.1": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.4.3.tgz#91ac73fc49b8c652b7a54e88b679af57d6ac6102" + integrity sha512-H4D+lbZbjbKNS/Zw1Lel64PioUAIT3cLYYJLUf3KkuO/oc9e0QCVhIYVtUI2SfBCF2NNdlyhBDQEEMygsCedIg== dependencies: fs-extra "^10.1.0" tslib "^2.4.0" -"@docusaurus/types@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.4.1.tgz#d8e82f9e0f704984f98df1f93d6b4554d5458705" - integrity sha512-0R+cbhpMkhbRXX138UOc/2XZFF8hiZa6ooZAEEJFp5scytzCw4tC1gChMFXrpa3d2tYE6AX8IrOEpSonLmfQuQ== +"@docusaurus/types@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.4.3.tgz#4aead281ca09f721b3c0a9b926818450cfa3db31" + integrity sha512-W6zNLGQqfrp/EoPD0bhb9n7OobP+RHpmvVzpA+Z/IuU3Q63njJM24hmT0GYboovWcDtFmnIJC9wcyx4RVPQscw== dependencies: "@types/history" "^4.7.11" "@types/react" "*" @@ -1925,30 +1803,30 @@ webpack "^5.73.0" webpack-merge "^5.8.0" -"@docusaurus/utils-common@2.4.1", "@docusaurus/utils-common@^2.0.0-beta.20": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.4.1.tgz#7f72e873e49bd5179588869cc3ab7449a56aae63" - integrity sha512-bCVGdZU+z/qVcIiEQdyx0K13OC5mYwxhSuDUR95oFbKVuXYRrTVrwZIqQljuo1fyJvFTKHiL9L9skQOPokuFNQ== +"@docusaurus/utils-common@2.4.3", "@docusaurus/utils-common@^2.0.0-rc.1": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.4.3.tgz#30656c39ef1ce7e002af7ba39ea08330f58efcfb" + integrity sha512-/jascp4GbLQCPVmcGkPzEQjNaAk3ADVfMtudk49Ggb+131B1WDD6HqlSmDf8MxGdy7Dja2gc+StHf01kiWoTDQ== dependencies: tslib "^2.4.0" -"@docusaurus/utils-validation@2.4.1", "@docusaurus/utils-validation@^2.0.0-beta.20": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.4.1.tgz#19959856d4a886af0c5cfb357f4ef68b51151244" - integrity sha512-unII3hlJlDwZ3w8U+pMO3Lx3RhI4YEbY3YNsQj4yzrkZzlpqZOLuAiZK2JyULnD+TKbceKU0WyWkQXtYbLNDFA== +"@docusaurus/utils-validation@2.4.3", "@docusaurus/utils-validation@^2.0.0-rc.1": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.4.3.tgz#8122c394feef3e96c73f6433987837ec206a63fb" + integrity sha512-G2+Vt3WR5E/9drAobP+hhZQMaswRwDlp6qOMi7o7ZypB+VO7N//DZWhZEwhcRGepMDJGQEwtPv7UxtYwPL9PBw== dependencies: - "@docusaurus/logger" "2.4.1" - "@docusaurus/utils" "2.4.1" + "@docusaurus/logger" "2.4.3" + "@docusaurus/utils" "2.4.3" joi "^17.6.0" js-yaml "^4.1.0" tslib "^2.4.0" -"@docusaurus/utils@2.4.1", "@docusaurus/utils@^2.0.0-beta.20": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.4.1.tgz#9c5f76eae37b71f3819c1c1f0e26e6807c99a4fc" - integrity sha512-1lvEZdAQhKNht9aPXPoh69eeKnV0/62ROhQeFKKxmzd0zkcuE/Oc5Gpnt00y/f5bIsmOsYMY7Pqfm/5rteT5GA== +"@docusaurus/utils@2.4.3", "@docusaurus/utils@^2.0.0-rc.1": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.4.3.tgz#52b000d989380a2125831b84e3a7327bef471e89" + integrity sha512-fKcXsjrD86Smxv8Pt0TBFqYieZZCPh4cbf9oszUq/AMhZn3ujwpKaVYZACPX8mmjtYx0JOgNx52CREBfiGQB4A== dependencies: - "@docusaurus/logger" "2.4.1" + "@docusaurus/logger" "2.4.3" "@svgr/webpack" "^6.2.1" escape-string-regexp "^4.0.0" file-loader "^6.2.0" @@ -1973,17 +1851,16 @@ cssesc "^3.0.0" immediate "^3.2.3" -"@easyops-cn/docusaurus-search-local@0.27.1": - version "0.27.1" - resolved "https://registry.yarnpkg.com/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.27.1.tgz#7e5e6182a3afd11f91744555fa54a391c8de913b" - integrity sha512-eNGA28La4GCyscSOQsFPlLJuSNhVEAAV9XIB7CS+OYLQa116LgtuffbvZ7QlFok36J7M/f0z3uRjC0m5JyYOkQ== - dependencies: - "@docusaurus/plugin-content-docs" "^2.0.0-beta.20" - "@docusaurus/theme-common" "^2.0.0-beta.20" - "@docusaurus/theme-translations" "^2.0.0-beta.20" - "@docusaurus/utils" "^2.0.0-beta.20" - "@docusaurus/utils-common" "^2.0.0-beta.20" - "@docusaurus/utils-validation" "^2.0.0-beta.20" +"@easyops-cn/docusaurus-search-local@^0.36.0": + version "0.36.0" + resolved "https://registry.yarnpkg.com/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.36.0.tgz#5f76abbaac2a97b2d58116fee1bda308b4e2a5f5" + integrity sha512-4R8tLYQc1aLTJcqIYHd7Np/wh6/psfHmGbNuJMwAFW7bJ6KyStlagBdXzv3k3SCqpo5emW2IUNYmHmN+8xvB6A== + dependencies: + "@docusaurus/plugin-content-docs" "^2.0.0-rc.1" + "@docusaurus/theme-translations" "^2.0.0-rc.1" + "@docusaurus/utils" "^2.0.0-rc.1" + "@docusaurus/utils-common" "^2.0.0-rc.1" + "@docusaurus/utils-validation" "^2.0.0-rc.1" "@easyops-cn/autocomplete.js" "^0.38.1" "@node-rs/jieba" "^1.6.0" cheerio "^1.0.0-rc.3" @@ -1996,27 +1873,50 @@ mark.js "^8.11.1" tslib "^2.4.0" -"@hapi/hoek@^9.0.0": +"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== -"@hapi/topo@^5.0.0": +"@hapi/topo@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== dependencies: "@hapi/hoek" "^9.0.0" -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": +"@jridgewell/gen-mapping@^0.3.0": version "0.3.2" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== @@ -2034,7 +1934,7 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": +"@jridgewell/resolve-uri@^3.0.3": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== @@ -2044,11 +1944,6 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/set-array@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" - integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== - "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" @@ -2067,7 +1962,15 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + +"@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== @@ -2077,15 +1980,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/trace-mapping@^0.3.17": - version "0.3.18" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" - integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" - -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": +"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -2106,10 +2001,10 @@ resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== -"@matteusan/sentro@0.1.25": - version "0.1.25" - resolved "https://registry.yarnpkg.com/@matteusan/sentro/-/sentro-0.1.25.tgz#626f8795ada5f31a746acad80c4c49cc6134d879" - integrity sha512-WADroUoOEnbGBij9ZSJkGbYp2yiNVi6UJZymJsSVyo1zuekM1pIzKF8+nI31SGt5wS3ChmOOR5+w1Z7c6jg9TQ== +"@matteusan/sentro@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@matteusan/sentro/-/sentro-1.1.0.tgz#62cf846a1e1d28ab1ce3033388f658fb2b33c072" + integrity sha512-wp0knryAWX1nXigPtaYpUmAjU2BCggPETCXfSdEVXctPR+HeJMe2Op50Fmf2JdF/drgd5ShL+wsKhDQ5JZhWvA== "@mdx-js/mdx@^1.6.22": version "1.6.22" @@ -2251,48 +2146,88 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@npmcli/config@^4.0.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/config/-/config-4.1.0.tgz#5c92e5ded2a44baf76b94926646329c3b39e79b8" - integrity sha512-cPQmIQ2Q0vuOfrenrA3isikdMFMAHgzlXV+EmvZ8f2JeJsU5xTU2bG7ipXECiMvPF9nM+QDnMLuIg8QLw9H4xg== - dependencies: - "@npmcli/map-workspaces" "^2.0.2" - ini "^3.0.0" - mkdirp-infer-owner "^2.0.0" - nopt "^5.0.0" - proc-log "^2.0.0" - read-package-json-fast "^2.0.3" +"@npmcli/config@^8.0.0": + version "8.3.4" + resolved "https://registry.yarnpkg.com/@npmcli/config/-/config-8.3.4.tgz#e2712c2215bb2659f39718b23bf7401f9ac1da59" + integrity sha512-01rtHedemDNhUXdicU7s+QYz/3JyV5Naj84cvdXGH4mgCdL+agmSYaLF4LUG4vMCLzhBO8YtS0gPpH1FGvbgAw== + dependencies: + "@npmcli/map-workspaces" "^3.0.2" + "@npmcli/package-json" "^5.1.1" + ci-info "^4.0.0" + ini "^4.1.2" + nopt "^7.2.1" + proc-log "^4.2.0" semver "^7.3.5" - walk-up-path "^1.0.0" + walk-up-path "^3.0.1" + +"@npmcli/git@^5.0.0": + version "5.0.8" + resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-5.0.8.tgz#8ba3ff8724192d9ccb2735a2aa5380a992c5d3d1" + integrity sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ== + dependencies: + "@npmcli/promise-spawn" "^7.0.0" + ini "^4.1.3" + lru-cache "^10.0.1" + npm-pick-manifest "^9.0.0" + proc-log "^4.0.0" + promise-inflight "^1.0.1" + promise-retry "^2.0.1" + semver "^7.3.5" + which "^4.0.0" -"@npmcli/map-workspaces@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-2.0.3.tgz#2d3c75119ee53246e9aa75bc469a55281cd5f08f" - integrity sha512-X6suAun5QyupNM8iHkNPh0AHdRC2rb1W+MTdMvvA/2ixgmqZwlq5cGUBgmKHUHT2LgrkKJMAXbfAoTxOigpK8Q== +"@npmcli/map-workspaces@^3.0.2": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz#27dc06c20c35ef01e45a08909cab9cb3da08cea6" + integrity sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA== dependencies: - "@npmcli/name-from-folder" "^1.0.1" - glob "^8.0.1" - minimatch "^5.0.1" - read-package-json-fast "^2.0.3" - -"@npmcli/name-from-folder@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz#77ecd0a4fcb772ba6fe927e2e2e155fbec2e6b1a" - integrity sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA== + "@npmcli/name-from-folder" "^2.0.0" + glob "^10.2.2" + minimatch "^9.0.0" + read-package-json-fast "^3.0.0" -"@polka/url@^1.0.0-next.20": - version "1.0.0-next.21" - resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" - integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== +"@npmcli/name-from-folder@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz#c44d3a7c6d5c184bb6036f4d5995eee298945815" + integrity sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg== -"@sideway/address@^4.1.3": - version "4.1.4" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" - integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== +"@npmcli/package-json@^5.1.1": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@npmcli/package-json/-/package-json-5.2.0.tgz#a1429d3111c10044c7efbfb0fce9f2c501f4cfad" + integrity sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ== + dependencies: + "@npmcli/git" "^5.0.0" + glob "^10.2.2" + hosted-git-info "^7.0.0" + json-parse-even-better-errors "^3.0.0" + normalize-package-data "^6.0.0" + proc-log "^4.0.0" + semver "^7.5.3" + +"@npmcli/promise-spawn@^7.0.0": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz#1d53d34ffeb5d151bfa8ec661bcccda8bbdfd532" + integrity sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ== + dependencies: + which "^4.0.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@polka/url@^1.0.0-next.24": + version "1.0.0-next.25" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.25.tgz#f077fdc0b5d0078d30893396ff4827a13f99e817" + integrity sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ== + +"@sideway/address@^4.1.5": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" + integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== dependencies: "@hapi/hoek" "^9.0.0" -"@sideway/formula@^3.0.0": +"@sideway/formula@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f" integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== @@ -2302,6 +2237,11 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -2316,109 +2256,111 @@ p-map "^4.0.0" webpack-sources "^3.2.2" -"@svgr/babel-plugin-add-jsx-attribute@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.0.0.tgz#bd6d1ff32a31b82b601e73672a789cc41e84fe18" - integrity sha512-MdPdhdWLtQsjd29Wa4pABdhWbaRMACdM1h31BY+c6FghTZqNGT7pEYdBoaGeKtdTOBC/XNFQaKVj+r/Ei2ryWA== - -"@svgr/babel-plugin-remove-jsx-attribute@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.0.0.tgz#58654908beebfa069681a83332544b17e5237e89" - integrity sha512-aVdtfx9jlaaxc3unA6l+M9YRnKIZjOhQPthLKqmTXC8UVkBLDRGwPKo+r8n3VZN8B34+yVajzPTZ+ptTSuZZCw== - -"@svgr/babel-plugin-remove-jsx-empty-expression@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.0.0.tgz#d06dd6e8a8f603f92f9979bb9990a1f85a4f57ba" - integrity sha512-Ccj42ApsePD451AZJJf1QzTD1B/BOU392URJTeXFxSK709i0KUsGtbwyiqsKu7vsYxpTM0IA5clAKDyf9RCZyA== - -"@svgr/babel-plugin-replace-jsx-attribute-value@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.0.0.tgz#0b85837577b02c31c09c758a12932820f5245cee" - integrity sha512-88V26WGyt1Sfd1emBYmBJRWMmgarrExpKNVmI9vVozha4kqs6FzQJ/Kp5+EYli1apgX44518/0+t9+NU36lThQ== - -"@svgr/babel-plugin-svg-dynamic-title@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.0.0.tgz#28236ec26f7ab9d486a487d36ae52d58ba15676f" - integrity sha512-F7YXNLfGze+xv0KMQxrl2vkNbI9kzT9oDK55/kUuymh1ACyXkMV+VZWX1zEhSTfEKh7VkHVZGmVtHg8eTZ6PRg== - -"@svgr/babel-plugin-svg-em-dimensions@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.0.0.tgz#40267c5dea1b43c4f83a0eb6169e08b43d8bafce" - integrity sha512-+rghFXxdIqJNLQK08kwPBD3Z22/0b2tEZ9lKiL/yTfuyj1wW8HUXu4bo/XkogATIYuXSghVQOOCwURXzHGKyZA== - -"@svgr/babel-plugin-transform-react-native-svg@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.0.0.tgz#eb688d0a5f539e34d268d8a516e81f5d7fede7c9" - integrity sha512-VaphyHZ+xIKv5v0K0HCzyfAaLhPGJXSk2HkpYfXIOKb7DjLBv0soHDxNv6X0vr2titsxE7klb++u7iOf7TSrFQ== +"@svgr/babel-plugin-add-jsx-attribute@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz#74a5d648bd0347bda99d82409d87b8ca80b9a1ba" + integrity sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ== -"@svgr/babel-plugin-transform-svg-component@^6.2.0": - version "6.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.2.0.tgz#7ba61d9fc1fb42b0ba1a04e4630019fa7e993c4f" - integrity sha512-bhYIpsORb++wpsp91fymbFkf09Z/YEKR0DnFjxvN+8JHeCUD2unnh18jIMKnDJTWtvpTaGYPXELVe4OOzFI0xg== +"@svgr/babel-plugin-remove-jsx-attribute@*": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz#69177f7937233caca3a1afb051906698f2f59186" + integrity sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA== -"@svgr/babel-preset@^6.2.0": - version "6.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-6.2.0.tgz#1d3ad8c7664253a4be8e4a0f0e6872f30d8af627" - integrity sha512-4WQNY0J71JIaL03DRn0vLiz87JXx0b9dYm2aA8XHlQJQoixMl4r/soYHm8dsaJZ3jWtkCiOYy48dp9izvXhDkQ== - dependencies: - "@svgr/babel-plugin-add-jsx-attribute" "^6.0.0" - "@svgr/babel-plugin-remove-jsx-attribute" "^6.0.0" - "@svgr/babel-plugin-remove-jsx-empty-expression" "^6.0.0" - "@svgr/babel-plugin-replace-jsx-attribute-value" "^6.0.0" - "@svgr/babel-plugin-svg-dynamic-title" "^6.0.0" - "@svgr/babel-plugin-svg-em-dimensions" "^6.0.0" - "@svgr/babel-plugin-transform-react-native-svg" "^6.0.0" - "@svgr/babel-plugin-transform-svg-component" "^6.2.0" - -"@svgr/core@^6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@svgr/core/-/core-6.2.1.tgz#195de807a9f27f9e0e0d678e01084b05c54fdf61" - integrity sha512-NWufjGI2WUyrg46mKuySfviEJ6IxHUOm/8a3Ph38VCWSp+83HBraCQrpEM3F3dB6LBs5x8OElS8h3C0oOJaJAA== - dependencies: - "@svgr/plugin-jsx" "^6.2.1" +"@svgr/babel-plugin-remove-jsx-empty-expression@*": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz#c2c48104cfd7dcd557f373b70a56e9e3bdae1d44" + integrity sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA== + +"@svgr/babel-plugin-replace-jsx-attribute-value@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz#fb9d22ea26d2bc5e0a44b763d4c46d5d3f596c60" + integrity sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg== + +"@svgr/babel-plugin-svg-dynamic-title@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz#01b2024a2b53ffaa5efceaa0bf3e1d5a4c520ce4" + integrity sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw== + +"@svgr/babel-plugin-svg-em-dimensions@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz#dd3fa9f5b24eb4f93bcf121c3d40ff5facecb217" + integrity sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA== + +"@svgr/babel-plugin-transform-react-native-svg@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz#1d8e945a03df65b601551097d8f5e34351d3d305" + integrity sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg== + +"@svgr/babel-plugin-transform-svg-component@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz#48620b9e590e25ff95a80f811544218d27f8a250" + integrity sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ== + +"@svgr/babel-preset@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-6.5.1.tgz#b90de7979c8843c5c580c7e2ec71f024b49eb828" + integrity sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw== + dependencies: + "@svgr/babel-plugin-add-jsx-attribute" "^6.5.1" + "@svgr/babel-plugin-remove-jsx-attribute" "*" + "@svgr/babel-plugin-remove-jsx-empty-expression" "*" + "@svgr/babel-plugin-replace-jsx-attribute-value" "^6.5.1" + "@svgr/babel-plugin-svg-dynamic-title" "^6.5.1" + "@svgr/babel-plugin-svg-em-dimensions" "^6.5.1" + "@svgr/babel-plugin-transform-react-native-svg" "^6.5.1" + "@svgr/babel-plugin-transform-svg-component" "^6.5.1" + +"@svgr/core@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/core/-/core-6.5.1.tgz#d3e8aa9dbe3fbd747f9ee4282c1c77a27410488a" + integrity sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw== + dependencies: + "@babel/core" "^7.19.6" + "@svgr/babel-preset" "^6.5.1" + "@svgr/plugin-jsx" "^6.5.1" camelcase "^6.2.0" cosmiconfig "^7.0.1" -"@svgr/hast-util-to-babel-ast@^6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.2.1.tgz#ae065567b74cbe745afae617053adf9a764bea25" - integrity sha512-pt7MMkQFDlWJVy9ULJ1h+hZBDGFfSCwlBNW1HkLnVi7jUhyEXUaGYWi1x6bM2IXuAR9l265khBT4Av4lPmaNLQ== +"@svgr/hast-util-to-babel-ast@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz#81800bd09b5bcdb968bf6ee7c863d2288fdb80d2" + integrity sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw== dependencies: - "@babel/types" "^7.15.6" - entities "^3.0.1" + "@babel/types" "^7.20.0" + entities "^4.4.0" -"@svgr/plugin-jsx@^6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-6.2.1.tgz#5668f1d2aa18c2f1bb7a1fc9f682d3f9aed263bd" - integrity sha512-u+MpjTsLaKo6r3pHeeSVsh9hmGRag2L7VzApWIaS8imNguqoUwDq/u6U/NDmYs/KAsrmtBjOEaAAPbwNGXXp1g== +"@svgr/plugin-jsx@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz#0e30d1878e771ca753c94e69581c7971542a7072" + integrity sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw== dependencies: - "@babel/core" "^7.15.5" - "@svgr/babel-preset" "^6.2.0" - "@svgr/hast-util-to-babel-ast" "^6.2.1" - svg-parser "^2.0.2" + "@babel/core" "^7.19.6" + "@svgr/babel-preset" "^6.5.1" + "@svgr/hast-util-to-babel-ast" "^6.5.1" + svg-parser "^2.0.4" -"@svgr/plugin-svgo@^6.2.0": - version "6.2.0" - resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-6.2.0.tgz#4cbe6a33ccccdcae4e3b63ded64cc1cbe1faf48c" - integrity sha512-oDdMQONKOJEbuKwuy4Np6VdV6qoaLLvoY86hjvQEgU82Vx1MSWRyYms6Sl0f+NtqxLI/rDVufATbP/ev996k3Q== +"@svgr/plugin-svgo@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz#0f91910e988fc0b842f88e0960c2862e022abe84" + integrity sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ== dependencies: cosmiconfig "^7.0.1" deepmerge "^4.2.2" - svgo "^2.5.0" + svgo "^2.8.0" "@svgr/webpack@^6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-6.2.1.tgz#ef5d51c1b6be4e7537fb9f76b3f2b2e22b63c58d" - integrity sha512-h09ngMNd13hnePwgXa+Y5CgOjzlCvfWLHg+MBnydEedAnuLRzUHUJmGS3o2OsrhxTOOqEsPOFt5v/f6C5Qulcw== - dependencies: - "@babel/core" "^7.15.5" - "@babel/plugin-transform-react-constant-elements" "^7.14.5" - "@babel/preset-env" "^7.15.6" - "@babel/preset-react" "^7.14.5" - "@babel/preset-typescript" "^7.15.0" - "@svgr/core" "^6.2.1" - "@svgr/plugin-jsx" "^6.2.1" - "@svgr/plugin-svgo" "^6.2.0" + version "6.5.1" + resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-6.5.1.tgz#ecf027814fc1cb2decc29dc92f39c3cf691e40e8" + integrity sha512-cQ/AsnBkXPkEK8cLbv4Dm7JGXq2XrumKnL1dRpJD9rIO2fTIlJI9a1uCciYG1F2aUsox/hJQyNGbt3soDxSRkA== + dependencies: + "@babel/core" "^7.19.6" + "@babel/plugin-transform-react-constant-elements" "^7.18.12" + "@babel/preset-env" "^7.19.4" + "@babel/preset-react" "^7.18.6" + "@babel/preset-typescript" "^7.18.6" + "@svgr/core" "^6.5.1" + "@svgr/plugin-jsx" "^6.5.1" + "@svgr/plugin-svgo" "^6.5.1" "@szmarczak/http-timer@^1.1.2": version "1.1.2" @@ -2432,10 +2374,25 @@ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== -"@tsconfig/docusaurus@2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/docusaurus/-/docusaurus-2.0.1.tgz#a5fafa047c8383258e3c5aad960e332e27ecf5ea" - integrity sha512-7JrI61bTZ37DWrHx1qhOW+kPxSG95+/q+EiDCMIahh8Aqbk03+nVu+Z6YGOj3O5e6lXHJuf/LHJ/lc6j8IEQyA== +"@tsconfig/docusaurus@2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/docusaurus/-/docusaurus-2.0.3.tgz#08a4a65e038a499fc4154ce32b538913d9f3c90d" + integrity sha512-3l1L5PzWVa7l0691TjnsZ0yOIEwG9DziSqu5IPZPlI5Dowi7z42cEym8Y35GHbgHvPcBfNxfrbxm7Cncn4nByQ== + +"@twemoji/api@15.1.0": + version "15.1.0" + resolved "https://registry.yarnpkg.com/@twemoji/api/-/api-15.1.0.tgz#66fc74c74accbcb6376d977560a03bba5215923c" + integrity sha512-CySXR4/e6vY0z9lC2tW9EVjsH6zzz2/LQvLRMwwpHsDI4xcaweSIP+LcESf1Mq7w2/zcrrhG4ozniMvpSsEXag== + dependencies: + "@twemoji/parser" "15.1.0" + fs-extra "^8.0.1" + jsonfile "^5.0.0" + universalify "^0.1.2" + +"@twemoji/parser@15.1.0": + version "15.1.0" + resolved "https://registry.yarnpkg.com/@twemoji/parser/-/parser-15.1.0.tgz#ad83b69fcd1fbcb705022f2b85d73e127ad5f335" + integrity sha512-3HTiSxPvkWUJ4kZeCvwyKlIwkpTUfBOk6igpBBRQni58ceQMv5YK4smkc8vX/eqOlMMNER/9qobv+Q6Q8LVrqA== "@types/acorn@^4.0.0": version "4.0.6" @@ -2504,10 +2461,10 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree-jsx@^0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-0.0.1.tgz#c36d7a1afeb47a95a8ee0b7bc8bc705db38f919d" - integrity sha512-gcLAYiMfQklDCPjQegGn0TBAn9it05ISEsEhlKQUddIk7o2XDokOcTN7HBO8tznM0D9dGezvHEfRZBfZf6me0A== +"@types/estree-jsx@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz#858a88ea20f34fe65111f005a689fa1ebf70dc18" + integrity sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg== dependencies: "@types/estree" "*" @@ -2516,10 +2473,10 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== -"@types/estree@^0.0.50": - version "0.0.50" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" - integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== +"@types/estree@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18": version "4.17.28" @@ -2541,9 +2498,16 @@ "@types/serve-static" "*" "@types/hast@^2.0.0": - version "2.3.4" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" - integrity sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g== + version "2.3.10" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.10.tgz#5c9d9e0b304bbb8879b857225c5ebab2d81d7643" + integrity sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw== + dependencies: + "@types/unist" "^2" + +"@types/hast@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" + integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== dependencies: "@types/unist" "*" @@ -2569,17 +2533,36 @@ resolved "https://registry.yarnpkg.com/@types/is-empty/-/is-empty-1.2.1.tgz#18d7256a73e43ec51f8b75c25fbdc31350be52a6" integrity sha512-a3xgqnFTuNJDm1fjsTjHocYJ40Cz3t8utYpi5GNaxzrJC2HSD08ym+whIL7fNqiqBCdM9bcqD1H/tORWAFXoZw== +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + "@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/mdast@^3.0.0": - version "3.0.10" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" - integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== + version "3.0.15" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.15.tgz#49c524a263f30ffa28b71ae282f813ed000ab9f5" + integrity sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ== dependencies: - "@types/unist" "*" + "@types/unist" "^2" "@types/mdast@^4.0.0": version "4.0.0" @@ -2598,6 +2581,13 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== +"@types/node-forge@^1.3.0": + version "1.3.11" + resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.11.tgz#0972ea538ddb0f4d9c2fa0ec5db5724773a604da" + integrity sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ== + dependencies: + "@types/node" "*" + "@types/node@*": version "17.0.42" resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.42.tgz#d7e8f22700efc94d125103075c074396b5f41f9b" @@ -2608,10 +2598,12 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.14.tgz#33b9b94f789a8fedd30a68efdbca4dbb06b61f20" integrity sha512-SbjLmERksKOGzWzPNuW7fJM7fk3YXVTFiZWB/Hs99gwhk+/dnrQRPBQjPW9aO+fi1tAffi9PrwFvsmOKmDTyng== -"@types/node@^18.0.0": - version "18.0.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.0.tgz#67c7b724e1bcdd7a8821ce0d5ee184d3b4dd525a" - integrity sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA== +"@types/node@^20.0.0": + version "20.14.15" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.15.tgz#e59477ab7bc7db1f80c85540bfd192a0becc588b" + integrity sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw== + dependencies: + undici-types "~5.26.4" "@types/parse-json@^4.0.0": version "4.0.0" @@ -2623,6 +2615,11 @@ resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109" integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw== +"@types/prismjs@^1.26.0": + version "1.26.4" + resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.26.4.tgz#1a9e1074619ce1d7322669e5b46fbe823925103a" + integrity sha512-rlAnzkW2sZOjbqZ743IHUhFcvzaGbqijwOu8QZnZCjfQzBqFE3s4lOTJEsxikImav9uzz/42I+O7YUs1mWgMlg== + "@types/prop-types@*": version "15.7.5" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" @@ -2638,7 +2635,7 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== -"@types/react-router-config@*", "@types/react-router-config@^5.0.6": +"@types/react-router-config@*": version "5.0.6" resolved "https://registry.yarnpkg.com/@types/react-router-config/-/react-router-config-5.0.6.tgz#87c5c57e72d241db900d9734512c50ccec062451" integrity sha512-db1mx37a1EJDf1XeX8jJN7R3PZABmJQXR8r28yUjVMFSjkmnQo6X6pOEEmNl+Tp2gYQOGPdYbFIipBtdElZ3Yg== @@ -2647,6 +2644,15 @@ "@types/react" "*" "@types/react-router" "*" +"@types/react-router-config@^5.0.6": + version "5.0.11" + resolved "https://registry.yarnpkg.com/@types/react-router-config/-/react-router-config-5.0.11.tgz#2761a23acc7905a66a94419ee40294a65aaa483a" + integrity sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-router" "^5.1.0" + "@types/react-router-dom@*": version "5.3.3" resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" @@ -2664,6 +2670,14 @@ "@types/history" "^4.7.11" "@types/react" "*" +"@types/react-router@^5.1.0": + version "5.1.20" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.20.tgz#88eccaa122a82405ef3efbcaaa5dcdd9f021387c" + integrity sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react@*", "@types/react@17.0.2": version "17.0.2" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.2.tgz#3de24c4efef902dd9795a49c75f760cbe4f7a5a8" @@ -2672,6 +2686,14 @@ "@types/prop-types" "*" csstype "^3.0.2" +"@types/react@17.0.0": + version "17.0.0" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.0.tgz#5af3eb7fad2807092f0046a1302b7823e27919b8" + integrity sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + "@types/retry@0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" @@ -2716,142 +2738,159 @@ resolved "https://registry.yarnpkg.com/@types/text-table/-/text-table-0.2.2.tgz#774c90cfcfbc8b4b0ebb00fecbe861dc8b1e8e26" integrity sha512-dGoI5Af7To0R2XE8wJuc6vwlavWARsCh3UKJPjWs1YEqGUqfgBI/j/4GX0yf19/DsDPPf0YAXWAp8psNeIehLg== -"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": +"@types/unist@*", "@types/unist@^2.0.0": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== +"@types/unist@^2", "@types/unist@^2.0.2", "@types/unist@^2.0.3": + version "2.0.11" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4" + integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== + "@types/unist@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.0.tgz#988ae8af1e5239e89f9fbb1ade4c935f4eeedf9a" integrity sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w== -"@types/ws@^8.5.1": - version "8.5.3" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" - integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== +"@types/ws@^8.5.5": + version "8.5.12" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.12.tgz#619475fe98f35ccca2a2f6c137702d85ec247b7e" + integrity sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ== dependencies: "@types/node" "*" -"@webassemblyjs/ast@1.11.5", "@webassemblyjs/ast@^1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.5.tgz#6e818036b94548c1fb53b754b5cae3c9b208281c" - integrity sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ== +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== dependencies: - "@webassemblyjs/helper-numbers" "1.11.5" - "@webassemblyjs/helper-wasm-bytecode" "1.11.5" + "@types/yargs-parser" "*" -"@webassemblyjs/floating-point-hex-parser@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.5.tgz#e85dfdb01cad16b812ff166b96806c050555f1b4" - integrity sha512-1j1zTIC5EZOtCplMBG/IEwLtUojtwFVwdyVMbL/hwWqbzlQoJsWCOavrdnLkemwNoC/EOwtUFch3fuo+cbcXYQ== +"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" + integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== -"@webassemblyjs/helper-api-error@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.5.tgz#1e82fa7958c681ddcf4eabef756ce09d49d442d1" - integrity sha512-L65bDPmfpY0+yFrsgz8b6LhXmbbs38OnwDCf6NpnMUYqa+ENfE5Dq9E42ny0qz/PdR0LJyq/T5YijPnU8AXEpA== +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== -"@webassemblyjs/helper-buffer@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.5.tgz#91381652ea95bb38bbfd270702351c0c89d69fba" - integrity sha512-fDKo1gstwFFSfacIeH5KfwzjykIE6ldh1iH9Y/8YkAZrhmu4TctqYjSh7t0K2VyDSXOZJ1MLhht/k9IvYGcIxg== +"@webassemblyjs/helper-buffer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" + integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== -"@webassemblyjs/helper-numbers@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.5.tgz#23380c910d56764957292839006fecbe05e135a9" - integrity sha512-DhykHXM0ZABqfIGYNv93A5KKDw/+ywBFnuWybZZWcuzWHfbp21wUfRkbtz7dMGwGgT4iXjWuhRMA2Mzod6W4WA== +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.5" - "@webassemblyjs/helper-api-error" "1.11.5" + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" "@xtuc/long" "4.2.2" -"@webassemblyjs/helper-wasm-bytecode@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.5.tgz#e258a25251bc69a52ef817da3001863cc1c24b9f" - integrity sha512-oC4Qa0bNcqnjAowFn7MPCETQgDYytpsfvz4ujZz63Zu/a/v71HeCAAmZsgZ3YVKec3zSPYytG3/PrRCqbtcAvA== +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== -"@webassemblyjs/helper-wasm-section@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.5.tgz#966e855a6fae04d5570ad4ec87fbcf29b42ba78e" - integrity sha512-uEoThA1LN2NA+K3B9wDo3yKlBfVtC6rh0i4/6hvbz071E8gTNZD/pT0MsBf7MeD6KbApMSkaAK0XeKyOZC7CIA== +"@webassemblyjs/helper-wasm-section@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" + integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== dependencies: - "@webassemblyjs/ast" "1.11.5" - "@webassemblyjs/helper-buffer" "1.11.5" - "@webassemblyjs/helper-wasm-bytecode" "1.11.5" - "@webassemblyjs/wasm-gen" "1.11.5" + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.12.1" -"@webassemblyjs/ieee754@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.5.tgz#b2db1b33ce9c91e34236194c2b5cba9b25ca9d60" - integrity sha512-37aGq6qVL8A8oPbPrSGMBcp38YZFXcHfiROflJn9jxSdSMMM5dS5P/9e2/TpaJuhE+wFrbukN2WI6Hw9MH5acg== +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.5.tgz#482e44d26b6b949edf042a8525a66c649e38935a" - integrity sha512-ajqrRSXaTJoPW+xmkfYN6l8VIeNnR4vBOTQO9HzR7IygoCcKWkICbKFbVTNMjMgMREqXEr0+2M6zukzM47ZUfQ== +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.5.tgz#83bef94856e399f3740e8df9f63bc47a987eae1a" - integrity sha512-WiOhulHKTZU5UPlRl53gHR8OxdGsSOxqfpqWeA2FmcwBMaoEdz6b2x2si3IwC9/fSPLfe8pBMRTHVMk5nlwnFQ== - -"@webassemblyjs/wasm-edit@^1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.5.tgz#93ee10a08037657e21c70de31c47fdad6b522b2d" - integrity sha512-C0p9D2fAu3Twwqvygvf42iGCQ4av8MFBLiTb+08SZ4cEdwzWx9QeAHDo1E2k+9s/0w1DM40oflJOpkZ8jW4HCQ== - dependencies: - "@webassemblyjs/ast" "1.11.5" - "@webassemblyjs/helper-buffer" "1.11.5" - "@webassemblyjs/helper-wasm-bytecode" "1.11.5" - "@webassemblyjs/helper-wasm-section" "1.11.5" - "@webassemblyjs/wasm-gen" "1.11.5" - "@webassemblyjs/wasm-opt" "1.11.5" - "@webassemblyjs/wasm-parser" "1.11.5" - "@webassemblyjs/wast-printer" "1.11.5" - -"@webassemblyjs/wasm-gen@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.5.tgz#ceb1c82b40bf0cf67a492c53381916756ef7f0b1" - integrity sha512-14vteRlRjxLK9eSyYFvw1K8Vv+iPdZU0Aebk3j6oB8TQiQYuO6hj9s4d7qf6f2HJr2khzvNldAFG13CgdkAIfA== - dependencies: - "@webassemblyjs/ast" "1.11.5" - "@webassemblyjs/helper-wasm-bytecode" "1.11.5" - "@webassemblyjs/ieee754" "1.11.5" - "@webassemblyjs/leb128" "1.11.5" - "@webassemblyjs/utf8" "1.11.5" - -"@webassemblyjs/wasm-opt@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.5.tgz#b52bac29681fa62487e16d3bb7f0633d5e62ca0a" - integrity sha512-tcKwlIXstBQgbKy1MlbDMlXaxpucn42eb17H29rawYLxm5+MsEmgPzeCP8B1Cl69hCice8LeKgZpRUAPtqYPgw== - dependencies: - "@webassemblyjs/ast" "1.11.5" - "@webassemblyjs/helper-buffer" "1.11.5" - "@webassemblyjs/wasm-gen" "1.11.5" - "@webassemblyjs/wasm-parser" "1.11.5" - -"@webassemblyjs/wasm-parser@1.11.5", "@webassemblyjs/wasm-parser@^1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.5.tgz#7ba0697ca74c860ea13e3ba226b29617046982e2" - integrity sha512-SVXUIwsLQlc8srSD7jejsfTU83g7pIGr2YYNb9oHdtldSxaOhvA5xwvIiWIfcX8PlSakgqMXsLpLfbbJ4cBYew== - dependencies: - "@webassemblyjs/ast" "1.11.5" - "@webassemblyjs/helper-api-error" "1.11.5" - "@webassemblyjs/helper-wasm-bytecode" "1.11.5" - "@webassemblyjs/ieee754" "1.11.5" - "@webassemblyjs/leb128" "1.11.5" - "@webassemblyjs/utf8" "1.11.5" - -"@webassemblyjs/wast-printer@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.5.tgz#7a5e9689043f3eca82d544d7be7a8e6373a6fa98" - integrity sha512-f7Pq3wvg3GSPUPzR0F6bmI89Hdb+u9WXrSKc4v+N0aV0q6r42WoF92Jp2jEorBEBRoRNXgjp53nBniDXcqZYPA== - dependencies: - "@webassemblyjs/ast" "1.11.5" +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" + integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-opt" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + "@webassemblyjs/wast-printer" "1.12.1" + +"@webassemblyjs/wasm-gen@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" + integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" + integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + +"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" + integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" + integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== + dependencies: + "@webassemblyjs/ast" "1.12.1" "@xtuc/long" "4.2.2" "@xtuc/ieee754@^1.2.0": @@ -2864,10 +2903,10 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abbrev@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" + integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" @@ -2877,10 +2916,10 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-import-assertions@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" - integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== acorn-jsx@^5.0.0: version "5.3.2" @@ -2897,6 +2936,11 @@ acorn@^8.0.0, acorn@^8.0.4, acorn@^8.5.0, acorn@^8.7.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== +acorn@^8.8.2: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + address@^1.0.1, address@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/address/-/address-1.2.0.tgz#d352a62c92fee90f89a693eccd2a8b2139ab02d9" @@ -2950,51 +2994,32 @@ ajv@^8.0.0, ajv@^8.8.0: uri-js "^4.2.2" algoliasearch-helper@^3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.10.0.tgz#59a0f645dd3c7e55cf01faa568d1af50c49d36f6" - integrity sha512-4E4od8qWWDMVvQ3jaRX6Oks/k35ywD011wAA4LbYMMjOtaZV6VWaTjRr4iN2bdaXP2o1BP7SLFMBf3wvnHmd8Q== + version "3.22.3" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.22.3.tgz#7c67a1a87c3adb0b52ef726a3de3c0b0edcbb5d1" + integrity sha512-2eoEz8mG4KHE+DzfrBTrCmDPxVXv7aZZWPojAJFtARpxxMO6lkos1dJ+XDCXdPvq7q3tpYWRi6xXmVQikejtpA== dependencies: "@algolia/events" "^4.0.1" -algoliasearch@^4.0.0: - version "4.12.1" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.12.1.tgz#574a2c5424c4b6681c026928fb810be2d2ec3924" - integrity sha512-c0dM1g3zZBJrkzE5GA/Nu1y3fFxx3LCzxKzcmp2dgGS8P4CjszB/l3lsSh2MSrrK1Hn/KV4BlbBMXtYgG1Bfrw== - dependencies: - "@algolia/cache-browser-local-storage" "4.12.1" - "@algolia/cache-common" "4.12.1" - "@algolia/cache-in-memory" "4.12.1" - "@algolia/client-account" "4.12.1" - "@algolia/client-analytics" "4.12.1" - "@algolia/client-common" "4.12.1" - "@algolia/client-personalization" "4.12.1" - "@algolia/client-search" "4.12.1" - "@algolia/logger-common" "4.12.1" - "@algolia/logger-console" "4.12.1" - "@algolia/requester-browser-xhr" "4.12.1" - "@algolia/requester-common" "4.12.1" - "@algolia/requester-node-http" "4.12.1" - "@algolia/transporter" "4.12.1" - -algoliasearch@^4.13.1: - version "4.13.1" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.13.1.tgz#54195c41c9e4bd13ed64982248cf49d4576974fe" - integrity sha512-dtHUSE0caWTCE7liE1xaL+19AFf6kWEcyn76uhcitWpntqvicFHXKFoZe5JJcv9whQOTRM6+B8qJz6sFj+rDJA== - dependencies: - "@algolia/cache-browser-local-storage" "4.13.1" - "@algolia/cache-common" "4.13.1" - "@algolia/cache-in-memory" "4.13.1" - "@algolia/client-account" "4.13.1" - "@algolia/client-analytics" "4.13.1" - "@algolia/client-common" "4.13.1" - "@algolia/client-personalization" "4.13.1" - "@algolia/client-search" "4.13.1" - "@algolia/logger-common" "4.13.1" - "@algolia/logger-console" "4.13.1" - "@algolia/requester-browser-xhr" "4.13.1" - "@algolia/requester-common" "4.13.1" - "@algolia/requester-node-http" "4.13.1" - "@algolia/transporter" "4.13.1" +algoliasearch@^4.13.1, algoliasearch@^4.19.1: + version "4.24.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.24.0.tgz#b953b3e2309ef8f25da9de311b95b994ac918275" + integrity sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g== + dependencies: + "@algolia/cache-browser-local-storage" "4.24.0" + "@algolia/cache-common" "4.24.0" + "@algolia/cache-in-memory" "4.24.0" + "@algolia/client-account" "4.24.0" + "@algolia/client-analytics" "4.24.0" + "@algolia/client-common" "4.24.0" + "@algolia/client-personalization" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/logger-console" "4.24.0" + "@algolia/recommend" "4.24.0" + "@algolia/requester-browser-xhr" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/requester-node-http" "4.24.0" + "@algolia/transporter" "4.24.0" ansi-align@^3.0.0, ansi-align@^3.0.1: version "3.0.1" @@ -3080,23 +3105,23 @@ array-union@^2.1.0: asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== at-least-node@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -autoprefixer@^10.3.7, autoprefixer@^10.4.7: - version "10.4.7" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.7.tgz#1db8d195f41a52ca5069b7593be167618edbbedf" - integrity sha512-ypHju4Y2Oav95SipEcCcI5J7CGPuvz8oat7sUtYj3ClK44bldfvtvcxK6IEK++7rqB7YchDGzweZIBG+SD0ZAA== +autoprefixer@^10.4.12, autoprefixer@^10.4.7: + version "10.4.20" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.20.tgz#5caec14d43976ef42e32dcb4bd62878e96be5b3b" + integrity sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g== dependencies: - browserslist "^4.20.3" - caniuse-lite "^1.0.30001335" - fraction.js "^4.2.0" + browserslist "^4.23.3" + caniuse-lite "^1.0.30001646" + fraction.js "^4.3.7" normalize-range "^0.1.2" - picocolors "^1.0.0" + picocolors "^1.0.1" postcss-value-parser "^4.2.0" axios@^0.25.0: @@ -3107,9 +3132,9 @@ axios@^0.25.0: follow-redirects "^1.14.7" babel-loader@^8.2.5: - version "8.2.5" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.5.tgz#d45f585e654d5a5d90f5350a779d7647c5ed512e" - integrity sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ== + version "8.3.0" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.3.0.tgz#124936e841ba4fe8176786d6ff28add1f134d6a8" + integrity sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q== dependencies: find-cache-dir "^3.3.1" loader-utils "^2.0.0" @@ -3138,29 +3163,40 @@ babel-plugin-extract-import-names@1.6.22: dependencies: "@babel/helper-plugin-utils" "7.10.4" -babel-plugin-polyfill-corejs2@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5" - integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== +babel-plugin-module-resolver@5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.2.tgz#cdeac5d4aaa3b08dd1ac23ddbf516660ed2d293e" + integrity sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg== dependencies: - "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.3.1" - semver "^6.1.1" + find-babel-config "^2.1.1" + glob "^9.3.3" + pkg-up "^3.1.0" + reselect "^4.1.7" + resolve "^1.22.8" -babel-plugin-polyfill-corejs3@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72" - integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ== +babel-plugin-polyfill-corejs2@^0.4.10: + version "0.4.11" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33" + integrity sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q== dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" - core-js-compat "^3.21.0" + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.6.2" + semver "^6.3.1" -babel-plugin-polyfill-regenerator@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" - integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== +babel-plugin-polyfill-corejs3@^0.10.1, babel-plugin-polyfill-corejs3@^0.10.4: + version "0.10.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz#2deda57caef50f59c525aeb4964d3b2f867710c7" + integrity sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA== dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" + "@babel/helper-define-polyfill-provider" "^0.6.2" + core-js-compat "^3.38.0" + +babel-plugin-polyfill-regenerator@^0.6.1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz#addc47e240edd1da1058ebda03021f382bba785e" + integrity sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.2" bail@^1.0.0: version "1.0.5" @@ -3180,7 +3216,7 @@ balanced-match@^1.0.0: base16@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70" - integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA= + integrity sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ== batch@0.6.1: version "0.6.1" @@ -3280,7 +3316,7 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.1.1" -browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.18.1, browserslist@^4.20.2, browserslist@^4.20.3: +browserslist@^4.0.0, browserslist@^4.18.1: version "4.20.4" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.4.tgz#98096c9042af689ee1e0271333dbc564b8ce4477" integrity sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw== @@ -3291,18 +3327,26 @@ browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4 node-releases "^2.0.5" picocolors "^1.0.0" +browserslist@^4.21.10, browserslist@^4.21.4, browserslist@^4.23.1, browserslist@^4.23.3: + version "4.23.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" + integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== + dependencies: + caniuse-lite "^1.0.30001646" + electron-to-chromium "^1.5.4" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -builtins@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" - integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== - dependencies: - semver "^7.0.0" - bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -3357,11 +3401,6 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -camelcase@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.0.tgz#fd112621b212126741f998d614cbc2a8623fd174" - integrity sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ== - caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" @@ -3372,10 +3411,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001335, caniuse-lite@^1.0.30001349: - version "1.0.30001352" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz#cc6f5da3f983979ad1e2cdbae0505dccaa7c6a12" - integrity sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001349, caniuse-lite@^1.0.30001646: + version "1.0.30001651" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz" + integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg== ccount@^1.0.0: version "1.1.0" @@ -3396,7 +3435,7 @@ chalk@^2.0.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.1.0, chalk@^4.1.2: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -3456,32 +3495,22 @@ cheerio-select@^2.1.0: domhandler "^5.0.3" domutils "^3.0.1" -cheerio@^1.0.0-rc.12: - version "1.0.0-rc.12" - resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.12.tgz#788bf7466506b1c6bf5fae51d24a2c4d62e47683" - integrity sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q== - dependencies: - cheerio-select "^2.1.0" - dom-serializer "^2.0.0" - domhandler "^5.0.3" - domutils "^3.0.1" - htmlparser2 "^8.0.1" - parse5 "^7.0.0" - parse5-htmlparser2-tree-adapter "^7.0.0" - -cheerio@^1.0.0-rc.3: - version "1.0.0-rc.11" - resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.11.tgz#1be84be1a126958366bcc57a11648cd9b30a60c2" - integrity sha512-bQwNaDIBKID5ts/DsdhxrjqFXYfLw4ste+wMKqWA8DyKcS4qwsPP4Bk8ZNaTJjvpiX/qW3BT4sU7d6Bh5i+dag== +cheerio@^1.0.0-rc.12, cheerio@^1.0.0-rc.3: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0.tgz#1ede4895a82f26e8af71009f961a9b8cb60d6a81" + integrity sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww== dependencies: cheerio-select "^2.1.0" dom-serializer "^2.0.0" domhandler "^5.0.3" - domutils "^3.0.1" - htmlparser2 "^8.0.1" - parse5 "^7.0.0" + domutils "^3.1.0" + encoding-sniffer "^0.2.0" + htmlparser2 "^9.1.0" + parse5 "^7.1.2" parse5-htmlparser2-tree-adapter "^7.0.0" - tslib "^2.4.0" + parse5-parser-stream "^7.1.2" + undici "^6.19.5" + whatwg-mimetype "^4.0.0" "chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.4.2, chokidar@^3.5.3: version "3.5.3" @@ -3513,13 +3542,30 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== -clean-css@^5.2.2, clean-css@^5.3.0: +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +ci-info@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.0.0.tgz#65466f8b280fc019b9f50a5388115d17a63a44f2" + integrity sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg== + +clean-css@^5.2.2: version "5.3.0" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.0.tgz#ad3d8238d5f3549e83d5f87205189494bc7cbb59" integrity sha512-YYuuxv4H/iNb1Z/5IbMRoxgrzjWGhOEFfd+groZ5dMCVkpENiMZmwspdrzBo9286JjM1gZJPAyL7ZIdzuvu2AQ== dependencies: source-map "~0.6.0" +clean-css@^5.3.0: + version "5.3.3" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd" + integrity sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg== + dependencies: + source-map "~0.6.0" + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -3536,9 +3582,9 @@ cli-boxes@^3.0.0: integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== cli-table3@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.2.tgz#aaf5df9d8b5bf12634dc8b3040806a0c07120d2a" - integrity sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw== + version "0.6.5" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" + integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== dependencies: string-width "^4.2.0" optionalDependencies: @@ -3554,16 +3600,16 @@ clone-deep@^4.0.1: shallow-clone "^3.0.0" clone-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q== + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" + integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== dependencies: mimic-response "^1.0.0" -clsx@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.0.0.tgz#12658f3fd98fafe62075595a5c30e43d18f3d00b" - integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q== +clsx@2.1.1, clsx@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== clsx@^1.1.1, clsx@^1.2.1: version "1.2.1" @@ -3575,6 +3621,11 @@ collapse-white-space@^1.0.2: resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== +collapse-white-space@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-2.1.0.tgz#640257174f9f42c740b40f3b55ee752924feefca" + integrity sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -3600,9 +3651,9 @@ color-name@~1.1.4: integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== colord@^2.9.1: - version "2.9.2" - resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1" - integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== + version "2.9.3" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" + integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== colorette@^2.0.10: version "2.0.17" @@ -3619,6 +3670,16 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== +comma-separated-tokens@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" + integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== + +command-exists-promise@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/command-exists-promise/-/command-exists-promise-2.0.2.tgz#7beecc4b218299f3c61fa69a4047aa0b36a64a99" + integrity sha512-T6PB6vdFrwnHXg/I0kivM3DqaCGZLjjYSOe0a5WgFKcz1sOnmOeIjnhQPXVXX3QjVbLyTJ85lJkX6lUpukTzaA== + commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -3724,11 +3785,14 @@ content-type@~1.0.5: integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== cookie-signature@1.0.6: version "1.0.6" @@ -3741,9 +3805,9 @@ cookie@0.6.0: integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== copy-text-to-clipboard@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz#8cbf8f90e0a47f12e4a24743736265d157bce69c" - integrity sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q== + version "3.2.0" + resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz#0202b2d9bdae30a49a53f898626dcc3b49ad960b" + integrity sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q== copy-webpack-plugin@^11.0.0: version "11.0.0" @@ -3757,23 +3821,22 @@ copy-webpack-plugin@^11.0.0: schema-utils "^4.0.0" serialize-javascript "^6.0.0" -core-js-compat@^3.21.0, core-js-compat@^3.22.1: - version "3.22.8" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.22.8.tgz#46fa34ce1ddf742acd7f95f575f66bbb21e05d62" - integrity sha512-pQnwg4xtuvc2Bs/5zYQPaEYYSuTxsF7LBWF0SvnVhthZo/Qe+rJpcEekrdNK5DWwDJ0gv0oI9NNX5Mppdy0ctg== +core-js-compat@^3.37.1, core-js-compat@^3.38.0: + version "3.38.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.38.0.tgz#d93393b1aa346b6ee683377b0c31172ccfe607aa" + integrity sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A== dependencies: - browserslist "^4.20.3" - semver "7.0.0" + browserslist "^4.23.3" -core-js-pure@^3.20.2: - version "3.22.8" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.22.8.tgz#f2157793b58719196ccf9673cc14f3683adc0957" - integrity sha512-bOxbZIy9S5n4OVH63XaLVXZ49QKicjowDx/UELyJ68vxfCRpYsbyh/WNZNfEfAk+ekA8vSjt+gCDpvh672bc3w== +core-js-pure@^3.30.2: + version "3.38.0" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.38.0.tgz#bc802cd152e33d5b0ec733b656c71cb847cac701" + integrity sha512-8balb/HAXo06aHP58mZMtXgD8vcnXz9tUDePgqBgJgKdmTlMt+jw3ujqniuBDQXMvTzxnMpxHFeuSM3g1jWQuQ== core-js@^3.23.3: - version "3.23.4" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.23.4.tgz#92d640faa7f48b90bbd5da239986602cfc402aa6" - integrity sha512-vjsKqRc1RyAJC3Ye2kYqgfdThb3zYnx9CrqoCcjMOENMtQPC7ZViBvlDxwYU/2z2NI/IPuiXw5mT4hWhddqjzQ== + version "3.38.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.38.0.tgz#8acb7c050bf2ccbb35f938c0d040132f6110f636" + integrity sha512-XPpwqEodRljce9KswjZShh95qJ1URisBeKCjUdq27YdenkslVe7OO0ZJhlYXAChW7OhXaRLl8AAba7IBfoIHug== core-util-is@~1.0.0: version "1.0.3" @@ -3791,10 +3854,10 @@ cosmiconfig@^6.0.0: path-type "^4.0.0" yaml "^1.7.2" -cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" - integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== +cosmiconfig@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== dependencies: "@types/parse-json" "^4.0.0" import-fresh "^3.2.1" @@ -3802,14 +3865,24 @@ cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" -cross-fetch@^3.0.4: - version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== +cosmiconfig@^8.3.5: + version "8.3.6" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" + integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== + dependencies: + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + path-type "^4.0.0" + +cross-fetch@^3.1.5: + version "3.1.8" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== dependencies: - node-fetch "2.6.7" + node-fetch "^2.6.12" -cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -3823,33 +3896,33 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== -css-declaration-sorter@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.0.tgz#72ebd995c8f4532ff0036631f7365cce9759df14" - integrity sha512-OGT677UGHJTAVMRhPO+HJ4oKln3wkBTwtDFH0ojbqm+MJm6xuDMHp2nkhh/ThaBqq20IbraBQSWKfSLNHQO9Og== +css-declaration-sorter@^6.3.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71" + integrity sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g== css-loader@^6.7.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.1.tgz#e98106f154f6e1baf3fc3bc455cb9981c1d5fd2e" - integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw== + version "6.11.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.11.0.tgz#33bae3bf6363d0a7c2cf9031c96c744ff54d85ba" + integrity sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g== dependencies: icss-utils "^5.1.0" - postcss "^8.4.7" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" - postcss-modules-scope "^3.0.0" + postcss "^8.4.33" + postcss-modules-extract-imports "^3.1.0" + postcss-modules-local-by-default "^4.0.5" + postcss-modules-scope "^3.2.0" postcss-modules-values "^4.0.0" postcss-value-parser "^4.2.0" - semver "^7.3.5" + semver "^7.5.4" css-minimizer-webpack-plugin@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.0.0.tgz#e11800388c19c2b7442c39cc78ac8ae3675c9605" - integrity sha512-7ZXXRzRHvofv3Uac5Y+RkWRNo0ZMlcg8e9/OtrqUYmwDWJo+qs67GvdeFrXLsFb7czKNwjQhPkM0avlIYl+1nA== + version "4.2.2" + resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.2.2.tgz#79f6199eb5adf1ff7ba57f105e3752d15211eb35" + integrity sha512-s3Of/4jKfw1Hj9CxEO1E5oXhQAxlayuHO2y/ML+C6I9sQ7FdzfEV6QgMLN3vI+qFsjJGIAFLKtQK7t8BOXAIyA== dependencies: cssnano "^5.1.8" - jest-worker "^27.5.1" - postcss "^8.4.13" + jest-worker "^29.1.2" + postcss "^8.4.17" schema-utils "^4.0.0" serialize-javascript "^6.0.0" source-map "^0.6.1" @@ -3895,36 +3968,36 @@ cssesc@^3.0.0: integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== cssnano-preset-advanced@^5.3.8: - version "5.3.8" - resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.8.tgz#027b1d05ef896d908178c483f0ec4190cb50ef9a" - integrity sha512-xUlLLnEB1LjpEik+zgRNlk8Y/koBPPtONZjp7JKbXigeAmCrFvq9H0pXW5jJV45bQWAlmJ0sKy+IMr0XxLYQZg== + version "5.3.10" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz#25558a1fbf3a871fb6429ce71e41be7f5aca6eef" + integrity sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ== dependencies: - autoprefixer "^10.3.7" - cssnano-preset-default "^5.2.12" + autoprefixer "^10.4.12" + cssnano-preset-default "^5.2.14" postcss-discard-unused "^5.1.0" postcss-merge-idents "^5.1.1" postcss-reduce-idents "^5.2.0" postcss-zindex "^5.1.0" -cssnano-preset-default@^5.2.12: - version "5.2.12" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.12.tgz#ebe6596ec7030e62c3eb2b3c09f533c0644a9a97" - integrity sha512-OyCBTZi+PXgylz9HAA5kHyoYhfGcYdwFmyaJzWnzxuGRtnMw/kR6ilW9XzlzlRAtB6PLT/r+prYgkef7hngFew== +cssnano-preset-default@^5.2.14: + version "5.2.14" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz#309def4f7b7e16d71ab2438052093330d9ab45d8" + integrity sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A== dependencies: - css-declaration-sorter "^6.3.0" + css-declaration-sorter "^6.3.1" cssnano-utils "^3.1.0" postcss-calc "^8.2.3" - postcss-colormin "^5.3.0" - postcss-convert-values "^5.1.2" + postcss-colormin "^5.3.1" + postcss-convert-values "^5.1.3" postcss-discard-comments "^5.1.2" postcss-discard-duplicates "^5.1.0" postcss-discard-empty "^5.1.1" postcss-discard-overridden "^5.1.0" - postcss-merge-longhand "^5.1.6" - postcss-merge-rules "^5.1.2" + postcss-merge-longhand "^5.1.7" + postcss-merge-rules "^5.1.4" postcss-minify-font-values "^5.1.0" postcss-minify-gradients "^5.1.1" - postcss-minify-params "^5.1.3" + postcss-minify-params "^5.1.4" postcss-minify-selectors "^5.2.1" postcss-normalize-charset "^5.1.0" postcss-normalize-display-values "^5.1.0" @@ -3932,11 +4005,11 @@ cssnano-preset-default@^5.2.12: postcss-normalize-repeat-style "^5.1.1" postcss-normalize-string "^5.1.0" postcss-normalize-timing-functions "^5.1.0" - postcss-normalize-unicode "^5.1.0" + postcss-normalize-unicode "^5.1.1" postcss-normalize-url "^5.1.0" postcss-normalize-whitespace "^5.1.1" postcss-ordered-values "^5.1.3" - postcss-reduce-initial "^5.1.0" + postcss-reduce-initial "^5.1.2" postcss-reduce-transforms "^5.1.0" postcss-svgo "^5.1.0" postcss-unique-selectors "^5.1.1" @@ -3947,11 +4020,11 @@ cssnano-utils@^3.1.0: integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== cssnano@^5.1.12, cssnano@^5.1.8: - version "5.1.12" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.12.tgz#bcd0b64d6be8692de79332c501daa7ece969816c" - integrity sha512-TgvArbEZu0lk/dvg2ja+B7kYoD7BBCmn3+k58xD0qjrGHsFzXY/wKTo9M5egcUCabPol05e/PVoIu79s2JN4WQ== + version "5.1.15" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.15.tgz#ded66b5480d5127fcb44dac12ea5a983755136bf" + integrity sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw== dependencies: - cssnano-preset-default "^5.2.12" + cssnano-preset-default "^5.2.14" lilconfig "^2.0.3" yaml "^1.10.2" @@ -3967,6 +4040,11 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== +debounce@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" + integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== + debug@2.6.9, debug@^2.6.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -3974,6 +4052,13 @@ debug@2.6.9, debug@^2.6.0: dependencies: ms "2.0.0" +debug@4: + version "4.3.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" + integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== + dependencies: + ms "2.1.2" + debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -4092,25 +4177,20 @@ detect-port-alt@^1.1.6: debug "^2.6.0" detect-port@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.3.0.tgz#d9c40e9accadd4df5cac6a782aefd014d573d1f1" - integrity sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ== + version "1.6.1" + resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.6.1.tgz#45e4073997c5f292b957cb678fb0bb8ed4250a67" + integrity sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q== dependencies: address "^1.0.1" - debug "^2.6.0" + debug "4" -devlop@^1.0.0: +devlop@^1.0.0, devlop@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018" integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== dependencies: dequal "^2.0.0" -diff@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -4203,6 +4283,15 @@ domutils@^3.0.1: domelementtype "^2.3.0" domhandler "^5.0.1" +domutils@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" + integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + dot-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" @@ -4219,9 +4308,9 @@ dot-prop@^5.2.0: is-obj "^2.0.0" duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA== + version "0.1.5" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" + integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== duplexer@^0.1.2: version "0.1.2" @@ -4243,6 +4332,16 @@ electron-to-chromium@^1.4.147: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.152.tgz#7dedbe8f3dc1c597088982a203f392e60f7ee90a" integrity sha512-jk4Ju5SGZAQQJ1iI4Rgru7dDlvkQPLpNPWH9gIZmwCD4YteA5Bbk1xPcPDUf5jUYs3e1e80RXdi8XgKQZaigeg== +electron-to-chromium@^1.5.4: + version "1.5.8" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.8.tgz#0a3225b305212f347be48f159a3c0a117d5e9801" + integrity sha512-4Nx0gP2tPNBLTrFxBMHpkQbtn2hidPVr/+/FTtcCiBYTucqc70zRyVZiOLj17Ui3wTO7SQ1/N+hkHYzJjBzt6A== + +emoji-regex@^10.2.1: + version "10.3.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.3.0.tgz#76998b9268409eb3dae3de989254d456e70cfe23" + integrity sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -4268,6 +4367,14 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encoding-sniffer@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz#799569d66d443babe82af18c9f403498365ef1d5" + integrity sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg== + dependencies: + iconv-lite "^0.6.3" + whatwg-encoding "^3.1.1" + end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -4275,10 +4382,10 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enhanced-resolve@^5.15.0: - version "5.15.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" - integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== +enhanced-resolve@^5.17.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -4288,16 +4395,21 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== -entities@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" - integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== - entities@^4.2.0, entities@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.3.0.tgz#62915f08d67353bb4eb67e3d62641a4059aec656" integrity sha512-/iP1rZrSEJ0DTlPiX+jbzlA3eVkY/e8L8SozroF395fIqE3TYF/Nz7YOMAawta+vLmyJ/hkGNNPcSbMADCCXbg== +entities@^4.4.0, entities@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + error-ex@^1.3.1, error-ex@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -4315,6 +4427,11 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + escape-goat@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" @@ -4370,18 +4487,18 @@ estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-util-is-identifier-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.0.0.tgz#e2d3d2ae3032c017b2112832bfc5d8ba938c8010" - integrity sha512-aXXZFVMnBBDRP81vS4YtAYJ0hUkgEsXea7lNKWCOeaAquGb1Jm2rcONPB5fpzwgbNxulTvrWuKnp9UElUGAKeQ== +estree-util-is-identifier-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz#0b5ef4c4ff13508b34dcd01ecfa945f61fce5dbd" + integrity sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg== -estree-util-visit@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/estree-util-visit/-/estree-util-visit-1.1.0.tgz#c0ea7942c40ac7889a77b57a11e92f987744bc6f" - integrity sha512-3lXJ4Us9j8TUif9cWcQy81t9p5OLasnDuuhrFiqb+XstmKC1d1LmrQWYsY49/9URcfHE64mPypDBaNK9NwWDPQ== +estree-util-visit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/estree-util-visit/-/estree-util-visit-2.0.0.tgz#13a9a9f40ff50ed0c022f831ddf4b58d05446feb" + integrity sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww== dependencies: - "@types/estree-jsx" "^0.0.1" - "@types/unist" "^2.0.0" + "@types/estree-jsx" "^1.0.0" + "@types/unist" "^3.0.0" esutils@^2.0.2: version "2.0.3" @@ -4389,9 +4506,9 @@ esutils@^2.0.2: integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== eta@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eta/-/eta-2.0.0.tgz#376865fadebc899e5b6dfce82fae64cbbe47e594" - integrity sha512-NqE7S2VmVwgMS8yBxsH4VgNQjNjLq1gfGU0u9I6Cjh468nPRMoDfGdK9n1p/3Dvsw3ebklDkZsFAnKJ9sefjBA== + version "2.2.0" + resolved "https://registry.yarnpkg.com/eta/-/eta-2.2.0.tgz#eb8b5f8c4e8b6306561a455e62cd7492fe3a9b8a" + integrity sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g== etag@~1.8.1: version "1.8.1" @@ -4542,17 +4659,17 @@ fbjs-css-vars@^1.0.0: integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== fbjs@^3.0.0, fbjs@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.2.tgz#dfae08a85c66a58372993ce2caf30863f569ff94" - integrity sha512-qv+boqYndjElAJHNN3NoM8XuwQZ1j2m3kEvTgdle8IDjr6oUbkEpvABWtj/rQl3vq4ew7dnElBxL4YJAwTVqQQ== + version "3.0.5" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.5.tgz#aa0edb7d5caa6340011790bd9249dbef8a81128d" + integrity sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg== dependencies: - cross-fetch "^3.0.4" + cross-fetch "^3.1.5" fbjs-css-vars "^1.0.0" loose-envify "^1.0.0" object-assign "^4.1.0" promise "^7.1.1" setimmediate "^1.0.5" - ua-parser-js "^0.7.30" + ua-parser-js "^1.0.35" feed@^4.2.2: version "4.2.2" @@ -4594,6 +4711,14 @@ finalhandler@1.2.0: statuses "2.0.1" unpipe "~1.0.0" +find-babel-config@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-2.1.1.tgz#93703fc8e068db5e4c57592900c5715dd04b7e5b" + integrity sha512-5Ji+EAysHGe1OipH7GN4qDjok5Z1uw5KAwDCbicU/4wyTZY7CqOCzcWbG7J5ad9mazq67k89fXlbc1MuIfl9uA== + dependencies: + json5 "^2.2.3" + path-exists "^4.0.0" + find-cache-dir@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" @@ -4626,10 +4751,15 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + flux@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.3.tgz#573b504a24982c4768fdfb59d8d2ea5637d72ee7" - integrity sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw== + version "4.0.4" + resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.4.tgz#9661182ea81d161ee1a6a6af10d20485ef2ac572" + integrity sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw== dependencies: fbemitter "^3.0.0" fbjs "^3.0.1" @@ -4639,6 +4769,14 @@ follow-redirects@^1.0.0, follow-redirects@^1.14.7: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== +foreground-child@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + fork-ts-checker-webpack-plugin@^6.5.0: version "6.5.2" resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz#4f67183f2f9eb8ba7df7177ce3cf3e75cdafb340" @@ -4668,10 +4806,10 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fraction.js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" - integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== +fraction.js@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" + integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== fresh@0.5.2: version "0.5.2" @@ -4706,6 +4844,13 @@ fs-extra@^9.0.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs-monkey@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" @@ -4721,10 +4866,10 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.1, function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: version "1.0.0-beta.2" @@ -4765,9 +4910,9 @@ get-stream@^6.0.0: integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== github-slugger@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.4.0.tgz#206eb96cdb22ee56fdc53a28d5a302338463444e" - integrity sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ== + version "1.5.0" + resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.5.0.tgz#17891bbc73232051474d68bd867a34625c955f7d" + integrity sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw== glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" @@ -4788,6 +4933,18 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@^10.0.0, glob@^10.2.2: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^7.0.0, glob@^7.1.3, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -4800,16 +4957,15 @@ glob@^7.0.0, glob@^7.1.3, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^8.0.0, glob@^8.0.1: - version "8.0.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e" - integrity sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ== +glob@^9.3.3: + version "9.3.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" + integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== dependencies: fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^5.0.1" - once "^1.3.0" + minimatch "^8.0.2" + minipass "^4.2.4" + path-scurry "^1.6.1" global-dirs@^3.0.0: version "3.0.0" @@ -4879,11 +5035,16 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + gray-matter@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" @@ -4934,11 +5095,16 @@ has-yarn@^2.1.0: integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + version "1.0.4" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" + integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: - function-bind "^1.1.1" + function-bind "^1.1.2" hast-to-hyperscript@^9.0.0: version "9.0.1" @@ -5032,6 +5198,13 @@ hoist-non-react-statics@^3.1.0: dependencies: react-is "^16.7.0" +hosted-git-info@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.2.tgz#9b751acac097757667f30114607ef7b661ff4f17" + integrity sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w== + dependencies: + lru-cache "^10.0.1" + hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" @@ -5047,6 +5220,11 @@ html-entities@^2.3.2: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== +html-escaper@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + html-minifier-terser@^6.0.2, html-minifier-terser@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" @@ -5061,9 +5239,9 @@ html-minifier-terser@^6.0.2, html-minifier-terser@^6.1.0: terser "^5.10.0" html-tags@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.2.0.tgz#dbb3518d20b726524e4dd43de397eb0a95726961" - integrity sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg== + version "3.3.1" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce" + integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ== html-void-elements@^1.0.0: version "1.0.5" @@ -5071,9 +5249,9 @@ html-void-elements@^1.0.0: integrity sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w== html-webpack-plugin@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50" - integrity sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw== + version "5.6.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz#50a8fa6709245608cb00e811eacecb8e0d7b7ea0" + integrity sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw== dependencies: "@types/html-minifier-terser" "^6.0.0" html-minifier-terser "^6.0.2" @@ -5091,15 +5269,15 @@ htmlparser2@^6.1.0: domutils "^2.5.2" entities "^2.0.0" -htmlparser2@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" - integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA== +htmlparser2@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-9.1.0.tgz#cdb498d8a75a51f739b61d3f718136c369bc8c23" + integrity sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ== dependencies: domelementtype "^2.3.0" - domhandler "^5.0.2" - domutils "^3.0.1" - entities "^4.3.0" + domhandler "^5.0.3" + domutils "^3.1.0" + entities "^4.5.0" http-cache-semantics@^4.0.0: version "4.1.1" @@ -5169,6 +5347,13 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.6.3, iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" @@ -5180,9 +5365,9 @@ ignore@^5.0.0, ignore@^5.2.0: integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== image-size@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.0.1.tgz#86d6cfc2b1d19eab5d2b368d4b9194d9e48541c5" - integrity sha512-VAwkvNSNGClRw9mDHhc5Efax8PLlsOGcUTh0T/LIriC8vPA3U5PdqXWqkz406MoYHMKW8Uf9gWr05T/rYB44kQ== + version "1.1.1" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.1.1.tgz#ddd67d4dc340e52ac29ce5f546a09f4e29e840ac" + integrity sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ== dependencies: queue "6.0.2" @@ -5214,12 +5399,10 @@ import-lazy@^2.1.0: resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" integrity sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A== -import-meta-resolve@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-2.0.3.tgz#117f3dc9a6415e82c32530545e1cf91be5c0a5d1" - integrity sha512-fpAppnBpZ3ymQ/dPP97TNsco1HB5+V9SYJ3chY50PP8xn4U/w+Y6ovWBmTImB/prmGsTjzPh8pQYY+EVBlr9mw== - dependencies: - builtins "^5.0.0" +import-meta-resolve@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706" + integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw== imurmurhash@^0.1.4: version "0.1.4" @@ -5231,11 +5414,6 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -infer-owner@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" - integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== - infima@0.2.0-alpha.43: version "0.2.0-alpha.43" resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.43.tgz#f7aa1d7b30b6c08afef441c726bac6150228cbe0" @@ -5269,10 +5447,10 @@ ini@^1.3.5, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -ini@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ini/-/ini-3.0.0.tgz#2f6de95006923aa75feed8894f5686165adc08f1" - integrity sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw== +ini@^4.1.2, ini@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.3.tgz#4c359675a6071a46985eb39b14e4a2c0ec98a795" + integrity sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg== inline-style-parser@0.1.1: version "0.1.1" @@ -5351,12 +5529,12 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-core-module@^2.8.1: - version "2.9.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" - integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== +is-core-module@^2.13.0, is-core-module@^2.8.1: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" + integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== dependencies: - has "^1.0.3" + hasown "^2.0.2" is-decimal@^1.0.0: version "1.0.4" @@ -5527,12 +5705,38 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isexe@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" + integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== + isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== -jest-worker@^27.4.5, jest-worker@^27.5.1: +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-worker@^27.4.5: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== @@ -5541,15 +5745,30 @@ jest-worker@^27.4.5, jest-worker@^27.5.1: merge-stream "^2.0.0" supports-color "^8.0.0" -joi@^17.6.0: - version "17.6.0" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.6.0.tgz#0bb54f2f006c09a96e75ce687957bd04290054b2" - integrity sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw== +jest-worker@^29.1.2: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: - "@hapi/hoek" "^9.0.0" - "@hapi/topo" "^5.0.0" - "@sideway/address" "^4.1.3" - "@sideway/formula" "^3.0.0" + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jiti@^1.20.0: + version "1.21.6" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" + integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== + +joi@^17.6.0: + version "17.13.3" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.13.3.tgz#0f5cc1169c999b30d344366d384b12d92558bcec" + integrity sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA== + dependencies: + "@hapi/hoek" "^9.3.0" + "@hapi/topo" "^5.1.0" + "@sideway/address" "^4.1.5" + "@sideway/formula" "^3.0.1" "@sideway/pinpoint" "^2.0.0" "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: @@ -5592,6 +5811,11 @@ json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-parse-even-better-errors@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz#b43d35e89c0f3be6b5fbbe9dc6c82467b30c28da" + integrity sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -5602,7 +5826,7 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json5@^2.0.0, json5@^2.1.2, json5@^2.2.1: +json5@^2.0.0, json5@^2.1.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -5610,7 +5834,7 @@ json5@^2.0.0, json5@^2.1.2, json5@^2.2.1: jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== optionalDependencies: graceful-fs "^4.1.6" @@ -5656,12 +5880,7 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -kleur@^4.0.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d" - integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA== - -klona@^2.0.4, klona@^2.0.5: +klona@^2.0.4: version "2.0.5" resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== @@ -5673,33 +5892,41 @@ latest-version@^5.1.0: dependencies: package-json "^6.3.0" +launch-editor@^2.6.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.8.1.tgz#3bda72af213ec9b46b170e39661916ec66c2f463" + integrity sha512-elBx2l/tp9z99X5H/qev8uyDywVh0VXAwEbjk8kJhnc5grOFkGh7aW6q55me9xnYbss261XtnUrysZ+XvGbhQA== + dependencies: + picocolors "^1.0.0" + shell-quote "^1.8.1" + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== lilconfig@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25" - integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg== + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lines-and-columns@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-2.0.3.tgz#b2f0badedb556b747020ab8ea7f0373e22efac1b" - integrity sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w== +lines-and-columns@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-2.0.4.tgz#d00318855905d2660d8c0822e3f5a4715855fc42" + integrity sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A== -load-plugin@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/load-plugin/-/load-plugin-5.0.0.tgz#e24f6a69ed905e6b31d4555b1a46603c11e9c1f0" - integrity sha512-jTz8tvC0BTMtof27lTSV5SAOnCRT0Z++k+S3QeQ5CrF8ZAS5L2nhi3euf4ZhJyDkds+nOQGyPcFqdQZ9s8ELkg== +load-plugin@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/load-plugin/-/load-plugin-6.0.3.tgz#b0eb8ea2361744f0e54850ccbc4c8a2d94ffabe3" + integrity sha512-kc0X2FEUZr145odl68frm+lMJuQ23+rTXYmR6TImqPtbpmXC4vVXbWKDQ9IzndA0HfyQamWfKLhzsqGSTxE63w== dependencies: - "@npmcli/config" "^4.0.0" - import-meta-resolve "^2.0.0" + "@npmcli/config" "^8.0.0" + import-meta-resolve "^4.0.0" loader-runner@^4.2.0: version "4.3.0" @@ -5745,7 +5972,7 @@ locate-path@^6.0.0: lodash.curry@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170" - integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA= + integrity sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA== lodash.debounce@^4.0.8: version "4.0.8" @@ -5755,7 +5982,7 @@ lodash.debounce@^4.0.8: lodash.flow@^3.3.0: version "3.5.0" resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a" - integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o= + integrity sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw== lodash.isequal@^4.5.0: version "4.5.0" @@ -5806,6 +6033,18 @@ lowercase-keys@^2.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== +lru-cache@^10.0.1, lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -5840,17 +6079,23 @@ markdown-escapes@^1.0.0: resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== +markdown-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/markdown-extensions/-/markdown-extensions-2.0.0.tgz#34bebc83e9938cae16e0e017e4a9814a8330d3c4" + integrity sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q== + markdown-table@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.2.tgz#9b59eb2c1b22fe71954a65ff512887065a7bb57c" integrity sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA== -mdast-comment-marker@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mdast-comment-marker/-/mdast-comment-marker-2.1.0.tgz#67acce26def829b310016c7a186ec6ec3e7d6a3f" - integrity sha512-/+Cfm8A83PjkqjQDB9iYqHESGuXlriCWAwRGPJjkYmxXrF4r6saxeUlOKNrf+SogTwg9E8uyHRCFHLG6/BAAdA== +mdast-comment-marker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mdast-comment-marker/-/mdast-comment-marker-3.0.0.tgz#8233f27c985ac7be53678ecb453dd9648fa1b5c5" + integrity sha512-bt08sLmTNg00/UtVDiqZKocxqvQqqyQZAg1uaRuO/4ysXV5motg7RolF5o5yy/sY1rG0v2XgZEqFWho1+2UquA== dependencies: - mdast-util-mdx-expression "^1.1.0" + "@types/mdast" "^4.0.0" + mdast-util-mdx-expression "^2.0.0" mdast-squeeze-paragraphs@^4.0.0: version "4.0.0" @@ -5866,32 +6111,29 @@ mdast-util-definitions@^4.0.0: dependencies: unist-util-visit "^2.0.0" -mdast-util-find-and-replace@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.1.0.tgz#69728acd250749f8aac6e150e07d1fd15619e829" - integrity sha512-1w1jbqAd13oU78QPBf5223+xB+37ecNtQ1JElq2feWols5oEYAl+SgNDnOZipe7NfLemoEt362yUS15/wip4mw== +mdast-util-directive@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz#3fb1764e705bbdf0afb0d3f889e4404c3e82561f" + integrity sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q== dependencies: - escape-string-regexp "^5.0.0" - unist-util-is "^5.0.0" - unist-util-visit-parents "^4.0.0" + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + parse-entities "^4.0.0" + stringify-entities "^4.0.0" + unist-util-visit-parents "^6.0.0" -mdast-util-from-markdown@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz#84df2924ccc6c995dec1e2368b2b208ad0a76268" - integrity sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q== +mdast-util-find-and-replace@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz#a6fc7b62f0994e973490e45262e4bc07607b04e0" + integrity sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA== dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - decode-named-character-reference "^1.0.0" - mdast-util-to-string "^3.1.0" - micromark "^3.0.0" - micromark-util-decode-numeric-character-reference "^1.0.0" - micromark-util-decode-string "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-stringify-position "^3.0.0" - uvu "^0.5.0" + "@types/mdast" "^4.0.0" + escape-string-regexp "^5.0.0" + unist-util-is "^6.0.0" + unist-util-visit-parents "^6.0.0" mdast-util-from-markdown@^2.0.0: version "2.0.0" @@ -5923,116 +6165,131 @@ mdast-util-frontmatter@^2.0.0: mdast-util-to-markdown "^2.0.0" micromark-extension-frontmatter "^2.0.0" -mdast-util-gfm-autolink-literal@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.2.tgz#4032dcbaddaef7d4f2f3768ed830475bb22d3970" - integrity sha512-FzopkOd4xTTBeGXhXSBU0OCDDh5lUj2rd+HQqG92Ld+jL4lpUfgX2AT2OHAVP9aEeDKp7G92fuooSZcYJA3cRg== +mdast-util-gfm-autolink-literal@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz#5baf35407421310a08e68c15e5d8821e8898ba2a" + integrity sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg== dependencies: - "@types/mdast" "^3.0.0" + "@types/mdast" "^4.0.0" ccount "^2.0.0" - mdast-util-find-and-replace "^2.0.0" - micromark-util-character "^1.0.0" + devlop "^1.0.0" + mdast-util-find-and-replace "^3.0.0" + micromark-util-character "^2.0.0" -mdast-util-gfm-footnote@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.1.tgz#11d2d40a1a673a399c459e467fa85e00223191fe" - integrity sha512-p+PrYlkw9DeCRkTVw1duWqPRHX6Ywh2BNKJQcZbCwAuP/59B0Lk9kakuAd7KbQprVO4GzdW8eS5++A9PUSqIyw== +mdast-util-gfm-footnote@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz#25a1753c7d16db8bfd53cd84fe50562bd1e6d6a9" + integrity sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-markdown "^1.3.0" - micromark-util-normalize-identifier "^1.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.1.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" -mdast-util-gfm-strikethrough@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.1.tgz#a4a74c36864ec6a6e3bbd31e1977f29beb475789" - integrity sha512-zKJbEPe+JP6EUv0mZ0tQUyLQOC+FADt0bARldONot/nefuISkaZFlmVK4tU6JgfyZGrky02m/I6PmehgAgZgqg== +mdast-util-gfm-strikethrough@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz#d44ef9e8ed283ac8c1165ab0d0dfd058c2764c16" + integrity sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-markdown "^1.3.0" + "@types/mdast" "^4.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" -mdast-util-gfm-table@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.4.tgz#0dbb25f04fd9c0877dc63b76203ecbdf5d945755" - integrity sha512-aEuoPwZyP4iIMkf2cLWXxx3EQ6Bmh2yKy9MVCg4i6Sd3cX80dcLEfXO/V4ul3pGH9czBK4kp+FAl+ZHmSUt9/w== +mdast-util-gfm-table@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz#7a435fb6223a72b0862b33afbd712b6dae878d38" + integrity sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg== dependencies: + "@types/mdast" "^4.0.0" + devlop "^1.0.0" markdown-table "^3.0.0" - mdast-util-from-markdown "^1.0.0" - mdast-util-to-markdown "^1.3.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" -mdast-util-gfm-task-list-item@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.1.tgz#6f35f09c6e2bcbe88af62fdea02ac199cc802c5c" - integrity sha512-KZ4KLmPdABXOsfnM6JHUIjxEvcx2ulk656Z/4Balw071/5qgnhz+H1uGtf2zIGnrnvDC8xR4Fj9uKbjAFGNIeA== +mdast-util-gfm-task-list-item@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz#e68095d2f8a4303ef24094ab642e1047b991a936" + integrity sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-markdown "^1.3.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" -mdast-util-gfm@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-2.0.1.tgz#16fcf70110ae689a06d77e8f4e346223b64a0ea6" - integrity sha512-42yHBbfWIFisaAfV1eixlabbsa6q7vHeSPY+cg+BBjX51M8xhgMacqH9g6TftB/9+YkcI0ooV4ncfrJslzm/RQ== - dependencies: - mdast-util-from-markdown "^1.0.0" - mdast-util-gfm-autolink-literal "^1.0.0" - mdast-util-gfm-footnote "^1.0.0" - mdast-util-gfm-strikethrough "^1.0.0" - mdast-util-gfm-table "^1.0.0" - mdast-util-gfm-task-list-item "^1.0.0" - mdast-util-to-markdown "^1.0.0" - -mdast-util-heading-style@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-heading-style/-/mdast-util-heading-style-2.0.0.tgz#19bcc14d96b4a6f24efbe1318409bd34af64bb7f" - integrity sha512-q9+WW2hJduW51LgV2r/fcU5wIt2GLFf0yYHxyi0f2aaxnC63ErBSOAJlhP6nbQ6yeG5rTCozbwOi4QNDPKV0zw== +mdast-util-gfm@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz#3f2aecc879785c3cb6a81ff3a243dc11eca61095" + integrity sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw== dependencies: - "@types/mdast" "^3.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-gfm-autolink-literal "^2.0.0" + mdast-util-gfm-footnote "^2.0.0" + mdast-util-gfm-strikethrough "^2.0.0" + mdast-util-gfm-table "^2.0.0" + mdast-util-gfm-task-list-item "^2.0.0" + mdast-util-to-markdown "^2.0.0" -mdast-util-mdx-expression@^1.0.0, mdast-util-mdx-expression@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-1.2.0.tgz#3e927afe27943956dc5d1c64cb949652062f71ff" - integrity sha512-wb36oi09XxqO9RVqgfD+xo8a7xaNgS+01+k3v0GKW0X0bYbeBmUZz22Z/IJ8SuphVlG+DNgNo9VoEaUJ3PKfJQ== +mdast-util-heading-style@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-heading-style/-/mdast-util-heading-style-3.0.0.tgz#f1a02b2d0950e8535713f54de5ee0eea82413f51" + integrity sha512-tsUfM9Kj9msjlemA/38Z3pvraQay880E3zP2NgIthMoGcpU9bcPX9oSM6QC/+eFXGGB4ba+VCB1dKAPHB7Veug== dependencies: - "@types/estree-jsx" "^0.0.1" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - mdast-util-to-markdown "^1.0.0" + "@types/mdast" "^4.0.0" -mdast-util-mdx-jsx@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-2.0.1.tgz#03d003c8b0b4bd94ab092d876c0f92d2b0c83b0b" - integrity sha512-oPC7/smPBf7vxnvIYH5y3fPo2lw1rdrswFfSb4i0GTAXRUQv7JUU/t/hbp07dgGdUFTSDOHm5DNamhNg/s2Hrg== +mdast-util-mdx-expression@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz#4968b73724d320a379110d853e943a501bfd9d87" + integrity sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw== dependencies: - "@types/estree-jsx" "^0.0.1" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-mdx-jsx@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.2.tgz#daae777c72f9c4a106592e3025aa50fb26068e1b" + integrity sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" ccount "^2.0.0" - mdast-util-to-markdown "^1.3.0" + devlop "^1.1.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" parse-entities "^4.0.0" stringify-entities "^4.0.0" - unist-util-remove-position "^4.0.0" - unist-util-stringify-position "^3.0.0" - vfile-message "^3.0.0" + unist-util-remove-position "^5.0.0" + unist-util-stringify-position "^4.0.0" + vfile-message "^4.0.0" -mdast-util-mdx@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-mdx/-/mdast-util-mdx-2.0.0.tgz#dd4f6c993cf27da32725e50a04874f595b7b63fb" - integrity sha512-M09lW0CcBT1VrJUaF/PYxemxxHa7SLDHdSn94Q9FhxjCQfuW7nMAWKWimTmA3OyDMSTH981NN1csW1X+HPSluw== +mdast-util-mdx@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz#792f9cf0361b46bee1fdf1ef36beac424a099c41" + integrity sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w== dependencies: - mdast-util-mdx-expression "^1.0.0" - mdast-util-mdx-jsx "^2.0.0" - mdast-util-mdxjs-esm "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-mdx-expression "^2.0.0" + mdast-util-mdx-jsx "^3.0.0" + mdast-util-mdxjs-esm "^2.0.0" + mdast-util-to-markdown "^2.0.0" -mdast-util-mdxjs-esm@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-1.2.0.tgz#eca8b985f091c2d65a72c19d2740cefbc209aa63" - integrity sha512-IPpX9GBzAIbIRCjbyeLDpMhACFb0wxTIujuR3YElB8LWbducUdMgRJuqs/Vg8xQ1bIAMm7lw8L+YNtua0xKXRw== +mdast-util-mdxjs-esm@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz#019cfbe757ad62dd557db35a695e7314bcc9fa97" + integrity sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg== dependencies: - "@types/estree-jsx" "^0.0.1" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - mdast-util-to-markdown "^1.0.0" + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" mdast-util-phrasing@^4.0.0: version "4.0.0" @@ -6056,19 +6313,6 @@ mdast-util-to-hast@10.0.1: unist-util-position "^3.0.0" unist-util-visit "^2.0.0" -mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-1.3.0.tgz#38b6cdc8dc417de642a469c4fc2abdf8c931bd1e" - integrity sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA== - dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - longest-streak "^3.0.0" - mdast-util-to-string "^3.0.0" - micromark-util-decode-string "^1.0.0" - unist-util-visit "^4.0.0" - zwitch "^2.0.0" - mdast-util-to-markdown@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz#9813f1d6e0cdaac7c244ec8c6dabfdb2102ea2b4" @@ -6088,11 +6332,6 @@ mdast-util-to-string@^2.0.0: resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== -mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz#56c506d065fbf769515235e577b5a261552d56e9" - integrity sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA== - mdast-util-to-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz#7a5121475556a04e7eddeb67b264aae79d312814" @@ -6142,28 +6381,6 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad" - integrity sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA== - dependencies: - decode-named-character-reference "^1.0.0" - micromark-factory-destination "^1.0.0" - micromark-factory-label "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-factory-title "^1.0.0" - micromark-factory-whitespace "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-chunked "^1.0.0" - micromark-util-classify-character "^1.0.0" - micromark-util-html-tag-name "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-resolve-all "^1.0.0" - micromark-util-subtokenize "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.1" - uvu "^0.5.0" - micromark-core-commonmark@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz#50740201f0ee78c12a675bf3e68ffebc0bf931a3" @@ -6196,120 +6413,114 @@ micromark-extension-frontmatter@^2.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromark-extension-gfm-autolink-literal@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.3.tgz#dc589f9c37eaff31a175bab49f12290edcf96058" - integrity sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg== +micromark-extension-gfm-autolink-literal@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz#6286aee9686c4462c1e3552a9d505feddceeb935" + integrity sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw== dependencies: - micromark-util-character "^1.0.0" - micromark-util-sanitize-uri "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" + micromark-util-character "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" -micromark-extension-gfm-footnote@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.4.tgz#cbfd8873b983e820c494498c6dac0105920818d5" - integrity sha512-E/fmPmDqLiMUP8mLJ8NbJWJ4bTw6tS+FEQS8CcuDtZpILuOb2kjLqPEeAePF1djXROHXChM/wPJw0iS4kHCcIg== +micromark-extension-gfm-footnote@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz#4dab56d4e398b9853f6fe4efac4fc9361f3e0750" + integrity sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw== dependencies: - micromark-core-commonmark "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-sanitize-uri "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" -micromark-extension-gfm-strikethrough@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.4.tgz#162232c284ffbedd8c74e59c1525bda217295e18" - integrity sha512-/vjHU/lalmjZCT5xt7CcHVJGq8sYRm80z24qAKXzaHzem/xsDYb2yLL+NNVbYvmpLx3O7SYPuGL5pzusL9CLIQ== +micromark-extension-gfm-strikethrough@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz#86106df8b3a692b5f6a92280d3879be6be46d923" + integrity sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw== dependencies: - micromark-util-chunked "^1.0.0" - micromark-util-classify-character "^1.0.0" - micromark-util-resolve-all "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" + devlop "^1.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" -micromark-extension-gfm-table@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz#7b708b728f8dc4d95d486b9e7a2262f9cddbcbb4" - integrity sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg== +micromark-extension-gfm-table@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz#5cadedfbb29fca7abf752447967003dc3b6583c9" + integrity sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g== dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" + devlop "^1.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" -micromark-extension-gfm-tagfilter@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.1.tgz#fb2e303f7daf616db428bb6a26e18fda14a90a4d" - integrity sha512-Ty6psLAcAjboRa/UKUbbUcwjVAv5plxmpUTy2XC/3nJFL37eHej8jrHrRzkqcpipJliuBH30DTs7+3wqNcQUVA== +micromark-extension-gfm-tagfilter@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz#f26d8a7807b5985fba13cf61465b58ca5ff7dc57" + integrity sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg== dependencies: - micromark-util-types "^1.0.0" + micromark-util-types "^2.0.0" -micromark-extension-gfm-task-list-item@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.3.tgz#7683641df5d4a09795f353574d7f7f66e47b7fc4" - integrity sha512-PpysK2S1Q/5VXi72IIapbi/jliaiOFzv7THH4amwXeYXLq3l1uo8/2Be0Ac1rEwK20MQEsGH2ltAZLNY2KI/0Q== +micromark-extension-gfm-task-list-item@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz#bcc34d805639829990ec175c3eea12bb5b781f2c" + integrity sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw== dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" + devlop "^1.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" -micromark-extension-gfm@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-2.0.1.tgz#40f3209216127a96297c54c67f5edc7ef2d1a2a2" - integrity sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA== - dependencies: - micromark-extension-gfm-autolink-literal "^1.0.0" - micromark-extension-gfm-footnote "^1.0.0" - micromark-extension-gfm-strikethrough "^1.0.0" - micromark-extension-gfm-table "^1.0.0" - micromark-extension-gfm-tagfilter "^1.0.0" - micromark-extension-gfm-task-list-item "^1.0.0" - micromark-util-combine-extensions "^1.0.0" - micromark-util-types "^1.0.0" +micromark-extension-gfm@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz#3e13376ab95dd7a5cfd0e29560dfe999657b3c5b" + integrity sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w== + dependencies: + micromark-extension-gfm-autolink-literal "^2.0.0" + micromark-extension-gfm-footnote "^2.0.0" + micromark-extension-gfm-strikethrough "^2.0.0" + micromark-extension-gfm-table "^2.0.0" + micromark-extension-gfm-tagfilter "^2.0.0" + micromark-extension-gfm-task-list-item "^2.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-types "^2.0.0" -micromark-extension-mdx-expression@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.3.tgz#cd3843573921bf55afcfff4ae0cd2e857a16dcfa" - integrity sha512-TjYtjEMszWze51NJCZmhv7MEBcgYRgb3tJeMAJ+HQCAaZHHRBaDCccqQzGizR/H4ODefP44wRTgOn2vE5I6nZA== +micromark-extension-mdx-expression@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz#1407b9ce69916cf5e03a196ad9586889df25302a" + integrity sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ== dependencies: - micromark-factory-mdx-expression "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" + "@types/estree" "^1.0.0" + devlop "^1.0.0" + micromark-factory-mdx-expression "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-events-to-acorn "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" -micromark-extension-mdx-jsx@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.3.tgz#9f196be5f65eb09d2a49b237a7b3398bba2999be" - integrity sha512-VfA369RdqUISF0qGgv2FfV7gGjHDfn9+Qfiv5hEwpyr1xscRj/CiVRkU7rywGFCO7JwJ5L0e7CJz60lY52+qOA== +micromark-extension-mdx-jsx@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.0.tgz#4aba0797c25efb2366a3fd2d367c6b1c1159f4f5" + integrity sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w== dependencies: "@types/acorn" "^4.0.0" - estree-util-is-identifier-name "^2.0.0" - micromark-factory-mdx-expression "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" - -micromark-extension-mdx-md@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-md/-/micromark-extension-mdx-md-1.0.1.tgz#595d4b2f692b134080dca92c12272ab5b74c6d1a" - integrity sha512-7MSuj2S7xjOQXAjjkbjBsHkMtb+mDGVW6uI2dBL9snOBCbZmoNgDAeZ0nSn9j3T42UE/g2xVNMn18PJxZvkBEA== - dependencies: - micromark-util-types "^1.0.0" + "@types/estree" "^1.0.0" + devlop "^1.0.0" + estree-util-is-identifier-name "^3.0.0" + micromark-factory-mdx-expression "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + vfile-message "^4.0.0" micromark-extension-mdx-md@^2.0.0: version "2.0.0" @@ -6318,42 +6529,34 @@ micromark-extension-mdx-md@^2.0.0: dependencies: micromark-util-types "^2.0.0" -micromark-extension-mdxjs-esm@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-1.0.2.tgz#df0c48743a0b1988119489c68314160b7942ffa6" - integrity sha512-bIaxblNIM+CCaJvp3L/V+168l79iuNmxEiTU6i3vB0YuDW+rumV64BFMxvhfRDxaJxQE1zD5vTPdyLBbW4efGA== +micromark-extension-mdxjs-esm@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz#de21b2b045fd2059bd00d36746081de38390d54a" + integrity sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A== dependencies: - micromark-core-commonmark "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-position-from-estree "^1.1.0" - uvu "^0.5.0" - vfile-message "^3.0.0" + "@types/estree" "^1.0.0" + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-events-to-acorn "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + unist-util-position-from-estree "^2.0.0" + vfile-message "^4.0.0" -micromark-extension-mdxjs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs/-/micromark-extension-mdxjs-1.0.0.tgz#772644e12fc8299a33e50f59c5aa15727f6689dd" - integrity sha512-TZZRZgeHvtgm+IhtgC2+uDMR7h8eTKF0QUX9YsgoL9+bADBpBY6SiLvWqnBlLbCEevITmTqmEuY3FoxMKVs1rQ== +micromark-extension-mdxjs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz#b5a2e0ed449288f3f6f6c544358159557549de18" + integrity sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ== dependencies: acorn "^8.0.0" acorn-jsx "^5.0.0" - micromark-extension-mdx-expression "^1.0.0" - micromark-extension-mdx-jsx "^1.0.0" - micromark-extension-mdx-md "^1.0.0" - micromark-extension-mdxjs-esm "^1.0.0" - micromark-util-combine-extensions "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-factory-destination@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz#fef1cb59ad4997c496f887b6977aa3034a5a277e" - integrity sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" + micromark-extension-mdx-expression "^3.0.0" + micromark-extension-mdx-jsx "^3.0.0" + micromark-extension-mdx-md "^2.0.0" + micromark-extension-mdxjs-esm "^3.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-types "^2.0.0" micromark-factory-destination@^2.0.0: version "2.0.0" @@ -6364,16 +6567,6 @@ micromark-factory-destination@^2.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromark-factory-label@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz#6be2551fa8d13542fcbbac478258fb7a20047137" - integrity sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - micromark-factory-label@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz#17c5c2e66ce39ad6f4fc4cbf40d972f9096f726a" @@ -6384,19 +6577,19 @@ micromark-factory-label@^2.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromark-factory-mdx-expression@^1.0.0: - version "1.0.6" - resolved "https://registry.yarnpkg.com/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-1.0.6.tgz#917e17d16e6e9c2551f3a862e6a9ebdd22056476" - integrity sha512-WRQIc78FV7KrCfjsEf/sETopbYjElh3xAmNpLkd1ODPqxEngP42eVRGbiPEQWpRV27LzqW+XVTvQAMIIRLPnNA== +micromark-factory-mdx-expression@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.1.tgz#f2a9724ce174f1751173beb2c1f88062d3373b1b" + integrity sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg== dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-position-from-estree "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" + "@types/estree" "^1.0.0" + devlop "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-events-to-acorn "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + unist-util-position-from-estree "^2.0.0" + vfile-message "^4.0.0" micromark-factory-space@^1.0.0: version "1.0.0" @@ -6414,17 +6607,6 @@ micromark-factory-space@^2.0.0: micromark-util-character "^2.0.0" micromark-util-types "^2.0.0" -micromark-factory-title@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz#7e09287c3748ff1693930f176e1c4a328382494f" - integrity sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A== - dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - micromark-factory-title@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz#726140fc77892af524705d689e1cf06c8a83ea95" @@ -6435,16 +6617,6 @@ micromark-factory-title@^2.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromark-factory-whitespace@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz#e991e043ad376c1ba52f4e49858ce0794678621c" - integrity sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A== - dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - micromark-factory-whitespace@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz#9e92eb0f5468083381f923d9653632b3cfb5f763" @@ -6471,13 +6643,6 @@ micromark-util-character@^2.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromark-util-chunked@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz#5b40d83f3d53b84c4c6bce30ed4257e9a4c79d06" - integrity sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g== - dependencies: - micromark-util-symbol "^1.0.0" - micromark-util-chunked@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz#e51f4db85fb203a79dbfef23fd41b2f03dc2ef89" @@ -6485,15 +6650,6 @@ micromark-util-chunked@^2.0.0: dependencies: micromark-util-symbol "^2.0.0" -micromark-util-classify-character@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz#cbd7b447cb79ee6997dd274a46fc4eb806460a20" - integrity sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - micromark-util-classify-character@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz#8c7537c20d0750b12df31f86e976d1d951165f34" @@ -6503,14 +6659,6 @@ micromark-util-classify-character@^2.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromark-util-combine-extensions@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz#91418e1e74fb893e3628b8d496085639124ff3d5" - integrity sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA== - dependencies: - micromark-util-chunked "^1.0.0" - micromark-util-types "^1.0.0" - micromark-util-combine-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz#75d6ab65c58b7403616db8d6b31315013bfb7ee5" @@ -6519,13 +6667,6 @@ micromark-util-combine-extensions@^2.0.0: micromark-util-chunked "^2.0.0" micromark-util-types "^2.0.0" -micromark-util-decode-numeric-character-reference@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz#dcc85f13b5bd93ff8d2868c3dba28039d490b946" - integrity sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w== - dependencies: - micromark-util-symbol "^1.0.0" - micromark-util-decode-numeric-character-reference@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.0.tgz#a798808d02cc74113e2c939fc95363096ade7f1d" @@ -6533,16 +6674,6 @@ micromark-util-decode-numeric-character-reference@^2.0.0: dependencies: micromark-util-symbol "^2.0.0" -micromark-util-decode-string@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz#942252ab7a76dec2dbf089cc32505ee2bc3acf02" - integrity sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q== - dependencies: - decode-named-character-reference "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-decode-numeric-character-reference "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-decode-string@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz#7dfa3a63c45aecaa17824e656bcdb01f9737154a" @@ -6553,45 +6684,30 @@ micromark-util-decode-string@^2.0.0: micromark-util-decode-numeric-character-reference "^2.0.0" micromark-util-symbol "^2.0.0" -micromark-util-encode@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz#2c1c22d3800870ad770ece5686ebca5920353383" - integrity sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA== - micromark-util-encode@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz#0921ac7953dc3f1fd281e3d1932decfdb9382ab1" integrity sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA== -micromark-util-events-to-acorn@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.0.4.tgz#07d26cd675dbca8c38b8d9aff2d4cdc91c9997aa" - integrity sha512-dpo8ecREK5s/KMph7jJ46RLM6g7N21CMc9LAJQbDLdbQnTpijigkSJPTIfLXZ+h5wdXlcsQ+b6ufAE9v76AdgA== +micromark-util-events-to-acorn@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz#4275834f5453c088bd29cd72dfbf80e3327cec07" + integrity sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA== dependencies: "@types/acorn" "^4.0.0" - "@types/estree" "^0.0.50" - estree-util-visit "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" - -micromark-util-html-tag-name@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.0.0.tgz#75737e92fef50af0c6212bd309bc5cb8dbd489ed" - integrity sha512-NenEKIshW2ZI/ERv9HtFNsrn3llSPZtY337LID/24WeLqMzeZhBEE6BQ0vS2ZBjshm5n40chKtJ3qjAbVV8S0g== + "@types/estree" "^1.0.0" + "@types/unist" "^3.0.0" + devlop "^1.0.0" + estree-util-visit "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + vfile-message "^4.0.0" micromark-util-html-tag-name@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz#ae34b01cbe063363847670284c6255bb12138ec4" integrity sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw== -micromark-util-normalize-identifier@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz#4a3539cb8db954bbec5203952bfe8cedadae7828" - integrity sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg== - dependencies: - micromark-util-symbol "^1.0.0" - micromark-util-normalize-identifier@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz#91f9a4e65fe66cc80c53b35b0254ad67aa431d8b" @@ -6599,13 +6715,6 @@ micromark-util-normalize-identifier@^2.0.0: dependencies: micromark-util-symbol "^2.0.0" -micromark-util-resolve-all@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz#a7c363f49a0162e931960c44f3127ab58f031d88" - integrity sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw== - dependencies: - micromark-util-types "^1.0.0" - micromark-util-resolve-all@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz#189656e7e1a53d0c86a38a652b284a252389f364" @@ -6613,15 +6722,6 @@ micromark-util-resolve-all@^2.0.0: dependencies: micromark-util-types "^2.0.0" -micromark-util-sanitize-uri@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz#27dc875397cd15102274c6c6da5585d34d4f12b2" - integrity sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-encode "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-sanitize-uri@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz#ec8fbf0258e9e6d8f13d9e4770f9be64342673de" @@ -6631,16 +6731,6 @@ micromark-util-sanitize-uri@^2.0.0: micromark-util-encode "^2.0.0" micromark-util-symbol "^2.0.0" -micromark-util-subtokenize@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz#ff6f1af6ac836f8bfdbf9b02f40431760ad89105" - integrity sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA== - dependencies: - micromark-util-chunked "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - micromark-util-subtokenize@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz#9f412442d77e0c5789ffdf42377fa8a2bcbdf581" @@ -6661,7 +6751,7 @@ micromark-util-symbol@^2.0.0: resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz#12225c8f95edf8b17254e47080ce0862d5db8044" integrity sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw== -micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: +micromark-util-types@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.0.2.tgz#f4220fdb319205812f99c40f8c87a9be83eded20" integrity sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w== @@ -6671,29 +6761,6 @@ micromark-util-types@^2.0.0: resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.0.tgz#63b4b7ffeb35d3ecf50d1ca20e68fc7caa36d95e" integrity sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w== -micromark@^3.0.0: - version "3.0.10" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.0.10.tgz#1eac156f0399d42736458a14b0ca2d86190b457c" - integrity sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg== - dependencies: - "@types/debug" "^4.0.0" - debug "^4.0.0" - decode-named-character-reference "^1.0.0" - micromark-core-commonmark "^1.0.1" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-chunked "^1.0.0" - micromark-util-combine-extensions "^1.0.0" - micromark-util-decode-numeric-character-reference "^1.0.0" - micromark-util-encode "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-resolve-all "^1.0.0" - micromark-util-sanitize-uri "^1.0.0" - micromark-util-subtokenize "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.1" - uvu "^0.5.0" - micromark@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.0.tgz#84746a249ebd904d9658cfabc1e8e5f32cbc6249" @@ -6764,20 +6831,13 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== -mini-create-react-context@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e" - integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== - dependencies: - "@babel/runtime" "^7.12.1" - tiny-warning "^1.0.3" - mini-css-extract-plugin@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz#9a1251d15f2035c342d99a468ab9da7a0451b71e" - integrity sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg== + version "2.9.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz#c73a1327ccf466f69026ac22a8e8fd707b78a235" + integrity sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA== dependencies: schema-utils "^4.0.0" + tapable "^2.2.1" minimalistic-assert@^1.0.0: version "1.0.1" @@ -6791,48 +6851,76 @@ minimatch@3.0.4: dependencies: brace-expansion "^1.1.7" -minimatch@^3.0.4, minimatch@^3.1.1: +minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimatch@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" - integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== +minimatch@^8.0.2: + version "8.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" + integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.0, minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" -minimist@^1.0.0, minimist@^1.2.0, minimist@^1.2.5: +minimist@^1.0.0, minimist@^1.2.0: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== -mkdirp-infer-owner@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" - integrity sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw== +minimist@^1.2.5: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== dependencies: - chownr "^2.0.0" - infer-owner "^1.0.4" - mkdirp "^1.0.3" + yallist "^4.0.0" + +minipass@^4.2.4: + version "4.2.8" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" mkdirp@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mri@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" - integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== - -mrmime@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" - integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw== +mrmime@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" + integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== ms@2.0.0: version "2.0.0" @@ -6887,10 +6975,10 @@ node-emoji@^1.10.0: dependencies: lodash "^4.17.21" -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== +node-fetch@2.7.0, node-fetch@^2.6.12: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" @@ -6899,17 +6987,31 @@ node-forge@^1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + node-releases@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666" integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== +nopt@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.1.tgz#1cac0eab9b8e97c9093338446eddd40b2c8ca1e7" + integrity sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w== + dependencies: + abbrev "^2.0.0" + +normalize-package-data@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-6.0.2.tgz#a7bc22167fe24025412bcff0a9651eb768b03506" + integrity sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g== dependencies: - abbrev "1" + hosted-git-info "^7.0.0" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -6931,10 +7033,37 @@ normalize-url@^6.0.1: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== -npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== +npm-install-checks@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-6.3.0.tgz#046552d8920e801fa9f919cad569545d60e826fe" + integrity sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw== + dependencies: + semver "^7.1.1" + +npm-normalize-package-bin@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" + integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== + +npm-package-arg@^11.0.0: + version "11.0.3" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-11.0.3.tgz#dae0c21199a99feca39ee4bfb074df3adac87e2d" + integrity sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw== + dependencies: + hosted-git-info "^7.0.0" + proc-log "^4.0.0" + semver "^7.3.5" + validate-npm-package-name "^5.0.0" + +npm-pick-manifest@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz#83562afde52b0b07cb6244361788d319ce7e8636" + integrity sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA== + dependencies: + npm-install-checks "^6.0.0" + npm-normalize-package-bin "^3.0.0" + npm-package-arg "^11.0.0" + semver "^7.3.5" npm-run-path@^4.0.1: version "4.0.1" @@ -7085,6 +7214,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + package-json@^6.3.0: version "6.5.0" resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" @@ -7136,7 +7270,7 @@ parse-entities@^4.0.0: is-decimal "^2.0.0" is-hexadecimal "^2.0.0" -parse-json@^5.0.0: +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -7146,15 +7280,16 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse-json@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-6.0.2.tgz#6bf79c201351cc12d5d66eba48d5a097c13dc200" - integrity sha512-SA5aMiaIjXkAiBrW/yPgLgQAQg42f7K3ACO+2l/zOvtQBwX58DMUsFJXelW2fx3yMBmWOVkR6j1MGsdSbCA4UA== +parse-json@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-7.1.1.tgz#68f7e6f0edf88c54ab14c00eb700b753b14e2120" + integrity sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw== dependencies: - "@babel/code-frame" "^7.16.0" + "@babel/code-frame" "^7.21.4" error-ex "^1.3.2" - json-parse-even-better-errors "^2.3.1" - lines-and-columns "^2.0.2" + json-parse-even-better-errors "^3.0.0" + lines-and-columns "^2.0.3" + type-fest "^3.8.0" parse-numeric-range@^1.3.0: version "1.3.0" @@ -7169,6 +7304,13 @@ parse5-htmlparser2-tree-adapter@^7.0.0: domhandler "^5.0.2" parse5 "^7.0.0" +parse5-parser-stream@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz#d7c20eadc37968d272e2c02660fff92dd27e60e1" + integrity sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow== + dependencies: + parse5 "^7.0.0" + parse5@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" @@ -7181,6 +7323,13 @@ parse5@^7.0.0: dependencies: entities "^4.3.0" +parse5@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" + parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -7224,6 +7373,14 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.11.1, path-scurry@^1.6.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" @@ -7246,12 +7403,22 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: +picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -7283,22 +7450,22 @@ postcss-calc@^8.2.3: postcss-selector-parser "^6.0.9" postcss-value-parser "^4.2.0" -postcss-colormin@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.0.tgz#3cee9e5ca62b2c27e84fce63affc0cfb5901956a" - integrity sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg== +postcss-colormin@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.1.tgz#86c27c26ed6ba00d96c79e08f3ffb418d1d1988f" + integrity sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ== dependencies: - browserslist "^4.16.6" + browserslist "^4.21.4" caniuse-api "^3.0.0" colord "^2.9.1" postcss-value-parser "^4.2.0" -postcss-convert-values@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.2.tgz#31586df4e184c2e8890e8b34a0b9355313f503ab" - integrity sha512-c6Hzc4GAv95B7suy4udszX9Zy4ETyMCgFPUDtWjdFTKH1SE9eFY/jEpHSwTH1QPuwxHpWslhckUQWbNRM4ho5g== +postcss-convert-values@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz#04998bb9ba6b65aa31035d669a6af342c5f9d393" + integrity sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA== dependencies: - browserslist "^4.20.3" + browserslist "^4.21.4" postcss-value-parser "^4.2.0" postcss-discard-comments@^5.1.2: @@ -7329,13 +7496,13 @@ postcss-discard-unused@^5.1.0: postcss-selector-parser "^6.0.5" postcss-loader@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.0.0.tgz#367d10eb1c5f1d93700e6b399683a6dc7c3af396" - integrity sha512-IDyttebFzTSY6DI24KuHUcBjbAev1i+RyICoPEWcAstZsj03r533uMXtDn506l6/wlsRYiS5XBdx7TpccCsyUg== + version "7.3.4" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.3.4.tgz#aed9b79ce4ed7e9e89e56199d25ad1ec8f606209" + integrity sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A== dependencies: - cosmiconfig "^7.0.0" - klona "^2.0.5" - semver "^7.3.7" + cosmiconfig "^8.3.5" + jiti "^1.20.0" + semver "^7.5.4" postcss-merge-idents@^5.1.1: version "5.1.1" @@ -7345,20 +7512,20 @@ postcss-merge-idents@^5.1.1: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-merge-longhand@^5.1.6: - version "5.1.6" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.6.tgz#f378a8a7e55766b7b644f48e5d8c789ed7ed51ce" - integrity sha512-6C/UGF/3T5OE2CEbOuX7iNO63dnvqhGZeUnKkDeifebY0XqkkvrctYSZurpNE902LDf2yKwwPFgotnfSoPhQiw== +postcss-merge-longhand@^5.1.7: + version "5.1.7" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz#24a1bdf402d9ef0e70f568f39bdc0344d568fb16" + integrity sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ== dependencies: postcss-value-parser "^4.2.0" - stylehacks "^5.1.0" + stylehacks "^5.1.1" -postcss-merge-rules@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.2.tgz#7049a14d4211045412116d79b751def4484473a5" - integrity sha512-zKMUlnw+zYCWoPN6yhPjtcEdlJaMUZ0WyVcxTAmw3lkkN/NDMRkOkiuctQEoWAOvH7twaxUUdvBWl0d4+hifRQ== +postcss-merge-rules@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz#2f26fa5cacb75b1402e213789f6766ae5e40313c" + integrity sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g== dependencies: - browserslist "^4.16.6" + browserslist "^4.21.4" caniuse-api "^3.0.0" cssnano-utils "^3.1.0" postcss-selector-parser "^6.0.5" @@ -7379,12 +7546,12 @@ postcss-minify-gradients@^5.1.1: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-minify-params@^5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.3.tgz#ac41a6465be2db735099bbd1798d85079a6dc1f9" - integrity sha512-bkzpWcjykkqIujNL+EVEPOlLYi/eZ050oImVtHU7b4lFS82jPnsCb44gvC6pxaNt38Els3jWYDHTjHKf0koTgg== +postcss-minify-params@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz#c06a6c787128b3208b38c9364cfc40c8aa5d7352" + integrity sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw== dependencies: - browserslist "^4.16.6" + browserslist "^4.21.4" cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" @@ -7395,24 +7562,24 @@ postcss-minify-selectors@^5.2.1: dependencies: postcss-selector-parser "^6.0.5" -postcss-modules-extract-imports@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" - integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== +postcss-modules-extract-imports@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz#b4497cb85a9c0c4b5aabeb759bb25e8d89f15002" + integrity sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q== -postcss-modules-local-by-default@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" - integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== +postcss-modules-local-by-default@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz#f1b9bd757a8edf4d8556e8d0f4f894260e3df78f" + integrity sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw== dependencies: icss-utils "^5.0.0" postcss-selector-parser "^6.0.2" postcss-value-parser "^4.1.0" -postcss-modules-scope@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" - integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== +postcss-modules-scope@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz#a43d28289a169ce2c15c00c4e64c0858e43457d5" + integrity sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ== dependencies: postcss-selector-parser "^6.0.4" @@ -7463,12 +7630,12 @@ postcss-normalize-timing-functions@^5.1.0: dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-unicode@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.0.tgz#3d23aede35e160089a285e27bf715de11dc9db75" - integrity sha512-J6M3MizAAZ2dOdSjy2caayJLQT8E8K9XjLce8AUQMwOrCvjCHv24aLC/Lps1R1ylOfol5VIDMaM/Lo9NGlk1SQ== +postcss-normalize-unicode@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz#f67297fca3fea7f17e0d2caa40769afc487aa030" + integrity sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA== dependencies: - browserslist "^4.16.6" + browserslist "^4.21.4" postcss-value-parser "^4.2.0" postcss-normalize-url@^5.1.0: @@ -7501,12 +7668,12 @@ postcss-reduce-idents@^5.2.0: dependencies: postcss-value-parser "^4.2.0" -postcss-reduce-initial@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.0.tgz#fc31659ea6e85c492fb2a7b545370c215822c5d6" - integrity sha512-5OgTUviz0aeH6MtBjHfbr57tml13PuedK/Ecg8szzd4XRMbYxH4572JFG067z+FqBIf6Zp/d+0581glkvvWMFw== +postcss-reduce-initial@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz#798cd77b3e033eae7105c18c9d371d989e1382d6" + integrity sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg== dependencies: - browserslist "^4.16.6" + browserslist "^4.21.4" caniuse-api "^3.0.0" postcss-reduce-transforms@^5.1.0: @@ -7516,7 +7683,7 @@ postcss-reduce-transforms@^5.1.0: dependencies: postcss-value-parser "^4.2.0" -postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9: +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: version "6.0.10" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== @@ -7524,12 +7691,20 @@ postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector cssesc "^3.0.0" util-deprecate "^1.0.2" +postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9: + version "6.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" + integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + postcss-sort-media-queries@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/postcss-sort-media-queries/-/postcss-sort-media-queries-4.2.1.tgz#a99bae69ef1098ee3b64a5fa94d258ec240d0355" - integrity sha512-9VYekQalFZ3sdgcTjXMa0dDjsfBVHXlraYJEMiOJ/2iMmI2JGCMavP16z3kWOaRu8NSaJCTgVpB/IVpH5yT9YQ== + version "4.4.1" + resolved "https://registry.yarnpkg.com/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz#04a5a78db3921eb78f28a1a781a2e68e65258128" + integrity sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw== dependencies: - sort-css-media-queries "2.0.4" + sort-css-media-queries "2.1.0" postcss-svgo@^5.1.0: version "5.1.0" @@ -7556,13 +7731,13 @@ postcss-zindex@^5.1.0: resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-5.1.0.tgz#4a5c7e5ff1050bd4c01d95b1847dfdcc58a496ff" integrity sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A== -postcss@^8.3.11, postcss@^8.4.13, postcss@^8.4.14, postcss@^8.4.7: - version "8.4.38" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e" - integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== +postcss@^8.3.11, postcss@^8.4.14, postcss@^8.4.17, postcss@^8.4.33: + version "8.4.41" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681" + integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ== dependencies: nanoid "^3.3.7" - picocolors "^1.0.0" + picocolors "^1.0.1" source-map-js "^1.2.0" prepend-http@^2.0.0: @@ -7583,26 +7758,47 @@ pretty-time@^1.1.0: resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA== -prism-react-renderer@1.3.5, prism-react-renderer@^1.3.5: +prism-react-renderer@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-2.3.1.tgz#e59e5450052ede17488f6bc85de1553f584ff8d5" + integrity sha512-Rdf+HzBLR7KYjzpJ1rSoxT9ioO85nZngQEoFIhL07XhtJHlCU3SOz0GJ6+qvMyQe0Se+BV3qpe6Yd/NmQF5Juw== + dependencies: + "@types/prismjs" "^1.26.0" + clsx "^2.0.0" + +prism-react-renderer@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz#786bb69aa6f73c32ba1ee813fbe17a0115435085" integrity sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg== prismjs@^1.28.0: - version "1.28.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.28.0.tgz#0d8f561fa0f7cf6ebca901747828b149147044b6" - integrity sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw== + version "1.29.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12" + integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q== -proc-log@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-2.0.1.tgz#8f3f69a1f608de27878f91f5c688b225391cb685" - integrity sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw== +proc-log@^4.0.0, proc-log@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-4.2.0.tgz#b6f461e4026e75fdfe228b265e9f7a00779d7034" + integrity sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA== process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== + +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -7618,7 +7814,7 @@ prompts@^2.4.2: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.7.2: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -7670,7 +7866,7 @@ pupa@^2.1.1: pure-color@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e" - integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4= + integrity sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA== qs@6.11.0: version "6.11.0" @@ -7718,7 +7914,7 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.2.8: +rc@1.2.8, rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -7731,7 +7927,7 @@ rc@^1.2.8: react-base16-styling@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c" - integrity sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw= + integrity sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ== dependencies: base16 "^1.0.0" lodash.curry "^4.0.1" @@ -7768,14 +7964,14 @@ react-dev-utils@^12.0.1: strip-ansi "^6.0.1" text-table "^0.2.0" -react-dom@17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== +react-dom@17.0.0: + version "17.0.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.0.tgz#f8266e4d9861584553ccbd186d596a1c7dd8dcb4" + integrity sha512-OGnFbxCjI2TMAZYMVxi4hqheJiN8rCEVVrL7XIGzCB6beNc4Am8M47HtkvxODZw9QgjmAPKpLba9FTu4fC1byA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - scheduler "^0.20.2" + scheduler "^0.20.0" react-error-overlay@^6.0.11: version "6.0.11" @@ -7825,6 +8021,13 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1: dependencies: "@babel/runtime" "^7.10.3" +react-loadable@5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/react-loadable/-/react-loadable-5.5.0.tgz#582251679d3da86c32aae2c8e689c59f1196d8c4" + integrity sha512-C8Aui0ZpMd4KokxRdVAm2bQtI03k2RMRNzOB+IipV3yxFTSVICv7WoUr5L9ALB5BmKO1iHgZtWM8EvYG83otdg== + dependencies: + prop-types "^15.5.0" + "react-loadable@npm:@docusaurus/react-loadable@5.5.2": version "5.5.2" resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz#81aae0db81ecafbdaee3651f12804580868fa6ce" @@ -7841,28 +8044,27 @@ react-router-config@^5.1.1: "@babel/runtime" "^7.1.2" react-router-dom@^5.3.3: - version "5.3.3" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.3.tgz#8779fc28e6691d07afcaf98406d3812fe6f11199" - integrity sha512-Ov0tGPMBgqmbu5CDmN++tv2HQ9HlWDuWIIqn4b88gjlAN5IHI+4ZUZRcpz9Hl0azFIwihbLDYw1OiHGRo7ZIng== + version "5.3.4" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.4.tgz#2ed62ffd88cae6db134445f4a0c0ae8b91d2e5e6" + integrity sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ== dependencies: "@babel/runtime" "^7.12.13" history "^4.9.0" loose-envify "^1.3.1" prop-types "^15.6.2" - react-router "5.3.3" + react-router "5.3.4" tiny-invariant "^1.0.2" tiny-warning "^1.0.0" -react-router@5.3.3, react-router@^5.3.3: - version "5.3.3" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.3.3.tgz#8e3841f4089e728cf82a429d92cdcaa5e4a3a288" - integrity sha512-mzQGUvS3bM84TnbtMYR8ZjKnuPJ71IjSzR+DE6UkUqvN4czWIqEs17yLL8xkAycv4ev0AiN+IGrWu88vJs/p2w== +react-router@5.3.4, react-router@^5.3.3: + version "5.3.4" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.3.4.tgz#8ca252d70fcc37841e31473c7a151cf777887bb5" + integrity sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA== dependencies: "@babel/runtime" "^7.12.13" history "^4.9.0" hoist-non-react-statics "^3.1.0" loose-envify "^1.3.1" - mini-create-react-context "^0.4.0" path-to-regexp "^1.7.0" prop-types "^15.6.2" react-is "^16.6.0" @@ -7870,38 +8072,38 @@ react-router@5.3.3, react-router@^5.3.3: tiny-warning "^1.0.0" react-textarea-autosize@^8.3.2: - version "8.3.3" - resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz#f70913945369da453fd554c168f6baacd1fa04d8" - integrity sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ== + version "8.5.3" + resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.5.3.tgz#d1e9fe760178413891484847d3378706052dd409" + integrity sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ== dependencies: - "@babel/runtime" "^7.10.2" - use-composed-ref "^1.0.0" - use-latest "^1.0.0" + "@babel/runtime" "^7.20.13" + use-composed-ref "^1.3.0" + use-latest "^1.2.1" -react-twemoji@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/react-twemoji/-/react-twemoji-0.5.0.tgz#0565f8e427fc4c9ef3680977c4a88fbdef79f874" - integrity sha512-xz3NLWTFCfWOmPd559jcFX4f976ORIPpL9SwdBQO5BZwIYD1U1vpbY2E6k2vwPCVH78s2m1GbG5jpHKGUPZ+gw== +react-twemoji@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/react-twemoji/-/react-twemoji-0.6.0.tgz#e07aa284107c5feb49b45259b5ff66e5e278ee6a" + integrity sha512-D7lP83ysE+yXZd5U1RV3aFiD90D0LCz5tgDaIXt4AYazCakGVTYClof8lf0uYLr4TzDHgYX46rMASEEqiopSAQ== dependencies: + "@twemoji/api" "15.1.0" lodash.isequal "^4.5.0" prop-types "^15.7.2" - twemoji "14.0.1" -react@17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== +react@17.0.0: + version "17.0.0" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.0.tgz#ad96d5fa1a33bb9b06d0cc52672f7992d84aa662" + integrity sha512-rG9bqS3LMuetoSUKHN8G3fMNuQOePKDThK6+2yXFWtoeTDLVNh/QCaxT+Jr+rNf4lwNXpx+atdn3Aa0oi8/6eQ== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" -read-package-json-fast@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" - integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== +read-package-json-fast@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz#394908a9725dc7a5f14e70c8e7556dff1d2b1049" + integrity sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw== dependencies: - json-parse-even-better-errors "^2.3.0" - npm-normalize-package-bin "^1.0.1" + json-parse-even-better-errors "^3.0.0" + npm-normalize-package-bin "^3.0.0" readable-stream@^2.0.1: version "2.3.7" @@ -7958,6 +8160,13 @@ regenerate-unicode-properties@^10.0.1: dependencies: regenerate "^1.4.2" +regenerate-unicode-properties@^10.1.0: + version "10.1.1" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz#6b0e05489d9076b04c436f318d9b067bba459480" + integrity sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q== + dependencies: + regenerate "^1.4.2" + regenerate@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" @@ -7968,24 +8177,17 @@ regenerator-runtime@^0.13.4: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== -regenerator-transform@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537" - integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg== - dependencies: - "@babel/runtime" "^7.8.4" +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== -regexpu-core@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.0.1.tgz#c531122a7840de743dcf9c83e923b5560323ced3" - integrity sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw== +regenerator-transform@^0.15.2: + version "0.15.2" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" + integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties "^10.0.1" - regjsgen "^0.6.0" - regjsparser "^0.8.2" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.0.0" + "@babel/runtime" "^7.8.4" regexpu-core@^5.1.0: version "5.1.0" @@ -7999,12 +8201,24 @@ regexpu-core@^5.1.0: unicode-match-property-ecmascript "^2.0.0" unicode-match-property-value-ecmascript "^2.0.0" +regexpu-core@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" + integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== + dependencies: + "@babel/regjsgen" "^0.8.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^10.1.0" + regjsparser "^0.9.1" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + registry-auth-token@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" - integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== + version "4.2.2" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.2.tgz#f02d49c3668884612ca031419491a13539e21fac" + integrity sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg== dependencies: - rc "^1.2.8" + rc "1.2.8" registry-url@^5.0.0: version "5.1.0" @@ -8025,18 +8239,27 @@ regjsparser@^0.8.2: dependencies: jsesc "~0.5.0" +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== + dependencies: + jsesc "~0.5.0" + relateurl@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== -remark-cli@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/remark-cli/-/remark-cli-11.0.0.tgz#302c15c5e73c0b422a6709f65adb74cac3b5eb53" - integrity sha512-8JEWwArXquRq1/In4Ftz7gSG9Scwb1ijT2/dEuBETW9omqhmMRxcfjZ3iKqrak3BnCJeZSXCdWEmPhFKC8+RUQ== +remark-cli@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/remark-cli/-/remark-cli-12.0.1.tgz#991ede01adfdf0471177c381168105da4b93f99a" + integrity sha512-2NAEOACoTgo+e+YAaCTODqbrWyhMVmlUyjxNCkTrDRHHQvH6+NbrnqVvQaLH/Q8Ket3v90A43dgAJmXv8y5Tkw== dependencies: - remark "^14.0.0" - unified-args "^10.0.0" + import-meta-resolve "^4.0.0" + markdown-extensions "^2.0.0" + remark "^15.0.0" + unified-args "^11.0.0" remark-comment@^1.0.0: version "1.0.0" @@ -8071,321 +8294,322 @@ remark-frontmatter@^5.0.0: micromark-extension-frontmatter "^2.0.0" unified "^11.0.0" -remark-gfm@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f" - integrity sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig== +remark-gfm@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-4.0.0.tgz#aea777f0744701aa288b67d28c43565c7e8c35de" + integrity sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-gfm "^2.0.0" - micromark-extension-gfm "^2.0.0" - unified "^10.0.0" + "@types/mdast" "^4.0.0" + mdast-util-gfm "^3.0.0" + micromark-extension-gfm "^3.0.0" + remark-parse "^11.0.0" + remark-stringify "^11.0.0" + unified "^11.0.0" -remark-lint-blockquote-indentation@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-blockquote-indentation/-/remark-lint-blockquote-indentation-3.1.1.tgz#756c099efd43a125f04df329bfe84398358758b6" - integrity sha512-u9cjedM6zcK8vRicis5n/xeOSDIC3FGBCKc3K9pqw+nNrOjY85FwxDQKZZ/kx7rmkdRZEhgyHak+wzPBllcxBQ== +remark-lint-blockquote-indentation@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-blockquote-indentation/-/remark-lint-blockquote-indentation-4.0.0.tgz#8b3860881c224d8e3f017ec516acf37dd2df1c03" + integrity sha512-hdUvn+KsJbBKpY9jLY01PmfpJ/WGhLu9GJMXQGU8ADXJc+F5DWSgKAr6GQ1IUKqvGYdEML/KZ61WomWFUuecVA== dependencies: - "@types/mdast" "^3.0.0" + "@types/mdast" "^4.0.0" + mdast-util-phrasing "^4.0.0" pluralize "^8.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" -remark-lint-checkbox-character-style@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-checkbox-character-style/-/remark-lint-checkbox-character-style-4.1.1.tgz#8d42edf52e7b359cf76ff7a6ba344dc70c933025" - integrity sha512-KPSW3wfHfB8m9hzrtHiBHCTUIsOPX5nZR7VM+2pMjwqnhI6Mp94DKprkNo1ekNZALNeoZIDWZUSYxSiiwFfmVQ== +remark-lint-checkbox-character-style@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-checkbox-character-style/-/remark-lint-checkbox-character-style-5.0.0.tgz#f41628a77bb3062391c3c2cdaa639e7be6719416" + integrity sha512-K0G/Nok59fb2q5KUxcemBVt+ymnhTkDVLJAatZ4PAh9At8y0DGctHdU27jWsuvO0Fs7Zy62Usk7IJE2VO89p1w== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + mdast-util-phrasing "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint-code-block-style@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/remark-lint-code-block-style/-/remark-lint-code-block-style-3.1.0.tgz#5a2d122d01f9175e762f81a144fc18e1a91a104c" - integrity sha512-Hv4YQ8ueLGpjItla4CkcOkcfGj+nlquqylDgCm1/xKnW+Ke2a4qVTMVJrP9Krp4FWmXgktJLDHjhRH+pzhDXLg== +remark-lint-code-block-style@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-code-block-style/-/remark-lint-code-block-style-4.0.0.tgz#cd85582e11a5182fcbca59a1591e39c6867d2bcc" + integrity sha512-LKBKMVruEO0tzDnnnqi1TfUcnwY6Mo7cVtZM4E4pKt3KMhtvgU2wD68/MxDOEJd0pmnLrEgIadv74bY0gWhZpg== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + mdast-util-phrasing "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint-emphasis-marker@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-emphasis-marker/-/remark-lint-emphasis-marker-3.1.1.tgz#3f3336ba4be97b8296eb1019338237d61b4e3db8" - integrity sha512-VduuT+KAr0vA78xBLJdIcenCQja4mAd81aNACfdz7BUPLphIQa84D5uzl+nZatSaCXLebCNp5jP/bzVUsBmRKw== +remark-lint-emphasis-marker@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-emphasis-marker/-/remark-lint-emphasis-marker-4.0.0.tgz#9d2f6515116479641ec6e602e3c8e7276a81c165" + integrity sha512-xIRiB4PFWUOyIslN/UOPL6Lh+J0VD4R11+jo+W4hpGMNsg58l+2SgtdbinlXzDeoBxmaaka9n/sYpJ7cJWEIPQ== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint-fenced-code-marker@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-fenced-code-marker/-/remark-lint-fenced-code-marker-3.1.1.tgz#ee977552bd130f1f1305301f97160d31ff6b7461" - integrity sha512-x/t8sJWPvE46knKz6zW03j9VX5477srHUmRFbnXhZ3K8e37cYVUIvfbPhcPCAosSsOki9+dvGfZsWQiKuUNNfQ== +remark-lint-fenced-code-marker@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-fenced-code-marker/-/remark-lint-fenced-code-marker-4.0.0.tgz#eb2587fdc7711fb890e646d5902761c54c2f88ce" + integrity sha512-WFN88Rx78m4/HSbW3Kx2XAYbVfzYns4bJd9qpwDD90DA3nc59zciYd01xi6Bk3n9vSs5gIlmG7xkwxVHHJ8KCA== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + mdast-util-phrasing "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint-final-newline@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-final-newline/-/remark-lint-final-newline-2.1.1.tgz#dac4e5ae92638808fb6e2de6164c43890f1248a5" - integrity sha512-cgKYaI7ujUse/kV4KajLv2j1kmi1CxpAu+w7wIU0/Faihhb3sZAf4a5ACf2Wu8NoTSIr1Q//3hDysG507PIoDg== +remark-lint-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-final-newline/-/remark-lint-final-newline-3.0.0.tgz#f436b4c228ae088b80072f7c3eac97678232e10a" + integrity sha512-NaPyn6FiOn3IV/6gIcwWfJmgraPT2IaVLjhakfPglZkKVfn/FrOfETyY8Bp+HLoSRI9967OH0yRDnK7/pPIWeQ== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + unified-lint-rule "^3.0.0" + vfile-location "^5.0.0" -remark-lint-hard-break-spaces@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-hard-break-spaces/-/remark-lint-hard-break-spaces-3.1.1.tgz#daaa6fbc9d08a0501dc6e3d4a844dc4783bdfaea" - integrity sha512-UfwFvESpX32qwyHJeluuUuRPWmxJDTkmjnWv2r49G9fC4Jrzm4crdJMs3sWsrGiQ3mSex6bgp/8rqDgtBng2IA== +remark-lint-hard-break-spaces@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-hard-break-spaces/-/remark-lint-hard-break-spaces-4.0.0.tgz#6392f242a4188b346ed196a6e8c6834af1a31c82" + integrity sha512-zCTq7/xfM0ZL3bMopXse9DH2nk38wE1LrxmYwnTrqASBLnEAJWE2U2//tRGVMEBfSAnNvmIo96twz6zkLWjbGA== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit "^5.0.0" -remark-lint-heading-style@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-heading-style/-/remark-lint-heading-style-3.1.1.tgz#19e321db9dc6c697f3ef8bf514a8b15323422776" - integrity sha512-Qm7ZAF+s46ns0Wo5TlHGIn/PPMMynytn8SSLEdMIo6Uo/+8PAcmQ3zU1pj57KYxfyDoN5iQPgPIwPYMLYQ2TSQ== +remark-lint-heading-style@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-heading-style/-/remark-lint-heading-style-4.0.0.tgz#9c7b5b8fb210132ac2db8e541efc10569c2cef66" + integrity sha512-dQ6Jul5K0+aNUvrq4W7H0+osSoC9hsmwHZqBFq000+eMP/hWJqI8tuudw1rap8HHYuOsKLRbB5q+Fr7G+3Vw+Q== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-heading-style "^2.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + mdast-util-heading-style "^3.0.0" + mdast-util-phrasing "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint-link-title-style@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-link-title-style/-/remark-lint-link-title-style-3.1.1.tgz#eb1a773816b4bee43170745245e9fed776633a7d" - integrity sha512-JWWiuUFy/N2iwQ3eWIxFy6olX8D7xCFw8LoM0vZI2CHTZJrmDMaWwnl8jziP+HHHheFX3wkVqsoaYod536ArRw== +remark-lint-link-title-style@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-link-title-style/-/remark-lint-link-title-style-4.0.0.tgz#4f78f9ba7178e095aa15b882e5ecdf720f05942a" + integrity sha512-cihTO5dkhjMj/evYIDAvRdQHD82OQeF4fNAq8FLb81HmFKo77VlSF6CK55H1bvlZogfJG58uN/5d1tSsOdcEbg== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" - vfile-location "^4.0.0" + "@types/mdast" "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint-list-item-bullet-indent@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-list-item-bullet-indent/-/remark-lint-list-item-bullet-indent-4.1.1.tgz#1ff4498b680bb4a8ce94a4192a1b52eca4c9fe48" - integrity sha512-NFvXVj1Nm12+Ma48NOjZCGb/D0IhmUcxyrTCpPp+UNJhEWrmFxM8nSyIiZgXadgXErnuv+xm2Atw7TAcZ9a1Cg== +remark-lint-list-item-bullet-indent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-list-item-bullet-indent/-/remark-lint-list-item-bullet-indent-5.0.0.tgz#1b2428c49e3220795aafec535e96da85d54d4a26" + integrity sha512-qq22QaxsDjfsL7aWGIPmP3P0N99CJBQQW1+iSrhYAMCDzqVlw6I3wPNAeR6s8mcoeHT8YlT6eQH3V8xJ0SlW6w== dependencies: - "@types/mdast" "^3.0.0" + "@types/mdast" "^4.0.0" pluralize "^8.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-visit "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" -remark-lint-list-item-content-indent@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-list-item-content-indent/-/remark-lint-list-item-content-indent-3.1.1.tgz#9fff6bf4e1a08e86d99430838b822b8209dca15e" - integrity sha512-gcZhAXLd1onkutTEqQTybyANjdxvlOlu0y/AU4H3f6L99UGC85ymRhEeu5vGSkvsKKPR1FrMTEH6G2nNgtavgg== +remark-lint-list-item-content-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-list-item-content-indent/-/remark-lint-list-item-content-indent-4.0.0.tgz#2aa75671757ad9b183eec5a334e251d50de8c527" + integrity sha512-L4GZgWQQ54qWKbnDle3dbEOtnq+qdmZJ70lpM3yMFEMHs4xejqPKsIoiYeUtIV0rYHHCWS7IlLzcgYUK9vENQw== dependencies: - "@types/mdast" "^3.0.0" + "@types/mdast" "^4.0.0" + mdast-util-phrasing "^4.0.0" pluralize "^8.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint-list-item-indent@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-list-item-indent/-/remark-lint-list-item-indent-3.1.1.tgz#1591d291a9f81c8f14219bdb63f226a5e9f271c3" - integrity sha512-OSTG64e52v8XBmmeT0lefpiAfCMYHJxMMUrMnhTjLVyWAbEO0vqqR5bLvfLwzK+P4nY2D/8XKku0hw35dM86Rw== +remark-lint-list-item-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-list-item-indent/-/remark-lint-list-item-indent-4.0.0.tgz#d72e7ef4c7ea238987e5475e33439b7efbe46389" + integrity sha512-Yd6/g8CH9e4vlPAPNgl7F575uKhP+pTo/qwGkE61GOcgEVNJ/529hjumUhyQ4sOAX0YAPAjxvq6fJvb4AhVOOA== dependencies: - "@types/mdast" "^3.0.0" + "@types/mdast" "^4.0.0" + mdast-util-phrasing "^4.0.0" pluralize "^8.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" -remark-lint-no-blockquote-without-marker@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-no-blockquote-without-marker/-/remark-lint-no-blockquote-without-marker-5.1.1.tgz#e07233866a742c41368886663d7caebbdebb1074" - integrity sha512-7jL7eKS25kKRhQ7SKKB5eRfNleDMWKWAmZ5Y/votJdDoM+6qsopLLumPWaSzP0onyV3dyHRhPfBtqelt3hvcyA== +remark-lint-no-blockquote-without-marker@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-no-blockquote-without-marker/-/remark-lint-no-blockquote-without-marker-6.0.0.tgz#cc243d86f6548492150b5a7871f99afad9653973" + integrity sha512-fBhoTpkWcl5tG4FdwPdJIyb8XLrdr6MdLk1+K2BQ6Rom3rRsIYvuox4ohxOunNrXuth8xyw8kC6wDmODR44oFw== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" - vfile-location "^4.0.0" - -remark-lint-no-duplicate-definitions@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-no-duplicate-definitions/-/remark-lint-no-duplicate-definitions-3.1.1.tgz#2f5042b8d2274d94a9423767c6e714b57c6a2dbf" - integrity sha512-9p+nBz8VvV+t4g/ALNLVN8naV+ffAzC4ADyg9QivzmKwLjyF93Avt4HYNlb2GZ+aoXRQSVG1wjjWFeDC9c7Tdg== + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-directive "^3.0.0" + mdast-util-phrasing "^4.0.0" + pluralize "^8.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-location "^5.0.0" + +remark-lint-no-duplicate-definitions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-no-duplicate-definitions/-/remark-lint-no-duplicate-definitions-4.0.0.tgz#ac9ff0f7dd373fd58521f57406625e03ef40ce42" + integrity sha512-21fcOACkCyhNsHkedKlpvqIywYx+5zGR507bW8e59gzdGhTbnBwQ9du4ACmN9jxPTfIBhUVMz0bWezkGrHE7Bg== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-stringify-position "^3.0.0" - unist-util-visit "^4.0.0" - -remark-lint-no-heading-content-indent@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-no-heading-content-indent/-/remark-lint-no-heading-content-indent-4.1.1.tgz#e4afb9872d12b29805c183999f5cb3adca9f394c" - integrity sha512-W4zF7MA72IDC5JB0qzciwsnioL5XlnoE0r1F7sDS0I5CJfQtHYOLlxb3UAIlgRCkBokPWCp0E4o1fsY/gQUKVg== + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-phrasing "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" + +remark-lint-no-heading-content-indent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-no-heading-content-indent/-/remark-lint-no-heading-content-indent-5.0.0.tgz#a83956dab3675dfe032ac1a7523d874be6185121" + integrity sha512-psYSlD2BjcVkgpeXOLwPcYFBrbtJWp8E8JX1J4vSfoHPeY6aIxgYxXkf57cjGTApfRL8xawBmMDiF1FgQvpZYg== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-heading-style "^2.0.0" + "@types/mdast" "^4.0.0" + mdast-util-phrasing "^4.0.0" pluralize "^8.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" -remark-lint-no-inline-padding@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-no-inline-padding/-/remark-lint-no-inline-padding-4.1.1.tgz#2f1dda78556f1f8a98b4cad52ff74f6a56b55c58" - integrity sha512-++IMm6ohOPKNOrybqjP9eiclEtVX/Rd2HpF2UD9icrC1X5nvrI6tlfN55tePaFvWAB7pe6MW4LzNEMnWse61Lw== +remark-lint-no-literal-urls@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-no-literal-urls/-/remark-lint-no-literal-urls-4.0.0.tgz#5b2c40f8ce2c102d823959e7933ae395cd5f8018" + integrity sha512-rl/3Ai4Ax9IH/fRpOJZuXk1HgYX6oFTauhmBOilpqbq/YT2kN3FuXaneXdRfKv1bgMdHaLKxHWxGj/mDyA2n8w== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-string "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + mdast-util-to-string "^4.0.0" + micromark-util-character "^2.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" -remark-lint-no-literal-urls@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-no-literal-urls/-/remark-lint-no-literal-urls-3.1.1.tgz#9e3b71c013ffa3d3a493c98b54c3d5bd0ea0ad23" - integrity sha512-tZZ4gtZMA//ZAf7GJTE8S9yjzqXUfUTlR/lvU7ffc7NeSurqCBwAtHqeXVCHiD39JnlHVSW2MLYhvHp53lBGvA== +remark-lint-no-shortcut-reference-image@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-no-shortcut-reference-image/-/remark-lint-no-shortcut-reference-image-4.0.0.tgz#eb3aa7aec0d41c64f5a18986cbd3e7e62fa98b7f" + integrity sha512-YEiCpW5F/8/LZyxlOuVK2L/n0NJ1AB0AJK7oP39OVyEk3Xl7w+JQi6nZ3KiH6REh+PWGqKn6M0KEPL9cT/iAOw== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-string "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" - -remark-lint-no-shortcut-reference-image@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-no-shortcut-reference-image/-/remark-lint-no-shortcut-reference-image-3.1.1.tgz#3714f31e98ca2063c43bb4cc4d7206e0581da501" - integrity sha512-m8tH+loDagd1JUns/T4eyulVXgVvE+ZSs7owRUOmP+dgsKJuO5sl1AdN9eyKDVMEvxHF3Pm5WqE62QIRNM48mA== + "@types/mdast" "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-visit-parents "^6.0.0" + +remark-lint-no-shortcut-reference-link@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-no-shortcut-reference-link/-/remark-lint-no-shortcut-reference-link-4.0.0.tgz#44c332c3b939dbb9d6b60d9cbcd5929f72658fe7" + integrity sha512-6jka2Zz3I6G2MvDcKrwADYhTOxHMFMK854u1cfBEIH5/XnCCXROtoqiiDtbZw+NJqbmwsBKvGL4t2gnmEJUmgg== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-visit-parents "^6.0.0" -remark-lint-no-shortcut-reference-link@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-no-shortcut-reference-link/-/remark-lint-no-shortcut-reference-link-3.1.1.tgz#b29bc4bfdb02b30a596b5fed235c99e470805130" - integrity sha512-oDJ92/jXQ842HgrBGgZdP7FA+N2jBMCBU2+jRElkS+OWVut0UaDILtNavNy/e85B3SLPj3RoXKF96M4vfJ7B2A== +remark-lint-no-undefined-references@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-no-undefined-references/-/remark-lint-no-undefined-references-5.0.0.tgz#2155f00a95b793ecac1921f7b45ce7c5d6087256" + integrity sha512-O0q8bHpRHK1T85oqO+uep4BkvQnZZp3y+wahDeeLLq9dCJfF56sq6Tt5OOTt1BAOZlpobS3OPQHUiJWYP6hX1w== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + collapse-white-space "^2.0.0" + devlop "^1.0.0" + micromark-util-normalize-identifier "^2.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-location "^5.0.0" -remark-lint-no-undefined-references@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-no-undefined-references/-/remark-lint-no-undefined-references-4.1.1.tgz#66c8049da8a72c5dc758562b85bb3019bd396fc1" - integrity sha512-J20rKfTGflLiTI3T5JlLZSmINk6aDGmZi1y70lpU69LDfAyHAKgDK6sSW9XDeFmCPPdm8Ybxe5Gf2a70k+GcVQ== +remark-lint-no-unused-definitions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-no-unused-definitions/-/remark-lint-no-unused-definitions-4.0.0.tgz#fc7f715d084283ca8b3a3c2e7b6afe87ace9765e" + integrity sha512-YCZ6k575NCTx7mnN+9ls0G6YgMsZHi0LYQqfLW8MNVHBtbpTBvfmk8I39bmsvuKWeBD98weZoXSDqIiIGg+Q/g== dependencies: - "@types/mdast" "^3.0.0" - micromark-util-normalize-identifier "^1.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" - vfile-location "^4.0.0" - -remark-lint-no-unused-definitions@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-no-unused-definitions/-/remark-lint-no-unused-definitions-3.1.1.tgz#584fcd0b1ad569d3e1933256e85b9fb308e88695" - integrity sha512-/GtyBukhAxi5MEX/g/m+FzDEflSbTe2/cpe2H+tJZyDmiLhjGXRdwWnPRDp+mB9g1iIZgVRCk7T4v90RbQX/mw== + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + unified-lint-rule "^3.0.0" + unist-util-visit "^5.0.0" + +remark-lint-ordered-list-marker-style@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-ordered-list-marker-style/-/remark-lint-ordered-list-marker-style-4.0.0.tgz#9a6e8867484ec3edf8ec85699e5cca6a11163102" + integrity sha512-xZ7Xppy5fzACH4b9h1b4lTzVtNY2AlUkNTfl1Oe6cIKN8tk3juFxN0wL2RpktPtSZ7iRIabzFmg6l8WPhlASJA== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + mdast-util-phrasing "^4.0.0" + micromark-util-character "^2.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint-ordered-list-marker-style@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-ordered-list-marker-style/-/remark-lint-ordered-list-marker-style-3.1.1.tgz#5431100f048ef44daa90a32251e8056f2de58449" - integrity sha512-IWcWaJoaSb4yoSOuvDbj9B2uXp9kSj58DqtrMKo8MoRShmbj1onVfulTxoTLeLtI11NvW+mj3jPSpqjMjls+5Q== +remark-lint-ordered-list-marker-value@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-ordered-list-marker-value/-/remark-lint-ordered-list-marker-value-4.0.0.tgz#a0724a161b2dbcd6dd0be6088e851b3183baab0e" + integrity sha512-7UjNU2Nv9LGEONTU9GPmTVoNoGKD5aL1X2xHzMbSJiTc50bfcazYqZawO+qj1pQ04WPhto1qHnl0HRB5wwSVwA== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-phrasing "^4.0.0" + micromark-util-character "^2.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint-rule-style@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-rule-style/-/remark-lint-rule-style-3.1.1.tgz#163b4f394422496c065c95227970657a57c786cf" - integrity sha512-+oZe0ph4DWHGwPkQ/FpqiGp4WULTXB1edftnnNbizYT+Wr+/ux7GNTx78oXH/PHwlnOtVIExMc4W/vDXrUj/DQ== +remark-lint-rule-style@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-rule-style/-/remark-lint-rule-style-4.0.0.tgz#8634deab41768b467329ff8212e982cef583c3f1" + integrity sha512-Kt7IHMB5IbLgRFKaFUmB895sV3PTD0MBgN9CvXKxr1wHFF43S6tabjFIBSoQqyJRlhH0S3rK6Lvopofa009gLg== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + mdast-util-phrasing "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint-strong-marker@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/remark-lint-strong-marker/-/remark-lint-strong-marker-3.1.1.tgz#4f77ba095cacbd8a8bcd7dd834dd792b50b1f3cb" - integrity sha512-tX9Os2C48Hh8P8CouY4dcnAhGnR3trL+NCDqIvJvFDR9Rvm9yfNQaY2N4ZHWVY0iUicq9DpqEiJTgUsT8AGv/w== +remark-lint-strong-marker@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-strong-marker/-/remark-lint-strong-marker-4.0.0.tgz#bbaae75846ccea9753a2f6935d1fb9a3114b9461" + integrity sha512-YcvuzakYhQWdCH+1E30sUY+wyvq+PNa77NZAMAYO/cS/pZczFB+q4Ccttw4Q+No/chX8oMfe0GYtm8dDWLei/g== dependencies: - "@types/mdast" "^3.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint-table-cell-padding@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/remark-lint-table-cell-padding/-/remark-lint-table-cell-padding-4.1.2.tgz#a7087f4513523ca0473986a7a9348847d52e6dad" - integrity sha512-cx5BXjHtpACa7Z51Vuqzy9BI4Z8Hnxz7vklhhrubkoB7mbctP/mR+Nh4B8eE5VtgFYJNHFwIltl96PuoctFCeQ== +remark-lint-table-cell-padding@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/remark-lint-table-cell-padding/-/remark-lint-table-cell-padding-5.0.0.tgz#652392e3b8c61153023e6c14793b30dd1fb2c6b7" + integrity sha512-LNyiHDQZBIOqcQGG1tYsZHW7g0v8OyRmRgDrD5WEsMaAYfM6EiECUokN/Q4py9h4oM/2KUSrdZbtfuZmy87/kA== dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - unified "^10.0.0" - unified-lint-rule "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + devlop "^1.0.0" + mdast-util-phrasing "^4.0.0" + pluralize "^8.0.0" + unified-lint-rule "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit-parents "^6.0.0" + vfile-message "^4.0.0" -remark-lint@^9.0.0: - version "9.1.1" - resolved "https://registry.yarnpkg.com/remark-lint/-/remark-lint-9.1.1.tgz#58c27adc4edeca93b7ce81e2861f05cbcecef72c" - integrity sha512-zhe6twuqgkx/9KgZyNyaO0cceA4jQuJcyzMOBC+JZiAzMN6mFUmcssWZyY30ko8ut9vQDMX/pyQnolGn+Fg/Tw== +remark-lint@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/remark-lint/-/remark-lint-10.0.0.tgz#161b24a18223a68ec2ed8d77e46015b5a0bd8bb5" + integrity sha512-E8yHHDOJ8b+qI0G49BRu24pe8t0fNNBWv8ENQJpCGNrVeTeyBIGEbaUe1yuF7OG8faA6PVpcN/pqWjzW9fcBWQ== dependencies: - "@types/mdast" "^3.0.0" - remark-message-control "^7.0.0" - unified "^10.1.0" + "@types/mdast" "^4.0.0" + remark-message-control "^8.0.0" + unified "^11.0.0" remark-mdx@1.6.22: version "1.6.22" @@ -8401,24 +8625,23 @@ remark-mdx@1.6.22: remark-parse "8.0.3" unified "9.2.0" -remark-mdx@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-2.3.0.tgz#efe678025a8c2726681bde8bf111af4a93943db4" - integrity sha512-g53hMkpM0I98MU266IzDFMrTD980gNF3BJnkyFcmN+dD873mQeD5rdMO3Y2X+x8umQfbSE0PcoEDl7ledSA+2g== +remark-mdx@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-3.0.1.tgz#8f73dd635c1874e44426e243f72c0977cf60e212" + integrity sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA== dependencies: - mdast-util-mdx "^2.0.0" - micromark-extension-mdxjs "^1.0.0" + mdast-util-mdx "^3.0.0" + micromark-extension-mdxjs "^3.0.0" -remark-message-control@^7.0.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/remark-message-control/-/remark-message-control-7.1.1.tgz#71e9b757b835fad2ac14fafa8b432f51b9b9bf52" - integrity sha512-xKRWl1NTBOKed0oEtCd8BUfH5m4s8WXxFFSoo7uUwx6GW/qdCy4zov5LfPyw7emantDmhfWn5PdIZgcbVcWMDQ== +remark-message-control@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/remark-message-control/-/remark-message-control-8.0.0.tgz#1d5880f33c05a65fcd60dcf0572b8198e9935d97" + integrity sha512-brpzOO+jdyE/mLqvqqvbogmhGxKygjpCUCG/PwSCU43+JZQ+RM+sSzkCWBcYvgF3KIAVNIoPsvXjBkzO7EdsYQ== dependencies: - "@types/mdast" "^3.0.0" - mdast-comment-marker "^2.0.0" - unified "^10.0.0" - unified-message-control "^4.0.0" - vfile "^5.0.0" + "@types/mdast" "^4.0.0" + mdast-comment-marker "^3.0.0" + unified-message-control "^5.0.0" + vfile "^6.0.0" remark-parse@8.0.3: version "8.0.3" @@ -8442,58 +8665,57 @@ remark-parse@8.0.3: vfile-location "^3.0.0" xtend "^4.0.1" -remark-parse@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.1.tgz#6f60ae53edbf0cf38ea223fe643db64d112e0775" - integrity sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - unified "^10.0.0" +remark-parse@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-11.0.0.tgz#aa60743fcb37ebf6b069204eb4da304e40db45a1" + integrity sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-from-markdown "^2.0.0" + micromark-util-types "^2.0.0" + unified "^11.0.0" + +remark-preset-lint-consistent@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/remark-preset-lint-consistent/-/remark-preset-lint-consistent-6.0.0.tgz#8ee11b681e1d40f1fd7a5ca1cf2c832df306db56" + integrity sha512-W3fwxajdietwjnFyTH5x2le63hxWGVOXxIs7KjRqU+5wkkN6ZQyuwPeeomblmS9wQr50fkidhXNHNDyCXtqgxQ== + dependencies: + remark-lint "^10.0.0" + remark-lint-blockquote-indentation "^4.0.0" + remark-lint-checkbox-character-style "^5.0.0" + remark-lint-code-block-style "^4.0.0" + remark-lint-emphasis-marker "^4.0.0" + remark-lint-fenced-code-marker "^4.0.0" + remark-lint-heading-style "^4.0.0" + remark-lint-link-title-style "^4.0.0" + remark-lint-list-item-content-indent "^4.0.0" + remark-lint-ordered-list-marker-style "^4.0.0" + remark-lint-ordered-list-marker-value "^4.0.0" + remark-lint-rule-style "^4.0.0" + remark-lint-strong-marker "^4.0.0" + remark-lint-table-cell-padding "^5.0.0" + unified "^11.0.0" -remark-preset-lint-consistent@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/remark-preset-lint-consistent/-/remark-preset-lint-consistent-5.1.2.tgz#d081ad91ab92367d280a4efe355d6fd0819d109e" - integrity sha512-RQrWBFmyIkKfXtp9P1Fui7UbGSfXth9nuvRJUVnO0vfevBJe02iyMZWPokXSwkDOI/cM539wj0i3vrQupz+v5A== - dependencies: - "@types/mdast" "^3.0.0" - remark-lint "^9.0.0" - remark-lint-blockquote-indentation "^3.0.0" - remark-lint-checkbox-character-style "^4.0.0" - remark-lint-code-block-style "^3.0.0" - remark-lint-emphasis-marker "^3.0.0" - remark-lint-fenced-code-marker "^3.0.0" - remark-lint-heading-style "^3.0.0" - remark-lint-link-title-style "^3.0.0" - remark-lint-list-item-content-indent "^3.0.0" - remark-lint-ordered-list-marker-style "^3.0.0" - remark-lint-rule-style "^3.0.0" - remark-lint-strong-marker "^3.0.0" - remark-lint-table-cell-padding "^4.0.0" - unified "^10.0.0" - -remark-preset-lint-recommended@^6.1.3: - version "6.1.3" - resolved "https://registry.yarnpkg.com/remark-preset-lint-recommended/-/remark-preset-lint-recommended-6.1.3.tgz#04b89a963bb7721d736fe731a9d8021d78ec95d7" - integrity sha512-DGjbeP2TsFmQeJflUiIvJWAOs1PxJt7SG3WQyMxOppkRr/up+mxWVkuv+6AUuaR0EsuaaFGz7WmZM5TrSSFWJw== - dependencies: - "@types/mdast" "^3.0.0" - remark-lint "^9.0.0" - remark-lint-final-newline "^2.0.0" - remark-lint-hard-break-spaces "^3.0.0" - remark-lint-list-item-bullet-indent "^4.0.0" - remark-lint-list-item-indent "^3.0.0" - remark-lint-no-blockquote-without-marker "^5.0.0" - remark-lint-no-duplicate-definitions "^3.0.0" - remark-lint-no-heading-content-indent "^4.0.0" - remark-lint-no-inline-padding "^4.0.0" - remark-lint-no-literal-urls "^3.0.0" - remark-lint-no-shortcut-reference-image "^3.0.0" - remark-lint-no-shortcut-reference-link "^3.0.0" - remark-lint-no-undefined-references "^4.0.0" - remark-lint-no-unused-definitions "^3.0.0" - remark-lint-ordered-list-marker-style "^3.0.0" - unified "^10.0.0" +remark-preset-lint-recommended@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/remark-preset-lint-recommended/-/remark-preset-lint-recommended-7.0.0.tgz#fec4288b9a148f63fb04f3f447bc0db1049ec835" + integrity sha512-A9aPDL78OO12xG2a83DVd+M2QzdBMjn545fbXj40BFJdpt9t//MADkPAwRfpMCBkKi+iECPUTFCb3Jm8SsFG2w== + dependencies: + remark-lint "^10.0.0" + remark-lint-final-newline "^3.0.0" + remark-lint-hard-break-spaces "^4.0.0" + remark-lint-list-item-bullet-indent "^5.0.0" + remark-lint-list-item-indent "^4.0.0" + remark-lint-no-blockquote-without-marker "^6.0.0" + remark-lint-no-duplicate-definitions "^4.0.0" + remark-lint-no-heading-content-indent "^5.0.0" + remark-lint-no-literal-urls "^4.0.0" + remark-lint-no-shortcut-reference-image "^4.0.0" + remark-lint-no-shortcut-reference-link "^4.0.0" + remark-lint-no-undefined-references "^5.0.0" + remark-lint-no-unused-definitions "^4.0.0" + remark-lint-ordered-list-marker-style "^4.0.0" + unified "^11.0.0" remark-squeeze-paragraphs@4.0.0: version "4.0.0" @@ -8502,24 +8724,24 @@ remark-squeeze-paragraphs@4.0.0: dependencies: mdast-squeeze-paragraphs "^4.0.0" -remark-stringify@^10.0.0: - version "10.0.2" - resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-10.0.2.tgz#50414a6983f5008eb9e72eed05f980582d1f69d7" - integrity sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw== +remark-stringify@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-11.0.0.tgz#4c5b01dd711c269df1aaae11743eb7e2e7636fd3" + integrity sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-markdown "^1.0.0" - unified "^10.0.0" + "@types/mdast" "^4.0.0" + mdast-util-to-markdown "^2.0.0" + unified "^11.0.0" -remark@^14.0.0: - version "14.0.2" - resolved "https://registry.yarnpkg.com/remark/-/remark-14.0.2.tgz#4a1833f7441a5c29e44b37bb1843fb820797b40f" - integrity sha512-A3ARm2V4BgiRXaUo5K0dRvJ1lbogrbXnhkJRmD0yw092/Yl0kOCZt1k9ZeElEwkZsWGsMumz6qL5MfNJH9nOBA== +remark@^15.0.0: + version "15.0.1" + resolved "https://registry.yarnpkg.com/remark/-/remark-15.0.1.tgz#ac7e7563260513b66426bc47f850e7aa5862c37c" + integrity sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A== dependencies: - "@types/mdast" "^3.0.0" - remark-parse "^10.0.0" - remark-stringify "^10.0.0" - unified "^10.0.0" + "@types/mdast" "^4.0.0" + remark-parse "^11.0.0" + remark-stringify "^11.0.0" + unified "^11.0.0" renderkid@^3.0.0: version "3.0.0" @@ -8552,6 +8774,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== +reselect@^4.1.7: + version "4.1.8" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" + integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -8562,7 +8789,16 @@ resolve-pathname@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== -resolve@^1.1.6, resolve@^1.14.2, resolve@^1.3.2: +resolve@^1.1.6, resolve@^1.22.8, resolve@^1.3.2: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^1.14.2: version "1.22.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== @@ -8578,6 +8814,11 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + retry@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" @@ -8618,19 +8859,12 @@ run-parallel@^1.1.9: queue-microtask "^1.2.2" rxjs@^7.5.4: - version "7.5.5" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" - integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== dependencies: tslib "^2.1.0" -sade@^1.7.3: - version "1.8.1" - resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" - integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== - dependencies: - mri "^1.1.0" - safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -8641,7 +8875,7 @@ safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -8657,10 +8891,10 @@ sass-loader@^10.1.1: schema-utils "^3.0.0" semver "^7.3.2" -sass@1.67.0: - version "1.67.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.67.0.tgz#fed84d74b9cd708db603b1380d6dc1f71bb24f6f" - integrity sha512-SVrO9ZeX/QQyEGtuZYCVxoeAL5vGlYjJ9p4i4HFuekWl8y/LtJ7tJc10Z+ck1c8xOuoBm2MYzcLfTAffD0pl/A== +sass@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.77.8.tgz#9f18b449ea401759ef7ec1752a16373e296b52bd" + integrity sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -8671,7 +8905,7 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scheduler@^0.20.2: +scheduler@^0.20.0: version "0.20.2" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== @@ -8716,6 +8950,11 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" +"search-insights@>=1 <3": + version "2.16.3" + resolved "https://registry.yarnpkg.com/search-insights/-/search-insights-2.16.3.tgz#7128e2c6c8499fff52326dda9209b380d4ee0e0a" + integrity sha512-hSHy/s4Zk2xibhj9XTCACB+1PqS+CaJxepGNBhKc/OsHRpqvHAUAm5+uZ6kJJbGXn0pb3XqekHjg6JAqPExzqg== + section-matter@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" @@ -8729,11 +8968,12 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== -selfsigned@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.0.1.tgz#8b2df7fa56bf014d19b6007655fff209c0ef0a56" - integrity sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ== +selfsigned@^2.1.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.4.1.tgz#560d90565442a3ed35b674034cec4e95dceb4ae0" + integrity sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q== dependencies: + "@types/node-forge" "^1.3.0" node-forge "^1" semver-diff@^3.1.1: @@ -8743,22 +8983,22 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - semver@^5.4.1: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: +semver@^7.1.1, semver@^7.3.4, semver@^7.5.3, semver@^7.5.4: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +semver@^7.3.2, semver@^7.3.5, semver@^7.3.7: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -8799,15 +9039,15 @@ serialize-javascript@^6.0.1: randombytes "^2.1.0" serve-handler@^6.1.3: - version "6.1.3" - resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8" - integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w== + version "6.1.5" + resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.5.tgz#a4a0964f5c55c7e37a02a633232b6f0d6f068375" + integrity sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg== dependencies: bytes "3.0.0" content-disposition "0.5.2" fast-url-parser "1.1.3" mime-types "2.1.18" - minimatch "3.0.4" + minimatch "3.1.2" path-is-inside "1.0.2" path-to-regexp "2.2.1" range-parser "1.2.0" @@ -8838,7 +9078,7 @@ serve-static@1.15.0: setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== setprototypeof@1.1.0: version "1.1.0" @@ -8879,6 +9119,11 @@ shell-quote@^1.7.3: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== +shell-quote@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + shelljs@^0.8.5: version "0.8.5" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" @@ -8902,14 +9147,19 @@ signal-exit@^3.0.2, signal-exit@^3.0.3: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -sirv@^1.0.7: - version "1.0.19" - resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49" - integrity sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +sirv@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.4.tgz#5dd9a725c578e34e449f332703eb2a74e46a29b0" + integrity sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ== dependencies: - "@polka/url" "^1.0.0-next.20" - mrmime "^1.0.0" - totalist "^1.0.0" + "@polka/url" "^1.0.0-next.24" + mrmime "^2.0.0" + totalist "^3.0.0" sisteransi@^1.0.5: version "1.0.5" @@ -8945,10 +9195,10 @@ sockjs@^0.3.24: uuid "^8.3.2" websocket-driver "^0.7.4" -sort-css-media-queries@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/sort-css-media-queries/-/sort-css-media-queries-2.0.4.tgz#b2badfa519cb4a938acbc6d3aaa913d4949dc908" - integrity sha512-PAIsEK/XupCQwitjv7XxoMvYhT7EAfyzI3hsy/MyDgTvc+Ft55ctdkctJLOy6cQejaIC+zjpUL4djFVm2ivOOw== +sort-css-media-queries@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz#7c85e06f79826baabb232f5560e9745d7a78c4ce" + integrity sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA== "source-map-js@>=0.6.2 <2.0.0": version "1.0.2" @@ -8983,6 +9233,37 @@ space-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== +space-separated-tokens@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" + integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== + +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.18" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz#22aa922dcf2f2885a6494a261f2d8b75345d0326" + integrity sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ== + spdy-transport@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" @@ -9036,6 +9317,15 @@ std-env@^3.0.1: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.1.1.tgz#1f19c4d3f6278c52efd08a94574a2a8d32b7d092" integrity sha512-/c645XdExBypL01TpFKiG/3RAa/Qmu+zRi0MwAmrdEkwHNuN0ebo8ccAXBBDa5Z0QOJgBskUIbuCK91x0sCVEw== +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -9045,7 +9335,7 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2 is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.0, string-width@^5.0.1: +string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== @@ -9054,6 +9344,15 @@ string-width@^5.0.0, string-width@^5.0.1: emoji-regex "^9.2.2" strip-ansi "^7.0.1" +string-width@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-6.1.0.tgz#96488d6ed23f9ad5d82d13522af9e4c4c3fd7518" + integrity sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^10.2.1" + strip-ansi "^7.0.1" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -9085,6 +9384,13 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -9092,6 +9398,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-ansi@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" @@ -9126,12 +9439,12 @@ style-to-object@0.3.0, style-to-object@^0.3.0: dependencies: inline-style-parser "0.1.1" -stylehacks@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520" - integrity sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q== +stylehacks@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9" + integrity sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw== dependencies: - browserslist "^4.16.6" + browserslist "^4.21.4" postcss-selector-parser "^6.0.4" supports-color@^5.3.0: @@ -9165,12 +9478,12 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -svg-parser@^2.0.2: +svg-parser@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== -svgo@^2.5.0, svgo@^2.7.0: +svgo@^2.7.0, svgo@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== @@ -9188,21 +9501,33 @@ tapable@^1.0.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: +tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -terser-webpack-plugin@^5.3.3, terser-webpack-plugin@^5.3.7: - version "5.3.7" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz#ef760632d24991760f339fe9290deb936ad1ffc7" - integrity sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw== +tar@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +terser-webpack-plugin@^5.3.10, terser-webpack-plugin@^5.3.3: + version "5.3.10" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" + integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== dependencies: - "@jridgewell/trace-mapping" "^0.3.17" + "@jridgewell/trace-mapping" "^0.3.20" jest-worker "^27.4.5" schema-utils "^3.1.1" serialize-javascript "^6.0.1" - terser "^5.16.5" + terser "^5.26.0" terser@^5.10.0: version "5.14.2" @@ -9214,13 +9539,13 @@ terser@^5.10.0: commander "^2.20.0" source-map-support "~0.5.20" -terser@^5.16.5: - version "5.16.9" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.9.tgz#7a28cb178e330c484369886f2afd623d9847495f" - integrity sha512-HPa/FdTB9XGI2H1/keLFZHxl6WNvAI4YalHGtDQTlMnJcoqSab1UwL4l1hGEhs6/GmLHBZIg/YgB++jcbzoOEg== +terser@^5.26.0: + version "5.31.6" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.6.tgz#c63858a0f0703988d0266a82fcbf2d7ba76422b1" + integrity sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg== dependencies: - "@jridgewell/source-map" "^0.3.2" - acorn "^8.5.0" + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" commander "^2.20.0" source-map-support "~0.5.20" @@ -9239,7 +9564,7 @@ tiny-invariant@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== -tiny-warning@^1.0.0, tiny-warning@^1.0.3: +tiny-warning@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== @@ -9261,28 +9586,20 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -to-vfile@^7.0.0: - version "7.2.3" - resolved "https://registry.yarnpkg.com/to-vfile/-/to-vfile-7.2.3.tgz#4e54ad10878901703f1a956a33ba4f131c31eef7" - integrity sha512-QO0A9aE6Z/YkmQadJ0syxpmNXtcQiu0qAtCKYKD5cS3EfgfFTAXfgLX6AOaBrSfWSek5nfsMf3gBZ9KGVFcLuw== - dependencies: - is-buffer "^2.0.0" - vfile "^5.1.0" - toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -totalist@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" - integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== +totalist@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" + integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== trim-trailing-lines@^1.0.0: version "1.1.4" @@ -9304,25 +9621,15 @@ trough@^2.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876" integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== -tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0: +tslib@^2.0.3, tslib@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -twemoji-parser@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-14.0.0.tgz#13dabcb6d3a261d9efbf58a1666b182033bf2b62" - integrity sha512-9DUOTGLOWs0pFWnh1p6NF+C3CkQ96PWmEFwhOVmT3WbecRC+68AIqpsnJXygfkFcp4aXbOp8Dwbhh/HQgvoRxA== - -twemoji@14.0.1: - version "14.0.1" - resolved "https://registry.yarnpkg.com/twemoji/-/twemoji-14.0.1.tgz#0640887ef149403ae577081cbc2480a026e55ed6" - integrity sha512-eoqhea0sUhmC10iTacksyp1v9O4BP1jKmVqtK+Nztw40/dzawSHkXL3/xCpyh+mukmEvJ0Gw9VLvwZfQ9HKXDw== - dependencies: - fs-extra "^8.0.1" - jsonfile "^5.0.0" - twemoji-parser "14.0.0" - universalify "^0.1.2" +tslib@^2.1.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== type-fest@^0.20.2: version "0.20.2" @@ -9334,6 +9641,11 @@ type-fest@^2.5.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.13.0.tgz#d1ecee38af29eb2e863b22299a3d68ef30d2abfb" integrity sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw== +type-fest@^3.8.0: + version "3.13.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.13.1.tgz#bb744c1f0678bea7543a2d1ec24e83e68e8c8706" + integrity sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g== + type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -9354,15 +9666,25 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" - integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== +typescript@5.5.4: + version "5.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" + integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== -ua-parser-js@^0.7.30: - version "0.7.33" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532" - integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw== +ua-parser-js@^1.0.35: + version "1.0.38" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.38.tgz#66bb0c4c0e322fe48edfe6d446df6042e62f25e2" + integrity sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +undici@^6.19.5: + version "6.19.7" + resolved "https://registry.yarnpkg.com/undici/-/undici-6.19.7.tgz#7d4cf26dc689838aa8b6753a3c5c4288fc1e0216" + integrity sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A== unherit@^1.0.4: version "1.1.3" @@ -9390,75 +9712,81 @@ unicode-match-property-value-ecmascript@^2.0.0: resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== + unicode-property-aliases-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== -unified-args@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/unified-args/-/unified-args-10.0.0.tgz#95994c5558fea83ff07006cb560fd88cdcf31134" - integrity sha512-PqsqxwkXpGSLiMkbjNnKU33Ffm6gso6rAvz1TlBGzMBx3gpx7ewIhViBX8HEWmy0v7pebA5PM6RkRWWaYmtfYw== +unified-args@^11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/unified-args/-/unified-args-11.0.1.tgz#5c82564616288b8d99feed7326c2223097d30726" + integrity sha512-WEQghE91+0s3xPVs0YW6a5zUduNLjmANswX7YbBfksHNDGMjHxaWCql4SR7c9q0yov/XiIEdk6r/LqfPjaYGcw== dependencies: "@types/text-table" "^0.2.0" - camelcase "^7.0.0" chalk "^5.0.0" chokidar "^3.0.0" - fault "^2.0.0" + comma-separated-tokens "^2.0.0" json5 "^2.0.0" minimist "^1.0.0" + strip-ansi "^7.0.0" text-table "^0.2.0" - unified-engine "^10.0.0" + unified-engine "^11.0.0" -unified-engine@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/unified-engine/-/unified-engine-10.0.1.tgz#94f27f1f88660d9b5910595095e4b463ca18e389" - integrity sha512-lsj7VC8kNWhK87rGBhidklk4llgrEdJoOZHoQFbTZQ/fA22JqowUPM10bEf05eSZOR6UnUSrZ/mPWHrQsHGm7g== +unified-engine@^11.0.0: + version "11.2.1" + resolved "https://registry.yarnpkg.com/unified-engine/-/unified-engine-11.2.1.tgz#8f9c05b3f262930666b1cdb83108c15dd39d6cdd" + integrity sha512-xBAdZ8UY2X4R9Hm6X6kMne4Nz0PlpOc1oE6DPeqJnewr5Imkb8uT5Eyvy1h7xNekPL3PSWh3ZJyNrMW6jnNQBg== dependencies: "@types/concat-stream" "^2.0.0" "@types/debug" "^4.0.0" "@types/is-empty" "^1.0.0" - "@types/node" "^18.0.0" - "@types/unist" "^2.0.0" + "@types/node" "^20.0.0" + "@types/unist" "^3.0.0" concat-stream "^2.0.0" debug "^4.0.0" - fault "^2.0.0" - glob "^8.0.0" + extend "^3.0.0" + glob "^10.0.0" ignore "^5.0.0" - is-buffer "^2.0.0" is-empty "^1.0.0" is-plain-obj "^4.0.0" - load-plugin "^5.0.0" - parse-json "^6.0.0" - to-vfile "^7.0.0" + load-plugin "^6.0.0" + parse-json "^7.0.0" trough "^2.0.0" - unist-util-inspect "^7.0.0" - vfile-message "^3.0.0" - vfile-reporter "^7.0.0" - vfile-statistics "^2.0.0" + unist-util-inspect "^8.0.0" + vfile "^6.0.0" + vfile-message "^4.0.0" + vfile-reporter "^8.0.0" + vfile-statistics "^3.0.0" yaml "^2.0.0" -unified-lint-rule@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/unified-lint-rule/-/unified-lint-rule-2.1.1.tgz#2363f27064f0b44675d11119bb573a738e346f24" - integrity sha512-vsLHyLZFstqtGse2gvrGwasOmH8M2y+r2kQMoDSWzSqUkQx2MjHjvZuGSv5FUaiv4RQO1bHRajy7lSGp7XWq5A== +unified-lint-rule@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unified-lint-rule/-/unified-lint-rule-3.0.0.tgz#75f8d7fbd9664e198a65f1399ab06c3950b54a70" + integrity sha512-Sz96ILLsTy3djsG3H44zFb2b77MFf9CQVYnV3PWkxgRX8/n31fFrr+JnzUaJ6cbOHTtZnL1A71+YodsTjzwAew== dependencies: - "@types/unist" "^2.0.0" + "@types/unist" "^3.0.0" trough "^2.0.0" - unified "^10.0.0" - vfile "^5.0.0" + unified "^11.0.0" + vfile "^6.0.0" -unified-message-control@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/unified-message-control/-/unified-message-control-4.0.0.tgz#7cd313df526fc660f218b19a56377bb6957019a8" - integrity sha512-1b92N+VkPHftOsvXNOtkJm4wHlr+UDmTBF2dUzepn40oy9NxanJ9xS1RwUBTjXJwqr2K0kMbEyv1Krdsho7+Iw== +unified-message-control@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unified-message-control/-/unified-message-control-5.0.0.tgz#7268a9a5d695c2591149ebe35e37eb200b852d7e" + integrity sha512-B2cSAkpuMVVmPP90KCfKdBhm1e9KYJ+zK3x5BCa0N65zpq1Ybkc9C77+M5qwR8FWO7RF3LM5QRRPZtgjW6DUCw== dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - unist-util-visit "^3.0.0" - vfile "^5.0.0" - vfile-location "^4.0.0" - vfile-message "^3.0.0" + "@types/unist" "^3.0.0" + devlop "^1.0.0" + space-separated-tokens "^2.0.0" + unist-util-is "^6.0.0" + unist-util-visit "^5.0.0" + vfile "^6.0.0" + vfile-location "^5.0.0" + vfile-message "^4.0.0" unified@9.2.0: version "9.2.0" @@ -9472,19 +9800,6 @@ unified@9.2.0: trough "^1.0.0" vfile "^4.0.0" -unified@^10.0.0, unified@^10.1.0: - version "10.1.2" - resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df" - integrity sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q== - dependencies: - "@types/unist" "^2.0.0" - bail "^2.0.0" - extend "^3.0.0" - is-buffer "^2.0.0" - is-plain-obj "^4.0.0" - trough "^2.0.0" - vfile "^5.0.0" - unified@^11.0.0: version "11.0.3" resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.3.tgz#e141be0fe466a2d28b2160f62712bc9cbc08fdd4" @@ -9527,28 +9842,18 @@ unist-util-generated@^1.0.0: resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.6.tgz#5ab51f689e2992a472beb1b35f2ce7ff2f324d4b" integrity sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg== -unist-util-generated@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.0.tgz#86fafb77eb6ce9bfa6b663c3f5ad4f8e56a60113" - integrity sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw== - -unist-util-inspect@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/unist-util-inspect/-/unist-util-inspect-7.0.0.tgz#98426f0219e24d011a27e32539be0693d9eb973e" - integrity sha512-2Utgv78I7PUu461Y9cdo+IUiiKSKpDV5CE/XD6vTj849a3xlpDAScvSJ6cQmtFBGgAmCn2wR7jLuXhpg1XLlJw== +unist-util-inspect@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/unist-util-inspect/-/unist-util-inspect-8.1.0.tgz#ff2729b543c483041b3c29cbe04c5460a406ee25" + integrity sha512-mOlg8Mp33pR0eeFpo5d2902ojqFFOKMMG2hF8bmH7ZlhnmjFgh0NI3/ZDwdaBJNbvrS7LZFVrBVtIE9KZ9s7vQ== dependencies: - "@types/unist" "^2.0.0" + "@types/unist" "^3.0.0" unist-util-is@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== -unist-util-is@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-5.1.1.tgz#e8aece0b102fa9bc097b0fef8f870c496d4a6236" - integrity sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ== - unist-util-is@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-6.0.0.tgz#b775956486aff107a9ded971d996c173374be424" @@ -9556,24 +9861,24 @@ unist-util-is@^6.0.0: dependencies: "@types/unist" "^3.0.0" -unist-util-position-from-estree@^1.0.0, unist-util-position-from-estree@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.1.tgz#96f4d543dfb0428edc01ebb928570b602d280c4c" - integrity sha512-xtoY50b5+7IH8tFbkw64gisG9tMSpxDjhX9TmaJJae/XuxQ9R/Kc8Nv1eOsf43Gt4KV/LkriMy9mptDr7XLcaw== +unist-util-position-from-estree@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz#d94da4df596529d1faa3de506202f0c9a23f2200" + integrity sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ== dependencies: - "@types/unist" "^2.0.0" + "@types/unist" "^3.0.0" unist-util-position@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47" integrity sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA== -unist-util-position@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.2.tgz#1915816906a3503f3e40d65b6e4fe6d41845d2e3" - integrity sha512-Y6+plxR41dOLbyyqVDLuGWgXDmxdXslCSRYQkSDagBnOT9oFsQH0J8FzhirSklUEe0xZTT0WDnAE1gXPaDFljA== +unist-util-position@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-5.0.0.tgz#678f20ab5ca1207a97d7ea8a388373c9cf896be4" + integrity sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA== dependencies: - "@types/unist" "^2.0.0" + "@types/unist" "^3.0.0" unist-util-remove-position@^2.0.0: version "2.0.1" @@ -9582,13 +9887,13 @@ unist-util-remove-position@^2.0.0: dependencies: unist-util-visit "^2.0.0" -unist-util-remove-position@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-4.0.1.tgz#d5b46a7304ac114c8d91990ece085ca7c2c135c8" - integrity sha512-0yDkppiIhDlPrfHELgB+NLQD5mfjup3a8UYclHruTJWmY74je8g+CIFr79x5f6AkmzSwlvKLbs63hC0meOMowQ== +unist-util-remove-position@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz#fea68a25658409c9460408bc6b4991b965b52163" + integrity sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q== dependencies: - "@types/unist" "^2.0.0" - unist-util-visit "^4.0.0" + "@types/unist" "^3.0.0" + unist-util-visit "^5.0.0" unist-util-remove@^2.0.0: version "2.1.0" @@ -9604,13 +9909,6 @@ unist-util-stringify-position@^2.0.0: dependencies: "@types/unist" "^2.0.2" -unist-util-stringify-position@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz#5c6aa07c90b1deffd9153be170dce628a869a447" - integrity sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg== - dependencies: - "@types/unist" "^2.0.0" - unist-util-stringify-position@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz#449c6e21a880e0855bf5aabadeb3a740314abac2" @@ -9626,22 +9924,6 @@ unist-util-visit-parents@^3.0.0: "@types/unist" "^2.0.0" unist-util-is "^4.0.0" -unist-util-visit-parents@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz#e83559a4ad7e6048a46b1bdb22614f2f3f4724f2" - integrity sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - -unist-util-visit-parents@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.0.tgz#44bbc5d25f2411e7dfc5cecff12de43296aa8521" - integrity sha512-y+QVLcY5eR/YVpqDsLf/xh9R3Q2Y4HxkZTp7ViLDU6WtJCEcPmRzW1gpdWDCDIqIlhuPDXOgttqPlykrHYDekg== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - unist-util-visit-parents@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz#4d5f85755c3b8f0dc69e21eca5d6d82d22162815" @@ -9659,24 +9941,6 @@ unist-util-visit@2.0.3, unist-util-visit@^2.0.0, unist-util-visit@^2.0.3: unist-util-is "^4.0.0" unist-util-visit-parents "^3.0.0" -unist-util-visit@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-3.1.0.tgz#9420d285e1aee938c7d9acbafc8e160186dbaf7b" - integrity sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - unist-util-visit-parents "^4.0.0" - -unist-util-visit@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-4.1.0.tgz#f41e407a9e94da31594e6b1c9811c51ab0b3d8f5" - integrity sha512-n7lyhFKJfVZ9MnKtqbsqkQEk5P1KShj0+//V7mAcoI6bpbUjh3C/OG8HVD+pBihfh6Ovl01m8dkcv9HNqYajmQ== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - unist-util-visit-parents "^5.0.0" - unist-util-visit@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-5.0.0.tgz#a7de1f31f72ffd3519ea71814cccf5fd6a9217d6" @@ -9701,6 +9965,14 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.1" + update-notifier@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-5.1.0.tgz#4ab0d7c7f36a231dd7316cf7729313f0214d9ad9" @@ -9740,31 +10012,31 @@ url-loader@^4.1.1: url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + integrity sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ== dependencies: prepend-http "^2.0.0" -use-composed-ref@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.2.1.tgz#9bdcb5ccd894289105da2325e1210079f56bf849" - integrity sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw== +use-composed-ref@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.3.0.tgz#3d8104db34b7b264030a9d916c5e94fbe280dbda" + integrity sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ== -use-isomorphic-layout-effect@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz#7bb6589170cd2987a152042f9084f9effb75c225" - integrity sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ== +use-isomorphic-layout-effect@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" + integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== -use-latest@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.0.tgz#a44f6572b8288e0972ec411bdd0840ada366f232" - integrity sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw== +use-latest@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.1.tgz#d13dfb4b08c28e3e33991546a2cee53e14038cf2" + integrity sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw== dependencies: - use-isomorphic-layout-effect "^1.0.0" + use-isomorphic-layout-effect "^1.1.1" use-sync-external-store@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" - integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + version "1.2.2" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9" + integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw== util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" @@ -9791,15 +10063,18 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uvu@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.3.tgz#3d83c5bc1230f153451877bfc7f4aea2392219ae" - integrity sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw== +validate-npm-package-license@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: - dequal "^2.0.0" - diff "^5.0.0" - kleur "^4.0.3" - sade "^1.7.3" + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validate-npm-package-name@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" + integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== value-equal@^1.0.1: version "1.0.1" @@ -9816,13 +10091,13 @@ vfile-location@^3.0.0, vfile-location@^3.2.0: resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c" integrity sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA== -vfile-location@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-4.0.1.tgz#06f2b9244a3565bef91f099359486a08b10d3a95" - integrity sha512-JDxPlTbZrZCQXogGheBHjbRWjESSPEak770XwWPfw5mTc1v1nWGLB/apzZxsx8a0SJVfF8HK8ql8RD308vXRUw== +vfile-location@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-5.0.3.tgz#cb9eacd20f2b6426d19451e0eafa3d0a846225c3" + integrity sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg== dependencies: - "@types/unist" "^2.0.0" - vfile "^5.0.0" + "@types/unist" "^3.0.0" + vfile "^6.0.0" vfile-message@^2.0.0: version "2.0.4" @@ -9832,14 +10107,6 @@ vfile-message@^2.0.0: "@types/unist" "^2.0.0" unist-util-stringify-position "^2.0.0" -vfile-message@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.1.2.tgz#a2908f64d9e557315ec9d7ea3a910f658ac05f7d" - integrity sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA== - dependencies: - "@types/unist" "^2.0.0" - unist-util-stringify-position "^3.0.0" - vfile-message@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181" @@ -9848,31 +10115,35 @@ vfile-message@^4.0.0: "@types/unist" "^3.0.0" unist-util-stringify-position "^4.0.0" -vfile-reporter@^7.0.0: - version "7.0.4" - resolved "https://registry.yarnpkg.com/vfile-reporter/-/vfile-reporter-7.0.4.tgz#f5a91c7420c7b2d6bed6f64719069545d47a22cd" - integrity sha512-4cWalUnLrEnbeUQ+hARG5YZtaHieVK3Jp4iG5HslttkVl+MHunSGNAIrODOTLbtjWsNZJRMCkL66AhvZAYuJ9A== +vfile-reporter@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/vfile-reporter/-/vfile-reporter-8.1.1.tgz#ac06a5a68f1b480609c443062dffea1cfa2d11b1" + integrity sha512-qxRZcnFSQt6pWKn3PAk81yLK2rO2i7CDXpy8v8ZquiEOMLSnPw6BMSi9Y1sUCwGGl7a9b3CJT1CKpnRF7pp66g== dependencies: "@types/supports-color" "^8.0.0" - string-width "^5.0.0" + string-width "^6.0.0" supports-color "^9.0.0" - unist-util-stringify-position "^3.0.0" - vfile-sort "^3.0.0" - vfile-statistics "^2.0.0" + unist-util-stringify-position "^4.0.0" + vfile "^6.0.0" + vfile-message "^4.0.0" + vfile-sort "^4.0.0" + vfile-statistics "^3.0.0" -vfile-sort@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/vfile-sort/-/vfile-sort-3.0.0.tgz#ee13d3eaac0446200a2047a3b45d78fad6b106e6" - integrity sha512-fJNctnuMi3l4ikTVcKpxTbzHeCgvDhnI44amA3NVDvA6rTC6oKCFpCVyT5n2fFMr3ebfr+WVQZedOCd73rzSxg== +vfile-sort@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/vfile-sort/-/vfile-sort-4.0.0.tgz#fa1929065b62fe5311e5391c9434f745e8641703" + integrity sha512-lffPI1JrbHDTToJwcq0rl6rBmkjQmMuXkAxsZPRS9DXbaJQvc642eCg6EGxcX2i1L+esbuhq+2l9tBll5v8AeQ== dependencies: - vfile-message "^3.0.0" + vfile "^6.0.0" + vfile-message "^4.0.0" -vfile-statistics@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/vfile-statistics/-/vfile-statistics-2.0.0.tgz#f04ee3e3c666809a3c10c06021becd41ea9c8037" - integrity sha512-foOWtcnJhKN9M2+20AOTlWi2dxNfAoeNIoxD5GXcO182UJyId4QrXa41fWrgcfV3FWTjdEDy3I4cpLVcQscIMA== +vfile-statistics@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/vfile-statistics/-/vfile-statistics-3.0.0.tgz#0f5cd00c611c1862b13a9b5bc5599efaf465f2cf" + integrity sha512-/qlwqwWBWFOmpXujL/20P+Iuydil0rZZNglR+VNm6J0gpLHwuVM5s7g2TfVoswbXjZ4HuIhLMySEyIw5i7/D8w== dependencies: - vfile-message "^3.0.0" + vfile "^6.0.0" + vfile-message "^4.0.0" vfile@^4.0.0: version "4.2.1" @@ -9884,16 +10155,6 @@ vfile@^4.0.0: unist-util-stringify-position "^2.0.0" vfile-message "^2.0.0" -vfile@^5.0.0, vfile@^5.1.0: - version "5.3.2" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-5.3.2.tgz#b499fbc50197ea50ad3749e9b60beb16ca5b7c54" - integrity sha512-w0PLIugRY3Crkgw89TeMvHCzqCs/zpreR31hl4D92y6SOE07+bfJe+dK5Q2akwS+i/c801kzjoOr9gMcTe6IAA== - dependencies: - "@types/unist" "^2.0.0" - is-buffer "^2.0.0" - unist-util-stringify-position "^3.0.0" - vfile-message "^3.0.0" - vfile@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.1.tgz#1e8327f41eac91947d4fe9d237a2dd9209762536" @@ -9914,15 +10175,15 @@ wait-on@^6.0.1: minimist "^1.2.5" rxjs "^7.5.4" -walk-up-path@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-1.0.0.tgz#d4745e893dd5fd0dbb58dd0a4c6a33d9c9fec53e" - integrity sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg== +walk-up-path@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-3.0.1.tgz#c8d78d5375b4966c717eb17ada73dbd41490e886" + integrity sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA== -watchpack@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== +watchpack@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da" + integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" @@ -9942,24 +10203,27 @@ web-namespaces@^1.0.0: webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== webpack-bundle-analyzer@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz#1b0eea2947e73528754a6f9af3e91b2b6e0f79d5" - integrity sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ== + version "4.10.2" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz#633af2862c213730be3dbdf40456db171b60d5bd" + integrity sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw== dependencies: + "@discoveryjs/json-ext" "0.5.7" acorn "^8.0.4" acorn-walk "^8.0.0" - chalk "^4.1.0" commander "^7.2.0" + debounce "^1.2.1" + escape-string-regexp "^4.0.0" gzip-size "^6.0.0" - lodash "^4.17.20" + html-escaper "^2.0.2" opener "^1.5.2" - sirv "^1.0.7" + picocolors "^1.0.0" + sirv "^2.0.3" ws "^7.3.1" -webpack-dev-middleware@^5.3.1: +webpack-dev-middleware@^5.3.4: version "5.3.4" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517" integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q== @@ -9971,9 +10235,9 @@ webpack-dev-middleware@^5.3.1: schema-utils "^4.0.0" webpack-dev-server@^4.9.3: - version "4.9.3" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.9.3.tgz#2360a5d6d532acb5410a668417ad549ee3b8a3c9" - integrity sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw== + version "4.15.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz#9e0c70a42a012560860adb186986da1248333173" + integrity sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g== dependencies: "@types/bonjour" "^3.5.9" "@types/connect-history-api-fallback" "^1.3.5" @@ -9981,7 +10245,7 @@ webpack-dev-server@^4.9.3: "@types/serve-index" "^1.9.1" "@types/serve-static" "^1.13.10" "@types/sockjs" "^0.3.33" - "@types/ws" "^8.5.1" + "@types/ws" "^8.5.5" ansi-html-community "^0.0.8" bonjour-service "^1.0.11" chokidar "^3.5.3" @@ -9994,23 +10258,25 @@ webpack-dev-server@^4.9.3: html-entities "^2.3.2" http-proxy-middleware "^2.0.3" ipaddr.js "^2.0.1" + launch-editor "^2.6.0" open "^8.0.9" p-retry "^4.5.0" rimraf "^3.0.2" schema-utils "^4.0.0" - selfsigned "^2.0.1" + selfsigned "^2.1.1" serve-index "^1.9.1" sockjs "^0.3.24" spdy "^4.0.2" - webpack-dev-middleware "^5.3.1" - ws "^8.4.2" + webpack-dev-middleware "^5.3.4" + ws "^8.13.0" webpack-merge@^5.8.0: - version "5.8.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" - integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== + version "5.10.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" + integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== dependencies: clone-deep "^4.0.1" + flat "^5.0.2" wildcard "^2.0.0" webpack-sources@^3.2.2, webpack-sources@^3.2.3: @@ -10018,34 +10284,34 @@ webpack-sources@^3.2.2, webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.73.0, webpack@^5.88.2: - version "5.88.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" - integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== +webpack@^5.73.0, webpack@^5.93.0: + version "5.93.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.93.0.tgz#2e89ec7035579bdfba9760d26c63ac5c3462a5e5" + integrity sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA== dependencies: "@types/eslint-scope" "^3.7.3" - "@types/estree" "^1.0.0" - "@webassemblyjs/ast" "^1.11.5" - "@webassemblyjs/wasm-edit" "^1.11.5" - "@webassemblyjs/wasm-parser" "^1.11.5" + "@types/estree" "^1.0.5" + "@webassemblyjs/ast" "^1.12.1" + "@webassemblyjs/wasm-edit" "^1.12.1" + "@webassemblyjs/wasm-parser" "^1.12.1" acorn "^8.7.1" - acorn-import-assertions "^1.9.0" - browserslist "^4.14.5" + acorn-import-attributes "^1.9.5" + browserslist "^4.21.10" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.15.0" + enhanced-resolve "^5.17.0" es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" glob-to-regexp "^0.4.1" - graceful-fs "^4.2.9" + graceful-fs "^4.2.11" json-parse-even-better-errors "^2.3.1" loader-runner "^4.2.0" mime-types "^2.1.27" neo-async "^2.6.2" schema-utils "^3.2.0" tapable "^2.1.1" - terser-webpack-plugin "^5.3.7" - watchpack "^2.4.0" + terser-webpack-plugin "^5.3.10" + watchpack "^2.4.1" webpack-sources "^3.2.3" webpackbar@^5.0.2: @@ -10072,10 +10338,22 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== +whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== + dependencies: + iconv-lite "0.6.3" + +whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" @@ -10094,6 +10372,13 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +which@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" + integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== + dependencies: + isexe "^3.1.1" + widest-line@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" @@ -10113,6 +10398,15 @@ wildcard@^2.0.0: resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -10131,10 +10425,19 @@ wrap-ansi@^8.0.1: string-width "^5.0.1" strip-ansi "^7.0.1" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^3.0.0: version "3.0.3" @@ -10151,10 +10454,10 @@ ws@^7.3.1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -ws@^8.4.2: - version "8.17.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" - integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== +ws@^8.13.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== xdg-basedir@^4.0.0: version "4.0.0" @@ -10173,6 +10476,11 @@ xtend@^4.0.0, xtend@^4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" @@ -10188,10 +10496,18 @@ yaml@^2.0.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec" integrity sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw== -yarn@^1.22.19: - version "1.22.19" - resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.19.tgz#4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447" - integrity sha512-/0V5q0WbslqnwP91tirOvldvYISzaqhClxzyUKXYxs07yUILIs5jx/k6CFe8bvKSkds5w+eiOqta39Wk3WxdcQ== +yarn@^1.22.22: + version "1.22.22" + resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.22.tgz#ac34549e6aa8e7ead463a7407e1c7390f61a6610" + integrity sha512-prL3kGtyG7o9Z9Sv8IPfBNrWTDmXB4Qbes8A9rEzt6wkJV8mUvoirjU0Mp3GGAU06Y0XQyA3/2/RQFVuK7MTfg== + +yauzl@^3.1.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-3.1.3.tgz#f61c17ad1a09403bc7adb01dfb302a9e74bf4a50" + integrity sha512-JCCdmlJJWv7L0q/KylOekyRaUrdEoUxWkWVcgorosTROCFWiS9p2NNPE9Yb91ak7b1N5SxAZEliWpspbZccivw== + dependencies: + buffer-crc32 "~0.2.3" + pend "~1.2.0" yocto-queue@^0.1.0: version "0.1.0"