From a28bcd4f8b1ae09879265a7701b44ab1da7a7f67 Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Wed, 20 May 2026 21:55:18 +0200 Subject: [PATCH] (v4.2.0) Large README overhaul (Part 1) --- .github/SPONSORS.json | 90 +++++ .github/SPONSORS.svg | 61 ++++ .../pterodactyl-eggs/README.md | 0 .../pterodactyl-eggs/openticket-egg-dev.json | 0 .../pterodactyl-eggs/openticket-egg-main.json | 0 .../openticket-egg-v3.5.9.json | 0 .../openticket-egg-v4.0.7.json | 0 .../openticket-egg-v4.1.0.json | 0 .../openticket-egg-v4.1.1.json | 0 .../openticket-egg-v4.1.2.json | 0 .../openticket-egg-v4.1.3.json | 0 .../openticket-egg-v4.2.0.json | 0 .gitignore | 6 +- .tools/createDocs.js | 328 ------------------ .tools/createSponsors.ts | 131 +++++++ ...geTranslations.js => mergeTranslations.ts} | 7 +- .tools/typedoc-config.json | 13 - README.md | 171 ++++----- package.json | 4 +- 19 files changed, 379 insertions(+), 432 deletions(-) create mode 100644 .github/SPONSORS.json create mode 100644 .github/SPONSORS.svg rename {.tools => .github}/pterodactyl-eggs/README.md (100%) rename {.tools => .github}/pterodactyl-eggs/openticket-egg-dev.json (100%) rename {.tools => .github}/pterodactyl-eggs/openticket-egg-main.json (100%) rename {.tools => .github}/pterodactyl-eggs/openticket-egg-v3.5.9.json (100%) rename {.tools => .github}/pterodactyl-eggs/openticket-egg-v4.0.7.json (100%) rename {.tools => .github}/pterodactyl-eggs/openticket-egg-v4.1.0.json (100%) rename {.tools => .github}/pterodactyl-eggs/openticket-egg-v4.1.1.json (100%) rename {.tools => .github}/pterodactyl-eggs/openticket-egg-v4.1.2.json (100%) rename {.tools => .github}/pterodactyl-eggs/openticket-egg-v4.1.3.json (100%) rename {.tools => .github}/pterodactyl-eggs/openticket-egg-v4.2.0.json (100%) delete mode 100644 .tools/createDocs.js create mode 100644 .tools/createSponsors.ts rename .tools/{mergeTranslations.js => mergeTranslations.ts} (99%) delete mode 100644 .tools/typedoc-config.json diff --git a/.github/SPONSORS.json b/.github/SPONSORS.json new file mode 100644 index 0000000..1e9399a --- /dev/null +++ b/.github/SPONSORS.json @@ -0,0 +1,90 @@ +{ + "_INFO":"This document contains all Open Ticket sponsors.", + "SPONSOR_TEMPLATE":{ + "name":"INSERT_NAME", + "pictureUrl":"INSERT_PICTURE_URL", + "profileUrl":"INSERT_PROFILE_URL", + "sectionId":"INSERT_ID" + }, + "SECTION_TEMPLATE":{ + "name":"INSERT_NAME", + "id":"INSERT_ID", + "pfpSize":50, + "pfpColumns":5, + "withNames":true + }, + "sections":[ + { + "name":"๐Ÿ’Ž Platinum Sponsors", + "id":"platinum", + "pfpSize":120, + "pfpColumns":4, + "withNames":true + }, + { + "name":"๐Ÿฅ‡ Gold Sponsors", + "id":"gold", + "pfpSize":60, + "pfpColumns":8, + "withNames":true + }, + { + "name":"๐Ÿฅˆ Silver Sponsors", + "id":"silver", + "pfpSize":40, + "pfpColumns":16, + "withNames":false + }, + { + "name":"โค๏ธ Past Sponsors", + "id":"past", + "pfpSize":30, + "pfpColumns":20, + "withNames":false + } + ], + "sponsors":[ + { + "name":"Guillee3", + "pictureUrl":"https://github.com/guillee3.png", + "profileUrl":"https://github.com/guillee3", + "sectionId":"platinum" + }, + { + "name":"Jacob Humston", + "pictureUrl":"https://github.com/jacobhumston.png", + "profileUrl":"https://github.com/jacobhumston", + "sectionId":"platinum" + }, + { + "name":"SpyEye2", + "pictureUrl":"https://github.com/SpyEye2.png", + "profileUrl":"https://github.com/SpyEye2", + "sectionId":"gold" + }, + { + "name":"DOSEV5", + "pictureUrl":"https://github.com/DOSEV5.png", + "profileUrl":"https://github.com/DOSEV5", + "sectionId":"gold" + }, + { + "name":"YeeetSK", + "pictureUrl":"https://github.com/YeeetSK.png", + "profileUrl":"https://github.com/YeeetSK", + "sectionId":"silver" + }, + { + "name":"BENZORICH", + "pictureUrl":"https://github.com/BENZORICH.png", + "profileUrl":"https://github.com/BENZORICH", + "sectionId":"silver" + }, + { + "name":"Mods HD", + "pictureUrl":"https://github.com/mods-hd.png", + "profileUrl":"https://github.com/mods-hd", + "sectionId":"silver" + } + ] +} \ No newline at end of file diff --git a/.github/SPONSORS.svg b/.github/SPONSORS.svg new file mode 100644 index 0000000..e3edf79 --- /dev/null +++ b/.github/SPONSORS.svg @@ -0,0 +1,61 @@ + + + + + \ No newline at end of file diff --git a/.tools/pterodactyl-eggs/README.md b/.github/pterodactyl-eggs/README.md similarity index 100% rename from .tools/pterodactyl-eggs/README.md rename to .github/pterodactyl-eggs/README.md diff --git a/.tools/pterodactyl-eggs/openticket-egg-dev.json b/.github/pterodactyl-eggs/openticket-egg-dev.json similarity index 100% rename from .tools/pterodactyl-eggs/openticket-egg-dev.json rename to .github/pterodactyl-eggs/openticket-egg-dev.json diff --git a/.tools/pterodactyl-eggs/openticket-egg-main.json b/.github/pterodactyl-eggs/openticket-egg-main.json similarity index 100% rename from .tools/pterodactyl-eggs/openticket-egg-main.json rename to .github/pterodactyl-eggs/openticket-egg-main.json diff --git a/.tools/pterodactyl-eggs/openticket-egg-v3.5.9.json b/.github/pterodactyl-eggs/openticket-egg-v3.5.9.json similarity index 100% rename from .tools/pterodactyl-eggs/openticket-egg-v3.5.9.json rename to .github/pterodactyl-eggs/openticket-egg-v3.5.9.json diff --git a/.tools/pterodactyl-eggs/openticket-egg-v4.0.7.json b/.github/pterodactyl-eggs/openticket-egg-v4.0.7.json similarity index 100% rename from .tools/pterodactyl-eggs/openticket-egg-v4.0.7.json rename to .github/pterodactyl-eggs/openticket-egg-v4.0.7.json diff --git a/.tools/pterodactyl-eggs/openticket-egg-v4.1.0.json b/.github/pterodactyl-eggs/openticket-egg-v4.1.0.json similarity index 100% rename from .tools/pterodactyl-eggs/openticket-egg-v4.1.0.json rename to .github/pterodactyl-eggs/openticket-egg-v4.1.0.json diff --git a/.tools/pterodactyl-eggs/openticket-egg-v4.1.1.json b/.github/pterodactyl-eggs/openticket-egg-v4.1.1.json similarity index 100% rename from .tools/pterodactyl-eggs/openticket-egg-v4.1.1.json rename to .github/pterodactyl-eggs/openticket-egg-v4.1.1.json diff --git a/.tools/pterodactyl-eggs/openticket-egg-v4.1.2.json b/.github/pterodactyl-eggs/openticket-egg-v4.1.2.json similarity index 100% rename from .tools/pterodactyl-eggs/openticket-egg-v4.1.2.json rename to .github/pterodactyl-eggs/openticket-egg-v4.1.2.json diff --git a/.tools/pterodactyl-eggs/openticket-egg-v4.1.3.json b/.github/pterodactyl-eggs/openticket-egg-v4.1.3.json similarity index 100% rename from .tools/pterodactyl-eggs/openticket-egg-v4.1.3.json rename to .github/pterodactyl-eggs/openticket-egg-v4.1.3.json diff --git a/.tools/pterodactyl-eggs/openticket-egg-v4.2.0.json b/.github/pterodactyl-eggs/openticket-egg-v4.2.0.json similarity index 100% rename from .tools/pterodactyl-eggs/openticket-egg-v4.2.0.json rename to .github/pterodactyl-eggs/openticket-egg-v4.2.0.json diff --git a/.gitignore b/.gitignore index 193d71e..6363a68 100644 --- a/.gitignore +++ b/.gitignore @@ -19,9 +19,7 @@ otdebug.txt .backup/* .tools/* -!.tools/createDocs.js -!.tools/mergeTranslations.js -!.tools/typedoc-config.json -!.tools/pterodactyl-eggs/ +!.tools/createSponsors.ts +!.tools/mergeTranslations.ts !.tools/docker-compose.yml !.tools/dockerfile \ No newline at end of file diff --git a/.tools/createDocs.js b/.tools/createDocs.js deleted file mode 100644 index efb5a05..0000000 --- a/.tools/createDocs.js +++ /dev/null @@ -1,328 +0,0 @@ -//@ts-check -const fs = require("fs") - -/*////// OT DOCS GENERATOR //////// -What does this file do?: -Well, this file will parse the result returned from typedoc (the documentation generator). -The resulting file will then be used in the OT Docs markdown generator to generate the Open Ticket API Reference. - -In short: -This file generates the documentation for Open Ticket :) - -Contributing: -If you want to contribute to the Open Ticket Docs, please run the following command: - -> npm run docs - -This will give you a "result.json" file which can then be used in the OT Docs. -Further instructions can be found there. -/////////////////////////////////*/ - -if (!fs.existsSync(".docs/typedoc-result.json")){ - console.log("Unable to generate documentation! Run typedoc first!") - process.exit(1) -} -const result = JSON.parse(fs.readFileSync(".docs/typedoc-result.json").toString()) -const availableElements = [] -const skipElementNames = [ - "#opendiscord-types" -] - -const handleFunction = (memberType) => { - if (!memberType || !memberType.signatures || !Array.isArray(memberType.signatures)) return {type:"unknown"} - - //try to get signature - let signature = memberType.signatures.find((s) => !s.typeParameters) - if (!signature) signature = memberType.signatures[0] - if (!signature) return {type:"unknown"} - - //try to get comment - let comment = signature.comment - if (!comment) comment = memberType.signatures.find((s) => s.comment)?.comment - if (!comment) comment = null - - const signatureInherited = signature.flags.isInherited ? true : false - const signatureComment = comment ? comment.summary?.map((c) => c.text).join("") : null - const signatureParameters = signature.parameters?.map((p) => { - return {name:p.name,details:handleType(p.type)} - }) ?? [] - const signatureReturns = handleType(signature.type) - - return {type:"function",inherited:signatureInherited,comment:signatureComment,parameters:signatureParameters,returns:signatureReturns} -} - -const handleObject = (memberType) => { - if (!memberType || !memberType.children || !Array.isArray(memberType.children)) return {type:"unknown"} - const propertyIds = memberType.groups?.find((g) => g.title == "Properties")?.children ?? [] - const methodIds = memberType.groups?.find((g) => g.title == "Methods")?.children ?? [] - - const objectChildren = [] - for (const member of (memberType.children ?? [])){ - const memberName = member.name - const memberType = propertyIds.includes(member.id) ? "property" : methodIds.includes(member.id) ? "method" : "other" - let memberComment = member.comment?.summary?.map((c) => c.text).join("") ?? null - - const rawMemberSource = member.sources ? (member.sources[0] ?? null) : null - let memberSource = rawMemberSource ? rawMemberSource.fileName+":"+rawMemberSource.line+":"+rawMemberSource.character : null - - let memberDetails = null - if (memberType == "property"){ - //INTERFACE => PROPERTY - memberDetails = handleType(member.type) - }else if (memberType == "method"){ - //INTERFACE => METHOD - memberDetails = handleFunction(member) - memberComment = memberDetails.comment - } - - objectChildren.push({ - type:memberType, - name:memberName, - comment:memberComment, - source:memberSource, - details:memberDetails - }) - } - return {type:"object",children:objectChildren} -} - -const handleType = (memberType) => { - if (!memberType || !memberType.type) return {type:"unknown"} - else if (memberType.type == "intrinsic") return {type:"primitive",name:memberType.name} - else if (memberType.type == "array") return {type:"array",child:handleType(memberType.elementType)} - else if (memberType.type == "union") return {type:"union",children:memberType.types.map((t) => handleType(t))} - else if (memberType.type == "intersection") return {type:"intersection",children:memberType.types.map((t) => handleType(t))} - else if (memberType.type == "reference"){ - const referenceTypeArguments = (memberType.typeArguments) ? memberType.typeArguments.map((ta) => handleType(ta)) : null - let referenceType = availableElements.find((el) => el.name == memberType.name)?.type ?? null - - if (referenceType){ - //member is known type (from Open Ticket) - return {type:"reference",name:memberType.name,target:referenceType,typeArguments:referenceTypeArguments} - }else if (memberType.package){ - //member is type from node.js or another package - if (memberType.package == "typescript") return {type:"internal",name:memberType.name,typeArguments:referenceTypeArguments} - if (memberType.package == "open-ticket" && memberType.refersToTypeParameter) return {type:"typeParam",name:memberType.name,typeArguments:referenceTypeArguments} - else return {type:"external",package:memberType.package,name:memberType.name,typeArguments:referenceTypeArguments} - }else return {type:"unknown"} - } - else if (memberType.type == "literal") return {type:"literal",name:(typeof memberType.value == "string") ? JSON.stringify(memberType.value) : String(memberType.value)} - else if (memberType.type == "typeOperator"){ - if (memberType.operator == "keyof") return {type:"keyof",child:handleType(memberType.target)} - else if (memberType.operator == "readonly") return {type:"readonly",child:handleType(memberType.target)} - else if (memberType.operator == "unique") return {type:"unique",child:handleType(memberType.target)} - } - else if (memberType.type == "conditional") return {type:"conditional",checker:handleType(memberType.checkType),extends:handleType(memberType.extendsType),trueValue:handleType(memberType.trueType),falseValue:handleType(memberType.falseType)} - else if (memberType.type == "indexedAccess") return {type:"index",index:handleType(memberType.indexType),object:handleType(memberType.objectType)} - else if (memberType.type == "mapped") return {type:"mapped",parameterName:memberType.parameter,parameter:handleType(memberType.parameterType),template:handleType(memberType.templateType)} - else if (memberType.type == "optional") return {type:"optional",child:handleType(memberType.elementType)} - else if (memberType.type == "predicate") return {type:"predicate",name:memberType.name,target:handleType(memberType.targetType)} - else if (memberType.type == "query") return {type:"query",target:handleType(memberType.queryType)} - else if (memberType.type == "rest") return {type:"rest",child:handleType(memberType.elementType)} - else if (memberType.type == "tuple") return {type:"tuple",children:memberType.elements.map((t) => handleType(t))} - else if (memberType.type == "templateLiteral") return {type:"template",head:memberType.head,tails:memberType.tail.map((t) => { - return {element:handleType(t[0]),text:t[1]} - })} - else if (memberType.type == "reflection" && memberType.declaration && memberType.declaration.signatures && memberType.declaration.signatures[0]){ - return handleFunction(memberType.declaration) - } - else if (memberType.type == "reflection"){ - return handleObject(memberType.declaration) - } - else return {type:"unknown"} -} - -for (const file of result.children){ - const classIds = file.groups?.find((g) => g.title == "Classes")?.children ?? [] - const interfaceIds = file.groups?.find((g) => g.title == "Interfaces")?.children ?? [] - const typeIds = file.groups?.find((g) => g.title == "Type Aliases")?.children ?? [] - const enumIds = file.groups?.find((g) => g.title == "Enumerations")?.children ?? [] - const varIds = file.groups?.find((g) => g.title == "Variables")?.children ?? [] - const funcIds = file.groups?.find((g) => g.title == "Functions")?.children ?? [] - - for (const declaration of file.children){ - const declarationName = declaration.name - const declarationType = classIds.includes(declaration.id) ? "class" : interfaceIds.includes(declaration.id) ? "interface" : typeIds.includes(declaration.id) ? "type" : enumIds.includes(declaration.id) ? "enum" : varIds.includes(declaration.id) ? "variable" : funcIds.includes(declaration.id) ? "function" : "other" - availableElements.push({name:declarationName,type:declarationType}) - } -} - -const exported = [] -for (const file of result.children){ - const classIds = file.groups?.find((g) => g.title == "Classes")?.children ?? [] - const interfaceIds = file.groups?.find((g) => g.title == "Interfaces")?.children ?? [] - const typeIds = file.groups?.find((g) => g.title == "Type Aliases")?.children ?? [] - const enumIds = file.groups?.find((g) => g.title == "Enumerations")?.children ?? [] - const varIds = file.groups?.find((g) => g.title == "Variables")?.children ?? [] - const funcIds = file.groups?.find((g) => g.title == "Functions")?.children ?? [] - - for (const declaration of (file.children ?? [])){ - const declarationName = declaration.name - if (skipElementNames.includes(declarationName)) continue - - const declarationType = classIds.includes(declaration.id) ? "class" : interfaceIds.includes(declaration.id) ? "interface" : typeIds.includes(declaration.id) ? "type" : enumIds.includes(declaration.id) ? "enum" : varIds.includes(declaration.id) ? "variable" : funcIds.includes(declaration.id) ? "function" : "other" - const declarationTypeParams = (declaration.typeParameters) ? declaration.typeParameters.map((tp) => { - return {name:tp.name,type:handleType(tp.type)} - }) : null - const declarationComment = declaration.comment?.summary?.map((c) => c.text).join("") ?? null - const declarationConstant = declaration.flags.isConst ? true : false - - const rawDeclarationSource = declaration.sources ? (declaration.sources[0] ?? null) : null - const declarationSource = rawDeclarationSource ? rawDeclarationSource.fileName+":"+rawDeclarationSource.line+":"+rawDeclarationSource.character : null - - const declarationChildren = [] - if (declarationType == "class"){ - //CLASS - const constructorIds = declaration.groups?.find((g) => g.title == "Constructors")?.children ?? [] - const propertyIds = declaration.groups?.find((g) => g.title == "Properties")?.children ?? [] - const methodIds = declaration.groups?.find((g) => g.title == "Methods")?.children ?? [] - - for (const member of (declaration.children ?? [])){ - const memberName = member.name - const memberType = constructorIds.includes(member.id) ? "constructor" : propertyIds.includes(member.id) ? "property" : methodIds.includes(member.id) ? "method" : "other" - let memberComment = member.comment?.summary?.map((c) => c.text).join("") ?? null - - const rawMemberSource = member.sources ? (member.sources[0] ?? null) : null - let memberSource = rawMemberSource ? rawMemberSource.fileName+":"+rawMemberSource.line+":"+rawMemberSource.character : null - - const memberInherited = member.flags.isInherited ? true : false - const memberStatic = member.flags.isStatic ? true : false - const memberProtected = member.flags.isProtected ? true : false - const memberOptional = member.flags.isOptional ? true : false - const memberReadonly = member.flags.isReadonly ? true : false - - let memberDetails = null - if (memberType == "property"){ - //CLASS => PROPERTY - memberDetails = handleType(member.type) - - }else if (memberType == "method"){ - //CLASS => METHOD - memberDetails = handleFunction(member) - memberComment = memberDetails.comment - - }else if (memberType == "constructor"){ - //CLASS => CONSTRUCTOR - memberDetails = handleFunction(member) - memberComment = memberDetails.comment - } - - declarationChildren.push({ - type:memberType, - name:memberName, - comment:memberComment, - source:memberSource, - details:memberDetails, - inherited:memberInherited, - static:memberStatic, - protected:memberProtected, - optional:memberOptional, - readonly:memberReadonly - }) - } - }else if (declarationType == "interface"){ - //INTERFACE - const propertyIds = declaration.groups?.find((g) => g.title == "Properties")?.children ?? [] - const methodIds = declaration.groups?.find((g) => g.title == "Methods")?.children ?? [] - - for (const member of (declaration.children ?? [])){ - const memberName = member.name - const memberType = propertyIds.includes(member.id) ? "property" : methodIds.includes(member.id) ? "method" : "other" - let memberComment = member.comment?.summary?.map((c) => c.text).join("") ?? null - - const rawMemberSource = member.sources ? (member.sources[0] ?? null) : null - let memberSource = rawMemberSource ? rawMemberSource.fileName+":"+rawMemberSource.line+":"+rawMemberSource.character : null - - const memberInherited = member.flags.isInherited ? true : false - const memberStatic = member.flags.isStatic ? true : false - const memberProtected = member.flags.isProtected ? true : false - const memberOptional = member.flags.isOptional ? true : false - const memberReadonly = member.flags.isReadonly ? true : false - - let memberDetails = null - if (memberType == "property"){ - //INTERFACE => PROPERTY - memberDetails = handleType(member.type) - }else if (memberType == "method"){ - //INTERFACE => METHOD - memberDetails = handleFunction(member) - memberComment = memberDetails.comment - } - - declarationChildren.push({ - type:memberType, - name:memberName, - comment:memberComment, - source:memberSource, - details:memberDetails, - inherited:memberInherited, - static:memberStatic, - protected:memberProtected, - optional:memberOptional, - readonly:memberReadonly - }) - } - }else if (declarationType == "type"){ - //TYPE - declarationChildren.push(handleType(declaration.type)) - }else if (declarationType == "enum"){ - //ENUM - const enumerableIds = declaration.groups?.find((g) => g.title == "Enumeration Members")?.children ?? [] - - for (const member of (declaration.children ?? [])){ - const memberName = member.name - const memberType = enumerableIds.includes(member.id) ? "enumerable" : "other" - const memberComment = member.comment?.summary?.map((c) => c.text).join("") ?? null - - const rawMemberSource = member.sources ? (member.sources[0] ?? null) : null - let memberSource = rawMemberSource ? rawMemberSource.fileName+":"+rawMemberSource.line+":"+rawMemberSource.character : null - - let memberDetails = null - if (memberType == "enumerable"){ - //ENUM => ENUMERABLE - memberDetails = handleType(member.type) - } - - const memberInherited = member.flags.isInherited ? true : false - const memberStatic = member.flags.isStatic ? true : false - const memberProtected = member.flags.isProtected ? true : false - const memberOptional = member.flags.isOptional ? true : false - const memberReadonly = member.flags.isReadonly ? true : false - - declarationChildren.push({ - type:memberType, - name:memberName, - comment:memberComment, - source:memberSource, - details:memberDetails, - inherited:memberInherited, - static:memberStatic, - protected:memberProtected, - optional:memberOptional, - readonly:memberReadonly - }) - } - }else if (declarationType == "variable"){ - //VARIABLE - declarationChildren.push(handleType(declaration.type)) - - }else if (declarationType == "function"){ - //FUNCTION - declarationChildren.push(handleFunction(declaration)) - - } - - exported.push({ - type:declarationType, - name:declarationName, - comment:declarationComment, - constant:declarationConstant, - source:declarationSource, - children:declarationChildren, - typeParams:declarationTypeParams - }) - } -} - -fs.writeFileSync(".docs/result.json",JSON.stringify(exported,null,"\t")) -fs.rmSync(".docs/typedoc-result.json") \ No newline at end of file diff --git a/.tools/createSponsors.ts b/.tools/createSponsors.ts new file mode 100644 index 0000000..6b2d496 --- /dev/null +++ b/.tools/createSponsors.ts @@ -0,0 +1,131 @@ +import fs from "fs" +import path from "path" +import crypto from "crypto" + +const sponsorData: {sponsors:Sponsor[],sections:Section[]} = JSON.parse(fs.readFileSync(path.join(process.cwd(),"./.github/SPONSORS.json")).toString()) + +//CONSTANTS +const CORNER_RADIUS = 10 +const SPACE_MULTIPLIER = 1.2 +const SVG_WIDTH = 1000 + +//TYPES +interface Sponsor { + name:string, + pictureUrl:string, + profileUrl:string, + sectionId:string +} +interface Section { + name:string, + id:string, + pfpSize:number, + pfpColumns:number, + withNames:boolean +} + + +//FUNCTIONS +async function downloadPfpToBase64URL(url:string){ + const res = await fetch(url,{method:"GET"}) + if (!res.ok) return null + const buffer = Buffer.from(await res.arrayBuffer()) + console.log("Downloaded picture URL:",url) + return "data:image/png;base64,"+buffer.toString("base64") +} + +function createTitle(yPos:number,name:string){ + return `` +} + +async function createPfp(yPos:number,xPos:number,size:number,sponsor:Sponsor,withNames:boolean){ + const randomId = crypto.randomBytes(8).toString("hex") + const nameElement = (withNames) ? `${sponsor.name}` : "" + + return (``) +} + +async function generateSection(yPos:number,section:Section,sponsors:Sponsor[]){ + let sectionHtml: string = "" + sectionHtml += createTitle(yPos,section.name) + const nameOffset = (section.withNames) ? 20 : 0 + + //divide sponsors in rows + const groupedSponsors: Sponsor[][] = [] + let currentGroup: Sponsor[] = [] + for (const sponsor of sponsors){ + currentGroup.push(sponsor) + if (currentGroup.length == section.pfpColumns){ + groupedSponsors.push(currentGroup) + currentGroup = [] + } + } + if (currentGroup.length > 0) groupedSponsors.push(currentGroup) + + let y = 0 + for (const sponsorGroup of groupedSponsors){ + const xOffset = Math.round((SVG_WIDTH - (sponsorGroup.length * section.pfpSize * SPACE_MULTIPLIER))/2) + let x = 0 + for (const sponsor of sponsorGroup){ + const pfpYPos = 40 + yPos + (y * ((section.pfpSize * SPACE_MULTIPLIER) + nameOffset)) + const pfpXPos = xOffset + (x * section.pfpSize * SPACE_MULTIPLIER) + sectionHtml += await createPfp(pfpYPos,pfpXPos,section.pfpSize,sponsor,section.withNames) + x++ + } + y++ + } + + let sectionHeight: number = 40 + (y * ((section.pfpSize * SPACE_MULTIPLIER) + nameOffset)) + return {sectionHtml,sectionHeight} +} + +async function generateSections(sections:Section[],sponsors:Sponsor[]){ + let finalHeight: number = 10 + let finalHtml: string = "" + for (const section of sections){ + const sectionSponsors = sponsors.filter((s) => s.sectionId === section.id) + if (sectionSponsors.length < 1) continue + const {sectionHtml,sectionHeight} = await generateSection(finalHeight,section,sectionSponsors) + + finalHeight += sectionHeight + finalHtml += sectionHtml + } + + finalHeight += 10 + return {finalHeight,finalHtml} +} + +function generateFinalHtml(sectionsHtml:string,sectionHeight:number){ + return (` + + + ${sectionsHtml} + `) +} + +//GENERATE SPONSORS SVG +async function main(){ + const {finalHeight,finalHtml} = await generateSections(sponsorData.sections,sponsorData.sponsors) + fs.writeFileSync(path.join(process.cwd(),"./.github/SPONSORS.svg"),generateFinalHtml(finalHtml,finalHeight)) +} +main() \ No newline at end of file diff --git a/.tools/mergeTranslations.js b/.tools/mergeTranslations.ts similarity index 99% rename from .tools/mergeTranslations.js rename to .tools/mergeTranslations.ts index d789c9e..5f9db7f 100644 --- a/.tools/mergeTranslations.js +++ b/.tools/mergeTranslations.ts @@ -1,6 +1,7 @@ -//@ts-check -const fjs = require("formatted-json-stringify") -const fs = require("fs") + +import fjs from "formatted-json-stringify" +import fs from "fs" + const formatter = new fjs.ObjectFormatter(null,true,[ new fjs.ObjectFormatter("_TRANSLATION",true,[ new fjs.PropertyFormatter("otversion"), diff --git a/.tools/typedoc-config.json b/.tools/typedoc-config.json deleted file mode 100644 index 61e64f7..0000000 --- a/.tools/typedoc-config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": [ - "../src/core/api/modules/", - "../src/core/api/defaults/", - "../src/core/api/openticket/", - "../src/core/api/main.ts", - "../src/core/startup/init.ts", - ], - "entryPointStrategy": "expand", - "json": "./typedoc-result.json", - "basePath": "../" -} \ No newline at end of file diff --git a/README.md b/README.md index 16c90c3..23f147a 100644 --- a/README.md +++ b/README.md @@ -8,104 +8,110 @@ Open Ticket Documentation Open Ticket License Open Ticket Stars -
Sponsor DJj123dj Open Ticket supports Docker! -Open Ticket supports Pterodactyl Eggs! +Open Ticket supports Pterodactyl Eggs!

