g360-cli 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -0
- package/package.json +11 -4
- package/src/assets/brand/brand.json +43 -0
- package/src/assets/brand/cipsa/logotypes/Logo_cipsa_borde.png +0 -0
- package/src/assets/brand/cipsa/logotypes/Logo_cipsa_borde.svg +9 -0
- package/src/assets/brand/cipsa/logotypes/Logo_cipsa_solid.png +0 -0
- package/src/assets/brand/cipsa/logotypes/Logo_cipsa_solid.svg +9 -0
- package/src/assets/brand/g360/logotypes/logo-g360-dark.svg +19 -0
- package/src/assets/brand/g360/logotypes/logo-g360-light.svg +19 -0
- package/src/assets/brand/g360/logotypes/logo_g360_dark_b64.txt +1 -0
- package/src/assets/brand/g360/logotypes/logo_g360_light_b64.txt +1 -0
- package/src/assets/config/g360-skills.json +60 -0
- package/src/assets/signature/g360_flet/__init__.py +5 -0
- package/src/assets/signature/g360_flet/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/assets/signature/g360_flet/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/assets/signature/g360_flet/__pycache__/g360_signature.cpython-312.pyc +0 -0
- package/src/assets/signature/g360_flet/__pycache__/g360_signature.cpython-314.pyc +0 -0
- package/src/assets/signature/g360_flet/g360_signature.py +224 -0
- package/src/assets/signature/index.js +130 -0
- package/src/assets/snippets/snippets.json +293 -101
- package/src/assets/templates/lit-web/src/core/skill.json +12 -5
- package/src/assets/templates/python-cli/build-portable.bat +19 -9
- package/src/assets/templates/python-cli/src/core/skill.json +25 -6
- package/src/assets/templates/python-customtkinter/README.md +32 -31
- package/src/assets/templates/python-customtkinter/assets/images/logo-g360-dark.svg +19 -0
- package/src/assets/templates/python-customtkinter/assets/images/logo-g360-light.svg +19 -0
- package/src/assets/templates/python-customtkinter/build.bat +50 -0
- package/src/assets/templates/python-customtkinter/pyproject.toml +26 -0
- package/src/assets/templates/python-customtkinter/run.bat +11 -20
- package/src/assets/templates/python-customtkinter/src/core/g360_theme.py +101 -0
- package/src/assets/templates/python-customtkinter/src/core/skill.json +23 -10
- package/src/assets/templates/python-customtkinter/src/main.py +61 -81
- package/src/assets/templates/python-flet/README.md +52 -93
- package/src/assets/templates/python-flet/assets/images/Logo_cipsa_borde.png +0 -0
- package/src/assets/templates/python-flet/assets/images/Logo_cipsa_borde.svg +9 -0
- package/src/assets/templates/python-flet/assets/images/Logo_cipsa_solid.png +0 -0
- package/src/assets/templates/python-flet/assets/images/Logo_cipsa_solid.svg +9 -0
- package/src/assets/templates/python-flet/assets/images/logo-g360-dark.svg +19 -0
- package/src/assets/templates/python-flet/assets/images/logo-g360-light.svg +19 -0
- package/src/assets/templates/python-flet/build.bat +36 -0
- package/src/assets/templates/python-flet/pyproject.toml +26 -0
- package/src/assets/templates/python-flet/run.bat +11 -72
- package/src/assets/templates/python-flet/src/core/__init__.py +0 -0
- package/src/assets/templates/python-flet/src/core/g360_theme.py +193 -0
- package/src/assets/templates/python-flet/src/core/skill.json +28 -8
- package/src/assets/templates/python-flet/src/export/__init__.py +0 -0
- package/src/assets/templates/python-flet/src/main.py +113 -68
- package/src/assets/templates/python-flet/src/test_app.py +41 -37
- package/src/assets/templates/python-flet/src/ui/__init__.py +0 -0
- package/src/assets/templates/python-flet-migrate/README.md +70 -0
- package/src/assets/templates/python-flet-migrate/assets/images/logo-g360-dark.svg +19 -0
- package/src/assets/templates/python-flet-migrate/assets/images/logo-g360-light.svg +19 -0
- package/src/assets/templates/python-flet-migrate/build.bat +36 -0
- package/src/assets/templates/python-flet-migrate/pyproject.toml +26 -0
- package/src/assets/templates/python-flet-migrate/run.bat +20 -0
- package/src/assets/templates/python-flet-migrate/src/core/__init__.py +0 -0
- package/src/assets/templates/python-flet-migrate/src/core/g360_theme.py +186 -0
- package/src/assets/templates/python-flet-migrate/src/core/skill.json +34 -0
- package/src/assets/templates/python-flet-migrate/src/main.py +71 -42
- package/src/assets/templates/solid-web/src/core/skill.json +12 -5
- package/src/assets/templates/svelte-web/src/core/skill.json +12 -5
- package/src/assets/templates/web-pwa/index.html +5 -7
- package/src/assets/templates/web-pwa/public/favicon.svg +4 -0
- package/src/assets/templates/web-pwa/public/manifest.json +11 -0
- package/src/assets/templates/web-pwa/src/App.jsx +22 -0
- package/src/assets/templates/web-pwa/src/components/FooterSignature.jsx +9 -0
- package/src/assets/templates/web-pwa/src/components/Header.jsx +12 -0
- package/src/assets/templates/web-pwa/src/components/LoadingOverlay.jsx +10 -0
- package/src/assets/templates/web-pwa/src/core/skill.json +25 -0
- package/src/assets/templates/web-pwa/src/main.jsx +9 -0
- package/src/assets/templates/web-pwa/src/styles/main.css +133 -0
- package/src/assets/templates/web-pwa/vite.config.js +12 -0
- package/src/cli.js +10 -5
- package/src/commands/bring.js +81 -6
- package/src/commands/list.js +79 -9
- package/src/commands/signature.js +252 -55
- package/src/lib/asset-validator.js +145 -0
- package/src/lib/auditor.js +48 -0
- package/src/lib/global-config.js +260 -0
- package/src/lib/i18n.js +238 -0
- package/src/lib/logger.js +100 -0
- package/src/lib/manifest.js +70 -1
- package/src/lib/validator.js +39 -0
- package/src/schemas/skills-schema.json +1 -0
- package/src/schemas/snippets-schema.json +1 -0
- package/dist/g360.exe +0 -0
- package/src/assets/templates/python-customtkinter/build-portable.bat +0 -28
- package/src/assets/templates/python-customtkinter/requirements.txt +0 -1
- package/src/assets/templates/python-flet/build-portable.bat +0 -42
- package/src/assets/templates/python-flet/create_shortcut.vbs +0 -35
- package/src/assets/templates/python-flet/requirements.txt +0 -3
- package/src/assets/templates/web-pwa/app.js +0 -1
- package/src/assets/templates/web-pwa/styles.css +0 -28
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<svg viewBox="0 0 280 70" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<filter id="glow-dark" x="-40%" y="-40%" width="180%" height="180%">
|
|
4
|
+
<feGaussianBlur stdDeviation="3" result="blur" />
|
|
5
|
+
<feFlood flood-color="#22c55e" flood-opacity="0.8" result="glowColor"/>
|
|
6
|
+
<feComposite in="glowColor" in2="blur" operator="in" result="softGlow"/>
|
|
7
|
+
<feMerge>
|
|
8
|
+
<feMergeNode in="softGlow"/>
|
|
9
|
+
<feMergeNode in="SourceGraphic"/>
|
|
10
|
+
</feMerge>
|
|
11
|
+
</filter>
|
|
12
|
+
</defs>
|
|
13
|
+
<circle cx="20" cy="20" r="5" fill="#94a3b8" />
|
|
14
|
+
<circle cx="20" cy="40" r="5" fill="#22c55e" filter="url(#glow-dark)" />
|
|
15
|
+
<circle cx="20" cy="60" r="5" fill="#94a3b8" />
|
|
16
|
+
<path d="M45 20 L 65 40 L 45 60" fill="none" stroke="#22c55e" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow-dark)"/>
|
|
17
|
+
<text x="85" y="45" font-family="Arial Black, sans-serif" font-weight="bold" font-size="38" fill="#f8fafc">G360</text>
|
|
18
|
+
<text x="85" y="65" font-family="monospace" font-size="12" fill="#94a3b8" letter-spacing="4">BY CCUSI</text>
|
|
19
|
+
</svg>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<svg viewBox="0 0 280 70" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<filter id="glow-light" x="-30%" y="-30%" width="160%" height="160%">
|
|
4
|
+
<feGaussianBlur stdDeviation="2.5" result="blur" />
|
|
5
|
+
<feFlood flood-color="#22c55e" flood-opacity="0.6" result="glowColor"/>
|
|
6
|
+
<feComposite in="glowColor" in2="blur" operator="in" result="softGlow"/>
|
|
7
|
+
<feMerge>
|
|
8
|
+
<feMergeNode in="softGlow"/>
|
|
9
|
+
<feMergeNode in="SourceGraphic"/>
|
|
10
|
+
</feMerge>
|
|
11
|
+
</filter>
|
|
12
|
+
</defs>
|
|
13
|
+
<circle cx="20" cy="20" r="5" fill="#475569" />
|
|
14
|
+
<circle cx="20" cy="40" r="5" fill="#22c55e" filter="url(#glow-light)" />
|
|
15
|
+
<circle cx="20" cy="60" r="5" fill="#475569" />
|
|
16
|
+
<path d="M45 20 L 65 40 L 45 60" fill="none" stroke="#22c55e" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow-light)"/>
|
|
17
|
+
<text x="85" y="45" font-family="Arial Black, sans-serif" font-weight="bold" font-size="38" fill="#1e293b">G360</text>
|
|
18
|
+
<text x="85" y="65" font-family="monospace" font-size="12" fill="#64748b" letter-spacing="4">BY CCUSI</text>
|
|
19
|
+
</svg>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
chcp 65001 >nul
|
|
3
|
+
cd /d "%~dp0"
|
|
4
|
+
|
|
5
|
+
echo.
|
|
6
|
+
echo ========================================
|
|
7
|
+
echo G360 - Build Windows App
|
|
8
|
+
echo Genera ejecutable standalone
|
|
9
|
+
echo ========================================
|
|
10
|
+
echo.
|
|
11
|
+
|
|
12
|
+
REM Verificar uv
|
|
13
|
+
where uv >nul 2>&1
|
|
14
|
+
if errorlevel 1 (
|
|
15
|
+
echo Instalando uv...
|
|
16
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
REM Verificar dependencias
|
|
20
|
+
uv sync --extra build
|
|
21
|
+
|
|
22
|
+
REM Build con PyInstaller
|
|
23
|
+
echo [BUILD] Generando ejecutable...
|
|
24
|
+
uv run pyinstaller --onefile --windowed ^
|
|
25
|
+
--name "G360-App" ^
|
|
26
|
+
--add-data "src/core;core" ^
|
|
27
|
+
--icon "assets/images/app.ico" ^
|
|
28
|
+
--distpath "dist" ^
|
|
29
|
+
--workpath "build" ^
|
|
30
|
+
--specpath "build" ^
|
|
31
|
+
--noconfirm ^
|
|
32
|
+
src/main.py
|
|
33
|
+
|
|
34
|
+
if errorlevel 1 (
|
|
35
|
+
echo.
|
|
36
|
+
echo ERROR: Fallo la generacion del ejecutable.
|
|
37
|
+
pause
|
|
38
|
+
exit /b 1
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
REM Limpiar temporales
|
|
42
|
+
if exist "build" rmdir /s /q build
|
|
43
|
+
|
|
44
|
+
echo.
|
|
45
|
+
echo ========================================
|
|
46
|
+
echo BUILD EXITOSO
|
|
47
|
+
echo Ejecutable: dist/G360-App.exe
|
|
48
|
+
echo ========================================
|
|
49
|
+
echo.
|
|
50
|
+
pause
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "g360-app"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "G360 Desktop Application (CustomTkinter)"
|
|
5
|
+
authors = [
|
|
6
|
+
{ name = "ccusi", email = "ccusi@cipsa.com.pe" },
|
|
7
|
+
]
|
|
8
|
+
requires-python = ">=3.11,<4.0"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"customtkinter>=5.2.0",
|
|
11
|
+
"openpyxl>=3.1.0",
|
|
12
|
+
"pandas>=2.0.0",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[project.optional-dependencies]
|
|
16
|
+
dev = [
|
|
17
|
+
"pytest>=8.0.0",
|
|
18
|
+
"pytest-cov>=5.0.0",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[build-system]
|
|
22
|
+
requires = ["hatchling"]
|
|
23
|
+
build-backend = "hatchling.build"
|
|
24
|
+
|
|
25
|
+
[tool.hatch.build.targets.wheel]
|
|
26
|
+
packages = ["src"]
|
|
@@ -1,29 +1,20 @@
|
|
|
1
1
|
@echo off
|
|
2
2
|
chcp 65001 >nul
|
|
3
|
-
|
|
3
|
+
cd /d "%~dp0"
|
|
4
4
|
|
|
5
5
|
echo.
|
|
6
|
-
echo
|
|
7
|
-
echo
|
|
8
|
-
echo
|
|
6
|
+
echo ========================================
|
|
7
|
+
echo G360 CustomTkinter App
|
|
8
|
+
echo powered by G360
|
|
9
|
+
echo ========================================
|
|
9
10
|
echo.
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
echo ERROR: Python no encontrado
|
|
14
|
-
pause
|
|
15
|
-
exit /b 1
|
|
16
|
-
)
|
|
12
|
+
REM uv run detecta/instala Python y dependencias automaticamente
|
|
13
|
+
uv run python src/main.py
|
|
17
14
|
|
|
18
|
-
echo Verificando customtkinter...
|
|
19
|
-
pip show customtkinter >nul 2>&1
|
|
20
15
|
if errorlevel 1 (
|
|
21
|
-
echo
|
|
22
|
-
|
|
16
|
+
echo.
|
|
17
|
+
echo ERROR: La aplicacion fallo.
|
|
18
|
+
echo Verifique que uv este instalado: https://docs.astral.sh/uv/
|
|
19
|
+
pause
|
|
23
20
|
)
|
|
24
|
-
|
|
25
|
-
echo.
|
|
26
|
-
echo Ejecutando aplicacion...
|
|
27
|
-
python src\main.py
|
|
28
|
-
|
|
29
|
-
pause
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class G360Theme:
|
|
6
|
+
def __init__(self, skill_path=None):
|
|
7
|
+
self._search_paths(skill_path)
|
|
8
|
+
self._load_colors()
|
|
9
|
+
self._load_effects()
|
|
10
|
+
|
|
11
|
+
def _search_paths(self, skill_path):
|
|
12
|
+
if skill_path and Path(skill_path).exists():
|
|
13
|
+
self.config_path = Path(skill_path)
|
|
14
|
+
return
|
|
15
|
+
candidates = [
|
|
16
|
+
Path("skill.json"),
|
|
17
|
+
Path("src/core/skill.json"),
|
|
18
|
+
Path(__file__).resolve().parent.parent.parent / "skill.json",
|
|
19
|
+
Path(__file__).resolve().parent / "skill.json",
|
|
20
|
+
Path(__file__).resolve().parent.parent / "g360" / "skills" / "customtkinter-desktop.json",
|
|
21
|
+
]
|
|
22
|
+
for c in candidates:
|
|
23
|
+
if c.exists():
|
|
24
|
+
self.config_path = c
|
|
25
|
+
return
|
|
26
|
+
raise FileNotFoundError("skill.json not found. Run: g360 init <name> --skill customtkinter-desktop")
|
|
27
|
+
|
|
28
|
+
def _load_colors(self):
|
|
29
|
+
with open(self.config_path, encoding="utf-8") as f:
|
|
30
|
+
self.config = json.load(f)
|
|
31
|
+
colors = self.config.get("colors", {})
|
|
32
|
+
self.bg = colors.get("bg", "#0b1220")
|
|
33
|
+
self.surface = colors.get("surface", "#1a2332")
|
|
34
|
+
self.accent = colors.get("accent", "#00d084")
|
|
35
|
+
self.text = colors.get("text", "#f0f4f8")
|
|
36
|
+
self.muted = colors.get("muted", "#94a3b8")
|
|
37
|
+
self.success = colors.get("success", "#22c55e")
|
|
38
|
+
self.warning = colors.get("warning", "#f59e0b")
|
|
39
|
+
self.error = colors.get("error", "#ef4444")
|
|
40
|
+
self.brand = self.config.get("brand", "g360")
|
|
41
|
+
|
|
42
|
+
def _load_effects(self):
|
|
43
|
+
effects = self.config.get("effects", {})
|
|
44
|
+
self.glassmorphism = effects.get("glassmorphism", True)
|
|
45
|
+
self.blur = effects.get("blur", "12px")
|
|
46
|
+
self.rounded = int(effects.get("rounded", "12px").replace("px", ""))
|
|
47
|
+
|
|
48
|
+
def apply_ctk(self):
|
|
49
|
+
import customtkinter as ctk
|
|
50
|
+
ctk.set_appearance_mode("dark")
|
|
51
|
+
ctk.set_default_color_theme("green")
|
|
52
|
+
|
|
53
|
+
def build_name(self):
|
|
54
|
+
build_cfg = self.config.get("build", {})
|
|
55
|
+
return build_cfg.get("name", "G360-App")
|
|
56
|
+
|
|
57
|
+
def glass_frame(self, parent, **kwargs):
|
|
58
|
+
import customtkinter as ctk
|
|
59
|
+
kwargs.setdefault("fg_color", self.surface)
|
|
60
|
+
kwargs.setdefault("corner_radius", self.rounded)
|
|
61
|
+
if self.glassmorphism:
|
|
62
|
+
kwargs.setdefault("border_width", 1)
|
|
63
|
+
kwargs.setdefault("border_color", f"{self.accent}40")
|
|
64
|
+
return ctk.CTkFrame(parent, **kwargs)
|
|
65
|
+
|
|
66
|
+
def accent_button(self, parent, text="", command=None, **kwargs):
|
|
67
|
+
import customtkinter as ctk
|
|
68
|
+
return ctk.CTkButton(
|
|
69
|
+
parent,
|
|
70
|
+
text=text,
|
|
71
|
+
command=command,
|
|
72
|
+
fg_color=self.accent,
|
|
73
|
+
text_color=self.bg,
|
|
74
|
+
hover_color="#00b070",
|
|
75
|
+
corner_radius=8,
|
|
76
|
+
**kwargs,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def styled_label(self, parent, text="", size=14, color=None, **kwargs):
|
|
80
|
+
import customtkinter as ctk
|
|
81
|
+
return ctk.CTkLabel(
|
|
82
|
+
parent,
|
|
83
|
+
text=text,
|
|
84
|
+
font=("Segoe UI", size),
|
|
85
|
+
text_color=color or self.text,
|
|
86
|
+
**kwargs,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def as_dict(self):
|
|
91
|
+
return {
|
|
92
|
+
"bg": self.bg,
|
|
93
|
+
"surface": self.surface,
|
|
94
|
+
"accent": self.accent,
|
|
95
|
+
"text": self.text,
|
|
96
|
+
"muted": self.muted,
|
|
97
|
+
"success": self.success,
|
|
98
|
+
"warning": self.warning,
|
|
99
|
+
"error": self.error,
|
|
100
|
+
"brand": self.brand,
|
|
101
|
+
}
|
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
"
|
|
2
|
+
"name": "customtkinter-desktop",
|
|
3
|
+
"description": "G360 CustomTkinter Desktop Application",
|
|
4
|
+
"framework": "customtkinter",
|
|
5
|
+
"version": "1.2.0",
|
|
6
|
+
"python": ">=3.11,<4.0",
|
|
5
7
|
"colors": {
|
|
6
8
|
"bg": "#0b1220",
|
|
7
9
|
"surface": "#1a2332",
|
|
8
10
|
"accent": "#00d084",
|
|
9
11
|
"text": "#f0f4f8",
|
|
10
|
-
"muted": "#94a3b8"
|
|
12
|
+
"muted": "#94a3b8",
|
|
13
|
+
"success": "#22c55e",
|
|
14
|
+
"warning": "#f59e0b",
|
|
15
|
+
"error": "#ef4444"
|
|
11
16
|
},
|
|
12
17
|
"effects": {
|
|
13
|
-
"glassmorphism":
|
|
18
|
+
"glassmorphism": true,
|
|
19
|
+
"blur": "12px",
|
|
14
20
|
"rounded": "12px"
|
|
15
21
|
},
|
|
16
22
|
"signature": {
|
|
17
|
-
"mode": "
|
|
18
|
-
"text": "G360
|
|
23
|
+
"mode": "powered",
|
|
24
|
+
"text": "powered by G360"
|
|
19
25
|
},
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
"build": {
|
|
27
|
+
"tool": "pyinstaller",
|
|
28
|
+
"target": "windows",
|
|
29
|
+
"name": "G360-App"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"customtkinter": ">=5.2.0",
|
|
33
|
+
"pyinstaller": ">=6.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -4,114 +4,94 @@ G360 CustomTkinter Desktop Application
|
|
|
4
4
|
Modern GUI with G360 theme
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import sys
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
import json
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
VERSION = "1.0.0"
|
|
13
|
-
APP_NAME = "G360 Desktop"
|
|
14
9
|
|
|
10
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if skill_path.exists():
|
|
19
|
-
with open(skill_path) as f:
|
|
20
|
-
return json.load(f)
|
|
21
|
-
return {
|
|
22
|
-
"colors": {
|
|
23
|
-
"bg": "#0b1220",
|
|
24
|
-
"surface": "#1a2332",
|
|
25
|
-
"accent": "#00d084"
|
|
26
|
-
}
|
|
27
|
-
}
|
|
12
|
+
import customtkinter as ctk
|
|
13
|
+
from core.g360_theme import G360Theme
|
|
28
14
|
|
|
29
15
|
|
|
30
16
|
class G360App(ctk.CTk):
|
|
31
17
|
def __init__(self):
|
|
32
18
|
super().__init__()
|
|
33
19
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
ctk.set_appearance_mode("dark")
|
|
38
|
-
ctk.set_default_color_theme("green")
|
|
20
|
+
self.theme = G360Theme()
|
|
21
|
+
self.theme.apply_ctk()
|
|
39
22
|
|
|
40
|
-
self.title(
|
|
41
|
-
self.geometry("
|
|
42
|
-
self.configure(fg_color=
|
|
23
|
+
self.title(self.theme.build_name())
|
|
24
|
+
self.geometry("900x700")
|
|
25
|
+
self.configure(fg_color=self.theme.bg)
|
|
43
26
|
|
|
44
27
|
self.grid_columnconfigure(0, weight=1)
|
|
45
|
-
self.grid_rowconfigure(
|
|
28
|
+
self.grid_rowconfigure(1, weight=1)
|
|
46
29
|
|
|
47
|
-
self.
|
|
48
|
-
self.
|
|
49
|
-
self.
|
|
30
|
+
self._build_header()
|
|
31
|
+
self._build_content()
|
|
32
|
+
self._build_footer()
|
|
50
33
|
|
|
51
|
-
def
|
|
52
|
-
|
|
53
|
-
|
|
34
|
+
def _build_header(self):
|
|
35
|
+
header = self.theme.glass_frame(self)
|
|
36
|
+
header.grid(row=0, column=0, sticky="ew", padx=10, pady=10)
|
|
54
37
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
text=
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
)
|
|
61
|
-
title.pack(side="left", padx=20, pady=10)
|
|
38
|
+
self.theme.styled_label(
|
|
39
|
+
header,
|
|
40
|
+
text=self.theme.build_name(),
|
|
41
|
+
size=20,
|
|
42
|
+
color=self.theme.accent
|
|
43
|
+
).pack(side="left", padx=20, pady=10)
|
|
62
44
|
|
|
63
|
-
|
|
64
|
-
|
|
45
|
+
self.theme.accent_button(
|
|
46
|
+
header,
|
|
65
47
|
text="Settings",
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
border_color=colors.get("accent", "#00d084"),
|
|
69
|
-
text_color=colors.get("accent", "#00d084")
|
|
70
|
-
)
|
|
71
|
-
btn_settings.pack(side="right", padx=20)
|
|
48
|
+
command=self._on_settings
|
|
49
|
+
).pack(side="right", padx=20, pady=10)
|
|
72
50
|
|
|
73
|
-
def
|
|
74
|
-
|
|
75
|
-
|
|
51
|
+
def _build_content(self):
|
|
52
|
+
content = ctk.CTkFrame(self, fg_color="transparent")
|
|
53
|
+
content.grid(row=1, column=0, sticky="nsew", padx=20, pady=10)
|
|
54
|
+
content.grid_columnconfigure(0, weight=1)
|
|
55
|
+
content.grid_rowconfigure(0, weight=1)
|
|
76
56
|
|
|
77
|
-
self.
|
|
78
|
-
self.content.grid_rowconfigure(0, weight=1)
|
|
79
|
-
|
|
80
|
-
card = ctk.CTkFrame(
|
|
81
|
-
self.content,
|
|
82
|
-
fg_color=colors.get("surface", "#1a2332"),
|
|
83
|
-
corner_radius=12
|
|
84
|
-
)
|
|
57
|
+
card = self.theme.glass_frame(content)
|
|
85
58
|
card.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
|
|
86
59
|
|
|
87
|
-
|
|
60
|
+
self.theme.styled_label(
|
|
88
61
|
card,
|
|
89
62
|
text="G360 Application\nReady to build",
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
)
|
|
93
|
-
label.pack(pady=40)
|
|
63
|
+
size=18
|
|
64
|
+
).pack(pady=40)
|
|
94
65
|
|
|
95
|
-
|
|
66
|
+
self.theme.accent_button(
|
|
96
67
|
card,
|
|
97
68
|
text="Start",
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
hover_color="#00b070"
|
|
101
|
-
)
|
|
102
|
-
btn_primary.pack(pady=20)
|
|
69
|
+
command=self._on_start
|
|
70
|
+
).pack(pady=20)
|
|
103
71
|
|
|
104
|
-
def
|
|
105
|
-
|
|
106
|
-
|
|
72
|
+
def _build_footer(self):
|
|
73
|
+
footer = ctk.CTkFrame(self, fg_color="transparent")
|
|
74
|
+
footer.grid(row=2, column=0, sticky="ew", padx=10, pady=(0, 10))
|
|
75
|
+
|
|
76
|
+
self.theme.styled_label(
|
|
77
|
+
footer,
|
|
78
|
+
text=f"v{self.theme.config.get('version', '1.0.0')}",
|
|
79
|
+
size=12,
|
|
80
|
+
color=self.theme.muted
|
|
81
|
+
).pack(side="left", padx=20)
|
|
107
82
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
text="
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
)
|
|
114
|
-
|
|
83
|
+
self.theme.styled_label(
|
|
84
|
+
footer,
|
|
85
|
+
text="powered by G360",
|
|
86
|
+
size=10,
|
|
87
|
+
color=self.theme.muted
|
|
88
|
+
).pack(side="right", padx=20)
|
|
89
|
+
|
|
90
|
+
def _on_settings(self):
|
|
91
|
+
print("Settings clicked")
|
|
92
|
+
|
|
93
|
+
def _on_start(self):
|
|
94
|
+
print("Start clicked")
|
|
115
95
|
|
|
116
96
|
|
|
117
97
|
def main():
|
|
@@ -120,4 +100,4 @@ def main():
|
|
|
120
100
|
|
|
121
101
|
|
|
122
102
|
if __name__ == "__main__":
|
|
123
|
-
main()
|
|
103
|
+
main()
|
|
@@ -5,126 +5,85 @@
|
|
|
5
5
|
```
|
|
6
6
|
mi-proyecto/
|
|
7
7
|
├── src/
|
|
8
|
-
│ ├── main.py #
|
|
9
|
-
│ ├──
|
|
10
|
-
│
|
|
11
|
-
│
|
|
8
|
+
│ ├── main.py # Entry point: ft.run(main)
|
|
9
|
+
│ ├── core/
|
|
10
|
+
│ │ ├── skill.json # Configuracion del skill G360
|
|
11
|
+
│ │ └── g360_theme.py # Theme engine (lee colores de skill.json)
|
|
12
|
+
│ ├── ui/
|
|
13
|
+
│ │ └── __init__.py # Componentes Flet (PascalCase)
|
|
14
|
+
│ └── export/
|
|
15
|
+
│ └── __init__.py # Reportes Excel (openpyxl)
|
|
12
16
|
├── assets/
|
|
13
17
|
│ └── images/
|
|
14
18
|
│ └── app.ico # Icono de la app
|
|
15
|
-
├──
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
├──
|
|
19
|
-
├── g360/
|
|
20
|
-
│ └── (estructura G360)
|
|
21
|
-
├── requirements.txt
|
|
22
|
-
├── create_shortcut.vbs # Crear acceso directo
|
|
19
|
+
├── skill.json # Skill G360 aplicado
|
|
20
|
+
├── pyproject.toml # Dependencias (uv sync)
|
|
21
|
+
├── run.bat # Ejecutar app
|
|
22
|
+
├── build.bat # Build EXE standalone
|
|
23
23
|
└── README.md
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
##
|
|
26
|
+
## Requisitos
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
## Desarrollo
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
python src/main.py
|
|
36
|
-
```
|
|
28
|
+
- **Python**: 3.11+ (instalado automaticamente por uv)
|
|
29
|
+
- **uv**: Gestor de paquetes Python (https://docs.astral.sh/uv/)
|
|
30
|
+
- **Windows**: 10/11 x64
|
|
37
31
|
|
|
38
|
-
##
|
|
32
|
+
## Ejecucion
|
|
39
33
|
|
|
34
|
+
### Con uv (recomendado)
|
|
40
35
|
```bash
|
|
41
|
-
|
|
42
|
-
pytest src/test_app.py --cov=src --cov-report=html
|
|
36
|
+
run.bat
|
|
43
37
|
```
|
|
44
38
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
### Modalidad 1: Con Python (run.bat)
|
|
48
|
-
Para PCs que tienen Python instalado o pueden instalarlo:
|
|
49
|
-
|
|
39
|
+
### Manual
|
|
50
40
|
```bash
|
|
51
|
-
run.
|
|
41
|
+
uv run python src/main.py
|
|
52
42
|
```
|
|
53
43
|
|
|
54
|
-
|
|
55
|
-
1. Detecta si hay Python en el sistema
|
|
56
|
-
2. Si no hay, instala UV (gestor rápido)
|
|
57
|
-
3. UV instala Python 3.10
|
|
58
|
-
4. Crea entorno virtual
|
|
59
|
-
5. Instala dependencias
|
|
60
|
-
6. Crea acceso directo en escritorio
|
|
61
|
-
7. Ejecuta la app
|
|
44
|
+
`uv run` detecta/instala Python y dependencias automaticamente.
|
|
62
45
|
|
|
63
|
-
|
|
64
|
-
Para PCs que NO tienen Python - genera ejecutable standalone:
|
|
46
|
+
## Build Windows (EXE standalone)
|
|
65
47
|
|
|
66
48
|
```bash
|
|
67
|
-
cd portable
|
|
68
49
|
build.bat
|
|
69
50
|
```
|
|
70
51
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
El EXE funciona en cualquier PC con Windows sin necesidad de Python.
|
|
52
|
+
Genera ejecutable en `build/windows/` usando `flet build`.
|
|
74
53
|
|
|
75
|
-
##
|
|
54
|
+
## Theme y Colores
|
|
76
55
|
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
portable\build.bat
|
|
80
|
-
```
|
|
56
|
+
Los colores se definen en `src/core/skill.json` y se cargan via `G360Theme`.
|
|
81
57
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
1. Primero ejecuta los tests: `pytest src/test_app.py -v`
|
|
94
|
-
2. Identifica el test que falla
|
|
95
|
-
3. Reproduce el problema en el código
|
|
96
|
-
4. Implementa la solución
|
|
97
|
-
5. Verifica con tests
|
|
98
|
-
|
|
99
|
-
### Para cálculos y procesamiento:
|
|
100
|
-
1. Usa la clase TestCalculations en test_app.py
|
|
101
|
-
2. Agrega nuevos tests para funciones de cálculo
|
|
102
|
-
3. Ejecuta: `pytest src/test_app.py::TestCalculations -v`
|
|
103
|
-
|
|
104
|
-
### Antes de subir a GitHub:
|
|
105
|
-
```bash
|
|
106
|
-
g360 clean . --github
|
|
107
|
-
```
|
|
108
|
-
Esto actualiza el .gitignore y prepara el repo para remoto.
|
|
109
|
-
|
|
110
|
-
## Skills Disponibles
|
|
111
|
-
|
|
112
|
-
- `flet-desktop` - Estilo G360 moderno para desktop
|
|
113
|
-
- `flet-desktop-corporativo` - Estilo corporativo
|
|
58
|
+
### Paleta G360
|
|
59
|
+
| Token | Color | Uso |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| `bg` | `#0b1220` | Fondo principal |
|
|
62
|
+
| `surface` | `#1a2332` | Cards, contenedores |
|
|
63
|
+
| `accent` | `#00d084` | Verde G360 primary |
|
|
64
|
+
| `text` | `#f0f4f8` | Texto principal |
|
|
65
|
+
| `muted` | `#94a3b8` | Texto secundario |
|
|
66
|
+
| `success` | `#22c55e` | Exito/positivo |
|
|
67
|
+
| `warning` | `#f59e0b` | Advertencia |
|
|
68
|
+
| `error` | `#ef4444` | Error/peligro |
|
|
114
69
|
|
|
115
70
|
## Snippets Flet
|
|
116
71
|
|
|
117
|
-
|
|
118
|
-
- `flet-page` - Configuración de página
|
|
72
|
+
- `flet-page` - Configuracion de pagina con tema
|
|
119
73
|
- `flet-card` - Tarjetas con estilo G360
|
|
120
74
|
- `flet-button` - Botones G360
|
|
75
|
+
- `flet-kpi-card` - Card de KPI para dashboards
|
|
76
|
+
- `flet-drop-zone` - Zona de carga de archivos
|
|
121
77
|
- `flet-datatable` - Tablas de datos
|
|
122
|
-
- `flet-dialog` -
|
|
123
|
-
- `flet-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
78
|
+
- `flet-dialog` - Dialogos modales
|
|
79
|
+
- `flet-loading-overlay` - Overlay de carga
|
|
80
|
+
- `flet-footer-signature` - Footer con branding G360
|
|
81
|
+
|
|
82
|
+
## Lineamientos de Arquitectura
|
|
83
|
+
|
|
84
|
+
1. **src/core/**: NO importa `flet`. Solo logica de negocio
|
|
85
|
+
2. **src/ui/**: Importa `flet` y `core`. Solo presentacion
|
|
86
|
+
3. **src/export/**: Importa `openpyxl` y `core`. Solo reportes
|
|
87
|
+
4. **Threading**: Usar `threading.Thread` para operaciones bloqueantes
|
|
88
|
+
5. **Estado**: Atributos de clase. Evitar variables globales
|
|
89
|
+
6. **Colores**: Siempre via `G360Theme`. Nunca hardcodear
|