slicejs-web-framework 3.4.4 → 3.5.1
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/Slice/Components/Structural/Controller/Controller.js +135 -0
- package/Slice/Components/Structural/EventManager/EventManager.js +289 -4
- package/Slice/Components/Structural/EventManager/EventManagerDebugger.js +368 -30
- package/Slice/Components/Structural/LeakInspector/LeakInspector.js +296 -0
- package/Slice/Components/Structural/StylesManager/ThemeManager/ThemeManager.js +56 -0
- package/Slice/Slice.js +14 -1
- package/Slice/tests/event-emitters.test.js +79 -0
- package/Slice/tests/event-registry.test.js +141 -0
- package/Slice/tests/leak-orphans.test.js +131 -0
- package/api/{middleware → framework}/securityMiddleware.js +18 -74
- package/api/framework/server.js +333 -0
- package/api/index.js +5 -279
- package/api/tests/public-env-resolver.test.js +1 -1
- package/package.json +4 -2
- package/sliceConfig.schema.json +10 -1
- package/src/App/index.html +31 -1
- package/src/manifest.json +15 -0
- package/src/robots.txt +4 -0
- package/src/sitemap.xml +8 -0
- package/src/sliceConfig.json +5 -1
- package/types/index.d.ts +12 -0
- package/slicejs-cli/.github/workflows/ci.yml +0 -43
- package/slicejs-cli/LICENSE +0 -21
- package/slicejs-cli/assets/Slice.js-logo.png +0 -0
- package/slicejs-cli/client.js +0 -740
- package/slicejs-cli/commands/Print.js +0 -164
- package/slicejs-cli/commands/Validations.js +0 -92
- package/slicejs-cli/commands/build/build.js +0 -40
- package/slicejs-cli/commands/buildProduction/buildProduction.js +0 -577
- package/slicejs-cli/commands/bundle/bundle.js +0 -236
- package/slicejs-cli/commands/createComponent/VisualComponentTemplate.js +0 -55
- package/slicejs-cli/commands/createComponent/createComponent.js +0 -128
- package/slicejs-cli/commands/deleteComponent/deleteComponent.js +0 -81
- package/slicejs-cli/commands/doctor/doctor.js +0 -516
- package/slicejs-cli/commands/getComponent/getComponent.js +0 -695
- package/slicejs-cli/commands/init/init.js +0 -473
- package/slicejs-cli/commands/listComponents/listComponents.js +0 -172
- package/slicejs-cli/commands/startServer/startServer.js +0 -240
- package/slicejs-cli/commands/startServer/watchServer.js +0 -66
- package/slicejs-cli/commands/types/types.js +0 -583
- package/slicejs-cli/commands/utils/LocalCliDelegation.js +0 -53
- package/slicejs-cli/commands/utils/PackageManager.js +0 -148
- package/slicejs-cli/commands/utils/PathHelper.js +0 -75
- package/slicejs-cli/commands/utils/VersionChecker.js +0 -169
- package/slicejs-cli/commands/utils/bundling/BundleGenerator.js +0 -2525
- package/slicejs-cli/commands/utils/bundling/DependencyAnalyzer.js +0 -933
- package/slicejs-cli/commands/utils/loadConfig.js +0 -31
- package/slicejs-cli/commands/utils/sliceScripts.js +0 -48
- package/slicejs-cli/commands/utils/updateManager.js +0 -471
- package/slicejs-cli/package.json +0 -71
- package/slicejs-cli/playwright.config.js +0 -51
- package/slicejs-cli/pnpm-lock.yaml +0 -1629
- package/slicejs-cli/tests/build-command-integration.test.js +0 -87
- package/slicejs-cli/tests/build-mangling-e2e.test.js +0 -290
- package/slicejs-cli/tests/build-production-e2e.test.js +0 -140
- package/slicejs-cli/tests/builder-edge-cases.test.js +0 -322
- package/slicejs-cli/tests/bundle-generate-e2e.test.js +0 -115
- package/slicejs-cli/tests/bundle-generator.test.js +0 -691
- package/slicejs-cli/tests/bundle-v2-register-output.test.js +0 -470
- package/slicejs-cli/tests/bundling-dependency-edges.test.js +0 -127
- package/slicejs-cli/tests/bundling-imports-unit.test.js +0 -267
- package/slicejs-cli/tests/client-launcher-contract.test.js +0 -211
- package/slicejs-cli/tests/commands-component-crud.test.js +0 -128
- package/slicejs-cli/tests/commands-doctor.test.js +0 -152
- package/slicejs-cli/tests/commands-version-checker.test.js +0 -37
- package/slicejs-cli/tests/component-registry-parse.test.js +0 -34
- package/slicejs-cli/tests/dependency-analyzer.test.js +0 -24
- package/slicejs-cli/tests/e2e/bundles.spec.js +0 -91
- package/slicejs-cli/tests/e2e/dependency-scenarios.spec.js +0 -56
- package/slicejs-cli/tests/e2e/fixtures/components/Service/FetchManager/FetchManager.js +0 -136
- package/slicejs-cli/tests/e2e/fixtures/components/Service/IndexedDbManager/IndexedDbManager.js +0 -149
- package/slicejs-cli/tests/e2e/fixtures/components/Service/LocalStorageManager/LocalStorageManager.js +0 -45
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/Button/Button.css +0 -106
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/Button/Button.html +0 -5
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/Button/Button.js +0 -158
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/Link/Link.js +0 -33
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/Loading/Loading.css +0 -56
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/Loading/Loading.html +0 -83
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/Loading/Loading.js +0 -164
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/MultiRoute/MultiRoute.js +0 -167
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/Navbar/Navbar.css +0 -116
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/Navbar/Navbar.html +0 -44
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/Navbar/Navbar.js +0 -180
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/NotFound/NotFound.js +0 -20
- package/slicejs-cli/tests/e2e/fixtures/components/Visual/Route/Route.js +0 -181
- package/slicejs-cli/tests/e2e/fixtures/components/registry.json +0 -12
- package/slicejs-cli/tests/e2e/fixtures/vendor-components.mjs +0 -65
- package/slicejs-cli/tests/e2e/navigation.spec.js +0 -44
- package/slicejs-cli/tests/e2e/render.spec.js +0 -34
- package/slicejs-cli/tests/e2e/serve.mjs +0 -264
- package/slicejs-cli/tests/e2e/shared-deps.spec.js +0 -61
- package/slicejs-cli/tests/e2e/unminified.spec.js +0 -33
- package/slicejs-cli/tests/e2e-serve.test.js +0 -148
- package/slicejs-cli/tests/fixtures/components.js +0 -8
- package/slicejs-cli/tests/fixtures/sliceConfig.json +0 -74
- package/slicejs-cli/tests/getcomponent.test.js +0 -435
- package/slicejs-cli/tests/helpers/setup.js +0 -102
- package/slicejs-cli/tests/init-command-contract.test.js +0 -101
- package/slicejs-cli/tests/init-e2e.test.js +0 -82
- package/slicejs-cli/tests/init-project-isolation.test.js +0 -98
- package/slicejs-cli/tests/local-cli-delegation.test.js +0 -81
- package/slicejs-cli/tests/package-manager.test.js +0 -127
- package/slicejs-cli/tests/path-helper.test.js +0 -206
- package/slicejs-cli/tests/perf-budget.test.js +0 -84
- package/slicejs-cli/tests/postinstall-command.test.js +0 -103
- package/slicejs-cli/tests/property-mangling-regression.test.js +0 -182
- package/slicejs-cli/tests/types-breakage.test.js +0 -491
- package/slicejs-cli/tests/types-generator-errors.test.js +0 -361
- package/slicejs-cli/tests/types-generator.test.js +0 -348
- /package/api/{utils → framework}/publicEnvResolver.js +0 -0
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
// Warns once per deprecated prop name (kept module-scoped so each component
|
|
2
|
-
// reports a given alias only once per session).
|
|
3
|
-
const _sliceDeprecated = new Set();
|
|
4
|
-
function deprecate(oldName, newName) {
|
|
5
|
-
if (_sliceDeprecated.has(oldName)) return;
|
|
6
|
-
_sliceDeprecated.add(oldName);
|
|
7
|
-
console.warn(`[Slice] "${oldName}" is deprecated; use "${newName}" instead.`);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export default class Loading extends HTMLElement {
|
|
11
|
-
|
|
12
|
-
static props = {
|
|
13
|
-
// Canonical busy-state flag. `isActive` is kept as a deprecated alias.
|
|
14
|
-
active: {
|
|
15
|
-
type: 'boolean',
|
|
16
|
-
default: false,
|
|
17
|
-
required: false
|
|
18
|
-
},
|
|
19
|
-
isActive: {
|
|
20
|
-
type: 'boolean',
|
|
21
|
-
default: false,
|
|
22
|
-
required: false
|
|
23
|
-
},
|
|
24
|
-
container: {
|
|
25
|
-
type: 'object',
|
|
26
|
-
default: null,
|
|
27
|
-
required: false
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
constructor(props) {
|
|
32
|
-
super();
|
|
33
|
-
slice.attachTemplate(this);
|
|
34
|
-
slice.controller.setComponentProps(this, props);
|
|
35
|
-
this._container = this.container || null;
|
|
36
|
-
this._isActive = false;
|
|
37
|
-
this._currentContainer = null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
init() {}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Muestra el loading spinner
|
|
44
|
-
* @param {HTMLElement} container - Opcional. Contenedor donde mostrar el loading.
|
|
45
|
-
* Si no se proporciona, usa document.body (fullscreen)
|
|
46
|
-
*/
|
|
47
|
-
start(container = null) {
|
|
48
|
-
// Determinar el contenedor
|
|
49
|
-
const targetContainer = container || this._container || document.body;
|
|
50
|
-
|
|
51
|
-
// Si ya está activo en el mismo container, no hacer nada
|
|
52
|
-
if (this._isActive && this._currentContainer === targetContainer) {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Si está activo en otro container, primero detenerlo
|
|
57
|
-
if (this._isActive) {
|
|
58
|
-
this.stop();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Configurar estilos según el contenedor
|
|
62
|
-
if (targetContainer !== document.body) {
|
|
63
|
-
// Para contenedores específicos
|
|
64
|
-
// Guardar el position original para restaurarlo después
|
|
65
|
-
this._originalPosition = targetContainer.style.position;
|
|
66
|
-
this._originalOverflow = targetContainer.style.overflow;
|
|
67
|
-
|
|
68
|
-
// Solo cambiar si no tiene position definido o es static
|
|
69
|
-
const currentPosition = window.getComputedStyle(targetContainer).position;
|
|
70
|
-
if (currentPosition === 'static' || currentPosition === '') {
|
|
71
|
-
targetContainer.style.position = 'relative';
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Ocultar overflow para que el loading no se salga
|
|
75
|
-
targetContainer.style.overflow = 'hidden';
|
|
76
|
-
|
|
77
|
-
// Configurar el loading como absolute para que llene el container
|
|
78
|
-
this.style.position = 'absolute';
|
|
79
|
-
this.style.top = '0';
|
|
80
|
-
this.style.left = '0';
|
|
81
|
-
this.style.right = '0';
|
|
82
|
-
this.style.bottom = '0';
|
|
83
|
-
this.style.width = '100%';
|
|
84
|
-
this.style.height = '100%';
|
|
85
|
-
} else {
|
|
86
|
-
// Para document.body (fullscreen)
|
|
87
|
-
this.style.position = 'fixed';
|
|
88
|
-
this.style.top = '0';
|
|
89
|
-
this.style.left = '0';
|
|
90
|
-
this.style.right = '0';
|
|
91
|
-
this.style.bottom = '0';
|
|
92
|
-
this.style.width = '100%';
|
|
93
|
-
this.style.height = '100%';
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Append al contenedor
|
|
97
|
-
targetContainer.appendChild(this);
|
|
98
|
-
this._isActive = true;
|
|
99
|
-
this._currentContainer = targetContainer;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Oculta el loading spinner
|
|
104
|
-
*/
|
|
105
|
-
stop() {
|
|
106
|
-
if (!this._isActive) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Restaurar estilos originales del container si los modificamos
|
|
111
|
-
if (this._currentContainer &&
|
|
112
|
-
this._currentContainer !== document.body) {
|
|
113
|
-
if (this._originalPosition !== undefined) {
|
|
114
|
-
this._currentContainer.style.position = this._originalPosition;
|
|
115
|
-
}
|
|
116
|
-
if (this._originalOverflow !== undefined) {
|
|
117
|
-
this._currentContainer.style.overflow = this._originalOverflow;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Remover del DOM
|
|
122
|
-
if (this.parentNode) {
|
|
123
|
-
this.parentNode.removeChild(this);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
this._isActive = false;
|
|
127
|
-
this._currentContainer = null;
|
|
128
|
-
this._originalPosition = undefined;
|
|
129
|
-
this._originalOverflow = undefined;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Canonical busy-state flag. Toggling it shows/hides the spinner.
|
|
133
|
-
get active() {
|
|
134
|
-
return this._isActive;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
set active(value) {
|
|
138
|
-
if (value === true && !this._isActive) {
|
|
139
|
-
this.start();
|
|
140
|
-
} else if (value === false && this._isActive) {
|
|
141
|
-
this.stop();
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Deprecated alias for `active`.
|
|
146
|
-
get isActive() {
|
|
147
|
-
return this._isActive;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
set isActive(value) {
|
|
151
|
-
if (value) deprecate('isActive', 'active');
|
|
152
|
-
this.active = value;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
get container() {
|
|
156
|
-
return this._container;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
set container(value) {
|
|
160
|
-
this._container = value;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
customElements.define('slice-loading', Loading);
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
export default class MultiRoute extends HTMLElement {
|
|
2
|
-
constructor(props) {
|
|
3
|
-
super();
|
|
4
|
-
this.props = props;
|
|
5
|
-
this.renderedComponents = new Map(); // Cache para componentes renderizados
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
init() {
|
|
9
|
-
if (!this.props.routes || !Array.isArray(this.props.routes)) {
|
|
10
|
-
slice.logger.logError('MultiRoute', 'No valid routes array provided in props.');
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
// NOTE: MultiRoute does NOT register its routes in the Router. `routes.js` is the single
|
|
14
|
-
// source of truth for what the Router knows. The Router resolves the URL on first load /
|
|
15
|
-
// refresh / deep-link BEFORE this component mounts, so a path that only lived inside a
|
|
16
|
-
// MultiRoute would 404 on a direct load — incoherent. Declare every section path in
|
|
17
|
-
// `routes.js` (pointing at the shell); MultiRoute just chooses which one to show.
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Encuentra una ruta que coincida con el path actual
|
|
22
|
-
* Soporta rutas estáticas y dinámicas con parámetros ${param}
|
|
23
|
-
*/
|
|
24
|
-
matchRoute(currentPath) {
|
|
25
|
-
// Normalize trailing slash so '/about/' behaves like '/about' (keep root '/').
|
|
26
|
-
currentPath = currentPath.length > 1 ? currentPath.replace(/\/+$/, '') : currentPath;
|
|
27
|
-
|
|
28
|
-
// 1. Match exacto, case-insensitive ('/About' coincide con '/about')
|
|
29
|
-
const lowerPath = currentPath.toLowerCase();
|
|
30
|
-
const exactMatch = this.props.routes.find(
|
|
31
|
-
(route) => (route.path.length > 1 ? route.path.replace(/\/+$/, '') : route.path).toLowerCase() === lowerPath
|
|
32
|
-
);
|
|
33
|
-
if (exactMatch) {
|
|
34
|
-
return { route: exactMatch, params: {} };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// 2. Si no hay match exacto, buscar rutas dinámicas
|
|
38
|
-
for (const route of this.props.routes) {
|
|
39
|
-
if (route.path.includes('${')) {
|
|
40
|
-
const { regex, paramNames } = this.compilePathPattern(route.path);
|
|
41
|
-
const match = currentPath.match(regex);
|
|
42
|
-
|
|
43
|
-
if (match) {
|
|
44
|
-
// Extraer parámetros de la URL
|
|
45
|
-
const params = {};
|
|
46
|
-
paramNames.forEach((name, i) => {
|
|
47
|
-
params[name] = match[i + 1];
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
return { route, params };
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// 3. No se encontró ninguna ruta
|
|
56
|
-
return { route: null, params: {} };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Convierte un patrón de ruta con ${param} en una expresión regular
|
|
61
|
-
* Ejemplo: "/user/${id}" -> /^\/user\/([^/]+)$/
|
|
62
|
-
*/
|
|
63
|
-
compilePathPattern(pattern) {
|
|
64
|
-
const paramNames = [];
|
|
65
|
-
const regexPattern = '^' + pattern.replace(/\$\{([^}]+)\}/g, (_, paramName) => {
|
|
66
|
-
paramNames.push(paramName);
|
|
67
|
-
return '([^/]+)'; // Captura cualquier caracter excepto /
|
|
68
|
-
}) + '$';
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
// 'i': case-insensitive path matching. Captured param values keep their original case.
|
|
72
|
-
regex: new RegExp(regexPattern, 'i'),
|
|
73
|
-
paramNames
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async render() {
|
|
78
|
-
const currentPath = window.location.pathname;
|
|
79
|
-
const { route: routeMatch, params } = this.matchRoute(currentPath);
|
|
80
|
-
|
|
81
|
-
if (routeMatch) {
|
|
82
|
-
const { component, metadata } = routeMatch;
|
|
83
|
-
|
|
84
|
-
if (this.renderedComponents.has(component)) {
|
|
85
|
-
const cachedComponent = this.renderedComponents.get(component);
|
|
86
|
-
this.innerHTML = '';
|
|
87
|
-
|
|
88
|
-
// Actualizar props del componente cacheado
|
|
89
|
-
if (cachedComponent.props) {
|
|
90
|
-
cachedComponent.props = {
|
|
91
|
-
...cachedComponent.props,
|
|
92
|
-
params: params,
|
|
93
|
-
metadata: metadata || {} // ✅ Incluir metadata
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Si el componente en caché tiene un método update, lo ejecutamos
|
|
98
|
-
if (cachedComponent.update) {
|
|
99
|
-
await cachedComponent.update();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
this.appendChild(cachedComponent);
|
|
103
|
-
} else {
|
|
104
|
-
if (!slice.controller.componentCategories.has(component)) {
|
|
105
|
-
slice.logger.logError(`${this.sliceId}`, `Component ${component} not found`);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Crear el componente con los parámetros y metadata de la ruta
|
|
110
|
-
const newComponent = await slice.build(component, {
|
|
111
|
-
params: params,
|
|
112
|
-
metadata: metadata || {}
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
this.innerHTML = '';
|
|
116
|
-
this.appendChild(newComponent);
|
|
117
|
-
this.renderedComponents.set(component, newComponent);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Emitir evento personalizado cuando el renderizado está completo
|
|
121
|
-
this.dispatchEvent(new CustomEvent('route-rendered', {
|
|
122
|
-
bubbles: true,
|
|
123
|
-
detail: {
|
|
124
|
-
component,
|
|
125
|
-
path: currentPath,
|
|
126
|
-
params: params,
|
|
127
|
-
metadata: metadata || {} // ✅ Incluir metadata en el evento
|
|
128
|
-
}
|
|
129
|
-
}));
|
|
130
|
-
} else {
|
|
131
|
-
// Limpiamos el contenido si no hay una coincidencia de ruta
|
|
132
|
-
this.innerHTML = '';
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async renderIfCurrentRoute() {
|
|
137
|
-
const currentPath = window.location.pathname;
|
|
138
|
-
const { route: routeMatch } = this.matchRoute(currentPath);
|
|
139
|
-
|
|
140
|
-
if (routeMatch) {
|
|
141
|
-
await this.render();
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
removeComponent() {
|
|
148
|
-
const currentPath = window.location.pathname;
|
|
149
|
-
const { route: routeMatch } = this.matchRoute(currentPath);
|
|
150
|
-
|
|
151
|
-
if (routeMatch) {
|
|
152
|
-
const { component } = routeMatch;
|
|
153
|
-
this.renderedComponents.delete(component);
|
|
154
|
-
this.innerHTML = '';
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Cleanup cuando el componente se destruye
|
|
160
|
-
*/
|
|
161
|
-
destroy() {
|
|
162
|
-
this.renderedComponents.clear();
|
|
163
|
-
this.innerHTML = '';
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
customElements.define('slice-multi-route', MultiRoute);
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
.slice_nav_header {
|
|
2
|
-
font-family: var(--font-family);
|
|
3
|
-
width: 100%;
|
|
4
|
-
z-index: 1;
|
|
5
|
-
box-shadow: 0px 0px 10px #00000050;
|
|
6
|
-
background-color: var(--primary-color);
|
|
7
|
-
display: flex;
|
|
8
|
-
justify-content: space-around;
|
|
9
|
-
align-items: center;
|
|
10
|
-
}
|
|
11
|
-
.direction-row-reverse {
|
|
12
|
-
flex-direction: row-reverse;
|
|
13
|
-
}
|
|
14
|
-
.nav_bar_fixed {
|
|
15
|
-
z-index: 100;
|
|
16
|
-
width: 100%;
|
|
17
|
-
left: 0;
|
|
18
|
-
top: 0;
|
|
19
|
-
position: fixed;
|
|
20
|
-
}
|
|
21
|
-
.slice_nav_bar {
|
|
22
|
-
transition: transform 0.3s ease;
|
|
23
|
-
width: 100%;
|
|
24
|
-
justify-content: center;
|
|
25
|
-
display: flex;
|
|
26
|
-
align-items: center;
|
|
27
|
-
left: 0;
|
|
28
|
-
top: 0;
|
|
29
|
-
}
|
|
30
|
-
.nav_bar_menu {
|
|
31
|
-
width: 100%;
|
|
32
|
-
overflow-y: hidden;
|
|
33
|
-
overflow-x: auto;
|
|
34
|
-
-webkit-overflow-scrolling: touch;
|
|
35
|
-
display: flex;
|
|
36
|
-
align-items: center;
|
|
37
|
-
justify-content: center;
|
|
38
|
-
list-style: none;
|
|
39
|
-
}
|
|
40
|
-
.slice_nav_header .item {
|
|
41
|
-
cursor: pointer;
|
|
42
|
-
font-weight: bold;
|
|
43
|
-
text-decoration: none;
|
|
44
|
-
color: var(--primary-color-contrast);
|
|
45
|
-
border-radius: var(--border-radius-slice);
|
|
46
|
-
}
|
|
47
|
-
.anim-item {
|
|
48
|
-
position: absolute;
|
|
49
|
-
top: 100%;
|
|
50
|
-
left: 50%;
|
|
51
|
-
width: 0%;
|
|
52
|
-
height: 2.5px;
|
|
53
|
-
border-radius: 5px;
|
|
54
|
-
background-color: var(--primary-color-contrast);
|
|
55
|
-
transition: width 0.3s ease, left 0.3s ease;
|
|
56
|
-
}
|
|
57
|
-
.slice_nav_header li {
|
|
58
|
-
margin: 25px;
|
|
59
|
-
display: flex;
|
|
60
|
-
justify-content: center;
|
|
61
|
-
position: relative;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.slice_nav_header li:hover .anim-item {
|
|
65
|
-
width: 100%;
|
|
66
|
-
left: 0;
|
|
67
|
-
}
|
|
68
|
-
.slice_nav_header .logo_container {
|
|
69
|
-
padding: 10px;
|
|
70
|
-
}
|
|
71
|
-
.logo_container img {
|
|
72
|
-
pointer-events: none;
|
|
73
|
-
user-select: none;
|
|
74
|
-
max-height: 50px;
|
|
75
|
-
max-width: 200px;
|
|
76
|
-
}
|
|
77
|
-
.nav_bar_buttons {
|
|
78
|
-
justify-content: flex-end;
|
|
79
|
-
display: flex;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.mobile_menu_button,
|
|
83
|
-
.mobile_close_menu {
|
|
84
|
-
visibility: hidden;
|
|
85
|
-
position: absolute;
|
|
86
|
-
right: 0px;
|
|
87
|
-
margin-right: 25px;
|
|
88
|
-
}
|
|
89
|
-
.mobile_close_menu {
|
|
90
|
-
top: 25px;
|
|
91
|
-
}
|
|
92
|
-
@media only screen and (max-width: 1020px) {
|
|
93
|
-
.slice_nav_bar {
|
|
94
|
-
z-index: 1;
|
|
95
|
-
list-style: none;
|
|
96
|
-
width: 100%;
|
|
97
|
-
height: 100%;
|
|
98
|
-
position: fixed;
|
|
99
|
-
top: 0;
|
|
100
|
-
left: 0;
|
|
101
|
-
display: flex;
|
|
102
|
-
justify-content: center;
|
|
103
|
-
align-items: center;
|
|
104
|
-
flex-direction: column;
|
|
105
|
-
background-color: var(--primary-color);
|
|
106
|
-
transform: translateX(100%);
|
|
107
|
-
}
|
|
108
|
-
.nav_bar_menu,
|
|
109
|
-
.nav_bar_buttons {
|
|
110
|
-
flex-direction: column;
|
|
111
|
-
}
|
|
112
|
-
.mobile_menu_button,
|
|
113
|
-
.mobile_close_menu {
|
|
114
|
-
visibility: visible;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
<header class="slice_nav_header">
|
|
2
|
-
<a class="logo_container"></a>
|
|
3
|
-
<nav class="slice_nav_bar">
|
|
4
|
-
<div class="nav_bar_menu"></div>
|
|
5
|
-
<div class="nav_bar_buttons"></div>
|
|
6
|
-
<div class="mobile_close_menu">
|
|
7
|
-
<svg
|
|
8
|
-
class="w-6 h-6 text-gray-800 dark:text-white"
|
|
9
|
-
aria-hidden="true"
|
|
10
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
-
width="24"
|
|
12
|
-
height="24"
|
|
13
|
-
fill="none"
|
|
14
|
-
viewBox="0 0 24 24"
|
|
15
|
-
>
|
|
16
|
-
<path
|
|
17
|
-
stroke="var(--primary-color-contrast)"
|
|
18
|
-
stroke-linecap="round"
|
|
19
|
-
stroke-linejoin="round"
|
|
20
|
-
stroke-width="2"
|
|
21
|
-
d="M6 18 17.94 6M18 18 6.06 6"
|
|
22
|
-
/>
|
|
23
|
-
</svg>
|
|
24
|
-
</div>
|
|
25
|
-
</nav>
|
|
26
|
-
<div class="mobile_menu_button">
|
|
27
|
-
<svg
|
|
28
|
-
class="w-6 h-6 text-gray-800 dark:text-white"
|
|
29
|
-
aria-hidden="true"
|
|
30
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
-
width="24"
|
|
32
|
-
height="24"
|
|
33
|
-
fill="none"
|
|
34
|
-
viewBox="0 0 24 24"
|
|
35
|
-
>
|
|
36
|
-
<path
|
|
37
|
-
stroke="var(--primary-color-contrast)"
|
|
38
|
-
stroke-linecap="round"
|
|
39
|
-
stroke-width="3"
|
|
40
|
-
d="M12 6h.01M12 12h.01M12 18h.01"
|
|
41
|
-
/>
|
|
42
|
-
</svg>
|
|
43
|
-
</div>
|
|
44
|
-
</header>
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
export default class Navbar extends HTMLElement {
|
|
2
|
-
|
|
3
|
-
static props = {
|
|
4
|
-
logo: {
|
|
5
|
-
type: 'object',
|
|
6
|
-
default: null,
|
|
7
|
-
required: false
|
|
8
|
-
},
|
|
9
|
-
items: {
|
|
10
|
-
type: 'array',
|
|
11
|
-
default: [],
|
|
12
|
-
required: false
|
|
13
|
-
},
|
|
14
|
-
buttons: {
|
|
15
|
-
type: 'array',
|
|
16
|
-
default: [],
|
|
17
|
-
required: false
|
|
18
|
-
},
|
|
19
|
-
position: {
|
|
20
|
-
type: 'string',
|
|
21
|
-
default: 'static',
|
|
22
|
-
required: false
|
|
23
|
-
},
|
|
24
|
-
direction: {
|
|
25
|
-
type: 'string',
|
|
26
|
-
default: 'normal',
|
|
27
|
-
required: false
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
constructor(props) {
|
|
32
|
-
super();
|
|
33
|
-
slice.attachTemplate(this);
|
|
34
|
-
|
|
35
|
-
this.$header = this.querySelector('.slice_nav_header');
|
|
36
|
-
this.$navBar = this.querySelector('.slice_nav_bar');
|
|
37
|
-
this.$menu = this.querySelector('.nav_bar_menu');
|
|
38
|
-
this.$buttonsContainer = this.querySelector('.nav_bar_buttons');
|
|
39
|
-
this.$logoContainer = this.querySelector('.logo_container');
|
|
40
|
-
this.$mobileMenu = this.querySelector('.slice_mobile_menu');
|
|
41
|
-
this.$mobileButton = this.querySelector('.mobile_menu_button');
|
|
42
|
-
this.$closeMenu = this.querySelector('.mobile_close_menu');
|
|
43
|
-
|
|
44
|
-
this.$mobileButton.addEventListener('click', () => {
|
|
45
|
-
this.$navBar.style.transform = 'translateX(0%)';
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
this.$closeMenu.addEventListener('click', () => {
|
|
49
|
-
this.$navBar.style.transform = 'translateX(100%)';
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
slice.controller.setComponentProps(this, props);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async init() {
|
|
56
|
-
if (this.items && this.items.length > 0) {
|
|
57
|
-
await this.addItems(this.items);
|
|
58
|
-
}
|
|
59
|
-
if (this.buttons && this.buttons.length > 0) {
|
|
60
|
-
this.buttons.forEach(async (item) => {
|
|
61
|
-
await this.addButton(item, this.$buttonsContainer);
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (window.screen.width >= 1020 && this.items && this.logo && this.buttons) {
|
|
66
|
-
this.$menu.style.maxWidth = '60%';
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async addItems(items) {
|
|
71
|
-
for (let i = 0; i < items.length; i++) {
|
|
72
|
-
await this.addItem(items[i], this.$menu);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
get position() {
|
|
77
|
-
return this._position;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
set position(value) {
|
|
81
|
-
this._position = value;
|
|
82
|
-
if (value === 'fixed') {
|
|
83
|
-
this.classList.add('nav_bar_fixed');
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
get logo() {
|
|
88
|
-
return this._logo;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
set logo(value) {
|
|
92
|
-
this._logo = value;
|
|
93
|
-
// ✅ CORREGIDO: Validar que value no sea null antes de usarlo
|
|
94
|
-
if (!value) return;
|
|
95
|
-
|
|
96
|
-
const img = document.createElement('img');
|
|
97
|
-
img.src = value.src;
|
|
98
|
-
this.$logoContainer.appendChild(img);
|
|
99
|
-
this.$logoContainer.href = value.path;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
get items() {
|
|
103
|
-
return this._items;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
set items(values) {
|
|
107
|
-
this._items = values;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
get buttons() {
|
|
111
|
-
return this._buttons;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
set buttons(values) {
|
|
115
|
-
this._buttons = values;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
get direction() {
|
|
119
|
-
return this._direction;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
set direction(value) {
|
|
123
|
-
this._direction = value;
|
|
124
|
-
// ✅ MEJORADO: Validar valor antes de aplicar clase
|
|
125
|
-
if (value === 'reverse') {
|
|
126
|
-
this.$header.classList.add('direction-row-reverse');
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async addItem(value, addTo) {
|
|
131
|
-
const item = document.createElement('li');
|
|
132
|
-
const hover = document.createElement('div');
|
|
133
|
-
hover.classList.add('anim-item');
|
|
134
|
-
|
|
135
|
-
if (!value.type) {
|
|
136
|
-
value.type = 'text';
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (value.type === 'text') {
|
|
140
|
-
const link = await slice.build('Link', {
|
|
141
|
-
text: value.text,
|
|
142
|
-
path: value.path,
|
|
143
|
-
classes: 'item',
|
|
144
|
-
});
|
|
145
|
-
item.appendChild(link);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (value.type === 'dropdown') {
|
|
149
|
-
const d = await slice.build('DropDown', {
|
|
150
|
-
label: value.text,
|
|
151
|
-
options: value.options,
|
|
152
|
-
});
|
|
153
|
-
d.classList.add('item');
|
|
154
|
-
item.appendChild(d);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
item.appendChild(hover);
|
|
158
|
-
addTo.appendChild(item);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async addButton(value, addTo) {
|
|
162
|
-
if (!value.color) {
|
|
163
|
-
value.color = {
|
|
164
|
-
text: 'var(--primary-color-rgb)',
|
|
165
|
-
background: 'var(--primary-background-color)',
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const button = await slice.build('Button', {
|
|
170
|
-
value: value.value,
|
|
171
|
-
customColor: value.color,
|
|
172
|
-
icon: value.icon,
|
|
173
|
-
onClick: value.onClick ?? value.onClickCallback,
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
addTo.appendChild(button);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
window.customElements.define('slice-nav-bar', Navbar);
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export default class NotFound extends HTMLElement {
|
|
2
|
-
|
|
3
|
-
static props = {
|
|
4
|
-
// No props needed for this component
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
constructor(props) {
|
|
8
|
-
super();
|
|
9
|
-
slice.attachTemplate(this);
|
|
10
|
-
|
|
11
|
-
slice.controller.setComponentProps(this, props);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
init() {
|
|
15
|
-
//change title of the page
|
|
16
|
-
document.title = '404 - Not Found';
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
customElements.define('slice-notfound', NotFound);
|