Merge pull request #2 from DiscordFactory/doc-next

Doc next
This commit is contained in:
Baptiste Parmantier
2021-10-06 21:07:03 +02:00
committed by GitHub
38 changed files with 3591 additions and 2412 deletions

4
index.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
declare module 'markdown-it'
declare module 'markdown-it-container'
declare module 'markdown-it-highlightjs'
declare module 'markdown-it-emoji'

View File

@@ -15,12 +15,14 @@
"@types/vue-router": "^2.0.0",
"axios": "^0.21.1",
"luxon": "^2.0.2",
"markdown-it": "^12.2.0",
"markdown-it-vue": "^1.1.6",
"prismjs": "^1.24.1",
"reflect-metadata": "^0.1.13",
"sass": "^1.38.0",
"sass-loader": "^12.1.0",
"tailwindcss": "^2.2.7",
"typescript": "^4.3.5",
"typescript": "^4.4.3",
"vue": "^3.0.5",
"vue-prism-component": "^2.0.0",
"vue-router": "4"
@@ -28,8 +30,14 @@
"devDependencies": {
"@vitejs/plugin-vue": "^1.3.0",
"@vue/compiler-sfc": "^3.0.5",
"markdown-it-anchor": "^8.3.1",
"markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^2.0.0",
"markdown-it-highlightjs": "^3.5.0",
"markdown-it-toc-done-right": "^4.2.0",
"vite": "^2.4.4",
"vite-plugin-windicss": "^1.2.7",
"vue3-markdown-it": "^1.0.9",
"windicss": "^3.1.7"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 KiB

View File

@@ -1,20 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 300 67" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="discord-ts-app-logo.jpg" transform="matrix(0.067,0,0,0.067,0,0)">
<clipPath id="_clip1">
<path d="M0,138.415C-0,101.705 14.583,66.499 40.541,40.541C66.499,14.583 101.705,-0 138.415,0C329.163,0 670.837,0 861.585,0C898.295,-0 933.501,14.583 959.459,40.541C985.417,66.499 1000,101.705 1000,138.415C1000,329.163 1000,670.837 1000,861.585C1000,898.295 985.417,933.501 959.459,959.459C933.501,985.417 898.295,1000 861.585,1000C670.837,1000 329.163,1000 138.415,1000C101.705,1000 66.499,985.417 40.541,959.459C14.583,933.501 -0,898.295 -0,861.585L0,138.415Z"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g transform="matrix(14.9254,-0,-0,14.9254,0,0)">
<use xlink:href="#_Image2" x="0" y="0" width="67px" height="67px"/>
<svg width="100%" height="100%" viewBox="0 0 5000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(28.0584,0,0,28.0584,-2.27374e-13,-24.9434)">
<path d="M0,18.709C0,33.081 3.448,36.529 17.82,36.529C32.192,36.529 35.64,33.081 35.64,18.709C35.64,4.337 32.192,0.889 17.82,0.889C3.448,0.889 0,4.337 0,18.709Z" style="fill:rgb(0,56,111);"/>
<g>
<g>
<clipPath id="_clip1">
<path d="M0,18.709C0,33.081 3.448,36.529 17.82,36.529C32.192,36.529 35.64,33.081 35.64,18.709C35.64,4.337 32.192,0.889 17.82,0.889C3.448,0.889 0,4.337 0,18.709Z"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g transform="matrix(0.03564,0,0,0.03564,8.1036e-15,0.888982)">
<path d="M686.631,208.399L1000,357L1000,1000L308,1000L199.539,575.081L304,368L572.161,303.562L686.631,208.399Z" style="fill:rgb(0,42,84);"/>
</g>
</g>
</g>
</g>
<g transform="matrix(0.310218,0,0,0.310218,7.01897,4.50168)">
<path d="M60.105,13.898C55.579,11.821 50.727,10.292 45.653,9.415C45.56,9.399 45.468,9.441 45.42,9.525C44.796,10.635 44.105,12.083 43.621,13.222C38.164,12.405 32.734,12.405 27.389,13.222C26.905,12.058 26.189,10.635 25.562,9.525C25.514,9.444 25.422,9.401 25.329,9.415C20.258,10.289 15.406,11.819 10.878,13.898C10.838,13.915 10.805,13.943 10.783,13.98C1.578,27.731 -0.944,41.144 0.293,54.391C0.299,54.456 0.335,54.518 0.386,54.558C6.459,59.017 12.341,61.725 18.115,63.52C18.207,63.548 18.305,63.514 18.364,63.438C19.73,61.573 20.947,59.606 21.991,57.538C22.052,57.417 21.994,57.274 21.868,57.226C19.937,56.493 18.098,55.6 16.329,54.586C16.189,54.504 16.178,54.304 16.307,54.208C16.679,53.929 17.051,53.639 17.407,53.346C17.471,53.293 17.561,53.281 17.636,53.315C29.256,58.62 41.835,58.62 53.318,53.315C53.394,53.279 53.483,53.29 53.55,53.343C53.906,53.636 54.278,53.929 54.653,54.208C54.782,54.304 54.773,54.504 54.633,54.586C52.865,55.62 51.026,56.493 49.092,57.223C48.966,57.271 48.91,57.417 48.972,57.538C50.038,59.603 51.255,61.57 52.596,63.435C52.652,63.514 52.753,63.548 52.845,63.52C58.646,61.725 64.529,59.017 70.602,54.558C70.655,54.518 70.689,54.459 70.694,54.394C72.175,39.079 68.215,25.776 60.197,13.982C60.177,13.943 60.144,13.915 60.105,13.898ZM23.726,46.325C20.228,46.325 17.345,43.114 17.345,39.169C17.345,35.225 20.172,32.013 23.726,32.013C27.308,32.013 30.163,35.253 30.107,39.169C30.107,43.114 27.28,46.325 23.726,46.325ZM47.318,46.325C43.82,46.325 40.937,43.114 40.937,39.169C40.937,35.225 43.764,32.013 47.318,32.013C50.9,32.013 53.755,35.253 53.699,39.169C53.699,43.114 50.9,46.325 47.318,46.325Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.03564,0,0,0.03564,0.211622,1.67679)">
<g>
<g transform="matrix(1,0,0,1,136,793)">
<g transform="matrix(164.733,0,0,164.733,0,0)">
<path d="M0.491,-0.291L0.21,-0.291L0.21,-0L0.063,-0L0.063,-0.711L0.526,-0.711L0.526,-0.592L0.21,-0.592L0.21,-0.409L0.491,-0.409L0.491,-0.291Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</g>
<g transform="matrix(1,0,0,1,210.806,793)">
<g>
<g transform="matrix(164.733,0,0,164.733,0,0)">
<path d="M0.465,-0.146L0.208,-0.146L0.159,-0L0.003,-0L0.268,-0.711L0.404,-0.711L0.67,-0L0.514,-0L0.465,-0.146ZM0.248,-0.265L0.425,-0.265L0.336,-0.531L0.248,-0.265Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,109.152,0)">
<g transform="matrix(164.733,0,0,164.733,0,0)">
<path d="M0.622,-0.237C0.616,-0.16 0.588,-0.1 0.537,-0.056C0.486,-0.012 0.419,0.01 0.335,0.01C0.244,0.01 0.173,-0.021 0.12,-0.082C0.068,-0.144 0.042,-0.228 0.042,-0.335L0.042,-0.378C0.042,-0.447 0.054,-0.507 0.078,-0.559C0.102,-0.611 0.137,-0.651 0.181,-0.679C0.226,-0.707 0.278,-0.721 0.337,-0.721C0.419,-0.721 0.486,-0.699 0.536,-0.655C0.586,-0.611 0.615,-0.549 0.623,-0.47L0.476,-0.47C0.472,-0.516 0.46,-0.549 0.438,-0.57C0.416,-0.59 0.382,-0.601 0.337,-0.601C0.289,-0.601 0.252,-0.583 0.228,-0.548C0.204,-0.513 0.191,-0.459 0.19,-0.385L0.19,-0.332C0.19,-0.255 0.202,-0.199 0.225,-0.163C0.249,-0.128 0.285,-0.11 0.335,-0.11C0.381,-0.11 0.414,-0.12 0.437,-0.141C0.459,-0.162 0.472,-0.194 0.475,-0.237L0.622,-0.237Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(164.733,0,0,164.733,105.452,0)">
<path d="M0.599,-0.592L0.381,-0.592L0.381,-0L0.234,-0L0.234,-0.592L0.02,-0.592L0.02,-0.711L0.599,-0.711L0.599,-0.592Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(164.733,0,0,164.733,205.112,0)">
<path d="M0.647,-0.339C0.647,-0.269 0.635,-0.208 0.61,-0.155C0.586,-0.103 0.55,-0.062 0.504,-0.033C0.458,-0.005 0.405,0.01 0.346,0.01C0.287,0.01 0.234,-0.004 0.188,-0.033C0.142,-0.061 0.106,-0.101 0.081,-0.154C0.055,-0.207 0.042,-0.267 0.042,-0.335L0.042,-0.371C0.042,-0.441 0.055,-0.502 0.08,-0.555C0.105,-0.609 0.141,-0.649 0.187,-0.678C0.233,-0.706 0.285,-0.721 0.345,-0.721C0.404,-0.721 0.457,-0.706 0.503,-0.678C0.549,-0.649 0.584,-0.609 0.61,-0.555C0.635,-0.502 0.647,-0.441 0.647,-0.371L0.647,-0.339ZM0.499,-0.372C0.499,-0.446 0.486,-0.503 0.459,-0.542C0.432,-0.58 0.394,-0.6 0.345,-0.6C0.296,-0.6 0.258,-0.58 0.231,-0.542C0.204,-0.504 0.191,-0.448 0.19,-0.374L0.19,-0.339C0.19,-0.267 0.204,-0.21 0.23,-0.17C0.257,-0.13 0.296,-0.11 0.346,-0.11C0.395,-0.11 0.433,-0.13 0.459,-0.168C0.485,-0.207 0.499,-0.263 0.499,-0.337L0.499,-0.372Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(164.733,0,0,164.733,318.848,0)">
<path d="M0.327,-0.26L0.21,-0.26L0.21,-0L0.063,-0L0.063,-0.711L0.328,-0.711C0.412,-0.711 0.476,-0.692 0.522,-0.655C0.568,-0.617 0.59,-0.564 0.59,-0.496C0.59,-0.448 0.58,-0.407 0.559,-0.375C0.538,-0.342 0.506,-0.317 0.463,-0.297L0.617,-0.007L0.617,-0L0.46,-0L0.327,-0.26ZM0.21,-0.379L0.328,-0.379C0.365,-0.379 0.393,-0.388 0.414,-0.407C0.434,-0.426 0.444,-0.451 0.444,-0.484C0.444,-0.518 0.434,-0.544 0.415,-0.563C0.396,-0.583 0.367,-0.592 0.328,-0.592L0.21,-0.592L0.21,-0.379Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(164.733,0,0,164.733,420.117,0)">
<path d="M0.309,-0.391L0.457,-0.711L0.617,-0.711L0.383,-0.258L0.383,-0L0.234,-0L0.234,-0.258L0.001,-0.711L0.162,-0.711L0.309,-0.391Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
</g>
</g>
<g transform="matrix(0.03564,0,0,0.03564,1.38996,0.0665664)">
<g>
<g transform="matrix(1,0,0,1,1059,816.714)">
<g transform="matrix(826.061,0,0,826.061,0,0)">
<path d="M0.491,-0.291L0.21,-0.291L0.21,-0L0.063,-0L0.063,-0.711L0.526,-0.711L0.526,-0.592L0.21,-0.592L0.21,-0.409L0.491,-0.409L0.491,-0.291Z" style="fill:rgb(0,56,111);fill-rule:nonzero;"/>
</g>
</g>
<g transform="matrix(1,0,0,1,1434.12,816.714)">
<g transform="matrix(826.061,0,0,826.061,0,0)">
<path d="M0.465,-0.146L0.208,-0.146L0.159,-0L0.003,-0L0.268,-0.711L0.404,-0.711L0.67,-0L0.514,-0L0.465,-0.146ZM0.248,-0.265L0.425,-0.265L0.336,-0.531L0.248,-0.265Z" style="fill:rgb(0,56,111);fill-rule:nonzero;"/>
</g>
<g transform="matrix(826.061,0,0,826.061,547.346,0)">
<path d="M0.622,-0.237C0.616,-0.16 0.588,-0.1 0.537,-0.056C0.486,-0.012 0.419,0.01 0.335,0.01C0.244,0.01 0.173,-0.021 0.12,-0.082C0.068,-0.144 0.042,-0.228 0.042,-0.335L0.042,-0.378C0.042,-0.447 0.054,-0.507 0.078,-0.559C0.102,-0.611 0.137,-0.651 0.181,-0.679C0.226,-0.707 0.278,-0.721 0.337,-0.721C0.419,-0.721 0.486,-0.699 0.536,-0.655C0.586,-0.611 0.615,-0.549 0.623,-0.47L0.476,-0.47C0.472,-0.516 0.46,-0.549 0.438,-0.57C0.416,-0.59 0.382,-0.601 0.337,-0.601C0.289,-0.601 0.252,-0.583 0.228,-0.548C0.204,-0.513 0.191,-0.459 0.19,-0.385L0.19,-0.332C0.19,-0.255 0.202,-0.199 0.225,-0.163C0.249,-0.128 0.285,-0.11 0.335,-0.11C0.381,-0.11 0.414,-0.12 0.437,-0.141C0.459,-0.162 0.472,-0.194 0.475,-0.237L0.622,-0.237Z" style="fill:rgb(0,56,111);fill-rule:nonzero;"/>
</g>
<g transform="matrix(826.061,0,0,826.061,1076.14,0)">
<path d="M0.599,-0.592L0.381,-0.592L0.381,-0L0.234,-0L0.234,-0.592L0.02,-0.592L0.02,-0.711L0.599,-0.711L0.599,-0.592Z" style="fill:rgb(0,56,111);fill-rule:nonzero;"/>
</g>
<g transform="matrix(826.061,0,0,826.061,1575.89,0)">
<path d="M0.647,-0.339C0.647,-0.269 0.635,-0.208 0.61,-0.155C0.586,-0.103 0.55,-0.062 0.504,-0.033C0.458,-0.005 0.405,0.01 0.346,0.01C0.287,0.01 0.234,-0.004 0.188,-0.033C0.142,-0.061 0.106,-0.101 0.081,-0.154C0.055,-0.207 0.042,-0.267 0.042,-0.335L0.042,-0.371C0.042,-0.441 0.055,-0.502 0.08,-0.555C0.105,-0.609 0.141,-0.649 0.187,-0.678C0.233,-0.706 0.285,-0.721 0.345,-0.721C0.404,-0.721 0.457,-0.706 0.503,-0.678C0.549,-0.649 0.584,-0.609 0.61,-0.555C0.635,-0.502 0.647,-0.441 0.647,-0.371L0.647,-0.339ZM0.499,-0.372C0.499,-0.446 0.486,-0.503 0.459,-0.542C0.432,-0.58 0.394,-0.6 0.345,-0.6C0.296,-0.6 0.258,-0.58 0.231,-0.542C0.204,-0.504 0.191,-0.448 0.19,-0.374L0.19,-0.339C0.19,-0.267 0.204,-0.21 0.23,-0.17C0.257,-0.13 0.296,-0.11 0.346,-0.11C0.395,-0.11 0.433,-0.13 0.459,-0.168C0.485,-0.207 0.499,-0.263 0.499,-0.337L0.499,-0.372Z" style="fill:rgb(0,56,111);fill-rule:nonzero;"/>
</g>
<g transform="matrix(826.061,0,0,826.061,2146.23,0)">
<path d="M0.327,-0.26L0.21,-0.26L0.21,-0L0.063,-0L0.063,-0.711L0.328,-0.711C0.412,-0.711 0.476,-0.692 0.522,-0.655C0.568,-0.617 0.59,-0.564 0.59,-0.496C0.59,-0.448 0.58,-0.407 0.559,-0.375C0.538,-0.342 0.506,-0.317 0.463,-0.297L0.617,-0.007L0.617,-0L0.46,-0L0.327,-0.26ZM0.21,-0.379L0.328,-0.379C0.365,-0.379 0.393,-0.388 0.414,-0.407C0.434,-0.426 0.444,-0.451 0.444,-0.484C0.444,-0.518 0.434,-0.544 0.415,-0.563C0.396,-0.583 0.367,-0.592 0.328,-0.592L0.21,-0.592L0.21,-0.379Z" style="fill:rgb(0,56,111);fill-rule:nonzero;"/>
</g>
<g transform="matrix(826.061,0,0,826.061,2654.04,0)">
<path d="M0.309,-0.391L0.457,-0.711L0.617,-0.711L0.383,-0.258L0.383,-0L0.234,-0L0.234,-0.258L0.001,-0.711L0.162,-0.711L0.309,-0.391Z" style="fill:rgb(0,56,111);fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
</g>
<g transform="matrix(0.767778,0,0,0.767778,22.0129,9.9378)">
<text x="72.153px" y="55px" style="font-family:'Roboto-Regular', 'Roboto';font-size:65.614px;fill:rgb(32,73,119);">F<tspan x="105.281px 150.038px 194.123px 234.683px 282.1px 323.269px " y="55px 55px 55px 55px 55px 55px ">ACTORY</tspan></text>
</g>
<defs>
<image id="_Image2" width="67px" height="67px" xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCABDAEMDAREAAhEBAxEB/8QAHQABAAIBBQEAAAAAAAAAAAAAAAYHCAEDBAUJAv/EADkQAAEDBAAEBAIIAwkAAAAAAAECAwQABQYRBxIhQQgTMVEUIhUyQmFicYGRFyM4UnJ2kqGxssTR/8QAGgEBAAIDAQAAAAAAAAAAAAAAAAQFAQIDBv/EAC8RAAICAQIEAwcEAwAAAAAAAAABAgMRBBIFITFBUZGhFCIjYXGB0RMyRMGC4fH/2gAMAwEAAhEDEQA/AKcr2B5kUAoBQCgFAKAUAoBQE44N8PJvEXJHLezIMSFFa86ZJDZWUJ3oJSO6lddAnsT21UbValUQz3O+nod0sdjJXH+DNutrSGbTBt9naGguZKjon3F0euwpweSwfUaShfTR2DVPPWyl+559F+WWcdKo9OXq/wAI5yeA2ByJq5t8+mL9JX9ZyfPVvXYDy+TQHYegrX2+1LEcL6Iz7HW3mWWfczgDwskMFtvHnYqj6ONTn+Yf5lkf6UXENQu/ojL0VL7H2/wrbZhohiXFyOChvyzEyCI265oegblNpS42e2yHNdhWFq8vPR/L8f8AB7Nyx1Xz/JT3G3gZGsuOSstxdqTFZi/PMtby/N8pO+q2nB1KBvelddbJI1qrDS69zkq5+ZD1GjUY74+Rj/VoV4oBQGZ3hLxhFj4XN3VxtIl3p5UlaijSg0klDaSe46KUP79ee4jbvu29kXWhr2158S4KgEwUAoBQGzPiRp8F+DMZQ/GkNqaebWNpWhQ0QfuIJrKbi8ow0msM87s1sb2NZbdbA+orXAlLYCynXOkH5Va+8aP616uqxWQUl3PO2Q2ScfA6iuhobkZlyRIbjtJ5nHVhCB7knQrDeFkJZPR2wW5q0WK32lg7ahRm46PyQkJH+1eSnLdJyfc9JGO2KRV3ilzm9YbhsJqwurizLlIU0ZaQCWkJTtQTv0UdjR7AHXXRE3h9EbZvd0RF1t0q4Lb3K98KfEfKrnmTmLXu6S7tDfjuPNuSnC46ytOj9c9SkjY0Seuta67lcQ01cYb4rDI+ivnKeyTyWt4kMyu2E8OFXCyKDU6VLREbfKQryeZKlFWj03pBA371C0NMbrcS6EvV2yqrzHqUv4ZOJmXyuI8TG7veJt2g3IO7EtwuraWltSwpKldQPk1reuu9VYa/S1qpzisNEHR6ibs2t5TMsqoy3MOfGHaBA4rIuKB8tygNPKP40bbI/ZCf3q/4ZPdTjwZTa+OLc+JS9WJCO/4bsokcRMbjua5HbtFQrfsXkg1yveKpP5M6VLNkfqj0Pryh6Ih2V2rEeJVnmYvdHfMcjuBTrCV+XKiOAEJXynqOhOiQUqB6bBqRXOzTyU4/6ZxnGFycGcLhXwmxfh29JlWn4uXOkJ5FSpa0qWlHQ8ieUAAbAJ6bPv0FbajV2X8pdDWnTQp5rqSbMsbtGW49JsV7j+fDkAbAVyqQoHYUk9iD/wCHYJFcarZVSUo9TrZXGyO2RDOHHCLDOG86Rfo0mS/JDRSJVwdRqOj7XLpKQN91Hrrp0BO5F+st1C2v0ONWlrpe5E/s9zh3aGJtvcL0VZ/lPBJCHR/aQT9ZPsodD22Kiyi4vDO8ZKSyjG3xwsoTPxSQNc62pSD+SS0R/wAjVvwp8pL6FbxFc4/cxvq3K01QpSFhaFFKknYIOiDQGRnCvxIrgwWLVnMV+WGgEIuUcBThHbzEEjmP4gdnuCdk1Oo4bl7qvIsadfhYs8yS8TeJPCXJ7G3JhyY82/oWlu3vrS9DdiLJOnFPAJUltOyogE79NbNcaNNqK5YfJd+jz9jrdfRNZXXyOsskjOLViv0xH472d+zJk/DfFS4pkDzeXm5OdaSreuut1vNVSntdTyaxdkY7v1OR1+OZxxWv1tuF7XxCsdmx2JLMRF0mQWkCS4OoDaCgkkjR0devuDradGng1HY3J9smsLrppy3JLxNbFdLNacuZ/i/kMXLIM1ozrPchMckw0kEoUkxh8qTsEA8mgQR6+icZSh8CO1rk138xGUYy+M8p9H28iY5h4ksKtsRaceal3yWQQ3ppTDIP4lLAV+yT+lR6uG2yfv8AI7Wa+uK93mYvZ9mF8zfIXb1fZIceUOVttA02wjshA7AfufUkmrqmmFMdsSrttlbLdIj9dTmKAUAoC1kf0ouf4u/6wqD/ADP8f7Jf8b7/ANHAwDNYMHCZOL5fjLt8xZU5L6XWXFNOxJCknXIr0JKUq+XY+12JFbXUN2b65Ylj0NarUobJrMTa4n4ZZLVjljy/E7nNmWC8FxtlucgJkR3EEhSFa6Eb5uo9u+91nT3ylKVc1zXgYuqjGKnB8mV7UsjigFAKAUAoDlOXCa5a2bWuQ4YTLq3m2d/KHFhIUrXuQlI/Stdqzu7mdzxgkOF59e8Wt0q1R2LbcbVLcDr9vuURMhhawAAvlPoeg9D2HsK5W6eFjUnyfijpXdKCwua+ZtZznF9zD4Nq5qisQoKCiHChsBmPHSdb5UD8h679KzTRCrO3q+4sulZjPYjNdjkKAUAoBQCgFAKAUAoBQCgP/9k="/>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,64 +1,74 @@
<template>
<div class="px-5 sm:px-0 flex flex-col sm:flex-row space-y-5 sm:space-y-0 sm:space-x-5">
<div class="px-5 lg:px-0 flex flex-col sm:flex-row space-y-5 sm:space-y-0 sm:space-x-5">
<div class="sm:w-1/2">
<Collapse
:items="collapseHighlighting"
@handleChange="handleChange" />
</div>
<div class="flex sm:w-1/2 bg-[#263238] rounded-lg overflow-hidden">
<transition
enter-active-class="transition ease-out duration-300"
<transition-group
enter-active-class="transition ease-out duration-100"
enter-from-class="transform opacity-0"
enter-to-class="transform opacity-100"
leave-active-class="transition ease-in duration-300"
leave-active-class="transition ease-in duration-100"
leave-from-class="transform opacity-100"
leave-to-class="transform opacity-0">
<CodeHighlight class="h-full" v-if="renderComponent" :code="currentFrame" />
</transition>
<Markdown v-if="renderComponent && activeFrame === 0" class="h-full" :source="event" />
<Markdown v-if="renderComponent && activeFrame === 1" class="h-full" :source="command" />
<Markdown v-if="renderComponent && activeFrame === 2" class="h-full" :source="contextMenu" />
<Markdown v-if="renderComponent && activeFrame === 3" class="h-full" :source="model" />
</transition-group>
</div>
</div>
</template>
<script setup lang='ts'>
import Markdown from './Markdown.vue'
import Collapse from './Collapse.vue'
import CodeHighlight from './CodeHighlight.vue'
import { ref, computed, nextTick } from 'vue'
import { command, event, middleware, slashCommand } from '../utils/CodeHighlignt'
import { computed, nextTick, ref } from 'vue'
import useDocumentation from '../services/Documentation'
import { markdownEndpoint } from '../utils/Navigation'
let activeFrame = ref(0)
let renderComponent = ref(true);
function handleChange (key: number) {
activeFrame.value = key
renderComponent.value = false
activeFrame.value = key
nextTick(() => {
setTimeout(() => {
renderComponent.value = true;
});
}, 100)
}
const currentFrame = computed(() => collapseHighlighting[activeFrame.value].code)
const event = ref('')
const command = ref('')
const contextMenu = ref('')
const model = ref('')
nextTick(async () => {
event.value = await useDocumentation(markdownEndpoint.PARTIAL_EVENT)
command.value = await useDocumentation(markdownEndpoint.PARTIAL_COMMAND)
contextMenu.value = await useDocumentation(markdownEndpoint.PARTIAL_CONTEXT_MENU)
model.value = await useDocumentation(markdownEndpoint.PARTIAL_MODEL)
})
const collapseHighlighting = [
{
label: 'Events',
description: 'The use of events is the basis when developing a robot for discord. It is important to be able to create your own events quickly and efficiently. Discord Factory provides a command in the CLI that allows you to easily generate ready-to-use event files.',
code: event,
},
{
label: 'Commands',
description: 'The use of commands has become commonplace in the world of discord robots, it is important to be able to create your own commands quickly and efficiently. Discord Factory provides you with a command that allows you to easily generate ready-to-use command files.',
code: command,
},
{
label: 'Slash commands',
description: 'The use of commands has become commonplace in the world of discord robots, it is important to be able to create your own commands quickly and efficiently. Discord Factory provides you with a command that allows you to easily generate ready-to-use command files.',
code: slashCommand,
},
{
label: 'Middlewares',
label: 'Context menus',
description: 'Middlewares are fragments of code that intervene upstream of one or several commands in order to authorise or not the execution. These fragments are governed by a regex that will allow you to create a single business logic applicable to the associated commands.',
code: middleware,
},
{
label: 'Models',
description: 'Models are used to interact with a database, they represent your tables from the database within your application. You can make full use of them by using the @discord-factory/storage-next module.',
},
]
</script>
</script>

View File

@@ -1,232 +0,0 @@
<template>
<Prism :language="language">{{ code.trim() }}</Prism>
</template>
<script setup lang='ts'>
import 'prismjs'
import 'prismjs/components/prism-typescript'
// @ts-ignore
import Prism from 'vue-prism-component'
type Props = {
language?: string
code: string
}
withDefaults(defineProps<Props>(), {
language: 'typescript',
code: ''
})
</script>
<style lang="scss">
code[class*="language-"],
pre[class*="language-"] {
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
color: #c3cee3;
background: #263238;
font-family: Jetbrains Mono, Roboto Mono, monospace;
font-size: 0.9em;
line-height: 1.8em;
-moz-tab-size: 2;
-o-tab-size: 2;
tab-size: 2;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
@apply rounded-md;
}
code[class*="language-"]::-moz-selection,
pre[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection,
pre[class*="language-"] ::-moz-selection {
background: #363636;
}
code[class*="language-"]::selection,
pre[class*="language-"]::selection,
code[class*="language-"] ::selection,
pre[class*="language-"] ::selection {
background: #363636;
}
:not(pre) > code[class*="language-"] {
white-space: normal;
border-radius: 0.2em;
padding: 0.1em;
}
pre[class*="language-"] {
overflow: auto;
position: relative;
padding: .5rem 1em .5rem;
margin: 0;
}
.language-css > code,
.language-sass > code,
.language-scss > code {
color: #fd9170;
}
[class*="language-"] .namespace {
opacity: 0.7;
}
.token.atrule {
color: #c792ea;
}
.token.attr-name {
color: #ffcb6b;
}
.token.attr-value {
color: #c3e88d;
}
.token.attribute {
color: #c3e88d;
}
.token.boolean {
color: #c792ea;
}
.token.builtin {
color: #BFBFBF;
}
.token.cdata {
color: #80cbc4;
}
.token.char {
color: #80cbc4;
}
.token.class {
color: #ffcb6b;
}
.token.class-name {
color: #BFBFBF;
}
.token.color {
color: #f2ff00;
}
.token.comment {
color: #546e7a;
}
.token.constant {
color: #c792ea;
}
.token.deleted {
color: #f07178;
}
.token.doctype {
color: #546e7a;
}
.token.entity {
color: #f07178;
}
.token.function {
color: #0F74B9;
}
.token.hexcode {
color: #f2ff00;
}
.token.id {
color: #c792ea;
font-weight: bold;
}
.token.important {
color: #c792ea;
font-weight: bold;
}
.token.inserted {
color: #80cbc4;
}
.token.keyword {
color: #17A7C1;
font-style: italic;
}
.token.number {
color: #fd9170;
}
.token.operator {
color: #0F74B9;
}
.token.prolog {
color: #546e7a;
}
.token.property {
color: #80cbc4;
}
.token.pseudo-class {
color: #c3e88d;
}
.token.pseudo-element {
color: #c3e88d;
}
.token.punctuation {
color: #BFBFBF;
}
.token.regex {
color: #f2ff00;
}
.token.selector {
color: #f07178;
}
.token.string {
color: #c3e88d;
}
.token.symbol {
color: #C792EA;
}
.token.tag {
color: #f07178;
}
.token.unit {
color: #f07178;
}
.token.url {
color: #fd9170;
}
.token.variable {
color: #f07178;
}
</style>

View File

@@ -28,11 +28,11 @@
<div class="flex justify-between">
<div class="flex space-x-5">
<div
class="h-10 w-10 rounded-md"
:class="popover.color"></div>
class="h-10 w-10 rounded-md"
:class="popover.color"></div>
<div class="flex-col">
<p>
{{ popover.color.replace(/-/g, '_').toUpperCase() }}
{{ popover.color.replace(/bg-/g, '').replace(/-/g, '_').toUpperCase() }}
</p>
<div class="mt-3 flex space-x-7">
<button
@@ -75,7 +75,10 @@ function handleChoose (color: string) {
function handleCopy () {
navigator.clipboard.writeText(
popover.color.replace(/-/g, '_').toUpperCase()
popover.color
.replace(/-/g, '_')
.toUpperCase()
.replace(/BG_/g, '')
)
popover.show = false
popover.color = null

View File

@@ -6,7 +6,7 @@
<div class="relative z-10 lg:col-start-1 lg:row-start-1 lg:col-span-4 lg:py-16 lg:bg-transparent">
<div class="max-w-md mx-auto px-4 sm:max-w-3xl sm:px-6 lg:max-w-none lg:p-0">
<div class="bg-blue-900 rounded-xl aspect-w-10 aspect-h-6 sm:aspect-w-2 sm:aspect-h-1 lg:aspect-w-1.5">
<img class="m-auto w-1/2 sm:h-1/2" src="../assets/discord-logo-white.svg" alt="Workflow" />
<img class="rounded-md object-cover" src="../assets/discord-banner.jpg" alt="Workflow" />
</div>
</div>
</div>

View File

@@ -1,6 +1,6 @@
<!-- This example requires Tailwind CSS v2.0+ -->
<template>
<div class="z-40 top-0 left-0 w-full min-h-screen flex bg-gray-100">
<div class="z-40 top-0 left-0 w-full min-h-screen md:flex bg-gray-100">
<TransitionRoot as="template" :show="sidebarOpen">
<Dialog
as="div"
@@ -24,7 +24,7 @@
leave="transition ease-in-out duration-300 transform"
leave-from="translate-x-0"
leave-to="-translate-x-full">
<div class="relative flex-1 flex flex-col max-w-xs w-full bg-white">
<div class="relative flex-1 flex flex-col max-w-xs w-full bg-white overflow-x-hidden overflow-y-scroll">
<TransitionChild
as="template"
enter="ease-in-out duration-300"
@@ -33,7 +33,7 @@
leave="ease-in-out duration-300"
leave-from="opacity-100"
leave-to="opacity-0">
<div class="absolute top-0 right-0 -mr-12 pt-2">
<div class="absolute top-0 right-0 md:-mr-12 pt-2">
<button
type="button"
class="ml-1 flex items-center justify-center h-10 w-10 rounded-full focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
@@ -44,13 +44,7 @@
</div>
</TransitionChild>
<div class="flex-1 h-0 pt-5 pb-4 ">
<div class="flex-shrink-0 flex items-center px-4">
<img
class="h-8 w-auto"
src="https://tailwindui.com/img/logos/workflow-logo-indigo-600-mark-gray-800-text.svg"
alt="Workflow" />
</div>
<nav class="mt-5 px-2 space-y-2">
<nav class="mt-12 sm:mt-5 px-2 space-y-2">
<template v-for="item in documentation">
<div v-if="item.isMenu">
<p>{{ item.label }}</p>
@@ -72,23 +66,6 @@
</template>
</nav>
</div>
<div class="flex-shrink-0 flex border-t border-gray-200 p-4">
<a href="#" class="flex-shrink-0 group block">
<div class="flex items-center">
<div>
<img class="inline-block h-10 w-10 rounded-full" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="" />
</div>
<div class="ml-3">
<p class="text-base font-medium text-gray-700 group-hover:text-gray-900">
Tom Cook
</p>
<p class="text-sm font-medium text-gray-500 group-hover:text-gray-700">
View profile
</p>
</div>
</div>
</a>
</div>
</div>
</TransitionChild>
<div class="flex-shrink-0 w-14">
@@ -98,14 +75,14 @@
</TransitionRoot>
<!-- Static sidebar for desktop -->
<div class="hidden sm:fixed pt-[64px] top-0 left-0 h-full md:flex md:flex-shrink-0">
<div class="flex flex-col w-96">
<div class="hidden sm:fixed pt-[40px] xl:pt-[64px] top-0 left-0 h-full md:flex md:flex-shrink-0">
<div class="flex flex-col">
<!-- Sidebar component, swap this element with another sidebar if you like -->
<div class="flex-1 flex flex-col min-h-0 border-r border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 transition duration-300">
<div class="flex-1 flex flex-col min-h-0 border-r border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 transition duration-300 overflow-y-auto lg:pl-5 xl:pl-10">
<div class="flex-1 flex flex-col pt-5 pb-4 ">
<nav class="mt-5 flex-1 px-2 space-y-5">
<template v-for="item in documentation">
<div v-if="item.isMenu" class="w-1/2 ml-auto">
<div v-if="item.isMenu" class="ml-auto">
<p class="text-blue-900 dark:text-gray-600 font-bold">{{ item.label }}</p>
<router-link
v-for="link in item.child"
@@ -115,11 +92,11 @@
{{ link.label }}
</router-link>
</div>
<div v-else class="w-1/2 ml-auto">
<div v-else class="ml-auto">
<router-link
:key="item.name"
:to="item.href"
:class="[item.current ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900', 'group flex items-center py-2 text-base font-medium rounded-md']">
:class="[item.current ? 'bg-gray-100 text-gray-900' : 'text-gray-600 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-800 hover:text-gray-900 dark:hover:text-gray-100', 'group flex items-center p-2 w-full text-base font-medium rounded-md']">
{{ item.label }}
</router-link>
</div>
@@ -129,18 +106,15 @@
</div>
</div>
</div>
<div class="px-96 mx-auto flex flex-col flex-1 bg-gray-100 dark:bg-gray-800 dark:text-gray-600">
<div class="md:px-50 lg:px-54 xl:px-96 mx-auto flex flex-col flex-1 bg-gray-100 dark:bg-gray-800 dark:text-gray-600">
<div class="md:hidden pl-1 pt-1 sm:pl-3 sm:pt-3">
<button type="button" class="-ml-0.5 -mt-0.5 h-12 w-12 inline-flex items-center justify-center rounded-md text-gray-500 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500" @click="sidebarOpen = true">
<span class="sr-only">Open sidebar</span>
<MenuIcon class="h-6 w-6" aria-hidden="true" />
</button>
</div>
<main class="flex-1 relative z-0 focus:outline-none">
<main class="flex-1 relative z-0 md:w-[36rem] lg:w-[40rem] xl:w-auto focus:outline-none">
<div class="py-6 space-y-5">
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
<h1 class="text-4xl font-semibold text-[#204977] dark:text-white">{{ title }}</h1>
</div>
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8 dark:text-gray-400 space-y-6">
<slot />
</div>
@@ -149,8 +123,8 @@
</div>
<!-- Static toc for desktop -->
<div class="hidden sm:fixed top-0 right-0 pt-[64px] h-full md:flex md:flex-shrink-0">
<div class="flex flex-col w-64">
<div class="hidden lg:fixed top-0 right-0 md:pt-[40px] xl:pt-[64px] h-full md:flex md:flex-shrink-0">
<div class="flex flex-col lg:w-44 xl:w-64">
<!-- Sidebar component, swap this element with another sidebar if you like -->
<div class="flex-1 flex flex-col min-h-0 border-l border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 transition duration-300">
<div class="flex-1 flex flex-col pt-5 pb-4 ">
@@ -180,25 +154,27 @@ import { Dialog, DialogOverlay, TransitionChild, TransitionRoot } from '@headles
import { documentation } from '../utils/Navigation'
import { CalendarIcon, ChartBarIcon, FolderIcon, HomeIcon, InboxIcon, MenuIcon, UsersIcon, XIcon, MenuAlt2Icon } from '@heroicons/vue/outline'
defineProps<{ title: string }>()
const sidebarOpen = ref(false)
let toc = ref([])
let toc = ref(null)
onMounted(() => {
const elements = document.querySelectorAll('h2, h3, h4, h5, h6')
elements.forEach((element: HTMLElement) => element.id = `anchor-${element.innerText}`)
toc.value = Array.from(elements).map((element: HTMLElement) => ({
label: element.innerText,
id: `anchor-${element.innerText}`
}))
window.scroll(0, top + 20)
setTimeout(() => {
const elements = document.querySelectorAll('h2, h3')
toc.value = Array.from(elements).map((element: HTMLElement) => ({
label: element.innerText,
id: element.innerText
.toLowerCase()
.replace(/ /g, '-')
}))
}, 300)
})
function scrollMeTo (refName) {
function scrollMeTo (refName: string) {
const element = document.getElementById(refName)
const top = element.offsetTop;
const top = element.offsetTop
window.scroll(0, top - 64);
window.scroll(0, top)
}
</script>
@@ -212,7 +188,7 @@ h2 {
color: #204977;
}
h3 {
@apply text-2xl leading-10 pt-10;
@apply text-2xl leading-0 pt-16;
color: #204977;
}
h4 {
@@ -223,10 +199,6 @@ h5 {
@apply text-xl leading-10 pt-10;
color: #204977;
}
h6 {
@apply text-lg leading-10 pt-2;
color: #204977;
}
ul {
li {
@apply leading-8

214
src/components/Markdown.vue Normal file
View File

@@ -0,0 +1,214 @@
<template>
<div class="markdown-viewer" v-html="content"></div>
</template>
<script setup lang='ts'>
import MarkdownIt from 'markdown-it'
import Emogi from 'markdown-it-emoji'
import MarkdownItHighlightjs from 'markdown-it-highlightjs'
import Anchor from 'markdown-it-anchor'
import MarkdownContainer from 'markdown-it-container'
import { onMounted, onUpdated, ref } from 'vue'
interface Props {
source: string
}
const props = defineProps<Props>()
const content = ref('')
function render () {
const md = new MarkdownIt({
html: true,
linkify: true,
typographer: true
})
.use(MarkdownItHighlightjs)
.use(MarkdownContainer, 'warning')
.use(MarkdownContainer, 'success')
.use(MarkdownContainer, 'error')
.use(MarkdownContainer, 'info')
.use(Anchor)
.use(Emogi)
content.value = md.render(props.source)
}
onMounted(() => render())
onUpdated(() => render())
</script>
<style lang="scss">
h1 {
@apply text-4xl font-bold mb-5 relative;
&::after {
content: '';
@apply absolute bottom-0 left-0 transform translate-y-5 border-b border-gray-700 border-opacity-10 w-full;
}
}
h6 {
@apply text-xs -mb-2.5 pt-2 text-gray-700 opacity-75;
}
.markdown-viewer {
& > p {
@apply leading-8 pt-5;
code {
@apply bg-white dark:bg-gray-600 p-1 rounded-md;
}
}
blockquote {
@apply relative;
&::before {
content: '';
@apply absolute left-0 top-1/2 transform -translate-y-1/2 -translate-x-4 border-l-4 border-black h-[75%] border-gray-300;
}
}
pre {
@apply bg-[#263238] overflow-x-auto rounded-md leading-7 px-3 py-2;
code {
@apply text-[14px] text-[#bfbfbf];
&.language {
font-family: Jetbrains Mono, Roboto Mono, monospace;
&-ts {
.hljs-meta {
@apply text-[#0f74b9];
}
.hljs-keyword, .hljs-built_in {
@apply text-[#17a7c1];
}
.hljs-string {
@apply text-[#c3e88d];
}
.hljs-comment {
@apply text-[#546e7a];
}
.hljs-subst {
@apply text-[#bfbfbf];
}
}
&-bash {
.hljs-comment {
@apply text-[#546e7a];
}
}
&-dockerfile {
.hljs-keyword {
@apply text-[#17a7c1];
}
.hljs-string {
@apply text-[#c3e88d];
}
.hljs-comment {
@apply text-[#546e7a];
}
}
&-yaml {
.hljs-attr {
@apply text-[#17a7c1];
}
.hljs-comment {
@apply text-[#546e7a];
}
}
&-json {
.hljs-attr {
@apply text-[#17a7c1];
}
.hljs-string {
@apply text-[#c3e88d];
}
.hljs-comment {
@apply text-[#546e7a];
}
.hljs-literal {
@apply text-blue-200;
}
}
}
}
}
.warning {
@apply rounded-md bg-yellow-50 dark:bg-yellow-500 border border-yellow-400 dark:border-yellow-900 md:w-1/2 flex flex-col p-4 my-5 relative;
&::before {
content: url('data:image/svg+xml; utf8, <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /> </svg>');
@apply absolute transform left-0 translate-x-3 block h-6 w-6;
}
p {
@apply pl-8 text-sm font-medium text-yellow-800 dark:text-yellow-900 sm:flex items-center;
& > code {
@apply bg-yellow-100 dark:opacity-50 py-0.5 px-1 mx-1 rounded-md;
}
}
& > ul {
@apply pl-8 text-sm text-yellow-800 dark:text-yellow-900 space-y-3;
li {
@apply leading-5;
&::before {
content: '• ';
}
}
code {
@apply bg-yellow-100 dark:opacity-50 py-0.5 px-1 mx-1 rounded-md;
}
}
}
.error {
@apply rounded-md bg-red-50 dark:bg-red-600 border border-red-400 dark:border-red-900 md:w-1/2 flex p-4 my-5 relative;
&::before {
content: url('data:image/svg+xml; utf8, <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" /></svg>');
@apply absolute transform left-0 translate-x-3 block h-6 w-6;
}
p {
@apply pl-8 text-sm font-medium text-red-800 dark:text-red-900 sm:flex items-center;
& > code {
@apply bg-red-100 dark:opacity-50 py-0.5 px-1 mx-1 rounded-md;
}
}
}
.success {
@apply rounded-md bg-green-50 dark:bg-green-500 border border-green-400 dark:border-green-900 md:w-1/2 flex p-4 my-5 relative;
&::before {
content: url('data:image/svg+xml; utf8, <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>');
@apply absolute transform left-0 translate-x-3 block h-6 w-6;
}
p {
@apply pl-8 text-sm font-medium text-green-800 dark:text-green-900;
& > code {
@apply bg-green-100 dark:opacity-50 py-0.5 px-1 mx-1 rounded-md;
}
}
}
.info {
@apply rounded-md bg-blue-50 dark:bg-blue-500 border border-blue-400 dark:border-blue-900 md:w-1/2 flex flex-col p-4 my-5 relative;
&::before {
content: url('data:image/svg+xml; utf8, <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>');
@apply absolute transform left-0 translate-x-3 block h-6 w-6;
}
p {
@apply pl-8 text-sm font-medium text-blue-800 dark:text-blue-900;
& > code {
@apply bg-blue-100 dark:opacity-50 py-0.5 px-1 mx-1 rounded-md;
}
}
& > ul {
@apply pl-8 text-sm text-yellow-800 dark:text-yellow-900 space-y-3;
li {
@apply leading-5;
&::before {
content: '• ';
}
}
code {
@apply bg-yellow-100 dark:opacity-50 py-0.5 px-1 mx-1 rounded-md;
}
}
}
}
</style>

View File

@@ -0,0 +1,49 @@
<template>
<svg class="spinner" viewBox="0 0 50 50">
<circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"></circle>
</svg>
</template>
<script setup lang='ts'>
</script>
<style lang="scss">
.spinner {
animation: rotate 2s linear infinite;
z-index: 2;
position: absolute;
top: 25%;
left: 50%;
margin: -25px 0 0 -25px;
width: 50px;
height: 50px;
& .path {
stroke: #93bfec;
stroke-linecap: round;
animation: dash 1.5s ease-in-out infinite;
}
}
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}
@keyframes dash {
0% {
stroke-dasharray: 1, 150;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -35;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -124;
}
}
</style>

View File

@@ -1,7 +1,7 @@
<!-- This example requires Tailwind CSS v2.0+ -->
<template>
<div class="relative bg-gray-800 rounded-xl overflow-hidden">
<img class="absolute" src="../assets/discord-background.png" alt="Workflow" />
<img class="absolute w-full h-full object-cover" src="../assets/discord-background.png" alt="Workflow" />
<div class="absolute inset-0 bg-black opacity-25"></div>
<div class="relative z-10 max-w-7xl mx-auto py-12 px-4 sm:py-16 sm:px-6 lg:px-8 lg:py-20">
<div class="max-w-4xl mx-auto text-center">
@@ -56,8 +56,8 @@ const state = reactive({
async function getData () {
const now = DateTime.now().toFormat('yyyy-MM-dd')
const { data: users } = await axios.get(`https://api.npmjs.org/downloads/point/2020-01-01:${now}/@discord-factory/command`)
const { data: projects } = await axios.get(`https://api.npmjs.org/downloads/point/2020-01-01:${now}/@discord-factory/core`)
const { data: users } = await axios.get(`https://api.npmjs.org/downloads/point/2021-09-01:${now}/create-factory-app`)
const { data: projects } = await axios.get(`https://api.npmjs.org/downloads/point/2021-09-01:${now}/@discord-factory/core`)
const { data: discord } = await axios.get('https://discord.com/api/guilds/874056537444859984/widget.json')
state.userCount = users.downloads

View File

@@ -0,0 +1,7 @@
import axios from 'axios'
import { markdownEndpoint } from '../utils/Navigation'
export default async function useDocumentation (url: markdownEndpoint): Promise<string> {
const { data } = await axios.get(url)
return data
}

View File

@@ -1,10 +1,10 @@
<template>
<Navbar />
<main class="pt-[64px] bg-white dark:bg-gray-800 transition duration-300 min-h-screen pb-10">
<main class="pt-[64px] overflow-x-hidden bg-white dark:bg-gray-800 transition duration-300 min-h-screen pb-10">
<RouterView />
<button
@click.prevent="toggle()"
class="fixed z-50 bottom-5 left-5 w-10 h-10 border-2 rounded focus:outline-none"
class="fixed z-50 bottom-5 right-5 sm:right-0 sm:left-5 w-10 h-10 border-2 rounded focus:outline-none"
:class="isDark() ? 'bg-gray-800 border-white' : 'bg-white border-gray-800'">
<div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
<svg v-if="isDark()" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -30,11 +30,6 @@ onMounted(() => {
htmlStatut.value = document.documentElement.classList.contains('dark')
})
const route = useRoute()
onMounted(() => $route.path, () => {
console.log('test')
})
function toggle () {
const htmlRoot = document.documentElement as HTMLElement
htmlRoot.classList.contains('dark')

View File

@@ -4,14 +4,18 @@ import Starting from './base/Starting.vue'
import Environment from './base/Environment.vue'
import Structure from './base/Structure.vue'
import Command from './base/Command.vue'
import SlashCommand from './base/SlashCommand.vue'
import ContextMenu from './base/ContextMenu.vue'
import Event from './base/Event.vue'
import Middleware from './base/Middleware.vue'
import Hook from './base/Hook.vue'
import Deployment from './advanced/Deployment.vue'
import CreateAddon from './advanced/CreateAddon.vue'
import PartialHooks from './base/PartialHooks.vue'
import PingPong from './examples/PingPong.vue'
import ExampleButtons from './examples/Buttons.vue'
import PresenceProvider from './examples/PresenceProvider.vue'
import MessageCommands from './modules/MessageCommands.vue'
import Colorize from './modules/Colorize.vue'
import Storage from './modules/Storage.vue'
@@ -22,16 +26,18 @@ const routes: RouteRecordRaw[] = [
{ path: '/documentation/structure', component: Structure },
{ path: '/documentation/partial-hooks', component: PartialHooks },
{ path: '/documentation/commands', component: Command },
{ path: '/documentation/slash-commands', component: SlashCommand },
{ path: '/documentation/context-menu', component: ContextMenu },
{ path: '/documentation/events', component: Event },
{ path: '/documentation/middlewares', component: Middleware },
{ path: '/documentation/hooks', component: Hook },
{ path: '/documentation/deployment', component: Deployment },
{ path: '/documentation/create-your-addon', component: CreateAddon },
{ path: '/documentation/modules/message-command', component: MessageCommands },
{ path: '/documentation/modules/colorize', component: Colorize },
{ path: '/documentation/modules/database-storage', component: Storage },
{ path: '/documentation/examples/presence-with-provider', component: PresenceProvider },
{ path: '/documentation/examples/ping-pong', component: PingPong },
{ path: '/documentation/examples/buttons', component: ExampleButtons },
]

View File

@@ -0,0 +1,20 @@
<template>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.ADDON)
})
</script>

View File

@@ -1,151 +1,20 @@
<template>
<Documentation title="Deployment">
<p>
Deployment is the logical phase after developing an application. This section will deal with the production deployment of the application.
In the first time, you should to install all dependencies.
</p>
<h2>Starting your project</h2>
<p>All you have to do is install the dependencies with the following commands</p>
<div class="flex items-center space-x-5">
<CodeHighlight code="$ npm install" />
<p class="text-gray-800">or</p>
<CodeHighlight code="$ yarn install" />
</div>
<p>In the second time, you should to build your application because the production mode cannot read and execute the typescript natively.</p>
<div class="flex items-center space-x-5">
<CodeHighlight code="$ npm run build" />
<p class="text-gray-800">or</p>
<CodeHighlight code="$ yarn build" />
</div>
<div class="space-y-5">
<h2>Deploy with PM2</h2>
<p>PM2 is a daemon process manager that will help you manage and keep your application online 24/7. Install PM2 :</p>
<div class="flex items-center space-x-5">
<CodeHighlight code="$ npm install -g pm2" />
<p class="text-gray-800">or</p>
<CodeHighlight code="$ yarn global add pm2" />
</div>
<p>Create a root file named <code class="active">ecosystem.config.js</code>.</p>
<CodeHighlight :code="ecosystem" />
<AlertInfo>
<template v-slot:label>
Info
</template>
<template v-slot:message>
The <span class="font-bold">index.ts</span> file in the <span class="font-bold">start folder</span> is the entry point for your application.
</template>
</AlertInfo>
<p>Then open a terminal in the root folder of your application and run the following command :</p>
<CodeHighlight :code="startPm2" />
</div>
<div class="space-y-5">
<h2>Deploy with Docker</h2>
<p>Docker is free software for launching applications in isolated containers.</p>
<div>
<p class="mr-2">Learn more: </p>
<LinkExternal url="https://www.docker.com">
Docker Documentation
</LinkExternal>
</div>
<AlertWarn>
<template v-slot:label>
Warn
</template>
<template v-slot:message>
In the docker section, replace <br />
- <span class="font-bold">[name]</span> with the name of your bot, <br />
- <span class="font-bold">[version]</span> with the version of your bot. (You can use `latest`, `dev`... with docker) <br />
- <span class="font-bold">[env]</span> with your env file (`environment.json` or `environment.yml`)
</template>
</AlertWarn>
<p>Create a root file named <code class="active">Dockerfile</code>.</p>
<CodeHighlight :code="Dockerfile" />
<p>Then open a terminal in the root folder of your application and run the following command :</p>
<CodeHighlight :code="buildImage" />
<p>Use docker-compose to automate the start command of your bot with the following content :</p>
<CodeHighlight :code="dockerCompose" />
<p>Finally, you can run your image inside a container with the following command :</p>
<CodeHighlight :code="startContainer" />
<AlertInfo>
<template v-slot:label>
Info
</template>
<template v-slot:message>
The option <span class="font-bold">-d</span> allows to launch the container in the background.
</template>
</AlertInfo>
<p>To stop the container, run the following command :</p>
<CodeHighlight :code="stopContainer" />
<p>To stop see the log of your discord bot, run the following command :</p>
<CodeHighlight :code="seeLogs" />
</div>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import LinkExternal from '../../../../components/LinkExternal.vue'
import AlertInfo from '../../../../components/AlertInfo.vue'
import AlertWarn from "../../../../components/AlertWarn.vue";
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const ecosystem = `
module.exports = {
apps : [{
name : 'Discord Factory application',
instances : 'max',
script : 'npm',
args : 'start'
}]
}`
const startPm2 = `
$ cd /path/to/project/folder/root
$ pm2 start`
const Dockerfile = `
FROM node:16-alpine3.11
RUN mkdir -p /usr/src/[name]
WORKDIR /usr/src/[name]
COPY . /usr/src/[name]
RUN yarn build
CMD ["yarn", "start"]
`
const buildImage = `
$ cd /path/to/project/folder/root
$ docker build -t [name]:[version] .
`
const startContainer = `
$ docker-compose up -d
`
const stopContainer = `
$ docker-compose down
`
const seeLogs = `
$ docker logs [name]
`
const dockerCompose = `
version: "3"
services:
[name]:
image: [name]:[version]
container_name: [name]
volumes:
- "/path/to/project/folder/root/[env]:/usr/src/[name]/[env]:ro"
`
</script>
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.DEPLOYMENT)
})
</script>

View File

@@ -1,78 +1,20 @@
<template>
<Documentation title="Commands">
<p>
The design of a discord bot spends most of the time developing commands.
The purpose of these commands is to execute certain actions by the moderation or the community. Creating a command with the framework is very simple.
</p>
<div class="space-y-5">
<h2>Create new command from CLI</h2>
<p>
Open a new terminal in your project and write the following command :
</p>
<CodeHighlight class="w-min" code="$ factory make:file" />
<AlertInfo>
<template v-slot:label>
Info
</template>
<template v-slot:message>
Choose to create a command and then answer the questions you will be asked. It is important to note that when you define the file name, you can "place" the file in folders by specifying a path directory in addition to the file name as in the following example :
</template>
</AlertInfo>
</div>
<div class="space-y-5">
<h2>Default command file</h2>
<p>
A file will be created in the specified location otherwise in the root of your project with the following structure :
</p>
<CodeHighlight class="w-min" :code="file" />
</div>
<div class="space-y-5">
<h2>Decorator options</h2>
<p>
A file will be created in the specified location otherwise in the root of your project with the following structure :
</p>
<CodeHighlight class="w-min" :code="decorator" />
</div>
<div class="space-y-5">
<h2>Operation of the controls</h2>
<p>
Open a new terminal in your project and write the following command :
</p>
<img class="" src="../../../../assets/application-command.svg" alt="Workflow" />
</div>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import Divider from '../../../../components/Divider.vue'
import LinkExternal from '../../../../components/LinkExternal.vue'
import AlertInfo from '../../../../components/AlertInfo.vue'
const file = `
import { BaseCommand, Command } from '@discord-factory/core'
import { Message } from 'discord.js'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
@Command({ label: 'FooCommand command', description: 'FooCommand description', tag: 'foo' })
export default class FooCommand implements BaseCommand {
public async run(message: Message, args: string[]): Promise<void> {
// Your code here
}
}`
const decorator = `
export interface CommandInterface {
label: string
description: string
tag: string
alias?: string[]
usages?: string[]
roles?: string[]
permissions?: PermissionResolvable[]
middlewares?: string[]
}`
</script>
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.COMMAND)
})
</script>

View File

@@ -0,0 +1,20 @@
<template>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.CONTEXT_MENU)
})
</script>

View File

@@ -1,174 +1,20 @@
<template>
<Documentation title="Environment">
<p>
The environment file contains information confidential to your application such as your token. You must not disclose it under any circumstances.
The Discord Factory framework offers you the possibility to choose between 3 types of files :
</p>
<ul>
<li> Json</li>
<li> Yaml</li>
</ul>
<p>
In order to meet the widest variety of needs, each environment file can be extended by adding your own elements such as messages, etc...
</p>
<h2>Why an environment file</h2>
<p>
The environment file is crucial for several reasons, it contains all the sensitive information of the project and should never be versioned on git.
The use of an environment file allows when using container managers (such as docker, kubernetes) to adapt the startup data to the production environment.
</p>
<p>
When you create a new project, you can choose between three types of environment :
</p>
<!-- -->
<div>
<div class="sm:hidden">
<label for="tabs" class="sr-only">Select a tab</label>
<select id="tabs" name="tabs" class="block w-full focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 rounded-md">
<option
v-for="tab in tabs"
:key="tab.name"
:selected="tab.current">
{{ tab.name }}
</option>
</select>
</div>
<div class="hidden sm:block space-y-5 ">
<nav class="flex space-x-4" aria-label="Tabs">
<button
v-for="tab in tabs"
@click.prevent="changeTab(tab.id)"
:class="[tab.id === activeTab ? 'bg-indigo-100 text-indigo-700' : 'text-gray-500 hover:text-gray-700', 'px-3 py-2 font-medium text-sm rounded-md cursor-pointer focus:outline-none']"
:aria-current="activeTab || undefined"
:key="tab.name">
{{ tab.name }}
</button>
</nav>
<div v-if="activeTab === 'yaml'">
<CodeHighlight :code="yaml" />
</div>
<div v-if="activeTab === 'json'">
<CodeHighlight :code="json" />
</div>
</div>
</div>
<!--<div>-->
<!-- <h3>json</h3>-->
<!-- <CodeHighlight :code="json" />-->
<!--</div>-->
<!--<div>-->
<!-- <h3>yaml</h3>-->
<!-- <CodeHighlight :code="yaml" />-->
<!--</div>-->
<!--<h2>Retrieving environment variables</h2>-->
<!--<CodeHighlight :code="getClient" />-->
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import Divider from '../../../../components/Divider.vue'
import LinkExternal from '../../../../components/LinkExternal.vue'
import AlertWarn from '../../../../components/AlertWarn.vue'
import AlertSuccess from '../../../../components/AlertSuccess.vue'
import AlertInfo from '../../../../components/AlertInfo.vue'
import { ref } from 'vue'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const tabs = [
{ id: 'yaml', name: 'YAML', href: '#' },
{ id: 'json', name: 'JSON', href: '#' },
]
const activeTab = ref('yaml')
function changeTab (identifier: string) {
activeTab.value = identifier
}
const json = `
{
"APP_TOKEN": "your prefix",
"APP_PREFIX": "your token",
"PARTIALS": [
"MESSAGE",
"CHANNEl",
"REACTION"
],
"INTENTS": [
"GUILDS",
"GUILD_MEMBERS",
"GUILD_BANS",
"GUILD_EMOJIS_AND_STICKERS",
"GUILD_INTEGRATIONS",
"GUILD_WEBHOOKS",
"GUILD_INVITES",
"GUILD_VOICE_STATES",
"GUILD_PRESENCES",
"GUILD_MESSAGES",
"GUILD_MESSAGE_REACTIONS",
"GUILD_MESSAGE_TYPING",
"DIRECT_MESSAGES",
"DIRECT_MESSAGE_REACTIONS",
"DIRECT_MESSAGE_TYPING",
],
"PRESETS": {
"COMMAND_AUTO_REMOVE": true
},
"MESSAGES": {
"COMMAND_MISSING_PERMISSION": "You're not authorized to execute this command",
"COMMAND_MISSING_ROLES": "You're not authorized to execute this command",
"ENVIRONMENT_FILE_PREFIX_MISSING": "The prefix is missing in the environment file.",
"ENVIRONMENT_FILE_TOKEN_MISSING": "The token is missing in the environment file.",
"ENVIRONMENT_FILE_MISSING": "Environment file is missing, please create one."
}
}
`
const yaml = `
APP_TOKEN: your token
APP_PREFIX: your prefix
PARTIALS:
- MESSAGE
- CHANNEL
- REACTION
INTENTS:
- GUILDS
- GUILD_MEMBERS
- GUILD_BANS
- GUILD_EMOJIS_AND_STICKERS
- GUILD_INTEGRATIONS
- GUILD_WEBHOOKS
- GUILD_INVITES
- GUILD_VOICE_STATES
- GUILD_PRESENCES
- GUILD_MESSAGES
- GUILD_MESSAGE_REACTIONS
- GUILD_MESSAGE_TYPING
- DIRECT_MESSAGES
- DIRECT_MESSAGE_REACTIONS
- DIRECT_MESSAGE_TYPING
PRESETS:
COMMAND_AUTO_REMOVE: true
MESSAGES:
COMMAND_MISSING_PERMISSION: You're not authorized to execute this command
COMMAND_MISSING_ROLES: You're not authorized to execute this command
ENVIRONMENT_FILE_PREFIX_MISSING: The prefix is missing in the environment file.
ENVIRONMENT_FILE_TOKEN_MISSING: The token is missing in the environment file.
ENVIRONMENT_FILE_MISSING: Environment file is missing, please create one.
DATABASE:
DRIVER: SQLite
PATH: database.sql`
const getClient = `
import { Application } from '@discord-factory/core'
const environment = Application.getEnvironment('APP_PREFIX')
console.log(environment) // '!'
`
</script>
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.ENVIRONMENT)
})
</script>

View File

@@ -1,51 +1,20 @@
<template>
<Documentation title="Events">
<p>
The design of a discord bot spends most of the time developing commands.
The purpose of these commands is to execute certain actions by the moderation or the community. Creating an event with the framework is very simple.
</p>
<div class="space-y-5">
<h2>Create new command from CLI</h2>
<p>
Open a new terminal in your project and write the following command :
</p>
<CodeHighlight class="w-min" code="$ factory make:file" />
<AlertInfo>
<template v-slot:label>
Info
</template>
<template v-slot:message>
Choose to create a command and then answer the questions you will be asked. It is important to note that when you define the file name, you can "place" the file in folders by specifying a path directory in addition to the file name as in the following example :
</template>
</AlertInfo>
</div>
<div class="space-y-5">
<h2>Default command file</h2>
<p>
A file will be created in the specified location otherwise in the root of your project with the following structure :
</p>
<CodeHighlight class="w-min" :code="file" />
</div>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import Divider from '../../../../components/Divider.vue'
import LinkExternal from '../../../../components/LinkExternal.vue'
import AlertInfo from '../../../../components/AlertInfo.vue'
const file = `
import { Event, BaseEvent } from '@discord-factory/core'
import { GuildMember } from 'discord.js'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
@Event('guildMemberAdd')
export default class FooEvent implements BaseEvent {
public async run(member: GuildMember): Promise<void> {
// Please go to the documentation in order to know the parameters you can use
// Your code here
}
}`
</script>
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.EVENT)
})
</script>

View File

@@ -1,30 +1,47 @@
<template>
<Documentation title="Getting started">
<p>
Are you tired of reinventing the wheel at the start of each project, and of spending too much time on how your bot will work?
</p>
<p>
The Discord Factory framework offers you a completely free development structure. You choose how you organize your application.
</p>
<p>
Creation, Structural, Behavioural or even Singleton, you can finally choose your own design pattern without being forced to modify the whole functioning of your project.
</p>
<ul>
<li>🧪 Mode flexibility, no limits. You are free to create your own architecture.</li>
<li> Factory includes "in memory" compilation to make the compilation of your application more efficient.</li>
<li>📦 Learn and create in a powerful development environment with the various tools Discord Factory offers.</li>
</ul>
<p>
It's now up to you!
</p>
<Documentation>
<div class="getting-started">
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</div>
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.GETTING_STARTED)
})
</script>
<style>
<style lang="scss">
.getting-started {
.markdown-viewer {
display: block !important;
& > p:nth-child(2), & > p:last-child, & > p:nth-last-child(3) {
@apply flex md:flex-wrap md:space-x-2 overflow-x-auto;
}
& > img {
@apply md:w-1/3;
}
& > p {
@apply md:flex-wrap md:space-x-2 overflow-x-auto;
code {
@apply bg-red-500;
}
}
blockquote {
code {
@apply bg-white dark:bg-gray-600 p-1 rounded-md;
}
}
}
}
</style>

View File

@@ -1,58 +1,20 @@
<template>
<Documentation title="Hooks">
<p>
Hooks are hooks at certain points in the application's life cycle. You can add specific behaviours to them according to your needs, such as a filter that allows you to delete any message that contains an insult.
Creating a command with the framework is very simple.
</p>
<div class="space-y-5">
<h2>Create new command from CLI</h2>
<p>
Open a new terminal in your project and write the following command :
</p>
<CodeHighlight class="w-min" code="$ factory make:file" />
<AlertInfo>
<template v-slot:label>
Info
</template>
<template v-slot:message>
Choose to create a hook and then answer the questions you will be asked. It is important to note that when you define the file name, you can "place" the file in folders by specifying a path directory in addition to the file name as in the following example :
</template>
</AlertInfo>
</div>
<div class="space-y-5">
<h2>Default command file</h2>
<p>
A file will be created in the specified location otherwise in the root of your project with the following structure :
</p>
<CodeHighlight class="w-min" :code="file" />
</div>
<div class="space-y-5">
<h2>Issuing of events</h2>
<p>
Open a new terminal in your project and write the following command :
</p>
<img class="" src="../../../../assets/application-lifecycle.svg" alt="Workflow" />
</div>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import Divider from '../../../../components/Divider.vue'
import LinkExternal from '../../../../components/LinkExternal.vue'
import AlertInfo from '../../../../components/AlertInfo.vue'
const file = `
import { Hook, BaseHook, HookContext } from '@discord-factory/core'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
@Hook('app::command::received')
export default class FooHook implements BaseHook {
public async run(context: HookContext): Promise<void> {
// Your code here
}
}`
</script>
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.HOOK)
})
</script>

View File

@@ -1,56 +0,0 @@
<template>
<Documentation title="Middlewares">
<p>
When creating commands, it is very common to have to perform a check before the execution of the command in order to verify,
for example, if the executor of the command has a specific role, required permissions (non-exhaustive list).
</p>
<p>
These checks are usually recurring from command to command and must be duplicated which goes against the Don't Repeat Yourself principle.<br>
The role of middleware is to create a file that can be reused at will and used by any command that requires recurring checks.
</p>
<p>
Creating a command with the framework is very simple.
</p>
<div class="space-y-5">
<h2>Create new command from CLI</h2>
<p>
Open a new terminal in your project and write the following command :
</p>
<CodeHighlight class="w-min" code="$ factory make:file" />
<AlertInfo>
<template v-slot:label>
Info
</template>
<template v-slot:message>
Choose to create a middleware and then answer the questions you will be asked. It is important to note that when you define the file name, you can "place" the file in folders by specifying a path directory in addition to the file name as in the following example :
</template>
</AlertInfo>
</div>
<div class="space-y-5">
<h2>Default middleware file</h2>
<p>
A file will be created in the specified location otherwise in the root of your project with the following structure :
</p>
<CodeHighlight class="w-min" :code="file" />
</div>
</Documentation>
</template>
<script setup lang="ts">
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import Divider from '../../../../components/Divider.vue'
import LinkExternal from '../../../../components/LinkExternal.vue'
import AlertInfo from '../../../../components/AlertInfo.vue'
const file = `
import { Middleware, BaseMiddleware, MiddlewareContext } from '@discord-factory/core'
@Middleware({ pattern: 'YourRegexPattern')}
export default class FooMiddleware implements BaseMiddleware {
public async run(context: MiddlewareContext): Promise<void> {
// Your code here
}
}`
</script>

View File

@@ -1,98 +1,20 @@
<template>
<Documentation title="Hooks">
<p>
The @discord-factory/core module is intended to simplify access to certain resources such as commands,events registered within the instance of your application.
</p>
<div class="space-y-5">
<h2>useClient</h2>
<p>
Returns the instance of the Discord Client linked to the bot.
</p>
<CodeHighlight class="w-min" :code="useClient" />
</div>
<div class="space-y-5">
<h2>useCommands</h2>
<p>
Returns the set of commands registered within the application instance.
</p>
<CodeHighlight class="w-min" :code="useCommands" />
</div>
<div class="space-y-5">
<h2>useEvents</h2>
<p>
Returns the set of events registered within the application instance.
</p>
<CodeHighlight class="w-min" :code="useEvents" />
</div>
<div class="space-y-5">
<h2>useMiddlewares</h2>
<p>
Returns the set of middlewares registered within the application instance.
</p>
<CodeHighlight class="w-min" :code="useMiddlewares" />
</div>
<div class="space-y-5">
<h2>useHooks</h2>
<p>
Returns the set of hooks registered within the application instance.
</p>
<CodeHighlight class="w-min" :code="useHooks" />
</div>
<div class="space-y-5">
<h2>useProviders</h2>
<p>
Returns the set of providers registered within the application instance.
</p>
<CodeHighlight class="w-min" :code="useProviders" />
</div>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import Divider from '../../../../components/Divider.vue'
import LinkExternal from '../../../../components/LinkExternal.vue'
import AlertInfo from '../../../../components/AlertInfo.vue'
const useClient = `
import { Application } from '@discord-factory/core'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const client = Application.getClient()
console.log(client)`
const useCommands = `
import { Application } from '@discord-factory/core'
const commands = Application.getCommands()
console.log(commands)`
const useEvents = `
import { Application } from '@discord-factory/core'
const events = Application.getEvents()
console.log(events)`
const useMiddlewares = `
import { Application } from '@discord-factory/core'
const middlewares = Application.getMiddlewares()
console.log(middlewares)`
const useHooks = `
import { Application } from '@discord-factory/core'
const hooks = Application.getHooks()
console.log(hooks)`
const useProviders = `
import { Application } from '@discord-factory/core'
const providers = Application.getProviders()
console.log(providers)`
</script>
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.APPLICATION_HOOK)
})
</script>

