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.
Files changed (93) hide show
  1. package/README.md +122 -0
  2. package/package.json +11 -4
  3. package/src/assets/brand/brand.json +43 -0
  4. package/src/assets/brand/cipsa/logotypes/Logo_cipsa_borde.png +0 -0
  5. package/src/assets/brand/cipsa/logotypes/Logo_cipsa_borde.svg +9 -0
  6. package/src/assets/brand/cipsa/logotypes/Logo_cipsa_solid.png +0 -0
  7. package/src/assets/brand/cipsa/logotypes/Logo_cipsa_solid.svg +9 -0
  8. package/src/assets/brand/g360/logotypes/logo-g360-dark.svg +19 -0
  9. package/src/assets/brand/g360/logotypes/logo-g360-light.svg +19 -0
  10. package/src/assets/brand/g360/logotypes/logo_g360_dark_b64.txt +1 -0
  11. package/src/assets/brand/g360/logotypes/logo_g360_light_b64.txt +1 -0
  12. package/src/assets/config/g360-skills.json +60 -0
  13. package/src/assets/signature/g360_flet/__init__.py +5 -0
  14. package/src/assets/signature/g360_flet/__pycache__/__init__.cpython-312.pyc +0 -0
  15. package/src/assets/signature/g360_flet/__pycache__/__init__.cpython-314.pyc +0 -0
  16. package/src/assets/signature/g360_flet/__pycache__/g360_signature.cpython-312.pyc +0 -0
  17. package/src/assets/signature/g360_flet/__pycache__/g360_signature.cpython-314.pyc +0 -0
  18. package/src/assets/signature/g360_flet/g360_signature.py +224 -0
  19. package/src/assets/signature/index.js +130 -0
  20. package/src/assets/snippets/snippets.json +293 -101
  21. package/src/assets/templates/lit-web/src/core/skill.json +12 -5
  22. package/src/assets/templates/python-cli/build-portable.bat +19 -9
  23. package/src/assets/templates/python-cli/src/core/skill.json +25 -6
  24. package/src/assets/templates/python-customtkinter/README.md +32 -31
  25. package/src/assets/templates/python-customtkinter/assets/images/logo-g360-dark.svg +19 -0
  26. package/src/assets/templates/python-customtkinter/assets/images/logo-g360-light.svg +19 -0
  27. package/src/assets/templates/python-customtkinter/build.bat +50 -0
  28. package/src/assets/templates/python-customtkinter/pyproject.toml +26 -0
  29. package/src/assets/templates/python-customtkinter/run.bat +11 -20
  30. package/src/assets/templates/python-customtkinter/src/core/g360_theme.py +101 -0
  31. package/src/assets/templates/python-customtkinter/src/core/skill.json +23 -10
  32. package/src/assets/templates/python-customtkinter/src/main.py +61 -81
  33. package/src/assets/templates/python-flet/README.md +52 -93
  34. package/src/assets/templates/python-flet/assets/images/Logo_cipsa_borde.png +0 -0
  35. package/src/assets/templates/python-flet/assets/images/Logo_cipsa_borde.svg +9 -0
  36. package/src/assets/templates/python-flet/assets/images/Logo_cipsa_solid.png +0 -0
  37. package/src/assets/templates/python-flet/assets/images/Logo_cipsa_solid.svg +9 -0
  38. package/src/assets/templates/python-flet/assets/images/logo-g360-dark.svg +19 -0
  39. package/src/assets/templates/python-flet/assets/images/logo-g360-light.svg +19 -0
  40. package/src/assets/templates/python-flet/build.bat +36 -0
  41. package/src/assets/templates/python-flet/pyproject.toml +26 -0
  42. package/src/assets/templates/python-flet/run.bat +11 -72
  43. package/src/assets/templates/python-flet/src/core/__init__.py +0 -0
  44. package/src/assets/templates/python-flet/src/core/g360_theme.py +193 -0
  45. package/src/assets/templates/python-flet/src/core/skill.json +28 -8
  46. package/src/assets/templates/python-flet/src/export/__init__.py +0 -0
  47. package/src/assets/templates/python-flet/src/main.py +113 -68
  48. package/src/assets/templates/python-flet/src/test_app.py +41 -37
  49. package/src/assets/templates/python-flet/src/ui/__init__.py +0 -0
  50. package/src/assets/templates/python-flet-migrate/README.md +70 -0
  51. package/src/assets/templates/python-flet-migrate/assets/images/logo-g360-dark.svg +19 -0
  52. package/src/assets/templates/python-flet-migrate/assets/images/logo-g360-light.svg +19 -0
  53. package/src/assets/templates/python-flet-migrate/build.bat +36 -0
  54. package/src/assets/templates/python-flet-migrate/pyproject.toml +26 -0
  55. package/src/assets/templates/python-flet-migrate/run.bat +20 -0
  56. package/src/assets/templates/python-flet-migrate/src/core/__init__.py +0 -0
  57. package/src/assets/templates/python-flet-migrate/src/core/g360_theme.py +186 -0
  58. package/src/assets/templates/python-flet-migrate/src/core/skill.json +34 -0
  59. package/src/assets/templates/python-flet-migrate/src/main.py +71 -42
  60. package/src/assets/templates/solid-web/src/core/skill.json +12 -5
  61. package/src/assets/templates/svelte-web/src/core/skill.json +12 -5
  62. package/src/assets/templates/web-pwa/index.html +5 -7
  63. package/src/assets/templates/web-pwa/public/favicon.svg +4 -0
  64. package/src/assets/templates/web-pwa/public/manifest.json +11 -0
  65. package/src/assets/templates/web-pwa/src/App.jsx +22 -0
  66. package/src/assets/templates/web-pwa/src/components/FooterSignature.jsx +9 -0
  67. package/src/assets/templates/web-pwa/src/components/Header.jsx +12 -0
  68. package/src/assets/templates/web-pwa/src/components/LoadingOverlay.jsx +10 -0
  69. package/src/assets/templates/web-pwa/src/core/skill.json +25 -0
  70. package/src/assets/templates/web-pwa/src/main.jsx +9 -0
  71. package/src/assets/templates/web-pwa/src/styles/main.css +133 -0
  72. package/src/assets/templates/web-pwa/vite.config.js +12 -0
  73. package/src/cli.js +10 -5
  74. package/src/commands/bring.js +81 -6
  75. package/src/commands/list.js +79 -9
  76. package/src/commands/signature.js +252 -55
  77. package/src/lib/asset-validator.js +145 -0
  78. package/src/lib/auditor.js +48 -0
  79. package/src/lib/global-config.js +260 -0
  80. package/src/lib/i18n.js +238 -0
  81. package/src/lib/logger.js +100 -0
  82. package/src/lib/manifest.js +70 -1
  83. package/src/lib/validator.js +39 -0
  84. package/src/schemas/skills-schema.json +1 -0
  85. package/src/schemas/snippets-schema.json +1 -0
  86. package/dist/g360.exe +0 -0
  87. package/src/assets/templates/python-customtkinter/build-portable.bat +0 -28
  88. package/src/assets/templates/python-customtkinter/requirements.txt +0 -1
  89. package/src/assets/templates/python-flet/build-portable.bat +0 -42
  90. package/src/assets/templates/python-flet/create_shortcut.vbs +0 -35
  91. package/src/assets/templates/python-flet/requirements.txt +0 -3
  92. package/src/assets/templates/web-pwa/app.js +0 -1
  93. package/src/assets/templates/web-pwa/styles.css +0 -28
