diff --git a/docs/.vuepress/components/Adapter.vue b/docs/.vuepress/components/Adapter.vue deleted file mode 100644 index 7d7bf7f2..00000000 --- a/docs/.vuepress/components/Adapter.vue +++ /dev/null @@ -1,228 +0,0 @@ - - - diff --git a/docs/.vuepress/components/Bot.vue b/docs/.vuepress/components/Bot.vue deleted file mode 100644 index b2d797d6..00000000 --- a/docs/.vuepress/components/Bot.vue +++ /dev/null @@ -1,194 +0,0 @@ - - - diff --git a/docs/.vuepress/components/Messenger.vue b/docs/.vuepress/components/Messenger.vue deleted file mode 100644 index 9e694df2..00000000 --- a/docs/.vuepress/components/Messenger.vue +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - diff --git a/docs/.vuepress/components/Plugin.vue b/docs/.vuepress/components/Plugin.vue deleted file mode 100644 index 771e0705..00000000 --- a/docs/.vuepress/components/Plugin.vue +++ /dev/null @@ -1,230 +0,0 @@ - - - diff --git a/docs/.vuepress/components/PublishCard.vue b/docs/.vuepress/components/PublishCard.vue deleted file mode 100644 index b6c0a5ac..00000000 --- a/docs/.vuepress/components/PublishCard.vue +++ /dev/null @@ -1,84 +0,0 @@ - - - - - diff --git a/docs/.vuepress/components/Store.vue b/docs/.vuepress/components/Store.vue deleted file mode 100644 index b672b1aa..00000000 --- a/docs/.vuepress/components/Store.vue +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - diff --git a/nonebot/params.py b/nonebot/params.py index 61548e13..1aa7715f 100644 --- a/nonebot/params.py +++ b/nonebot/params.py @@ -183,19 +183,20 @@ class BotParam(Param): ) -> Optional["BotParam"]: if param.default == param.empty: if generic_check_issubclass(param.annotation, Bot): - dependent.pre_checkers.append( - _BotChecker( - Required, - field=ModelField( - name="", - type_=param.annotation, - class_validators=None, - model_config=CustomConfig, - default=None, - required=True, - ), + if param.annotation is not Bot: + dependent.pre_checkers.append( + _BotChecker( + Required, + field=ModelField( + name="", + type_=param.annotation, + class_validators=None, + model_config=CustomConfig, + default=None, + required=True, + ), + ) ) - ) return cls(Required) elif param.annotation == param.empty and name == "bot": return cls(Required) @@ -223,19 +224,20 @@ class EventParam(Param): ) -> Optional["EventParam"]: if param.default == param.empty: if generic_check_issubclass(param.annotation, Event): - dependent.pre_checkers.append( - _EventChecker( - Required, - field=ModelField( - name="", - type_=param.annotation, - class_validators=None, - model_config=CustomConfig, - default=None, - required=True, - ), + if param.annotation is not Event: + dependent.pre_checkers.append( + _EventChecker( + Required, + field=ModelField( + name="", + type_=param.annotation, + class_validators=None, + model_config=CustomConfig, + default=None, + required=True, + ), + ) ) - ) return cls(Required) elif param.annotation == param.empty and name == "event": return cls(Required) diff --git a/website/docs/tutorial/plugin/create-handler.md b/website/docs/tutorial/plugin/create-handler.md index 7504aa42..95b29b20 100644 --- a/website/docs/tutorial/plugin/create-handler.md +++ b/website/docs/tutorial/plugin/create-handler.md @@ -15,3 +15,252 @@ options: ## 添加一个处理依赖 ## 事件处理流程 + +## 获取上下文信息 + +### Bot + +```python {7-9} +from typing import Union + +from nonebot.adapters import Bot +from nonebot.adapters.ding import Bot as DingBot +from nonebot.adapters.onebot.v11 import Bot as OneBotV11Bot + +async def _(foo: Bot): ... +async def _(foo: Union[DingBot, OneBotV11Bot]): ... +async def _(bot): ... # 兼容性处理 +``` + +### Event + +```python {6-8} +from typing import Union + +from nonebot.adapters import Event +from nonebot.adapters.onebot.v11 import PrivateMessageEvent, GroupMessageEvent + +async def _(foo: Event): ... +async def _(foo: Union[PrivateMessageEvent, GroupMessageEvent]): ... +async def _(event): ... # 兼容性处理 +``` + +### EventType + +```python {3} +from nonebot.params import EventType + +async def _(foo: str = EventType()): ... +``` + +### EventMessage + +```python {4} +from nonebot.adapters import Message +from nonebot.params import EventMessage + +async def _(foo: str = EventMessage()): ... +``` + +### EventPlainText + +```python {3} +from nonebot.params import EventPlainText + +async def _(foo: str = EventPlainText()): ... +``` + +### EventToMe + +```python {3} +from nonebot.params import EventToMe + +async def _(foo: bool = EventToMe()): ... +``` + +### State + +```python {4} +from nonebot.params import State +from nonebot.typing import T_State + +async def _(foo: T_State = State()): ... +``` + +### Command + +```python {7} +from nonebot import on_command +from nonebot.params import Command + +matcher = on_command("cmd") + +@matcher.handle() +async def _(foo: Tuple[str, ...] = Command()): ... +``` + +### CommandArg + +```python {8} +from nonebot import on_command +from nonebot.adapters import Message +from nonebot.params import CommandArg + +matcher = on_command("cmd") + +@matcher.handle() +async def _(foo: Message = CommandArg()): ... +``` + +### ShellCommandArgs + +```python {7} +from nonebot import on_command +from nonebot.params import ShellCommandArgs + +matcher = on_shell_command("cmd", parser) + +@matcher.handle() +async def _(foo: Dict[str, Any] = ShellCommandArgs()): ... +``` + +### ShellCommandArgv + +```python {7} +from nonebot import on_command +from nonebot.params import ShellCommandArgs + +matcher = on_shell_command("cmd") + +@matcher.handle() +async def _(foo: List[str] = ShellCommandArgv()): ... +``` + +### RegexMatched + +```python {7} +from nonebot import on_regex +from nonebot.params import RegexMatched + +matcher = on_regex("regex") + +@matcher.handle() +async def _(foo: str = RegexMatched()): ... +``` + +### RegexGroup + +```python {7} +from nonebot import on_regex +from nonebot.params import RegexGroup + +matcher = on_regex("regex") + +@matcher.handle() +async def _(foo: Tuple[Any, ...] = RegexGroup()): ... +``` + +### RegexDict + +```python {7} +from nonebot import on_regex +from nonebot.params import RegexDict + +matcher = on_regex("regex") + +@matcher.handle() +async def _(foo: Dict[str, Any] = RegexDict()): ... +``` + +### Matcher + +```python {7} +from nonebot import on_message +from nonebot.matcher import Matcher + +foo = on_message() + +@foo.handle() +async def _(matcher: Matcher): ... +``` + +### Received + +```python {8} +from nonebot import on_message +from nonebot.adapters import Event +from nonebot.params import Received + +matcher = on_message() + +@matcher.receive("id") +async def _(foo: Event = Received("id")): ... +``` + +### LastReceived + +```python {8} +from nonebot import on_message +from nonebot.adapters import Event +from nonebot.params import LastReceived + +matcher = on_message() + +@matcher.receive("any") +async def _(foo: Event = LastReceived()): ... +``` + +### Arg + +```python {8-9} +from nonebot.params import Arg +from nonebot import on_message +from nonebot.adapters import Message + +matcher = on_message() + +@matcher.got("key") +async def _(key: Message = Arg()): ... +async def _(foo: Message = Arg("key")): ... +``` + +### ArgStr + +```python {7-8} +from nonebot import on_message +from nonebot.params import ArgStr + +matcher = on_message() + +@matcher.got("key") +async def _(key: str = ArgStr()): ... +async def _(foo: str = ArgStr("key")): ... +``` + +### ArgPlainText + +```python {7-8} +from nonebot import on_message +from nonebot.params import ArgPlainText + +matcher = on_message() + +@matcher.got("key") +async def _(key: str = ArgPlainText()): ... +async def _(foo: str = ArgPlainText("key")): ... +``` + +### Exception + +```python {4} +from nonebot.message import run_postprocessor + +@run_postprocessor +async def _(e: Exception): ... +``` + +### Default + +```python {1} +async def _(foo="bar"): ... +``` diff --git a/website/src/components/Adapter.tsx b/website/src/components/Adapter.tsx index d72305b1..ba0b257d 100644 --- a/website/src/components/Adapter.tsx +++ b/website/src/components/Adapter.tsx @@ -1,12 +1,20 @@ -import React from "react"; +import clsx from "clsx"; +import React, { useRef, useState } from "react"; +import { ChromePicker } from "react-color"; import { usePagination } from "react-use-pagination"; import adapters from "../../static/adapters.json"; -import { useFilteredObjs } from "../libs/store"; +import { Tag, useFilteredObjs } from "../libs/store"; import Card from "./Card"; +import Modal from "./Modal"; +import ModalAction from "./ModalAction"; +import ModalContent from "./ModalContent"; +import ModalTitle from "./ModalTitle"; import Paginate from "./Paginate"; +import TagComponent from "./Tag"; export default function Adapter(): JSX.Element { + const [modalOpen, setModalOpen] = useState(false); const { filter, setFilter, @@ -20,6 +28,93 @@ export default function Adapter(): JSX.Element { const { startIndex, endIndex } = props; const currentAdapters = filteredAdapters.slice(startIndex, endIndex + 1); + const [form, setForm] = useState<{ + name: string; + desc: string; + projectLink: string; + moduleName: string; + homepage: string; + }>({ name: "", desc: "", projectLink: "", moduleName: "", homepage: "" }); + + const ref = useRef(null); + const [tags, setTags] = useState([]); + const [label, setLabel] = useState(""); + const [color, setColor] = useState("#ea5252"); + + const onSubmit = () => { + setModalOpen(false); + const title = encodeURIComponent(`Adapter: ${form.name}`).replace( + /%2B/gi, + "+" + ); + const body = encodeURIComponent( + ` +**协议名称:** + +${form.name} + +**协议功能:** + +${form.desc} + +**PyPI 项目名:** + +${form.projectLink} + +**协议 import 包名:** + +${form.moduleName} + +**协议项目仓库/主页链接:** + +${form.homepage} + +**标签:** + +${JSON.stringify(tags)} +`.trim() + ).replace(/%2B/gi, "+"); + window.open( + `https://github.com/nonebot/nonebot2/issues/new?title=${title}&body=${body}&labels=Adapter` + ); + }; + const onChange = (event) => { + const target = event.target; + const value = target.type === "checkbox" ? target.checked : target.value; + const name = target.name; + + setForm({ + ...form, + [name]: value, + }); + event.preventDefault(); + }; + const onChangeLabel = (event) => { + setLabel(event.target.value); + }; + const onChangeColor = (color) => { + setColor(color.hex); + }; + const validateTag = () => { + return label.length >= 1 && label.length <= 10; + }; + const newTag = () => { + if (tags.length >= 3) { + return; + } + if (validateTag()) { + const tag = { label, color }; + setTags([...tags, tag]); + } + }; + const delTag = (index: number) => { + setTags(tags.filter((_, i) => i !== index)); + }; + const insertTagType = (text: string) => { + setLabel(text + label); + ref.current.value = text + label; + }; + return ( <>
@@ -29,7 +124,10 @@ export default function Adapter(): JSX.Element { placeholder="搜索适配器" onChange={(event) => setFilter(event.target.value)} /> -
@@ -44,6 +142,129 @@ export default function Adapter(): JSX.Element {
+ + + +
+
+ + + + + +
+
+
+ +
+
+ + +
+ Type: + + +
+
+ + +
+
+
+ + + + +
); } diff --git a/website/src/components/Bot.tsx b/website/src/components/Bot.tsx index 3994f14e..86bbb625 100644 --- a/website/src/components/Bot.tsx +++ b/website/src/components/Bot.tsx @@ -1,12 +1,20 @@ -import React from "react"; +import clsx from "clsx"; +import React, { useRef, useState } from "react"; +import { ChromePicker } from "react-color"; import { usePagination } from "react-use-pagination"; import bots from "../../static/bots.json"; -import { useFilteredObjs } from "../libs/store"; +import { Tag, useFilteredObjs } from "../libs/store"; import Card from "./Card"; +import Modal from "./Modal"; +import ModalAction from "./ModalAction"; +import ModalContent from "./ModalContent"; +import ModalTitle from "./ModalTitle"; import Paginate from "./Paginate"; +import TagComponent from "./Tag"; export default function Adapter(): JSX.Element { + const [modalOpen, setModalOpen] = useState(false); const { filter, setFilter, @@ -20,6 +28,80 @@ export default function Adapter(): JSX.Element { const { startIndex, endIndex } = props; const currentBots = filteredBots.slice(startIndex, endIndex + 1); + const [form, setForm] = useState<{ + name: string; + desc: string; + homepage: string; + }>({ name: "", desc: "", homepage: "" }); + + const ref = useRef(null); + const [tags, setTags] = useState([]); + const [label, setLabel] = useState(""); + const [color, setColor] = useState("#ea5252"); + + const onSubmit = () => { + setModalOpen(false); + const title = encodeURIComponent(`Bot: ${form.name}`).replace(/%2B/gi, "+"); + const body = encodeURIComponent( + ` +**机器人名称:** + +${form.name} + +**机器人功能:** + +${form.desc} + +**机器人项目仓库/主页链接:** + +${form.homepage} + +**标签:** + +${JSON.stringify(tags)} +`.trim() + ).replace(/%2B/gi, "+"); + window.open( + `https://github.com/nonebot/nonebot2/issues/new?title=${title}&body=${body}&labels=Bot` + ); + }; + const onChange = (event) => { + const target = event.target; + const value = target.type === "checkbox" ? target.checked : target.value; + const name = target.name; + + setForm({ + ...form, + [name]: value, + }); + event.preventDefault(); + }; + const onChangeLabel = (event) => { + setLabel(event.target.value); + }; + const onChangeColor = (color) => { + setColor(color.hex); + }; + const validateTag = () => { + return label.length >= 1 && label.length <= 10; + }; + const newTag = () => { + if (tags.length >= 3) { + return; + } + if (validateTag()) { + const tag = { label, color }; + setTags([...tags, tag]); + } + }; + const delTag = (index: number) => { + setTags(tags.filter((_, i) => i !== index)); + }; + const insertTagType = (text: string) => { + setLabel(text + label); + ref.current.value = text + label; + }; + return ( <>
@@ -29,7 +111,10 @@ export default function Adapter(): JSX.Element { placeholder="搜索机器人" onChange={(event) => setFilter(event.target.value)} /> -
@@ -44,6 +129,111 @@ export default function Adapter(): JSX.Element {
+ + + +
+
+ + + +
+
+
+ +
+
+ + +
+ Type: + + +
+
+ + +
+
+
+ + + + +
); } diff --git a/website/static/bots.json b/website/static/bots.json index 5eeca3ae..4b9f7086 100644 --- a/website/static/bots.json +++ b/website/static/bots.json @@ -94,5 +94,13 @@ "homepage": "https://github.com/ssttkkl/PixivBot", "tags": [], "is_official": false + }, + { + "name": "SeaBot_QQ", + "desc": "一个能够获取新闻资讯并推送至QQ的群聊机器人。", + "author": "B1ue1nWh1te", + "homepage": "https://github.com/B1ue1nWh1te/SeaBot_QQ", + "tags": [], + "is_official": false } ] diff --git a/website/static/plugins.json b/website/static/plugins.json index ad3a2c33..604cb930 100644 --- a/website/static/plugins.json +++ b/website/static/plugins.json @@ -688,5 +688,85 @@ "homepage": "https://github.com/yzyyz1387/nonebot_plugin_heisi", "tags": [], "is_official": false + }, + { + "module_name": "nonebot_plugin_picsbank", + "project_link": "nonebot-plugin-picsbank", + "name": "picsbank", + "desc": "匹配图片进行回答", + "author": "Diaosi1111", + "homepage": "https://github.com/Diaosi1111/nonebot_plugin_picsbank", + "tags": [], + "is_official": false + }, + { + "module_name": "nonebot_plugin_tvseries", + "project_link": "nonebot-plugin-tvseries", + "name": "剧集更新列表", + "desc": "获取聚集更新", + "author": "kexue-z", + "homepage": "https://github.com/kexue-z/nonebot-plugin-tvseries", + "tags": [], + "is_official": false + }, + { + "module_name": "nonebot_plugin_lolmatch", + "project_link": "nonebot-plugin-lolmatch", + "name": "lol比赛信息", + "desc": "简单的lol比赛信息插件,订阅后会定时推送当日比赛结果", + "author": "Diaosi1111", + "homepage": "https://github.com/Diaosi1111/nonebot_plugin_lolmatch", + "tags": [], + "is_official": false + }, + { + "module_name": "OlivOS", + "project_link": "olivos.nb2", + "name": "OlivOS.nb2", + "desc": "在 NoneBot2 中加载 OlivOS 插件", + "author": "j1g5awi", + "homepage": "https://github.com/nonepkg/OlivOS.nb2", + "tags": [], + "is_official": false + }, + { + "module_name": "nonebot_plugin_htmlrender", + "project_link": "nonebot-plugin-htmlrender", + "name": "通过浏览器来生成图片", + "desc": "通过playwright加一点点前端知识来简单的生成图片", + "author": "kexue-z", + "homepage": "https://github.com/kexue-z/nonebot-plugin-htmlrender", + "tags": [], + "is_official": false + }, + { + "module_name": "nonebot_plugin_admin", + "project_link": "nonebot-plugin-admin", + "name": "简易群管", + "desc": "简易群管 踢 禁 改", + "author": "yzyyz1387", + "homepage": "https://github.com/yzyyz1387/nonebot_plugin_admin", + "tags": [], + "is_official": false + }, + { + "module_name": "nonebot_plugin_logo", + "project_link": "nonebot-plugin-logo", + "name": "nonebot-plugin-logo", + "desc": "PornHub、Youtube 等风格logo生成", + "author": "MeetWq", + "homepage": "https://github.com/MeetWq/nonebot-plugin-logo", + "tags": [], + "is_official": false + }, + { + "module_name": "nonebot_plugin_memes", + "project_link": "nonebot-plugin-memes", + "name": "Memes generator", + "desc": "表情包制作", + "author": "MeetWq", + "homepage": "https://github.com/MeetWq/nonebot-plugin-memes", + "tags": [], + "is_official": false } ]