View File

@@ -1,81 +0,0 @@
<template>
<Documentation title="Slash commands">
<p>
The version 13 update of discord.js marks the arrival of Slash Commands.<br>This new feature provides real support for developers who want to create commands on their bots.
It was announced by Discord that they will gradually replace the old command system that we all knew based on the presence of a prefix as the first character of a message with this new suppo
</p>
<div class="space-y-5">
<h2>Create new slash command from CLI</h2>
<p>
Open a new terminal in your project and write the following command :
</p>
<CodeHighlight class="w-min" code="$ factory make:file" />
<AlertInfo>
<template v-slot:label>
Info
</template>
<template v-slot:message>
Choose to create a command and then answer the questions you will be asked. It is important to note that when you define the file name, you can "place" the file in folders by specifying a path directory in addition to the file name as in the following example.
</template>
</AlertInfo>
</div>
<div class="space-y-5">
<h2>Default command file</h2>
<p>
A file will be created in the specified location otherwise in the root of your project with the following structure :
</p>
<CodeHighlight class="w-min" :code="file" />
</div>
<div class="space-y-5">
<h2>Decorator options</h2>
<p>
A file will be created in the specified location otherwise in the root of your project with the following structure :
</p>
<CodeHighlight class="w-min" :code="decorator" />
<p>
See more about ApplicationCommandOption <LinkExternal url="https://discord.js.org/#/docs/main/stable/typedef/ApplicationCommandOption">here</LinkExternal>
</p>
</div>
</Documentation>
</template>
<script setup lang="ts">
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import Divider from '../../../../components/Divider.vue'
import LinkExternal from '../../../../components/LinkExternal.vue'
import AlertInfo from '../../../../components/AlertInfo.vue'
import Hightlight from '../../../../components/Hightlight.vue'
const file = `
import { BaseSlashCommand, SlashCommand } from '@discord-factory/core'
import { CommandInteraction } from 'discord.js'
@SlashCommand({
scope: ['your guild id'], 👈 // Or 'GLOBAL' if you want to register globally
options: {
name: 'foo', 👈 // UpperCase isn't valid, please use lowerCase
description: 'Your foo command description',
options: [],
},
})
export default class FooCommand implements BaseSlashCommand {
public async run(interaction: CommandInteraction): Promise<void> {
// Your code here
}
}`
const decorator = `
export interface SlashCommandInterface {
scope: 'GLOBAL' | Snowflake[], 👈 // Or 'GLOBAL' if you want to register globally
roles: Snowflake[],
options: {
name: string, 👈 // UpperCase isn't valid, please use lowerCase
description: string,
options: ApplicationCommandOption[],
}
}`
</script>

