djs-builder 0.7.2 → 0.7.4
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 +915 -154
- package/function/dash.js +214 -5
- package/function/log.js +407 -332
- package/handler/starter.js +3 -1
- package/package.json +3 -3
- package/views/giveaways.ejs +1 -0
- package/views/guild.ejs +4 -0
- package/views/levels.ejs +1 -0
- package/views/logs.ejs +589 -0
package/views/logs.ejs
ADDED
|
@@ -0,0 +1,589 @@
|
|
|
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>سجلات المراقبة - <%= guild.name %></title>
|
|
7
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Noto+Color+Emoji&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 {
|
|
11
|
+
--bg-primary: #030305;
|
|
12
|
+
--bg-secondary: #0a0a0f;
|
|
13
|
+
--bg-card: #12121a;
|
|
14
|
+
--bg-card-hover: #1a1a25;
|
|
15
|
+
--accent: #5865F2;
|
|
16
|
+
--accent-light: #7289DA;
|
|
17
|
+
--accent-glow: rgba(88, 101, 242, 0.3);
|
|
18
|
+
--purple: #9b59b6;
|
|
19
|
+
--pink: #e91e63;
|
|
20
|
+
--success: #10b981;
|
|
21
|
+
--warning: #f59e0b;
|
|
22
|
+
--danger: #ef4444;
|
|
23
|
+
--text-primary: #ffffff;
|
|
24
|
+
--text-secondary: #94a3b8;
|
|
25
|
+
--text-muted: #64748b;
|
|
26
|
+
--border: rgba(255,255,255,0.06);
|
|
27
|
+
--radius: 16px;
|
|
28
|
+
--radius-sm: 10px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
32
|
+
body { font-family: 'Inter', 'Noto Color Emoji', sans-serif; background: var(--bg-primary); color: var(--text-primary); min-height: 100vh; overflow-x: hidden; }
|
|
33
|
+
a { color: inherit; text-decoration: none; }
|
|
34
|
+
::-webkit-scrollbar { width: 6px; }
|
|
35
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
36
|
+
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 6px; }
|
|
37
|
+
|
|
38
|
+
.bg-effects { position: fixed; inset: 0; pointer-events: none; overflow: hidden; z-index: 0; }
|
|
39
|
+
.bg-gradient-1 { position: absolute; top: -20%; right: -15%; width: 50%; height: 50%; background: radial-gradient(circle, rgba(88,101,242,0.12) 0%, transparent 60%); filter: blur(80px); }
|
|
40
|
+
.bg-gradient-2 { position: absolute; bottom: -20%; left: -15%; width: 40%; height: 40%; background: radial-gradient(circle, rgba(16,185,129,0.08) 0%, transparent 60%); filter: blur(80px); }
|
|
41
|
+
.bg-grid { position: absolute; inset: 0; background-image: linear-gradient(rgba(255,255,255,0.015) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.015) 1px, transparent 1px); background-size: 50px 50px; }
|
|
42
|
+
|
|
43
|
+
.btn { display: inline-flex; align-items: center; gap: 8px; padding: 12px 24px; border-radius: var(--radius-sm); font-weight: 600; font-size: 14px; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); border: none; }
|
|
44
|
+
.btn-primary { background: linear-gradient(135deg, var(--accent), var(--accent-light)); color: white; box-shadow: 0 4px 15px var(--accent-glow); }
|
|
45
|
+
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 8px 25px var(--accent-glow); }
|
|
46
|
+
.btn-secondary { background: rgba(255,255,255,0.03); color: var(--text-primary); border: 1px solid var(--border); }
|
|
47
|
+
.btn-secondary:hover { background: rgba(255,255,255,0.06); border-color: var(--accent); }
|
|
48
|
+
.btn-success { background: linear-gradient(135deg, var(--success), #059669); color: white; }
|
|
49
|
+
.btn-success:hover { box-shadow: 0 8px 20px rgba(16,185,129,0.3); }
|
|
50
|
+
.btn-danger { background: linear-gradient(135deg, var(--danger), #dc2626); color: white; }
|
|
51
|
+
.btn-danger:hover { box-shadow: 0 8px 20px rgba(239,68,68,0.3); }
|
|
52
|
+
.btn-sm { padding: 8px 16px; font-size: 13px; }
|
|
53
|
+
.btn:disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
|
|
54
|
+
|
|
55
|
+
.sidebar { width: 280px; height: 100vh; position: fixed; right: 0; top: 0; background: rgba(10,10,15,0.95); backdrop-filter: blur(20px); border-left: 1px solid var(--border); display: flex; flex-direction: column; z-index: 100; }
|
|
56
|
+
.sidebar-header { padding: 24px; border-bottom: 1px solid var(--border); background: rgba(0,0,0,0.2); }
|
|
57
|
+
.guild-card { display: flex; align-items: center; gap: 14px; }
|
|
58
|
+
.guild-icon-wrapper { position: relative; }
|
|
59
|
+
.guild-icon { width: 52px; height: 52px; border-radius: var(--radius-sm); border: 2px solid transparent; background: linear-gradient(var(--bg-card), var(--bg-card)) padding-box, linear-gradient(135deg, var(--accent), var(--purple)) border-box; }
|
|
60
|
+
.guild-icon-placeholder { width: 52px; height: 52px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; font-size: 22px; font-weight: 700; color: var(--accent); border: 2px solid transparent; background: linear-gradient(var(--bg-card), var(--bg-card)) padding-box, linear-gradient(135deg, var(--accent), var(--purple)) border-box; }
|
|
61
|
+
.guild-status { position: absolute; bottom: -2px; left: -2px; width: 16px; height: 16px; background: var(--success); border-radius: 50%; border: 3px solid var(--bg-secondary); }
|
|
62
|
+
.guild-info { flex: 1; min-width: 0; }
|
|
63
|
+
.guild-name { font-size: 16px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 4px; }
|
|
64
|
+
.guild-meta { font-size: 12px; color: var(--text-muted); display: flex; align-items: center; gap: 6px; }
|
|
65
|
+
|
|
66
|
+
.sidebar-nav { flex: 1; padding: 16px; overflow-y: auto; }
|
|
67
|
+
.nav-section { margin-bottom: 24px; }
|
|
68
|
+
.nav-section-title { font-size: 10px; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px; padding: 8px 14px; }
|
|
69
|
+
.nav-link { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: var(--radius-sm); color: var(--text-secondary); font-size: 14px; font-weight: 500; margin-bottom: 4px; transition: all 0.3s; position: relative; overflow: hidden; }
|
|
70
|
+
.nav-link::before { content: ''; position: absolute; right: 0; top: 50%; transform: translateY(-50%); width: 3px; height: 0; background: var(--accent); border-radius: 3px; transition: height 0.3s; }
|
|
71
|
+
.nav-link:hover { background: rgba(255,255,255,0.03); color: var(--text-primary); }
|
|
72
|
+
.nav-link.active { background: rgba(88,101,242,0.15); color: var(--accent); }
|
|
73
|
+
.nav-link.active::before { height: 60%; }
|
|
74
|
+
.nav-link i { font-size: 20px; }
|
|
75
|
+
|
|
76
|
+
.sidebar-footer { padding: 16px; border-top: 1px solid var(--border); background: rgba(0,0,0,0.2); }
|
|
77
|
+
.back-btn { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px; background: rgba(255,255,255,0.02); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text-secondary); font-size: 13px; font-weight: 500; transition: all 0.3s; }
|
|
78
|
+
.back-btn:hover { background: rgba(255,255,255,0.05); color: var(--text-primary); border-color: var(--accent); }
|
|
79
|
+
|
|
80
|
+
.main { margin-right: 280px; padding: 40px; min-height: 100vh; position: relative; z-index: 1; }
|
|
81
|
+
.page-header { margin-bottom: 32px; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px; }
|
|
82
|
+
.page-header h1 { font-size: 36px; font-weight: 800; background: linear-gradient(135deg, #fff, var(--text-secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; display: flex; align-items: center; }
|
|
83
|
+
.page-header h1 i { margin-left: 12px; -webkit-text-fill-color: var(--success); }
|
|
84
|
+
.page-header p { color: var(--text-secondary); margin-top: 8px; }
|
|
85
|
+
|
|
86
|
+
/* Alert Banner */
|
|
87
|
+
.alert-banner { padding: 18px 24px; border-radius: var(--radius); margin-bottom: 28px; display: flex; align-items: center; gap: 14px; }
|
|
88
|
+
.alert-banner.warning { background: rgba(245,158,11,0.1); border: 1px solid rgba(245,158,11,0.3); color: var(--warning); }
|
|
89
|
+
.alert-banner.info { background: rgba(88,101,242,0.1); border: 1px solid rgba(88,101,242,0.3); color: var(--accent-light); }
|
|
90
|
+
.alert-banner.success { background: rgba(16,185,129,0.1); border: 1px solid rgba(16,185,129,0.3); color: var(--success); }
|
|
91
|
+
.alert-banner i { font-size: 24px; }
|
|
92
|
+
.alert-banner-content { flex: 1; }
|
|
93
|
+
.alert-banner-content strong { display: block; margin-bottom: 4px; }
|
|
94
|
+
.alert-banner-content p { font-size: 14px; opacity: 0.9; }
|
|
95
|
+
|
|
96
|
+
/* Stats Row */
|
|
97
|
+
.stats-row { display: flex; gap: 18px; margin-bottom: 28px; flex-wrap: wrap; }
|
|
98
|
+
.mini-stat { background: linear-gradient(145deg, var(--bg-card), rgba(18,18,26,0.6)); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 20px 28px; display: flex; align-items: center; gap: 16px; transition: all 0.3s; flex: 1; min-width: 180px; }
|
|
99
|
+
.mini-stat:hover { border-color: var(--accent); transform: translateY(-3px); }
|
|
100
|
+
.mini-stat i { font-size: 28px; }
|
|
101
|
+
.mini-stat:nth-child(1) i { color: var(--success); }
|
|
102
|
+
.mini-stat:nth-child(2) i { color: var(--accent); }
|
|
103
|
+
.mini-stat:nth-child(3) i { color: var(--warning); }
|
|
104
|
+
.mini-stat:nth-child(4) i { color: var(--danger); }
|
|
105
|
+
.mini-stat-value { font-size: 26px; font-weight: 800; }
|
|
106
|
+
.mini-stat-label { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
|
|
107
|
+
|
|
108
|
+
/* Setup Card */
|
|
109
|
+
.setup-card { background: linear-gradient(145deg, var(--bg-card), rgba(18,18,26,0.6)); border: 1px solid var(--border); border-radius: var(--radius); padding: 28px; margin-bottom: 28px; }
|
|
110
|
+
.setup-card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; flex-wrap: wrap; gap: 16px; }
|
|
111
|
+
.setup-card-header h3 { font-size: 18px; font-weight: 600; display: flex; align-items: center; gap: 10px; }
|
|
112
|
+
.setup-card-header h3 i { color: var(--accent); }
|
|
113
|
+
|
|
114
|
+
.form-group { margin-bottom: 20px; }
|
|
115
|
+
.form-group label { display: block; font-size: 14px; font-weight: 500; margin-bottom: 10px; color: var(--text-secondary); }
|
|
116
|
+
.form-group select, .form-group input { width: 100%; padding: 14px 16px; background: rgba(255,255,255,0.03); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text-primary); font-size: 14px; transition: all 0.3s; }
|
|
117
|
+
.form-group select:focus, .form-group input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
|
|
118
|
+
.form-group select option { background: var(--bg-card); color: var(--text-primary); }
|
|
119
|
+
.form-hint { font-size: 12px; color: var(--text-muted); margin-top: 6px; }
|
|
120
|
+
|
|
121
|
+
.form-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; }
|
|
122
|
+
|
|
123
|
+
/* Events Grid */
|
|
124
|
+
.events-section { margin-top: 32px; }
|
|
125
|
+
.events-section h3 { font-size: 18px; font-weight: 600; margin-bottom: 20px; display: flex; align-items: center; gap: 10px; }
|
|
126
|
+
.events-section h3 i { color: var(--accent); }
|
|
127
|
+
|
|
128
|
+
.events-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; }
|
|
129
|
+
|
|
130
|
+
.event-card { background: linear-gradient(145deg, var(--bg-card), rgba(18,18,26,0.6)); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 20px; transition: all 0.3s; }
|
|
131
|
+
.event-card:hover { border-color: rgba(88,101,242,0.3); transform: translateY(-2px); }
|
|
132
|
+
.event-card.disabled { opacity: 0.5; }
|
|
133
|
+
.event-card.disabled .event-status { background: rgba(239,68,68,0.15); color: var(--danger); }
|
|
134
|
+
|
|
135
|
+
.event-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
|
|
136
|
+
.event-name { font-weight: 600; display: flex; align-items: center; gap: 10px; }
|
|
137
|
+
.event-name i { font-size: 20px; color: var(--accent); }
|
|
138
|
+
.event-status { padding: 4px 12px; border-radius: 50px; font-size: 11px; font-weight: 600; }
|
|
139
|
+
.event-status.enabled { background: rgba(16,185,129,0.15); color: var(--success); }
|
|
140
|
+
.event-status.disabled { background: rgba(239,68,68,0.15); color: var(--danger); }
|
|
141
|
+
|
|
142
|
+
.event-settings { display: flex; flex-direction: column; gap: 12px; }
|
|
143
|
+
.event-setting { display: flex; align-items: center; justify-content: space-between; font-size: 13px; color: var(--text-secondary); }
|
|
144
|
+
.event-setting-label { display: flex; align-items: center; gap: 8px; }
|
|
145
|
+
.event-setting-label i { font-size: 16px; color: var(--text-muted); }
|
|
146
|
+
.event-setting-value { color: var(--text-primary); font-weight: 500; max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
147
|
+
|
|
148
|
+
.event-actions { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); display: flex; gap: 8px; }
|
|
149
|
+
.event-actions button { flex: 1; }
|
|
150
|
+
|
|
151
|
+
/* Toggle Switch */
|
|
152
|
+
.toggle-switch { position: relative; width: 48px; height: 26px; cursor: pointer; }
|
|
153
|
+
.toggle-switch input { opacity: 0; width: 0; height: 0; }
|
|
154
|
+
.toggle-slider { position: absolute; inset: 0; background: rgba(255,255,255,0.1); border-radius: 50px; transition: all 0.3s; }
|
|
155
|
+
.toggle-slider::before { content: ''; position: absolute; width: 20px; height: 20px; left: 3px; top: 3px; background: var(--text-muted); border-radius: 50%; transition: all 0.3s; }
|
|
156
|
+
.toggle-switch input:checked + .toggle-slider { background: var(--success); }
|
|
157
|
+
.toggle-switch input:checked + .toggle-slider::before { transform: translateX(22px); background: white; }
|
|
158
|
+
|
|
159
|
+
/* Color Picker */
|
|
160
|
+
.color-picker-wrapper { display: flex; align-items: center; gap: 12px; }
|
|
161
|
+
.color-picker-preview { width: 36px; height: 36px; border-radius: var(--radius-sm); border: 2px solid var(--border); cursor: pointer; }
|
|
162
|
+
.color-picker-input { flex: 1; }
|
|
163
|
+
|
|
164
|
+
/* Channel Select */
|
|
165
|
+
.channel-select { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: rgba(255,255,255,0.02); border: 1px solid var(--border); border-radius: var(--radius-sm); cursor: pointer; transition: all 0.3s; }
|
|
166
|
+
.channel-select:hover { border-color: var(--accent); }
|
|
167
|
+
.channel-select i { color: var(--text-muted); }
|
|
168
|
+
.channel-select span { flex: 1; color: var(--text-primary); }
|
|
169
|
+
|
|
170
|
+
/* Empty State */
|
|
171
|
+
.empty-state { text-align: center; padding: 80px 20px; background: linear-gradient(145deg, var(--bg-card), rgba(18,18,26,0.6)); border: 1px solid var(--border); border-radius: var(--radius); }
|
|
172
|
+
.empty-state i { font-size: 64px; color: var(--success); margin-bottom: 24px; opacity: 0.3; }
|
|
173
|
+
.empty-state h3 { font-size: 22px; margin-bottom: 12px; }
|
|
174
|
+
.empty-state p { color: var(--text-secondary); margin-bottom: 24px; }
|
|
175
|
+
|
|
176
|
+
/* Toast */
|
|
177
|
+
.toast { position: fixed; bottom: 24px; left: 24px; background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 16px 24px; display: flex; align-items: center; gap: 12px; box-shadow: 0 10px 40px rgba(0,0,0,0.4); transform: translateY(120px); opacity: 0; transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); z-index: 3000; }
|
|
178
|
+
.toast.show { transform: translateY(0); opacity: 1; }
|
|
179
|
+
.toast.success { border-color: var(--success); }
|
|
180
|
+
.toast.success i { color: var(--success); }
|
|
181
|
+
.toast.error { border-color: var(--danger); }
|
|
182
|
+
.toast.error i { color: var(--danger); }
|
|
183
|
+
|
|
184
|
+
/* Modal */
|
|
185
|
+
.modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.8); backdrop-filter: blur(8px); align-items: center; justify-content: center; z-index: 2000; }
|
|
186
|
+
.modal.show { display: flex; }
|
|
187
|
+
.modal-content { background: linear-gradient(145deg, var(--bg-card), rgba(18,18,26,0.95)); border: 1px solid var(--border); border-radius: var(--radius); width: 500px; max-width: 90%; max-height: 80vh; overflow-y: auto; box-shadow: 0 25px 60px rgba(0,0,0,0.5); animation: modalIn 0.3s ease; }
|
|
188
|
+
@keyframes modalIn { from { opacity: 0; transform: scale(0.95) translateY(20px); } to { opacity: 1; transform: scale(1) translateY(0); } }
|
|
189
|
+
.modal-header { padding: 24px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; position: sticky; top: 0; background: var(--bg-card); z-index: 1; }
|
|
190
|
+
.modal-header h3 { font-size: 18px; font-weight: 600; display: flex; align-items: center; gap: 10px; }
|
|
191
|
+
.modal-header h3 i { color: var(--accent); }
|
|
192
|
+
.modal-close { background: none; border: none; color: var(--text-muted); cursor: pointer; font-size: 24px; transition: all 0.3s; }
|
|
193
|
+
.modal-close:hover { color: var(--text-primary); transform: rotate(90deg); }
|
|
194
|
+
.modal-body { padding: 24px; }
|
|
195
|
+
.modal-footer { padding: 20px 24px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 10px; position: sticky; bottom: 0; background: var(--bg-card); }
|
|
196
|
+
|
|
197
|
+
/* Channels List in Modal */
|
|
198
|
+
.channels-list { max-height: 300px; overflow-y: auto; border: 1px solid var(--border); border-radius: var(--radius-sm); }
|
|
199
|
+
.channel-item { display: flex; align-items: center; gap: 12px; padding: 12px 16px; cursor: pointer; transition: all 0.2s; border-bottom: 1px solid var(--border); }
|
|
200
|
+
.channel-item:last-child { border-bottom: none; }
|
|
201
|
+
.channel-item:hover { background: rgba(88,101,242,0.1); }
|
|
202
|
+
.channel-item.selected { background: rgba(88,101,242,0.2); }
|
|
203
|
+
.channel-item i { color: var(--text-muted); font-size: 18px; }
|
|
204
|
+
.channel-item span { flex: 1; }
|
|
205
|
+
.channel-item .check { color: var(--success); display: none; }
|
|
206
|
+
.channel-item.selected .check { display: block; }
|
|
207
|
+
|
|
208
|
+
@keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
|
|
209
|
+
.animate-in { animation: fadeIn 0.5s ease forwards; }
|
|
210
|
+
|
|
211
|
+
@media (max-width: 992px) {
|
|
212
|
+
.sidebar { transform: translateX(100%); transition: transform 0.3s; }
|
|
213
|
+
.sidebar.open { transform: translateX(0); }
|
|
214
|
+
.main { margin-right: 0; padding: 20px; padding-top: 70px; }
|
|
215
|
+
.mobile-menu-btn { position: fixed; top: 16px; right: 16px; z-index: 101; width: 44px; height: 44px; background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; color: var(--text-primary); font-size: 22px; cursor: pointer; }
|
|
216
|
+
.events-grid { grid-template-columns: 1fr; }
|
|
217
|
+
.page-header h1 { font-size: 24px; }
|
|
218
|
+
.stats-row { flex-direction: column; }
|
|
219
|
+
.mini-stat { min-width: auto; }
|
|
220
|
+
}
|
|
221
|
+
@media (min-width: 993px) { .mobile-menu-btn { display: none; } }
|
|
222
|
+
</style>
|
|
223
|
+
</head>
|
|
224
|
+
<body>
|
|
225
|
+
<div class="bg-effects"><div class="bg-gradient-1"></div><div class="bg-gradient-2"></div><div class="bg-grid"></div></div>
|
|
226
|
+
|
|
227
|
+
<button class="mobile-menu-btn" onclick="document.querySelector('.sidebar').classList.toggle('open')"><i class="ri-menu-line"></i></button>
|
|
228
|
+
|
|
229
|
+
<aside class="sidebar">
|
|
230
|
+
<div class="sidebar-header">
|
|
231
|
+
<div class="guild-card">
|
|
232
|
+
<div class="guild-icon-wrapper">
|
|
233
|
+
<% if (guild.icon) { %><img src="https://cdn.discordapp.com/icons/<%= guild.id %>/<%= guild.icon %>.png?size=128" alt="<%= guild.name %>" class="guild-icon"><% } else { %><div class="guild-icon-placeholder"><%= guild.name.charAt(0).toUpperCase() %></div><% } %>
|
|
234
|
+
<div class="guild-status"></div>
|
|
235
|
+
</div>
|
|
236
|
+
<div class="guild-info">
|
|
237
|
+
<div class="guild-name"><%= guild.name %></div>
|
|
238
|
+
<div class="guild-meta"><i class="ri-group-line"></i> <%= (guild.memberCount || 0).toLocaleString() %> عضو</div>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
<nav class="sidebar-nav">
|
|
243
|
+
<div class="nav-section"><div class="nav-section-title">الرئيسية</div><a href="/dashboard/<%= guild.id %>" class="nav-link"><i class="ri-dashboard-3-line"></i><span>نظرة عامة</span></a></div>
|
|
244
|
+
<div class="nav-section"><div class="nav-section-title">الميزات</div>
|
|
245
|
+
<a href="/dashboard/<%= guild.id %>/levels" class="nav-link"><i class="ri-bar-chart-grouped-line"></i><span>نظام المستويات</span></a>
|
|
246
|
+
<a href="/dashboard/<%= guild.id %>/giveaways" class="nav-link"><i class="ri-gift-2-line"></i><span>الهدايا</span></a>
|
|
247
|
+
<a href="/dashboard/<%= guild.id %>/logs" class="nav-link active"><i class="ri-shield-check-line"></i><span>سجلات المراقبة</span></a>
|
|
248
|
+
</div>
|
|
249
|
+
</nav>
|
|
250
|
+
<div class="sidebar-footer"><a href="/dashboard" class="back-btn"><i class="ri-arrow-right-line"></i><span>العودة للوحة التحكم</span></a></div>
|
|
251
|
+
</aside>
|
|
252
|
+
|
|
253
|
+
<main class="main">
|
|
254
|
+
<div class="page-header animate-in">
|
|
255
|
+
<div><h1><i class="ri-shield-check-line"></i> سجلات المراقبة</h1><p>إدارة وتخصيص سجلات الأحداث في السيرفر</p></div>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
<% if (configSource === 'code') { %>
|
|
259
|
+
<!-- Code Mode - Read Only -->
|
|
260
|
+
<div class="alert-banner warning animate-in" style="animation-delay: 0.05s">
|
|
261
|
+
<i class="ri-code-s-slash-line"></i>
|
|
262
|
+
<div class="alert-banner-content">
|
|
263
|
+
<strong>⚙️ وضع القراءة فقط (من الكود)</strong>
|
|
264
|
+
<p>إعدادات السجلات محددة في الكود. لتعديلها من لوحة التحكم، فعّل <code>database: true</code> في إعدادات نظام السجلات.</p>
|
|
265
|
+
</div>
|
|
266
|
+
</div>
|
|
267
|
+
<% } else if (databaseEnabled && logConfig) { %>
|
|
268
|
+
<!-- Database Enabled - Success Banner -->
|
|
269
|
+
<div class="alert-banner success animate-in" style="animation-delay: 0.05s">
|
|
270
|
+
<i class="ri-checkbox-circle-line"></i>
|
|
271
|
+
<div class="alert-banner-content">
|
|
272
|
+
<strong>✅ نظام السجلات مفعل</strong>
|
|
273
|
+
<p>يمكنك تعديل جميع الإعدادات من هذه الصفحة. التغييرات يتم حفظها تلقائياً.</p>
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
<% } else if (databaseEnabled && !logConfig) { %>
|
|
277
|
+
<!-- Database Enabled but No Config -->
|
|
278
|
+
<div class="alert-banner info animate-in" style="animation-delay: 0.05s">
|
|
279
|
+
<i class="ri-information-line"></i>
|
|
280
|
+
<div class="alert-banner-content">
|
|
281
|
+
<strong>📝 لم يتم إعداد السجلات بعد</strong>
|
|
282
|
+
<p>قم بتحديد القناة الافتراضية لبدء تسجيل الأحداث في هذا السيرفر.</p>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
<% } else { %>
|
|
286
|
+
<!-- No Database and No Config -->
|
|
287
|
+
<div class="alert-banner warning animate-in" style="animation-delay: 0.05s">
|
|
288
|
+
<i class="ri-error-warning-line"></i>
|
|
289
|
+
<div class="alert-banner-content">
|
|
290
|
+
<strong>⚠️ لم يتم ضبط إعدادات السجلات</strong>
|
|
291
|
+
<p>هذا السيرفر غير موجود في إعدادات نظام السجلات. أضفه في الكود أو فعّل <code>database: true</code> للتحكم من هنا.</p>
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
<% } %>
|
|
295
|
+
|
|
296
|
+
<!-- Stats Row -->
|
|
297
|
+
<div class="stats-row animate-in" style="animation-delay: 0.1s">
|
|
298
|
+
<div class="mini-stat">
|
|
299
|
+
<i class="ri-checkbox-circle-line"></i>
|
|
300
|
+
<div>
|
|
301
|
+
<div class="mini-stat-value"><%= enabledEvents %></div>
|
|
302
|
+
<div class="mini-stat-label">حدث مفعل</div>
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
<div class="mini-stat">
|
|
306
|
+
<i class="ri-close-circle-line"></i>
|
|
307
|
+
<div>
|
|
308
|
+
<div class="mini-stat-value"><%= disabledEvents %></div>
|
|
309
|
+
<div class="mini-stat-label">حدث معطل</div>
|
|
310
|
+
</div>
|
|
311
|
+
</div>
|
|
312
|
+
<div class="mini-stat">
|
|
313
|
+
<i class="ri-palette-line"></i>
|
|
314
|
+
<div>
|
|
315
|
+
<div class="mini-stat-value"><%= customColors %></div>
|
|
316
|
+
<div class="mini-stat-label">لون مخصص</div>
|
|
317
|
+
</div>
|
|
318
|
+
</div>
|
|
319
|
+
<div class="mini-stat">
|
|
320
|
+
<i class="ri-git-branch-line"></i>
|
|
321
|
+
<div>
|
|
322
|
+
<div class="mini-stat-value"><%= customChannels %></div>
|
|
323
|
+
<div class="mini-stat-label">قناة مخصصة</div>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
|
|
328
|
+
<!-- Main Setup Card -->
|
|
329
|
+
<div class="setup-card animate-in" style="animation-delay: 0.15s">
|
|
330
|
+
<div class="setup-card-header">
|
|
331
|
+
<h3><i class="ri-settings-3-line"></i> الإعدادات الأساسية</h3>
|
|
332
|
+
<% if (databaseEnabled && logConfig) { %>
|
|
333
|
+
<button class="btn btn-danger btn-sm" onclick="resetConfig()"><i class="ri-refresh-line"></i> إعادة تعيين</button>
|
|
334
|
+
<% } %>
|
|
335
|
+
</div>
|
|
336
|
+
|
|
337
|
+
<div class="form-row">
|
|
338
|
+
<div class="form-group">
|
|
339
|
+
<label><i class="ri-hashtag"></i> القناة الافتراضية للسجلات</label>
|
|
340
|
+
<% if (databaseEnabled) { %>
|
|
341
|
+
<select id="defaultChannel" onchange="updateDefaultChannel(this.value)">
|
|
342
|
+
<option value="">-- اختر قناة --</option>
|
|
343
|
+
<% channels.forEach(channel => { %>
|
|
344
|
+
<option value="<%= channel.id %>" <%= logConfig && logConfig.channelId === channel.id ? 'selected' : '' %>>#<%= channel.name %></option>
|
|
345
|
+
<% }); %>
|
|
346
|
+
</select>
|
|
347
|
+
<% } else if (configSource === 'code' && logConfig) { %>
|
|
348
|
+
<div class="channel-select" style="cursor: not-allowed; opacity: 0.8;">
|
|
349
|
+
<i class="ri-hashtag"></i>
|
|
350
|
+
<span><%= logConfig.channelId ? '#' + (channels.find(c => c.id === logConfig.channelId)?.name || logConfig.channelId) : 'يتم تحديدها لكل حدث' %></span>
|
|
351
|
+
<i class="ri-lock-line" style="color: var(--warning);"></i>
|
|
352
|
+
</div>
|
|
353
|
+
<% } else { %>
|
|
354
|
+
<div class="channel-select" style="cursor: not-allowed; opacity: 0.5;">
|
|
355
|
+
<i class="ri-hashtag"></i>
|
|
356
|
+
<span>غير محدد</span>
|
|
357
|
+
</div>
|
|
358
|
+
<% } %>
|
|
359
|
+
<div class="form-hint">
|
|
360
|
+
<% if (configSource === 'code') { %>
|
|
361
|
+
<i class="ri-information-line"></i> هذه القيمة محددة في الكود ولا يمكن تعديلها من هنا
|
|
362
|
+
<% } else { %>
|
|
363
|
+
القناة التي سيتم إرسال جميع السجلات إليها بشكل افتراضي
|
|
364
|
+
<% } %>
|
|
365
|
+
</div>
|
|
366
|
+
</div>
|
|
367
|
+
</div>
|
|
368
|
+
</div>
|
|
369
|
+
|
|
370
|
+
<!-- Events Section -->
|
|
371
|
+
<% if (logConfig || databaseEnabled) { %>
|
|
372
|
+
<div class="events-section animate-in" style="animation-delay: 0.2s">
|
|
373
|
+
<h3><i class="ri-list-check-2"></i> أنواع الأحداث (<%= eventTypes.length %>)</h3>
|
|
374
|
+
|
|
375
|
+
<div class="events-grid">
|
|
376
|
+
<% eventTypes.forEach((event, index) => {
|
|
377
|
+
const isDisabled = logConfig && logConfig.disable && logConfig.disable.includes(event.value);
|
|
378
|
+
const customChannel = logConfig && logConfig.channels && logConfig.channels[event.value];
|
|
379
|
+
const customColor = logConfig && logConfig.colors && logConfig.colors[event.value];
|
|
380
|
+
const canEdit = databaseEnabled; // يمكن التعديل فقط في وضع Database
|
|
381
|
+
%>
|
|
382
|
+
<div class="event-card <%= isDisabled ? 'disabled' : '' %>" data-event="<%= event.value %>" style="animation-delay: <%= 0.25 + (index * 0.02) %>s">
|
|
383
|
+
<div class="event-header">
|
|
384
|
+
<div class="event-name"><i class="<%= event.icon %>"></i> <%= event.name %></div>
|
|
385
|
+
<span class="event-status <%= isDisabled ? 'disabled' : 'enabled' %>"><%= isDisabled ? 'معطل' : 'مفعل' %></span>
|
|
386
|
+
</div>
|
|
387
|
+
|
|
388
|
+
<div class="event-settings">
|
|
389
|
+
<div class="event-setting">
|
|
390
|
+
<div class="event-setting-label"><i class="ri-hashtag"></i> القناة</div>
|
|
391
|
+
<div class="event-setting-value" title="<%= customChannel ? '#' + (channels.find(c => c.id === customChannel)?.name || customChannel) : 'الافتراضية' %>">
|
|
392
|
+
<%= customChannel ? '#' + (channels.find(c => c.id === customChannel)?.name || customChannel) : 'الافتراضية' %>
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
<div class="event-setting">
|
|
396
|
+
<div class="event-setting-label"><i class="ri-palette-line"></i> اللون</div>
|
|
397
|
+
<div class="event-setting-value" style="<%= customColor ? 'color: ' + customColor : '' %>">
|
|
398
|
+
<%= customColor || 'افتراضي' %>
|
|
399
|
+
</div>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
|
|
403
|
+
<% if (canEdit) { %>
|
|
404
|
+
<div class="event-actions">
|
|
405
|
+
<button class="btn btn-secondary btn-sm" onclick="openEventSettings('<%= event.value %>', '<%= event.name %>')"><i class="ri-settings-3-line"></i> تعديل</button>
|
|
406
|
+
<button class="btn <%= isDisabled ? 'btn-success' : 'btn-danger' %> btn-sm" onclick="toggleEvent('<%= event.value %>', <%= isDisabled %>)">
|
|
407
|
+
<i class="<%= isDisabled ? 'ri-play-line' : 'ri-pause-line' %>"></i> <%= isDisabled ? 'تفعيل' : 'تعطيل' %>
|
|
408
|
+
</button>
|
|
409
|
+
</div>
|
|
410
|
+
<% } else { %>
|
|
411
|
+
<div class="event-actions" style="opacity: 0.5;">
|
|
412
|
+
<div style="flex: 1; text-align: center; font-size: 12px; color: var(--text-muted);">
|
|
413
|
+
<i class="ri-lock-line"></i> محدد في الكود
|
|
414
|
+
</div>
|
|
415
|
+
</div>
|
|
416
|
+
<% } %>
|
|
417
|
+
</div>
|
|
418
|
+
<% }); %>
|
|
419
|
+
</div>
|
|
420
|
+
</div>
|
|
421
|
+
<% } else { %>
|
|
422
|
+
<!-- Empty State when no config -->
|
|
423
|
+
<div class="empty-state animate-in" style="animation-delay: 0.2s">
|
|
424
|
+
<i class="ri-shield-check-line"></i>
|
|
425
|
+
<h3>لم يتم إعداد السجلات لهذا السيرفر</h3>
|
|
426
|
+
<p>أضف هذا السيرفر في إعدادات نظام السجلات في الكود، أو فعّل وضع Database للتحكم من هنا.</p>
|
|
427
|
+
</div>
|
|
428
|
+
<% } %>
|
|
429
|
+
</main>
|
|
430
|
+
|
|
431
|
+
<!-- Event Settings Modal -->
|
|
432
|
+
<div class="modal" id="eventModal">
|
|
433
|
+
<div class="modal-content">
|
|
434
|
+
<div class="modal-header">
|
|
435
|
+
<h3><i class="ri-settings-3-line"></i> إعدادات: <span id="eventModalTitle"></span></h3>
|
|
436
|
+
<button class="modal-close" onclick="closeEventModal()">×</button>
|
|
437
|
+
</div>
|
|
438
|
+
<div class="modal-body">
|
|
439
|
+
<input type="hidden" id="currentEventType">
|
|
440
|
+
|
|
441
|
+
<div class="form-group">
|
|
442
|
+
<label><i class="ri-hashtag"></i> قناة مخصصة (اختياري)</label>
|
|
443
|
+
<select id="eventChannel">
|
|
444
|
+
<option value="">استخدم القناة الافتراضية</option>
|
|
445
|
+
<% channels.forEach(channel => { %>
|
|
446
|
+
<option value="<%= channel.id %>">#<%= channel.name %></option>
|
|
447
|
+
<% }); %>
|
|
448
|
+
</select>
|
|
449
|
+
<div class="form-hint">اترك فارغاً لاستخدام القناة الافتراضية</div>
|
|
450
|
+
</div>
|
|
451
|
+
|
|
452
|
+
<div class="form-group">
|
|
453
|
+
<label><i class="ri-palette-line"></i> لون مخصص</label>
|
|
454
|
+
<div class="color-picker-wrapper">
|
|
455
|
+
<input type="color" id="eventColorPicker" class="color-picker-preview" value="#5865F2">
|
|
456
|
+
<input type="text" id="eventColor" class="color-picker-input" placeholder="مثال: Red, #FF5733, أو اتركه فارغاً">
|
|
457
|
+
</div>
|
|
458
|
+
<div class="form-hint">يمكنك كتابة اسم اللون (Red, Blue, Green...) أو كود HEX</div>
|
|
459
|
+
</div>
|
|
460
|
+
</div>
|
|
461
|
+
<div class="modal-footer">
|
|
462
|
+
<button class="btn btn-secondary" onclick="closeEventModal()">إلغاء</button>
|
|
463
|
+
<button class="btn btn-primary" onclick="saveEventSettings()"><i class="ri-save-line"></i> حفظ</button>
|
|
464
|
+
</div>
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
|
|
468
|
+
<div class="toast" id="toast"><i class="ri-checkbox-circle-line"></i> <span></span></div>
|
|
469
|
+
|
|
470
|
+
<script>
|
|
471
|
+
const guildId = '<%= guild.id %>';
|
|
472
|
+
const databaseEnabled = <%= databaseEnabled %>;
|
|
473
|
+
const logConfig = <%- JSON.stringify(logConfig || null) %>;
|
|
474
|
+
|
|
475
|
+
function showToast(message, type = 'success') {
|
|
476
|
+
const toast = document.getElementById('toast');
|
|
477
|
+
toast.querySelector('span').textContent = message;
|
|
478
|
+
toast.querySelector('i').className = type === 'success' ? 'ri-checkbox-circle-line' : 'ri-error-warning-line';
|
|
479
|
+
toast.className = 'toast ' + type + ' show';
|
|
480
|
+
setTimeout(() => toast.classList.remove('show'), 3000);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
async function updateDefaultChannel(channelId) {
|
|
484
|
+
if (!databaseEnabled) return;
|
|
485
|
+
try {
|
|
486
|
+
const res = await fetch(`/api/${guildId}/logs/channel`, {
|
|
487
|
+
method: 'POST',
|
|
488
|
+
headers: { 'Content-Type': 'application/json' },
|
|
489
|
+
body: JSON.stringify({ channelId })
|
|
490
|
+
});
|
|
491
|
+
const data = await res.json();
|
|
492
|
+
if (data.success) {
|
|
493
|
+
showToast('تم تحديث القناة الافتراضية');
|
|
494
|
+
} else {
|
|
495
|
+
showToast(data.error || 'حدث خطأ', 'error');
|
|
496
|
+
}
|
|
497
|
+
} catch (e) {
|
|
498
|
+
showToast('حدث خطأ في الاتصال', 'error');
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
async function toggleEvent(eventType, currentlyDisabled) {
|
|
503
|
+
if (!databaseEnabled) return;
|
|
504
|
+
try {
|
|
505
|
+
const res = await fetch(`/api/${guildId}/logs/toggle`, {
|
|
506
|
+
method: 'POST',
|
|
507
|
+
headers: { 'Content-Type': 'application/json' },
|
|
508
|
+
body: JSON.stringify({ eventType, enable: currentlyDisabled })
|
|
509
|
+
});
|
|
510
|
+
const data = await res.json();
|
|
511
|
+
if (data.success) {
|
|
512
|
+
showToast(currentlyDisabled ? 'تم تفعيل الحدث' : 'تم تعطيل الحدث');
|
|
513
|
+
setTimeout(() => location.reload(), 1000);
|
|
514
|
+
} else {
|
|
515
|
+
showToast(data.error || 'حدث خطأ', 'error');
|
|
516
|
+
}
|
|
517
|
+
} catch (e) {
|
|
518
|
+
showToast('حدث خطأ في الاتصال', 'error');
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function openEventSettings(eventType, eventName) {
|
|
523
|
+
document.getElementById('currentEventType').value = eventType;
|
|
524
|
+
document.getElementById('eventModalTitle').textContent = eventName;
|
|
525
|
+
|
|
526
|
+
// Load current settings
|
|
527
|
+
const currentChannel = logConfig?.channels?.[eventType] || '';
|
|
528
|
+
const currentColor = logConfig?.colors?.[eventType] || '';
|
|
529
|
+
|
|
530
|
+
document.getElementById('eventChannel').value = currentChannel;
|
|
531
|
+
document.getElementById('eventColor').value = currentColor;
|
|
532
|
+
if (currentColor.startsWith('#')) {
|
|
533
|
+
document.getElementById('eventColorPicker').value = currentColor;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
document.getElementById('eventModal').classList.add('show');
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function closeEventModal() {
|
|
540
|
+
document.getElementById('eventModal').classList.remove('show');
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Sync color picker with text input
|
|
544
|
+
document.getElementById('eventColorPicker').addEventListener('input', function() {
|
|
545
|
+
document.getElementById('eventColor').value = this.value;
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
async function saveEventSettings() {
|
|
549
|
+
const eventType = document.getElementById('currentEventType').value;
|
|
550
|
+
const channel = document.getElementById('eventChannel').value;
|
|
551
|
+
const color = document.getElementById('eventColor').value;
|
|
552
|
+
|
|
553
|
+
try {
|
|
554
|
+
const res = await fetch(`/api/${guildId}/logs/event`, {
|
|
555
|
+
method: 'POST',
|
|
556
|
+
headers: { 'Content-Type': 'application/json' },
|
|
557
|
+
body: JSON.stringify({ eventType, channel, color })
|
|
558
|
+
});
|
|
559
|
+
const data = await res.json();
|
|
560
|
+
if (data.success) {
|
|
561
|
+
showToast('تم حفظ الإعدادات');
|
|
562
|
+
closeEventModal();
|
|
563
|
+
setTimeout(() => location.reload(), 1000);
|
|
564
|
+
} else {
|
|
565
|
+
showToast(data.error || 'حدث خطأ', 'error');
|
|
566
|
+
}
|
|
567
|
+
} catch (e) {
|
|
568
|
+
showToast('حدث خطأ في الاتصال', 'error');
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
async function resetConfig() {
|
|
573
|
+
if (!confirm('هل أنت متأكد من إعادة تعيين جميع إعدادات السجلات؟')) return;
|
|
574
|
+
try {
|
|
575
|
+
const res = await fetch(`/api/${guildId}/logs/reset`, { method: 'POST' });
|
|
576
|
+
const data = await res.json();
|
|
577
|
+
if (data.success) {
|
|
578
|
+
showToast('تم إعادة تعيين الإعدادات');
|
|
579
|
+
setTimeout(() => location.reload(), 1000);
|
|
580
|
+
} else {
|
|
581
|
+
showToast(data.error || 'حدث خطأ', 'error');
|
|
582
|
+
}
|
|
583
|
+
} catch (e) {
|
|
584
|
+
showToast('حدث خطأ في الاتصال', 'error');
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
</script>
|
|
588
|
+
</body>
|
|
589
|
+
</html>
|