g360-cli 1.3.0 → 1.5.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 (86) hide show
  1. package/README.md +209 -5
  2. package/package.json +15 -8
  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 +112 -0
  13. package/src/assets/config/project-types.json +16 -0
  14. package/src/assets/config/skills.json +12 -0
  15. package/src/assets/snippets/snippets.json +293 -24
  16. package/src/assets/templates/lit-web/src/core/skill.json +12 -5
  17. package/src/assets/templates/python-cli/build-portable.bat +43 -0
  18. package/src/assets/templates/python-cli/src/core/skill.json +25 -6
  19. package/src/assets/templates/python-cli/src/main.py +107 -3
  20. package/src/assets/templates/python-customtkinter/README.md +48 -0
  21. package/src/assets/templates/python-customtkinter/assets/images/logo-g360-dark.svg +19 -0
  22. package/src/assets/templates/python-customtkinter/assets/images/logo-g360-light.svg +19 -0
  23. package/src/assets/templates/python-customtkinter/build.bat +50 -0
  24. package/src/assets/templates/python-customtkinter/pyproject.toml +26 -0
  25. package/src/assets/templates/python-customtkinter/run.bat +20 -0
  26. package/src/assets/templates/python-customtkinter/src/core/g360_theme.py +101 -0
  27. package/src/assets/templates/python-customtkinter/src/core/skill.json +35 -0
  28. package/src/assets/templates/python-customtkinter/src/main.py +103 -0
  29. package/src/assets/templates/python-flet/README.md +89 -0
  30. package/src/assets/templates/python-flet/assets/images/Logo_cipsa_borde.png +0 -0
  31. package/src/assets/templates/python-flet/assets/images/Logo_cipsa_borde.svg +9 -0
  32. package/src/assets/templates/python-flet/assets/images/Logo_cipsa_solid.png +0 -0
  33. package/src/assets/templates/python-flet/assets/images/Logo_cipsa_solid.svg +9 -0
  34. package/src/assets/templates/python-flet/assets/images/logo-g360-dark.svg +19 -0
  35. package/src/assets/templates/python-flet/assets/images/logo-g360-light.svg +19 -0
  36. package/src/assets/templates/python-flet/build.bat +36 -0
  37. package/src/assets/templates/python-flet/pyproject.toml +26 -0
  38. package/src/assets/templates/python-flet/run.bat +20 -0
  39. package/src/assets/templates/python-flet/src/core/__init__.py +0 -0
  40. package/src/assets/templates/python-flet/src/core/g360_theme.py +186 -0
  41. package/src/assets/templates/python-flet/src/core/skill.json +41 -0
  42. package/src/assets/templates/python-flet/src/export/__init__.py +0 -0
  43. package/src/assets/templates/python-flet/src/main.py +146 -0
  44. package/src/assets/templates/python-flet/src/test_app.py +107 -0
  45. package/src/assets/templates/python-flet/src/ui/__init__.py +0 -0
  46. package/src/assets/templates/python-flet-migrate/README.md +70 -0
  47. package/src/assets/templates/python-flet-migrate/assets/images/logo-g360-dark.svg +19 -0
  48. package/src/assets/templates/python-flet-migrate/assets/images/logo-g360-light.svg +19 -0
  49. package/src/assets/templates/python-flet-migrate/build.bat +36 -0
  50. package/src/assets/templates/python-flet-migrate/pyproject.toml +26 -0
  51. package/src/assets/templates/python-flet-migrate/run.bat +20 -0
  52. package/src/assets/templates/python-flet-migrate/src/core/__init__.py +0 -0
  53. package/src/assets/templates/python-flet-migrate/src/core/g360_theme.py +186 -0
  54. package/src/assets/templates/python-flet-migrate/src/core/skill.json +34 -0
  55. package/src/assets/templates/python-flet-migrate/src/main.py +97 -0
  56. package/src/assets/templates/python-flet-migrate/src/migrate_tkinter.py +56 -0
  57. package/src/assets/templates/solid-web/src/core/skill.json +12 -5
  58. package/src/assets/templates/svelte-web/src/core/skill.json +12 -5
  59. package/src/assets/templates/web-pwa/index.html +2 -7
  60. package/src/assets/templates/web-pwa/public/favicon.svg +4 -0
  61. package/src/assets/templates/web-pwa/public/manifest.json +11 -0
  62. package/src/assets/templates/web-pwa/src/App.jsx +22 -0
  63. package/src/assets/templates/web-pwa/src/components/FooterSignature.jsx +9 -0
  64. package/src/assets/templates/web-pwa/src/components/Header.jsx +12 -0
  65. package/src/assets/templates/web-pwa/src/components/LoadingOverlay.jsx +10 -0
  66. package/src/assets/templates/web-pwa/src/core/skill.json +25 -0
  67. package/src/assets/templates/web-pwa/src/main.jsx +9 -0
  68. package/src/assets/templates/web-pwa/src/styles/main.css +133 -0
  69. package/src/assets/templates/web-pwa/vite.config.js +12 -0
  70. package/src/cli.js +8 -4
  71. package/src/commands/bring.js +81 -6
  72. package/src/commands/clean.js +51 -4
  73. package/src/commands/init.js +60 -8
  74. package/src/commands/list.js +79 -9
  75. package/src/commands/signature.js +12 -8
  76. package/src/lib/asset-validator.js +145 -0
  77. package/src/lib/auditor.js +48 -0
  78. package/src/lib/global-config.js +260 -0
  79. package/src/lib/i18n.js +238 -0
  80. package/src/lib/logger.js +100 -0
  81. package/src/lib/manifest.js +70 -1
  82. package/src/lib/validator.js +39 -0
  83. package/src/schemas/skills-schema.json +1 -0
  84. package/src/schemas/snippets-schema.json +1 -0
  85. package/src/assets/templates/web-pwa/app.js +0 -1
  86. package/src/assets/templates/web-pwa/styles.css +0 -28