View File

@@ -1,88 +1,20 @@
<template>
<Documentation title="Starting">
<p>
Installing a framework to use it is not always obvious because of the configuration that the developer must make.
</p>
<p>
Unfortunately there is currently no equivalent to automatically create the project. (But we are thinking about it! 😐)
</p>
<h2>Factory, the interactive ordering guest</h2>
<p>
Let's get to the heart of the matter.<br>
In order to develop with the framework, you need to have
<LinkExternal url="https://nodejs.org/en/download/current">NodeJS (<span class="font-extrabold">v.16+</span>)</LinkExternal>
installed on your development environment. Then, globally install the CLI Architect of the bot.
</p>
<div class="flex items-center space-x-5">
<CodeHighlight code="npm install -g @discord-factory/command" />
<p class="text-gray-800">or</p>
<CodeHighlight code="yarn global add @discord-factory/command" />
</div>
<AlertWarn>
<template v-slot:label>
Warn
</template>
<template v-slot:message>
It's possible that using YARN to add the CLI globally does not work correctly, in this case please use NPM.
</template>
</AlertWarn>
<h2>Create your first project</h2>
<p>
The <span class="font-bold">@discord-factory/command</span> module is a CLI which, in the same way as Artisan for Laravel, will allow you to interact quickly with the bot's functionalities.
You can now initialize a project very easily with the following command
</p>
<CodeHighlight class="w-min" code="$ factory create-project" />
<p>
Answer the questions and a blank project will be initialized according to the elements you have defined.
An .env file will be created, this file must have at least the following data :
</p>
<AlertInfo>
<template v-slot:label>
Info
</template>
<template v-slot:message>
The <span class="font-bold">prefix</span> key represents the prefix that each message must have in order to be recognised as a command.
</template>
</AlertInfo>
<AlertInfo>
<template v-slot:label>
Info
</template>
<template v-slot:message>
The <span class="font-bold">token</span> key is the token of your bot. It should never be disclosed or sent on a versioning platform such as github. An article is available here to know how to recover the token of its bot.
</template>
</AlertInfo>
<h2>Starting your project</h2>
<p>All you have to do is install the dependencies with the following commands</p>
<div class="flex items-center space-x-5">
<CodeHighlight code="$ npm install" />
<p class="text-gray-800">or</p>
<CodeHighlight code="$ yarn install" />
</div>
<p>
The Factory framework uses in memory compilation allowing typescript code to be executed directly by ts-node without having to go through a build folder.
Furthermore, this hot compile allows you to reduce your CPU usage by almost 4 times by reducing the memory cost from <span class="font-bold">~600MB</span> to <span class="font-bold">~170MB</span>.
</p>
<div class="flex items-center space-x-5">
<CodeHighlight code="$ npm run dev" />
<p class="text-gray-800">or</p>
<CodeHighlight code="$ yarn dev" />
</div>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import Divider from '../../../../components/Divider.vue'
import LinkExternal from '../../../../components/LinkExternal.vue'
import AlertWarn from '../../../../components/AlertWarn.vue'
import AlertSuccess from '../../../../components/AlertSuccess.vue'
import AlertInfo from '../../../../components/AlertInfo.vue'
</script>
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.STARTING)
})
</script>

