Compare commits
14 Commits
reacord@0.
...
reacord@0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fa4bc800b | ||
|
|
e3351654ea | ||
|
|
d1ca002939 | ||
|
|
72f4a4afff | ||
|
|
eed5715f1f | ||
|
|
e486da0881 | ||
|
|
b275d9b330 | ||
|
|
bab134d697 | ||
|
|
df9bdfaf77 | ||
|
|
35d7f0b33f | ||
|
|
4f9fb4310f | ||
|
|
7b74628732 | ||
|
|
7536bdee43 | ||
|
|
ef8d915e3b |
14
package.json
14
package.json
@@ -11,13 +11,13 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@changesets/cli": "^2.24.0",
|
"@changesets/cli": "^2.24.0",
|
||||||
"@itsmapleleaf/configs": "^1.1.3",
|
"@itsmapleleaf/configs": "^1.1.5",
|
||||||
"@rushstack/eslint-patch": "^1.1.3",
|
"@rushstack/eslint-patch": "^1.1.4",
|
||||||
"@types/eslint": "^8.4.1",
|
"@types/eslint": "^8.4.5",
|
||||||
"eslint": "^8.14.0",
|
"eslint": "^8.20.0",
|
||||||
"node": "^16",
|
"node": "^16.16.0",
|
||||||
"prettier": "^2.6.2",
|
"prettier": "^2.7.1",
|
||||||
"typescript": "^4.6.3"
|
"typescript": "^4.7.4"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"esbuild": "latest"
|
"esbuild": "latest"
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# reacord
|
# reacord
|
||||||
|
|
||||||
|
## 0.5.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 72f4a4a: upgrade dependencies and remove some unneeded
|
||||||
|
- 7536bde: add types in exports to work with TS nodenext
|
||||||
|
- e335165: fix links
|
||||||
|
|
||||||
## 0.5.0
|
## 0.5.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { nanoid } from "nanoid"
|
import { randomUUID } from "node:crypto"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { ReacordElement } from "../../internal/element.js"
|
import { ReacordElement } from "../../internal/element.js"
|
||||||
import type { ComponentInteraction } from "../../internal/interaction"
|
import type { ComponentInteraction } from "../../internal/interaction"
|
||||||
@@ -43,7 +43,7 @@ export function Button(props: ButtonProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ButtonNode extends Node<ButtonProps> {
|
class ButtonNode extends Node<ButtonProps> {
|
||||||
private customId = nanoid()
|
private customId = randomUUID()
|
||||||
|
|
||||||
// this has text children, but buttons themselves shouldn't yield text
|
// this has text children, but buttons themselves shouldn't yield text
|
||||||
// eslint-disable-next-line class-methods-use-this
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { nanoid } from "nanoid"
|
import { randomUUID } from "node:crypto"
|
||||||
import type { ReactNode } from "react"
|
import type { ReactNode } from "react"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { isInstanceOf } from "../../../helpers/is-instance-of"
|
import { isInstanceOf } from "../../../helpers/is-instance-of"
|
||||||
@@ -89,7 +89,7 @@ export function Select(props: SelectProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SelectNode extends Node<SelectProps> {
|
class SelectNode extends Node<SelectProps> {
|
||||||
readonly customId = nanoid()
|
readonly customId = randomUUID()
|
||||||
|
|
||||||
override modifyMessageOptions(message: MessageOptions): void {
|
override modifyMessageOptions(message: MessageOptions): void {
|
||||||
const actionRow: ActionRow = []
|
const actionRow: ActionRow = []
|
||||||
|
|||||||
@@ -353,6 +353,17 @@ function getDiscordMessageOptions(reacordOptions: MessageOptions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (component.type === "link") {
|
||||||
|
return {
|
||||||
|
type: Discord.ComponentType.Button,
|
||||||
|
url: component.url,
|
||||||
|
label: component.label ?? "",
|
||||||
|
style: Discord.ButtonStyle.Link,
|
||||||
|
disabled: component.disabled,
|
||||||
|
emoji: component.emoji,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (component.type === "select") {
|
if (component.type === "select") {
|
||||||
return {
|
return {
|
||||||
...component,
|
...component,
|
||||||
@@ -364,7 +375,7 @@ function getDiscordMessageOptions(reacordOptions: MessageOptions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
raise(`Unsupported component type: ${component.type}`)
|
raise(`Unsupported component type: ${(component as any).type}`)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
})),
|
})),
|
||||||
|
|||||||
@@ -47,7 +47,19 @@ export abstract class Reacord {
|
|||||||
|
|
||||||
this.renderers.push(renderer)
|
this.renderers.push(renderer)
|
||||||
|
|
||||||
const container = reconciler.createContainer(renderer, 0, false, {})
|
const container = reconciler.createContainer(
|
||||||
|
renderer,
|
||||||
|
0,
|
||||||
|
// eslint-disable-next-line unicorn/no-null
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
// eslint-disable-next-line unicorn/no-null
|
||||||
|
null,
|
||||||
|
"reacord",
|
||||||
|
() => {},
|
||||||
|
// eslint-disable-next-line unicorn/no-null
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
|
||||||
const instance: ReacordInstance = {
|
const instance: ReacordInstance = {
|
||||||
render: (content: ReactNode) => {
|
render: (content: ReactNode) => {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { HostConfig } from "react-reconciler"
|
import type { HostConfig } from "react-reconciler"
|
||||||
import ReactReconciler from "react-reconciler"
|
import ReactReconciler from "react-reconciler"
|
||||||
|
import { DefaultEventPriority } from "react-reconciler/constants"
|
||||||
import { raise } from "../../helpers/raise.js"
|
import { raise } from "../../helpers/raise.js"
|
||||||
import { Node } from "./node.js"
|
import { Node } from "./node.js"
|
||||||
import type { Renderer } from "./renderers/renderer"
|
import type { Renderer } from "./renderers/renderer"
|
||||||
@@ -20,8 +21,6 @@ const config: HostConfig<
|
|||||||
number, // TimeoutHandle,
|
number, // TimeoutHandle,
|
||||||
number // NoTimeout,
|
number // NoTimeout,
|
||||||
> = {
|
> = {
|
||||||
// config
|
|
||||||
now: Date.now,
|
|
||||||
supportsMutation: true,
|
supportsMutation: true,
|
||||||
supportsPersistence: false,
|
supportsPersistence: false,
|
||||||
supportsHydration: false,
|
supportsHydration: false,
|
||||||
@@ -52,8 +51,13 @@ const config: HostConfig<
|
|||||||
},
|
},
|
||||||
createTextInstance: (text) => new TextNode(text),
|
createTextInstance: (text) => new TextNode(text),
|
||||||
shouldSetTextContent: () => false,
|
shouldSetTextContent: () => false,
|
||||||
// @ts-expect-error
|
|
||||||
detachDeletedInstance: (instance) => {},
|
detachDeletedInstance: (instance) => {},
|
||||||
|
beforeActiveInstanceBlur: () => {},
|
||||||
|
afterActiveInstanceBlur: () => {},
|
||||||
|
// eslint-disable-next-line unicorn/no-null
|
||||||
|
getInstanceFromNode: (node: any) => null,
|
||||||
|
// eslint-disable-next-line unicorn/no-null
|
||||||
|
getInstanceFromScope: (scopeInstance: any) => null,
|
||||||
|
|
||||||
clearContainer: (renderer) => {
|
clearContainer: (renderer) => {
|
||||||
renderer.nodes.clear()
|
renderer.nodes.clear()
|
||||||
@@ -94,11 +98,14 @@ const config: HostConfig<
|
|||||||
resetAfterCommit: (renderer) => {
|
resetAfterCommit: (renderer) => {
|
||||||
renderer.render()
|
renderer.render()
|
||||||
},
|
},
|
||||||
|
prepareScopeUpdate: (scopeInstance: any, instance: any) => {},
|
||||||
|
|
||||||
preparePortalMount: () => raise("Portals are not supported"),
|
preparePortalMount: () => raise("Portals are not supported"),
|
||||||
getPublicInstance: () => raise("Refs are currently not supported"),
|
getPublicInstance: () => raise("Refs are currently not supported"),
|
||||||
|
|
||||||
finalizeInitialChildren: () => false,
|
finalizeInitialChildren: () => false,
|
||||||
|
|
||||||
|
getCurrentEventPriority: () => DefaultEventPriority,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reconciler = ReactReconciler(config)
|
export const reconciler = ReactReconciler(config)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "reacord",
|
"name": "reacord",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Create interactive Discord messages using React.",
|
"description": "Create interactive Discord messages using React.",
|
||||||
"version": "0.5.0",
|
"version": "0.5.1",
|
||||||
"types": "./dist/main.d.ts",
|
"types": "./dist/main.d.ts",
|
||||||
"homepage": "https://reacord.mapleleaf.dev",
|
"homepage": "https://reacord.mapleleaf.dev",
|
||||||
"repository": "https://github.com/itsMapleLeaf/reacord.git",
|
"repository": "https://github.com/itsMapleLeaf/reacord.git",
|
||||||
@@ -27,7 +27,8 @@
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"import": "./dist/main.js",
|
"import": "./dist/main.js",
|
||||||
"require": "./dist/main.cjs"
|
"require": "./dist/main.cjs",
|
||||||
|
"types": "./dist/main.d.ts"
|
||||||
},
|
},
|
||||||
"./package.json": {
|
"./package.json": {
|
||||||
"import": "./package.json",
|
"import": "./package.json",
|
||||||
@@ -46,10 +47,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"@types/react-reconciler": "^0.26.6",
|
"@types/react-reconciler": "^0.28.0",
|
||||||
"nanoid": "^3.3.3",
|
"react-reconciler": "^0.29.0",
|
||||||
"react-reconciler": "^0.27.0",
|
"rxjs": "^7.5.6"
|
||||||
"rxjs": "^7.5.5"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"discord.js": "^14",
|
"discord.js": "^14",
|
||||||
@@ -62,21 +62,20 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash-es": "^4.17.6",
|
"@types/lodash-es": "^4.17.6",
|
||||||
"c8": "^7.11.2",
|
"c8": "^7.12.0",
|
||||||
"discord.js": "^14.0.3",
|
"discord.js": "^14.0.3",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"nodemon": "^2.0.15",
|
"nodemon": "^2.0.19",
|
||||||
"prettier": "^2.6.2",
|
"prettier": "^2.7.1",
|
||||||
"pretty-ms": "^7.0.1",
|
"pretty-ms": "^8.0.0",
|
||||||
"react": "^18.0.0",
|
"react": "^18.2.0",
|
||||||
"release-it": "^14.14.2",
|
"release-it": "^15.1.3",
|
||||||
"tsup": "^5.12.6",
|
"tsup": "^6.1.3",
|
||||||
"tsx": "^3.8.0",
|
"tsx": "^3.8.0",
|
||||||
"type-fest": "^2.12.2",
|
"type-fest": "^2.17.0",
|
||||||
"typescript": "^4.6.3",
|
"typescript": "^4.7.4",
|
||||||
"vite": "^2.9.5",
|
"vitest": "^0.18.1"
|
||||||
"vitest": "^0.10.0"
|
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"esbuild": "latest"
|
"esbuild": "latest"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import * as React from "react"
|
|||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
|
Link,
|
||||||
Option,
|
Option,
|
||||||
ReacordDiscordJs,
|
ReacordDiscordJs,
|
||||||
Select,
|
Select,
|
||||||
@@ -132,3 +133,7 @@ await createTest("delete this", (channel) => {
|
|||||||
}
|
}
|
||||||
reacord.send(channel.id, <DeleteThis />)
|
reacord.send(channel.id, <DeleteThis />)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await createTest("link", (channel) => {
|
||||||
|
reacord.send(channel.id, <Link label="hi" url="https://mapleleaf.dev" />)
|
||||||
|
})
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ test("rendering behavior", async () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
tester.findButtonByLabel("show embed").click()
|
await tester.findButtonByLabel("show embed").click()
|
||||||
await tester.assertMessages([
|
await tester.assertMessages([
|
||||||
{
|
{
|
||||||
content: "count: 0",
|
content: "count: 0",
|
||||||
@@ -62,7 +62,7 @@ test("rendering behavior", async () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
tester.findButtonByLabel("clicc").click()
|
await tester.findButtonByLabel("clicc").click()
|
||||||
await tester.assertMessages([
|
await tester.assertMessages([
|
||||||
{
|
{
|
||||||
content: "count: 1",
|
content: "count: 1",
|
||||||
@@ -94,7 +94,7 @@ test("rendering behavior", async () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
tester.findButtonByLabel("clicc").click()
|
await tester.findButtonByLabel("clicc").click()
|
||||||
await tester.assertMessages([
|
await tester.assertMessages([
|
||||||
{
|
{
|
||||||
content: "count: 2",
|
content: "count: 2",
|
||||||
@@ -126,7 +126,7 @@ test("rendering behavior", async () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
tester.findButtonByLabel("hide embed").click()
|
await tester.findButtonByLabel("hide embed").click()
|
||||||
await tester.assertMessages([
|
await tester.assertMessages([
|
||||||
{
|
{
|
||||||
content: "count: 2",
|
content: "count: 2",
|
||||||
@@ -153,7 +153,7 @@ test("rendering behavior", async () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
tester.findButtonByLabel("clicc").click()
|
await tester.findButtonByLabel("clicc").click()
|
||||||
await tester.assertMessages([
|
await tester.assertMessages([
|
||||||
{
|
{
|
||||||
content: "count: 3",
|
content: "count: 3",
|
||||||
@@ -180,7 +180,7 @@ test("rendering behavior", async () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
tester.findButtonByLabel("deactivate").click()
|
await tester.findButtonByLabel("deactivate").click()
|
||||||
await tester.assertMessages([
|
await tester.assertMessages([
|
||||||
{
|
{
|
||||||
content: "count: 3",
|
content: "count: 3",
|
||||||
@@ -210,7 +210,7 @@ test("rendering behavior", async () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
tester.findButtonByLabel("clicc").click()
|
await tester.findButtonByLabel("clicc").click()
|
||||||
await tester.assertMessages([
|
await tester.assertMessages([
|
||||||
{
|
{
|
||||||
content: "count: 3",
|
content: "count: 3",
|
||||||
|
|||||||
@@ -59,16 +59,16 @@ test("single select", async () => {
|
|||||||
await assertSelect([])
|
await assertSelect([])
|
||||||
expect(onSelect).toHaveBeenCalledTimes(0)
|
expect(onSelect).toHaveBeenCalledTimes(0)
|
||||||
|
|
||||||
tester.findSelectByPlaceholder("choose one").select("2")
|
await tester.findSelectByPlaceholder("choose one").select("2")
|
||||||
await assertSelect(["2"])
|
await assertSelect(["2"])
|
||||||
expect(onSelect).toHaveBeenCalledWith(
|
expect(onSelect).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({ values: ["2"] }),
|
expect.objectContaining({ values: ["2"] }),
|
||||||
)
|
)
|
||||||
|
|
||||||
tester.findButtonByLabel("disable").click()
|
await tester.findButtonByLabel("disable").click()
|
||||||
await assertSelect(["2"], true)
|
await assertSelect(["2"], true)
|
||||||
|
|
||||||
tester.findSelectByPlaceholder("choose one").select("1")
|
await tester.findSelectByPlaceholder("choose one").select("1")
|
||||||
await assertSelect(["2"], true)
|
await assertSelect(["2"], true)
|
||||||
expect(onSelect).toHaveBeenCalledTimes(1)
|
expect(onSelect).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
@@ -125,19 +125,19 @@ test("multiple select", async () => {
|
|||||||
await assertSelect([])
|
await assertSelect([])
|
||||||
expect(onSelect).toHaveBeenCalledTimes(0)
|
expect(onSelect).toHaveBeenCalledTimes(0)
|
||||||
|
|
||||||
tester.findSelectByPlaceholder("select").select("1", "3")
|
await tester.findSelectByPlaceholder("select").select("1", "3")
|
||||||
await assertSelect(expect.arrayContaining(["1", "3"]) as unknown as string[])
|
await assertSelect(expect.arrayContaining(["1", "3"]) as unknown as string[])
|
||||||
expect(onSelect).toHaveBeenCalledWith(
|
expect(onSelect).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({ values: expect.arrayContaining(["1", "3"]) }),
|
expect.objectContaining({ values: expect.arrayContaining(["1", "3"]) }),
|
||||||
)
|
)
|
||||||
|
|
||||||
tester.findSelectByPlaceholder("select").select("2")
|
await tester.findSelectByPlaceholder("select").select("2")
|
||||||
await assertSelect(expect.arrayContaining(["2"]) as unknown as string[])
|
await assertSelect(expect.arrayContaining(["2"]) as unknown as string[])
|
||||||
expect(onSelect).toHaveBeenCalledWith(
|
expect(onSelect).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({ values: expect.arrayContaining(["2"]) }),
|
expect.objectContaining({ values: expect.arrayContaining(["2"]) }),
|
||||||
)
|
)
|
||||||
|
|
||||||
tester.findSelectByPlaceholder("select").select()
|
await tester.findSelectByPlaceholder("select").select()
|
||||||
await assertSelect([])
|
await assertSelect([])
|
||||||
expect(onSelect).toHaveBeenCalledWith(expect.objectContaining({ values: [] }))
|
expect(onSelect).toHaveBeenCalledWith(expect.objectContaining({ values: [] }))
|
||||||
})
|
})
|
||||||
@@ -145,7 +145,7 @@ test("multiple select", async () => {
|
|||||||
test("optional onSelect + unknown value", async () => {
|
test("optional onSelect + unknown value", async () => {
|
||||||
const tester = new ReacordTester()
|
const tester = new ReacordTester()
|
||||||
tester.reply().render(<Select placeholder="select" />)
|
tester.reply().render(<Select placeholder="select" />)
|
||||||
tester.findSelectByPlaceholder("select").select("something")
|
await tester.findSelectByPlaceholder("select").select("something")
|
||||||
await tester.assertMessages([
|
await tester.assertMessages([
|
||||||
{
|
{
|
||||||
content: "",
|
content: "",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable class-methods-use-this */
|
/* eslint-disable class-methods-use-this */
|
||||||
/* eslint-disable require-await */
|
/* eslint-disable require-await */
|
||||||
import { nanoid } from "nanoid"
|
import { randomUUID } from "node:crypto"
|
||||||
import { setTimeout } from "node:timers/promises"
|
import { setTimeout } from "node:timers/promises"
|
||||||
import type { ReactNode } from "react"
|
import type { ReactNode } from "react"
|
||||||
import { expect } from "vitest"
|
import { expect } from "vitest"
|
||||||
@@ -194,7 +194,7 @@ class TestCommandInteraction implements CommandInteraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TestInteraction {
|
class TestInteraction {
|
||||||
readonly id = nanoid()
|
readonly id = randomUUID()
|
||||||
readonly channelId = "test-channel-id"
|
readonly channelId = "test-channel-id"
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/// <reference types="vitest" />
|
/// <reference types="vitest" />
|
||||||
import { defineConfig } from "vite"
|
import { defineConfig } from "vitest/config"
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
build: {
|
build: {
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# website
|
# website
|
||||||
|
|
||||||
|
## 0.4.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [72f4a4a]
|
||||||
|
- Updated dependencies [7536bde]
|
||||||
|
- Updated dependencies [e335165]
|
||||||
|
- reacord@0.5.1
|
||||||
|
|
||||||
## 0.4.1
|
## 0.4.1
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -2,35 +2,34 @@ import glob from "fast-glob"
|
|||||||
import grayMatter from "gray-matter"
|
import grayMatter from "gray-matter"
|
||||||
import { readFile } from "node:fs/promises"
|
import { readFile } from "node:fs/promises"
|
||||||
import { join, parse } from "node:path"
|
import { join, parse } from "node:path"
|
||||||
import type { AppLinkProps } from "~/modules/navigation/app-link"
|
import { z } from "zod"
|
||||||
|
|
||||||
const guidesFolder = "app/routes/guides"
|
const guidesFolder = "app/routes/guides"
|
||||||
|
|
||||||
export type GuideLink = {
|
const frontmatterSchema = z.object({
|
||||||
title: string
|
meta: z.object({
|
||||||
order: number
|
title: z.string(),
|
||||||
link: AppLinkProps
|
description: z.string(),
|
||||||
}
|
}),
|
||||||
|
order: z.number().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
export async function loadGuideLinks(): Promise<GuideLink[]> {
|
export type GuideLink = Awaited<ReturnType<typeof loadGuideLinks>>[0]
|
||||||
|
|
||||||
|
export async function loadGuideLinks() {
|
||||||
const guideFiles = await glob(`**/*.md`, { cwd: guidesFolder })
|
const guideFiles = await glob(`**/*.md`, { cwd: guidesFolder })
|
||||||
|
|
||||||
const links: GuideLink[] = await Promise.all(
|
const links = await Promise.all(
|
||||||
guideFiles.map(async (file) => {
|
guideFiles.map(async (file) => {
|
||||||
const { data } = grayMatter(await readFile(join(guidesFolder, file)))
|
const result = grayMatter(await readFile(join(guidesFolder, file)))
|
||||||
|
const data = frontmatterSchema.parse(result.data)
|
||||||
let order = data.order
|
|
||||||
if (!Number.isFinite(order)) {
|
|
||||||
order = Number.POSITIVE_INFINITY
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: data.meta?.title,
|
title: data.meta.title,
|
||||||
order,
|
order: data.order ?? Number.POSITIVE_INFINITY,
|
||||||
link: {
|
link: {
|
||||||
type: "router",
|
type: "router" as const,
|
||||||
to: `/guides/${parse(file).name}`,
|
to: `/guides/${parse(file).name}`,
|
||||||
children: data.meta?.title,
|
children: data.meta.title,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
import type {
|
import type { LinksFunction, MetaFunction } from "@remix-run/node"
|
||||||
LinksFunction,
|
|
||||||
LoaderFunction,
|
|
||||||
MetaFunction,
|
|
||||||
} from "@remix-run/node"
|
|
||||||
import {
|
import {
|
||||||
Links,
|
Links,
|
||||||
LiveReload,
|
LiveReload,
|
||||||
@@ -16,7 +12,6 @@ import packageJson from "reacord/package.json"
|
|||||||
import bannerUrl from "~/assets/banner.png"
|
import bannerUrl from "~/assets/banner.png"
|
||||||
import faviconUrl from "~/assets/favicon.png"
|
import faviconUrl from "~/assets/favicon.png"
|
||||||
import { GuideLinksProvider } from "~/modules/navigation/guide-links-context"
|
import { GuideLinksProvider } from "~/modules/navigation/guide-links-context"
|
||||||
import type { GuideLink } from "~/modules/navigation/load-guide-links.server"
|
|
||||||
import { loadGuideLinks } from "~/modules/navigation/load-guide-links.server"
|
import { loadGuideLinks } from "~/modules/navigation/load-guide-links.server"
|
||||||
import prismThemeCss from "~/modules/ui/prism-theme.css"
|
import prismThemeCss from "~/modules/ui/prism-theme.css"
|
||||||
import tailwindCss from "~/modules/ui/tailwind.out.css"
|
import tailwindCss from "~/modules/ui/tailwind.out.css"
|
||||||
@@ -61,19 +56,14 @@ export const links: LinksFunction = () => [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
type LoaderData = {
|
export async function loader() {
|
||||||
guideLinks: GuideLink[]
|
return {
|
||||||
}
|
|
||||||
|
|
||||||
export const loader: LoaderFunction = async () => {
|
|
||||||
const data: LoaderData = {
|
|
||||||
guideLinks: await loadGuideLinks(),
|
guideLinks: await loadGuideLinks(),
|
||||||
}
|
}
|
||||||
return data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const data: LoaderData = useLoaderData()
|
const data = useLoaderData<typeof loader>()
|
||||||
return (
|
return (
|
||||||
<html lang="en" className="bg-slate-900 text-slate-100">
|
<html lang="en" className="bg-slate-900 text-slate-100">
|
||||||
<head>
|
<head>
|
||||||
|
|||||||
@@ -7,11 +7,15 @@ meta:
|
|||||||
|
|
||||||
# Getting Started
|
# Getting Started
|
||||||
|
|
||||||
This guide assumes some familiarity with JavaScript, [React](https://reactjs.org), [Discord.js](https://discord.js.org) and the [Discord API](https://discord.dev). Keep these pages as reference if you need it.
|
These guides assume some familiarity with JavaScript, [React](https://reactjs.org), [Discord.js](https://discord.js.org) and the [Discord API](https://discord.dev). Keep these pages as reference if you need it.
|
||||||
|
|
||||||
**Note:** Ensure your project has support for running code with JSX. I recommend using [esno](https://npm.im/esno).
|
## Setup from template
|
||||||
|
|
||||||
## Install
|
[Use this starter template](https://github.com/itsMapleLeaf/reacord-starter) to get off the ground quickly.
|
||||||
|
|
||||||
|
## Adding to an existing project
|
||||||
|
|
||||||
|
Install Reacord and dependencies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# npm
|
# npm
|
||||||
@@ -24,12 +28,10 @@ yarn add reacord react discord.js
|
|||||||
pnpm add reacord react discord.js
|
pnpm add reacord react discord.js
|
||||||
```
|
```
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
Create a Discord.js client and a Reacord instance:
|
Create a Discord.js client and a Reacord instance:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// main.js
|
// main.jsx
|
||||||
import { Client } from "discord.js"
|
import { Client } from "discord.js"
|
||||||
import { ReacordDiscordJs } from "reacord"
|
import { ReacordDiscordJs } from "reacord"
|
||||||
|
|
||||||
@@ -42,3 +44,10 @@ client.on("ready", () => {
|
|||||||
|
|
||||||
await client.login(process.env.BOT_TOKEN)
|
await client.login(process.env.BOT_TOKEN)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To use JSX in your code, run it with [tsx](https://npm.im/tsx):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install tsx
|
||||||
|
tsx main.tsx
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
order: 5
|
||||||
meta:
|
meta:
|
||||||
title: useInstance
|
title: useInstance
|
||||||
description: Using useInstance to get the current instance within a component
|
description: Using useInstance to get the current instance within a component
|
||||||
|
|||||||
8
packages/website/cypress.config.ts
Normal file
8
packages/website/cypress.config.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { defineConfig } from "cypress"
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
e2e: {
|
||||||
|
setupNodeEvents(on, config) {},
|
||||||
|
baseUrl: "http://localhost:3000/",
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"baseUrl": "http://localhost:3000/"
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Using fixtures to represent data",
|
|
||||||
"email": "hello@cypress.io",
|
|
||||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
// ***********************************************************
|
|
||||||
// This example plugins/index.js can be used to load plugins
|
|
||||||
//
|
|
||||||
// You can change the location of this file or turn off loading
|
|
||||||
// the plugins file with the 'pluginsFile' configuration option.
|
|
||||||
//
|
|
||||||
// You can read more here:
|
|
||||||
// https://on.cypress.io/plugins-guide
|
|
||||||
// ***********************************************************
|
|
||||||
|
|
||||||
// This function is called when a project is opened or re-opened (e.g. due to
|
|
||||||
// the project's config changing)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Cypress.PluginConfig}
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
export default function cypressConfig(on, config) {
|
|
||||||
// `on` is used to hook into various events Cypress emits
|
|
||||||
// `config` is the resolved Cypress config
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// ***********************************************
|
|
||||||
// This example commands.js shows you how to
|
|
||||||
// create various custom commands and overwrite
|
|
||||||
// existing commands.
|
|
||||||
//
|
|
||||||
// For more comprehensive examples of custom
|
|
||||||
// commands please read more here:
|
|
||||||
// https://on.cypress.io/custom-commands
|
|
||||||
// ***********************************************
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a parent command --
|
|
||||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a child command --
|
|
||||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a dual command --
|
|
||||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This will overwrite an existing command --
|
|
||||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
|
||||||
import "@testing-library/cypress/add-commands"
|
|
||||||
1
packages/website/cypress/support/commands.ts
Normal file
1
packages/website/cypress/support/commands.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import "@testing-library/cypress/add-commands"
|
||||||
1
packages/website/cypress/support/e2e.ts
Normal file
1
packages/website/cypress/support/e2e.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import "./commands"
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// ***********************************************************
|
|
||||||
// This example support/index.js is processed and
|
|
||||||
// loaded automatically before your test files.
|
|
||||||
//
|
|
||||||
// This is a great place to put global configuration and
|
|
||||||
// behavior that modifies Cypress.
|
|
||||||
//
|
|
||||||
// You can change the location of this file or turn off
|
|
||||||
// automatically serving support files with the
|
|
||||||
// 'supportFile' configuration option.
|
|
||||||
//
|
|
||||||
// You can read more here:
|
|
||||||
// https://on.cypress.io/configuration
|
|
||||||
// ***********************************************************
|
|
||||||
|
|
||||||
// Import commands.js using ES2015 syntax:
|
|
||||||
import "./commands"
|
|
||||||
|
|
||||||
// Alternatively you can use CommonJS syntax:
|
|
||||||
// require('./commands')
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "website",
|
"name": "website",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "concurrently 'typedoc --watch' 'pnpm tailwind -- --watch' 'remix dev'",
|
"dev": "concurrently 'typedoc --watch' 'pnpm tailwind -- --watch' 'remix dev'",
|
||||||
@@ -12,41 +12,42 @@
|
|||||||
"typecheck": "tsc --noEmit && tsc --project cypress/tsconfig.json --noEmit"
|
"typecheck": "tsc --noEmit && tsc --project cypress/tsconfig.json --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/react": "^1.6.0",
|
"@headlessui/react": "^1.6.6",
|
||||||
"@heroicons/react": "^1.0.6",
|
"@heroicons/react": "^1.0.6",
|
||||||
"@reach/rect": "^0.17.0",
|
"@reach/rect": "^0.17.0",
|
||||||
"@remix-run/node": "^1.4.1",
|
"@remix-run/node": "^1.6.5",
|
||||||
"@remix-run/react": "^1.4.1",
|
"@remix-run/react": "^1.6.5",
|
||||||
"@remix-run/serve": "^1.4.1",
|
"@remix-run/serve": "^1.6.5",
|
||||||
"@tailwindcss/typography": "^0.5.2",
|
"@tailwindcss/typography": "^0.5.4",
|
||||||
"clsx": "^1.1.1",
|
"clsx": "^1.2.1",
|
||||||
"fast-glob": "^3.2.11",
|
"fast-glob": "^3.2.11",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"reacord": "workspace:*",
|
"reacord": "workspace:*",
|
||||||
"react": "^18.0.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.0.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-focus-on": "^3.5.4",
|
"react-focus-on": "^3.6.0",
|
||||||
"react-router": "^6.3.0",
|
"react-router": "^6.3.0",
|
||||||
"react-router-dom": "^6.3.0"
|
"react-router-dom": "^6.3.0",
|
||||||
|
"zod": "^3.17.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@remix-run/dev": "^1.4.1",
|
"@remix-run/dev": "^1.6.5",
|
||||||
"@remix-run/node": "^1.4.1",
|
"@remix-run/node": "^1.4.1",
|
||||||
"@testing-library/cypress": "^8.0.2",
|
"@testing-library/cypress": "^8.0.3",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@types/react": "^18.0.7",
|
"@types/react": "^18.0.15",
|
||||||
"@types/react-dom": "^18.0.2",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@types/tailwindcss": "^3.0.10",
|
"@types/tailwindcss": "^3.0.11",
|
||||||
"@types/wait-on": "^5.3.1",
|
"@types/wait-on": "^5.3.1",
|
||||||
"autoprefixer": "^10.4.5",
|
"autoprefixer": "^10.4.7",
|
||||||
"concurrently": "^7.1.0",
|
"concurrently": "^7.3.0",
|
||||||
"cypress": "^9.6.0",
|
"cypress": "^10.3.1",
|
||||||
"execa": "^6.1.0",
|
"execa": "^6.1.0",
|
||||||
"postcss": "^8.4.12",
|
"postcss": "^8.4.14",
|
||||||
"rehype-prism-plus": "^1.3.2",
|
"rehype-prism-plus": "^1.4.2",
|
||||||
"tailwindcss": "^3.0.24",
|
"tailwindcss": "^3.1.6",
|
||||||
"typedoc": "^0.22.15",
|
"typedoc": "^0.23.8",
|
||||||
"typescript": "^4.6.3",
|
"typescript": "^4.7.4",
|
||||||
"wait-on": "^6.0.1"
|
"wait-on": "^6.0.1"
|
||||||
},
|
},
|
||||||
"sideEffects": false
|
"sideEffects": false
|
||||||
|
|||||||
@@ -6,5 +6,6 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"~/*": ["./app/*"]
|
"~/*": ["./app/*"]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||||
}
|
}
|
||||||
|
|||||||
5116
pnpm-lock.yaml
generated
5116
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user