@@ -0,0 +1,186 @@
1
+ import json
2
+ import base64
3
+ from pathlib import Path
4
+
5
+
6
+ class G360Theme:
7
+ def __init__(self, skill_path=None):
8
+ self._search_paths(skill_path)
9
+ self._load_colors()
10
+ self._load_effects()
11
+ self._load_logo()
12
+
13
+ def _search_paths(self, skill_path):
14
+ if skill_path and Path(skill_path).exists():
15
+ self.config_path = Path(skill_path)
16
+ return
17
+ candidates = [
18
+ Path("skill.json"),
19
+ Path("src/core/skill.json"),
20
+ Path(__file__).resolve().parent.parent.parent / "skill.json",
21
+ Path(__file__).resolve().parent / "skill.json",
22
+ Path(__file__).resolve().parent.parent / "g360" / "skills" / "flet-desktop.json",
23
+ ]
24
+ for c in candidates:
25
+ if c.exists():
26
+ self.config_path = c
27
+ return
28
+ raise FileNotFoundError("skill.json not found. Run: g360 init <name> --skill flet-desktop")
29
+
30
+ def _load_colors(self):
31
+ with open(self.config_path, encoding="utf-8") as f:
32
+ self.config = json.load(f)
33
+ colors = self.config.get("colors", {})
34
+ self.bg = colors.get("bg", "#0b1220")
35
+ self.surface = colors.get("surface", "#1a2332")
36
+ self.accent = colors.get("accent", "#00d084")
37
+ self.text = colors.get("text", "#f0f4f8")
38
+ self.muted = colors.get("muted", "#94a3b8")
39
+ self.success = colors.get("success", "#22c55e")
40
+ self.warning = colors.get("warning", "#f59e0b")
41
+ self.error = colors.get("error", "#ef4444")
42
+ self.brand = self.config.get("brand", "g360")
43
+
44
+ def _load_effects(self):
45
+ effects = self.config.get("effects", {})
46
+ self.glassmorphism = effects.get("glassmorphism", True)
47
+ self.blur = effects.get("blur", "12px")
48
+ self.rounded = int(effects.get("rounded", "12px").replace("px", ""))
49
+
50
+ def _load_logo(self):
51
+ logo_name = None
52
+ guidelines = self.config.get("guidelines", {})
53
+ if guidelines.get("logo"):
54
+ logo_name = guidelines["logo"]
55
+ if not logo_name:
56
+ logo_name = "logo-g360-dark.svg"
57
+ paths = [
58
+ Path("assets/images") / logo_name,
59
+ Path(__file__).resolve().parent.parent.parent / "assets" / "images" / logo_name,
60
+ ]
61
+ self._logo_path = None
62
+ for p in paths:
63
+ if p.exists():
64
+ self._logo_path = p
65
+ break
66
+ self._logo_b64 = None
67
+
68
+ def logo_src(self, page=None):
69
+ if self._logo_path and self._logo_path.exists():
70
+ return str(self._logo_path)
71
+ return None
72
+
73
+ def logo_base64(self):
74
+ if self._logo_b64:
75
+ return self._logo_b64
76
+ if self._logo_path and self._logo_path.exists():
77
+ raw = self._logo_path.read_bytes()
78
+ ext = self._logo_path.suffix.lower()
79
+ mime = "image/svg+xml" if ext == ".svg" else f"image/{ext[1:]}"
80
+ self._logo_b64 = f"data:{mime};base64,{base64.b64encode(raw).decode()}"
81
+ return self._logo_b64
82
+ brand_dir = Path(__file__).resolve().parent.parent.parent / "assets" / "images"
83
+ fallback = brand_dir / "logo-g360-dark.svg"
84
+ if fallback.exists():
85
+ raw = fallback.read_bytes()
86
+ self._logo_b64 = f"data:image/svg+xml;base64,{base64.b64encode(raw).decode()}"
87
+ return self._logo_b64
88
+ return None
89
+
90
+ def build_name(self):
91
+ build_cfg = self.config.get("build", {})
92
+ return build_cfg.get("name", "G360-App")
93
+
94
+ def logo_component(self, height=40):
95
+ import flet as ft
96
+ src = self.logo_base64()
97
+ if src:
98
+ return ft.Image(src_base64=src, height=height, fit=ft.ImageFit.CONTAIN)
99
+ return ft.Text(self.build_name(), size=18, weight=ft.FontWeight.BOLD, color=self.accent)
100
+
101
+ def container(self, content=None, **kwargs):
102
+ kwargs.setdefault("bgcolor", self.surface)
103
+ kwargs.setdefault("border_radius", self.rounded)
104
+ kwargs.setdefault("padding", 15)
105
+ if self.glassmorphism and "shadow" not in kwargs:
106
+ import flet as ft
107
+ kwargs["shadow"] = ft.BoxShadow(
108
+ spread_radius=1,
109
+ blur_radius=20,
110
+ color=f"{self.accent}20",
111
+ )
112
+ import flet as ft
113
+ return ft.Container(content=content, **kwargs)
114
+
115
+ def accent_button(self, text="", on_click=None, **kwargs):
116
+ import flet as ft
117
+ return ft.ElevatedButton(
118
+ text=text,
119
+ on_click=on_click,
120
+ style=ft.ButtonStyle(
121
+ bgcolor=self.accent,
122
+ color=self.bg,
123
+ shape=ft.RoundedRectangleBorder(radius=8),
124
+ padding=15,
125
+ ),
126
+ **kwargs,
127
+ )
128
+
129
+ def styled_text(self, value="", size=14, color=None, weight=None, **kwargs):
130
+ import flet as ft
131
+ return ft.Text(
132
+ value=value,
133
+ size=size,
134
+ color=color or self.text,
135
+ weight=weight,
136
+ **kwargs,
137
+ )
138
+
139
+ def loading_overlay(self, message="Cargando..."):
140
+ import flet as ft
141
+ return ft.Container(
142
+ content=ft.Column(
143
+ [
144
+ ft.ProgressRing(width=48, height=48, color=self.accent),
145
+ ft.Container(height=16),
146
+ ft.Text(message, size=16, color=self.text),
147
+ ],
148
+ horizontal_alignment=ft.CrossAxisAlignment.CENTER,
149
+ alignment=ft.MainAxisAlignment.CENTER,
150
+ ),
151
+ bgcolor=f"{self.bg}E0",
152
+ expand=True,
153
+ alignment=ft.alignment.center,
154
+ visible=False,
155
+ )
156
+
157
+ def footer_signature(self):
158
+ import flet as ft
159
+ mode = self.config.get("signature", {}).get("mode", "powered")
160
+ text = self.config.get("signature", {}).get("text", "powered by G360")
161
+ return ft.Container(
162
+ content=ft.Row(
163
+ [
164
+ self.logo_component(height=16),
165
+ ft.Container(width=8),
166
+ ft.Text(text, size=10, color=self.muted),
167
+ ],
168
+ alignment=ft.MainAxisAlignment.CENTER,
169
+ ),
170
+ padding=8,
171
+ bgcolor=self.surface,
172
+ )
173
+
174
+ @property
175
+ def as_dict(self):
176
+ return {
177
+ "bg": self.bg,
178
+ "surface": self.surface,
179
+ "accent": self.accent,
180
+ "text": self.text,
181
+ "muted": self.muted,
182
+ "success": self.success,
183
+ "warning": self.warning,
184
+ "error": self.error,
185
+ "brand": self.brand,
186
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "flet-desktop",
3
+ "description": "G360 Flet Migration Application",
4
+ "framework": "flet",
5
+ "version": "1.2.0",
6
+ "python": ">=3.11,<4.0",
7
+ "colors": {
8
+ "bg": "#0b1220",
9
+ "surface": "#1a2332",
10
+ "accent": "#00d084",
11
+ "text": "#f0f4f8",
12
+ "muted": "#94a3b8",
13
+ "success": "#22c55e",
14
+ "warning": "#f59e0b",
15
+ "error": "#ef4444"
16
+ },
17
+ "effects": {
18
+ "glassmorphism": true,
19
+ "blur": "12px",
20
+ "rounded": "12px"
21
+ },
22
+ "signature": {
23
+ "mode": "powered",
24
+ "text": "powered by G360"
25
+ },
26
+ "build": {
27
+ "tool": "flet",
28
+ "target": "windows",
29
+ "name": "G360-App"
30
+ },
31
+ "dependencies": {
32
+ "flet": ">=0.25.0"
33
+ }
34
+ }
@@ -1,63 +1,86 @@
1
+ import sys
2
+ from pathlib import Path
1
3
  import flet as ft