View File

@@ -1,195 +1,20 @@
<template>
<Documentation title="Structure">
<p>
The framework offers a very modular way of structuring your files within your application, the only restriction is that they must be included in the src/ folder as this represents level 0 of your application (also called root directory).
</p>
<CodeHighlight :code="structure" />
<div class="space-y-5">
<h2>Folder start</h2>
<p>
This folder contains the files needed to start the application.<br>
You will find the index, the entry point of the application which initializes the application.
</p>
<CodeHighlight :code="startFolder" />
<AlertInfo>
<template v-slot:label>
Info
</template>
<template v-slot:message>
The <span class="font-bold">index.ts</span> file in the <span class="font-bold">start folder</span> is the entry point for your application.
</template>
</AlertInfo>
</div>
<div class="space-y-5">
<h2>Folder provider</h2>
<p>
Providers are files that have certain methods defined in advance.<br>
You can create them at will as long as they are built in the following way :
</p>
<CodeHighlight :code="providerFolder" />
<AlertInfo>
<template v-slot:label>
Info
</template>
<template v-slot:message>
You can create as many providers as you like, they will be executed in alphabetical order. You can learn more here.
</template>
</AlertInfo>
<p>
These files are read first, even before the recovery of the command files, events...
It can be very interesting to use them to record a default behaviour before the application is ready to run.
</p>
<p>
A concrete example would be the console display of the files instantiated in your application :
</p>
<CodeHighlight :code="providerFile" />
<p>
The <span class="font-bold">context</span> object collects the various file types in your application
</p>
</div>
<div class="space-y-5">
<h2>Folder application</h2>
<p>
The <code class="active">src/</code> folder is the base folder for your project.
This is where you will work.
Please consider this folder as the root of your application.
</p>
<p>
The advantage of considering the <code class="active">src/</code> folder as the base of your application is that you can structure it as you see fit.
It can be interesting to look at design patterns, here are some of them :
</p>
<ul>
<li> Monolithic Architecture vs Microservice</li>
<li> NodeTSkeleton, a clean architecture</li>
<li> Hexagonal Architecture</li>
</ul>
<p>
Please use the <code class="active">factory make:file</code> command to create a file quickly
</p>
</div>
<div class="space-y-5">
<h3>Import with alias</h3>
<p>
The <code class="active">src/</code> folder is the base folder for your project.<br>
To simplify the import of your files, the alias <code class="active">App/</code> is available.<br>
This alias refers to the root folder <code class="active">src/</code>.
</p>
<CodeHighlight :code="aliasImport" />
</div>
<div class="space-y-5">
<h2>Testing</h2>
<p>
It is very important to test your code using unit tests for small features or integration tests for large features.
his folder allows you to write tests on files named <code class="active">foo.spec.ts</code>.
The default test framework used in the Discord Factory framework is ava but you can replace it with any other.
</p>
<AlertWarn>
<template v-slot:label>
Warn
</template>
<template v-slot:message>
Do not neglect unit or integration testing. They are extremely useful in the medium/long term. Indeed, when you develop a new feature, it must not break the existing code, this is called regression.
</template>
</AlertWarn>
<p>
The strict minimum code is as follows :
</p>
<CodeHighlight :code="test" />
<p>
Then you can use the followed command to run your tests :
</p>
<div class="flex items-center space-x-5">
<CodeHighlight code="$ npm install" />
<p class="text-gray-800">or</p>
<CodeHighlight code="$ yarn install" />
</div>
</div>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import Divider from '../../../../components/Divider.vue'
import LinkExternal from '../../../../components/LinkExternal.vue'
import AlertInfo from '../../../../components/AlertInfo.vue'
import AlertWarn from '../../../../components/AlertWarn.vue'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const structure = `
|- node_modules
|- provider
|- src
|- start
|- test
.env
.eslintignore
.eslintrc
.npmignore
LICENSE
README.md
package.json
tsconfig.json`
const startFolder = `
import 'module-alias/register'
import { Factory } from '@discord-factory/core'
Factory.getInstance().setup()`
const providerFolder = `
import { Context, Provider } from '@discord-factory/core'
export default class AppProvider implements Provider {
public async boot(): Promise<void> {
// Your code here
}
public async loadFile(context: Context): Promise<void> {
// Your code here
}
public async ready(): Promise<void> {
// Your code here
}
}`
const providerFile = `
export default class AppProvider implements Provider {
public async boot(): Promise<void> {
// Your code here
}
public async loadFile(context: Context): Promise<void> {
// Create type wrapper
const fileType = {
event: () => console.log(\`The event \${(context as EventEntity).event} is loaded.\`),
command: () => console.log(\`The command \${(context as CommandEntity).label} is loaded.\`),
middleware: () => console.log(\`The middleware with pattern \${(context as MiddlewareEntity).pattern} is loaded.\`),
hook: () => console.log(\`The hook is bind in \${(context as HookEntity).hook} event.\`)
}
// Call the wrapper
fileType[file.type]()
}
public async ready(): Promise<void> {
// Your code here
}
}`
const aliasImport = `
- import Foo from '../../../Foo'
+ import Foo from 'App/Folder/Foo'`
const test = `
import test from 'ava'
test('foo', (t) => {
t.pass()
})`
</script>
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.STRUCTURE)
})
</script>

