Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions builder/src/components/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { project, title } from "../../util/parsed";
import FunctionPage from "../../pages/FunctionPage";
import TablePage from "../../pages/TablePage";
import CategoryPage from "../../pages/CategoryPage";
import WikiPage from "../../pages/WikiPage";
import { dark } from "../../styles/themes/dark";
import { Helmet } from "react-helmet";

Expand All @@ -29,6 +30,8 @@ const RouteController: React.FC<{}> = () => {

if (item.item.startsWith("category")) {
return <CategoryPage />;
} else if (item.item === "wiki") {
return <WikiPage />;
} else if (item.item.endsWith("table")) {
return <TablePage />;
}
Expand Down
98 changes: 98 additions & 0 deletions builder/src/pages/WikiPage/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React from "react";
import Page from "../Page";
import { useParams } from "react-router-dom";
import { project, WikiPage as WikiPageObject, WikiContent } from "../../util/parsed";
import marked from "../../util/marked";
import { SectionContainer, Section } from "../Page/styles";
import Prism from "prismjs";
import "prismjs/components/prism-lua";

const CODE_LANGUAGE = "lua";
const CODE_CLASS = `language-${CODE_LANGUAGE}`;

const renderCodeBlock = (code: string, key: string) => {
const language = Prism.languages[CODE_LANGUAGE];
const highlighted = language
? Prism.highlight(code, language, CODE_LANGUAGE)
: code;
return (
<pre key={key} className={CODE_CLASS}>
<code
className={CODE_CLASS}
dangerouslySetInnerHTML={{ __html: highlighted }}
/>
</pre>
);
};

const WikiPage: React.FC<{}> = () => {
const { tab, category } = useParams();
const category_object = project[tab]?.subcategories?.[category];
const item = category_object as WikiPageObject;
const description = item.description;
const content: WikiContent[] = item.content ?? [];

function markedDescription() {
return {
__html: marked(description as string),
};
}

function renderContent() {
const elements: JSX.Element[] = [];
let currentParagraph: string[] = [];

const flushParagraph = () => {
if (currentParagraph.length > 0) {
const text = currentParagraph.join(" ");
elements.push(
<p
key={`text-${elements.length}`}
dangerouslySetInnerHTML={{ __html: marked(text) }}
/>
);
currentParagraph = [];
}
};

content.forEach((item, index) => {
switch (item.type) {
case "header":
flushParagraph();
elements.push(
<Section key={`header-${index}`}>{item.content}</Section>
);
break;
case "text":
currentParagraph.push(item.content);
break;
case "br":
flushParagraph();
break;
case "code":
flushParagraph();
elements.push(renderCodeBlock(item.content, `code-${index}`));
break;
}
});

flushParagraph();
return elements;
}

return (
<Page title={item.name}>
{description && (
<>
<Section>Description</Section>
<SectionContainer
dangerouslySetInnerHTML={markedDescription()}
/>
</>
)}
<SectionContainer>{renderContent()}</SectionContainer>
</Page>
);
};

export default WikiPage;
19 changes: 18 additions & 1 deletion builder/src/util/parsed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
mdiFormatListNumbered,
mdiHook,
mdiViewQuilt,
mdiFileDocument,
} from "@mdi/js";
import * as mdiIcons from "@mdi/js";

Expand Down Expand Up @@ -51,6 +52,21 @@ export interface TablePage {
item: "table";
}

export interface WikiContent {
type: "header" | "text" | "code" | "br";
content: string;
}

export interface WikiPage {
name: string;
description?: string;
content: WikiContent[];
realm?: string;
internal?: boolean;
deprecated?: boolean;
item: "wiki";
}