4
+ from core.g360_theme import G360Theme
5
+
6
+ BASE_DIR = Path(__file__).resolve().parent.parent
7
+ if str(BASE_DIR) not in sys.path:
8
+ sys.path.insert(0, str(BASE_DIR))
2
9
 
3
10
 
4
11
  class MigratedApp:
5
12
  def __init__(self, page: ft.Page):
6
13
  self.page = page
7
- self.setup_theme()
8
- self.create_ui()
14
+ self.theme = G360Theme()
15
+ self._setup_page()
16
+ self._build_ui()
9
17
 
10
- def setup_theme(self):
11
- self.page.title = "G360 - Migrated App"
18
+ def _setup_page(self):
19
+ self.page.title = self.theme.build_name()
12
20
  self.page.theme_mode = ft.ThemeMode.DARK
13
- self.page.padding = 20
14
- self.page.bgcolor = "#0b1220"
21
+ self.page.bgcolor = self.theme.bg
22
+ self.page.padding = 0
23
+ self.page.window_width = 900
24
+ self.page.window_height = 700
25
+ self.page.window_resizable = True
26
+ self.page.window_center()
15
27
 
16
- def create_ui(self):
28
+ def _build_ui(self):
17
29
  self.page.add(
18
30
  ft.Column([
19
- self.create_header(),
20
- self.create_main_content(),
21
- ], spacing=20, expand=True)
31
+ self._build_header(),
32
+ ft.Container(
33
+ content=self._build_content(),
34
+ expand=True,
35
+ padding=20,
36
+ ),
37
+ self.theme.footer_signature(),
38
+ ], spacing=0, expand=True)
22
39
  )