View File

@@ -1,65 +1,20 @@
<template>
<Documentation title="Example of slash command">
<p>
In the near future, slash commands will completely replace the "prefixed" commands we all know.
Even if these "old commands" will still work because they are based on the messageCreate event, it is important to learn how to use this new medium that discord is introducing.
</p>
<div class="space-y-5">
<h2>Basic reply with embed</h2>
<p>
Returns the instance of the Discord Client linked to the bot.
</p>
<CodeHighlight class="" :code="slashCommandWithEmbed" />
</div>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const slashCommandWithEmbed = `
import { Colors } from '@discord-factory/colorize'
import { BaseSlashCommand, SlashCommand } from '@discord-factory/core'
import { CommandInteraction, TextChannel, MessageEmbed } from 'discord.js'
import { GuildId, Channel, Role } from 'App/Utils/Settings'
@SlashCommand({
scope: [GuildId], 👈 // Or 'GLOBAL' if you want to register globally
options: {
name: 'send-buttons', 👈 // UpperCase isn't valid, please use lowerCase
description: 'Sends buttons in the chat',
options: [],
},
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.BUTTONS)
})
export default class PingCommand implements BaseSlashCommand {
public async run(interaction: CommandInteraction): Promise<void> {
// First, we will create two buttons, one "classic" and the other allowing access to a website
const button = new MessageButton({
label: My button,
emoji: '⚡',
customId: 'myButton',
style: 'SECONDARY', 👈 // Available 'PRIMARY', 'SECONDARY', 'SUCCESS', 'DANGER'
})
const buttonLink = new MessageButton({
label: 'Go to my website',
emoji: '🌐',
url: 'https://discord-factory.com'
})
// Then we create a "line" to which we attach our two buttons
const row = {
type: 'ACTION_ROW',
components: [button, buttonLink] 👈 // You cannot define more than 5 components per row
}
// Then we send the message an emperor or non-emperor message to the user containing our buttons
await interaction.reply({
components: [row] 👈 // You must create a "line" to which you will attach your buttons
ephemeral: true, 👈 // If you want to send the client-side or server-side message
})
}
}`
</script>