@@ -0,0 +1,20 @@
1
+ @echo off
2
+ chcp 65001 >nul
3
+ cd /d "%~dp0"
4
+
5
+ echo.
6
+ echo ========================================
7
+ echo G360 Flet Migration App
8
+ echo powered by G360
9
+ echo ========================================
10
+ echo.
11
+
12
+ REM uv run detecta/instala Python y dependencias automaticamente
13
+ uv run python src/main.py
14
+
15
+ if errorlevel 1 (
16
+ echo.
17
+ echo ERROR: La aplicacion fallo.
18
+ echo Verifique que uv este instalado: https://docs.astral.sh/uv/
19
+ pause
20
+ )
@@ -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
+ }
@@ -0,0 +1,97 @@
1
+ import sys
2
+ from pathlib import Path
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))
9
+
10
+
11
+ class MigratedApp:
12
+ def __init__(self, page: ft.Page):
13
+ self.page = page
14
+ self.theme = G360Theme()
15
+ self._setup_page()
16
+ self._build_ui()
17
+
18
+ def _setup_page(self):
19
+ self.page.title = self.theme.build_name()
20
+ self.page.theme_mode = ft.ThemeMode.DARK
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()
27
+
28
+ def _build_ui(self):
29
+ self.page.add(
30
+ ft.Column([
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)
39
+ )
40
+
41
+ def _build_header(self):
42
+ return self.theme.container(
43
+ content=ft.Row([
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),
47
+ ft.Container(expand=True),
48
+ ft.Text("from tkinter/ctkinter", size=14, color=self.theme.muted),
49
+ ]),
50
+ padding=20,
51
+ bgcolor=self.theme.surface,
52
+ )
53
+
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)
84
+
85
+
86
+ def main(page: ft.Page):
87
+ MigratedApp(page)
88
+
89
+
90
+ if __name__ == "__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...")
@@ -0,0 +1,56 @@
1
+ """
2
+ Migración de tkinter/ctkinter a Flet
3
+ Script de ayuda para convertir código existente
4
+ """
5
+
6
+ MAPPING = {
7
+ 'tk.Label': 'ft.Text',
8
+ 'tk.Button': 'ft.ElevatedButton',
9
+ 'tk.Entry': 'ft.TextField',
10
+ 'tk.Checkbutton': 'ft.Checkbox',
11
+ 'tk.Radiobutton': 'ft.Radio',
12
+ 'tk.Listbox': 'ft.ListView',
13
+ 'tk.Frame': 'ft.Container',
14
+ 'tk.LabelFrame': 'ft.Container with border',
15
+ 'tk.Canvas': 'ft.Canvas',
16
+ 'tk.Menu': 'ft.AppBar with actions',
17
+ 'ctk.CTkButton': 'ft.ElevatedButton',
18
+ 'ctk.CTkLabel': 'ft.Text',
19
+ 'ctk.CTkEntry': 'ft.TextField',
20
+ 'ctk.CTkFrame': 'ft.Container',
21
+ 'ctk.CTkCheckBox': 'ft.Checkbox',
22
+ 'ctk.CTkRadioButton': 'ft.Radio',
23
+ 'ctk.CTkProgressBar': 'ft.ProgressBar',
24
+ 'ctk.CTkSlider': 'ft.Slider',
25
+ 'ctk.CTkSwitch': 'ft.Switch',
26
+ 'ctk.CTkComboBox': 'ft.Dropdown',
27
+ 'ctk.CTkTextbox': 'ft.TextField multiline',
28
+ 'ctk.CTkTabview': 'ft.Tabs',
29
+ }
30
+
31
+ LAYOUT_MAPPING = {
32
+ 'pack()': 'page.add()',
33
+ 'pack(fill=..., expand=...)': 'expand=True, alignment=...',
34
+ 'grid(row=..., column=...)': 'use Column with Row for grid-like',
35
+ 'place(x=..., y=...)': 'position in Container',
36
+ }
37
+
38
+ THEME_MAPPING = {
39
+ 'bg': 'bgcolor',
40
+ 'fg': 'color',
41
+ 'font': 'size + weight',
42
+ 'relief': 'border_style',
43
+ 'padx/pady': 'padding',
44
+ 'width': 'width',
45
+ 'height': 'height',
46
+ }
47
+
48
+ def convert_tkinter_to_flet(code: str) -> str:
49
+ result = code
50
+ for tk_widget, flet_widget in MAPPING.items():
51
+ result = result.replace(tk_widget, flet_widget)
52
+ return result
53
+
54
+ print("Mapeo de tkinter/ctkinter a Flet cargado")
55
+ print("Usa: from migrate_tkinter import convert_tkinter_to_flet")
56
+ print("Para convertir código existente a Flet")
@@ -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,10 @@
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>
22
17
  </body>
23
18
  </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
+ );