djs-builder 0.6.401 → 0.7.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 +292 -43
- package/function/dash.js +638 -0
- package/function/giveaway.js +47 -10
- package/function/security.js +0 -0
- package/handler/starter.js +73 -38
- package/package.json +9 -4
- package/views/404.ejs +40 -0
- package/views/dashboard.ejs +894 -0
- package/views/giveaways.ejs +306 -0
- package/views/guild.ejs +576 -0
- package/views/index.ejs +419 -0
- package/views/levels.ejs +326 -0
- package/views/login.ejs +437 -0
package/function/giveaway.js
CHANGED
|
@@ -9,6 +9,7 @@ const giveawaySchema = new Schema({
|
|
|
9
9
|
hoster: { type: String, required: true },
|
|
10
10
|
endEmbed: { type: Object, required: true },
|
|
11
11
|
winnerCount: { type: Number, default: 1 },
|
|
12
|
+
prize: { type: String, required: true },
|
|
12
13
|
winners: Array,
|
|
13
14
|
paused: { type: Boolean, default: false },
|
|
14
15
|
pausedTime: Array,
|
|
@@ -19,6 +20,7 @@ const giveawaySchema = new Schema({
|
|
|
19
20
|
enum: ["reaction", "button"],
|
|
20
21
|
default: "reaction",
|
|
21
22
|
},
|
|
23
|
+
requiredRoles: { type: [String], default: [] },
|
|
22
24
|
|
|
23
25
|
users: { type: [String], default: [] },
|
|
24
26
|
});
|
|
@@ -32,6 +34,7 @@ async function Gstart({
|
|
|
32
34
|
endTime: endTime,
|
|
33
35
|
winers: winnerCount,
|
|
34
36
|
channelId: channelId,
|
|
37
|
+
prize: prize,
|
|
35
38
|
embed: {
|
|
36
39
|
custom: Scustom = false,
|
|
37
40
|
title: Stitle = false,
|
|
@@ -53,13 +56,15 @@ async function Gstart({
|
|
|
53
56
|
emoji: emoji = false,
|
|
54
57
|
label: label = false,
|
|
55
58
|
style: style = false,
|
|
56
|
-
id
|
|
59
|
+
id: id = false,
|
|
57
60
|
},
|
|
61
|
+
requirements: { requiredRoles: requiredRoles = [] } = {},
|
|
58
62
|
}) {
|
|
59
63
|
if (!winnerCount) winnerCount = 1;
|
|
60
64
|
if (!endTime) return { error: "End time is required." };
|
|
61
65
|
if (!channelId) return { error: "Channel ID is required." };
|
|
62
66
|
if (!context) return { error: "Context is required." };
|
|
67
|
+
if (!prize) return { error: "Prize is required." };
|
|
63
68
|
|
|
64
69
|
if (type === "reaction" && !emoji) return { error: "Emoji is not required." };
|
|
65
70
|
|
|
@@ -91,11 +96,20 @@ async function Gstart({
|
|
|
91
96
|
if (Sthumbnail) embed.setThumbnail(Sthumbnail);
|
|
92
97
|
}
|
|
93
98
|
|
|
99
|
+
let requirementsText = "";
|
|
100
|
+
if (requiredRoles.length > 0) {
|
|
101
|
+
requirementsText = `\n- Required Roles: ${requiredRoles
|
|
102
|
+
.map((r) => `<@&${r}>`)
|
|
103
|
+
.join(", ")}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
94
106
|
embed.addFields({
|
|
95
107
|
name: "🎉 Giveaway",
|
|
96
|
-
value: `-
|
|
108
|
+
value: `- Prize: ${prize}\n- Winner(s) : ${winnerCount}\n- Time : <t:${Math.floor(
|
|
97
109
|
endTime / 1000
|
|
98
|
-
)}:R>\n- Hosted By : ${
|
|
110
|
+
)}:R>\n- Hosted By : ${
|
|
111
|
+
context.user ? context.user : context.author
|
|
112
|
+
}${requirementsText}`,
|
|
99
113
|
inline: true,
|
|
100
114
|
});
|
|
101
115
|
|
|
@@ -124,7 +138,7 @@ async function Gstart({
|
|
|
124
138
|
|
|
125
139
|
end_embed.addFields({
|
|
126
140
|
name: "🎉 Giveaway",
|
|
127
|
-
value: `-
|
|
141
|
+
value: `- Prize: ${prize}\n- Winner(s): ${winnerCount}\n- Time : <t:${Math.floor(
|
|
128
142
|
endTime / 1000
|
|
129
143
|
)}:R>\n- Hosted By : ${context.user ? context.user : context.author}`,
|
|
130
144
|
inline: true,
|
|
@@ -136,6 +150,7 @@ async function Gstart({
|
|
|
136
150
|
messageId: message.id,
|
|
137
151
|
hoster: context.user ? context.user.id : context.author.id,
|
|
138
152
|
endTime: endTime,
|
|
153
|
+
prize: prize,
|
|
139
154
|
endType: false,
|
|
140
155
|
paused: false,
|
|
141
156
|
pausedTime: [],
|
|
@@ -145,6 +160,7 @@ async function Gstart({
|
|
|
145
160
|
reaction: type,
|
|
146
161
|
endEmbed: end_embed.toJSON(),
|
|
147
162
|
users: [],
|
|
163
|
+
requiredRoles: requiredRoles,
|
|
148
164
|
});
|
|
149
165
|
|
|
150
166
|
if (type === "reaction") message.react(emoji);
|
|
@@ -293,6 +309,7 @@ async function Glist(type) {
|
|
|
293
309
|
|
|
294
310
|
const list = giveaways.map((g) => {
|
|
295
311
|
return {
|
|
312
|
+
prize: g.prize,
|
|
296
313
|
messageId: g.messageId,
|
|
297
314
|
guildId: g.guildId,
|
|
298
315
|
channelId: g.channelId,
|
|
@@ -328,7 +345,7 @@ async function Gpause(client, messageId) {
|
|
|
328
345
|
|
|
329
346
|
message.embeds[0].data.fields.find(
|
|
330
347
|
(f) => f.name === "🎉 Giveaway"
|
|
331
|
-
).value = `-
|
|
348
|
+
).value = `- Winner(s): ${g.winnerCount}\n- Time : Pause ⏸️\n- Hosted By : <@${g.hoster}>`;
|
|
332
349
|
|
|
333
350
|
await message.edit({ embeds: [message.embeds[0]] });
|
|
334
351
|
await giveaway.findOneAndUpdate(
|
|
@@ -343,7 +360,7 @@ async function Gresume(client, messageId) {
|
|
|
343
360
|
const g = await giveaway.findOne({ messageId });
|
|
344
361
|
if (!g) return { error: "❌ Giveaway Data Not Found" };
|
|
345
362
|
|
|
346
|
-
if (g.paused ===
|
|
363
|
+
if (g.paused === false) return { error: "❌ Giveaway Already Paused" };
|
|
347
364
|
if (g.ended === true) return { error: "❌ Giveaway Already Ended" };
|
|
348
365
|
|
|
349
366
|
const guild = await client.guilds.cache.get(g.guildId);
|
|
@@ -356,7 +373,7 @@ async function Gresume(client, messageId) {
|
|
|
356
373
|
|
|
357
374
|
message.embeds[0].data.fields.find(
|
|
358
375
|
(f) => f.name === "🎉 Giveaway"
|
|
359
|
-
).value = `-
|
|
376
|
+
).value = `- Winner(s): ${g.winnerCount}\n- Time : <t:${Math.floor(
|
|
360
377
|
time / 1000
|
|
361
378
|
)}:R>\n- Hosted By : <@${g.hoster}>`;
|
|
362
379
|
|
|
@@ -386,13 +403,32 @@ async function Gdelete(messageId) {
|
|
|
386
403
|
}
|
|
387
404
|
|
|
388
405
|
////////////////////////////////////* Giveaway Add User
|
|
389
|
-
async function GaddUser(messageId, userId) {
|
|
406
|
+
async function GaddUser(messageId, userId, guild) {
|
|
390
407
|
const g = await giveaway.findOne({ messageId });
|
|
391
408
|
if (!g) return { error: "❌ Giveaway Data Not Found" };
|
|
392
409
|
|
|
410
|
+
if (g.ended) return { error: "❌ Giveaway Already Ended" };
|
|
411
|
+
|
|
393
412
|
const all_users = g.users || [];
|
|
394
413
|
if (all_users.includes(userId)) return { error: "❌ User Already Joined" };
|
|
395
414
|
|
|
415
|
+
if (g.requiredRoles && g.requiredRoles.length > 0) {
|
|
416
|
+
if (!guild) return { error: "❌ Guild object is required to check roles." };
|
|
417
|
+
const member = await guild.members.fetch(userId).catch(() => null);
|
|
418
|
+
if (!member) return { error: "❌ Member not found in guild." };
|
|
419
|
+
|
|
420
|
+
const hasRole = g.requiredRoles.some((roleId) =>
|
|
421
|
+
member.roles.cache.has(roleId)
|
|
422
|
+
);
|
|
423
|
+
if (!hasRole) {
|
|
424
|
+
return {
|
|
425
|
+
error: `❌ You need one of the following roles to join: ${g.requiredRoles
|
|
426
|
+
.map((r) => `<@&${r}>`)
|
|
427
|
+
.join(", ")}`,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
396
432
|
if (!all_users.includes(userId)) {
|
|
397
433
|
all_users.push(userId);
|
|
398
434
|
await giveaway.findOneAndUpdate({ messageId }, { users: all_users });
|
|
@@ -434,7 +470,7 @@ async function GaddTime(messageId, client, time) {
|
|
|
434
470
|
|
|
435
471
|
message.embeds[0].data.fields.find(
|
|
436
472
|
(f) => f.name === "🎉 Giveaway"
|
|
437
|
-
).value = `-
|
|
473
|
+
).value = `- Winner(s): ${g.winnerCount}\n- Time : <t:${Math.floor(
|
|
438
474
|
finel_time / 1000
|
|
439
475
|
)}:R>\n- Hosted By : <@${g.hoster}>`;
|
|
440
476
|
|
|
@@ -466,7 +502,7 @@ async function GremoveTime(messageId, client, time) {
|
|
|
466
502
|
|
|
467
503
|
message.embeds[0].data.fields.find(
|
|
468
504
|
(f) => f.name === "🎉 Giveaway"
|
|
469
|
-
).value = `-
|
|
505
|
+
).value = `- Winner(s): ${g.winnerCount}\n- Time : <t:${Math.floor(
|
|
470
506
|
finel_time / 1000
|
|
471
507
|
)}:R>\n- Hosted By : <@${g.hoster}>`;
|
|
472
508
|
|
|
@@ -487,6 +523,7 @@ async function Gdata(messageId) {
|
|
|
487
523
|
}
|
|
488
524
|
|
|
489
525
|
module.exports = {
|
|
526
|
+
giveaway,
|
|
490
527
|
Gstart,
|
|
491
528
|
Gcheck,
|
|
492
529
|
Greroll,
|
|
File without changes
|
package/handler/starter.js
CHANGED
|
@@ -150,7 +150,13 @@ async function starter(client, options) {
|
|
|
150
150
|
const events = options.events || null;
|
|
151
151
|
const anticrash = options.anticrash || null;
|
|
152
152
|
const terminal = options.terminal || null;
|
|
153
|
+
const dashboard = options.dashboard || null;
|
|
153
154
|
|
|
155
|
+
//////////////////////////////////////////? Dashboard Loader ////////////////////////////////////////////////////////
|
|
156
|
+
if (dashboard) {
|
|
157
|
+
await dashboard(client, dashboard);
|
|
158
|
+
}
|
|
159
|
+
//////////////////////////////////////////! terminal info !////////////////////////////////////////////////////////
|
|
154
160
|
if (terminal) {
|
|
155
161
|
console.log("🚀 Bot is starting...");
|
|
156
162
|
}
|
|
@@ -260,12 +266,13 @@ async function starter(client, options) {
|
|
|
260
266
|
if (command.guildOnly && !message.guild) return;
|
|
261
267
|
if (command.dmOnly && message.guild) return;
|
|
262
268
|
if (command.devOnly && message.author.id !== client.owner.id) return;
|
|
263
|
-
if (
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
+
if (command.ownerOnly) {
|
|
270
|
+
if (
|
|
271
|
+
message.guild &&
|
|
272
|
+
message.author.id !== (await message.guild.fetchOwner()).id
|
|
273
|
+
)
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
269
276
|
|
|
270
277
|
if (
|
|
271
278
|
command.Permissions &&
|
|
@@ -274,11 +281,13 @@ async function starter(client, options) {
|
|
|
274
281
|
)
|
|
275
282
|
return;
|
|
276
283
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
284
|
+
if (command.Blacklist) {
|
|
285
|
+
const userBlacklisted = await isBlacklisted(
|
|
286
|
+
message.guild ? message.guild.id : null,
|
|
287
|
+
"user",
|
|
288
|
+
message.author.id
|
|
289
|
+
);
|
|
290
|
+
if (userBlacklisted) {
|
|
282
291
|
return message.reply({
|
|
283
292
|
content: "`❌` You are blacklisted from using bot commands.",
|
|
284
293
|
flags: 64,
|
|
@@ -287,23 +296,33 @@ async function starter(client, options) {
|
|
|
287
296
|
|
|
288
297
|
let roleBlacklist = null;
|
|
289
298
|
for (const [id, role] of message.member.roles.cache) {
|
|
290
|
-
const isBlocked = await isBlacklisted(
|
|
299
|
+
const isBlocked = await isBlacklisted(
|
|
300
|
+
message.guild ? message.guild.id : null,
|
|
301
|
+
"role",
|
|
302
|
+
id
|
|
303
|
+
);
|
|
291
304
|
if (isBlocked) {
|
|
292
305
|
roleBlacklist = isBlocked;
|
|
293
306
|
break;
|
|
294
307
|
}
|
|
295
308
|
}
|
|
296
|
-
|
|
297
|
-
if(roleBlacklist) {
|
|
309
|
+
|
|
310
|
+
if (roleBlacklist) {
|
|
298
311
|
const role = message.guild.roles.cache.get(roleBlacklist.id);
|
|
299
312
|
return message.reply({
|
|
300
|
-
content: `\`❌\` The role **${
|
|
313
|
+
content: `\`❌\` The role **${
|
|
314
|
+
role ? role.name : "Unknown"
|
|
315
|
+
}** is blacklisted from using bot commands.`,
|
|
301
316
|
flags: 64,
|
|
302
317
|
});
|
|
303
318
|
}
|
|
304
319
|
|
|
305
|
-
const channelBlacklist = await isBlacklisted(
|
|
306
|
-
|
|
320
|
+
const channelBlacklist = await isBlacklisted(
|
|
321
|
+
message.guild ? message.guild.id : null,
|
|
322
|
+
"channel",
|
|
323
|
+
message.channel.id
|
|
324
|
+
);
|
|
325
|
+
if (channelBlacklist) {
|
|
307
326
|
return message.reply({
|
|
308
327
|
content: "`❌` This channel is blacklisted from using bot commands.",
|
|
309
328
|
flags: 64,
|
|
@@ -346,15 +365,15 @@ async function starter(client, options) {
|
|
|
346
365
|
if (cooldown.type) return interaction.reply(cooldown.text);
|
|
347
366
|
}
|
|
348
367
|
|
|
349
|
-
if (
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
368
|
+
if (command.ownerOnly) {
|
|
369
|
+
if (
|
|
370
|
+
interaction.guild &&
|
|
371
|
+
interaction.user.id !== (await interaction.guild.fetchOwner()).id
|
|
372
|
+
)
|
|
373
|
+
return interaction.reply({
|
|
374
|
+
content: "`❌` This command is restricted to the server owner only!",
|
|
375
|
+
flags: 64,
|
|
376
|
+
});
|
|
358
377
|
}
|
|
359
378
|
|
|
360
379
|
if (command.devOnly && interaction.user.id !== client.owner.id) {
|
|
@@ -386,15 +405,19 @@ async function starter(client, options) {
|
|
|
386
405
|
)
|
|
387
406
|
) {
|
|
388
407
|
return interaction.reply({
|
|
389
|
-
content:
|
|
408
|
+
content:
|
|
409
|
+
"`❌` You do not have enough permissions to execute this command.",
|
|
390
410
|
flags: 64,
|
|
391
411
|
});
|
|
392
412
|
}
|
|
393
413
|
|
|
394
|
-
if(command.Blacklist) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
414
|
+
if (command.Blacklist) {
|
|
415
|
+
const userBlacklisted = await isBlacklisted(
|
|
416
|
+
interaction.guild ? interaction.guild.id : null,
|
|
417
|
+
"user",
|
|
418
|
+
interaction.user.id
|
|
419
|
+
);
|
|
420
|
+
if (userBlacklisted) {
|
|
398
421
|
return interaction.reply({
|
|
399
422
|
content: "`❌` You are blacklisted from using bot commands.",
|
|
400
423
|
flags: 64,
|
|
@@ -403,23 +426,33 @@ async function starter(client, options) {
|
|
|
403
426
|
|
|
404
427
|
let roleBlacklist = null;
|
|
405
428
|
for (const [id, role] of interaction.member.roles.cache) {
|
|
406
|
-
const isBlocked = await isBlacklisted(
|
|
429
|
+
const isBlocked = await isBlacklisted(
|
|
430
|
+
interaction.guild ? interaction.guild.id : null,
|
|
431
|
+
"role",
|
|
432
|
+
id
|
|
433
|
+
);
|
|
407
434
|
if (isBlocked) {
|
|
408
435
|
roleBlacklist = isBlocked;
|
|
409
436
|
break;
|
|
410
437
|
}
|
|
411
438
|
}
|
|
412
439
|
|
|
413
|
-
if(roleBlacklist) {
|
|
440
|
+
if (roleBlacklist) {
|
|
414
441
|
const role = interaction.guild.roles.cache.get(roleBlacklist.id);
|
|
415
442
|
return interaction.reply({
|
|
416
|
-
content: `\`❌\` The role **${
|
|
443
|
+
content: `\`❌\` The role **${
|
|
444
|
+
role ? role.name : "Unknown"
|
|
445
|
+
}** is blacklisted from using bot commands.`,
|
|
417
446
|
flags: 64,
|
|
418
447
|
});
|
|
419
448
|
}
|
|
420
449
|
|
|
421
|
-
const channelBlacklist = await isBlacklisted(
|
|
422
|
-
|
|
450
|
+
const channelBlacklist = await isBlacklisted(
|
|
451
|
+
interaction.guild ? interaction.guild.id : null,
|
|
452
|
+
"channel",
|
|
453
|
+
interaction.channel.id
|
|
454
|
+
);
|
|
455
|
+
if (channelBlacklist) {
|
|
423
456
|
return interaction.reply({
|
|
424
457
|
content: "`❌` This channel is blacklisted from using bot commands.",
|
|
425
458
|
flags: 64,
|
|
@@ -483,12 +516,13 @@ async function starter(client, options) {
|
|
|
483
516
|
const { Wait, CreateBar, CreateRow, GetUser } = require("../function/function");
|
|
484
517
|
const { Level, addXP, UserLevel, leaderboard } = require("../function/level");
|
|
485
518
|
const { log } = require("../function/log");
|
|
519
|
+
const { dashboard } = require("../function/dash");
|
|
486
520
|
const {
|
|
487
521
|
Blacklist,
|
|
488
522
|
isBlacklisted,
|
|
489
523
|
addToBlacklist,
|
|
490
524
|
removeFromBlacklist,
|
|
491
|
-
getBlacklist
|
|
525
|
+
getBlacklist,
|
|
492
526
|
} = require("../function/blacklist");
|
|
493
527
|
const {
|
|
494
528
|
giveaway,
|
|
@@ -510,6 +544,7 @@ module.exports = {
|
|
|
510
544
|
Level,
|
|
511
545
|
giveaway,
|
|
512
546
|
starter,
|
|
547
|
+
dashboard,
|
|
513
548
|
reload,
|
|
514
549
|
log,
|
|
515
550
|
Wait,
|
|
@@ -535,5 +570,5 @@ module.exports = {
|
|
|
535
570
|
isBlacklisted,
|
|
536
571
|
addToBlacklist,
|
|
537
572
|
removeFromBlacklist,
|
|
538
|
-
getBlacklist
|
|
573
|
+
getBlacklist,
|
|
539
574
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "djs-builder",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"note": "🎉 Package Update! 🥏\n\n-
|
|
5
|
-
"description": "🎉
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"note": "🎉 Package Update! 🥏\n\n- 🌐 NEW: Dashboard System - Modern web-based control panel!\n • Discord OAuth2 Login\n • Server Management\n • Level System Control\n • Giveaway Management\n • Blacklist Management\n- � Documentation: Full Dashboard guide added to README.\n- ✨ Standalone Usage: Use Dashboard with or without Starter!\n\n🔗 Learn more on [NPM](https://www.npmjs.com/package/djs-builder)",
|
|
5
|
+
"description": "🎉 NEW: Dashboard System - Web Control Panel! 🌐",
|
|
6
6
|
"main": "handler/starter.js",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"axios": "^1.11.0",
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"cli-table3": "^0.6.5",
|
|
11
11
|
"discord-inviter": "^0.9.3",
|
|
12
12
|
"discord.js": "^14.21.0",
|
|
13
|
-
"mongoose": "^8.18.0"
|
|
13
|
+
"mongoose": "^8.18.0",
|
|
14
|
+
"express": "^4.18.2",
|
|
15
|
+
"express-session": "^1.17.3",
|
|
16
|
+
"passport": "^0.7.0",
|
|
17
|
+
"passport-discord": "^0.1.4",
|
|
18
|
+
"ejs": "^3.1.9"
|
|
14
19
|
}
|
|
15
20
|
}
|
package/views/404.ejs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="ar" dir="rtl">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>404 - الصفحة غير موجودة</title>
|
|
7
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
|
8
|
+
<link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
|
|
9
|
+
<style>
|
|
10
|
+
:root { --bg-primary: #0f0f0f; --bg-secondary: #1a1a1a; --bg-card: #242424; --accent: #5865F2; --accent-hover: #4752C4; --text-primary: #fff; --text-secondary: #b9bbbe; --text-muted: #72767d; --border: #2f2f2f; --radius: 12px; --radius-sm: 8px; }
|
|
11
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
12
|
+
body { font-family: 'Inter', sans-serif; background: var(--bg-primary); color: var(--text-primary); min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
13
|
+
.error-container { text-align: center; padding: 40px; max-width: 500px; }
|
|
14
|
+
.error-code { font-size: 120px; font-weight: 700; color: var(--accent); line-height: 1; margin-bottom: 16px; text-shadow: 0 0 60px rgba(88, 101, 242, 0.3); }
|
|
15
|
+
.error-icon { font-size: 64px; color: var(--text-muted); margin-bottom: 24px; }
|
|
16
|
+
.error-title { font-size: 28px; font-weight: 600; margin-bottom: 12px; }
|
|
17
|
+
.error-desc { font-size: 16px; color: var(--text-secondary); margin-bottom: 32px; line-height: 1.6; }
|
|
18
|
+
.btn { display: inline-flex; align-items: center; gap: 8px; padding: 12px 24px; border-radius: var(--radius-sm); font-weight: 500; font-size: 15px; transition: all 0.2s ease; text-decoration: none; }
|
|
19
|
+
.btn-primary { background: var(--accent); color: white; }
|
|
20
|
+
.btn-primary:hover { background: var(--accent-hover); transform: translateY(-2px); }
|
|
21
|
+
.btn-secondary { background: var(--bg-card); color: var(--text-primary); border: 1px solid var(--border); margin-right: 12px; }
|
|
22
|
+
.btn-secondary:hover { background: var(--bg-secondary); }
|
|
23
|
+
.buttons { display: flex; justify-content: center; gap: 12px; flex-wrap: wrap; }
|
|
24
|
+
@keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
|
|
25
|
+
.error-icon { animation: float 3s ease-in-out infinite; }
|
|
26
|
+
</style>
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<div class="error-container">
|
|
30
|
+
<div class="error-code">404</div>
|
|
31
|
+
<i class="ri-compass-discover-line error-icon"></i>
|
|
32
|
+
<h1 class="error-title">الصفحة غير موجودة</h1>
|
|
33
|
+
<p class="error-desc">عذراً، الصفحة التي تبحث عنها غير موجودة أو تم نقلها. تأكد من صحة الرابط أو عد للصفحة الرئيسية.</p>
|
|
34
|
+
<div class="buttons">
|
|
35
|
+
<a href="/" class="btn btn-primary"><i class="ri-home-line"></i> الصفحة الرئيسية</a>
|
|
36
|
+
<a href="/dashboard" class="btn btn-secondary"><i class="ri-dashboard-line"></i> لوحة التحكم</a>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</body>
|
|
40
|
+
</html>
|