View File

@@ -1,64 +1,20 @@
<template>
<Documentation title="Example of slash command">
<p>
In the near future, slash commands will completely replace the "prefixed" commands we all know.
Even if these "old commands" will still work because they are based on the messageCreate event, it is important to learn how to use this new medium that discord is introducing.
</p>
<div class="space-y-5">
<h2>Basic reply with embed</h2>
<p>
First, we need to create an enumeration that will contain our different channels and their associated ID.
</p>
<CodeHighlight class="" :code="enum1" />
<p>
Next, we create the command using the slash command support of discord.js 13.
</p>
<CodeHighlight class="" :code="slashCommandWithEmbed" />
</div>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const enum1 = `
export const GuildId = '583050048766476353'
export enum Channel {
COMMAND = '583050048766476355'
}
`
const slashCommandWithEmbed = `
import { Colors } from '@discord-factory/colorize'
import { BaseSlashCommand, SlashCommand } from '@discord-factory/core'
import { CommandInteraction, TextChannel, MessageEmbed } from 'discord.js'
import { GuildId, Channel, Role } from 'App/Utils/Settings'
@SlashCommand({
scope: [GuildId], 👈 // Or 'GLOBAL' if you want to register globally
options: {
name: 'ping', 👈 // UpperCase isn't valid, please use lowerCase
description: 'Answer pong when the bot returns an answer',
options: [],
},
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.PING_PONG)
})
export default class PingCommand implements BaseSlashCommand {
public async run(interaction: CommandInteraction): Promise<void> {
// First, we design the structure of the embed
const embed = new MessageEmbed({
description: 'Pong !',
color: Colors.INVISIBLE,
})
// Then we send the message an emperor or non-emperor message to the user containing our embed
await interaction.reply({
embed: [embed]
ephemeral: true, 👈 // If you want to send the client-side or server-side message
})
}
}`
</script>

