migrate to cv2 jsx

This commit is contained in:
nin0 2025-05-16 06:16:52 -04:00
parent 6858283ecc
commit dcd22a9d8c
Signed by: nin0
SSH key fingerprint: SHA256:NOoDnFVvZNFvqfXCIhzr6oCTDImZAbTTuyAysZ8Ufk8
18 changed files with 101 additions and 122 deletions

View file

@ -2,12 +2,12 @@ import { ComponentTypes, MessageActionRow, MessageActionRowComponent } from "oce
import { childrenToArray } from "./utils"; import { childrenToArray } from "./utils";
export type ActionRowProps = Omit<MessageActionRow, "type" | "components"> & { children?: MessageActionRowComponent | MessageActionRowComponent[] }; export type ActionRowProps = Omit<MessageActionRow, "type" | "components"> & { children: MessageActionRowComponent | MessageActionRowComponent[]; };
export function ActionRow(props: ActionRowProps): MessageActionRow { export function ActionRow({ children, ...props }: ActionRowProps): MessageActionRow {
return { return {
type: ComponentTypes.ACTION_ROW, type: ComponentTypes.ACTION_ROW,
components: childrenToArray(props.children), components: childrenToArray(children),
...props ...props
}; };
} }

View file

@ -5,7 +5,7 @@ import { childrenToString } from "./utils";
export { ButtonStyles } from "oceanic.js"; export { ButtonStyles } from "oceanic.js";
type Button = Omit<TextButton, "type" | "label"> | Omit<URLButton, "type" | "label">; type Button = Omit<TextButton, "type" | "label"> | Omit<URLButton, "type" | "label">;
export type ButtonProps = Button & { children?: any; }; export type ButtonProps = Button & { children?: string; };
export function Button({ children, ...props }: ButtonProps): ButtonComponent { export function Button({ children, ...props }: ButtonProps): ButtonComponent {
return { return {

View file

@ -3,7 +3,7 @@ import { CreateMessageOptions, EditMessageOptions, MessageComponent, MessageFlag
import { childrenToArray } from "./utils"; import { childrenToArray } from "./utils";
type MessageOptions = CreateMessageOptions | EditMessageOptions; type MessageOptions = CreateMessageOptions | EditMessageOptions;
export type ComponentMessageProps = MessageOptions & { children?: MessageComponent[]; }; export type ComponentMessageProps = MessageOptions & { children: MessageComponent[]; };
export function ComponentMessage({ children, flags, ...props }: ComponentMessageProps): MessageOptions { export function ComponentMessage({ children, flags, ...props }: ComponentMessageProps): MessageOptions {
return { return {

View file

@ -2,7 +2,7 @@ import { ComponentTypes, ContainerComponent } from "oceanic.js";
import { childrenToArray } from "./utils"; import { childrenToArray } from "./utils";
export type ContainerProps = Omit<ContainerComponent, "type" | "components"> & { children?: ContainerComponent["components"] }; export type ContainerProps = Omit<ContainerComponent, "type" | "components"> & { children: ContainerComponent["components"]; };
export function Container({ children, ...props }: ContainerProps): ContainerComponent { export function Container({ children, ...props }: ContainerProps): ContainerComponent {
return { return {

View file

@ -0,0 +1,5 @@
import { Separator } from "./Separator";
export function Divider() {
return <Separator divider={true} />;
}

5
components-jsx/JSX.d.ts vendored Normal file
View file

@ -0,0 +1,5 @@
declare namespace JSX {
interface ElementChildrenAttribute {
children: {};
}
}

View file

@ -2,12 +2,12 @@ import { ComponentTypes, MediaGalleryComponent } from "oceanic.js";
import { childrenToArray } from "./utils"; import { childrenToArray } from "./utils";
export type MediaGalleryProps = Omit<MediaGalleryComponent, "type" | "items"> & { children: MediaGalleryComponent["items"] }; export type MediaGalleryProps = Omit<MediaGalleryComponent, "type" | "items"> & { children: MediaGalleryComponent["items"]; };
export function MediaGallery(props: MediaGalleryProps): MediaGalleryComponent { export function MediaGallery({ children, ...props }: MediaGalleryProps): MediaGalleryComponent {
return { return {
type: ComponentTypes.MEDIA_GALLERY, type: ComponentTypes.MEDIA_GALLERY,
items: childrenToArray(props.children), items: childrenToArray(children),
...props ...props
}; };
} }

View file

@ -3,14 +3,14 @@ import { ButtonComponent, ComponentTypes, SectionComponent, TextDisplayComponent
import { childrenToArray } from "./utils"; import { childrenToArray } from "./utils";
export interface SectionProps { export interface SectionProps {
children: TextDisplayComponent[] children: TextDisplayComponent[];
accessory: ThumbnailComponent | ButtonComponent; accessory: ThumbnailComponent | ButtonComponent;
} }
export function Section(props: SectionProps): SectionComponent { export function Section({ children, ...props }: SectionProps): SectionComponent {
return { return {
type: ComponentTypes.SECTION, type: ComponentTypes.SECTION,
components: childrenToArray(props.children), components: childrenToArray(children),
...props ...props
}; };
} }

View file

@ -2,12 +2,12 @@ import { ComponentTypes, StringSelectMenu } from "oceanic.js";
import { childrenToArray } from "./utils"; import { childrenToArray } from "./utils";
export type StringSelectProps = Omit<StringSelectMenu, "type" | "options"> & { children: StringSelectMenu["options"] }; export type StringSelectProps = Omit<StringSelectMenu, "type" | "options"> & { children: StringSelectMenu["options"]; };
export function StringSelect(props: StringSelectProps): StringSelectMenu { export function StringSelect({ children, ...props }: StringSelectProps): StringSelectMenu {
return { return {
type: ComponentTypes.STRING_SELECT, type: ComponentTypes.STRING_SELECT,
options: childrenToArray(props.children), options: childrenToArray(children),
...props ...props
}; };
} }

View file

@ -3,12 +3,12 @@ import { ComponentTypes, TextDisplayComponent } from "oceanic.js";
import { childrenToString } from "./utils"; import { childrenToString } from "./utils";
export interface TextDisplayProps { export interface TextDisplayProps {
children?: any; children: any;
id?: number; id?: number;
} }
export function TextDisplay({ children, id }: TextDisplayProps): TextDisplayComponent { export function TextDisplay({ children, id }: TextDisplayProps): TextDisplayComponent {
children = childrenToString("TextDisplay", children); children = childrenToString("TextDisplay", children)!;
if (!children) { if (!children) {
throw new Error("TextDisplay requires at least one child"); throw new Error("TextDisplay requires at least one child");
} }

View file

@ -1,11 +1,11 @@
import { ComponentTypes, ThumbnailComponent } from "oceanic.js"; import { ComponentTypes, ThumbnailComponent } from "oceanic.js";
export type ThumbnailProps = Omit<ThumbnailComponent, "type" | "media"> & { children: ThumbnailComponent["media"] }; export type ThumbnailProps = Omit<ThumbnailComponent, "type" | "media"> & { children: ThumbnailComponent["media"]; };
export function Thumbnail(props: ThumbnailProps): ThumbnailComponent { export function Thumbnail({ children, ...props }: ThumbnailProps): ThumbnailComponent {
return { return {
type: ComponentTypes.THUMBNAIL, type: ComponentTypes.THUMBNAIL,
media: props.children, media: children,
...props ...props
}; };
} }

9
components-jsx/br.tsx Normal file
View file

@ -0,0 +1,9 @@
import { TextDisplay } from "./TextDisplay";
export function br() {
return (
<>
<TextDisplay>{"\n"}</TextDisplay>
</>
);
}

View file

@ -1,7 +1,9 @@
export * from "./ActionRow"; export * from "./ActionRow";
export * from "./br";
export * from "./Button"; export * from "./Button";
export * from "./ComponentMessage"; export * from "./ComponentMessage";
export * from "./Container"; export * from "./Container";
export * from "./Divider";
export * from "./File"; export * from "./File";
export * from "./MediaGallery"; export * from "./MediaGallery";
export * from "./MediaGalleryItem"; export * from "./MediaGalleryItem";

View file

@ -1,6 +1,8 @@
export const Fragment = Symbol("ComponentsJsx.Fragment"); export const Fragment = Symbol("ComponentsJsx.Fragment");
export function createElement(type: typeof Fragment | ((props: any) => any), props: any, ...children: any[]) { type FunctionComponent = (props: any) => any;
export function createElement(type: typeof Fragment | FunctionComponent, props: any, ...children: any[]) {
if (type === Fragment) { if (type === Fragment) {
return children; return children;
} }

View file

@ -7,7 +7,7 @@ export function filterChildren(children: any[]) {
export function childrenToString(name: string, children: any) { export function childrenToString(name: string, children: any) {
if (Array.isArray(children)) { if (Array.isArray(children)) {
return filterChildren(children).join("\n"); return filterChildren(children).join("");
} }
if (typeof children === "string") { if (typeof children === "string") {
return children; return children;

24
src/components/User.tsx Normal file
View file

@ -0,0 +1,24 @@
import { Section } from "components-jsx/Section";
import { client } from "..";
import { Thumbnail } from "components-jsx/Thumbnail";
import { TextDisplay } from "components-jsx/TextDisplay";
import { br } from "components-jsx/br";
export async function User(props: { id: string }) {
const user = await client.rest.users.get(props.id);
return (
<Section
accessory={
<Thumbnail children={{ url: user.avatarURL("png", 128) }} />
}
>
<TextDisplay>### User</TextDisplay>
<TextDisplay>
{user.globalName || user.username}
<br />
-# @{user.username}
</TextDisplay>
</Section>
);
}

View file

@ -1,68 +0,0 @@
import {
AnyMessageComponent,
Component,
ComponentTypes,
FileComponent,
MediaGalleryComponent,
MessageActionRow,
SectionComponent,
SeparatorComponent,
TextDisplayComponent
} from "oceanic.js";
import { client } from ".";
export const Divider: SeparatorComponent = {
type: ComponentTypes.SEPARATOR,
divider: true
};
export const Header = (
title: string,
level: 1 | 2 | 3
): TextDisplayComponent => {
return {
type: ComponentTypes.TEXT_DISPLAY,
content: `${"#".repeat(level)} ${title}`
};
};
export async function generateUserComponent(
id: string
): Promise<SectionComponent> {
const user = await client.rest.users.get(id);
return {
type: ComponentTypes.SECTION,
components: [
Header("User", 3),
{
type: ComponentTypes.TEXT_DISPLAY,
content: `${user.globalName || user.username}\n-# @${
user.username
}`
}
],
accessory: {
type: ComponentTypes.THUMBNAIL,
media: {
url: user.avatarURL("png", 128)
}
}
};
}
export function generateList(
elements: {
[key: string]: string;
},
title?: string
): TextDisplayComponent[] {
let working: TextDisplayComponent[] = [];
if (title) working.push(Header(title, 3));
for (const key of Object.keys(elements)) {
working.push({
type: ComponentTypes.TEXT_DISPLAY,
content: `**${key}**\n-# ${elements[key].replaceAll("\n", "\n-# ")}`
});
}
return working;
}

View file

@ -1,9 +1,19 @@
import { ComponentTypes, MessageFlags, Shard } from "oceanic.js"; import { ComponentTypes, MessageFlags, Shard } from "oceanic.js";
import { client } from "."; import { client } from ".";
import { Constants } from "./Constants"; import { Constants } from "./Constants";
import { Header, Divider, generateUserComponent } from "./cv2";
import { db } from "./database"; import { db } from "./database";
import {
ActionRow,
Button,
ComponentMessage,
Container,
Divider,
Section,
Separator,
TextDisplay
} from "~/components";
import { selfappReq } from "./selfappReq"; import { selfappReq } from "./selfappReq";
import { User } from "./components/User";
export async function setupJoinRequestHandler(shard: Shard) { export async function setupJoinRequestHandler(shard: Shard) {
shard.ws?.on("message", async (d) => { shard.ws?.on("message", async (d) => {
@ -18,9 +28,9 @@ export async function setupJoinRequestHandler(shard: Shard) {
const pendingMsg = const pendingMsg =
await client.rest.channels.createMessage( await client.rest.channels.createMessage(
Constants.PENDING_CHANNEL_ID, Constants.PENDING_CHANNEL_ID,
{ <ComponentMessage>
content: "Placeholder" <TextDisplay>Placeholder</TextDisplay>
} </ComponentMessage>
); );
await db.run( await db.run(
"INSERT INTO applications (id, user_id, status, message_id, channel_id) VALUES (?, ?, 0, ?, ?)", "INSERT INTO applications (id, user_id, status, message_id, channel_id) VALUES (?, ?, 0, ?, ?)",
@ -52,34 +62,24 @@ export async function setupJoinRequestHandler(shard: Shard) {
} }
await client.rest.channels.createMessage( await client.rest.channels.createMessage(
Constants.REJECTION_CHANNEL_ID, Constants.REJECTION_CHANNEL_ID,
{ <ComponentMessage>
flags: MessageFlags.IS_COMPONENTS_V2, <Container accentColor={0xffaaaa}>
components: [ <TextDisplay>
{ ## Join request withdrawn
type: ComponentTypes.CONTAINER, </TextDisplay>
accentColor: 0xffaaaa, <Divider />
components: [ <User id={applicationData.user_id} />
Header("Join request withdrawn", 2), <Divider />
Divider, <TextDisplay>### Application</TextDisplay>
await generateUserComponent( {application ? (
applicationData.user_id <TextDisplay>User has applied</TextDisplay>
), ) : (
Divider, <TextDisplay>
Header("Application", 3), User hasn't applied
application </TextDisplay>
? { )}
type: ComponentTypes.TEXT_DISPLAY, </Container>
content: "User has applied" </ComponentMessage>
}
: {
type: ComponentTypes.TEXT_DISPLAY,
content:
"User has never applied"
}
]
}
]
}
); );
break; break;
} }