mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-07-28 00:31:14 +00:00
🚧 add handler di example
This commit is contained in:
@ -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"): ...
|
||||
```
|
||||
|
@ -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<boolean>(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<HTMLInputElement>(null);
|
||||
const [tags, setTags] = useState<Tag[]>([]);
|
||||
const [label, setLabel] = useState<string>("");
|
||||
const [color, setColor] = useState<string>("#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 (
|
||||
<>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-4 px-4">
|
||||
@ -29,7 +124,10 @@ export default function Adapter(): JSX.Element {
|
||||
placeholder="搜索适配器"
|
||||
onChange={(event) => setFilter(event.target.value)}
|
||||
/>
|
||||
<button className="w-full rounded-lg bg-hero text-white">
|
||||
<button
|
||||
className="w-full rounded-lg bg-hero text-white"
|
||||
onClick={() => setModalOpen(true)}
|
||||
>
|
||||
发布适配器
|
||||
</button>
|
||||
</div>
|
||||
@ -44,6 +142,129 @@ export default function Adapter(): JSX.Element {
|
||||
<div className="grid grid-cols-1 p-4">
|
||||
<Paginate {...props} />
|
||||
</div>
|
||||
<Modal active={modalOpen} setActive={setModalOpen}>
|
||||
<ModalTitle title={"适配器信息"} />
|
||||
<ModalContent>
|
||||
<form onSubmit={onSubmit}>
|
||||
<div className="grid grid-cols-1 gap-4 p-4">
|
||||
<label className="flex flex-wrap">
|
||||
<span className="mr-2">适配器名称:</span>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
maxLength={20}
|
||||
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
|
||||
onChange={onChange}
|
||||
/>
|
||||
</label>
|
||||
<label className="flex flex-wrap">
|
||||
<span className="mr-2">适配器介绍:</span>
|
||||
<input
|
||||
type="text"
|
||||
name="desc"
|
||||
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
|
||||
onChange={onChange}
|
||||
/>
|
||||
</label>
|
||||
<label className="flex flex-wrap">
|
||||
<span className="mr-2">PyPI 项目名:</span>
|
||||
<input
|
||||
type="text"
|
||||
name="projectLink"
|
||||
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
|
||||
onChange={onChange}
|
||||
/>
|
||||
</label>
|
||||
<label className="flex flex-wrap">
|
||||
<span className="mr-2">import 包名:</span>
|
||||
<input
|
||||
type="text"
|
||||
name="moduleName"
|
||||
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
|
||||
onChange={onChange}
|
||||
/>
|
||||
</label>
|
||||
<label className="flex flex-wrap">
|
||||
<span className="mr-2">仓库/主页:</span>
|
||||
<input
|
||||
type="text"
|
||||
name="homepage"
|
||||
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
|
||||
onChange={onChange}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
<div className="px-4">
|
||||
<label className="flex flex-wrap">
|
||||
<span className="mr-2">标签:</span>
|
||||
{tags.map((tag, index) => (
|
||||
<TagComponent
|
||||
key={index}
|
||||
{...tag}
|
||||
className="cursor-pointer"
|
||||
onClick={() => delTag(index)}
|
||||
/>
|
||||
))}
|
||||
</label>
|
||||
</div>
|
||||
<div className="px-4 pt-4">
|
||||
<input
|
||||
ref={ref}
|
||||
type="text"
|
||||
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
|
||||
onChange={onChangeLabel}
|
||||
/>
|
||||
<ChromePicker
|
||||
className="mt-2"
|
||||
color={color}
|
||||
disableAlpha={true}
|
||||
onChangeComplete={onChangeColor}
|
||||
/>
|
||||
<div className="flex flex-wrap mt-2 items-center">
|
||||
<span className="mr-2">Type:</span>
|
||||
<button
|
||||
className="px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
|
||||
onClick={() => insertTagType("a:")}
|
||||
>
|
||||
Adapter
|
||||
</button>
|
||||
<button
|
||||
className="px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
|
||||
onClick={() => insertTagType("t:")}
|
||||
>
|
||||
Topic
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex mt-2">
|
||||
<TagComponent label={label} color={color} />
|
||||
<button
|
||||
className={clsx(
|
||||
"px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]",
|
||||
{ "pointer-events-none opacity-60": !validateTag() }
|
||||
)}
|
||||
onClick={newTag}
|
||||
>
|
||||
添加标签
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalContent>
|
||||
<ModalAction>
|
||||
<button
|
||||
className="px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
|
||||
onClick={() => setModalOpen(false)}
|
||||
>
|
||||
关闭
|
||||
</button>
|
||||
<button
|
||||
className="ml-2 px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
|
||||
onClick={onSubmit}
|
||||
>
|
||||
发布
|
||||
</button>
|
||||
</ModalAction>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -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<boolean>(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<HTMLInputElement>(null);
|
||||
const [tags, setTags] = useState<Tag[]>([]);
|
||||
const [label, setLabel] = useState<string>("");
|
||||
const [color, setColor] = useState<string>("#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 (
|
||||
<>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-4 px-4">
|
||||
@ -29,7 +111,10 @@ export default function Adapter(): JSX.Element {
|
||||
placeholder="搜索机器人"
|
||||
onChange={(event) => setFilter(event.target.value)}
|
||||
/>
|
||||
<button className="w-full rounded-lg bg-hero text-white">
|
||||
<button
|
||||
className="w-full rounded-lg bg-hero text-white"
|
||||
onClick={() => setModalOpen(true)}
|
||||
>
|
||||
发布机器人
|
||||
</button>
|
||||
</div>
|
||||
@ -44,6 +129,111 @@ export default function Adapter(): JSX.Element {
|
||||
<div className="grid grid-cols-1 p-4">
|
||||
<Paginate {...props} />
|
||||
</div>
|
||||
<Modal active={modalOpen} setActive={setModalOpen}>
|
||||
<ModalTitle title={"机器人信息"} />
|
||||
<ModalContent>
|
||||
<form onSubmit={onSubmit}>
|
||||
<div className="grid grid-cols-1 gap-4 p-4">
|
||||
<label className="flex flex-wrap">
|
||||
<span className="mr-2">机器人名称:</span>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
maxLength={20}
|
||||
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
|
||||
onChange={onChange}
|
||||
/>
|
||||
</label>
|
||||
<label className="flex flex-wrap">
|
||||
<span className="mr-2">机器人介绍:</span>
|
||||
<input
|
||||
type="text"
|
||||
name="desc"
|
||||
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
|
||||
onChange={onChange}
|
||||
/>
|
||||
</label>
|
||||
<label className="flex flex-wrap">
|
||||
<span className="mr-2">仓库/主页:</span>
|
||||
<input
|
||||
type="text"
|
||||
name="homepage"
|
||||
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
|
||||
onChange={onChange}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
<div className="px-4">
|
||||
<label className="flex flex-wrap">
|
||||
<span className="mr-2">标签:</span>
|
||||
{tags.map((tag, index) => (
|
||||
<TagComponent
|
||||
key={index}
|
||||
{...tag}
|
||||
className="cursor-pointer"
|
||||
onClick={() => delTag(index)}
|
||||
/>
|
||||
))}
|
||||
</label>
|
||||
</div>
|
||||
<div className="px-4 pt-4">
|
||||
<input
|
||||
ref={ref}
|
||||
type="text"
|
||||
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
|
||||
onChange={onChangeLabel}
|
||||
/>
|
||||
<ChromePicker
|
||||
className="mt-2"
|
||||
color={color}
|
||||
disableAlpha={true}
|
||||
onChangeComplete={onChangeColor}
|
||||
/>
|
||||
<div className="flex flex-wrap mt-2 items-center">
|
||||
<span className="mr-2">Type:</span>
|
||||
<button
|
||||
className="px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
|
||||
onClick={() => insertTagType("a:")}
|
||||
>
|
||||
Adapter
|
||||
</button>
|
||||
<button
|
||||
className="px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
|
||||
onClick={() => insertTagType("t:")}
|
||||
>
|
||||
Topic
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex mt-2">
|
||||
<TagComponent label={label} color={color} />
|
||||
<button
|
||||
className={clsx(
|
||||
"px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]",
|
||||
{ "pointer-events-none opacity-60": !validateTag() }
|
||||
)}
|
||||
onClick={newTag}
|
||||
>
|
||||
添加标签
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalContent>
|
||||
<ModalAction>
|
||||
<button
|
||||
className="px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
|
||||
onClick={() => setModalOpen(false)}
|
||||
>
|
||||
关闭
|
||||
</button>
|
||||
<button
|
||||
className="ml-2 px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
|
||||
onClick={onSubmit}
|
||||
>
|
||||
发布
|
||||
</button>
|
||||
</ModalAction>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
Reference in New Issue
Block a user