diff --git a/bun.lock b/bun.lock index 8df1994..d114722 100644 --- a/bun.lock +++ b/bun.lock @@ -5,6 +5,7 @@ "name": "thenextlvl-docs", "dependencies": { "@icons-pack/react-simple-icons": "^13.7.0", + "@shikijs/types": "^3.11.0", "fumadocs-core": "15.7.1", "fumadocs-mdx": "11.8.0", "fumadocs-ui": "15.7.1", diff --git a/content/docs/characters/manage/actions.mdx b/content/docs/characters/manage/actions.mdx index f3b4b4b..45810dd 100644 --- a/content/docs/characters/manage/actions.mdx +++ b/content/docs/characters/manage/actions.mdx @@ -54,7 +54,7 @@ Using `` in a parameter will be replaced with the name of the player who To add a greeting action to a character named "Steve", use the following command: ``` -/character action add Steve greet any_click send-message Hello, ! +/character action add Steve greet any_click send-message Hello, ! ``` This action will be triggered on any click and sends `Hello, NonSwag!` if the player's name is NonSwag. @@ -81,7 +81,7 @@ To set a cooldown for an action, use the command: #### Example [!toc] [#cooldown-set-example] ``` -/character action cooldown Steve greet 10s +/character action cooldown Steve greet 10s ``` This sets a cooldown of **10 seconds** for the **greet** action of the character **Steve**. @@ -94,7 +94,7 @@ To view the current cooldown for an action, use the command #### Example [!toc] [#cooldown-view-example] ``` -/character action cooldown Steve greet +/character action cooldown Steve greet ``` --- @@ -112,7 +112,7 @@ To define a permission for an action, use the command #### Example [!toc] [#permission-set-example] ``` -/character action permission Steve greet set warm.welcome.permission +/character action permission Steve greet set warm.welcome.permission ``` ### Remove a Permission @@ -123,7 +123,7 @@ To remove a permission for an action, use the command #### Example [!toc] [#permission-remove-example] ``` -/character action permission Steve greet remove +/character action permission Steve greet remove ``` ### View Current Permission @@ -134,7 +134,7 @@ To view the current permission for an action, use the command #### Example [!toc] [#permission-view-example] ``` -/character action permission Steve greet +/character action permission Steve greet ``` --- @@ -147,7 +147,7 @@ To remove a specific action from a character, use the command ### Example [!toc] [#remove-example] ``` -/character action remove Steve greet +/character action remove Steve greet ``` --- @@ -159,6 +159,6 @@ List all actions configured for a character using `/character action list Steve ``` diff --git a/content/docs/characters/manage/create.mdx b/content/docs/characters/manage/create.mdx index 14a591c..545d94c 100644 --- a/content/docs/characters/manage/create.mdx +++ b/content/docs/characters/manage/create.mdx @@ -12,11 +12,11 @@ If you do not specify a type, the default type is `minecraft:player`. To create a player character named "Steve", you can use the following command: ``` -/character create Steve minecraft:player +/character create Steve minecraft:player ``` To create a zombie character named "Zed", you would use: ``` -/character create Zed minecraft:zombie +/character create Zed minecraft:zombie ``` diff --git a/content/docs/characters/manage/delete.mdx b/content/docs/characters/manage/delete.mdx index efaf90f..ce7562c 100644 --- a/content/docs/characters/manage/delete.mdx +++ b/content/docs/characters/manage/delete.mdx @@ -15,5 +15,5 @@ Deleting a character is permanent and cannot be undone. ## Example [!toc] ``` -/character delete Steve +/character delete Steve ``` diff --git a/content/docs/characters/manage/equipment.mdx b/content/docs/characters/manage/equipment.mdx index 224244e..95a96fc 100644 --- a/content/docs/characters/manage/equipment.mdx +++ b/content/docs/characters/manage/equipment.mdx @@ -21,7 +21,7 @@ To equip an item in a specific slot for a character, use the command: To equip a diamond helmet for a character named "Guardian", use: ``` -/character equipment set Guardian head minecraft:diamond_helmet +/character equipment set Guardian head minecraft:diamond_helmet ``` ## Clearing Equipment @@ -39,7 +39,7 @@ To clear a specific equipment slot for a character, use the command: To clear the chestplate slot for a character named "Warrior": ``` -/character equipment clear Warrior chest +/character equipment clear Warrior chest ``` ### Clear All Equipment @@ -52,7 +52,7 @@ To clear all equipment slots for a character, use the command To clear all equipment for a character named "Mage": ``` -/character equipment clear Mage +/character equipment clear Mage ``` ## Available Equipment Slots diff --git a/content/docs/characters/manage/skins.mdx b/content/docs/characters/manage/skins.mdx index 8b1e4c2..a2638a8 100644 --- a/content/docs/characters/manage/skins.mdx +++ b/content/docs/characters/manage/skins.mdx @@ -32,13 +32,13 @@ you can use the command `/character skin set player [slim]` Classic skins can be applied using the following command: ``` -/character skin set MyCharacter player Notch +/character skin set MyCharacter player Notch ``` To apply a slim skin, just append the `slim` option: ``` -/character skin set MyCharacter player Notch slim +/character skin set MyCharacter player Notch slim ``` ## Applying a Skin from File @@ -59,7 +59,7 @@ If the file is located in the server's main directory, you can use a relative pa To change a character's skin using a file, you can use the following command: ``` -/character skin set MyCharacter file "/home/skins/my_skin.png" +/character skin set MyCharacter file "/home/skins/my_skin.png" ``` ## Applying a Skin from URL @@ -77,7 +77,7 @@ You can change a character's skin using a URL with the command To change a character's skin using a URL, you can use the following command: ``` -/character skin set MyCharacter url "https://example.com/skin.png" +/character skin set MyCharacter url "https://example.com/skin.png" ``` ## Resetting a Skin @@ -85,7 +85,7 @@ To change a character's skin using a URL, you can use the following command: To reset a character's skin to default, you can use the following command: ``` -/character skin reset MyCharacter +/character skin reset MyCharacter ``` This will only reset the skin, not the skin layers. @@ -102,7 +102,7 @@ By default, all layers are shown. You can hide or show each layer individually. To hide a character's cape layer, you can use the following command: ``` -/character skin layer hide cape MyCharacter +/character skin layer hide cape MyCharacter ``` ### Available Skin Layers diff --git a/content/docs/characters/manage/tag.mdx b/content/docs/characters/manage/tag.mdx index f6ca4f0..288e97c 100644 --- a/content/docs/characters/manage/tag.mdx +++ b/content/docs/characters/manage/tag.mdx @@ -39,17 +39,17 @@ You can customize your character's nametag using the `/character tag` command. Set the nametag text: ``` -/character tag set text Hello there!Welcome to the game! +/character tag set Steve text Hello there!Welcome to the game! ``` Change the background color to red: ``` -/character tag set background-color red +/character tag set Steve background-color red ``` Reset the scale to default: ``` -/character tag reset scale +/character tag reset Steve scale ``` diff --git a/content/docs/perworlds/manage/add.mdx b/content/docs/perworlds/manage/add.mdx index d5aa1df..c66ffe8 100644 --- a/content/docs/perworlds/manage/add.mdx +++ b/content/docs/perworlds/manage/add.mdx @@ -11,7 +11,7 @@ The `` argument is the key of the world you want to add, and `` is Adding all farmworlds to the group "farmworld": ``` -/world group add farmworld:normal farmworld -/world group add farmworld:nether farmworld -/world group add farmworld:the_end farmworld +/world group add farmworld:normal farmworld +/world group add farmworld:nether farmworld +/world group add farmworld:the_end farmworld ``` diff --git a/content/docs/perworlds/manage/create.mdx b/content/docs/perworlds/manage/create.mdx index 94f8e26..d7e2d72 100644 --- a/content/docs/perworlds/manage/create.mdx +++ b/content/docs/perworlds/manage/create.mdx @@ -11,5 +11,5 @@ The `` argument is the name you want to give to your world group. Creating a world group called "farmworld": ``` -/world group create farmworld +/world group create farmworld ``` diff --git a/content/docs/perworlds/manage/delete.mdx b/content/docs/perworlds/manage/delete.mdx index 830952c..591a7d6 100644 --- a/content/docs/perworlds/manage/delete.mdx +++ b/content/docs/perworlds/manage/delete.mdx @@ -18,5 +18,5 @@ Deleting a group is irreversible. Make sure to back up any important data before ### Example [!toc] ``` -/world group delete farmworld +/world group delete farmworld ``` diff --git a/content/docs/perworlds/manage/options.mdx b/content/docs/perworlds/manage/options.mdx index ac52ac8..593a0e9 100644 --- a/content/docs/perworlds/manage/options.mdx +++ b/content/docs/perworlds/manage/options.mdx @@ -19,13 +19,13 @@ The player state will not change when switching between worlds within the same g To disable a group entirely, you can use the command: ``` -/world group option enabled farmworld false +/world group option enabled farmworld false ``` To query the current value of an option, you can use the command: ``` -/world group option inventory farmworld +/world group option inventory farmworld ``` ## All available options [!toc] diff --git a/content/docs/perworlds/manage/remove.mdx b/content/docs/perworlds/manage/remove.mdx index edcc2f4..7fa5fba 100644 --- a/content/docs/perworlds/manage/remove.mdx +++ b/content/docs/perworlds/manage/remove.mdx @@ -16,5 +16,5 @@ This will remove the specified world from the specified group. ### Example [!toc] ``` -/world group remove farmworld worlds:void +/world group remove farmworld worlds:void ``` diff --git a/content/docs/worlds/manage/clone.mdx b/content/docs/worlds/manage/clone.mdx index 8c15bf2..89f8e80 100644 --- a/content/docs/worlds/manage/clone.mdx +++ b/content/docs/worlds/manage/clone.mdx @@ -15,11 +15,11 @@ The `template` option defines whether the cloned world should be regenerated or Example on how to create an exact copy of a world (1:1): ``` -/world clone worlds:my_world my_world_copy +/world clone worlds:my_world my_world_copy ``` Example on how to clone a world's generation settings (no region data, scoreboards, player data, etc.): ``` -/world clone worlds:my_world my_world_copy template +/world clone worlds:my_world my_world_copy template ``` diff --git a/content/docs/worlds/manage/create.mdx b/content/docs/worlds/manage/create.mdx index 476d42f..85c5b53 100644 --- a/content/docs/worlds/manage/create.mdx +++ b/content/docs/worlds/manage/create.mdx @@ -17,7 +17,7 @@ If you don't specify any of these options, the default world settings will be us Creating a new world with the default settings: ``` -/world create "My New World" +/world create "My New World" ``` ## Using a world generator plugin @@ -31,7 +31,7 @@ The generator argument takes the name of the plugin that provides the custom chu PlotSquared generation example: ``` -/world create city generator PlotSquared +/world create city generator PlotSquared ``` ## Defining the world type @@ -54,7 +54,7 @@ The following types are available: Amplified world example: ``` -/world create Amplified type amplified +/world create Amplified type amplified ``` ## Using a flat world preset @@ -73,7 +73,7 @@ Check out the [Creating a world preset](/docs/worlds/presets) documentation. Void world example: ``` -/world create "My Void World" preset the-void +/world create "My Void World" preset the-void ``` ## Additional options @@ -94,19 +94,19 @@ Options are specified as `option value` pairs, and can be used in any given orde Creating a normal world with structures disabled, a bonus chest, and a specific seed: ``` -/world create "A cool new world" type normal structures false bonus-chest true seed 123456789 +/world create "A cool new world" type normal structures false bonus-chest true seed 123456789 ``` Creating a nether world with a specificified key: ``` -/world create "My Nether World" type normal dimension nether key citybuild:farmworld/nether +/world create "My Nether World" type normal dimension nether key citybuild:farmworld/nether ``` To create a default world without any custom options, you can use: ``` -/world create "My Default World" +/world create "My Default World" ``` ## Available Dimensions diff --git a/content/docs/worlds/manage/delete.mdx b/content/docs/worlds/manage/delete.mdx index b547c81..2865bef 100644 --- a/content/docs/worlds/manage/delete.mdx +++ b/content/docs/worlds/manage/delete.mdx @@ -26,11 +26,11 @@ Deleting a world is irreversible. Make sure to back up any important data before To simply delete a world, you can use the following command: ``` -/world delete worlds:my_world --confirm +/world delete worlds:my_world --confirm ``` To schedule the deletion of a world, you can use: ``` -/world delete minecraft:overworld --confirm --schedule +/world delete minecraft:overworld --confirm --schedule ``` diff --git a/content/docs/worlds/manage/import.mdx b/content/docs/worlds/manage/import.mdx index 61ca4a8..4881aae 100644 --- a/content/docs/worlds/manage/import.mdx +++ b/content/docs/worlds/manage/import.mdx @@ -21,23 +21,23 @@ Options are specified as `option value` pairs, and can be used in any given orde To import a specific dimension of a world, you can use the following command: ``` -/world import End key worlds:end dimension end +/world import End key worlds:end dimension end ``` To import a world with a specific generator, you can use the following command: ``` -/world import "My World" generator TheGeneratorPlugin +/world import "My World" generator TheGeneratorPlugin ``` To import a world with a different name, you can use: ``` -/world import "My World" name "New World Name" +/world import "My World" name "New World Name" ``` To import a world without any custom options, you can use: ``` -/world import Survival +/world import Survival ``` diff --git a/content/docs/worlds/manage/links.mdx b/content/docs/worlds/manage/links.mdx index 7417c5c..f9dbaba 100644 --- a/content/docs/worlds/manage/links.mdx +++ b/content/docs/worlds/manage/links.mdx @@ -31,13 +31,13 @@ The `` world must be a `Nether` or `End` dimension. Linking an **Overworld** to a **Nether** world: ``` -/world link create farmworld:normal farmworld:nether +/world link create farmworld:normal farmworld:nether ``` Linking an **Overworld** to an **End** world: ``` -/world link create farmworld:normal farmworld:the_end +/world link create farmworld:normal farmworld:the_end ``` ## Removing world links @@ -50,11 +50,11 @@ You can remove a link by using the command `/world link remove farmworld:normal farmworld:nether ``` Removing the link between an **Overworld** and an **End** world: ``` -/world link remove farmworld:normal farmworld:the_end +/world link remove farmworld:normal farmworld:the_end ``` diff --git a/content/docs/worlds/manage/load-unload.mdx b/content/docs/worlds/manage/load-unload.mdx index 7a2f914..b22356c 100644 --- a/content/docs/worlds/manage/load-unload.mdx +++ b/content/docs/worlds/manage/load-unload.mdx @@ -12,7 +12,7 @@ if you want to load a world that is not managed by Worlds, [import](/docs/worlds ### Example [!toc] ``` -/world load MyWorld +/world load MyWorld ``` ## Unloading worlds @@ -24,5 +24,5 @@ If undefined, players will be sent to the default world (usually `minecraft:over ### Example [!toc] ``` -/world unload worlds:my_world worlds:my_fallback_world +/world unload worlds:my_world worlds:my_fallback_world ``` diff --git a/package.json b/package.json index 8eb02d5..ff19077 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@icons-pack/react-simple-icons": "^13.7.0", + "@shikijs/types": "^3.11.0", "fumadocs-core": "15.7.1", "fumadocs-mdx": "11.8.0", "fumadocs-ui": "15.7.1", @@ -32,5 +33,5 @@ "tailwindcss": "^4.1.12", "typescript": "^5.9.2" }, - "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" -} + "packageManager": "bun@1.2.20" +} \ No newline at end of file diff --git a/source.config.ts b/source.config.ts index 1abf7bd..dccb4eb 100644 --- a/source.config.ts +++ b/source.config.ts @@ -1,4 +1,5 @@ -import { defineConfig, defineDocs, frontmatterSchema, metaSchema } from "fumadocs-mdx/config" +import { defineConfig, defineDocs, frontmatterSchema, metaSchema } from "fumadocs-mdx/config"; +import { transformerCommandColor } from "./src/lib/command-transformer"; // You can customise Zod schemas for frontmatter and `meta.json` here // see https://fumadocs.vercel.app/docs/mdx/collections#define-docs @@ -9,10 +10,21 @@ export const docs = defineDocs({ meta: { schema: metaSchema, }, -}) +}); export default defineConfig({ mdxOptions: { - // MDX options + rehypeCodeOptions: { + themes: { + light: "github-light", + dark: "github-dark", + }, + langAlias: { + command: 'text', + }, + transformers: [ + transformerCommandColor(), + ], + }, }, -}) +}); diff --git a/src/app/docs/[[...slug]]/page.tsx b/src/app/docs/[[...slug]]/page.tsx index a988b19..a6ac585 100644 --- a/src/app/docs/[[...slug]]/page.tsx +++ b/src/app/docs/[[...slug]]/page.tsx @@ -26,7 +26,7 @@ export default async function Page(props: { params: Promise<{ slug?: string[] }> {page.data.description} content + * ``` + */ +export const commandColors: Record = { + black: "#000000", + dark_blue: "#0000aa", + dark_green: "#00aa00", + dark_aqua: "#00aaaa", + dark_red: "#aa0000", + dark_purple: "#aa00aa", + gold: "#ffaa00", + gray: "#aaaaaa", + dark_gray: "#555555", + blue: "#5555ff", + green: "#55ff55", + aqua: "#55ffff", + red: "#ff5555", + light_purple: "#ff55ff", + yellow: "#ffff55", + white: "#ffffff", +} + +export function getCommandColor(colorName: string): string | null { + return commandColors[colorName.toLowerCase()] || null +} diff --git a/src/lib/command-transformer.ts b/src/lib/command-transformer.ts new file mode 100644 index 0000000..664dbbd --- /dev/null +++ b/src/lib/command-transformer.ts @@ -0,0 +1,129 @@ +import type { ShikiTransformer, ThemedToken } from "@shikijs/types" +import { getCommandColor } from "./command-colors" + +interface ColorContentRange { + start: number + end: number + color: string +} + +interface HideRange { + start: number + end: number +} + +interface MetaRanges { + contents: ColorContentRange[] + hides: HideRange[] +} + +function detectRanges(code: string): MetaRanges { + const contents: ColorContentRange[] = [] + const hides: HideRange[] = [] + + const re = /<([A-Za-z_+-]+)>([\s\S]*?)<\/\1>/g + let match: RegExpExecArray | null + while ((match = re.exec(code)) !== null) { + const [full, colorName, inner] = match + const openStart = match.index + const openEnd = openStart + `<${colorName}>`.length + const closeEnd = openStart + full.length + const closeStart = closeEnd - ``.length + hides.push({ start: openStart, end: openEnd }) + hides.push({ start: closeStart, end: closeEnd }) + contents.push({ start: openEnd, end: closeStart, color: colorName }) + } + + return { contents, hides } +} + +function splitTokenAtOffsets(token: ThemedToken, breakpoints: number[]): ThemedToken[] { + if (!breakpoints.length) return [token] + const local = Array.from( + new Set( + breakpoints.filter((bp) => bp > token.offset && bp < token.offset + token.content.length), + ), + ).sort((a, b) => a - b) + + if (!local.length) return [token] + + const result: ThemedToken[] = [] + let last = 0 + for (const bp of local) { + const idx = bp - token.offset + if (idx > last) { + result.push({ + ...token, + content: token.content.slice(last, idx), + offset: token.offset + last, + }) + } + last = idx + } + if (last < token.content.length) { + result.push({ ...token, content: token.content.slice(last), offset: token.offset + last }) + } + return result +} + +export function transformerCommandColor(): ShikiTransformer { + const map = new WeakMap() + + return { + name: "color-tags", + preprocess(code) { + const ranges = detectRanges(code) + const metaKey = (this as unknown as { meta?: object }).meta ?? {} + map.set(metaKey, ranges) + return undefined + }, + tokens(lines) { + const metaKey = (this as unknown as { meta?: object }).meta ?? {} + const ranges = map.get(metaKey) + if (!ranges) return lines + + return lines.map((line) => { + if (!line.length) return line + + const start = line[0] + const end = line[line.length - 1] + const lineStart = start.offset + const lineEnd = end.offset + end.content.length + + const bps: number[] = [] + for (const r of [...ranges.hides, ...ranges.contents]) { + if (r.start > lineStart && r.start < lineEnd) bps.push(r.start) + if (r.end > lineStart && r.end < lineEnd) bps.push(r.end) + } + + if (!bps.length) return line + + const splitted = line.flatMap((t) => splitTokenAtOffsets(t, bps)) + + const styled: ThemedToken[] = splitted + .filter((seg) => { + return !ranges.hides.some( + (r) => r.start <= seg.offset && seg.offset + seg.content.length <= r.end, + ) + }) + .map((seg) => { + const contentRange = ranges.contents.find( + (r) => r.start <= seg.offset && seg.offset + seg.content.length <= r.end, + ) + if (contentRange) { + const cfg = getCommandColor(contentRange.color) + if (cfg) { + return { + ...seg, + htmlStyle: { ...(seg.htmlStyle || {}), color: cfg }, + } + } + } + return seg + }) + + return styled + }) + }, + } +}