Spaces:
Running
Running
Add 3 files
Browse files- README.md +7 -5
- index.html +1576 -19
- prompts.txt +2 -0
README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
+
title: dashmaster
|
| 3 |
+
emoji: 🐳
|
| 4 |
+
colorFrom: purple
|
| 5 |
+
colorTo: gray
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- deepsite
|
| 10 |
---
|
| 11 |
|
| 12 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
index.html
CHANGED
|
@@ -1,19 +1,1576 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="pt-BR">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Painel de Controle Inteligente</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
| 9 |
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
| 10 |
+
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
|
| 11 |
+
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
|
| 12 |
+
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
| 13 |
+
<style>
|
| 14 |
+
.dark {
|
| 15 |
+
--bg-primary: #1a1a2e;
|
| 16 |
+
--bg-secondary: #16213e;
|
| 17 |
+
--text-primary: #e6e6e6;
|
| 18 |
+
--text-secondary: #b8b8b8;
|
| 19 |
+
--accent: #4f46e5;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
.light {
|
| 23 |
+
--bg-primary: #f8fafc;
|
| 24 |
+
--bg-secondary: #ffffff;
|
| 25 |
+
--text-primary: #1e293b;
|
| 26 |
+
--text-secondary: #64748b;
|
| 27 |
+
--accent: #4f46e5;
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
body {
|
| 31 |
+
background-color: var(--bg-primary);
|
| 32 |
+
color: var(--text-primary);
|
| 33 |
+
transition: all 0.3s ease;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
.sidebar {
|
| 37 |
+
background-color: var(--bg-secondary);
|
| 38 |
+
border-right: 1px solid rgba(255, 255, 255, 0.1);
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
.card {
|
| 42 |
+
background-color: var(--bg-secondary);
|
| 43 |
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
| 44 |
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
.card:hover {
|
| 48 |
+
transform: translateY(-2px);
|
| 49 |
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2);
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
.usage-bar {
|
| 53 |
+
height: 4px;
|
| 54 |
+
position: absolute;
|
| 55 |
+
bottom: 0;
|
| 56 |
+
left: 0;
|
| 57 |
+
border-radius: 0 0 0.375rem 0.375rem;
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
.terminal {
|
| 61 |
+
font-family: 'Courier New', monospace;
|
| 62 |
+
background-color: #1e1e1e;
|
| 63 |
+
color: #f8f8f2;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
.blink {
|
| 67 |
+
animation: blink 1s step-end infinite;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
@keyframes blink {
|
| 71 |
+
from, to { opacity: 1; }
|
| 72 |
+
50% { opacity: 0; }
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
.container-status {
|
| 76 |
+
border-left-width: 4px;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
.container-status.running {
|
| 80 |
+
border-left-color: #10b981;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
.container-status.stopped {
|
| 84 |
+
border-left-color: #ef4444;
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
.container-status.restarting {
|
| 88 |
+
border-left-color: #f59e0b;
|
| 89 |
+
}
|
| 90 |
+
</style>
|
| 91 |
+
</head>
|
| 92 |
+
<body class="dark">
|
| 93 |
+
<div id="root"></div>
|
| 94 |
+
|
| 95 |
+
<script type="text/babel">
|
| 96 |
+
const { useState, useEffect } = React;
|
| 97 |
+
|
| 98 |
+
// Componentes principais
|
| 99 |
+
const App = () => {
|
| 100 |
+
const [darkMode, setDarkMode] = useState(true);
|
| 101 |
+
const [activeSection, setActiveSection] = useState('dashboard');
|
| 102 |
+
const [vpsList, setVpsList] = useState([]);
|
| 103 |
+
const [botList, setBotList] = useState([]);
|
| 104 |
+
const [contentList, setContentList] = useState([]);
|
| 105 |
+
const [user, setUser] = useState({
|
| 106 |
+
name: 'Admin',
|
| 107 |
+
role: 'admin',
|
| 108 |
+
email: 'admin@painel.com'
|
| 109 |
+
});
|
| 110 |
+
const [notifications, setNotifications] = useState([]);
|
| 111 |
+
const [showAddVpsModal, setShowAddVpsModal] = useState(false);
|
| 112 |
+
const [showAddBotModal, setShowAddBotModal] = useState(false);
|
| 113 |
+
const [showAddContentModal, setShowAddContentModal] = useState(false);
|
| 114 |
+
const [terminalOutput, setTerminalOutput] = useState([]);
|
| 115 |
+
|
| 116 |
+
// Dados mockados
|
| 117 |
+
useEffect(() => {
|
| 118 |
+
// Mock VPS data
|
| 119 |
+
setVpsList([
|
| 120 |
+
{
|
| 121 |
+
id: 1,
|
| 122 |
+
name: 'Servidor Principal',
|
| 123 |
+
ip: '192.168.1.100',
|
| 124 |
+
status: 'online',
|
| 125 |
+
cpu: 45,
|
| 126 |
+
memory: 65,
|
| 127 |
+
storage: 30,
|
| 128 |
+
containers: 5,
|
| 129 |
+
lastUpdated: new Date()
|
| 130 |
+
},
|
| 131 |
+
{
|
| 132 |
+
id: 2,
|
| 133 |
+
name: 'Servidor de Backup',
|
| 134 |
+
ip: '192.168.1.101',
|
| 135 |
+
status: 'offline',
|
| 136 |
+
cpu: 0,
|
| 137 |
+
memory: 0,
|
| 138 |
+
storage: 0,
|
| 139 |
+
containers: 0,
|
| 140 |
+
lastUpdated: new Date(Date.now() - 86400000)
|
| 141 |
+
}
|
| 142 |
+
]);
|
| 143 |
+
|
| 144 |
+
// Mock Bot data
|
| 145 |
+
setBotList([
|
| 146 |
+
{
|
| 147 |
+
id: 1,
|
| 148 |
+
name: 'Bot de Notícias',
|
| 149 |
+
type: 'scraping',
|
| 150 |
+
status: 'running',
|
| 151 |
+
lastRun: new Date(),
|
| 152 |
+
nextRun: new Date(Date.now() + 3600000),
|
| 153 |
+
logs: ['Iniciado às 10:00', 'Coletou 15 notícias']
|
| 154 |
+
},
|
| 155 |
+
{
|
| 156 |
+
id: 2,
|
| 157 |
+
name: 'Bot de Redes Sociais',
|
| 158 |
+
type: 'social',
|
| 159 |
+
status: 'stopped',
|
| 160 |
+
lastRun: new Date(Date.now() - 86400000),
|
| 161 |
+
nextRun: null,
|
| 162 |
+
logs: ['Parado pelo usuário']
|
| 163 |
+
}
|
| 164 |
+
]);
|
| 165 |
+
|
| 166 |
+
// Mock Content data
|
| 167 |
+
setContentList([
|
| 168 |
+
{
|
| 169 |
+
id: 1,
|
| 170 |
+
title: 'Análise do Mercado de IA em 2023',
|
| 171 |
+
source: 'Google News',
|
| 172 |
+
status: 'approved',
|
| 173 |
+
created: new Date(),
|
| 174 |
+
published: new Date(),
|
| 175 |
+
author: 'Sistema de IA'
|
| 176 |
+
},
|
| 177 |
+
{
|
| 178 |
+
id: 2,
|
| 179 |
+
title: 'Novas Tendências em Desenvolvimento Web',
|
| 180 |
+
source: 'Tech Blogs',
|
| 181 |
+
status: 'pending',
|
| 182 |
+
created: new Date(),
|
| 183 |
+
published: null,
|
| 184 |
+
author: 'Sistema de IA'
|
| 185 |
+
}
|
| 186 |
+
]);
|
| 187 |
+
|
| 188 |
+
// Mock notifications
|
| 189 |
+
setNotifications([
|
| 190 |
+
{
|
| 191 |
+
id: 1,
|
| 192 |
+
message: 'Novo conteúdo aguardando aprovação',
|
| 193 |
+
type: 'content',
|
| 194 |
+
read: false,
|
| 195 |
+
date: new Date()
|
| 196 |
+
},
|
| 197 |
+
{
|
| 198 |
+
id: 2,
|
| 199 |
+
message: 'Servidor de Backup está offline',
|
| 200 |
+
type: 'vps',
|
| 201 |
+
read: false,
|
| 202 |
+
date: new Date(Date.now() - 3600000)
|
| 203 |
+
}
|
| 204 |
+
]);
|
| 205 |
+
|
| 206 |
+
// Mock terminal output
|
| 207 |
+
setTerminalOutput([
|
| 208 |
+
{ id: 1, text: 'Bem-vindo ao Terminal do Painel de Controle', type: 'system' },
|
| 209 |
+
{ id: 2, text: 'Digite "help" para ver os comandos disponíveis', type: 'system' }
|
| 210 |
+
]);
|
| 211 |
+
}, []);
|
| 212 |
+
|
| 213 |
+
const toggleDarkMode = () => {
|
| 214 |
+
setDarkMode(!darkMode);
|
| 215 |
+
document.body.classList.toggle('dark');
|
| 216 |
+
document.body.classList.toggle('light');
|
| 217 |
+
};
|
| 218 |
+
|
| 219 |
+
const executeCommand = (command) => {
|
| 220 |
+
const newOutput = [
|
| 221 |
+
...terminalOutput,
|
| 222 |
+
{ id: terminalOutput.length + 1, text: `$ ${command}`, type: 'command' },
|
| 223 |
+
{ id: terminalOutput.length + 2, text: 'Comando executado com sucesso', type: 'response' }
|
| 224 |
+
];
|
| 225 |
+
setTerminalOutput(newOutput);
|
| 226 |
+
};
|
| 227 |
+
|
| 228 |
+
const renderSection = () => {
|
| 229 |
+
switch (activeSection) {
|
| 230 |
+
case 'dashboard':
|
| 231 |
+
return <DashboardSection
|
| 232 |
+
vpsList={vpsList}
|
| 233 |
+
botList={botList}
|
| 234 |
+
contentList={contentList}
|
| 235 |
+
notifications={notifications}
|
| 236 |
+
/>;
|
| 237 |
+
case 'vps':
|
| 238 |
+
return <VpsSection
|
| 239 |
+
vpsList={vpsList}
|
| 240 |
+
setShowAddVpsModal={setShowAddVpsModal}
|
| 241 |
+
executeCommand={executeCommand}
|
| 242 |
+
terminalOutput={terminalOutput}
|
| 243 |
+
/>;
|
| 244 |
+
case 'bots':
|
| 245 |
+
return <BotsSection
|
| 246 |
+
botList={botList}
|
| 247 |
+
setShowAddBotModal={setShowAddBotModal}
|
| 248 |
+
/>;
|
| 249 |
+
case 'content':
|
| 250 |
+
return <ContentSection
|
| 251 |
+
contentList={contentList}
|
| 252 |
+
setShowAddContentModal={setShowAddContentModal}
|
| 253 |
+
/>;
|
| 254 |
+
case 'settings':
|
| 255 |
+
return <SettingsSection
|
| 256 |
+
user={user}
|
| 257 |
+
darkMode={darkMode}
|
| 258 |
+
toggleDarkMode={toggleDarkMode}
|
| 259 |
+
/>;
|
| 260 |
+
default:
|
| 261 |
+
return <DashboardSection
|
| 262 |
+
vpsList={vpsList}
|
| 263 |
+
botList={botList}
|
| 264 |
+
contentList={contentList}
|
| 265 |
+
notifications={notifications}
|
| 266 |
+
/>;
|
| 267 |
+
}
|
| 268 |
+
};
|
| 269 |
+
|
| 270 |
+
return (
|
| 271 |
+
<div className="flex h-screen overflow-hidden">
|
| 272 |
+
{/* Sidebar */}
|
| 273 |
+
<Sidebar
|
| 274 |
+
activeSection={activeSection}
|
| 275 |
+
setActiveSection={setActiveSection}
|
| 276 |
+
user={user}
|
| 277 |
+
notifications={notifications}
|
| 278 |
+
/>
|
| 279 |
+
|
| 280 |
+
{/* Main Content */}
|
| 281 |
+
<div className="flex-1 overflow-auto">
|
| 282 |
+
{/* Header */}
|
| 283 |
+
<Header
|
| 284 |
+
activeSection={activeSection}
|
| 285 |
+
darkMode={darkMode}
|
| 286 |
+
toggleDarkMode={toggleDarkMode}
|
| 287 |
+
user={user}
|
| 288 |
+
setShowAddVpsModal={setShowAddVpsModal}
|
| 289 |
+
setShowAddBotModal={setShowAddBotModal}
|
| 290 |
+
setShowAddContentModal={setShowAddContentModal}
|
| 291 |
+
/>
|
| 292 |
+
|
| 293 |
+
{/* Main Content */}
|
| 294 |
+
<main className="p-6">
|
| 295 |
+
{renderSection()}
|
| 296 |
+
</main>
|
| 297 |
+
</div>
|
| 298 |
+
|
| 299 |
+
{/* Modals */}
|
| 300 |
+
{showAddVpsModal && (
|
| 301 |
+
<AddVpsModal
|
| 302 |
+
setShowAddVpsModal={setShowAddVpsModal}
|
| 303 |
+
setVpsList={setVpsList}
|
| 304 |
+
/>
|
| 305 |
+
)}
|
| 306 |
+
|
| 307 |
+
{showAddBotModal && (
|
| 308 |
+
<AddBotModal
|
| 309 |
+
setShowAddBotModal={setShowAddBotModal}
|
| 310 |
+
setBotList={setBotList}
|
| 311 |
+
/>
|
| 312 |
+
)}
|
| 313 |
+
|
| 314 |
+
{showAddContentModal && (
|
| 315 |
+
<AddContentModal
|
| 316 |
+
setShowAddContentModal={setShowAddContentModal}
|
| 317 |
+
setContentList={setContentList}
|
| 318 |
+
/>
|
| 319 |
+
)}
|
| 320 |
+
</div>
|
| 321 |
+
);
|
| 322 |
+
};
|
| 323 |
+
|
| 324 |
+
// Componentes de layout
|
| 325 |
+
const Sidebar = ({ activeSection, setActiveSection, user, notifications }) => {
|
| 326 |
+
const unreadNotifications = notifications.filter(n => !n.read).length;
|
| 327 |
+
|
| 328 |
+
return (
|
| 329 |
+
<div className="sidebar w-64 flex-shrink-0 flex flex-col">
|
| 330 |
+
<div className="p-4 border-b border-gray-700 flex items-center justify-between">
|
| 331 |
+
<h1 className="text-xl font-bold text-white flex items-center">
|
| 332 |
+
<i className="fas fa-robot text-indigo-500 mr-2"></i>
|
| 333 |
+
<span>Painel AI</span>
|
| 334 |
+
</h1>
|
| 335 |
+
</div>
|
| 336 |
+
|
| 337 |
+
<div className="flex-1 overflow-y-auto">
|
| 338 |
+
<nav className="p-4">
|
| 339 |
+
<div className="mb-6">
|
| 340 |
+
<h3 className="text-xs uppercase font-semibold text-gray-400 mb-3">GERAL</h3>
|
| 341 |
+
<ul>
|
| 342 |
+
<li className="mb-2">
|
| 343 |
+
<button
|
| 344 |
+
onClick={() => setActiveSection('dashboard')}
|
| 345 |
+
className={`w-full text-left flex items-center p-2 rounded-lg ${activeSection === 'dashboard' ? 'bg-indigo-500/20 text-indigo-400' : 'hover:bg-gray-700'}`}
|
| 346 |
+
>
|
| 347 |
+
<i className="fas fa-tachometer-alt mr-3"></i>
|
| 348 |
+
Dashboard
|
| 349 |
+
</button>
|
| 350 |
+
</li>
|
| 351 |
+
</ul>
|
| 352 |
+
</div>
|
| 353 |
+
|
| 354 |
+
<div className="mb-6">
|
| 355 |
+
<h3 className="text-xs uppercase font-semibold text-gray-400 mb-3">GERENCIAMENTO</h3>
|
| 356 |
+
<ul>
|
| 357 |
+
<li className="mb-2">
|
| 358 |
+
<button
|
| 359 |
+
onClick={() => setActiveSection('vps')}
|
| 360 |
+
className={`w-full text-left flex items-center p-2 rounded-lg ${activeSection === 'vps' ? 'bg-indigo-500/20 text-indigo-400' : 'hover:bg-gray-700'}`}
|
| 361 |
+
>
|
| 362 |
+
<i className="fas fa-server mr-3"></i>
|
| 363 |
+
VPS
|
| 364 |
+
</button>
|
| 365 |
+
</li>
|
| 366 |
+
<li className="mb-2">
|
| 367 |
+
<button
|
| 368 |
+
onClick={() => setActiveSection('bots')}
|
| 369 |
+
className={`w-full text-left flex items-center p-2 rounded-lg ${activeSection === 'bots' ? 'bg-indigo-500/20 text-indigo-400' : 'hover:bg-gray-700'}`}
|
| 370 |
+
>
|
| 371 |
+
<i className="fas fa-robot mr-3"></i>
|
| 372 |
+
Bots
|
| 373 |
+
</button>
|
| 374 |
+
</li>
|
| 375 |
+
<li className="mb-2">
|
| 376 |
+
<button
|
| 377 |
+
onClick={() => setActiveSection('content')}
|
| 378 |
+
className={`w-full text-left flex items-center p-2 rounded-lg ${activeSection === 'content' ? 'bg-indigo-500/20 text-indigo-400' : 'hover:bg-gray-700'}`}
|
| 379 |
+
>
|
| 380 |
+
<i className="fas fa-newspaper mr-3"></i>
|
| 381 |
+
Conteúdo
|
| 382 |
+
{unreadNotifications > 0 && (
|
| 383 |
+
<span className="ml-auto bg-red-500 text-white text-xs px-2 py-1 rounded-full">
|
| 384 |
+
{unreadNotifications}
|
| 385 |
+
</span>
|
| 386 |
+
)}
|
| 387 |
+
</button>
|
| 388 |
+
</li>
|
| 389 |
+
</ul>
|
| 390 |
+
</div>
|
| 391 |
+
|
| 392 |
+
<div className="mb-6">
|
| 393 |
+
<h3 className="text-xs uppercase font-semibold text-gray-400 mb-3">CONFIGURAÇÕES</h3>
|
| 394 |
+
<ul>
|
| 395 |
+
<li className="mb-2">
|
| 396 |
+
<button
|
| 397 |
+
onClick={() => setActiveSection('settings')}
|
| 398 |
+
className={`w-full text-left flex items-center p-2 rounded-lg ${activeSection === 'settings' ? 'bg-indigo-500/20 text-indigo-400' : 'hover:bg-gray-700'}`}
|
| 399 |
+
>
|
| 400 |
+
<i className="fas fa-cog mr-3"></i>
|
| 401 |
+
Configurações
|
| 402 |
+
</button>
|
| 403 |
+
</li>
|
| 404 |
+
</ul>
|
| 405 |
+
</div>
|
| 406 |
+
</nav>
|
| 407 |
+
</div>
|
| 408 |
+
|
| 409 |
+
<div className="p-4 border-t border-gray-700">
|
| 410 |
+
<div className="flex items-center justify-between">
|
| 411 |
+
<div className="flex items-center">
|
| 412 |
+
<div className="w-10 h-10 rounded-full bg-indigo-500 flex items-center justify-center">
|
| 413 |
+
<i className="fas fa-user text-white"></i>
|
| 414 |
+
</div>
|
| 415 |
+
<div className="ml-3">
|
| 416 |
+
<p className="text-sm font-medium">{user.name}</p>
|
| 417 |
+
<p className="text-xs text-gray-400">{user.role}</p>
|
| 418 |
+
</div>
|
| 419 |
+
</div>
|
| 420 |
+
<button className="text-gray-400 hover:text-white">
|
| 421 |
+
<i className="fas fa-sign-out-alt"></i>
|
| 422 |
+
</button>
|
| 423 |
+
</div>
|
| 424 |
+
</div>
|
| 425 |
+
</div>
|
| 426 |
+
);
|
| 427 |
+
};
|
| 428 |
+
|
| 429 |
+
const Header = ({
|
| 430 |
+
activeSection,
|
| 431 |
+
darkMode,
|
| 432 |
+
toggleDarkMode,
|
| 433 |
+
user,
|
| 434 |
+
setShowAddVpsModal,
|
| 435 |
+
setShowAddBotModal,
|
| 436 |
+
setShowAddContentModal
|
| 437 |
+
}) => {
|
| 438 |
+
const sectionTitles = {
|
| 439 |
+
dashboard: 'Dashboard',
|
| 440 |
+
vps: 'Gerenciamento de VPS',
|
| 441 |
+
bots: 'Controle de Bots',
|
| 442 |
+
content: 'Gestão de Conteúdo',
|
| 443 |
+
settings: 'Configurações'
|
| 444 |
+
};
|
| 445 |
+
|
| 446 |
+
const handleAddNew = () => {
|
| 447 |
+
switch (activeSection) {
|
| 448 |
+
case 'vps':
|
| 449 |
+
setShowAddVpsModal(true);
|
| 450 |
+
break;
|
| 451 |
+
case 'bots':
|
| 452 |
+
setShowAddBotModal(true);
|
| 453 |
+
break;
|
| 454 |
+
case 'content':
|
| 455 |
+
setShowAddContentModal(true);
|
| 456 |
+
break;
|
| 457 |
+
default:
|
| 458 |
+
break;
|
| 459 |
+
}
|
| 460 |
+
};
|
| 461 |
+
|
| 462 |
+
return (
|
| 463 |
+
<header className="bg-gray-800 border-b border-gray-700 p-4 flex justify-between items-center">
|
| 464 |
+
<h2 className="text-xl font-semibold">{sectionTitles[activeSection]}</h2>
|
| 465 |
+
|
| 466 |
+
<div className="flex items-center space-x-4">
|
| 467 |
+
<div className="relative">
|
| 468 |
+
<i className="fas fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"></i>
|
| 469 |
+
<input
|
| 470 |
+
type="text"
|
| 471 |
+
placeholder="Pesquisar..."
|
| 472 |
+
className="bg-gray-700 border border-gray-600 rounded-lg pl-10 pr-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
| 473 |
+
/>
|
| 474 |
+
</div>
|
| 475 |
+
|
| 476 |
+
<button
|
| 477 |
+
onClick={toggleDarkMode}
|
| 478 |
+
className="text-gray-400 hover:text-white p-2"
|
| 479 |
+
>
|
| 480 |
+
{darkMode ? (
|
| 481 |
+
<i className="fas fa-sun"></i>
|
| 482 |
+
) : (
|
| 483 |
+
<i className="fas fa-moon"></i>
|
| 484 |
+
)}
|
| 485 |
+
</button>
|
| 486 |
+
|
| 487 |
+
{(activeSection === 'vps' || activeSection === 'bots' || activeSection === 'content') && (
|
| 488 |
+
<button
|
| 489 |
+
onClick={handleAddNew}
|
| 490 |
+
className="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg flex items-center"
|
| 491 |
+
>
|
| 492 |
+
<i className="fas fa-plus mr-2"></i>
|
| 493 |
+
Adicionar
|
| 494 |
+
</button>
|
| 495 |
+
)}
|
| 496 |
+
</div>
|
| 497 |
+
</header>
|
| 498 |
+
);
|
| 499 |
+
};
|
| 500 |
+
|
| 501 |
+
// Componentes de seção
|
| 502 |
+
const DashboardSection = ({ vpsList, botList, contentList, notifications }) => {
|
| 503 |
+
const onlineVps = vpsList.filter(vps => vps.status === 'online').length;
|
| 504 |
+
const runningBots = botList.filter(bot => bot.status === 'running').length;
|
| 505 |
+
const pendingContent = contentList.filter(content => content.status === 'pending').length;
|
| 506 |
+
|
| 507 |
+
return (
|
| 508 |
+
<div className="space-y-6">
|
| 509 |
+
{/* Quick Stats */}
|
| 510 |
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
| 511 |
+
<div className="card rounded-lg p-6 relative">
|
| 512 |
+
<div className="flex justify-between items-start">
|
| 513 |
+
<div>
|
| 514 |
+
<p className="text-gray-400">VPS Online</p>
|
| 515 |
+
<h3 className="text-2xl font-bold mt-1">{onlineVps}/{vpsList.length}</h3>
|
| 516 |
+
</div>
|
| 517 |
+
<div className="bg-blue-500/10 p-3 rounded-full">
|
| 518 |
+
<i className="fas fa-server text-blue-500"></i>
|
| 519 |
+
</div>
|
| 520 |
+
</div>
|
| 521 |
+
<div className="usage-bar bg-blue-500" style={{ width: `${(onlineVps / vpsList.length) * 100}%` }}></div>
|
| 522 |
+
</div>
|
| 523 |
+
|
| 524 |
+
<div className="card rounded-lg p-6 relative">
|
| 525 |
+
<div className="flex justify-between items-start">
|
| 526 |
+
<div>
|
| 527 |
+
<p className="text-gray-400">Bots Ativos</p>
|
| 528 |
+
<h3 className="text-2xl font-bold mt-1">{runningBots}/{botList.length}</h3>
|
| 529 |
+
</div>
|
| 530 |
+
<div className="bg-green-500/10 p-3 rounded-full">
|
| 531 |
+
<i className="fas fa-robot text-green-500"></i>
|
| 532 |
+
</div>
|
| 533 |
+
</div>
|
| 534 |
+
<div className="usage-bar bg-green-500" style={{ width: `${(runningBots / botList.length) * 100}%` }}></div>
|
| 535 |
+
</div>
|
| 536 |
+
|
| 537 |
+
<div className="card rounded-lg p-6 relative">
|
| 538 |
+
<div className="flex justify-between items-start">
|
| 539 |
+
<div>
|
| 540 |
+
<p className="text-gray-400">Conteúdo Pendente</p>
|
| 541 |
+
<h3 className="text-2xl font-bold mt-1">{pendingContent}</h3>
|
| 542 |
+
</div>
|
| 543 |
+
<div className="bg-yellow-500/10 p-3 rounded-full">
|
| 544 |
+
<i className="fas fa-newspaper text-yellow-500"></i>
|
| 545 |
+
</div>
|
| 546 |
+
</div>
|
| 547 |
+
<div className="usage-bar bg-yellow-500" style={{ width: `${(pendingContent / (contentList.length || 1)) * 100}%` }}></div>
|
| 548 |
+
</div>
|
| 549 |
+
|
| 550 |
+
<div className="card rounded-lg p-6 relative">
|
| 551 |
+
<div className="flex justify-between items-start">
|
| 552 |
+
<div>
|
| 553 |
+
<p className="text-gray-400">Notificações</p>
|
| 554 |
+
<h3 className="text-2xl font-bold mt-1">{notifications.filter(n => !n.read).length}</h3>
|
| 555 |
+
</div>
|
| 556 |
+
<div className="bg-red-500/10 p-3 rounded-full">
|
| 557 |
+
<i className="fas fa-bell text-red-500"></i>
|
| 558 |
+
</div>
|
| 559 |
+
</div>
|
| 560 |
+
<div className="usage-bar bg-red-500" style={{ width: `${(notifications.filter(n => !n.read).length / (notifications.length || 1)) * 100}%` }}></div>
|
| 561 |
+
</div>
|
| 562 |
+
</div>
|
| 563 |
+
|
| 564 |
+
{/* Charts */}
|
| 565 |
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
| 566 |
+
<div className="card rounded-lg p-4">
|
| 567 |
+
<h3 className="font-medium mb-4">Uso de Recursos das VPS</h3>
|
| 568 |
+
<canvas id="resourceChart" height="200"></canvas>
|
| 569 |
+
</div>
|
| 570 |
+
|
| 571 |
+
<div className="card rounded-lg p-4">
|
| 572 |
+
<h3 className="font-medium mb-4">Atividade de Bots</h3>
|
| 573 |
+
<canvas id="botActivityChart" height="200"></canvas>
|
| 574 |
+
</div>
|
| 575 |
+
</div>
|
| 576 |
+
|
| 577 |
+
{/* Recent Activity */}
|
| 578 |
+
<div className="card rounded-lg">
|
| 579 |
+
<div className="border-b border-gray-700 p-4">
|
| 580 |
+
<h3 className="font-semibold">Atividade Recente</h3>
|
| 581 |
+
</div>
|
| 582 |
+
<div className="p-4">
|
| 583 |
+
<div className="space-y-4">
|
| 584 |
+
{notifications.slice(0, 5).map(notification => (
|
| 585 |
+
<div key={notification.id} className="flex items-start">
|
| 586 |
+
<div className={`p-2 rounded-full mr-3 ${
|
| 587 |
+
notification.type === 'vps' ? 'bg-blue-500/10 text-blue-500' :
|
| 588 |
+
notification.type === 'content' ? 'bg-yellow-500/10 text-yellow-500' :
|
| 589 |
+
'bg-gray-500/10 text-gray-500'
|
| 590 |
+
}`}>
|
| 591 |
+
<i className={
|
| 592 |
+
notification.type === 'vps' ? 'fas fa-server' :
|
| 593 |
+
notification.type === 'content' ? 'fas fa-newspaper' :
|
| 594 |
+
'fas fa-info-circle'
|
| 595 |
+
}></i>
|
| 596 |
+
</div>
|
| 597 |
+
<div>
|
| 598 |
+
<p className="text-sm">{notification.message}</p>
|
| 599 |
+
<p className="text-xs text-gray-400">{new Date(notification.date).toLocaleString()}</p>
|
| 600 |
+
</div>
|
| 601 |
+
</div>
|
| 602 |
+
))}
|
| 603 |
+
</div>
|
| 604 |
+
</div>
|
| 605 |
+
</div>
|
| 606 |
+
</div>
|
| 607 |
+
);
|
| 608 |
+
};
|
| 609 |
+
|
| 610 |
+
const VpsSection = ({ vpsList, setShowAddVpsModal, executeCommand, terminalOutput }) => {
|
| 611 |
+
const [selectedVps, setSelectedVps] = useState(null);
|
| 612 |
+
const [command, setCommand] = useState('');
|
| 613 |
+
|
| 614 |
+
useEffect(() => {
|
| 615 |
+
// Initialize charts
|
| 616 |
+
if (selectedVps) {
|
| 617 |
+
const cpuCtx = document.getElementById('vpsCpuChart').getContext('2d');
|
| 618 |
+
const memoryCtx = document.getElementById('vpsMemoryChart').getContext('2d');
|
| 619 |
+
|
| 620 |
+
new Chart(cpuCtx, {
|
| 621 |
+
type: 'line',
|
| 622 |
+
data: {
|
| 623 |
+
labels: Array(24).fill().map((_, i) => `${i}h`),
|
| 624 |
+
datasets: [{
|
| 625 |
+
label: 'Uso de CPU',
|
| 626 |
+
data: Array(24).fill().map(() => Math.random() * 100),
|
| 627 |
+
borderColor: '#3B82F6',
|
| 628 |
+
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
| 629 |
+
tension: 0.4,
|
| 630 |
+
fill: true
|
| 631 |
+
}]
|
| 632 |
+
},
|
| 633 |
+
options: {
|
| 634 |
+
responsive: true,
|
| 635 |
+
plugins: {
|
| 636 |
+
legend: { display: false }
|
| 637 |
+
},
|
| 638 |
+
scales: {
|
| 639 |
+
y: { beginAtZero: true, max: 100 }
|
| 640 |
+
}
|
| 641 |
+
}
|
| 642 |
+
});
|
| 643 |
+
|
| 644 |
+
new Chart(memoryCtx, {
|
| 645 |
+
type: 'line',
|
| 646 |
+
data: {
|
| 647 |
+
labels: Array(24).fill().map((_, i) => `${i}h`),
|
| 648 |
+
datasets: [{
|
| 649 |
+
label: 'Uso de Memória',
|
| 650 |
+
data: Array(24).fill().map(() => Math.random() * 100),
|
| 651 |
+
borderColor: '#8B5CF6',
|
| 652 |
+
backgroundColor: 'rgba(139, 92, 246, 0.1)',
|
| 653 |
+
tension: 0.4,
|
| 654 |
+
fill: true
|
| 655 |
+
}]
|
| 656 |
+
},
|
| 657 |
+
options: {
|
| 658 |
+
responsive: true,
|
| 659 |
+
plugins: {
|
| 660 |
+
legend: { display: false }
|
| 661 |
+
},
|
| 662 |
+
scales: {
|
| 663 |
+
y: { beginAtZero: true, max: 100 }
|
| 664 |
+
}
|
| 665 |
+
}
|
| 666 |
+
});
|
| 667 |
+
}
|
| 668 |
+
}, [selectedVps]);
|
| 669 |
+
|
| 670 |
+
const handleCommandSubmit = (e) => {
|
| 671 |
+
e.preventDefault();
|
| 672 |
+
if (command.trim()) {
|
| 673 |
+
executeCommand(command);
|
| 674 |
+
setCommand('');
|
| 675 |
+
}
|
| 676 |
+
};
|
| 677 |
+
|
| 678 |
+
return (
|
| 679 |
+
<div className="space-y-6">
|
| 680 |
+
<div className="flex justify-between items-center">
|
| 681 |
+
<h3 className="text-lg font-semibold">Servidores VPS</h3>
|
| 682 |
+
<button
|
| 683 |
+
onClick={() => setShowAddVpsModal(true)}
|
| 684 |
+
className="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg flex items-center"
|
| 685 |
+
>
|
| 686 |
+
<i className="fas fa-plus mr-2"></i>
|
| 687 |
+
Adicionar VPS
|
| 688 |
+
</button>
|
| 689 |
+
</div>
|
| 690 |
+
|
| 691 |
+
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
| 692 |
+
{/* VPS List */}
|
| 693 |
+
<div className="lg:col-span-1">
|
| 694 |
+
<div className="card rounded-lg">
|
| 695 |
+
<div className="border-b border-gray-700 p-4">
|
| 696 |
+
<h3 className="font-semibold">Lista de Servidores</h3>
|
| 697 |
+
</div>
|
| 698 |
+
<div className="p-4 space-y-3">
|
| 699 |
+
{vpsList.map(vps => (
|
| 700 |
+
<div
|
| 701 |
+
key={vps.id}
|
| 702 |
+
onClick={() => setSelectedVps(vps)}
|
| 703 |
+
className={`p-3 rounded-lg cursor-pointer ${selectedVps?.id === vps.id ? 'bg-indigo-500/10 border border-indigo-500/30' : 'hover:bg-gray-700'}`}
|
| 704 |
+
>
|
| 705 |
+
<div className="flex justify-between items-center">
|
| 706 |
+
<h4 className="font-medium">{vps.name}</h4>
|
| 707 |
+
<span className={`px-2 py-1 text-xs rounded-full ${
|
| 708 |
+
vps.status === 'online' ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
|
| 709 |
+
}`}>
|
| 710 |
+
{vps.status === 'online' ? 'Online' : 'Offline'}
|
| 711 |
+
</span>
|
| 712 |
+
</div>
|
| 713 |
+
<p className="text-sm text-gray-400">{vps.ip}</p>
|
| 714 |
+
<div className="flex justify-between mt-2 text-xs">
|
| 715 |
+
<span className="text-blue-400">CPU: {vps.cpu}%</span>
|
| 716 |
+
<span className="text-purple-400">RAM: {vps.memory}%</span>
|
| 717 |
+
<span className="text-yellow-400">DISK: {vps.storage}%</span>
|
| 718 |
+
</div>
|
| 719 |
+
</div>
|
| 720 |
+
))}
|
| 721 |
+
</div>
|
| 722 |
+
</div>
|
| 723 |
+
</div>
|
| 724 |
+
|
| 725 |
+
{/* VPS Details */}
|
| 726 |
+
<div className="lg:col-span-2 space-y-6">
|
| 727 |
+
{selectedVps ? (
|
| 728 |
+
<>
|
| 729 |
+
<div className="card rounded-lg p-6">
|
| 730 |
+
<div className="flex justify-between items-center mb-4">
|
| 731 |
+
<h3 className="text-xl font-semibold">{selectedVps.name}</h3>
|
| 732 |
+
<div className="flex space-x-2">
|
| 733 |
+
<button className="bg-green-600 hover:bg-green-700 text-white px-3 py-1 rounded text-sm">
|
| 734 |
+
<i className="fas fa-play mr-1"></i> Iniciar
|
| 735 |
+
</button>
|
| 736 |
+
<button className="bg-yellow-600 hover:bg-yellow-700 text-white px-3 py-1 rounded text-sm">
|
| 737 |
+
<i className="fas fa-redo mr-1"></i> Reiniciar
|
| 738 |
+
</button>
|
| 739 |
+
<button className="bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded text-sm">
|
| 740 |
+
<i className="fas fa-stop mr-1"></i> Parar
|
| 741 |
+
</button>
|
| 742 |
+
</div>
|
| 743 |
+
</div>
|
| 744 |
+
|
| 745 |
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
| 746 |
+
<div className="bg-gray-700/50 p-3 rounded-lg">
|
| 747 |
+
<p className="text-gray-400 text-sm">Endereço IP</p>
|
| 748 |
+
<p className="font-medium">{selectedVps.ip}</p>
|
| 749 |
+
</div>
|
| 750 |
+
<div className="bg-gray-700/50 p-3 rounded-lg">
|
| 751 |
+
<p className="text-gray-400 text-sm">Status</p>
|
| 752 |
+
<p className={`font-medium ${
|
| 753 |
+
selectedVps.status === 'online' ? 'text-green-400' : 'text-red-400'
|
| 754 |
+
}`}>
|
| 755 |
+
{selectedVps.status === 'online' ? 'Online' : 'Offline'}
|
| 756 |
+
</p>
|
| 757 |
+
</div>
|
| 758 |
+
<div className="bg-gray-700/50 p-3 rounded-lg">
|
| 759 |
+
<p className="text-gray-400 text-sm">Última Atualização</p>
|
| 760 |
+
<p className="font-medium">{new Date(selectedVps.lastUpdated).toLocaleString()}</p>
|
| 761 |
+
</div>
|
| 762 |
+
</div>
|
| 763 |
+
|
| 764 |
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
| 765 |
+
<div>
|
| 766 |
+
<h4 className="font-medium mb-3">Uso de CPU</h4>
|
| 767 |
+
<canvas id="vpsCpuChart" height="150"></canvas>
|
| 768 |
+
</div>
|
| 769 |
+
<div>
|
| 770 |
+
<h4 className="font-medium mb-3">Uso de Memória</h4>
|
| 771 |
+
<canvas id="vpsMemoryChart" height="150"></canvas>
|
| 772 |
+
</div>
|
| 773 |
+
</div>
|
| 774 |
+
</div>
|
| 775 |
+
|
| 776 |
+
<div className="card rounded-lg">
|
| 777 |
+
<div className="border-b border-gray-700 p-4">
|
| 778 |
+
<h3 className="font-semibold">Terminal</h3>
|
| 779 |
+
</div>
|
| 780 |
+
<div className="p-4">
|
| 781 |
+
<div className="terminal rounded-lg p-4 mb-4 h-48 overflow-y-auto">
|
| 782 |
+
{terminalOutput.map(line => (
|
| 783 |
+
<div
|
| 784 |
+
key={line.id}
|
| 785 |
+
className={`terminal-line ${line.type === 'command' ? 'text-blue-400' : line.type === 'error' ? 'text-red-400' : 'text-gray-400'}`}
|
| 786 |
+
>
|
| 787 |
+
{line.text}
|
| 788 |
+
</div>
|
| 789 |
+
))}
|
| 790 |
+
<div className="terminal-line text-green-400">
|
| 791 |
+
<span className="mr-2">$</span>
|
| 792 |
+
<span className="blink">_</span>
|
| 793 |
+
</div>
|
| 794 |
+
</div>
|
| 795 |
+
|
| 796 |
+
<form onSubmit={handleCommandSubmit} className="flex">
|
| 797 |
+
<input
|
| 798 |
+
type="text"
|
| 799 |
+
value={command}
|
| 800 |
+
onChange={(e) => setCommand(e.target.value)}
|
| 801 |
+
placeholder="Digite um comando..."
|
| 802 |
+
className="flex-1 bg-gray-700 border border-gray-600 rounded-l-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
| 803 |
+
/>
|
| 804 |
+
<button
|
| 805 |
+
type="submit"
|
| 806 |
+
className="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-r-lg"
|
| 807 |
+
>
|
| 808 |
+
Executar
|
| 809 |
+
</button>
|
| 810 |
+
</form>
|
| 811 |
+
</div>
|
| 812 |
+
</div>
|
| 813 |
+
</>
|
| 814 |
+
) : (
|
| 815 |
+
<div className="card rounded-lg p-6 flex flex-col items-center justify-center h-full">
|
| 816 |
+
<i className="fas fa-server text-4xl text-gray-500 mb-4"></i>
|
| 817 |
+
<p className="text-gray-400">Selecione um servidor para visualizar os detalhes</p>
|
| 818 |
+
</div>
|
| 819 |
+
)}
|
| 820 |
+
</div>
|
| 821 |
+
</div>
|
| 822 |
+
</div>
|
| 823 |
+
);
|
| 824 |
+
};
|
| 825 |
+
|
| 826 |
+
const BotsSection = ({ botList, setShowAddBotModal }) => {
|
| 827 |
+
const [selectedBot, setSelectedBot] = useState(null);
|
| 828 |
+
|
| 829 |
+
return (
|
| 830 |
+
<div className="space-y-6">
|
| 831 |
+
<div className="flex justify-between items-center">
|
| 832 |
+
<h3 className="text-lg font-semibold">Controle de Bots</h3>
|
| 833 |
+
<button
|
| 834 |
+
onClick={() => setShowAddBotModal(true)}
|
| 835 |
+
className="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg flex items-center"
|
| 836 |
+
>
|
| 837 |
+
<i className="fas fa-plus mr-2"></i>
|
| 838 |
+
Adicionar Bot
|
| 839 |
+
</button>
|
| 840 |
+
</div>
|
| 841 |
+
|
| 842 |
+
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
| 843 |
+
{/* Bot List */}
|
| 844 |
+
<div className="lg:col-span-1">
|
| 845 |
+
<div className="card rounded-lg">
|
| 846 |
+
<div className="border-b border-gray-700 p-4">
|
| 847 |
+
<h3 className="font-semibold">Lista de Bots</h3>
|
| 848 |
+
</div>
|
| 849 |
+
<div className="p-4 space-y-3">
|
| 850 |
+
{botList.map(bot => (
|
| 851 |
+
<div
|
| 852 |
+
key={bot.id}
|
| 853 |
+
onClick={() => setSelectedBot(bot)}
|
| 854 |
+
className={`p-3 rounded-lg cursor-pointer ${selectedBot?.id === bot.id ? 'bg-indigo-500/10 border border-indigo-500/30' : 'hover:bg-gray-700'}`}
|
| 855 |
+
>
|
| 856 |
+
<div className="flex justify-between items-center">
|
| 857 |
+
<h4 className="font-medium">{bot.name}</h4>
|
| 858 |
+
<span className={`px-2 py-1 text-xs rounded-full ${
|
| 859 |
+
bot.status === 'running' ? 'bg-green-500/20 text-green-400' :
|
| 860 |
+
bot.status === 'stopped' ? 'bg-red-500/20 text-red-400' :
|
| 861 |
+
'bg-yellow-500/20 text-yellow-400'
|
| 862 |
+
}`}>
|
| 863 |
+
{bot.status === 'running' ? 'Ativo' : bot.status === 'stopped' ? 'Parado' : 'Pendente'}
|
| 864 |
+
</span>
|
| 865 |
+
</div>
|
| 866 |
+
<p className="text-sm text-gray-400 capitalize">{bot.type}</p>
|
| 867 |
+
<div className="flex justify-between mt-2 text-xs">
|
| 868 |
+
<span className="text-gray-400">Última execução: {new Date(bot.lastRun).toLocaleTimeString()}</span>
|
| 869 |
+
</div>
|
| 870 |
+
</div>
|
| 871 |
+
))}
|
| 872 |
+
</div>
|
| 873 |
+
</div>
|
| 874 |
+
</div>
|
| 875 |
+
|
| 876 |
+
{/* Bot Details */}
|
| 877 |
+
<div className="lg:col-span-2">
|
| 878 |
+
{selectedBot ? (
|
| 879 |
+
<div className="card rounded-lg p-6">
|
| 880 |
+
<div className="flex justify-between items-center mb-4">
|
| 881 |
+
<h3 className="text-xl font-semibold">{selectedBot.name}</h3>
|
| 882 |
+
<div className="flex space-x-2">
|
| 883 |
+
<button className={`px-3 py-1 rounded text-sm ${
|
| 884 |
+
selectedBot.status === 'running' ? 'bg-red-600 hover:bg-red-700' : 'bg-green-600 hover:bg-green-700'
|
| 885 |
+
} text-white`}
|
| 886 |
+
>
|
| 887 |
+
<i className={`fas ${selectedBot.status === 'running' ? 'fa-stop' : 'fa-play'} mr-1`}></i>
|
| 888 |
+
{selectedBot.status === 'running' ? 'Parar' : 'Iniciar'}
|
| 889 |
+
</button>
|
| 890 |
+
<button className="bg-indigo-600 hover:bg-indigo-700 text-white px-3 py-1 rounded text-sm">
|
| 891 |
+
<i className="fas fa-cog mr-1"></i> Configurar
|
| 892 |
+
</button>
|
| 893 |
+
</div>
|
| 894 |
+
</div>
|
| 895 |
+
|
| 896 |
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
| 897 |
+
<div className="bg-gray-700/50 p-3 rounded-lg">
|
| 898 |
+
<p className="text-gray-400 text-sm">Tipo</p>
|
| 899 |
+
<p className="font-medium capitalize">{selectedBot.type}</p>
|
| 900 |
+
</div>
|
| 901 |
+
<div className="bg-gray-700/50 p-3 rounded-lg">
|
| 902 |
+
<p className="text-gray-400 text-sm">Status</p>
|
| 903 |
+
<p className={`font-medium ${
|
| 904 |
+
selectedBot.status === 'running' ? 'text-green-400' :
|
| 905 |
+
selectedBot.status === 'stopped' ? 'text-red-400' :
|
| 906 |
+
'text-yellow-400'
|
| 907 |
+
}`}>
|
| 908 |
+
{selectedBot.status === 'running' ? 'Ativo' :
|
| 909 |
+
selectedBot.status === 'stopped' ? 'Parado' :
|
| 910 |
+
'Pendente'}
|
| 911 |
+
</p>
|
| 912 |
+
</div>
|
| 913 |
+
<div className="bg-gray-700/50 p-3 rounded-lg">
|
| 914 |
+
<p className="text-gray-400 text-sm">Última Execução</p>
|
| 915 |
+
<p className="font-medium">{new Date(selectedBot.lastRun).toLocaleString()}</p>
|
| 916 |
+
</div>
|
| 917 |
+
<div className="bg-gray-700/50 p-3 rounded-lg">
|
| 918 |
+
<p className="text-gray-400 text-sm">Próxima Execução</p>
|
| 919 |
+
<p className="font-medium">
|
| 920 |
+
{selectedBot.nextRun ? new Date(selectedBot.nextRun).toLocaleString() : 'Não agendado'}
|
| 921 |
+
</p>
|
| 922 |
+
</div>
|
| 923 |
+
</div>
|
| 924 |
+
|
| 925 |
+
<div>
|
| 926 |
+
<h4 className="font-medium mb-3">Logs de Execução</h4>
|
| 927 |
+
<div className="bg-gray-800 border border-gray-700 rounded-lg p-4 h-48 overflow-y-auto">
|
| 928 |
+
{selectedBot.logs.map((log, index) => (
|
| 929 |
+
<div key={index} className="text-sm font-mono mb-1">
|
| 930 |
+
<span className="text-gray-500">[{new Date().toLocaleTimeString()}]</span> {log}
|
| 931 |
+
</div>
|
| 932 |
+
))}
|
| 933 |
+
</div>
|
| 934 |
+
</div>
|
| 935 |
+
</div>
|
| 936 |
+
) : (
|
| 937 |
+
<div className="card rounded-lg p-6 flex flex-col items-center justify-center h-full">
|
| 938 |
+
<i className="fas fa-robot text-4xl text-gray-500 mb-4"></i>
|
| 939 |
+
<p className="text-gray-400">Selecione um bot para visualizar os detalhes</p>
|
| 940 |
+
</div>
|
| 941 |
+
)}
|
| 942 |
+
</div>
|
| 943 |
+
</div>
|
| 944 |
+
</div>
|
| 945 |
+
);
|
| 946 |
+
};
|
| 947 |
+
|
| 948 |
+
const ContentSection = ({ contentList, setShowAddContentModal }) => {
|
| 949 |
+
const [selectedContent, setSelectedContent] = useState(null);
|
| 950 |
+
const [filter, setFilter] = useState('all');
|
| 951 |
+
|
| 952 |
+
const filteredContent = contentList.filter(content => {
|
| 953 |
+
if (filter === 'all') return true;
|
| 954 |
+
return content.status === filter;
|
| 955 |
+
});
|
| 956 |
+
|
| 957 |
+
return (
|
| 958 |
+
<div className="space-y-6">
|
| 959 |
+
<div className="flex justify-between items-center">
|
| 960 |
+
<h3 className="text-lg font-semibold">Gestão de Conteúdo</h3>
|
| 961 |
+
<button
|
| 962 |
+
onClick={() => setShowAddContentModal(true)}
|
| 963 |
+
className="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg flex items-center"
|
| 964 |
+
>
|
| 965 |
+
<i className="fas fa-plus mr-2"></i>
|
| 966 |
+
Novo Conteúdo
|
| 967 |
+
</button>
|
| 968 |
+
</div>
|
| 969 |
+
|
| 970 |
+
<div className="flex space-x-2 overflow-x-auto pb-2">
|
| 971 |
+
<button
|
| 972 |
+
onClick={() => setFilter('all')}
|
| 973 |
+
className={`px-4 py-1 rounded-full text-sm whitespace-nowrap ${
|
| 974 |
+
filter === 'all' ? 'bg-indigo-600 text-white' : 'bg-gray-700 hover:bg-gray-600'
|
| 975 |
+
}`}
|
| 976 |
+
>
|
| 977 |
+
Todos
|
| 978 |
+
</button>
|
| 979 |
+
<button
|
| 980 |
+
onClick={() => setFilter('pending')}
|
| 981 |
+
className={`px-4 py-1 rounded-full text-sm whitespace-nowrap ${
|
| 982 |
+
filter === 'pending' ? 'bg-yellow-600 text-white' : 'bg-gray-700 hover:bg-gray-600'
|
| 983 |
+
}`}
|
| 984 |
+
>
|
| 985 |
+
Pendentes
|
| 986 |
+
</button>
|
| 987 |
+
<button
|
| 988 |
+
onClick={() => setFilter('approved')}
|
| 989 |
+
className={`px-4 py-1 rounded-full text-sm whitespace-nowrap ${
|
| 990 |
+
filter === 'approved' ? 'bg-green-600 text-white' : 'bg-gray-700 hover:bg-gray-600'
|
| 991 |
+
}`}
|
| 992 |
+
>
|
| 993 |
+
Aprovados
|
| 994 |
+
</button>
|
| 995 |
+
<button
|
| 996 |
+
onClick={() => setFilter('rejected')}
|
| 997 |
+
className={`px-4 py-1 rounded-full text-sm whitespace-nowrap ${
|
| 998 |
+
filter === 'rejected' ? 'bg-red-600 text-white' : 'bg-gray-700 hover:bg-gray-600'
|
| 999 |
+
}`}
|
| 1000 |
+
>
|
| 1001 |
+
Rejeitados
|
| 1002 |
+
</button>
|
| 1003 |
+
</div>
|
| 1004 |
+
|
| 1005 |
+
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
| 1006 |
+
{/* Content List */}
|
| 1007 |
+
<div className="lg:col-span-1">
|
| 1008 |
+
<div className="card rounded-lg">
|
| 1009 |
+
<div className="border-b border-gray-700 p-4">
|
| 1010 |
+
<h3 className="font-semibold">Lista de Conteúdos</h3>
|
| 1011 |
+
</div>
|
| 1012 |
+
<div className="p-4 space-y-3">
|
| 1013 |
+
{filteredContent.map(content => (
|
| 1014 |
+
<div
|
| 1015 |
+
key={content.id}
|
| 1016 |
+
onClick={() => setSelectedContent(content)}
|
| 1017 |
+
className={`p-3 rounded-lg cursor-pointer ${selectedContent?.id === content.id ? 'bg-indigo-500/10 border border-indigo-500/30' : 'hover:bg-gray-700'}`}
|
| 1018 |
+
>
|
| 1019 |
+
<div className="flex justify-between items-center">
|
| 1020 |
+
<h4 className="font-medium truncate">{content.title}</h4>
|
| 1021 |
+
<span className={`px-2 py-1 text-xs rounded-full ${
|
| 1022 |
+
content.status === 'approved' ? 'bg-green-500/20 text-green-400' :
|
| 1023 |
+
content.status === 'pending' ? 'bg-yellow-500/20 text-yellow-400' :
|
| 1024 |
+
'bg-red-500/20 text-red-400'
|
| 1025 |
+
}`}>
|
| 1026 |
+
{content.status === 'approved' ? 'Aprovado' :
|
| 1027 |
+
content.status === 'pending' ? 'Pendente' :
|
| 1028 |
+
'Rejeitado'}
|
| 1029 |
+
</span>
|
| 1030 |
+
</div>
|
| 1031 |
+
<p className="text-sm text-gray-400">{content.source}</p>
|
| 1032 |
+
<div className="flex justify-between mt-2 text-xs">
|
| 1033 |
+
<span className="text-gray-400">Criado em: {new Date(content.created).toLocaleDateString()}</span>
|
| 1034 |
+
</div>
|
| 1035 |
+
</div>
|
| 1036 |
+
))}
|
| 1037 |
+
</div>
|
| 1038 |
+
</div>
|
| 1039 |
+
</div>
|
| 1040 |
+
|
| 1041 |
+
{/* Content Details */}
|
| 1042 |
+
<div className="lg:col-span-2">
|
| 1043 |
+
{selectedContent ? (
|
| 1044 |
+
<div className="card rounded-lg p-6">
|
| 1045 |
+
<div className="flex justify-between items-center mb-4">
|
| 1046 |
+
<h3 className="text-xl font-semibold">{selectedContent.title}</h3>
|
| 1047 |
+
<div className="flex space-x-2">
|
| 1048 |
+
{selectedContent.status === 'pending' && (
|
| 1049 |
+
<>
|
| 1050 |
+
<button className="bg-green-600 hover:bg-green-700 text-white px-3 py-1 rounded text-sm">
|
| 1051 |
+
<i className="fas fa-check mr-1"></i> Aprovar
|
| 1052 |
+
</button>
|
| 1053 |
+
<button className="bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded text-sm">
|
| 1054 |
+
<i className="fas fa-times mr-1"></i> Rejeitar
|
| 1055 |
+
</button>
|
| 1056 |
+
</>
|
| 1057 |
+
)}
|
| 1058 |
+
<button className="bg-indigo-600 hover:bg-indigo-700 text-white px-3 py-1 rounded text-sm">
|
| 1059 |
+
<i className="fas fa-edit mr-1"></i> Editar
|
| 1060 |
+
</button>
|
| 1061 |
+
</div>
|
| 1062 |
+
</div>
|
| 1063 |
+
|
| 1064 |
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
| 1065 |
+
<div className="bg-gray-700/50 p-3 rounded-lg">
|
| 1066 |
+
<p className="text-gray-400 text-sm">Fonte</p>
|
| 1067 |
+
<p className="font-medium">{selectedContent.source}</p>
|
| 1068 |
+
</div>
|
| 1069 |
+
<div className="bg-gray-700/50 p-3 rounded-lg">
|
| 1070 |
+
<p className="text-gray-400 text-sm">Status</p>
|
| 1071 |
+
<p className={`font-medium ${
|
| 1072 |
+
selectedContent.status === 'approved' ? 'text-green-400' :
|
| 1073 |
+
selectedContent.status === 'pending' ? 'text-yellow-400' :
|
| 1074 |
+
'text-red-400'
|
| 1075 |
+
}`}>
|
| 1076 |
+
{selectedContent.status === 'approved' ? 'Aprovado' :
|
| 1077 |
+
selectedContent.status === 'pending' ? 'Pendente' :
|
| 1078 |
+
'Rejeitado'}
|
| 1079 |
+
</p>
|
| 1080 |
+
</div>
|
| 1081 |
+
<div className="bg-gray-700/50 p-3 rounded-lg">
|
| 1082 |
+
<p className="text-gray-400 text-sm">Criado em</p>
|
| 1083 |
+
<p className="font-medium">{new Date(selectedContent.created).toLocaleString()}</p>
|
| 1084 |
+
</div>
|
| 1085 |
+
<div className="bg-gray-700/50 p-3 rounded-lg">
|
| 1086 |
+
<p className="text-gray-400 text-sm">Publicado em</p>
|
| 1087 |
+
<p className="font-medium">
|
| 1088 |
+
{selectedContent.published ? new Date(selectedContent.published).toLocaleString() : 'Não publicado'}
|
| 1089 |
+
</p>
|
| 1090 |
+
</div>
|
| 1091 |
+
</div>
|
| 1092 |
+
|
| 1093 |
+
<div>
|
| 1094 |
+
<h4 className="font-medium mb-3">Conteúdo</h4>
|
| 1095 |
+
<div className="bg-gray-800 border border-gray-700 rounded-lg p-4">
|
| 1096 |
+
<p className="text-gray-300">
|
| 1097 |
+
Este é um exemplo de conteúdo gerado automaticamente pelo sistema de IA.
|
| 1098 |
+
O conteúdo real seria exibido aqui com formatação adequada.
|
| 1099 |
+
</p>
|
| 1100 |
+
<p className="text-gray-300 mt-2">
|
| 1101 |
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam auctor, nisl eget ultricies tincidunt, nisl nisl aliquam nisl, eget ultricies nisl nisl eget nisl.
|
| 1102 |
+
</p>
|
| 1103 |
+
</div>
|
| 1104 |
+
</div>
|
| 1105 |
+
</div>
|
| 1106 |
+
) : (
|
| 1107 |
+
<div className="card rounded-lg p-6 flex flex-col items-center justify-center h-full">
|
| 1108 |
+
<i className="fas fa-newspaper text-4xl text-gray-500 mb-4"></i>
|
| 1109 |
+
<p className="text-gray-400">Selecione um conteúdo para visualizar os detalhes</p>
|
| 1110 |
+
</div>
|
| 1111 |
+
)}
|
| 1112 |
+
</div>
|
| 1113 |
+
</div>
|
| 1114 |
+
</div>
|
| 1115 |
+
);
|
| 1116 |
+
};
|
| 1117 |
+
|
| 1118 |
+
const SettingsSection = ({ user, darkMode, toggleDarkMode }) => {
|
| 1119 |
+
const [currentTab, setCurrentTab] = useState('profile');
|
| 1120 |
+
|
| 1121 |
+
return (
|
| 1122 |
+
<div className="space-y-6">
|
| 1123 |
+
<h3 className="text-lg font-semibold">Configurações</h3>
|
| 1124 |
+
|
| 1125 |
+
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
|
| 1126 |
+
{/* Settings Menu */}
|
| 1127 |
+
<div className="lg:col-span-1">
|
| 1128 |
+
<div className="card rounded-lg">
|
| 1129 |
+
<div className="border-b border-gray-700 p-4">
|
| 1130 |
+
<h3 className="font-semibold">Menu</h3>
|
| 1131 |
+
</div>
|
| 1132 |
+
<div className="p-4 space-y-2">
|
| 1133 |
+
<button
|
| 1134 |
+
onClick={() => setCurrentTab('profile')}
|
| 1135 |
+
className={`w-full text-left p-3 rounded-lg ${
|
| 1136 |
+
currentTab === 'profile' ? 'bg-indigo-500/20 text-indigo-400' : 'hover:bg-gray-700'
|
| 1137 |
+
}`}
|
| 1138 |
+
>
|
| 1139 |
+
<i className="fas fa-user mr-2"></i> Perfil
|
| 1140 |
+
</button>
|
| 1141 |
+
<button
|
| 1142 |
+
onClick={() => setCurrentTab('account')}
|
| 1143 |
+
className={`w-full text-left p-3 rounded-lg ${
|
| 1144 |
+
currentTab === 'account' ? 'bg-indigo-500/20 text-indigo-400' : 'hover:bg-gray-700'
|
| 1145 |
+
}`}
|
| 1146 |
+
>
|
| 1147 |
+
<i className="fas fa-cog mr-2"></i> Conta
|
| 1148 |
+
</button>
|
| 1149 |
+
<button
|
| 1150 |
+
onClick={() => setCurrentTab('security')}
|
| 1151 |
+
className={`w-full text-left p-3 rounded-lg ${
|
| 1152 |
+
currentTab === 'security' ? 'bg-indigo-500/20 text-indigo-400' : 'hover:bg-gray-700'
|
| 1153 |
+
}`}
|
| 1154 |
+
>
|
| 1155 |
+
<i className="fas fa-shield-alt mr-2"></i> Segurança
|
| 1156 |
+
</button>
|
| 1157 |
+
<button
|
| 1158 |
+
onClick={() => setCurrentTab('notifications')}
|
| 1159 |
+
className={`w-full text-left p-3 rounded-lg ${
|
| 1160 |
+
currentTab === 'notifications' ? 'bg-indigo-500/20 text-indigo-400' : 'hover:bg-gray-700'
|
| 1161 |
+
}`}
|
| 1162 |
+
>
|
| 1163 |
+
<i className="fas fa-bell mr-2"></i> Notificações
|
| 1164 |
+
</button>
|
| 1165 |
+
<button
|
| 1166 |
+
onClick={() => setCurrentTab('appearance')}
|
| 1167 |
+
className={`w-full text-left p-3 rounded-lg ${
|
| 1168 |
+
currentTab === 'appearance' ? 'bg-indigo-500/20 text-indigo-400' : 'hover:bg-gray-700'
|
| 1169 |
+
}`}
|
| 1170 |
+
>
|
| 1171 |
+
<i className="fas fa-palette mr-2"></i> Aparência
|
| 1172 |
+
</button>
|
| 1173 |
+
</div>
|
| 1174 |
+
</div>
|
| 1175 |
+
</div>
|
| 1176 |
+
|
| 1177 |
+
{/* Settings Content */}
|
| 1178 |
+
<div className="lg:col-span-3">
|
| 1179 |
+
<div className="card rounded-lg p-6">
|
| 1180 |
+
{currentTab === 'profile' && (
|
| 1181 |
+
<div>
|
| 1182 |
+
<h3 className="text-xl font-semibold mb-6">Perfil</h3>
|
| 1183 |
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
| 1184 |
+
<div>
|
| 1185 |
+
<label className="block text-sm font-medium text-gray-400 mb-1">Nome</label>
|
| 1186 |
+
<input
|
| 1187 |
+
type="text"
|
| 1188 |
+
defaultValue={user.name}
|
| 1189 |
+
className="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
| 1190 |
+
/>
|
| 1191 |
+
</div>
|
| 1192 |
+
<div>
|
| 1193 |
+
<label className="block text-sm font-medium text-gray-400 mb-1">Email</label>
|
| 1194 |
+
<input
|
| 1195 |
+
type="email"
|
| 1196 |
+
defaultValue={user.email}
|
| 1197 |
+
className="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
| 1198 |
+
/>
|
| 1199 |
+
</div>
|
| 1200 |
+
<div>
|
| 1201 |
+
<label className="block text-sm font-medium text-gray-400 mb-1">Cargo</label>
|
| 1202 |
+
<input
|
| 1203 |
+
type="text"
|
| 1204 |
+
defaultValue={user.role}
|
| 1205 |
+
className="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
| 1206 |
+
disabled
|
| 1207 |
+
/>
|
| 1208 |
+
</div>
|
| 1209 |
+
<div>
|
| 1210 |
+
<label className="block text-sm font-medium text-gray-400 mb-1">Foto</label>
|
| 1211 |
+
<div className="flex items-center">
|
| 1212 |
+
<div className="w-16 h-16 rounded-full bg-indigo-500 flex items-center justify-center mr-4">
|
| 1213 |
+
<i className="fas fa-user text-white text-xl"></i>
|
| 1214 |
+
</div>
|
| 1215 |
+
<button className="bg-gray-700 hover:bg-gray-600 text-white px-4 py-2 rounded-lg">
|
| 1216 |
+
Alterar
|
| 1217 |
+
</button>
|
| 1218 |
+
</div>
|
| 1219 |
+
</div>
|
| 1220 |
+
</div>
|
| 1221 |
+
<div className="mt-6 flex justify-end">
|
| 1222 |
+
<button className="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg">
|
| 1223 |
+
Salvar Alterações
|
| 1224 |
+
</button>
|
| 1225 |
+
</div>
|
| 1226 |
+
</div>
|
| 1227 |
+
)}
|
| 1228 |
+
|
| 1229 |
+
{currentTab === 'account' && (
|
| 1230 |
+
<div>
|
| 1231 |
+
<h3 className="text-xl font-semibold mb-6">Configurações da Conta</h3>
|
| 1232 |
+
<div className="space-y-6">
|
| 1233 |
+
<div className="bg-gray-700/50 p-4 rounded-lg">
|
| 1234 |
+
<h4 className="font-medium mb-3">Plano Atual</h4>
|
| 1235 |
+
<div className="flex items-center justify-between">
|
| 1236 |
+
<div>
|
| 1237 |
+
<p className="text-2xl font-bold">Premium</p>
|
| 1238 |
+
<p className="text-gray-400">Acesso completo a todos os recursos</p>
|
| 1239 |
+
</div>
|
| 1240 |
+
<button className="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg">
|
| 1241 |
+
Gerenciar Plano
|
| 1242 |
+
</button>
|
| 1243 |
+
</div>
|
| 1244 |
+
</div>
|
| 1245 |
+
|
| 1246 |
+
<div className="bg-gray-700/50 p-4 rounded-lg">
|
| 1247 |
+
<h4 className="font-medium mb-3">Limites de Uso</h4>
|
| 1248 |
+
<div className="space-y-3">
|
| 1249 |
+
<div>
|
| 1250 |
+
<div className="flex justify-between mb-1">
|
| 1251 |
+
<span className="text-gray-400">VPS</span>
|
| 1252 |
+
<span className="font-medium">2/5</span>
|
| 1253 |
+
</div>
|
| 1254 |
+
<div className="w-full bg-gray-600 rounded-full h-2">
|
| 1255 |
+
<div className="bg-indigo-600 h-2 rounded-full" style={{ width: '40%' }}></div>
|
| 1256 |
+
</div>
|
| 1257 |
+
</div>
|
| 1258 |
+
<div>
|
| 1259 |
+
<div className="flex justify-between mb-1">
|
| 1260 |
+
<span className="text-gray-400">Bots</span>
|
| 1261 |
+
<span className="font-medium">3/10</span>
|
| 1262 |
+
</div>
|
| 1263 |
+
<div className="w-full bg-gray-600 rounded-full h-2">
|
| 1264 |
+
<div className="bg-indigo-600 h-2 rounded-full" style={{ width: '30%' }}></div>
|
| 1265 |
+
</div>
|
| 1266 |
+
</div>
|
| 1267 |
+
<div>
|
| 1268 |
+
<div className="flex justify-between mb-1">
|
| 1269 |
+
<span className="text-gray-400">Armazenamento</span>
|
| 1270 |
+
<span className="font-medium">15GB/50GB</span>
|
| 1271 |
+
</div>
|
| 1272 |
+
<div className="w-full bg-gray-600 rounded-full h-2">
|
| 1273 |
+
<div className="bg-indigo-600 h-2 rounded-full" style={{ width: '30%' }}></div>
|
| 1274 |
+
</div>
|
| 1275 |
+
</div>
|
| 1276 |
+
</div>
|
| 1277 |
+
</div>
|
| 1278 |
+
|
| 1279 |
+
<div className="bg-red-500/10 border border-red-500/30 p-4 rounded-lg">
|
| 1280 |
+
<h4 className="font-medium mb-3 text-red-400">Zona de Perigo</h4>
|
| 1281 |
+
<div className="flex justify-between items-center">
|
| 1282 |
+
<div>
|
| 1283 |
+
<p className="text-sm">Excluir permanentemente sua conta</p>
|
| 1284 |
+
<p className="text-xs text-gray-400">Esta ação não pode ser desfeita</p>
|
| 1285 |
+
</div>
|
| 1286 |
+
<button className="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg text-sm">
|
| 1287 |
+
Excluir Conta
|
| 1288 |
+
</button>
|
| 1289 |
+
</div>
|
| 1290 |
+
</div>
|
| 1291 |
+
</div>
|
| 1292 |
+
</div>
|
| 1293 |
+
)}
|
| 1294 |
+
|
| 1295 |
+
{currentTab === 'security' && (
|
| 1296 |
+
<div>
|
| 1297 |
+
<h3 className="text-xl font-semibold mb-6">Segurança</h3>
|
| 1298 |
+
<div className="space-y-6">
|
| 1299 |
+
<div className="bg-gray-700/50 p-4 rounded-lg">
|
| 1300 |
+
<h4 className="font-medium mb-3">Alterar Senha</h4>
|
| 1301 |
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
| 1302 |
+
<div>
|
| 1303 |
+
<label className="block text-sm font-medium text-gray-400 mb-1">Senha Atual</label>
|
| 1304 |
+
<input
|
| 1305 |
+
type="password"
|
| 1306 |
+
className="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
| 1307 |
+
/>
|
| 1308 |
+
</div>
|
| 1309 |
+
<div>
|
| 1310 |
+
<label className="block text-sm font-medium text-gray-400 mb-1">Nova Senha</label>
|
| 1311 |
+
<input
|
| 1312 |
+
type="password"
|
| 1313 |
+
className="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
| 1314 |
+
/>
|
| 1315 |
+
</div>
|
| 1316 |
+
<div>
|
| 1317 |
+
<label className="block text-sm font-medium text-gray-400 mb-1">Confirmar Nova Senha</label>
|
| 1318 |
+
<input
|
| 1319 |
+
type="password"
|
| 1320 |
+
className="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
| 1321 |
+
/>
|
| 1322 |
+
</div>
|
| 1323 |
+
</div>
|
| 1324 |
+
<div className="mt-4 flex justify-end">
|
| 1325 |
+
<button className="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg">
|
| 1326 |
+
Alterar Senha
|
| 1327 |
+
</button>
|
| 1328 |
+
</div>
|
| 1329 |
+
</div>
|
| 1330 |
+
|
| 1331 |
+
<div className="bg-gray-700/50 p-4 rounded-lg">
|
| 1332 |
+
<h4 className="font-medium mb-3">Autenticação de Dois Fatores</h4>
|
| 1333 |
+
<div className="flex justify-between items-center">
|
| 1334 |
+
<div>
|
| 1335 |
+
<p className="font-medium">2FA Desativado</p>
|
| 1336 |
+
<p className="text-sm text-gray-400">Proteja sua conta com um segundo fator de autenticação</p>
|
| 1337 |
+
</div>
|
| 1338 |
+
<button className="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg">
|
| 1339 |
+
Ativar 2FA
|
| 1340 |
+
</button>
|
| 1341 |
+
</div>
|
| 1342 |
+
</div>
|
| 1343 |
+
|
| 1344 |
+
<div className="bg-gray-700/50 p-4 rounded-lg">
|
| 1345 |
+
<h4 className="font-medium mb-3">Sessões Ativas</h4>
|
| 1346 |
+
<div className="space-y-3">
|
| 1347 |
+
<div className="flex justify-between items-center p-3 bg-gray-800 rounded-lg">
|
| 1348 |
+
<div>
|
| 1349 |
+
<p className="font-medium">Chrome - Windows</p>
|
| 1350 |
+
<p className="text-sm text-gray-400">192.168.1.5 - Ativo agora</p>
|
| 1351 |
+
</div>
|
| 1352 |
+
<button className="text-red-500 hover:text-red-700">
|
| 1353 |
+
<i className="fas fa-sign-out-alt"></i> Sair
|
| 1354 |
+
</button>
|
| 1355 |
+
</div>
|
| 1356 |
+
<div className="flex justify-between items-center p-3 bg-gray-800 rounded-lg">
|
| 1357 |
+
<div>
|
| 1358 |
+
<p className="font-medium">Firefox - Linux</p>
|
| 1359 |
+
<p className="text-sm text-gray-400">192.168.1.10 - 2 horas atrás</p>
|
| 1360 |
+
</div>
|
| 1361 |
+
<button className="text-red-500 hover:text-red-700">
|
| 1362 |
+
<i className="fas fa-sign-out-alt"></i> Sair
|
| 1363 |
+
</button>
|
| 1364 |
+
</div>
|
| 1365 |
+
</div>
|
| 1366 |
+
</div>
|
| 1367 |
+
</div>
|
| 1368 |
+
</div>
|
| 1369 |
+
)}
|
| 1370 |
+
|
| 1371 |
+
{currentTab === 'notifications' && (
|
| 1372 |
+
<div>
|
| 1373 |
+
<h3 className="text-xl font-semibold mb-6">Notificações</h3>
|
| 1374 |
+
<div className="space-y-6">
|
| 1375 |
+
<div className="bg-gray-700/50 p-4 rounded-lg">
|
| 1376 |
+
<h4 className="font-medium mb-3">Preferências de Notificação</h4>
|
| 1377 |
+
<div className="space-y-4">
|
| 1378 |
+
<div className="flex justify-between items-center">
|
| 1379 |
+
<div>
|
| 1380 |
+
<p className="font-medium">Notificações por Email</p>
|
| 1381 |
+
<p className="text-sm text-gray-400">Receba notificações importantes por email</p>
|
| 1382 |
+
</div>
|
| 1383 |
+
<label className="relative inline-flex items-center cursor-pointer">
|
| 1384 |
+
<input type="checkbox" className="sr-only peer" defaultChecked />
|
| 1385 |
+
<div className="w-11 h-6 bg-gray-600 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
|
| 1386 |
+
</label>
|
| 1387 |
+
</div>
|
| 1388 |
+
<div className="flex justify-between items-center">
|
| 1389 |
+
<div>
|
| 1390 |
+
<p className="font-medium">Notificações Push</p>
|
| 1391 |
+
<p className="text-sm text-gray-400">Receba notificações no navegador</p>
|
| 1392 |
+
</div>
|
| 1393 |
+
<label className="relative inline-flex items-center cursor-pointer">
|
| 1394 |
+
<input type="checkbox" className="sr-only peer" />
|
| 1395 |
+
<div className="w-11 h-6 bg-gray-600 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
|
| 1396 |
+
</label>
|
| 1397 |
+
</div>
|
| 1398 |
+
<div className="flex justify-between items-center">
|
| 1399 |
+
<div>
|
| 1400 |
+
<p className="font-medium">Alertas de Segurança</p>
|
| 1401 |
+
<p className="text-sm text-gray-400">Receba alertas sobre atividades suspeitas</p>
|
| 1402 |
+
</div>
|
| 1403 |
+
<label className="relative inline-flex items-center cursor-pointer">
|
| 1404 |
+
<input type="checkbox" className="sr-only peer" defaultChecked />
|
| 1405 |
+
<div className="w-11 h-6 bg-gray-600 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
|
| 1406 |
+
</label>
|
| 1407 |
+
</div>
|
| 1408 |
+
</div>
|
| 1409 |
+
</div>
|
| 1410 |
+
|
| 1411 |
+
<div className="bg-gray-700/50 p-4 rounded-lg">
|
| 1412 |
+
<h4 className="font-medium mb-3">Tipos de Notificação</h4>
|
| 1413 |
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
| 1414 |
+
<div className="flex items-center">
|
| 1415 |
+
<input type="checkbox" id="notif-vps" className="w-4 h-4 text-indigo-600 bg-gray-700 border-gray-600 rounded focus:ring-indigo-500" defaultChecked />
|
| 1416 |
+
<label htmlFor="notif-vps" className="ml-2 text-sm font-medium text-gray-300">Status da VPS</label>
|
| 1417 |
+
</div>
|
| 1418 |
+
<div className="flex items-center">
|
| 1419 |
+
<input type="checkbox" id="notif-bots" className="w-4 h-4 text-indigo-600 bg-gray-700 border-gray-600 rounded focus:ring-indigo-500" defaultChecked />
|
| 1420 |
+
<label htmlFor="notif-bots" className="ml-2 text-sm font-medium text-gray-300">Atividade de Bots</label>
|
| 1421 |
+
</div>
|
| 1422 |
+
<div className="flex items-center">
|
| 1423 |
+
<input type="checkbox" id="notif-content" className="w-4 h-4 text-indigo-600 bg-gray-700 border-gray-600 rounded focus:ring-indigo-500" defaultChecked />
|
| 1424 |
+
<label htmlFor="notif-content" className="ml-2 text-sm font-medium text-gray-300">Conteúdo Pendente</label>
|
| 1425 |
+
</div>
|
| 1426 |
+
<div className="flex items-center">
|
| 1427 |
+
<input type="checkbox" id="notif-security" className="w-4 h-4 text-indigo-600 bg-gray-700 border-gray-600 rounded focus:ring-indigo-500" defaultChecked />
|
| 1428 |
+
<label htmlFor="notif-security" className="ml-2 text-sm font-medium text-gray-300">Alertas de Segurança</label>
|
| 1429 |
+
</div>
|
| 1430 |
+
<div className="flex items-center">
|
| 1431 |
+
<input type="checkbox" id="notif-updates" className="w-4 h-4 text-indigo-600 bg-gray-700 border-gray-600 rounded focus:ring-indigo-500" />
|
| 1432 |
+
<label htmlFor="notif-updates" className="ml-2 text-sm font-medium text-gray-300">Atualizações do Sistema</label>
|
| 1433 |
+
</div>
|
| 1434 |
+
<div className="flex items-center">
|
| 1435 |
+
<input type="checkbox" id="notif-news" className="w-4 h-4 text-indigo-600 bg-gray-700 border-gray-600 rounded focus:ring-indigo-500" />
|
| 1436 |
+
<label htmlFor="notif-news" className="ml-2 text-sm font-medium text-gray-300">Novidades e Promoções</label>
|
| 1437 |
+
</div>
|
| 1438 |
+
</div>
|
| 1439 |
+
</div>
|
| 1440 |
+
</div>
|
| 1441 |
+
</div>
|
| 1442 |
+
)}
|
| 1443 |
+
|
| 1444 |
+
{currentTab === 'appearance' && (
|
| 1445 |
+
<div>
|
| 1446 |
+
<h3 className="text-xl font-semibold mb-6">Aparência</h3>
|
| 1447 |
+
<div className="space-y-6">
|
| 1448 |
+
<div className="bg-gray-700/50 p-4 rounded-lg">
|
| 1449 |
+
<h4 className="font-medium mb-3">Tema</h4>
|
| 1450 |
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
| 1451 |
+
<button
|
| 1452 |
+
onClick={toggleDarkMode}
|
| 1453 |
+
className={`p-4 rounded-lg border ${darkMode ? 'border-indigo-500 bg-indigo-500/10' : 'border-gray-600 hover:border-gray-500'}`}
|
| 1454 |
+
>
|
| 1455 |
+
<div className="flex flex-col items-center">
|
| 1456 |
+
<i className={`fas ${darkMode ? 'fa-moon' : 'fa-sun'} text-2xl mb-2 ${darkMode ? 'text-indigo-400' : 'text-yellow-400'}`}></i>
|
| 1457 |
+
<span>{darkMode ? 'Escuro' : 'Claro'}</span>
|
| 1458 |
+
</div>
|
| 1459 |
+
</button>
|
| 1460 |
+
<button className="p-4 rounded-lg border border-gray-600 hover:border-gray-500">
|
| 1461 |
+
<div className="flex flex-col items-center">
|
| 1462 |
+
<i className="fas fa-desktop text-2xl mb-2 text-gray-400"></i>
|
| 1463 |
+
<span>Seguir Sistema</span>
|
| 1464 |
+
</div>
|
| 1465 |
+
</button>
|
| 1466 |
+
</div>
|
| 1467 |
+
</div>
|
| 1468 |
+
|
| 1469 |
+
<div className="bg-gray-700/50 p-4 rounded-lg">
|
| 1470 |
+
<h4 className="font-medium mb-3">Densidade da Interface</h4>
|
| 1471 |
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
| 1472 |
+
<button className="p-4 rounded-lg border border-gray-600 hover:border-gray-500">
|
| 1473 |
+
<div className="flex flex-col items-center">
|
| 1474 |
+
<i className="fas fa-compress text-2xl mb-2 text-gray-400"></i>
|
| 1475 |
+
<span>Compacto</span>
|
| 1476 |
+
</div>
|
| 1477 |
+
</button>
|
| 1478 |
+
<button className="p-4 rounded-lg border border-indigo-500 bg-indigo-500/10">
|
| 1479 |
+
<div className="flex flex-col items-center">
|
| 1480 |
+
<i className="fas fa-expand text-2xl mb-2 text-indigo-400"></i>
|
| 1481 |
+
<span>Confortável</span>
|
| 1482 |
+
</div>
|
| 1483 |
+
</button>
|
| 1484 |
+
<button className="p-4 rounded-lg border border-gray-600 hover:border-gray-500">
|
| 1485 |
+
<div className="flex flex-col items-center">
|
| 1486 |
+
<i className="fas fa-text-height text-2xl mb-2 text-gray-400"></i>
|
| 1487 |
+
<span>Espaçoso</span>
|
| 1488 |
+
</div>
|
| 1489 |
+
</button>
|
| 1490 |
+
</div>
|
| 1491 |
+
</div>
|
| 1492 |
+
|
| 1493 |
+
<div className="bg-gray-700/50 p-4 rounded-lg">
|
| 1494 |
+
<h4 className="font-medium mb-3">Cor de Destaque</h4>
|
| 1495 |
+
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-3">
|
| 1496 |
+
{['indigo', 'blue', 'green', 'yellow', 'red', 'purple'].map(color => (
|
| 1497 |
+
<button
|
| 1498 |
+
key={color}
|
| 1499 |
+
className={`w-10 h-10 rounded-full bg-${color}-500 flex items-center justify-center`}
|
| 1500 |
+
>
|
| 1501 |
+
{color === 'indigo' && <i className="fas fa-check text-white"></i>}
|
| 1502 |
+
</button>
|
| 1503 |
+
))}
|
| 1504 |
+
</div>
|
| 1505 |
+
</div>
|
| 1506 |
+
</div>
|
| 1507 |
+
</div>
|
| 1508 |
+
)}
|
| 1509 |
+
</div>
|
| 1510 |
+
</div>
|
| 1511 |
+
</div>
|
| 1512 |
+
</div>
|
| 1513 |
+
);
|
| 1514 |
+
};
|
| 1515 |
+
|
| 1516 |
+
// Componentes de modal
|
| 1517 |
+
const AddVpsModal = ({ setShowAddVpsModal, setVpsList }) => {
|
| 1518 |
+
const [formData, setFormData] = useState({
|
| 1519 |
+
name: '',
|
| 1520 |
+
ip: '',
|
| 1521 |
+
sshPort: '22',
|
| 1522 |
+
sshUser: 'root',
|
| 1523 |
+
sshKey: '',
|
| 1524 |
+
tags: []
|
| 1525 |
+
});
|
| 1526 |
+
|
| 1527 |
+
const handleSubmit = (e) => {
|
| 1528 |
+
e.preventDefault();
|
| 1529 |
+
const newVps = {
|
| 1530 |
+
id: Date.now(),
|
| 1531 |
+
name: formData.name,
|
| 1532 |
+
ip: formData.ip,
|
| 1533 |
+
status: 'online',
|
| 1534 |
+
cpu: 0,
|
| 1535 |
+
memory: 0,
|
| 1536 |
+
storage: 0,
|
| 1537 |
+
containers: 0,
|
| 1538 |
+
lastUpdated: new Date()
|
| 1539 |
+
};
|
| 1540 |
+
|
| 1541 |
+
setVpsList(prev => [...prev, newVps]);
|
| 1542 |
+
setShowAddVpsModal(false);
|
| 1543 |
+
};
|
| 1544 |
+
|
| 1545 |
+
return (
|
| 1546 |
+
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
| 1547 |
+
<div className="bg-gray-800 rounded-lg border border-gray-700 w-full max-w-2xl">
|
| 1548 |
+
<div className="border-b border-gray-700 p-4 flex justify-between items-center">
|
| 1549 |
+
<h3 className="font-semibold">Adicionar Nova VPS</h3>
|
| 1550 |
+
<button
|
| 1551 |
+
onClick={() => setShowAddVpsModal(false)}
|
| 1552 |
+
className="text-gray-400 hover:text-white"
|
| 1553 |
+
>
|
| 1554 |
+
<i className="fas fa-times"></i>
|
| 1555 |
+
</button>
|
| 1556 |
+
</div>
|
| 1557 |
+
|
| 1558 |
+
<form onSubmit={handleSubmit} className="p-6">
|
| 1559 |
+
<div className="space-y-4">
|
| 1560 |
+
<div>
|
| 1561 |
+
<label className="block text-sm font-medium text-gray-400 mb-1">Nome da VPS</label>
|
| 1562 |
+
<input
|
| 1563 |
+
type="text"
|
| 1564 |
+
value={formData.name}
|
| 1565 |
+
onChange={(e) => setFormData({...formData, name: e.target.value})}
|
| 1566 |
+
className="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
| 1567 |
+
required
|
| 1568 |
+
/>
|
| 1569 |
+
</div>
|
| 1570 |
+
|
| 1571 |
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
| 1572 |
+
<div>
|
| 1573 |
+
<label className="block text-sm font-medium text-gray-400 mb-1">Endereço IP</label>
|
| 1574 |
+
<input
|
| 1575 |
+
type="text"
|
| 1576 |
+
</html>
|
prompts.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Fazer modificações como: Painel. Dentro dele Será monitorado os projetos separedos por conteiner (Docker), mostrar o ip da servidor conectado. em monitoramento usar cores no bloco completo mudando de tom de cor conforme for sendo usando (tom mais fraco menos usa, tom mais forte mais uso) mostrar trafego na rede. Opções de incluir app externo tipo n8n, evolution, redis, sql, etx. Usar com mo delo e ideia o Ease Panel. Deixar esse Painel Mais moderno e com funcões que cubra, tudo que usa VPS precise. criar contaas de emal, Opçõa de escolher o nome do Panel Baseado na VPS para maio controle. Criar o front e backend juntos, pronto para usar.
|
| 2 |
+
Recomeçar: Primeira decisão: Recomeçar com stack moderna Sim, refaz com stack real de app, porque HTML estático vai limitar muito: 🔧 Tech Stack ideal: Frontend: React + Tailwind + ShadCN UI (leve, moderno e estiloso) Usa Vite ou Next.js pra acelerar Backend/API: Node.js + Fastify (rápido) ou Python + FastAPI (perfeito se os bots forem Python) Cria endpoints REST ou GraphQL Banco: PostgreSQL ou MongoDB (dependendo da estrutura dos dados) Redis (pra cache, fila, jobs de bot e IA) Auth: JWT com roles ou integração com Auth0 ou Clerk Orquestração de tarefas: n8n (que você já usa) + Rasa + MCP → Integrado por API Hosting: VPS ou mesmo um Docker Swarm / Portainer se quiser escalar ou monitorar múltiplas VPS. Funcionalidades do painel (Free/Premium futuramente) Módulo 1 – Controle de VPS Adicionar/remover VPS (com conexão por SSH ou API tipo Agent) Status de CPU, RAM, processos, uso de disco (via script) Logs em tempo real (tail) Módulo 2 – Bots & Automações Criar/executar/pausar bots (por script ou trigger) Visualizar histórico de execuções Configurar fluxos com IA (Rasa, OpenAI, Ollama, etc) API Key pessoal para usar os bots remotamente Módulo 3 – IA & Conteúdo Criar artigo/matéria a partir de scrapings + IA Permitir aprovação manual antes de publicar Crosspost (Telegram, Twitter, site, etc) Módulo 4 – Sistema de Permissões Controle de acesso (admin, editor, bot user) Modo anônimo (pra denúncia segura, se quiser manter) Módulo 5 – SaaS Premium Conta gratuita com 1 VPS e bots básicos Conta paga com mais VPSs, scraping, integração Telegram, scraping avançado, IA com contexto, Estrutura de pastas sugerida /painel-ai-control ├── frontend/ (React) │ ├── src/components/ │ ├── src/pages/ │ ├── src/services/api.js │ └── ... ├── backend/ (Node.js ou FastAPI) │ ├── api/ │ ├── bots/ │ ├── controllers/ │ ├── database/ │ └── ... ├── docker-compose.yml ├── .env Refaz o painel com frontend em React + Tailwind, e já prepara pra conectar com um backend (Node.js ou FastAPI). O front não precisa ser 100% funcional ainda, mas precisa estar pronto pra receber dados de API. PROJETO: PAINEL DE CONTROLE INTELIGENTE Um sistema web moderno para controlar VPS, bots, automações com IA, e gerenciar conteúdos. Foco em: desempenho, visual bonito, API conectável e estrutura modular. 🧠 OBJETIVO Criar um painel completo com: Frontend moderno e bonito Backend preparado pra automação Estrutura API-first Integrações futuras com: bots, IA, scraping, publicação automática Controle de várias VPS, containers, e tarefas 📦 STACK TECNOLÓGICA 🎨 FRONTEND React (com Vite ou Next.js) TailwindCSS + ShadCN UI (visual moderno, responsivo e bonito) Componentes reutilizáveis Axios para chamadas de API Dashboard com temas escuros, responsivos e interativos 🔧 BACKEND Node.js com Fastify (leve, rápido e fácil de manter) ou Python com FastAPI (ideal se os bots forem em Python) Módulos obrigatórios: API RESTful (exemplo: /vps/status, /bots/start, /conteudos/aprovar) Banco de dados: PostgreSQL (estruturado) ou MongoDB (flexível) Fila de tarefas e cache: Redis Sistema de logs e eventos JWT para autenticação 🖥️ FUNCIONALIDADES DO SISTEMA 1. Painel Geral (Dashboard) Quantidade de VPS Status de bots Atividade recente Recursos ativos (CPU/RAM/Containers) 2. Gerenciador de VPS Adicionar nova VPS Ver uso de recursos (CPU, RAM, disco) Executar comandos via SSH remoto Criar container (Docker) ou reiniciar serviços 3. Controle de Bots Adicionar/remover/editar bots (com agendamento) Status: rodando/parado Logs de execução Integração com n8n, Rasa, MCP, etc 4. Gestão de Conteúdo com IA Área para aprovar conteúdos gerados por scraping + IA Opção de editar antes de publicar Publicação manual ou automática (com webhook) 5. Configurações e Permissões Controle de usuários (admin/editor) Temas (claro/escuro) Logs de login/ações 📂 ORGANIZAÇÃO DO PROJETO /painel-inteligente ├── frontend/ (React) │ ├��─ src/ │ │ ├── components/ │ │ ├── pages/ │ │ ├── styles/ │ │ └── services/api.js │ └── vite.config.js │ ├── backend/ (Node ou Python) │ ├── api/ │ ├── controllers/ │ ├── models/ │ ├── database/ │ ├── middlewares/ │ └── main.js ou main.py │ ├── docker-compose.yml ├── .env └── README.md 🎯 ENTREGA ESPERADA (MVP) Front pronto com páginas: Dashboard VPS Bots Conteúdos (raspagem/IA) Configurações API funcional com: Login Listar VPS Executar comandos Iniciar/parar bots Criar conteúdo com IA simulada (mocked) Visual bonito e escalável 🤖 PRÓXIMAS INTEGRAÇÕES FUTURAS (já deixa preparado) n8n (por webhook) Rasa + OpenAI (via API) Pinecone / Weaviate (busca semântica) Automatização com scraping (Twitter, Google News, etc)
|