devcodes-website 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +212 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +104 -0
- package/dist/index.js.map +1 -0
- package/dist/template.d.ts +3 -0
- package/dist/template.d.ts.map +1 -0
- package/dist/template.js +443 -0
- package/dist/template.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# devcodes-website
|
|
2
|
+
|
|
3
|
+
> Instantly generate a beautiful, modern website for any Discord bot.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/devcodes-website)
|
|
6
|
+
[](https://discord.gg/ESh2Dp2xX9)
|
|
7
|
+
|
|
8
|
+
Give your Discord bot a professional landing page in under 10 lines of code. `devcodes-website` generates a fully self-contained, mobile-responsive, dark-themed website served by an Express server — no static files to host, no templates to manage.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- 🎨 **Fully customisable** — change accent colour, background, cards
|
|
15
|
+
- 📊 **Live stats** — server count & user count update dynamically via `setStats()`
|
|
16
|
+
- 🔗 **Invite + Support links** — "Add to Discord" & "Support Server" CTAs built in
|
|
17
|
+
- ⚡ **Commands showcase** — list your commands grouped by category
|
|
18
|
+
- 📦 **Zero config HTML** — completely self-contained, no external assets required (except Google Fonts)
|
|
19
|
+
- 🟦 **TypeScript first** — full type definitions included
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install devcodes-website
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
const { BotWebsite } = require('devcodes-website');
|
|
35
|
+
|
|
36
|
+
const site = new BotWebsite({
|
|
37
|
+
name: 'My Bot',
|
|
38
|
+
tagline: 'The bot your server deserves',
|
|
39
|
+
description: 'A powerful, easy-to-use Discord bot with moderation, music, games and more.',
|
|
40
|
+
avatar: 'https://cdn.discordapp.com/avatars/YOUR_BOT_ID/YOUR_AVATAR.png',
|
|
41
|
+
prefix: '!',
|
|
42
|
+
|
|
43
|
+
serverCount: 150,
|
|
44
|
+
userCount: 12000,
|
|
45
|
+
|
|
46
|
+
inviteUrl: 'https://discord.com/oauth2/authorize?client_id=YOUR_ID&scope=bot',
|
|
47
|
+
supportUrl: 'https://discord.gg/your-server',
|
|
48
|
+
githubUrl: 'https://github.com/you/your-bot',
|
|
49
|
+
|
|
50
|
+
port: 3000,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
site.listen(() => console.log('Website running on http://localhost:3000'));
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Configuration
|
|
59
|
+
|
|
60
|
+
### `BotWebsiteConfig`
|
|
61
|
+
|
|
62
|
+
| Property | Type | Required | Description |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| `name` | `string` | ✅ | Bot display name |
|
|
65
|
+
| `description` | `string` | ✅ | Description paragraph shown in the hero |
|
|
66
|
+
| `tagline` | `string` | | Short one-line tagline shown as gradient text |
|
|
67
|
+
| `avatar` | `string` | | URL to the bot's avatar image |
|
|
68
|
+
| `prefix` | `string` | | Command prefix shown as a hero stat pill |
|
|
69
|
+
| `serverCount` | `number` | | Number of servers the bot is in |
|
|
70
|
+
| `userCount` | `number` | | Number of users the bot can see |
|
|
71
|
+
| `inviteUrl` | `string` | | OAuth2 invite link — renders "Add to Discord" button |
|
|
72
|
+
| `supportUrl` | `string` | | Discord support server invite — renders "Support Server" button |
|
|
73
|
+
| `githubUrl` | `string` | | GitHub repository URL shown in footer |
|
|
74
|
+
| `features` | `BotWebsiteFeature[]` | | Feature highlight cards (4 defaults if omitted) |
|
|
75
|
+
| `commands` | `BotWebsiteCommand[]` | | Commands to showcase — grouped by category |
|
|
76
|
+
| `theme` | `BotWebsiteTheme` | | Color scheme overrides |
|
|
77
|
+
| `port` | `number` | | Port to serve on (default: `3000`) |
|
|
78
|
+
|
|
79
|
+
### `BotWebsiteFeature`
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
{ icon: '🛡️', title: 'Moderation', description: 'Powerful moderation tools.' }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `BotWebsiteCommand`
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
{ name: 'ban', description: 'Ban a member from the server.', category: 'Moderation' }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `BotWebsiteTheme`
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
theme: {
|
|
95
|
+
accent: '#5865f2', // primary color (default: Discord blurple)
|
|
96
|
+
accentSecondary: '#7289da', // hover color
|
|
97
|
+
background: '#0a0a0f', // page background
|
|
98
|
+
backgroundCard: '#12121e', // card background
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Updating Live Stats
|
|
105
|
+
|
|
106
|
+
Call `setStats()` at any time to update the displayed counts without restarting:
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
// With discord.js
|
|
110
|
+
client.on('guildCreate', () => {
|
|
111
|
+
site.setStats({ serverCount: client.guilds.cache.size });
|
|
112
|
+
});
|
|
113
|
+
client.on('guildDelete', () => {
|
|
114
|
+
site.setStats({ serverCount: client.guilds.cache.size });
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The frontend polls `/devcodes-website/stats` and updates the hero stat pills automatically.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Adding Custom Routes
|
|
123
|
+
|
|
124
|
+
The underlying Express app is exposed as `site.app`:
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
site.app.get('/api/custom', (req, res) => {
|
|
128
|
+
res.json({ hello: 'world' });
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
site.listen(3000);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Full discord.js Example
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
const { Client, GatewayIntentBits } = require('discord.js');
|
|
140
|
+
const { BotWebsite } = require('devcodes-website');
|
|
141
|
+
|
|
142
|
+
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
|
143
|
+
|
|
144
|
+
const site = new BotWebsite({
|
|
145
|
+
name: 'Dev Codes Bot',
|
|
146
|
+
tagline: 'The ultimate utility bot',
|
|
147
|
+
description: 'Showcase, moderation, fun commands and more — everything your server needs.',
|
|
148
|
+
prefix: '!',
|
|
149
|
+
inviteUrl: 'https://discord.com/oauth2/authorize?client_id=YOUR_ID&scope=bot',
|
|
150
|
+
supportUrl: 'https://discord.gg/ESh2Dp2xX9',
|
|
151
|
+
theme: { accent: '#5865f2' },
|
|
152
|
+
features: [
|
|
153
|
+
{ icon: '🛡️', title: 'Moderation', description: 'Ban, kick, mute and more.' },
|
|
154
|
+
{ icon: '🎵', title: 'Music', description: 'High-quality music playback.' },
|
|
155
|
+
{ icon: '🎮', title: 'Fun', description: 'Games and fun commands.' },
|
|
156
|
+
{ icon: '📊', title: 'Stats', description: 'Detailed server statistics.' },
|
|
157
|
+
],
|
|
158
|
+
commands: [
|
|
159
|
+
{ name: 'ping', description: 'Check bot latency.', category: 'Utility' },
|
|
160
|
+
{ name: 'help', description: 'List all commands.', category: 'Utility' },
|
|
161
|
+
{ name: 'ban', description: 'Ban a member.', category: 'Moderation' },
|
|
162
|
+
{ name: 'kick', description: 'Kick a member.', category: 'Moderation' },
|
|
163
|
+
{ name: 'play', description: 'Play a song.', category: 'Music' },
|
|
164
|
+
{ name: 'skip', description: 'Skip the current song.',category: 'Music' },
|
|
165
|
+
],
|
|
166
|
+
port: 3000,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
client.once('ready', () => {
|
|
170
|
+
site.setStats({
|
|
171
|
+
serverCount: client.guilds.cache.size,
|
|
172
|
+
userCount: client.users.cache.size,
|
|
173
|
+
});
|
|
174
|
+
site.listen(() => {
|
|
175
|
+
console.log(`Website: http://localhost:3000`);
|
|
176
|
+
console.log(`Bot: ${client.user.tag}`);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
client.on('guildCreate', () => site.setStats({ serverCount: client.guilds.cache.size }));
|
|
181
|
+
client.on('guildDelete', () => site.setStats({ serverCount: client.guilds.cache.size }));
|
|
182
|
+
|
|
183
|
+
client.login(process.env.BOT_TOKEN);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## API
|
|
189
|
+
|
|
190
|
+
### `new BotWebsite(config)`
|
|
191
|
+
Creates the website instance. The Express server is set up but not started.
|
|
192
|
+
|
|
193
|
+
### `site.listen(port?, callback?)`
|
|
194
|
+
Starts the server. Returns the `http.Server` instance.
|
|
195
|
+
|
|
196
|
+
### `site.setStats({ serverCount?, userCount? })`
|
|
197
|
+
Updates live stats. The frontend polls automatically — no restart needed. Chainable.
|
|
198
|
+
|
|
199
|
+
### `site.updateConfig(patch)`
|
|
200
|
+
Patches the config and re-renders the page HTML. Useful for updating bot info at runtime. Chainable.
|
|
201
|
+
|
|
202
|
+
### `site.close(callback?)`
|
|
203
|
+
Gracefully stops the server.
|
|
204
|
+
|
|
205
|
+
### `site.app`
|
|
206
|
+
The raw Express `Application` — add custom middleware or routes.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Support
|
|
211
|
+
|
|
212
|
+
Need help? Join our Discord: **[discord.gg/ESh2Dp2xX9](https://discord.gg/ESh2Dp2xX9)**
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type Express } from 'express';
|
|
2
|
+
import type * as http from 'http';
|
|
3
|
+
import type { BotWebsiteConfig, BotWebsiteStats } from './types';
|
|
4
|
+
export declare class BotWebsite {
|
|
5
|
+
/** The underlying Express app — add your own routes here */
|
|
6
|
+
readonly app: Express;
|
|
7
|
+
private _config;
|
|
8
|
+
private _stats;
|
|
9
|
+
private _server;
|
|
10
|
+
private _cachedHtml;
|
|
11
|
+
constructor(config: BotWebsiteConfig);
|
|
12
|
+
private _setupRoutes;
|
|
13
|
+
/**
|
|
14
|
+
* Update live stats. The frontend polls `/devcodes-website/stats` and
|
|
15
|
+
* will reflect the new numbers automatically.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* const counts = await client.guilds.fetch();
|
|
19
|
+
* site.setStats({ serverCount: counts.size });
|
|
20
|
+
*/
|
|
21
|
+
setStats(stats: BotWebsiteStats): this;
|
|
22
|
+
/**
|
|
23
|
+
* Update any part of the bot config and re-render the page.
|
|
24
|
+
*/
|
|
25
|
+
updateConfig(patch: Partial<BotWebsiteConfig>): this;
|
|
26
|
+
/**
|
|
27
|
+
* Start the web server.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* site.listen(() => console.log('Website live!'));
|
|
31
|
+
* site.listen(4000, () => console.log('Live on :4000'));
|
|
32
|
+
*/
|
|
33
|
+
listen(portOrCallback?: number | (() => void), callback?: () => void): http.Server;
|
|
34
|
+
/** Stop the web server. */
|
|
35
|
+
close(callback?: (err?: Error) => void): void;
|
|
36
|
+
}
|
|
37
|
+
export { BotWebsiteConfig, BotWebsiteStats, BotWebsiteFeature, BotWebsiteCommand, BotWebsiteTheme } from './types';
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,KAAK,OAAO,EAA+B,MAAM,SAAS,CAAC;AAC7E,OAAO,KAAK,KAAK,IAAI,MAAM,MAAM,CAAC;AAClC,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGjE,qBAAa,UAAU;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IAEtB,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,WAAW,CAAS;gBAEhB,MAAM,EAAE,gBAAgB;IAgBpC,OAAO,CAAC,YAAY;IAsBpB;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAWtC;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI;IAMpD;;;;;;OAMG;IACH,MAAM,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;IAmBlF,2BAA2B;IAC3B,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;CAQ9C;AAED,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BotWebsite = void 0;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
const template_1 = require("./template");
|
|
9
|
+
class BotWebsite {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this._server = null;
|
|
12
|
+
this._config = config;
|
|
13
|
+
this._stats = {
|
|
14
|
+
serverCount: config.serverCount,
|
|
15
|
+
userCount: config.userCount,
|
|
16
|
+
};
|
|
17
|
+
this.app = (0, express_1.default)();
|
|
18
|
+
this.app.disable('x-powered-by');
|
|
19
|
+
// Build first render
|
|
20
|
+
this._cachedHtml = (0, template_1.renderPage)(this._config);
|
|
21
|
+
this._setupRoutes();
|
|
22
|
+
}
|
|
23
|
+
_setupRoutes() {
|
|
24
|
+
// Live stats endpoint — polled by the frontend JS
|
|
25
|
+
this.app.get('/devcodes-website/stats', (_req, res) => {
|
|
26
|
+
res.json({
|
|
27
|
+
serverCount: this._stats.serverCount ?? null,
|
|
28
|
+
userCount: this._stats.userCount ?? null,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
// Health check
|
|
32
|
+
this.app.get('/health', (_req, res) => {
|
|
33
|
+
res.json({ status: 'ok', name: this._config.name });
|
|
34
|
+
});
|
|
35
|
+
// Serve the bot website at '/'
|
|
36
|
+
this.app.get('/', (_req, res) => {
|
|
37
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
38
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
39
|
+
res.send(this._cachedHtml);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Update live stats. The frontend polls `/devcodes-website/stats` and
|
|
44
|
+
* will reflect the new numbers automatically.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const counts = await client.guilds.fetch();
|
|
48
|
+
* site.setStats({ serverCount: counts.size });
|
|
49
|
+
*/
|
|
50
|
+
setStats(stats) {
|
|
51
|
+
this._stats = { ...this._stats, ...stats };
|
|
52
|
+
// Rebuild the HTML so initial render also has updated values
|
|
53
|
+
this._cachedHtml = (0, template_1.renderPage)({
|
|
54
|
+
...this._config,
|
|
55
|
+
serverCount: this._stats.serverCount,
|
|
56
|
+
userCount: this._stats.userCount,
|
|
57
|
+
});
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Update any part of the bot config and re-render the page.
|
|
62
|
+
*/
|
|
63
|
+
updateConfig(patch) {
|
|
64
|
+
this._config = { ...this._config, ...patch };
|
|
65
|
+
this._cachedHtml = (0, template_1.renderPage)(this._config);
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Start the web server.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* site.listen(() => console.log('Website live!'));
|
|
73
|
+
* site.listen(4000, () => console.log('Live on :4000'));
|
|
74
|
+
*/
|
|
75
|
+
listen(portOrCallback, callback) {
|
|
76
|
+
let port;
|
|
77
|
+
let cb;
|
|
78
|
+
if (typeof portOrCallback === 'function') {
|
|
79
|
+
port = this._config.port ?? 3000;
|
|
80
|
+
cb = portOrCallback;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
port = portOrCallback ?? this._config.port ?? 3000;
|
|
84
|
+
cb = callback;
|
|
85
|
+
}
|
|
86
|
+
this._server = this.app.listen(port, () => {
|
|
87
|
+
if (cb)
|
|
88
|
+
cb();
|
|
89
|
+
});
|
|
90
|
+
return this._server;
|
|
91
|
+
}
|
|
92
|
+
/** Stop the web server. */
|
|
93
|
+
close(callback) {
|
|
94
|
+
if (this._server) {
|
|
95
|
+
this._server.close(callback);
|
|
96
|
+
this._server = null;
|
|
97
|
+
}
|
|
98
|
+
else if (callback) {
|
|
99
|
+
callback();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.BotWebsite = BotWebsite;
|
|
104
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAqOhD,wBAAgB,UAAU,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAyPxD"}
|
package/dist/template.js
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderPage = renderPage;
|
|
4
|
+
/** Escape a string for safe insertion into HTML text / attribute values */
|
|
5
|
+
function esc(s) {
|
|
6
|
+
return String(s)
|
|
7
|
+
.replace(/&/g, '&')
|
|
8
|
+
.replace(/</g, '<')
|
|
9
|
+
.replace(/>/g, '>')
|
|
10
|
+
.replace(/"/g, '"')
|
|
11
|
+
.replace(/'/g, ''');
|
|
12
|
+
}
|
|
13
|
+
/** Convert a 6-digit hex color to rgba() */
|
|
14
|
+
function hexToRgba(hex, alpha) {
|
|
15
|
+
const h = hex.replace('#', '').padEnd(6, '0');
|
|
16
|
+
try {
|
|
17
|
+
const n = parseInt(h, 16);
|
|
18
|
+
return `rgba(${(n >> 16) & 255},${(n >> 8) & 255},${n & 255},${alpha})`;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return `rgba(88,101,242,${alpha})`;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function generateCSS(accent, accentSec, bg, bgCard, accentGlow) {
|
|
25
|
+
return `
|
|
26
|
+
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
|
27
|
+
:root{
|
|
28
|
+
--accent:${accent};
|
|
29
|
+
--accent-2:${accentSec};
|
|
30
|
+
--accent-glow:${accentGlow};
|
|
31
|
+
--bg:${bg};
|
|
32
|
+
--bg-2:${bg === '#0a0a0f' ? '#0f0f1a' : bg};
|
|
33
|
+
--bg-card:${bgCard};
|
|
34
|
+
--bg-card-2:${bgCard === '#12121e' ? '#1a1a2e' : bgCard};
|
|
35
|
+
--border:rgba(255,255,255,0.07);
|
|
36
|
+
--border-2:rgba(255,255,255,0.12);
|
|
37
|
+
--green:#23d160;--yellow:#f0b429;--grey:#747f8d;
|
|
38
|
+
--text:#e8eaf6;--text-2:#a0a8c0;--text-3:#5a6386;
|
|
39
|
+
--font:'Inter',system-ui,sans-serif;
|
|
40
|
+
--mono:'JetBrains Mono','Fira Code',monospace;
|
|
41
|
+
--radius:12px;--radius-lg:20px;
|
|
42
|
+
--shadow:0 4px 24px rgba(0,0,0,.5);
|
|
43
|
+
--shadow-lg:0 8px 48px rgba(0,0,0,.7);
|
|
44
|
+
--nav-h:64px;
|
|
45
|
+
}
|
|
46
|
+
html{scroll-behavior:smooth}
|
|
47
|
+
body{font-family:var(--font);background:var(--bg);color:var(--text);line-height:1.6;overflow-x:hidden}
|
|
48
|
+
::-webkit-scrollbar{width:6px}
|
|
49
|
+
::-webkit-scrollbar-track{background:var(--bg)}
|
|
50
|
+
::-webkit-scrollbar-thumb{background:var(--bg-card-2);border-radius:3px}
|
|
51
|
+
h1,h2,h3,h4{font-weight:700;line-height:1.2}
|
|
52
|
+
.gradient-text{
|
|
53
|
+
background:linear-gradient(135deg,var(--accent) 0%,#a78bfa 50%,#06b6d4 100%);
|
|
54
|
+
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text
|
|
55
|
+
}
|
|
56
|
+
code{font-family:var(--mono);background:rgba(88,101,242,.12);color:var(--accent-2);padding:2px 6px;border-radius:4px;font-size:.85em}
|
|
57
|
+
.container{width:100%;max-width:1100px;margin:0 auto;padding:0 24px}
|
|
58
|
+
|
|
59
|
+
/* Buttons */
|
|
60
|
+
.btn{display:inline-flex;align-items:center;gap:8px;padding:10px 20px;border-radius:var(--radius);font-family:var(--font);font-size:.9rem;font-weight:600;text-decoration:none;border:none;cursor:pointer;transition:all .2s ease;white-space:nowrap}
|
|
61
|
+
.btn--primary{background:var(--accent);color:#fff;box-shadow:0 0 20px var(--accent-glow)}
|
|
62
|
+
.btn--primary:hover{background:var(--accent-2);transform:translateY(-1px);box-shadow:0 0 32px var(--accent-glow)}
|
|
63
|
+
.btn--ghost{background:transparent;color:var(--text-2);border:1px solid var(--border-2)}
|
|
64
|
+
.btn--ghost:hover{background:var(--bg-card);color:var(--text)}
|
|
65
|
+
.btn--lg{padding:14px 28px;font-size:1rem}
|
|
66
|
+
|
|
67
|
+
/* Nav */
|
|
68
|
+
.nav{position:fixed;top:0;left:0;right:0;height:var(--nav-h);z-index:100;background:rgba(10,10,15,.7);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-bottom:1px solid var(--border);transition:background .3s}
|
|
69
|
+
.nav--scrolled{background:rgba(10,10,15,.92);border-bottom-color:var(--border-2)}
|
|
70
|
+
.nav__inner{display:flex;align-items:center;gap:40px;height:100%;max-width:1100px;margin:0 auto;padding:0 24px}
|
|
71
|
+
.nav__brand{display:flex;align-items:center;gap:10px;text-decoration:none;color:var(--text);font-size:1.05rem;font-weight:700}
|
|
72
|
+
.nav__links{display:flex;gap:28px;list-style:none;margin-left:auto}
|
|
73
|
+
.nav__links a{text-decoration:none;color:var(--text-2);font-size:.88rem;font-weight:500;transition:color .15s}
|
|
74
|
+
.nav__links a:hover{color:var(--text)}
|
|
75
|
+
.nav__cta{margin-left:8px}
|
|
76
|
+
|
|
77
|
+
/* Hero */
|
|
78
|
+
.hero{position:relative;min-height:100vh;display:flex;align-items:center;justify-content:center;text-align:center;overflow:hidden;padding:calc(var(--nav-h) + 60px) 24px 80px}
|
|
79
|
+
.hero__bg{position:absolute;inset:0;pointer-events:none}
|
|
80
|
+
.hero__grid{position:absolute;inset:0;background-image:linear-gradient(rgba(88,101,242,.04) 1px,transparent 1px),linear-gradient(90deg,rgba(88,101,242,.04) 1px,transparent 1px);background-size:48px 48px;mask-image:radial-gradient(ellipse 80% 60% at 50% 40%,black 30%,transparent 70%)}
|
|
81
|
+
.hero__glow{position:absolute;border-radius:50%;filter:blur(80px);opacity:.25}
|
|
82
|
+
.hero__glow--1{width:600px;height:600px;background:var(--accent);top:-100px;left:50%;transform:translateX(-60%);animation:gpulse 6s ease-in-out infinite}
|
|
83
|
+
.hero__glow--2{width:400px;height:400px;background:#a78bfa;bottom:0;right:0;animation:gpulse 8s ease-in-out infinite reverse}
|
|
84
|
+
@keyframes gpulse{0%,100%{opacity:.2;transform:translateX(-60%) scale(1)}50%{opacity:.35;transform:translateX(-60%) scale(1.1)}}
|
|
85
|
+
.hero__content{position:relative;max-width:700px;z-index:1}
|
|
86
|
+
.hero__avatar{width:96px;height:96px;border-radius:50%;overflow:hidden;margin:0 auto 28px;border:2px solid var(--accent);box-shadow:0 0 24px var(--accent-glow),0 0 60px var(--accent-glow);transition:box-shadow .3s;flex-shrink:0}
|
|
87
|
+
.hero__avatar img{width:100%;height:100%;object-fit:cover}
|
|
88
|
+
.avatar__fallback{width:100%;height:100%;background:var(--accent);display:flex;align-items:center;justify-content:center;font-size:2.2rem;font-weight:900;color:#fff}
|
|
89
|
+
.hero__badge{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;background:rgba(88,101,242,.12);border:1px solid rgba(88,101,242,.3);border-radius:100px;font-size:.78rem;font-weight:600;color:var(--accent-2);letter-spacing:.06em;text-transform:uppercase;margin-bottom:24px}
|
|
90
|
+
.badge__dot{width:6px;height:6px;background:var(--green);border-radius:50%;animation:blink 2s ease-in-out infinite}
|
|
91
|
+
@keyframes blink{0%,100%{opacity:1}50%{opacity:.3}}
|
|
92
|
+
.hero__title{font-size:clamp(2.2rem,6vw,3.8rem);font-weight:900;letter-spacing:-.02em;margin-bottom:18px}
|
|
93
|
+
.hero__sub{font-size:clamp(.95rem,2vw,1.1rem);color:var(--text-2);max-width:540px;margin:0 auto 32px}
|
|
94
|
+
.hero__actions{display:flex;justify-content:center;gap:14px;flex-wrap:wrap;margin-bottom:40px}
|
|
95
|
+
.hero__pills{display:flex;justify-content:center;gap:10px;flex-wrap:wrap}
|
|
96
|
+
.stat-pill{display:flex;align-items:center;gap:7px;padding:8px 16px;background:var(--bg-card);border:1px solid var(--border);border-radius:100px;font-size:.83rem}
|
|
97
|
+
.stat-pill__icon{}
|
|
98
|
+
.stat-pill__value{font-weight:700;color:var(--text)}
|
|
99
|
+
.stat-pill__label{color:var(--text-3)}
|
|
100
|
+
.hero__scroll{position:absolute;bottom:32px;left:50%;transform:translateX(-50%);display:flex;flex-direction:column;align-items:center;gap:6px;color:var(--text-3);font-size:.72rem;font-weight:500;letter-spacing:.1em;text-transform:uppercase;animation:sbounce 2.5s ease-in-out infinite}
|
|
101
|
+
@keyframes sbounce{0%,100%{transform:translateX(-50%) translateY(0)}50%{transform:translateX(-50%) translateY(6px)}}
|
|
102
|
+
|
|
103
|
+
/* Sections */
|
|
104
|
+
.section{padding:96px 0}
|
|
105
|
+
.section--dark{background:var(--bg-2)}
|
|
106
|
+
.section__label{font-size:.72rem;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--accent-2);margin-bottom:12px}
|
|
107
|
+
.section__title{font-size:clamp(1.7rem,4vw,2.6rem);font-weight:800;letter-spacing:-.02em;margin-bottom:14px}
|
|
108
|
+
.section__sub{color:var(--text-2);font-size:1rem;max-width:540px;margin-bottom:52px}
|
|
109
|
+
|
|
110
|
+
/* Features */
|
|
111
|
+
.features{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:18px}
|
|
112
|
+
.feature{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:26px 22px;transition:border-color .2s,transform .2s}
|
|
113
|
+
.feature:hover{border-color:${accentGlow.replace(/,[^,]+\)$/, ',0.4)')};transform:translateY(-4px)}
|
|
114
|
+
.feature__icon{font-size:1.9rem;margin-bottom:14px}
|
|
115
|
+
.feature h3{font-size:1rem;margin-bottom:8px}
|
|
116
|
+
.feature p{color:var(--text-2);font-size:.88rem;line-height:1.65}
|
|
117
|
+
|
|
118
|
+
/* Big stats */
|
|
119
|
+
.big-stats{display:flex;justify-content:center;gap:80px;flex-wrap:wrap;margin-top:16px}
|
|
120
|
+
.big-stat{text-align:center}
|
|
121
|
+
.big-stat__value{font-size:clamp(3rem,8vw,5rem);font-weight:900;letter-spacing:-.03em;background:linear-gradient(135deg,var(--accent) 0%,#a78bfa 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;line-height:1;margin-bottom:10px}
|
|
122
|
+
.big-stat__label{font-size:.9rem;font-weight:600;color:var(--text-2);text-transform:uppercase;letter-spacing:.1em}
|
|
123
|
+
|
|
124
|
+
/* Commands */
|
|
125
|
+
.cmd-group{margin-bottom:40px}
|
|
126
|
+
.cmd-group__label{font-size:.72rem;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--accent-2);margin-bottom:14px}
|
|
127
|
+
.cmd-group__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:10px}
|
|
128
|
+
.cmd-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:14px 18px;transition:border-color .2s,transform .2s}
|
|
129
|
+
.cmd-card:hover{border-color:${accentGlow.replace(/,[^,]+\)$/, ',0.4)')};transform:translateY(-2px)}
|
|
130
|
+
.cmd-card__name{margin-bottom:6px}
|
|
131
|
+
.cmd-card__desc{font-size:.83rem;color:var(--text-2);line-height:1.55}
|
|
132
|
+
|
|
133
|
+
/* Footer */
|
|
134
|
+
.footer{background:var(--bg-2);border-top:1px solid var(--border);padding:40px 0}
|
|
135
|
+
.footer__inner{max-width:1100px;margin:0 auto;padding:0 24px;display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap}
|
|
136
|
+
.footer__brand{display:flex;align-items:center;gap:10px;font-weight:600;font-size:1rem}
|
|
137
|
+
.footer__links{display:flex;gap:24px;flex-wrap:wrap}
|
|
138
|
+
.footer__links a{color:var(--text-2);text-decoration:none;font-size:.88rem;transition:color .15s}
|
|
139
|
+
.footer__links a:hover{color:var(--text)}
|
|
140
|
+
.footer__copy{font-size:.78rem;color:var(--text-3)}
|
|
141
|
+
.footer__copy a{color:var(--accent-2);text-decoration:none}
|
|
142
|
+
.footer__copy a:hover{text-decoration:underline}
|
|
143
|
+
|
|
144
|
+
/* Responsive */
|
|
145
|
+
@media(max-width:768px){
|
|
146
|
+
.nav__links{display:none}
|
|
147
|
+
.hero__glow--1{width:300px;height:300px}
|
|
148
|
+
.hero__glow--2{width:200px;height:200px}
|
|
149
|
+
.big-stats{gap:40px}
|
|
150
|
+
.footer__inner{flex-direction:column;text-align:center}
|
|
151
|
+
.footer__links{justify-content:center}
|
|
152
|
+
}
|
|
153
|
+
`;
|
|
154
|
+
}
|
|
155
|
+
function generateJS(serverCount, userCount) {
|
|
156
|
+
return `
|
|
157
|
+
(function(){
|
|
158
|
+
// Nav scroll
|
|
159
|
+
window.addEventListener('scroll',function(){
|
|
160
|
+
var n=document.getElementById('nav');
|
|
161
|
+
if(n) n.classList.toggle('nav--scrolled',window.scrollY>20);
|
|
162
|
+
},{passive:true});
|
|
163
|
+
|
|
164
|
+
// Number formatter
|
|
165
|
+
function fmt(n){ return n.toLocaleString(); }
|
|
166
|
+
|
|
167
|
+
// Count-up animation
|
|
168
|
+
function countUp(el,target,duration){
|
|
169
|
+
duration=duration||1600;
|
|
170
|
+
var start=0,step=target/(duration/16);
|
|
171
|
+
var id=setInterval(function(){
|
|
172
|
+
start=Math.min(start+step,target);
|
|
173
|
+
el.textContent=fmt(Math.floor(start));
|
|
174
|
+
if(start>=target) clearInterval(id);
|
|
175
|
+
},16);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Trigger count-up when big stat enters viewport
|
|
179
|
+
var observed=false;
|
|
180
|
+
var bigEls=document.querySelectorAll('.big-stat__value[data-target]');
|
|
181
|
+
if(bigEls.length&&'IntersectionObserver' in window){
|
|
182
|
+
var obs=new IntersectionObserver(function(entries){
|
|
183
|
+
if(observed) return;
|
|
184
|
+
entries.forEach(function(e){
|
|
185
|
+
if(e.isIntersecting){
|
|
186
|
+
observed=true;
|
|
187
|
+
bigEls.forEach(function(el){
|
|
188
|
+
var t=parseInt(el.getAttribute('data-target'),10);
|
|
189
|
+
if(!isNaN(t)) countUp(el,t);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
},{threshold:0.3});
|
|
194
|
+
bigEls.forEach(function(el){ obs.observe(el); });
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Poll live stats from this server
|
|
198
|
+
fetch('/devcodes-website/stats')
|
|
199
|
+
.then(function(r){ return r.json(); })
|
|
200
|
+
.then(function(d){
|
|
201
|
+
if(d.serverCount!=null){
|
|
202
|
+
var v=document.getElementById('valServers');
|
|
203
|
+
if(v) v.textContent=fmt(d.serverCount);
|
|
204
|
+
var b=document.getElementById('bigServers');
|
|
205
|
+
if(b){ b.setAttribute('data-target',d.serverCount); b.textContent=fmt(d.serverCount); }
|
|
206
|
+
}
|
|
207
|
+
if(d.userCount!=null){
|
|
208
|
+
var v2=document.getElementById('valUsers');
|
|
209
|
+
if(v2) v2.textContent=fmt(d.userCount);
|
|
210
|
+
var b2=document.getElementById('bigUsers');
|
|
211
|
+
if(b2){ b2.setAttribute('data-target',d.userCount); b2.textContent=fmt(d.userCount); }
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
.catch(function(){});
|
|
215
|
+
})();
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
218
|
+
const DISCORD_ICON = `<svg width="18" height="14" viewBox="0 0 24 18" fill="currentColor"><path d="M20.317 1.492a19.79 19.79 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037 19.736 19.736 0 0 0-4.885 1.515.07.07 0 0 0-.032.027C.533 6.168-.32 10.703.099 15.18a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128c.126-.094.252-.192.372-.292a.074.074 0 0 1 .078-.01c3.927 1.793 8.18 1.793 12.061 0a.074.074 0 0 1 .079.01c.12.098.245.198.372.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.84 19.84 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03z"/></svg>`;
|
|
219
|
+
const GITHUB_ICON = `<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>`;
|
|
220
|
+
function renderPage(cfg) {
|
|
221
|
+
const accent = cfg.theme?.accent ?? '#5865f2';
|
|
222
|
+
const accentSec = cfg.theme?.accentSecondary ?? '#7289da';
|
|
223
|
+
const bg = cfg.theme?.background ?? '#0a0a0f';
|
|
224
|
+
const bgCard = cfg.theme?.backgroundCard ?? '#12121e';
|
|
225
|
+
const accentGlow = hexToRgba(accent, 0.35);
|
|
226
|
+
const name = esc(cfg.name);
|
|
227
|
+
const tagline = esc(cfg.tagline ?? 'The bot your server deserves');
|
|
228
|
+
const description = esc(cfg.description);
|
|
229
|
+
const avatarUrl = cfg.avatar ? esc(cfg.avatar) : null;
|
|
230
|
+
const prefix = cfg.prefix ? esc(cfg.prefix) : null;
|
|
231
|
+
const inviteUrl = cfg.inviteUrl ? esc(cfg.inviteUrl) : null;
|
|
232
|
+
const supportUrl = cfg.supportUrl ? esc(cfg.supportUrl) : null;
|
|
233
|
+
const githubUrl = cfg.githubUrl ? esc(cfg.githubUrl) : null;
|
|
234
|
+
const serverCount = cfg.serverCount ?? null;
|
|
235
|
+
const userCount = cfg.userCount ?? null;
|
|
236
|
+
const features = (cfg.features && cfg.features.length > 0) ? cfg.features : [
|
|
237
|
+
{ icon: '⚡', title: 'Lightning Fast', description: 'Responds to every command in milliseconds, even under heavy load.' },
|
|
238
|
+
{ icon: '🛡️', title: 'Reliable & Stable', description: '99.9% uptime with automatic reconnection and fault tolerance built in.' },
|
|
239
|
+
{ icon: '⚙️', title: 'Highly Configurable', description: 'Customise every aspect of the bot to fit your server\'s exact needs.' },
|
|
240
|
+
{ icon: '📖', title: 'Easy to Use', description: 'Simple, intuitive commands with helpful docs and clear error messages.' },
|
|
241
|
+
];
|
|
242
|
+
const commands = cfg.commands ?? [];
|
|
243
|
+
// ── Small pieces ──────────────────────────────────────────────────────────
|
|
244
|
+
const navAvatarHtml = avatarUrl
|
|
245
|
+
? `<img src="${avatarUrl}" alt="${name}" style="width:32px;height:32px;border-radius:50%;object-fit:cover;border:1.5px solid ${accent};box-shadow:0 0 10px ${accentGlow}" />`
|
|
246
|
+
: `<div style="width:32px;height:32px;border-radius:50%;background:${accent};display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1rem;color:#fff">${name.charAt(0)}</div>`;
|
|
247
|
+
const heroAvatarHtml = avatarUrl
|
|
248
|
+
? `<img src="${avatarUrl}" alt="${name} avatar" />`
|
|
249
|
+
: `<div class="avatar__fallback">${name.charAt(0)}</div>`;
|
|
250
|
+
const primaryCta = inviteUrl
|
|
251
|
+
? `<a class="btn btn--primary btn--lg" href="${inviteUrl}" target="_blank" rel="noopener noreferrer">${DISCORD_ICON} Add to Discord</a>`
|
|
252
|
+
: '';
|
|
253
|
+
const supportCta = supportUrl
|
|
254
|
+
? `<a class="btn btn--ghost btn--lg" href="${supportUrl}" target="_blank" rel="noopener noreferrer">${DISCORD_ICON} Support Server</a>`
|
|
255
|
+
: '';
|
|
256
|
+
const serversPill = `
|
|
257
|
+
<div class="stat-pill">
|
|
258
|
+
<span class="stat-pill__icon">🖥️</span>
|
|
259
|
+
<span class="stat-pill__value" id="valServers">${serverCount !== null ? serverCount.toLocaleString() : '—'}</span>
|
|
260
|
+
<span class="stat-pill__label">servers</span>
|
|
261
|
+
</div>`;
|
|
262
|
+
const usersPill = `
|
|
263
|
+
<div class="stat-pill">
|
|
264
|
+
<span class="stat-pill__icon">👥</span>
|
|
265
|
+
<span class="stat-pill__value" id="valUsers">${userCount !== null ? userCount.toLocaleString() : '—'}</span>
|
|
266
|
+
<span class="stat-pill__label">users</span>
|
|
267
|
+
</div>`;
|
|
268
|
+
const prefixPill = prefix ? `
|
|
269
|
+
<div class="stat-pill">
|
|
270
|
+
<span class="stat-pill__icon">💬</span>
|
|
271
|
+
<span class="stat-pill__value">${prefix}</span>
|
|
272
|
+
<span class="stat-pill__label">prefix</span>
|
|
273
|
+
</div>` : '';
|
|
274
|
+
// ── Features ───────────────────────────────────────────────────────────────
|
|
275
|
+
const featureCards = features.map(f => `
|
|
276
|
+
<div class="feature">
|
|
277
|
+
<div class="feature__icon">${esc(f.icon)}</div>
|
|
278
|
+
<h3>${esc(f.title)}</h3>
|
|
279
|
+
<p>${esc(f.description)}</p>
|
|
280
|
+
</div>`).join('');
|
|
281
|
+
// ── Stats section ──────────────────────────────────────────────────────────
|
|
282
|
+
const statsSection = (serverCount !== null || userCount !== null) ? `
|
|
283
|
+
<section class="section section--dark" id="stats">
|
|
284
|
+
<div class="container">
|
|
285
|
+
<div class="section__label">By the numbers</div>
|
|
286
|
+
<h2 class="section__title">Trusted by communities worldwide</h2>
|
|
287
|
+
<div class="big-stats">
|
|
288
|
+
${serverCount !== null ? `<div class="big-stat">
|
|
289
|
+
<div class="big-stat__value" id="bigServers" data-target="${serverCount}">${serverCount.toLocaleString()}</div>
|
|
290
|
+
<div class="big-stat__label">Servers</div>
|
|
291
|
+
</div>` : ''}
|
|
292
|
+
${userCount !== null ? `<div class="big-stat">
|
|
293
|
+
<div class="big-stat__value" id="bigUsers" data-target="${userCount}">${userCount.toLocaleString()}</div>
|
|
294
|
+
<div class="big-stat__label">Users</div>
|
|
295
|
+
</div>` : ''}
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
</section>` : '';
|
|
299
|
+
// ── Commands section ───────────────────────────────────────────────────────
|
|
300
|
+
let commandsSection = '';
|
|
301
|
+
if (commands.length > 0) {
|
|
302
|
+
const categories = [...new Set(commands.map(c => c.category ?? 'General'))];
|
|
303
|
+
const grouped = categories.map(cat => {
|
|
304
|
+
const catCmds = commands.filter(c => (c.category ?? 'General') === cat);
|
|
305
|
+
return `
|
|
306
|
+
<div class="cmd-group">
|
|
307
|
+
<div class="cmd-group__label">${esc(cat)}</div>
|
|
308
|
+
<div class="cmd-group__grid">
|
|
309
|
+
${catCmds.map(c => `<div class="cmd-card">
|
|
310
|
+
<div class="cmd-card__name"><code>${prefix ? esc(prefix) : ''}${esc(c.name)}</code></div>
|
|
311
|
+
<div class="cmd-card__desc">${esc(c.description)}</div>
|
|
312
|
+
</div>`).join('')}
|
|
313
|
+
</div>
|
|
314
|
+
</div>`;
|
|
315
|
+
}).join('');
|
|
316
|
+
commandsSection = `
|
|
317
|
+
<section class="section${(serverCount !== null || userCount !== null) ? '' : ' section--dark'}" id="commands">
|
|
318
|
+
<div class="container">
|
|
319
|
+
<div class="section__label">Commands</div>
|
|
320
|
+
<h2 class="section__title">What can ${name} do?</h2>
|
|
321
|
+
<p class="section__sub">Browse all available commands below.</p>
|
|
322
|
+
${grouped}
|
|
323
|
+
</div>
|
|
324
|
+
</section>`;
|
|
325
|
+
}
|
|
326
|
+
// ── Nav extra links ────────────────────────────────────────────────────────
|
|
327
|
+
const navSupport = supportUrl ? `<li><a href="${supportUrl}" target="_blank" rel="noopener noreferrer">Support</a></li>` : '';
|
|
328
|
+
const navCommands = commands.length > 0 ? `<li><a href="#commands">Commands</a></li>` : '';
|
|
329
|
+
// ── Footer links ───────────────────────────────────────────────────────────
|
|
330
|
+
const footerLinks = [
|
|
331
|
+
inviteUrl ? `<a href="${inviteUrl}" target="_blank" rel="noopener noreferrer">Add to Discord</a>` : '',
|
|
332
|
+
supportUrl ? `<a href="${supportUrl}" target="_blank" rel="noopener noreferrer">Support</a>` : '',
|
|
333
|
+
githubUrl ? `<a href="${githubUrl}" target="_blank" rel="noopener noreferrer">${GITHUB_ICON} GitHub</a>` : '',
|
|
334
|
+
].filter(Boolean).join('');
|
|
335
|
+
// ── CSS & JS ───────────────────────────────────────────────────────────────
|
|
336
|
+
const css = generateCSS(accent, accentSec, bg, bgCard, accentGlow);
|
|
337
|
+
const js = generateJS(serverCount, userCount);
|
|
338
|
+
// ── Full HTML ──────────────────────────────────────────────────────────────
|
|
339
|
+
return `<!DOCTYPE html>
|
|
340
|
+
<html lang="en">
|
|
341
|
+
<head>
|
|
342
|
+
<meta charset="UTF-8" />
|
|
343
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
344
|
+
<title>${name}</title>
|
|
345
|
+
<meta name="description" content="${description}" />
|
|
346
|
+
<meta name="theme-color" content="${accent}" />
|
|
347
|
+
<meta property="og:title" content="${name}" />
|
|
348
|
+
<meta property="og:description" content="${description}" />
|
|
349
|
+
${avatarUrl ? `<meta property="og:image" content="${avatarUrl}" />` : ''}
|
|
350
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
351
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
352
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
|
353
|
+
<style>${css}</style>
|
|
354
|
+
</head>
|
|
355
|
+
<body>
|
|
356
|
+
|
|
357
|
+
<!-- Nav -->
|
|
358
|
+
<nav class="nav" id="nav">
|
|
359
|
+
<div class="nav__inner">
|
|
360
|
+
<a class="nav__brand" href="#">
|
|
361
|
+
${navAvatarHtml}
|
|
362
|
+
<span>${name}</span>
|
|
363
|
+
</a>
|
|
364
|
+
<ul class="nav__links">
|
|
365
|
+
<li><a href="#about">About</a></li>
|
|
366
|
+
<li><a href="#features">Features</a></li>
|
|
367
|
+
${navCommands}
|
|
368
|
+
${navSupport}
|
|
369
|
+
</ul>
|
|
370
|
+
${inviteUrl ? `<a class="btn btn--primary nav__cta" href="${inviteUrl}" target="_blank" rel="noopener noreferrer">Add to Discord</a>` : ''}
|
|
371
|
+
</div>
|
|
372
|
+
</nav>
|
|
373
|
+
|
|
374
|
+
<!-- Hero -->
|
|
375
|
+
<header class="hero">
|
|
376
|
+
<div class="hero__bg">
|
|
377
|
+
<div class="hero__glow hero__glow--1"></div>
|
|
378
|
+
<div class="hero__glow hero__glow--2"></div>
|
|
379
|
+
<div class="hero__grid"></div>
|
|
380
|
+
</div>
|
|
381
|
+
<div class="hero__content">
|
|
382
|
+
<div class="hero__avatar">${heroAvatarHtml}</div>
|
|
383
|
+
<div class="hero__badge">
|
|
384
|
+
<span class="badge__dot"></span>
|
|
385
|
+
Discord Bot
|
|
386
|
+
</div>
|
|
387
|
+
<h1 class="hero__title">
|
|
388
|
+
${name}<br />
|
|
389
|
+
<span class="gradient-text">${tagline}</span>
|
|
390
|
+
</h1>
|
|
391
|
+
<p class="hero__sub">${description}</p>
|
|
392
|
+
<div class="hero__actions">
|
|
393
|
+
${primaryCta}
|
|
394
|
+
${supportCta}
|
|
395
|
+
</div>
|
|
396
|
+
<div class="hero__pills">
|
|
397
|
+
${serversPill}
|
|
398
|
+
${usersPill}
|
|
399
|
+
${prefixPill}
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
<div class="hero__scroll">
|
|
403
|
+
<span>Scroll</span>
|
|
404
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12l7 7 7-7"/></svg>
|
|
405
|
+
</div>
|
|
406
|
+
</header>
|
|
407
|
+
|
|
408
|
+
<!-- Features -->
|
|
409
|
+
<section class="section" id="about">
|
|
410
|
+
<div class="container">
|
|
411
|
+
<div class="section__label" id="features">Features</div>
|
|
412
|
+
<h2 class="section__title">Why choose ${name}?</h2>
|
|
413
|
+
<p class="section__sub">Everything you need, nothing you don't.</p>
|
|
414
|
+
<div class="features">
|
|
415
|
+
${featureCards}
|
|
416
|
+
</div>
|
|
417
|
+
</div>
|
|
418
|
+
</section>
|
|
419
|
+
|
|
420
|
+
${statsSection}
|
|
421
|
+
${commandsSection}
|
|
422
|
+
|
|
423
|
+
<!-- Footer -->
|
|
424
|
+
<footer class="footer">
|
|
425
|
+
<div class="footer__inner">
|
|
426
|
+
<div class="footer__brand">
|
|
427
|
+
${navAvatarHtml}
|
|
428
|
+
<span>${name}</span>
|
|
429
|
+
</div>
|
|
430
|
+
<div class="footer__links">
|
|
431
|
+
${footerLinks}
|
|
432
|
+
</div>
|
|
433
|
+
<p class="footer__copy">
|
|
434
|
+
Powered by <a href="https://www.npmjs.com/package/devcodes-website" target="_blank" rel="noopener noreferrer">devcodes-website</a>
|
|
435
|
+
</p>
|
|
436
|
+
</div>
|
|
437
|
+
</footer>
|
|
438
|
+
|
|
439
|
+
<script>${js}</script>
|
|
440
|
+
</body>
|
|
441
|
+
</html>`;
|
|
442
|
+
}
|
|
443
|
+
//# sourceMappingURL=template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":";;AAqOA,gCAyPC;AA5dD,2EAA2E;AAC3E,SAAS,GAAG,CAAC,CAAS;IACpB,OAAO,MAAM,CAAC,CAAC,CAAC;SACb,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,4CAA4C;AAC5C,SAAS,SAAS,CAAC,GAAW,EAAE,KAAa;IAC3C,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC9C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1B,OAAO,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,mBAAmB,KAAK,GAAG,CAAC;IACrC,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAClB,MAAc,EACd,SAAiB,EACjB,EAAU,EACV,MAAc,EACd,UAAkB;IAElB,OAAO;;;aAGI,MAAM;eACJ,SAAS;kBACN,UAAU;SACnB,EAAE;WACA,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;cAC9B,MAAM;gBACJ,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA+E3B,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC;;;;;;;;;;;;;;;;+BAgBvC,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;CAwBtE,CAAC;AACF,CAAC;AAED,SAAS,UAAU,CAAC,WAA0B,EAAE,SAAwB;IACtE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4DR,CAAC;AACF,CAAC;AAED,MAAM,YAAY,GAAG,u4BAAu4B,CAAC;AAE75B,MAAM,WAAW,GAAG,gyBAAgyB,CAAC;AAErzB,SAAgB,UAAU,CAAC,GAAqB;IAC9C,MAAM,MAAM,GAAO,GAAG,CAAC,KAAK,EAAE,MAAM,IAAa,SAAS,CAAC;IAC3D,MAAM,SAAS,GAAI,GAAG,CAAC,KAAK,EAAE,eAAe,IAAI,SAAS,CAAC;IAC3D,MAAM,EAAE,GAAW,GAAG,CAAC,KAAK,EAAE,UAAU,IAAS,SAAS,CAAC;IAC3D,MAAM,MAAM,GAAO,GAAG,CAAC,KAAK,EAAE,cAAc,IAAK,SAAS,CAAC;IAC3D,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAE3C,MAAM,IAAI,GAAU,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,OAAO,GAAO,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,8BAA8B,CAAC,CAAC;IACvE,MAAM,WAAW,GAAG,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,SAAS,GAAK,GAAG,CAAC,MAAM,CAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAG,CAAC,CAAC,IAAI,CAAC;IAC5D,MAAM,MAAM,GAAQ,GAAG,CAAC,MAAM,CAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAG,CAAC,CAAC,IAAI,CAAC;IAC5D,MAAM,SAAS,GAAK,GAAG,CAAC,SAAS,CAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAE,CAAC,CAAC,IAAI,CAAC;IAChE,MAAM,UAAU,GAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChE,MAAM,SAAS,GAAK,GAAG,CAAC,SAAS,CAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAE,CAAC,CAAC,IAAI,CAAC;IAEhE,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC;IAC5C,MAAM,SAAS,GAAK,GAAG,CAAC,SAAS,IAAM,IAAI,CAAC;IAE5C,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC1E,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,gBAAgB,EAAO,WAAW,EAAE,mEAAmE,EAAE;QAC7H,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAI,WAAW,EAAE,wEAAwE,EAAE;QACpI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,sEAAsE,EAAE;QACjI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAW,WAAW,EAAE,wEAAwE,EAAE;KACrI,CAAC;IAEF,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;IAEpC,6EAA6E;IAE7E,MAAM,aAAa,GAAG,SAAS;QAC7B,CAAC,CAAC,aAAa,SAAS,UAAU,IAAI,yFAAyF,MAAM,wBAAwB,UAAU,MAAM;QAC7K,CAAC,CAAC,mEAAmE,MAAM,sGAAsG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE1M,MAAM,cAAc,GAAG,SAAS;QAC9B,CAAC,CAAC,aAAa,SAAS,UAAU,IAAI,aAAa;QACnD,CAAC,CAAC,iCAAiC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE5D,MAAM,UAAU,GAAG,SAAS;QAC1B,CAAC,CAAC,6CAA6C,SAAS,+CAA+C,YAAY,qBAAqB;QACxI,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,UAAU,GAAG,UAAU;QAC3B,CAAC,CAAC,2CAA2C,UAAU,+CAA+C,YAAY,qBAAqB;QACvI,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,WAAW,GAAG;;;qDAG+B,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,GAAG;;SAErG,CAAC;IAER,MAAM,SAAS,GAAG;;;mDAG+B,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,GAAG;;SAE/F,CAAC;IAER,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC;;;qCAGO,MAAM;;SAElC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEb,8EAA8E;IAE9E,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;;iCAER,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;UAClC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;SACb,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;SAClB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAElB,8EAA8E;IAE9E,MAAM,YAAY,GAAG,CAAC,WAAW,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;;;;;;UAM5D,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC;sEACqC,WAAW,KAAK,WAAW,CAAC,cAAc,EAAE;;eAEnG,CAAC,CAAC,CAAC,EAAE;UACV,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC;oEACqC,SAAS,KAAK,SAAS,CAAC,cAAc,EAAE;;eAE7F,CAAC,CAAC,CAAC,EAAE;;;aAGP,CAAC,CAAC,CAAC,EAAE,CAAC;IAEjB,8EAA8E;IAE9E,IAAI,eAAe,GAAG,EAAE,CAAC;IACzB,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;QAC5E,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YACnC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC;YACxE,OAAO;;wCAE2B,GAAG,CAAC,GAAG,CAAC;;YAEpC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gDACmB,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;0CAC7C,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;iBAC3C,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;aAEd,CAAC;QACV,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,eAAe,GAAG;2BACK,CAAC,WAAW,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB;;;4CAGnD,IAAI;;QAExC,OAAO;;aAEF,CAAC;IACZ,CAAC;IAED,8EAA8E;IAE9E,MAAM,UAAU,GAAI,UAAU,CAAC,CAAC,CAAC,gBAAgB,UAAU,8DAA8D,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/H,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,2CAA2C,CAAC,CAAC,CAAC,EAAE,CAAC;IAE3F,8EAA8E;IAE9E,MAAM,WAAW,GAAG;QAClB,SAAS,CAAC,CAAC,CAAC,YAAY,SAAS,gEAAgE,CAAC,CAAC,CAAC,EAAE;QACtG,UAAU,CAAC,CAAC,CAAC,YAAY,UAAU,yDAAyD,CAAC,CAAC,CAAC,EAAE;QACjG,SAAS,CAAE,CAAC,CAAC,YAAY,SAAS,gDAAgD,WAAW,aAAa,CAAC,CAAC,CAAC,EAAE;KAChH,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAE3B,8EAA8E;IAE9E,MAAM,GAAG,GAAG,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IACnE,MAAM,EAAE,GAAI,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAE/C,8EAA8E;IAE9E,OAAO;;;;;WAKE,IAAI;sCACuB,WAAW;sCACX,MAAM;uCACL,IAAI;6CACE,WAAW;IACpD,SAAS,CAAC,CAAC,CAAC,sCAAsC,SAAS,MAAM,CAAC,CAAC,CAAC,EAAE;;;;WAI/D,GAAG;;;;;;;;UAQJ,aAAa;gBACP,IAAI;;;;;UAKV,WAAW;UACX,UAAU;;QAEZ,SAAS,CAAC,CAAC,CAAC,8CAA8C,SAAS,gEAAgE,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;kCAY9G,cAAc;;;;;;UAMtC,IAAI;sCACwB,OAAO;;6BAEhB,WAAW;;UAE9B,UAAU;UACV,UAAU;;;UAGV,WAAW;UACX,SAAS;UACT,UAAU;;;;;;;;;;;;;8CAa0B,IAAI;;;UAGxC,YAAY;;;;;IAKlB,YAAY;IACZ,eAAe;;;;;;UAMT,aAAa;gBACP,IAAI;;;UAGV,WAAW;;;;;;;;YAQT,EAAE;;QAEN,CAAC;AACT,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export interface BotWebsiteFeature {
|
|
2
|
+
/** Emoji or short text icon */
|
|
3
|
+
icon: string;
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
}
|
|
7
|
+
export interface BotWebsiteCommand {
|
|
8
|
+
/** Command name (without prefix) */
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
/** Optional category — commands are grouped by category */
|
|
12
|
+
category?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface BotWebsiteTheme {
|
|
15
|
+
/** Primary accent color as CSS hex (default: '#5865f2') */
|
|
16
|
+
accent?: string;
|
|
17
|
+
/** Secondary / hover accent color as CSS hex (default: '#7289da') */
|
|
18
|
+
accentSecondary?: string;
|
|
19
|
+
/** Page background color as CSS hex (default: '#0a0a0f') */
|
|
20
|
+
background?: string;
|
|
21
|
+
/** Card background color as CSS hex (default: '#12121e') */
|
|
22
|
+
backgroundCard?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface BotWebsiteStats {
|
|
25
|
+
/** Number of servers / guilds the bot is in */
|
|
26
|
+
serverCount?: number;
|
|
27
|
+
/** Number of unique users the bot can see */
|
|
28
|
+
userCount?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface BotWebsiteConfig {
|
|
31
|
+
/** Bot display name */
|
|
32
|
+
name: string;
|
|
33
|
+
/** Short hero tagline (shown as gradient text below the name) */
|
|
34
|
+
tagline?: string;
|
|
35
|
+
/** Full description paragraph shown in the hero */
|
|
36
|
+
description: string;
|
|
37
|
+
/** URL to the bot's avatar image */
|
|
38
|
+
avatar?: string;
|
|
39
|
+
/** Command prefix — shown as a stat pill (e.g. '!') */
|
|
40
|
+
prefix?: string;
|
|
41
|
+
/** Number of servers/guilds the bot is currently in */
|
|
42
|
+
serverCount?: number;
|
|
43
|
+
/** Number of users the bot can see */
|
|
44
|
+
userCount?: number;
|
|
45
|
+
/** Discord OAuth2 invite link — renders "Add to Discord" CTA */
|
|
46
|
+
inviteUrl?: string;
|
|
47
|
+
/** Discord support server invite URL — renders "Support Server" button */
|
|
48
|
+
supportUrl?: string;
|
|
49
|
+
/** GitHub repository URL */
|
|
50
|
+
githubUrl?: string;
|
|
51
|
+
/** Feature highlight cards (defaults to 4 generic cards if omitted) */
|
|
52
|
+
features?: BotWebsiteFeature[];
|
|
53
|
+
/** Commands to showcase — grouped by category */
|
|
54
|
+
commands?: BotWebsiteCommand[];
|
|
55
|
+
/** Color scheme overrides */
|
|
56
|
+
theme?: BotWebsiteTheme;
|
|
57
|
+
/** Port to serve the website on (default: 3000) */
|
|
58
|
+
port?: number;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAE/B,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC/B,iDAAiD;IACjD,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAG/B,6BAA6B;IAC7B,KAAK,CAAC,EAAE,eAAe,CAAC;IAGxB,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "devcodes-website",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Instantly generate a beautiful, modern website for any Discord bot. Powered by devcodes. Customise colours, features, commands, stats and more.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=16.9.0"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"discord",
|
|
21
|
+
"discord-bot",
|
|
22
|
+
"bot-website",
|
|
23
|
+
"bot-landing-page",
|
|
24
|
+
"devcodes",
|
|
25
|
+
"express",
|
|
26
|
+
"typescript"
|
|
27
|
+
],
|
|
28
|
+
"author": "azaresw",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/azaresw/devcodes-website.git"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://discord.gg/ESh2Dp2xX9"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"express": "^4.19.2"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/express": "^4.17.21",
|
|
42
|
+
"@types/node": "^20.11.5",
|
|
43
|
+
"typescript": "^5.3.3"
|
|
44
|
+
}
|
|
45
|
+
}
|