View File

@@ -0,0 +1,20 @@
<template>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.PRESENCE_PROVIDER)
})
</script>

View File

@@ -1,35 +1,27 @@
<template>
<Documentation title="Colorize">
<p>
In the near future, slash commands will completely replace the "prefixed" commands we all know.
Even if these "old commands" will still work because they are based on the messageCreate event, it is important to learn how to use this new medium that discord is introducing.
</p>
<div class="space-y-5">
<h2>How to use</h2>
<p>
Returns the instance of the Discord Client linked to the bot.
</p>
<CodeHighlight class="" :code="slashCommandWithEmbed" />
</div>
<div class="space-y-5">
<h2>Colour palette</h2>
<ColorContainer />
</div>
<Documentation>
<template v-if="data">
<Markdown :source="data" />
<div class="space-y-5">
<h2>Colour palette</h2>
<ColorContainer />
</div>
</template>
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import ColorContainer from '../../../../components/ColorContainer.vue'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const slashCommandWithEmbed = `
import { Colors } from '@discord-factory/colorize'
const embed = new MessageEmbed({
description: 'Description of your embed',
color: Colors.INVISIBLE,
})`
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.COLORIZE)
})
</script>

View File

@@ -0,0 +1,20 @@
<template>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.MESSAGE_COMMAND)
})
</script>

View File