23
40
 
24
- def create_header(self):
25
- return ft.Container(
41
+ def _build_header(self):
42
+ return self.theme.container(
26
43
  content=ft.Row([
27
- ft.Text("G360 Migrated App", size=28, weight=ft.FontWeight.BOLD, color="#00d084"),
44
+ self.theme.logo_component(height=32),
45
+ ft.Container(width=8),
46
+ self.theme.styled_text("Migrated App", size=20, color=self.theme.muted),
28
47
  ft.Container(expand=True),
29
- ft.Text("from tkinter/ctkinter", size=14, color="#94a3b8"),
48
+ ft.Text("from tkinter/ctkinter", size=14, color=self.theme.muted),
30
49
  ]),
31
50
  padding=20,
32
- bgcolor="#151e2e",
33
- border_radius=12
51
+ bgcolor=self.theme.surface,
34
52
  )
35
53
 
36
- def create_main_content(self):
37
- return ft.Container(
38
- content=ft.Column([
39
- ft.Text("Panel de Controles (antes tk.Button)", size=20, color="#f0f4f8"),
40
- ft.Row([
41
- ft.ElevatedButton("Aceptar", bgcolor="#00d084", color="#0b1220"),
42
- ft.ElevatedButton("Cancelar", bgcolor="#ef4444", color="#ffffff"),
43
- ft.ElevatedButton("Guardar", bgcolor="#00796B", color="#ffffff"),
44
- ], spacing=15),
45
- ft.Container(height=30),
46
- ft.Text("Campos de Entrada (antes tk.Entry)", size=20, color="#f0f4f8"),
47
- ft.Column([
48
- ft.TextField(label="Usuario", hint_text="Ingrese usuario", width=300),
49
- ft.TextField(label="Contraseña", hint_text="Ingrese contraseña", password=True, width=300),
50
- ], spacing=15),
51
- ft.Container(height=30),
52
- ft.Text("Casillas y Opciones (antes tk.Checkbutton/tk.Radiobutton)", size=20, color="#f0f4f8"),
53
- ft.Column([
54
- ft.Checkbox(label="Recordarme"),
55
- ft.Checkbox(label="Aceptar términos"),
56
- ], spacing=10),
57
- ], scroll=ft.ScrollMode.AUTO),
58
- expand=True,
59
- padding=20
60
- )
54
+ def _build_content(self):
55
+ return ft.Column([
56
+ self.theme.styled_text(
57
+ "Panel de Controles (antes tk.Button)",
58
+ size=20, weight=ft.FontWeight.BOLD,
59
+ ),
60
+ ft.Row([
61
+ self.theme.accent_button("Aceptar"),
62
+ ft.ElevatedButton("Cancelar", bgcolor=self.theme.error, color="#ffffff"),
63
+ ft.ElevatedButton("Guardar", bgcolor="#00796B", color="#ffffff"),
64
+ ], spacing=15),
65
+ ft.Container(height=30),
66
+ self.theme.styled_text(
67
+ "Campos de Entrada (antes tk.Entry)",
68
+ size=20, weight=ft.FontWeight.BOLD,
69
+ ),
70
+ ft.Column([
71
+ ft.TextField(label="Usuario", hint_text="Ingrese usuario", width=300),
72
+ ft.TextField(label="Contraseña", hint_text="Ingrese contraseña", password=True, width=300),
73
+ ], spacing=15),
74
+ ft.Container(height=30),
75
+ self.theme.styled_text(
76
+ "Casillas y Opciones (antes tk.Checkbutton/tk.Radiobutton)",
77
+ size=20, weight=ft.FontWeight.BOLD,
78
+ ),
79
+ ft.Column([
80
+ ft.Checkbox(label="Recordarme"),
81
+ ft.Checkbox(label="Aceptar términos"),
82
+ ], spacing=10),
83
+ ], scroll=ft.ScrollMode.AUTO)
61
84
 
62
85
 
63
86
  def main(page: ft.Page):
@@ -65,4 +88,10 @@ def main(page: ft.Page):
65
88
 
66
89
 
67
90
  if __name__ == "__main__":
68
- ft.app(target=main)
91
+ try:
92
+ ft.run(main)
93
+ except Exception as e:
94
+ print(f"\n[FATAL] Error al iniciar la aplicacion: {e}", flush=True)
95
+ import traceback
96
+ traceback.print_exc()
97
+ input("\nPresione Enter para salir...")
@@ -1,15 +1,22 @@
1
1
  {
2
- "skill": "corporativo",
3
- "device": "movil",
4
- "template": "solid-web",
2
+ "name": "solid-web",
3
+ "description": "G360 SolidJS Application",
4
+ "framework": "solid",
5
5
  "version": "1.0.0",
6
- "createdAt": "2024-01-01T00:00:00.000Z",
7
6
  "colors": {
8
7
  "bg": "#0b1220",
9
8
  "surface": "#151e2e",
10
9
  "accent": "#00d084",
11
10
  "text": "#f0f4f8",
12
- "muted": "#94a3b8"
11
+ "muted": "#94a3b8",
12
+ "success": "#22c55e",
13
+ "warning": "#f59e0b",
14
+ "error": "#ef4444"
15
+ },
16
+ "effects": {
17
+ "glassmorphism": true,
18
+ "blur": "12px",
19
+ "rounded": "12px"
13
20
  },
14
21
  "signature": {
15
22
  "mode": "powered",
@@ -1,15 +1,22 @@
1
1
  {
2
- "skill": "corporativo",
3
- "device": "movil",
4
- "template": "svelte-web",
2
+ "name": "svelte-web",
3
+ "description": "G360 SvelteKit Application",
4
+ "framework": "svelte",
5
5
  "version": "1.0.0",
6
- "createdAt": "2024-01-01T00:00:00.000Z",
7
6
  "colors": {
8
7
  "bg": "#0b1220",
9
8
  "surface": "#151e2e",
10
9
  "accent": "#00d084",
11
10
  "text": "#f0f4f8",
12
- "muted": "#94a3b8"
11
+ "muted": "#94a3b8",
12
+ "success": "#22c55e",
13
+ "warning": "#f59e0b",
14
+ "error": "#ef4444"
15
+ },
16
+ "effects": {
17
+ "glassmorphism": true,
18
+ "blur": "12px",
19
+ "rounded": "12px"
13
20
  },
14
21
  "signature": {
15
22
  "mode": "powered",
@@ -9,15 +9,13 @@
9
9
  <title>Mi Proyecto G360</title>
10
10
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
11
11
  <link rel="manifest" href="/manifest.json" />
12
- <link rel="stylesheet" href="/styles.css" />
12
+ <link rel="stylesheet" href="/src/styles/main.css" />
13
13
  </head>
14
14
  <body>
15
15
  <div id="root"></div>
16
-
17
- <!-- Firma G360 -->
18
- <g360-signature mode="powered" style="position: fixed; bottom: 16px; right: 16px; z-index: 100;"></g360-signature>
19
-
20
- <script type="module" src="https://unpkg.com/g360-signature@1.0.0/index.js"></script>
21
- <script type="module" src="/app.js"></script>
16
+ <script type="module" src="/src/main.jsx"></script>
17
+ <script src="https://unpkg.com/g360-signature@latest/index.js"></script>
18
+ <!-- Firma Oficial G360 -->
19
+ <g360-signature mode="powered" style="position: fixed; bottom: 16px; right: 16px; z-index: 99999;"></g360-signature>
22
20
  </body>
23
21
  </html>
@@ -0,0 +1,4 @@
1
+ <svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
2
+ <circle cx="16" cy="16" r="14" fill="#0b1220" stroke="#00d084" stroke-width="2"/>
3
+ <text x="16" y="22" text-anchor="middle" font-family="Arial Black,sans-serif" font-size="16" font-weight="bold" fill="#00d084">G</text>
4
+ </svg>
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "G360 App",
3
+ "short_name": "G360",
4
+ "start_url": "/",
5
+ "display": "standalone",
6
+ "background_color": "#0b1220",
7
+ "theme_color": "#00d084",
8
+ "icons": [
9
+ { "src": "/favicon.svg", "sizes": "any", "type": "image/svg+xml" }
10
+ ]
11
+ }
@@ -0,0 +1,22 @@
1
+ import { useState } from 'react';
2
+ import Header from './components/Header';
3
+ import LoadingOverlay from './components/LoadingOverlay';
4
+ import FooterSignature from './components/FooterSignature';
5
+
6
+ function App() {
7
+ const [loading, setLoading] = useState(false);
8
+
9
+ return (
10
+ <div className="app">
11
+ <Header />
12
+ <main className="container">
13
+ <h1>Bienvenido a G360</h1>
14
+ <p className="muted">Proyecto creado con React + Vite</p>
15
+ </main>
16
+ <FooterSignature />
17
+ {loading && <LoadingOverlay message="Cargando..." />}
18
+ </div>
19
+ );
20
+ }
21
+
22
+ export default App;
@@ -0,0 +1,9 @@
1
+ function FooterSignature() {
2
+ return (
3
+ <footer className="g360-footer">
4
+ <span>powered by G360</span>
5
+ </footer>
6
+ );
7
+ }
8
+
9
+ export default FooterSignature;
@@ -0,0 +1,12 @@
1
+ function Header() {
2
+ return (
3
+ <header className="g360-header">
4
+ <div className="header-content">
5
+ <h1 className="logo">G360</h1>
6
+ <span className="subtitle">React App</span>
7
+ </div>
8
+ </header>
9
+ );
10
+ }
11
+
12
+ export default Header;
@@ -0,0 +1,10 @@
1
+ function LoadingOverlay({ message = 'Cargando...' }) {
2
+ return (
3
+ <div className="g360-loading-overlay">
4
+ <div className="g360-loading-spinner" />
5
+ <p>{message}</p>
6
+ </div>
7
+ );
8
+ }
9
+
10
+ export default LoadingOverlay;
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "corporativo-movil",
3
+ "description": "G360 React + Vite Application",
4
+ "framework": "react",
5
+ "version": "1.0.0",
6
+ "colors": {
7
+ "bg": "#0b1220",
8
+ "surface": "#151e2e",
9
+ "accent": "#00d084",
10
+ "text": "#f0f4f8",
11
+ "muted": "#94a3b8",
12
+ "success": "#22c55e",
13
+ "warning": "#f59e0b",
14
+ "error": "#ef4444"
15
+ },
16
+ "effects": {
17
+ "glassmorphism": true,
18
+ "blur": "16px",
19
+ "rounded": "16px"
20
+ },
21
+ "signature": {
22
+ "mode": "powered",
23
+ "text": "powered by G360"
24
+ }
25
+ }
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import App from './App';
4
+
5
+ ReactDOM.createRoot(document.getElementById('root')).render(
6
+ <React.StrictMode>
7
+ <App />
8
+ </React.StrictMode>
9
+ );