export interface Category {
name: string;
description?: string;
Expand All @@ -64,7 +80,7 @@ export interface Category {
item: "category";
}

export type ValidSubcategory = Category | FunctionPage | TablePage;
export type ValidSubcategory = Category | FunctionPage | TablePage | WikiPage;

export interface ProjectStructure {
[key: string]: Category;
Expand All @@ -90,6 +106,7 @@ export const icons: {
panels: mdiViewQuilt,
enums: mdiFormatListNumbered,
structs: mdiDatabase,
wikis: mdiFileDocument,
default: mdiCursorDefault,
};

Expand Down
21 changes: 21 additions & 0 deletions parser/examples/wikis/getting_started.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- @wiki Getting Started
-- This wiki page explains how to get started with the project.
--
-- @header Introduction
-- @text Welcome to the documentation. This guide will help you understand
-- @text how to use the wiki pages feature in gdocs.
-- @br
-- @text Wiki pages allow you to create rich documentation with headers,
-- @text text paragraphs, and code examples.
--
-- @header Example Code
-- @text Here is an example of how to use the library:
-- @code
-- local function example()
-- print("Hello, World!")
-- end
--
-- @header Another Section
-- @text This is another section with more text.
-- @br
-- @text After a break, we start a new paragraph.
22 changes: 16 additions & 6 deletions parser/src/classes/Project/Category.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { DocBlock } from "../Parser/Tags.ts";
import { get_multiple, get_unique } from "../../utils/functions.ts";
import AliasTag from "../Tags/AliasTag.ts";
import TablePage, { FieldInfo } from "./TablePage.ts";
import WikiPage from "./WikiPage.ts";

export type ValidSubcategory = Category | FunctionPage | TablePage;
export type ValidSubcategory = Category | FunctionPage | TablePage | WikiPage;

export type ValidPageTypes = "function" | "table";
export type ValidPageTypes = "function" | "table" | "wiki";

export default class Category {
readonly subcategories: {
Expand Down Expand Up @@ -72,17 +73,26 @@ export default class Category {
.map((tag) => tag[0])
.join("\n\n")
.trim();
const page = this.pageType === "function"
? new FunctionPage(
let page: FunctionPage | TablePage | WikiPage;
if (this.pageType === "wiki") {
page = new WikiPage(
name,
description != "" ? description : undefined,
block,
)
: new TablePage(
);
} else if (this.pageType === "table") {
page = new TablePage(
name,
description != "" ? description : undefined,
block,
);
} else {
page = new FunctionPage(
name,
description != "" ? description : undefined,
block,
);
}

if (has_subcategory) {
const subcategory = get_unique(block, "subcategory") as string;
Expand Down
12 changes: 12 additions & 0 deletions parser/src/classes/Project/CategoryProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ export default class CategoryProject {
this.add_tag(new BooleanTag("internal"));
this.add_tag(new BooleanTag("deprecated"));
this.add_tag(new BooleanTag("stub"));
/* Wiki-specific tags */
this.add_tag(new Tag("header", 1, false));
this.add_tag(new Tag("text", 1, false, false, true));
this.add_tag(new Tag("code", 1, false, false, true));
this.add_tag(new Tag("br", 0, false));
this.add_tag(
new AliasTag("hook", 2, ([subcategory, name]) => [
"@category hooks",
Expand Down Expand Up @@ -84,6 +89,13 @@ export default class CategoryProject {
false,
true,
);
this.add_category(
new Category("Wikis", "wiki"),
false,
"wiki",
false,
true,
);

/* Default categories that define types. */
this.add_category_type("Classes");
Expand Down
85 changes: 85 additions & 0 deletions parser/src/classes/Project/WikiPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { DocBlock, TagInfo } from "../Parser/Tags.ts";
import { get_unique } from "../../utils/functions.ts";

export interface WikiContent {
type: "header" | "text" | "code" | "br";
content: string;
}

export default class WikiPage {
readonly item: "wiki";
readonly content: WikiContent[];
readonly realm?: string;
readonly internal?: boolean;
readonly deprecated?: boolean;

constructor(
public readonly name: string,
public readonly description?: string,
block: DocBlock = {},
) {
// Collect all content items with their line numbers for ordering
const contentItems: { line: number; type: WikiContent["type"]; content: string }[] = [];

// Process headers
if (block["header"]) {
block["header"].forEach((tag: TagInfo) => {
contentItems.push({
line: tag.line,
type: "header",
content: tag.args?.[0] ?? "",
});
});
}

// Process text blocks
if (block["text"]) {
block["text"].forEach((tag: TagInfo) => {
contentItems.push({
line: tag.line,
type: "text",
content: tag.args?.[0] ?? "",
});
});
}

// Process code blocks
if (block["code"]) {
block["code"].forEach((tag: TagInfo) => {
contentItems.push({
line: tag.line,
type: "code",
content: tag.args?.[0] ?? "",
});
});
}

// Process br (break) tags
if (block["br"]) {
block["br"].forEach((tag: TagInfo) => {
contentItems.push({
line: tag.line,
type: "br",
content: "",
});
});
}

// Sort by line number to preserve original order
contentItems.sort((a, b) => a.line - b.line);

// Convert to WikiContent format
this.content = contentItems.map(({ type, content }) => ({ type, content }));
this.realm = get_unique(block, "realm");
this.internal = get_unique(block, "internal") === "true" ? true : undefined;
this.deprecated = get_unique(block, "deprecated") === "true"
? true
: undefined;

this.item = "wiki";
}

print(level = 0) {
console.log(" ".repeat(level) + this.name);
}
}