@@ -1,301 +1,20 @@
<template>
<Documentation title="Database storage">
<p>
The <b>@discord-factory/storage</b> module allows you to use a MySQL, PostgreSQL or SQLite database without using an API to make some data persistent.
</p>
<p>
When you develop an application with a discord bot, you will need to regularly store values in order to share them globally with the application.
</p>
<p>
To solve this problem, we have designed a module that simplifies the use of databases such as <b>MySQL</b>, <b>PostgreSQL</b> or <b>SQLite</b>. This module is based on TypeORM.
No more endless lines of code and welcome to modernity, thanks to the <b>storage</b> module you will be able to simplify your life in the creation of a database relationship.
</p>
<div class="space-y-5">
<h2>Installation</h2>
<p>
To be able to use the module, you must have installed it beforehand by following the explanations below :
</p>
<div class="flex items-center space-x-5">
<CodeHighlight code="npm install @discord-factory/storage" />
<p class="text-gray-800">or</p>
<CodeHighlight code="yarn add @discord-factory/storage" />
</div>
<p>
In order to use the module, you will need to start it at the same time as your application through the providers.
</p>
<CodeHighlight :code="providerInit" />
<AlertSuccess>
<template v-slot:label>Success</template>
<template v-slot:message>
Congratulations you just installed the <b>storage</b> module 🎉
</template>
</AlertSuccess>
<p>
Now that the installation is done, we will have to configure the appropriate driver for your use :
</p>
<div>
<h6>SQLite</h6>
<div class="flex items-center space-x-5">
<CodeHighlight code="npm install sqlite3" />
<p class="text-gray-800">or</p>
<CodeHighlight code="yarn add sqlite3" />
</div>
</div>
<div>
<h6>MySQL</h6>
<div class="flex items-center space-x-5">
<CodeHighlight code="npm install mysql" />
<p class="text-gray-800">or</p>
<CodeHighlight code="yarn add mysql" />
</div>
</div>
<div>
<h6>PostgreSQL</h6>
<div class="flex items-center space-x-5">
<CodeHighlight code="npm install pg" />
<p class="text-gray-800">or</p>
<CodeHighlight code="yarn add pg" />
</div>
</div>
<p>
Once the driver is configured, we will detail the functionality of the <b>module</b>, inspired by the <LinkExternal url="https://adonisjs.com/">Adonis</LinkExternal> framework.
It takes its basics in designing a model and a migration.
</p>
<p>
You will say to me that a model or a migration?
</p>
</div>
<div class="space-y-5">
<h2>Model</h2>
<p>
A model is a representation of your table that you can call via its object on your code to use <b>CRUD</b> (Create, Read, Update or Delete).
</p>
<CodeHighlight :code="model" />
<AlertInfo>
<template v-slot:label>Info</template>
<template v-slot:message>
The <b>@PrimaryColumn()</b> represents the primary key of the model (tables) where we will add as data a UUID via a <b>decorator</b> so the <b>BeforeInsert()</b> is a Hook.
</template>
</AlertInfo>
<AlertInfo>
<template v-slot:label>Info</template>
<template v-slot:message>
The <b>@Column()</b> represents a column of the model which will take a <b>property</b> with a primitive typescript type.
</template>
</AlertInfo>
<p>
To create a model, simply run the <b>factory make:file</b> command and select `model`
</p>
</div>
<div class="space-y-5">
<h2>Migration</h2>
<p>
Now that the model representing your table is created, we need to create the corresponding migration to create the table and its columns in your database.
</p>
<CodeHighlight :code="migration" />
<p>
Identique aux migrations de <b>AdonisJS</b> il est assez facile de comprendre son fonctionnement :
</p>
<ul>
<li class="list-disc ml-5"><b>Foo_1624901710168</b> represents the table name and creation timestamp</li>
<li class="list-disc ml-5"><b>name: 'user'</b> represents the name of the table on the database</li>
<li class="list-disc ml-5"><b>columns</b> is an array of JSON information (name, type, options)</li>
</ul>
<p>
Once this is understood, it is fairly easy to create a migration using the framework.
</p>
<p>
To create a migration, simply run the <b>factory make:file</b> command and select <b>migration</b>.
Next, choose the type of file migration and answer the question and answer set that is presented to you. One of the questions will ask you to create or modify a table, if your table has not yet been created, please select Create Table.
</p>
<AlertInfo>
<template v-slot:label>Info</template>
<template v-slot:message>
You can also edit a database if you want to add columns or change existing ones.
When asked to choose the type of migration you want, select <b>Update Table</b> and a file like the one below will be generated.
</template>
</AlertInfo>
<CodeHighlight :code="migrationUpgrade" />
</div>
<div class="space-y-5">
<h2>Migrate to your database</h2>
<p>
Transfer your migrations to the database.
</p>
<CodeHighlight :code="migrateUp" />
</div>
<div class="space-y-5">
<h2>Resetting your database</h2>
<p>
Remove the migrations from the database.
</p>
<CodeHighlight :code="migrateDown" />
</div>
<div class="space-y-5">
<h2>Use the CRUD</h2>
<p>
The computer acronym CRUD designates the four basic operations for data persistence, in particular the storage of information in a database.
These are : <b>Create</b>, <b>Read</b>, <b>Update</b>, <b>Delete</b>.
</p>
<div class="space-y-5">
<div>
<h6>Get all resources</h6>
<CodeHighlight :code="getAll" />
</div>
<div>
<h6>Get one resource</h6>
<CodeHighlight :code="getOne" />
</div>
<div>
<h6>Create resource</h6>
<CodeHighlight :code="post" />
</div>
<div>
<h6>Update resource</h6>
<CodeHighlight :code="put" />
</div>
<div>
<h6>Destroy resource</h6>
<CodeHighlight :code="destroy" />
</div>
</div>
</div>
<Documentation>
<Markdown v-if="data" :source="data" />
<Spinner v-else />
</Documentation>
</template>
<script setup lang="ts">
import Markdown from '../../../../components/Markdown.vue'
import Documentation from '../../../../components/Documentation.vue'
import CodeHighlight from '../../../../components/CodeHighlight.vue'
import ColorContainer from '../../../../components/ColorContainer.vue'
import AlertSuccess from '../../../../components/AlertSuccess.vue'
import LinkExternal from '../../../../components/LinkExternal.vue'
import AlertInfo from '../../../../components/AlertInfo.vue'
import Spinner from '../../../../components/Spinner.vue'
import useDocumentation from '../../../../services/Documentation'
import { markdownEndpoint } from '../../../../utils/Navigation'
import { onMounted, ref } from 'vue'
const providerInit = `
import { Provider } from '@discord-factory/core'
import { useDatabase } from '@discord-factory/storage'
export default class AppProvider implements Provider {
public async boot(): Promise<void> {
/**
* The useDatabase() hook allows you to access
* the initialization of the module in order to operate it.
*/
const { initialize } = useDatabase()
/**
* You will then have to execute the function.
*/
await initialize()
}
}`
const model = `
import { BaseModel, Entity, Column, PrimaryColumn, BeforeInsert, Generate } from '@discord-factory/storage'
@Entity()
export default class User extends BaseModel {
@PrimaryColumn()
public id!: string
@BeforeInsert()
private generateUUID () {
this.id = Generate.generateUUID()
}
@Column()
public username!: string
}`
const migration = `
import { BaseSchema, QueryRunner, Migration, Table } from '@discord-factory/storage'
@Migration()
export default class Foo_1624901710168 extends BaseSchema {
async up(query: QueryRunner): Promise<void> {
await query.createTable(new Table({
name: 'foo',
columns: [
{ name: 'id', type: 'uuid', isPrimary: true },
{ name: 'bar', type: 'varchar'},
],
}), true)
}
async down(query: QueryRunner): Promise<void> {
await query.dropTable('user')
}
}`
const migrationUpgrade = `
import { BaseSchema, QueryRunner, Migration, TableColumn } from '@discord-factory/storage'
@Migration()
export default class User_1624901710168 extends BaseSchema {
async up(query: QueryRunner): Promise<void> {
await query.addColumns('user', [
new TableColumn({ name: 'foo', type: 'string' }),
])
}
async down(query: QueryRunner): Promise<void> {
await query.dropColumns('user', ['foo'])
}
}`
const migrateUp = `
import { useMigrations } from "@discord-factory/storage";
const { migrate } = useMigrations()
await migrate()
`
const migrateDown = `
import { useMigrations } from "@discord-factory/storage";
const { rollback } = useMigrations()
await rollback()
`
const getAll = `
const foo = Foo.find()
console.log(foo)
`
const getOne = `
const foo = Foo.findOne({ where: { id: 1 } })
console.log(foo)
`
const post = `
const foo = Foo.create({
firstname: 'John',
lastname: 'Doe'
const data = ref('')
onMounted(async () => {
data.value = await useDocumentation(markdownEndpoint.STORAGE)
})
await foo.save()
`
const put = `
const foo = Foo.findOne({ where: { id: 1 } })
if (foo) {
await Foo.update(foo, {
firstname: 'John',
lastname: 'Doe'
})
}
`
const destroy = `
const foo = Foo.findOne({ where: { id: 1 } })
await foo?.remove()
`
</script>

View File

@@ -1,6 +1,5 @@
import { NavbarLink } from '../types'
import { github, twitter } from './Icons'
import { CalendarIcon, ChartBarIcon, FolderIcon, HomeIcon, InboxIcon, UsersIcon } from '@heroicons/vue/outline'
export const links: NavbarLink[] = [
{ label: 'Home', path: '/', local: true },
@@ -24,9 +23,8 @@ export const documentation = [
{ label: 'Structure', href: '/documentation/structure', isMenu: false },
{ label: 'Partial Hooks', href: '/documentation/partial-hooks', isMenu: false },
{ label: 'Commands', href: '/documentation/commands', isMenu: false },
{ label: 'Slash Commands', href: '/documentation/slash-commands', isMenu: false },
{ label: 'Context Menu', href: '/documentation/context-menu', isMenu: false },
{ label: 'Events', href: '/documentation/events', isMenu: false },
{ label: 'Middlewares', href: '/documentation/middlewares', isMenu: false },
{ label: 'Hooks', href: '/documentation/hooks', isMenu: false },
]
},
@@ -35,22 +33,55 @@ export const documentation = [
isMenu: true,
child: [
{ label: 'Deployment', href: '/documentation/deployment', isMenu: false },
{ label: 'Addon', href: '/documentation/create-your-addon', isMenu: false },
]
},
{
label: 'Modules',
isMenu: true,
child: [
{ label: 'Message command', href: '/documentation/modules/message-command', isMenu: false },
{ label: 'Colorize', href: '/documentation/modules/colorize', isMenu: false },
{ label: 'Database storage', href: '/documentation/modules/database-storage', isMenu: false },
{ label: 'Storage next', href: '/documentation/modules/database-storage', isMenu: false },
]
},
{
label: 'Example',
isMenu: true,
child: [
{ label: 'Presence with provider', href: '/documentation/examples/presence-with-provider', isMenu: false },
{ label: 'Ping pong', href: '/documentation/examples/ping-pong', isMenu: false },
{ label: 'Buttons', href: '/documentation/examples/buttons', isMenu: false },
]
},
]
export enum markdownEndpoint {
GETTING_STARTED = 'https://raw.githubusercontent.com/DiscordFactory/.github/main/profile/README.md',
STARTING = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/Starting.md',
COMMAND = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/Command.md',
CONTEXT_MENU = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/ContextMenu.md',
APPLICATION_HOOK = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/Application.md',
EVENT = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/Event.md',
STRUCTURE = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/Structure.md',
ENVIRONMENT = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/Environment.md',
HOOK = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/Hook.md',
PRESENCE_PROVIDER = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/exemples/PresenceProvider.md',
PING_PONG = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/exemples/PingPong.md',
BUTTONS = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/exemples/Buttons.md',
MESSAGE_COMMAND = 'https://raw.githubusercontent.com/DiscordFactory/message-commands/master/README.md',
STORAGE = 'https://raw.githubusercontent.com/DiscordFactory/storage-next/master/README.md',
COLORIZE = 'https://raw.githubusercontent.com/DiscordFactory/colorize/master/README.md',
DEPLOYMENT = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/Deployment.md',
ADDON = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/advanced/CreateAddon.md',
PARTIAL_COMMAND = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/partials/Command.md',
PARTIAL_EVENT = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/partials/Event.md',
PARTIAL_CONTEXT_MENU = 'https://raw.githubusercontent.com/DiscordFactory/core/master/doc/partials/ContextMenu.md',
PARTIAL_MODEL = 'https://raw.githubusercontent.com/DiscordFactory/storage-next/master/doc/partials/Model.md',
test = 'https://raw.githubusercontent.com/DiscordFactory/.github/main/README.md',
}

File diff suppressed because it is too large Load Diff

1730
yarn.lock

File diff suppressed because it is too large Load Diff