-Open Ticket is the most advanced and customizable Discord ticket bot available. With 350+ configurable settings, you have full control over every aspect of your ticket system! -From HTML transcripts and Advanced Plugins to Claiming & Pinning, Questions & Modals, Detailed Statistics, and much more.

-The bot is fully translated into 37+ languages and has been battle-tested in large Discord servers.
+Open Ticket is the most advanced and customizable Discord ticket bot available right now. With 350+ configurable settings, you have full control over almost every aspect of your ticket system! +From HTML transcripts and Advanced Plugins to Claiming & Pinning, Modal Questions & Limits, Detailed Statistics, and much more.

+The bot is fully translated into 38+ languages and has been battle-tested in large Discord servers.
Need help or want to get involved? Feel free to join our Discord server.

โญ๏ธ Support Open Ticketโ€™s growth by starring this repo! โญ๏ธ

-

โค๏ธ Love Open Ticket? Sponsorships help fuel our HTML transcript servers and future features! โค๏ธ

+

โค๏ธ Love Open Ticket? Sponsorships help fuel our HTML transcript servers and future features! โค๏ธ
+Open Ticket +

--- -> **[-> Navigate to (โฑ๏ธ Quick Setup)](#๏ธ-quick-start-using-interactive-cli-tool)** -> **[-> Navigate to (๐Ÿ“š Documentation)](https://otdocs.dj-dj.be)** -> **[-> Navigate to (๐Ÿ“ž Support Server)](https://discord.dj-dj.be)** - -### ๐Ÿ“Œ Features -- **โณ Quick Setup** - Using the interactive Quick Setup CLI, you can **configure Open Ticket in less than 5min!** -- **๐Ÿฆ‡ Pterodactyl Support** - Open Ticket works perfect on Pterodactyl based panels. [(Download official eggs)](.eggs/README.md) -- **๐Ÿ’ฉ No Credits** - Your bot won't contain any form of bloat or credits. It's all yours! -- **๐Ÿ”’ Private & Secure** - It has been battletested by thousands of servers and **respects security & privacy.** -- **๐Ÿ“ˆ Scalable** - Made to handle huge servers and has already been **tested in servers with 100k members.** -- **๐Ÿ“„ HTML Transcripts** - The **built-in HTML Transcripts Service** provides beautiful & easy-to-use transcripts. -- **โœ… Ticket Status** - Close, reopen, delete, claim, pin, rename or move tickets in your server. -- **๐Ÿ‡ฌ๐Ÿ‡ง Translation** - Every message has been translated in more than **37 languages** by our community. -- **๐ŸŽจ Customisation** - More than **200+ settings** are related to customisation & advanced features. -- **๐Ÿ–ฅ๏ธ Interactions** - The bot has full support for buttons, dropdowns, slash/text commands & modals. -- **โˆž Unlimited Possibilities** - Create an infinite amount of tickets, questions & panels. -- **๐Ÿ“ Advanced Plugins** - Create advanced plugins or use [**pre-made plugins**](#-plugins) by our community. -- **๐Ÿ‘ฅ Participants** - Add or remove participants & transfer ownership from one user to another. -- **๐Ÿ“Š Detailed Statistics** - With more than **50+ statistics** for tickets, users & the server. -- **๐Ÿšซ Blacklist** - Blacklist users to prevent them from creating new tickets. -- **๐Ÿšจ Priorities** - Assign different **priority levels** to tickets to mark them as important. -- **โ“ Modal Questions** - Give users the ability to **answer questions** in a modal before their ticket is created. -- **โœจ Commands** - Manage all your tickets with more than 28+ commands. -- **๐Ÿค– Automation** - Automate ticket handling with **autoclose, autodelete** & slow mode. -- **๐Ÿ˜Ž Additional Features** - For some weird reason, the bot also supports Reaction Role & URL Buttons. - -#### And even more using [pre-made community plugins](#-plugins)! - - **๐Ÿ’ฌ Reviews** - Create & manage a support review system. - - **๐Ÿ“ข Feedback** - Collect feedback & create forms for users to answer. - - **โฐ Reminders** - Create & manage customisable reminders. - - **๐Ÿท๏ธ Tags** - Create tags & answer questions automatically using keywords. - - **๐Ÿ“ Forms** - Create advanced forms and automatically ask for repetitive questions. - - **๐Ÿ”„ Channel Display** - Create a voice channel with realtime statistics from the ticket system. - - **๐Ÿ’พ SQLite Database** - Use an `SQLite` database for increased performance. - - **๐ŸŽ‰ Custom Embeds** - Create your own embeds and send them using a command. - - **๐ŸŽจ Customisation** - Yep, you heard it right. Even more customisation! - - **๐Ÿ˜ And so much more...** - -### โฑ๏ธ Quick Start (Using Interactive CLI Tool) -> 1. Download the latest version of Open Ticket on [Github](https://github.com/open-discord-bots/open-ticket). -> 2. Make sure Node.js & Npm are installed using `node -v` (minimum `v20`). -> 3. Install any required dependencies using `npm install`. -> 4. Start the **Quick Setup CLI** using `npm run setup`. -> 5. Click on `> โฑ๏ธ Quick Setup` and follow the instructions. -> 6. Start the bot using `npm start` or `node index.js` -> - If required, the bot will give a report of errors that must be solved. -> - Follow the instructions and restart the bot. -> 7. Enjoy using Open Ticket! -> -> #### ๐Ÿšฆ Navigation +> **[-> Navigate to (โฑ๏ธ Quick Setup)](#๏ธ-quick-start)** > **[-> Navigate to (๐Ÿ“š Documentation)](https://otdocs.dj-dj.be)** > **[-> Navigate to (๐Ÿ“ž Support Server)](https://discord.dj-dj.be)** -> **[-> Navigate to (๐Ÿงฉ Download Plugins)](https://odplugins.dj-dj.be)** +> **[-> Navigate to (๐Ÿงฉ Plugins/Addons)](https://odplugins.dj-dj.be)** +> **[-> Navigate to (๐Ÿฆ‡ Pterodactyl Eggs)](.github/pterodactyl-eggs/README.md)** + +### ๐Ÿ“Œ Features +#### Core Features +- **Ticket Management** - Close, reopen, delete, claim or pin tickets with ease. +- **Powerful Commands** - Manage your support system with **30+ commands** for staff & users. +- **Modal Questions** - Ask users **custom questions** before a ticket is created. +- **Priorities** - Assign **priority levels** to tickets to highlight urgent requests. +- **Participants** - Add or remove participants & transfer ownership from one user to another. +- **Adjustments** - Rename tickets, change ticket types or transfer ownership. +- **Blacklist & Limits** - Prevent users from creating tickets and set per-user or global ticket limits. +- **Highly Customisable** - Configure **350+ settings** covering appearance and behaviour. + +#### Ticket Automation & Workflows +- **Unlimited Possibilities** - Create unlimited tickets, panels & question flows. +- **Autoclose Tickets** - Automatically **close tickets** after predefined conditions. +- **Autodelete Tickets** - Automatically **delete closed tickets** to keep channels clean. +- **Category Routing** - Move tickets between categories based on claim or close state. + +#### Transcripts & Insights +- **HTML Transcripts** - Generate beautiful, easy-to-read **HTML transcripts** for every ticket. +- **Detailed Statistics** - Track **50+ statistics** for tickets, users and server activity. +- **Ticket Logs** - Track **all ticket events** such as creation, closures, and staff actions. + +#### User Experience +- **Fully Translated** - Available in **38+ languages**, translated and maintained by the community. +- **Modern Interactions** - Full support for buttons, dropdowns, slash/text commands & modals. +- **Panels** - Create messages with buttons or a dropdown for users to open tickets. +- **Sub-Panels** - One panel not enough? Use multiple panels to offer more choices. + +#### Plugins & Ecosystem +- **Plugin System** - Use custom plugins to **add new features** or **modify existing behavior** of the bot. +- **Community Plugins** - Use and share plugins built by the community. +- **Advanced API** - Build advanced plugins with access to ticket events and internal systems. +- **Integrations** - Connect Open Ticket with external services to automate workflows across platforms. +- **Bonus Features** - Somehow, we included Reaction Roles and URL Button support as well. + +#### Deployment +- **Quick Setup** - Easy **5-minute configuration** using the Interactive Setup CLI. +- **Scalable & Reliable** - Battle-tested in servers with **100k+ members**. +- **Private & Secure** - Used by thousands of servers with respect for security & privacy. +- **Pterodactyl Support** - 100% compatible with Pterodactyl panels. [(Download official eggs)](.eggs/README.md) +- **Docker Support** - Deploy Open Ticket in minutes with Docker containers. + +#### Extend functionality even more with our [pre-made community plugins](#-plugins)! +> - **Reviews** - Create and manage a support review system for tickets. +> - **Tags** - Define keywords that automatically trigger predefined responses. +> - **Reminders** - Create and manage custom reminders for users or staff. +> - **AI Integrations** - Connect to AI providers such as ChatGPT, Claude, or Gemini. +> - **Channel Display** - Create voice channels that display real-time ticket system statistics. +> - **Forms** - Build advanced forms for collecting structured information from users. +> - **Custom Embeds** - Create and send custom embeds via commands. +> - **Customization Tools** - Additional configuration options for advanced behavior and styling. +> - **Web Dashboard** - Configure and manage the bot through a remote web dashboard. +> - **Feedback** - Collect user feedback after ticket deletion using forms. +> - **SQLite Database** - Use an SQLite backend for improved performance and lightweight storage. +> - **And more** - Additional community plugins are available and actively expanding. + +## โฑ๏ธ Quick Start +> 1. Download the [latest version of Open Ticket](https://github.com/open-discord-bots/open-ticket/releases/latest). +> 2. Make sure you have installed Node.js on your system (check using `node -v`, minimum `v20`). +> 3. Install any required dependencies using `npm install`. +> 4. Configure the bot in one of the following ways: +> - Method 1 (Easy): Start the **Quick Setup CLI** using `npm run setup`. +> - Method 2 (Hard): Manual **JSON configuration** in `./config/...` +> 5. If using the **Quick Setup CLI**, click on `> โฑ๏ธ Quick Setup` and follow the instructions. +> 6. Start the bot using `npm start` or `node index.js` +> - If any config errors occur, the bot will give you a report of how to solve them. +> - Follow the instructions and restart the bot. +> 7. Enjoy using Open Ticket! +> 8. Install plugins from the [**Official Plugin Repository**](https://github.com/open-discord-bots/plugins) +> +> #### ๐Ÿšฆ Next Steps +> **[-> Navigate to (๐Ÿ“š Documentation)](https://otdocs.dj-dj.be)** +> **[-> Navigate to (๐Ÿ“ž Support Server)](https://discord.dj-dj.be)** +> **[-> Navigate to (๐Ÿงฉ Plugins/Addons)](https://odplugins.dj-dj.be)** +> **[-> Navigate to (๐Ÿฆ‡ Pterodactyl Eggs)](.github/pterodactyl-eggs/README.md)** > > #### ๐Ÿ–ฅ๏ธ Recommended Hosting > - **A VPS (Virtual Private Server)** - Extra customisation & more stability. Recommended for most servers. > - **Any Pterodactyl-Based Panel** - Easy installation & configuration. -### โค๏ธ Sponsors -Huge thanks to our sponsors for making this project possible. Your support means everything to us. - - - - - - - - - - - -
Profile PictureProfile PictureProfile Picture
guillee3yeeetSKjacobhumston
- -**Past Sponsors:**
- -SpyEye -Mods HD -DOSEV5 -BENZORICH - - ## ๐Ÿ“ธ Preview An example of a panel. An example of a ticket message. @@ -134,14 +140,14 @@ A list of amazing people who have contributed or provided supported for **Open T ### ๐Ÿ’ฌ Translators -With the amazing support of our translators, we've been able to translate Open Ticket in more than **37 languages**! +With the amazing support of our translators, we've been able to translate Open Ticket in more than **38 languages**! #### Categories: - **๐ŸŸข Available** - **๐Ÿค– Partially Made Using AI** - **๐ŸŸ  Incomplete** - **๐Ÿ”ด Unavailable/Outdated** -|๐Ÿ” |Languages (37) |Maintainer (Github/Discord) | +|๐Ÿ” |Languages (38) |Maintainer (Github/Discord) | |----|---------------------|--------------------------------| |๐ŸŸข |๐Ÿ‡ฌ๐Ÿ‡ง English |djj123dj | |๐ŸŸข |๐Ÿ‡ณ๐Ÿ‡ฑ Dutch |djj123dj | @@ -168,6 +174,7 @@ With the amazing support of our translators, we've been able to translate Open T |๐ŸŸข |๐Ÿ‡ง๐Ÿ‡ฉ Bengali |HanumeshGupta | |๐ŸŸข |โ“ Catalan |guillee3 | |๐ŸŸข |๐Ÿ‡จ๐Ÿ‡ณ Traditional Chinese|me.october | +|๐ŸŸข |๐Ÿ‡ฐ๐Ÿ‡ญ Khmer (Cambodia) |yuuslokrobjakkroval | |๐Ÿค– |๐Ÿ‡ช๐Ÿ‡ช Estonian |iamnotmega | |๐Ÿค– |๐Ÿ‡ซ๐Ÿ‡ฎ Finnish |iamnotmega | |๐Ÿค– |๐Ÿ‡ฏ๐Ÿ‡ต Japanese |HanumeshGupta | diff --git a/package.json b/package.json index 92ca691..44d4d3f 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "test": "node index.js --dev-config --dev-database --soft-plugins", "testsetup": "node index.js --cli --dev-config --dev-database --soft-plugins", "testnc": "node index.js --no-compile --dev-config --dev-database --soft-plugins", - "docs": "npx typedoc --options .tools/typedoc-config.json && node .tools/createDocs.js", - "mergelang": "node .tools/mergeTranslations.js" + "tools:mergelang": "bun run .tools/mergeTranslations.js", + "tools:sponsors": "bun run .tools/createSponsors.ts" }, "type": "module", "license": "GPL-3.0-only",