From cf92c0f49a442e863ff3a560248c30f192e2666b Mon Sep 17 00:00:00 2001 From: lmf-git Date: Sun, 3 May 2026 14:52:50 -0300 Subject: [PATCH] More content translations broken --- .gitignore | 2 + app/About/About.html | 58 -- app/About/About.js | 14 - app/Company/Company.html | 105 +++ app/Company/Company.js | 17 + app/Contact/Contact.html | 164 +--- app/Contact/Contact.js | 78 +- app/Dashboard/Dashboard.html | 379 -------- app/Dashboard/Dashboard.js | 42 - app/Fleet/Fleet.html | 71 ++ app/Fleet/Fleet.js | 17 + app/Home/Home.html | 813 ++++++++++++++++-- app/Home/Home.js | 23 + app/Login/Login.html | 206 ----- app/Login/Login.js | 49 -- app/NotFound/NotFound.html | 22 - app/NotFound/NotFound.js | 8 - app/Products/Products.html | 70 ++ app/Products/Products.js | 17 + app/Sustainability/Sustainability.html | 53 ++ app/Sustainability/Sustainability.js | 17 + app/Users/[id]/User.html | 36 - app/Users/[id]/User.js | 13 - app/_Layout/_Layout.html | 37 +- app/_Layout/_Layout.js | 4 - changelog/optimisations-1.txt | 23 - components/About/About.html | 107 +++ components/About/About.js | 8 + components/Counter/Counter.html | 34 - components/Counter/Counter.js | 13 - components/Fleet/Fleet.html | 119 +++ components/Fleet/Fleet.js | 17 + components/Footer/Footer.html | 144 ++++ components/Footer/Footer.js | 8 + components/Hero/Hero.html | 143 +++ components/Hero/Hero.js | 8 + .../LocalStateDisplay/LocalStateDisplay.html | 55 -- .../LocalStateDisplay/LocalStateDisplay.js | 44 - components/Logo/Logo.html | 21 + components/Logo/Logo.js | 7 + components/Navigation/Navigation.html | 165 ++-- components/Navigation/Navigation.js | 20 +- components/ThemeToggle/ThemeToggle.html | 39 - components/ThemeToggle/ThemeToggle.js | 12 - components/Values/Values.html | 73 ++ components/Values/Values.js | 8 + globals.css | 177 ++-- index.html | 4 +- lib/store.js | 18 +- 49 files changed, 2046 insertions(+), 1536 deletions(-) delete mode 100644 app/About/About.html delete mode 100644 app/About/About.js create mode 100644 app/Company/Company.html create mode 100644 app/Company/Company.js delete mode 100644 app/Dashboard/Dashboard.html delete mode 100644 app/Dashboard/Dashboard.js create mode 100644 app/Fleet/Fleet.html create mode 100644 app/Fleet/Fleet.js create mode 100644 app/Home/Home.js delete mode 100644 app/Login/Login.html delete mode 100644 app/Login/Login.js delete mode 100644 app/NotFound/NotFound.html delete mode 100644 app/NotFound/NotFound.js create mode 100644 app/Products/Products.html create mode 100644 app/Products/Products.js create mode 100644 app/Sustainability/Sustainability.html create mode 100644 app/Sustainability/Sustainability.js delete mode 100644 app/Users/[id]/User.html delete mode 100644 app/Users/[id]/User.js delete mode 100644 changelog/optimisations-1.txt create mode 100644 components/About/About.html create mode 100644 components/About/About.js delete mode 100644 components/Counter/Counter.html delete mode 100644 components/Counter/Counter.js create mode 100644 components/Fleet/Fleet.html create mode 100644 components/Fleet/Fleet.js create mode 100644 components/Footer/Footer.html create mode 100644 components/Footer/Footer.js create mode 100644 components/Hero/Hero.html create mode 100644 components/Hero/Hero.js delete mode 100644 components/LocalStateDisplay/LocalStateDisplay.html delete mode 100644 components/LocalStateDisplay/LocalStateDisplay.js create mode 100644 components/Logo/Logo.html create mode 100644 components/Logo/Logo.js delete mode 100644 components/ThemeToggle/ThemeToggle.html delete mode 100644 components/ThemeToggle/ThemeToggle.js create mode 100644 components/Values/Values.html create mode 100644 components/Values/Values.js diff --git a/.gitignore b/.gitignore index ac96833..7212962 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ node_modules/ .yarn/ .claude/ +reference/ +.DS_Store dist/ diff --git a/app/About/About.html b/app/About/About.html deleted file mode 100644 index 22381cb..0000000 --- a/app/About/About.html +++ /dev/null @@ -1,58 +0,0 @@ - -
-

{{title}}

-

This is the about page of our application using vanilla web components and client-side routing.

-

This component demonstrates scoped styles using Shadow DOM with a highlighted example.

- -
-

Global State Access

-

The counter value persists across pages:

- -

Current counter: {{counter}}

-

Counter doubled: {{counter * 2}}

-

Last visited path: {{lastRoute || 'None'}}

-
- - - -

Page rendered at: {{timestamp}}

-
diff --git a/app/About/About.js b/app/About/About.js deleted file mode 100644 index 29208fc..0000000 --- a/app/About/About.js +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, define } from '../../core/component.js'; - -export default class AboutPage extends Component { - static templateUrl = '/app/About/About.html'; - static store = ['counter']; - static metadata = { title: 'About', description: 'Learn more about our application.' }; - static ssrProps = { title: 'About Us' }; - - get props() { - return { ...super.props, title: 'About Us', timestamp: new Date().toLocaleString() }; - } -} - -define('about-page', AboutPage); diff --git a/app/Company/Company.html b/app/Company/Company.html new file mode 100644 index 0000000..734dff7 --- /dev/null +++ b/app/Company/Company.html @@ -0,0 +1,105 @@ + + + + +
+
+
+
+

{{lang === 'es' ? 'Pasión por el mar y compromiso con el futuro' : 'Passion for the sea and commitment to the future'}}

+
+ {{#if lang === 'es'}} +

Estremar es una empresa pesquera líder en Argentina, dedicada a la captura y procesamiento de productos del mar de alta calidad. Con base en Ushuaia, operamos en las frías y ricas aguas del Atlántico Sur.

+ {{else}} +

Estremar is a leading fishing company in Argentina, dedicated to the capture and processing of high-quality seafood products. Based in Ushuaia, we operate in the cold and rich waters of the South Atlantic.

+ {{/if}} +
+
+
+
+ +
+
+
{{lang === 'es' ? 'Sustentabilidad' : 'Sustainability'}}
+ {{#if lang === 'es'}} +

Protegemos los recursos marinos para las generaciones futuras.

+ {{else}} +

We protect marine resources for future generations.

+ {{/if}} +
+
+
{{lang === 'es' ? 'Calidad' : 'Quality'}}
+ {{#if lang === 'es'}} +

Mantenemos los más altos estándares en cada etapa.

+ {{else}} +

We maintain the highest standards at every stage.

+ {{/if}} +
+
+
{{lang === 'es' ? 'Nuestra Gente' : 'Our People'}}
+ {{#if lang === 'es'}} +

Valoramos el esfuerzo de nuestro equipo y su seguridad.

+ {{else}} +

We value our team's effort and their safety.

+ {{/if}} +
+
+
+
diff --git a/app/Company/Company.js b/app/Company/Company.js new file mode 100644 index 0000000..8ef787b --- /dev/null +++ b/app/Company/Company.js @@ -0,0 +1,17 @@ +import { Component, define } from '../../core/component.js'; + +export default class Company extends Component { + static templateUrl = '/app/Company/Company.html'; + static store = ['lang']; + + mount() { + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) entry.target.classList.add('visible'); + }); + }, { threshold: 0.12 }); + this.$$('.fade-up').forEach(el => observer.observe(el)); + } +} + +define('company-page', Company); diff --git a/app/Contact/Contact.html b/app/Contact/Contact.html index 11fee42..d0aef8e 100644 --- a/app/Contact/Contact.html +++ b/app/Contact/Contact.html @@ -1,138 +1,40 @@ -
-

{{title}}

-

Get in touch with us using the form below.

- -
- -
- - - -
-
- - - -
-
- - - -
- + + + +
+
+
+
+

{{lang === 'es' ? 'Contacto' : 'Contact'}}

+

info@estremar.com

+
+
+

{{lang === 'es' ? 'Formulario de contacto aquí.' : 'Contact form here.'}}

+
+
- -

Page rendered at: {{timestamp}}

diff --git a/app/Contact/Contact.js b/app/Contact/Contact.js index 23008d7..b48057c 100644 --- a/app/Contact/Contact.js +++ b/app/Contact/Contact.js @@ -1,73 +1,17 @@ import { Component, define } from '../../core/component.js'; -import { validateAll } from '../../lib/validate.js'; -const schema = { - name: { required: true, min: 2 }, - email: { required: true, email: true }, - message: { required: true, min: 10 } -}; - -export default class ContactPage extends Component { +export default class Contact extends Component { static templateUrl = '/app/Contact/Contact.html'; - static store = ['counter']; - static metadata = { title: 'Contact', description: 'Get in touch with us.' }; - static local = { errors: {}, isLoading: false, sent: false }; - // local values auto-included in SSR; only need non-local values here - static ssrProps = { title: 'Contact Us' }; - static reactive = false; // Don't auto-update, we'll handle it manually - - get props() { - const { errors, isLoading, sent } = this.local; - return { ...super.props, title: 'Contact Us', timestamp: new Date().toLocaleString(), isLoading, sent, errors }; - } - - bind() { - this.on('button', 'click', () => this.submit()); - } - - showErrors(errors) { - // Update error messages and styles without full re-render - ['name', 'email', 'message'].forEach(field => { - const input = this.$(`#${field}`); - const errorEl = this.$(`.error-${field}`); - if (input) input.classList.toggle('input-error', !!errors[field]); - if (errorEl) { - errorEl.textContent = errors[field] || ''; - errorEl.style.display = errors[field] ? 'block' : 'none'; - } - }); - } - - async submit() { - const data = { - name: this.$('#name')?.value || '', - email: this.$('#email')?.value || '', - message: this.$('#message')?.value || '' - }; - - const { valid, errors } = validateAll(data, schema); - this.showErrors(errors); - if (!valid) return; - - // Show loading state - const btn = this.$('button'); - btn.disabled = true; - btn.textContent = 'Sending...'; - - await new Promise(r => setTimeout(r, 800)); - - // Show success and clear form - this.$('#name').value = ''; - this.$('#email').value = ''; - this.$('#message').value = ''; - this.showErrors({}); - btn.disabled = false; - btn.textContent = 'Send Message'; - - // Show success message - const successEl = this.$('.success-message'); - if (successEl) successEl.style.display = 'block'; + static store = ['lang']; + + mount() { + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) entry.target.classList.add('visible'); + }); + }, { threshold: 0.12 }); + this.$$('.fade-up').forEach(el => observer.observe(el)); } } -define('contact-page', ContactPage); +define('contact-page', Contact); diff --git a/app/Dashboard/Dashboard.html b/app/Dashboard/Dashboard.html deleted file mode 100644 index 6782e70..0000000 --- a/app/Dashboard/Dashboard.html +++ /dev/null @@ -1,379 +0,0 @@ - - -
-

🛡️ Protected Dashboard

-

This is a protected page that requires authentication. You can only see this content because you're logged in!

- -
- {{user.username}} -
-

Welcome back, {{user.username}}!

-

Email: {{user.email}}

-

Role: {{user.role}}

-

User ID: {{user.id}}

-
-
- -
-

🔒 Secret Information

-

This content is only visible to authenticated users. Your session is secure and persistent across page refreshes.

-
- -
-
-
42
-
Projects
-
-
-
1,337
-
Points
-
-
-
{{user.role === 'admin' ? '∞' : '5'}}
-
Access Level
-
-
- - {{#if user.role === 'admin'}} -
-

👑 Admin Features

-

You have administrator privileges. Special admin-only content and features are available to you.

-
- {{/if}} - - -
-

📝 My Tasks

-

A reactive todo list with local component state management

- - -
- - -
- - -
- - - - -
- - -
- {{#if filteredTodos.length}} - {{#each filteredTodos}} -
-
- - {{text}} - {{priority}} -
- -
- {{/each}} - {{else}} -
- {{#if filterMessage}}{{filterMessage}}{{else}}No todos yet!{{/if}} -
- {{/if}} -
- - -
- Total: {{todoCount}} - Active: {{activeCount}} - Completed: {{completedCount}} -
-
- -

- Try logging out and visiting this page again - you'll be redirected to login! -

-
\ No newline at end of file diff --git a/app/Dashboard/Dashboard.js b/app/Dashboard/Dashboard.js deleted file mode 100644 index a64bdea..0000000 --- a/app/Dashboard/Dashboard.js +++ /dev/null @@ -1,42 +0,0 @@ -import { Component, define } from '../../core/component.js'; - -export default class DashboardPage extends Component { - static templateUrl = '/app/Dashboard/Dashboard.html'; - static store = ['user', 'isAuthenticated']; - static requiresAuth = true; - static metadata = { title: 'Dashboard', description: 'Protected dashboard area' }; - static local = { - todos: [ - { id: 1, text: 'Review quarterly reports', completed: false, priority: 'high' }, - { id: 2, text: 'Update user documentation', completed: true, priority: 'medium' }, - { id: 3, text: 'Optimize database queries', completed: false, priority: 'high' }, - { id: 4, text: 'Plan team meeting agenda', completed: false, priority: 'low' } - ], - filter: 'all', nextId: 5 - }; - - get props() { - const { todos, filter } = this.local; - const filtered = filter === 'all' ? todos : todos.filter(t => filter === 'completed' ? t.completed : !t.completed); - const completed = todos.filter(t => t.completed).length; - return { ...super.props, filteredTodos: filtered, filter, filterMessage: filtered.length ? null : `No ${filter} todos`, todoCount: todos.length, activeCount: todos.length - completed, completedCount: completed }; - } - - bind() { - this.on('#add-todo', 'click', () => this.addTodo()); - this.on('#new-todo-input', 'keypress', e => e.key === 'Enter' && this.addTodo()); - this.on('#clear-completed', 'click', () => this.local.todos = this.local.todos.filter(t => !t.completed)); - this.delegate('click', '[data-filter]', el => this.local.filter = el.dataset.filter); - this.delegate('click', '.todo-delete', el => this.local.todos = this.local.todos.filter(t => t.id !== +el.dataset.todoId)); - this.delegate('change', '.todo-checkbox', el => this.local.todos = this.local.todos.map(t => t.id === +el.dataset.todoId ? { ...t, completed: !t.completed } : t)); - } - - addTodo() { - const input = this.$('#new-todo-input'), text = input?.value.trim(); - if (!text) return; - this.local.todos = [...this.local.todos, { id: this.local.nextId++, text, completed: false, priority: 'medium' }]; - input.value = ''; - } -} - -define('dashboard-page', DashboardPage); diff --git a/app/Fleet/Fleet.html b/app/Fleet/Fleet.html new file mode 100644 index 0000000..a136f46 --- /dev/null +++ b/app/Fleet/Fleet.html @@ -0,0 +1,71 @@ + + + + +
+
+
+
+
{{lang === 'es' ? 'Buques Palangreros' : 'Longline Vessels'}}
+ {{#if lang === 'es'}} +

Técnica selectiva y sustentable para la captura de Merluza Negra.

+ {{else}} +

Selective and sustainable technique for Patagonian Toothfish capture.

+ {{/if}} +
+
+
{{lang === 'es' ? 'Buques Pelágicos' : 'Pelagic Vessels'}}
+ {{#if lang === 'es'}} +

Flota dirigida a pesquerías bien gestionadas de la plataforma continental.

+ {{else}} +

Fleet targeting well-managed fisheries of the continental shelf.

+ {{/if}} +
+
+
{{lang === 'es' ? 'Planta a bordo' : 'Onboard Plant'}}
+ {{#if lang === 'es'}} +

Procesamiento inmediato para garantizar máxima frescura.

+ {{else}} +

Immediate processing to guarantee maximum freshness.

+ {{/if}} +
+
+
+
diff --git a/app/Fleet/Fleet.js b/app/Fleet/Fleet.js new file mode 100644 index 0000000..4f0e1d7 --- /dev/null +++ b/app/Fleet/Fleet.js @@ -0,0 +1,17 @@ +import { Component, define } from '../../core/component.js'; + +export default class Fleet extends Component { + static templateUrl = '/app/Fleet/Fleet.html'; + static store = ['lang']; + + mount() { + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) entry.target.classList.add('visible'); + }); + }, { threshold: 0.12 }); + this.$$('.fade-up').forEach(el => observer.observe(el)); + } +} + +define('fleet-page', Fleet); diff --git a/app/Home/Home.html b/app/Home/Home.html index 4f8ca8e..255e57c 100644 --- a/app/Home/Home.html +++ b/app/Home/Home.html @@ -1,116 +1,739 @@ -
-

{{title}}

-

Welcome to the home page of our web component application!

-
- -
-

Local State Demo

-

This state is local to this component only:

-
- - {{localCount}} - +
+
+
+
+
-

- -

-

You typed: {{message}}

-
- -
-

Prop Passing Demo

-

This child component receives props from the parent's local state:

- -
- -
-

Global State Demo

-

This counter is shared across all components:

- -

Current counter value: {{counter}}

-
- -
-

Auth Context Demo

-
- {{#if isAuthenticated}} -

Logged in as: {{user.username}}

-

Email: {{user.email}} | Role: {{user.role}}

- Avatar -
- - {{else}} -

Not logged in

- - - {{/if}} + +
+
+
+ {{#if lang === 'es'}} PESCA ARGENTINA · DESDE 1992 {{else}} ARGENTINE FISHING · SINCE 1992 {{/if}} +
+

+ {{#if lang === 'es'}} Proveedor líder de Merluza Negra del mar austral {{else}} Leading provider of Patagonian Toothfish from the southern sea {{/if}} +

+

+ {{#if lang === 'es'}} + Operamos desde Ushuaia, el puerto más austral del mundo, pescando con responsabilidad en las aguas de la Plataforma Continental Argentina. + {{else}} + We operate from Ushuaia, the world's southernmost port, fishing responsibly in the waters of the Argentine Continental Shelf. + {{/if}} +

+ +
-

Authentication state persists across page refreshes!

-
-
-

You are currently on the path: {{path}}

-

Navigate to: About Page | Contact Page

-
+
+
+ 30+ + {{#if lang === 'es'}} AÑOS DE OPERACIÓN {{else}} YEARS OF OPERATION {{/if}} +
+
+ MSC + {{#if lang === 'es'}} CERTIFICADO DESDE 2012 {{else}} CERTIFIED SINCE 2012 {{/if}} +
+
+ #1 + {{#if lang === 'es'}} MERLUZA NEGRA ARGENTINA {{else}} ARGENTINE TOOTHFISH #1 {{/if}} +
+
+
-

Page rendered at: {{timestamp}}

+ +
+
+
+
+ +

+ {{#if lang === 'es'}} Una compañía pesquera Argentina líder {{else}} A leading Argentine fishing company {{/if}} +

+
+ {{#if lang === 'es'}} +

Estremar es una de las más grandes compañías pesqueras en Argentina. Somos proveedores líderes de Merluza Negra y nuestros productos de mar se sirven en los platos de los mercados más importantes del mundo.

+

Mejoramos continuamente nuestras operaciones e invertimos en procesos de producción innovadores. Hemos operado en el puerto más austral, Ushuaia, desde 1992, y siempre nos hemos enorgullecido de emplear a las personas correctas.

+ {{else}} +

Estremar is one of the largest fishing companies in Argentina. We are leading providers of Patagonian Toothfish and our seafood products are served on the plates of the world's most important markets.

+

We continuously improve our operations and invest in innovative production processes. We have operated in the southernmost port, Ushuaia, since 1992, and have always taken pride in employing the right people.

+ {{/if}} +
+ + {{#if lang === 'es'}} Mensaje del Presidente {{else}} President's Message {{/if}} + +
+
+
1992
+
+
- +
+
+
+
{{#if lang === 'es'}} FORMATO {{else}} FORMAT {{/if}}
+
{{#if lang === 'es'}} Filetes y porciones {{else}} Fillets and portions {{/if}}
+

{{#if lang === 'es'}} Procesado a bordo y en planta, congelado a –40°C para máxima frescura. {{else}} Processed onboard and at the plant, frozen at -40°C for maximum freshness. {{/if}}

+
+
+
{{#if lang === 'es'}} DESTINOS {{else}} DESTINATIONS {{/if}}
+
{{#if lang === 'es'}} Mercados globales {{else}} Global markets {{/if}}
+

{{#if lang === 'es'}} Japón, Estados Unidos, Europa, China y los principales mercados gastronómicos del mundo. {{else}} Japan, United States, Europe, China, and the world's major gastronomic markets. {{/if}}

+
+
+
+
+ +
+ + +
+
+
+
+ +

+ {{#if lang === 'es'}} Comprometidos con el futuro del mar {{else}} Committed to the future of the sea {{/if}} +

+

+ {{#if lang === 'es'}} La sustentabilidad es la base de nuestras operaciones. La existencia de productos de mar silvestres constituye la base de nuestra compañía y la forma de vida de muchas personas. {{else}} Sustainability is the foundation of our operations. The existence of wild seafood products forms the base of our company and the way of life for many people. {{/if}} +

+
+
+
MSC
+
+
Marine Stewardship Council
+
{{#if lang === 'es'}} Merluza de Cola certificada desde 2012. Primera en Sudamérica. {{else}} Grenadier certified since 2012. First in South America. {{/if}}
+
+
+
+
COL
+
+
COLTO Member
+
{{#if lang === 'es'}} Coalición de Operadores Legales de Merluza Negra {{else}} Coalition of Legal Toothfish Operators {{/if}}
+
+
+
+
INI
+
+
INIDEP
+
{{#if lang === 'es'}} Apoyo al Instituto Nacional de Investigación y Desarrollo Pesquero {{else}} Supporting the National Institute of Fishery Research and Development {{/if}}
+
+
+
+
+ +
+
+ 01 +
+
{{#if lang === 'es'}} Certificación MSC {{else}} MSC Certification {{/if}}
+

{{#if lang === 'es'}} Estremar ha promovido activamente la certificación de las pesquerías argentinas bajo los principios del Consejo de Administración Marina, el estándar de oro mundial para la pesca sustentable. {{else}} Estremar has actively promoted the certification of Argentine fisheries under the Marine Stewardship Council principles, the global gold standard for sustainable fishing. {{/if}}

+
+
+
+ 02 +
+
{{#if lang === 'es'}} Lucha contra la pesca ilegal {{else}} Fighting illegal fishing {{/if}}
+

{{#if lang === 'es'}} Como miembro de COLTO, trabajamos activamente para eliminar la pesca ilegal, no declarada y no reglamentada de Merluza Negra, protegiendo el recurso para las generaciones futuras. {{else}} As a member of COLTO, we work actively to eliminate illegal, unreported, and unregulated fishing of Patagonian Toothfish, protecting the resource for future generations. {{/if}}

+
+
+
+ 03 +
+
{{#if lang === 'es'}} Protección de la fauna marina {{else}} Marine wildlife protection {{/if}}
+

{{#if lang === 'es'}} Colaboramos con Aves Argentinas para reducir la interacción de aves con la pesca. Instructores del grupo Albatros se embarcan en nuestros viajes para reunir datos y minimizar el impacto. {{else}} We collaborate with Aves Argentinas to reduce the interaction of birds with fishing. Albatross group instructors embark on our trips to gather data and minimize impact. {{/if}}

+
+
+
+ 04 +
+
{{#if lang === 'es'}} Investigación científica {{else}} Scientific research {{/if}}
+

{{#if lang === 'es'}} Apoyamos el trabajo del INIDEP, que trabaja bajo rigurosos procedimientos científicos para lograr un manejo sustentable del stock comercial de peces en Argentina. {{else}} We support the work of INIDEP, which operates under rigorous scientific procedures to achieve sustainable management of the commercial fish stock in Argentina. {{/if}}

+
+
+
+
+
+
+ + +
+
+
+
+ +

{{#if lang === 'es'}} Hablemos sobre nuestros productos {{else}} Let's talk about our products {{/if}}

+

{{#if lang === 'es'}} Estamos siempre disponibles para responder sus consultas sobre nuestros productos, certificaciones y condiciones de venta. {{else}} We are always available to answer your inquiries about our products, certifications, and terms of sale. {{/if}}

+ +
+
EMAIL
infoc@estremar.com
+
{{#if lang === 'es'}} TELÉFONO {{else}} PHONE {{/if}}
+54 11 5032-4971
+
{{#if lang === 'es'}} DIRECCIÓN {{else}} ADDRESS {{/if}}
Ushuaia, Tierra del Fuego, Argentina
+
+
+ +
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+
diff --git a/app/Home/Home.js b/app/Home/Home.js new file mode 100644 index 0000000..0d52dbc --- /dev/null +++ b/app/Home/Home.js @@ -0,0 +1,23 @@ +import { Component, define } from '../../core/component.js'; + +export default class Home extends Component { + static templateUrl = '../../app/Home/Home.html'; + static store = ['lang']; // Subscribe to lang for dynamic text + + mount() { + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + } + }); + }, { threshold: 0.12 }); + + // Find elements with 'fade-up' class within the component's shadow DOM. + // This ensures animations are applied to elements within the component itself, + // rather than relying on global selectors that might not work as expected with Shadow DOM. + this.$$('.fade-up').forEach(el => observer.observe(el)); + } +} + +define('home-page', Home); diff --git a/app/Login/Login.html b/app/Login/Login.html deleted file mode 100644 index 621a334..0000000 --- a/app/Login/Login.html +++ /dev/null @@ -1,206 +0,0 @@ - - -
- {{#if redirectFrom}} -
- 🛡️ Login Required - Redirected from {{redirectFrom}}. Please login. -
- {{/if}} - -

- 🔐 - Login -

- -

- Enter your credentials or use quick login to access protected areas -

- - - -

- This is a demo - any credentials will work! -

-
diff --git a/app/Login/Login.js b/app/Login/Login.js deleted file mode 100644 index 8ba264f..0000000 --- a/app/Login/Login.js +++ /dev/null @@ -1,49 +0,0 @@ -import { Component, store, navigate, define } from '../../core/component.js'; -import { validateAll } from '../../lib/validate.js'; -import { getQueryParam } from '../../lib/nav.js'; - -const schema = { username: { min: 2 }, email: { email: true } }; - -export default class LoginPage extends Component { - static templateUrl = '/app/Login/Login.html'; - static metadata = { title: 'Login', description: 'Login to access your dashboard.' }; - static local = { username: '', email: '', isLoading: false, errors: {}, attempts: 0 }; - // local values auto-included in SSR; only need computed defaults here - static ssrProps = { hasErrors: false, errorMessages: [], canSubmit: false }; - - get props() { - const { username, errors, isLoading, attempts } = this.local; - const errorMessages = Object.values(errors); - const redirectFrom = this.pageProps?.query?.from || getQueryParam('from'); - return { ...super.props, isLoading, attempts, hasErrors: errorMessages.length > 0, errorMessages, canSubmit: username.length > 0 && !errorMessages.length, redirectFrom }; - } - - bind() { - // Combined handler: update value + validate in one render cycle - this.on('#username', 'input', e => this.updateField('username', e.target.value)); - this.on('#email', 'input', e => this.updateField('email', e.target.value)); - this.on('#custom-login', 'click', () => this.login({ username: this.local.username, email: this.local.email })); - this.on('#quick-login', 'click', () => this.login()); - this.on('#clear-form', 'click', () => this.batch(() => Object.assign(this.local, { username: '', email: '', errors: {}, attempts: 0 }))); - } - - updateField(field, value) { - // Batch updates to trigger only one re-render - this.batch(() => { - this.local[field] = value; - const { errors } = validateAll(this.local, schema); - this.local.errors = errors; - }); - } - - async login(creds = {}) { - this.local.attempts++; - await this.withLoading(async () => { - await new Promise(r => setTimeout(r, 600)); - store.login(creds); - navigate(this.props.redirectFrom || '/dashboard'); - }); - } -} - -define('login-page', LoginPage); diff --git a/app/NotFound/NotFound.html b/app/NotFound/NotFound.html deleted file mode 100644 index 5030183..0000000 --- a/app/NotFound/NotFound.html +++ /dev/null @@ -1,22 +0,0 @@ - -
-

404

-

Oops! The page you're looking for could not be found.

- Go back to Home -
diff --git a/app/NotFound/NotFound.js b/app/NotFound/NotFound.js deleted file mode 100644 index 94d09aa..0000000 --- a/app/NotFound/NotFound.js +++ /dev/null @@ -1,8 +0,0 @@ -import { Component, define } from '../../core/component.js'; - -export default class NotFoundPage extends Component { - static templateUrl = '/app/NotFound/NotFound.html'; - static metadata = { title: '404 - Not Found', description: 'Page not found.' }; -} - -define('notfound-page', NotFoundPage); diff --git a/app/Products/Products.html b/app/Products/Products.html new file mode 100644 index 0000000..2b316ad --- /dev/null +++ b/app/Products/Products.html @@ -0,0 +1,70 @@ + + + + +
+
+
+
+
{{lang === 'es' ? 'Merluza Negra' : 'Patagonian Toothfish'}}
+ {{#if lang === 'es'}} +

Uno de los pescados más preciados del mundo.

+ {{else}} +

One of the most prized fish in the world.

+ {{/if}} +
+
+
{{lang === 'es' ? 'Merluza de Cola' : 'Grenadier'}}
+ {{#if lang === 'es'}} +

Primera pesquería en Sudamérica en obtener la certificación MSC.

+ {{else}} +

First fishery in South America to obtain MSC certification.

+ {{/if}} +
+
+
{{lang === 'es' ? 'Calamar' : 'Squid'}}
+ {{#if lang === 'es'}} +

Capturado en las ricas aguas de la Patagonia.

+ {{else}} +

Caught in the rich Patagonian waters.

+ {{/if}} +
+
+
+
diff --git a/app/Products/Products.js b/app/Products/Products.js new file mode 100644 index 0000000..0286736 --- /dev/null +++ b/app/Products/Products.js @@ -0,0 +1,17 @@ +import { Component, define } from '../../core/component.js'; + +export default class Products extends Component { + static templateUrl = '/app/Products/Products.html'; + static store = ['lang']; + + mount() { + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) entry.target.classList.add('visible'); + }); + }, { threshold: 0.12 }); + this.$$('.fade-up').forEach(el => observer.observe(el)); + } +} + +define('products-page', Products); diff --git a/app/Sustainability/Sustainability.html b/app/Sustainability/Sustainability.html new file mode 100644 index 0000000..6a9de0f --- /dev/null +++ b/app/Sustainability/Sustainability.html @@ -0,0 +1,53 @@ + + + + +
+
+
+
+ 01 +
+

{{lang === 'es' ? 'Certificación MSC' : 'MSC Certification'}}

+ {{#if lang === 'es'}} +

Promovemos activamente la certificación de las pesquerías argentinas.

+ {{else}} +

We actively promote the certification of Argentine fisheries.

+ {{/if}} +
+
+
+ 02 +
+

{{lang === 'es' ? 'Lucha contra la pesca ilegal' : 'Fighting illegal fishing'}}

+ {{#if lang === 'es'}} +

Como miembro de COLTO, trabajamos para eliminar la pesca ilegal.

+ {{else}} +

As a COLTO member, we work to eliminate illegal fishing.

+ {{/if}} +
+
+
+
+
diff --git a/app/Sustainability/Sustainability.js b/app/Sustainability/Sustainability.js new file mode 100644 index 0000000..3f2f86a --- /dev/null +++ b/app/Sustainability/Sustainability.js @@ -0,0 +1,17 @@ +import { Component, define } from '../../core/component.js'; + +export default class Sustainability extends Component { + static templateUrl = '/app/Sustainability/Sustainability.html'; + static store = ['lang']; + + mount() { + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) entry.target.classList.add('visible'); + }); + }, { threshold: 0.12 }); + this.$$('.fade-up').forEach(el => observer.observe(el)); + } +} + +define('sustainability-page', Sustainability); diff --git a/app/Users/[id]/User.html b/app/Users/[id]/User.html deleted file mode 100644 index ac0618f..0000000 --- a/app/Users/[id]/User.html +++ /dev/null @@ -1,36 +0,0 @@ - -
-

User Profile

- -

This is a dynamic route example, where the ID is extracted from the URL.

-

- Go back to Home -

-
diff --git a/app/Users/[id]/User.js b/app/Users/[id]/User.js deleted file mode 100644 index a2a41fc..0000000 --- a/app/Users/[id]/User.js +++ /dev/null @@ -1,13 +0,0 @@ -import { Component, define } from '../../../core/component.js'; - -export default class UserPage extends Component { - static templateUrl = '/app/Users/[id]/User.html'; - static store = ['user', 'isAuthenticated']; - - mount() { - const id = this.pageProps?.params?.id || 'Unknown'; - this.setMeta({ title: `User ${id}`, description: `Profile for user ${id}.` }); - } -} - -define('user-page', UserPage); diff --git a/app/_Layout/_Layout.html b/app/_Layout/_Layout.html index 1fac284..350e30c 100644 --- a/app/_Layout/_Layout.html +++ b/app/_Layout/_Layout.html @@ -1,38 +1,7 @@ - -
-
- -
- +
+
- -
-

© {{year}} Web Components App

-
+
diff --git a/app/_Layout/_Layout.js b/app/_Layout/_Layout.js index 74e51c3..b63a714 100644 --- a/app/_Layout/_Layout.js +++ b/app/_Layout/_Layout.js @@ -2,10 +2,6 @@ import { Component, define } from '../../core/component.js'; export default class Layout extends Component { static templateUrl = '/app/_Layout/_Layout.html'; - - get props() { - return { ...super.props, year: new Date().getFullYear() }; - } } define('app-layout', Layout); diff --git a/changelog/optimisations-1.txt b/changelog/optimisations-1.txt deleted file mode 100644 index aaa7e78..0000000 --- a/changelog/optimisations-1.txt +++ /dev/null @@ -1,23 +0,0 @@ - 1. Eliminated Render-Blocking CSS - - Inlining: globals.css is now inlined directly into the of the HTML template during both development (SSR) and - the build process. This eliminates a network request and saves the ~150-300ms delay for the initial paint. - - Template Update: Added an placeholder in index.html to facilitate this injection. - - 2. Optimized Network Dependency Tree - - Parallel Loading: Introduced modulepreload links for all critical-path JavaScript files (entry-client.js, loader.js, - store.js, etc.) and the routes.json file. - - Latency Reduction: By preloading these assets, I've flattened the deep serial import chain (where the browser had to - download one file to discover the next), allowing them to be fetched in parallel. This significantly reduces the - 1,418ms critical path latency. - - 3. Resolved Forced Reflows & DOM Bottlenecks - - Efficient Scanning: Refactored the core/loader.js scanning logic. The previous recursive implementation using - querySelectorAll('*') was causing exponential DOM traversals ($O(N^2)$). I replaced it with a linear TreeWalker scan, - which is substantially faster and avoids layout-triggering churn. - - Removed Staging Element: Eliminated the temporary staging div in Router.js. Appending and removing elements from - document.body on every navigation was a primary source of layout invalidation. - - Modern Hydration Wait: Updated Router.js and entry-client.js to use customElements.whenDefined() instead of polling - the DOM with querySelectorAll. This is more efficient and provides a smoother hydration experience. - - Stable Scroll Restoration: Removed the behavior: 'smooth' option from the scroll restoration logic. Smooth scrolling - during the hydration phase can trigger unnecessary layout calculations and animations that delay the page's "ready" - state. \ No newline at end of file diff --git a/components/About/About.html b/components/About/About.html new file mode 100644 index 0000000..acff61d --- /dev/null +++ b/components/About/About.html @@ -0,0 +1,107 @@ + + +
+
+
+ +

+ {{#if lang === 'es'}} Una compañía pesquera Argentina líder {{else}} A leading Argentine fishing company {{/if}} +

+
+ {{#if lang === 'es'}} +

Estremar es una de las más grandes compañías pesqueras en Argentina. Somos proveedores líderes de Merluza Negra y nuestros productos de mar se sirven en los platos de los mercados más importantes del mundo.

+

Mejoramos continuamente nuestras operaciones e invertimos en procesos de producción innovadores. Hemos operado en el puerto más austral, Ushuaia, desde 1992, y siempre nos hemos enorgullecido de emplear a las personas correctas.

+ {{else}} +

Estremar is one of the largest fishing companies in Argentina. We are leading providers of Patagonian Toothfish and our seafood products are served on the plates of the world's most important markets.

+

We continuously improve our operations and invest in innovative production processes. We have operated in the southernmost port, Ushuaia, since 1992, and have always taken pride in employing the right people.

+ {{/if}} +
+ + {{#if lang === 'es'}} Mensaje del Presidente {{else}} President's Message {{/if}} + +
+
+
1992
+
+
+
diff --git a/components/About/About.js b/components/About/About.js new file mode 100644 index 0000000..5ccc018 --- /dev/null +++ b/components/About/About.js @@ -0,0 +1,8 @@ +import { Component, define } from '../../core/component.js'; + +export default class About extends Component { + static templateUrl = '../../components/About/About.html'; + static store = ['lang']; // Subscribe to lang for dynamic text +} + +define('home-about', About); diff --git a/components/Counter/Counter.html b/components/Counter/Counter.html deleted file mode 100644 index e2dae53..0000000 --- a/components/Counter/Counter.html +++ /dev/null @@ -1,34 +0,0 @@ - -
- - {{counter}} - -
diff --git a/components/Counter/Counter.js b/components/Counter/Counter.js deleted file mode 100644 index 091e88b..0000000 --- a/components/Counter/Counter.js +++ /dev/null @@ -1,13 +0,0 @@ -import { Component, store, define } from '../../core/component.js'; - -export default class Counter extends Component { - static templateUrl = '/components/Counter/Counter.html'; - static store = ['counter']; - - bind() { - this.on('.increment', 'click', () => store.update('counter', c => c + 1)); - this.on('.decrement', 'click', () => store.update('counter', c => Math.max(0, c - 1))); - } -} - -define('app-counter', Counter); diff --git a/components/Fleet/Fleet.html b/components/Fleet/Fleet.html new file mode 100644 index 0000000..2f4bcce --- /dev/null +++ b/components/Fleet/Fleet.html @@ -0,0 +1,119 @@ + + +
+
+
+
+ +

+ {{#if lang === 'es'}} Operaciones en aguas del Atlántico Sur {{else}} Operations in South Atlantic waters {{/if}} +

+
+

+ {{#if lang === 'es'}} Nuestra flota opera en las aguas de la Plataforma Continental Argentina, con base en Ushuaia, el puerto más austral del mundo. Empleamos las más modernas tecnologías de pesca responsable. {{else}} Our fleet operates in the waters of the Argentine Continental Shelf, based in Ushuaia, the world's southernmost port. We employ the most modern responsible fishing technologies. {{/if}} +

+
+ +
+
+
{{#if lang === 'es'}} PESCA DE PALANGRE {{else}} LONGLINE FISHING {{/if}}
+
{{#if lang === 'es'}} Buques Palangreros {{else}} Longline Vessels {{/if}}
+

{{#if lang === 'es'}} Embarcaciones especializadas en la captura de Merluza Negra mediante el sistema de palangre, la técnica más selectiva y sustentable disponible. {{else}} Vessels specialized in Patagonian Toothfish capture using the longline system, the most selective and sustainable technique available. {{/if}}

+
+
{{#if lang === 'es'}} ESPECIE OBJETIVO {{else}} TARGET SPECIES {{/if}}{{#if lang === 'es'}} Merluza Negra {{else}} Patagonian Toothfish {{/if}}
+
{{#if lang === 'es'}} PUERTO BASE {{else}} HOME PORT {{/if}}Ushuaia, TDF
+
CERTIF.MSC ✓
+
+
+ +
+
{{#if lang === 'es'}} PESCA PELÁGICA {{else}} PELAGIC FISHING {{/if}}
+
{{#if lang === 'es'}} Buques Pelágicos {{else}} Pelagic Vessels {{/if}}
+

{{#if lang === 'es'}} Flota dirigida a la captura de especies pelágicas en pesquerías bien gestionadas y sustentables de la Plataforma Continental Argentina. {{else}} Fleet targeting the capture of pelagic species in well-managed and sustainable fisheries of the Argentine Continental Shelf. {{/if}}

+
+
{{#if lang === 'es'}} ÁREA DE PESCA {{else}} FISHING AREA {{/if}}{{#if lang === 'es'}} Plataforma Continental {{else}} Continental Shelf {{/if}}
+
ZONAFAO 41
+
+
+ +
+
{{#if lang === 'es'}} PROCESAMIENTO A BORDO {{else}} ONBOARD PROCESSING {{/if}}
+
{{#if lang === 'es'}} Planta de Procesado {{else}} Processing Plant {{/if}}
+

{{#if lang === 'es'}} Procesamiento a bordo de los buques y en tierra en Ushuaia, con los más altos estándares de calidad para la cadena de frío. {{else}} Onboard and onshore processing in Ushuaia, with the highest quality standards for the cold chain. {{/if}}

+
+
{{#if lang === 'es'}} UBICACIÓN {{else}} LOCATION {{/if}}Ushuaia, Argentina
+
ESTÁNDARHACCP ✓
+
+
+
+
+
diff --git a/components/Fleet/Fleet.js b/components/Fleet/Fleet.js new file mode 100644 index 0000000..757960b --- /dev/null +++ b/components/Fleet/Fleet.js @@ -0,0 +1,17 @@ +import { Component, define } from '../../core/component.js'; + +export default class Fleet extends Component { + static templateUrl = '../../components/Fleet/Fleet.html'; + static store = ['lang']; // Subscribe to lang for dynamic text + + mount() { + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) entry.target.classList.add('visible'); + }); + }, { threshold: 0.12 }); + this.$$('.fade-up').forEach(el => observer.observe(el)); + } +} + +define('fleet-page', Fleet); diff --git a/components/Footer/Footer.html b/components/Footer/Footer.html new file mode 100644 index 0000000..08b155b --- /dev/null +++ b/components/Footer/Footer.html @@ -0,0 +1,144 @@ + + + diff --git a/components/Footer/Footer.js b/components/Footer/Footer.js new file mode 100644 index 0000000..d34fd20 --- /dev/null +++ b/components/Footer/Footer.js @@ -0,0 +1,8 @@ +import { Component, define } from '../../core/component.js'; + +export default class Footer extends Component { + static templateUrl = '/components/Footer/Footer.html'; + static store = ['lang']; +} + +define('app-footer', Footer); diff --git a/components/Hero/Hero.html b/components/Hero/Hero.html new file mode 100644 index 0000000..d4a926e --- /dev/null +++ b/components/Hero/Hero.html @@ -0,0 +1,143 @@ + + +
+
+
+
+
+ +
+
+
+ {{#if lang === 'es'}} PESCA ARGENTINA · DESDE 1992 {{else}} ARGENTINE FISHING · SINCE 1992 {{/if}} +
+

+ {{#if lang === 'es'}} Proveedor líder de Merluza Negra del mar austral {{else}} Leading provider of Patagonian Toothfish from the southern sea {{/if}} +

+

+ {{#if lang === 'es'}} + Operamos desde Ushuaia, el puerto más austral del mundo, pescando con responsabilidad en las aguas de la Plataforma Continental Argentina. + {{else}} + We operate from Ushuaia, the world's southernmost port, fishing responsibly in the waters of the Argentine Continental Shelf. + {{/if}} +

+ +
+
+ +
+
+ 30+ + {{#if lang === 'es'}} AÑOS DE OPERACIÓN {{else}} YEARS OF OPERATION {{/if}} +
+
+ MSC + {{#if lang === 'es'}} CERTIFICADO DESDE 2012 {{else}} CERTIFIED SINCE 2012 {{/if}} +
+
+ #1 + {{#if lang === 'es'}} MERLUZA NEGRA ARGENTINA {{else}} ARGENTINE TOOTHFISH #1 {{/if}} +
+
diff --git a/components/Hero/Hero.js b/components/Hero/Hero.js new file mode 100644 index 0000000..660717f --- /dev/null +++ b/components/Hero/Hero.js @@ -0,0 +1,8 @@ +import { Component, define } from '../../core/component.js'; + +export default class Hero extends Component { + static templateUrl = '../../components/Hero/Hero.html'; + static store = ['lang']; // Subscribe to lang for dynamic text +} + +define('home-hero', Hero); diff --git a/components/LocalStateDisplay/LocalStateDisplay.html b/components/LocalStateDisplay/LocalStateDisplay.html deleted file mode 100644 index 676c15f..0000000 --- a/components/LocalStateDisplay/LocalStateDisplay.html +++ /dev/null @@ -1,55 +0,0 @@ - - - -
-
Props received from parent:
-
Count: {{count}}
-
- - -
- {{#if message}} -
"{{message}}"
- {{/if}} -
diff --git a/components/LocalStateDisplay/LocalStateDisplay.js b/components/LocalStateDisplay/LocalStateDisplay.js deleted file mode 100644 index b862f86..0000000 --- a/components/LocalStateDisplay/LocalStateDisplay.js +++ /dev/null @@ -1,44 +0,0 @@ -import { Component, define } from '../../core/component.js'; - -export default class LocalStateDisplay extends Component { - static templateUrl = '/components/LocalStateDisplay/LocalStateDisplay.html'; - static local = { count: 0, message: '', cardClass: '' }; - - #pendingProps = {}; - - // Props can be set before component is connected - store them for later - set count(val) { - if (this.shadowRoot) this.local.count = val; - else this.#pendingProps.count = val; - } - - set message(val) { - if (this.shadowRoot) this.local.message = val; - else this.#pendingProps.message = val; - } - - set cardClass(val) { - if (this.shadowRoot) this.local.cardClass = val; - else this.#pendingProps.cardClass = val; - } - - mount() { - // Apply any props that were set before component was connected - this.batch(() => { - if (this.#pendingProps.count !== undefined) this.local.count = this.#pendingProps.count; - if (this.#pendingProps.message !== undefined) this.local.message = this.#pendingProps.message; - if (this.#pendingProps.cardClass !== undefined) this.local.cardClass = this.#pendingProps.cardClass; - }); - } - - // Emit events to parent to update its state - increment() { - this.emit('update-count', { delta: 1 }); - } - - decrement() { - this.emit('update-count', { delta: -1 }); - } -} - -define('local-state-display', LocalStateDisplay); diff --git a/components/Logo/Logo.html b/components/Logo/Logo.html new file mode 100644 index 0000000..1c68232 --- /dev/null +++ b/components/Logo/Logo.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/components/Logo/Logo.js b/components/Logo/Logo.js new file mode 100644 index 0000000..fdff58b --- /dev/null +++ b/components/Logo/Logo.js @@ -0,0 +1,7 @@ +import { Component, define } from '../../core/component.js'; + +export default class Logo extends Component { + static templateUrl = '/components/Logo/Logo.html'; +} + +define('app-logo', Logo); diff --git a/components/Navigation/Navigation.html b/components/Navigation/Navigation.html index 6371857..07a18c8 100644 --- a/components/Navigation/Navigation.html +++ b/components/Navigation/Navigation.html @@ -1,107 +1,108 @@ diff --git a/components/Navigation/Navigation.js b/components/Navigation/Navigation.js index 76c153c..1bf2ba4 100644 --- a/components/Navigation/Navigation.js +++ b/components/Navigation/Navigation.js @@ -2,11 +2,23 @@ import { Component, store, define } from '../../core/component.js'; export default class Navigation extends Component { static templateUrl = '/components/Navigation/Navigation.html'; - static store = ['user', 'isAuthenticated', 'theme']; + static store = ['lang']; - bind() { - this.on('#auth-btn', 'click', () => { - store.get('isAuthenticated') ? store.logout() : store.login(); + setLanguage(e) { + const lang = e.target.closest('button')?.dataset.lang; + if (lang) store.setLang(lang); + } + + mount() { + window.addEventListener('scroll', () => { + const nav = this.$('nav'); + if (nav) { + if (window.scrollY > 60) { + nav.style.background = 'rgba(10, 24, 37, 0.98)'; + } else { + nav.style.background = 'rgba(10, 24, 37, 0.92)'; + } + } }); } } diff --git a/components/ThemeToggle/ThemeToggle.html b/components/ThemeToggle/ThemeToggle.html deleted file mode 100644 index 33e3e05..0000000 --- a/components/ThemeToggle/ThemeToggle.html +++ /dev/null @@ -1,39 +0,0 @@ - - - \ No newline at end of file diff --git a/components/ThemeToggle/ThemeToggle.js b/components/ThemeToggle/ThemeToggle.js deleted file mode 100644 index 12bee46..0000000 --- a/components/ThemeToggle/ThemeToggle.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, store, define } from '../../core/component.js'; - -export default class ThemeToggle extends Component { - static templateUrl = '/components/ThemeToggle/ThemeToggle.html'; - static store = ['theme']; - - bind() { - this.on('#toggle-btn', 'click', () => store.toggleTheme()); - } -} - -define('theme-toggle', ThemeToggle); diff --git a/components/Values/Values.html b/components/Values/Values.html new file mode 100644 index 0000000..dab617e --- /dev/null +++ b/components/Values/Values.html @@ -0,0 +1,73 @@ + + +
+
+
+
+
{{#if lang === 'es'}} Confianza del cliente {{else}} Customer trust {{/if}}
+
{{#if lang === 'es'}} La confianza de nuestros clientes es la base para nuestras operaciones y todos los días nos esforzamos por superar sus expectativas. {{else}} Our customers' trust is the foundation for our operations, and every day we strive to exceed their expectations. {{/if}}
+
+
+
+
+
{{#if lang === 'es'}} Practicidad operativa {{else}} Operational practicality {{/if}}
+
{{#if lang === 'es'}} Nos involucramos y comprometemos, sabemos qué estamos haciendo y hacemos bien nuestro trabajo. {{else}} We get involved and committed; we know what we are doing and we do our job well. {{/if}}
+
+
+
+
+
{{#if lang === 'es'}} Seguridad y medioambiente {{else}} Safety and environment {{/if}}
+
{{#if lang === 'es'}} Nos importa y nos responsabilizamos personalmente por la seguridad de nuestra gente y el medio ambiente. {{else}} We care and take personal responsibility for the safety of our people and the environment. {{/if}}
+
+
+
+
+
{{#if lang === 'es'}} Desarrollo de personas {{else}} People development {{/if}}
+
{{#if lang === 'es'}} Nuestros logros son resultado de los esfuerzos del equipo. Compartimos lo que sabemos y nos ayudamos mutuamente. {{else}} Our achievements are the result of team effort. We share what we know and help each other. {{/if}}
+
+
+
+
diff --git a/components/Values/Values.js b/components/Values/Values.js new file mode 100644 index 0000000..d0ca238 --- /dev/null +++ b/components/Values/Values.js @@ -0,0 +1,8 @@ +import { Component, define } from '../../core/component.js'; + +export default class Values extends Component { + static templateUrl = '../../components/Values/Values.html'; + static store = ['lang']; // Subscribe to lang for dynamic text +} + +define('home-values', Values); diff --git a/globals.css b/globals.css index dcea4f0..b21434a 100644 --- a/globals.css +++ b/globals.css @@ -1,75 +1,130 @@ -/* Global CSS Custom Properties for Theme Switching */ - :root { - /* Light theme (default) */ - --bg-color: #ffffff; - --bg-secondary: #f8f9fa; - --text-color: #212529; - --text-secondary: #6c757d; - --border-color: #dee2e6; - --hover-bg: #e9ecef; - --primary-color: #0d6efd; - --primary-hover: #0b5ed7; - --success-color: #198754; - --danger-color: #dc3545; - --warning-color: #ffc107; - --info-color: #0dcaf0; - - /* Shadows */ - --shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); - --shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); - --shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175); - - /* Transitions */ - --transition: all 0.2s ease; + --blue: #2B789D; + --blue-dark: #1d5a7a; + --blue-deep: #0d2233; + --teal: #9CC0CC; + --teal-light: #c8dde4; + --navy: #0a1825; + --navy-mid: #112233; + --white: #f7f8f9; + --off-white: #eef2f5; + --text-dark: #111820; + --text-mid: #3d5162; + --text-light: #7a95a8; + --font-serif: 'EB Garamond', Georgia, serif; + --font-sans: 'DM Sans', Helvetica, Arial, sans-serif; } -[data-theme="dark"] { - /* Dark theme */ - --bg-color: #121212; - --bg-secondary: #1e1e1e; - --text-color: #ffffff; - --text-secondary: #b3b3b3; - --border-color: #404040; - --hover-bg: #2a2a2a; - --primary-color: #4dabf7; - --primary-hover: #339af0; - --success-color: #51cf66; - --danger-color: #ff6b6b; - --warning-color: #ffd43b; - --info-color: #74c0fc; - - /* Dark shadows */ - --shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.3); - --shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.4); - --shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.5); -} +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } -/* Prevent layout shift from scrollbar */ html { - scrollbar-gutter: stable; + scroll-behavior: smooth; } -/* Global body styles */ body { - background-color: var(--bg-color); - color: var(--text-color); - transition: var(--transition); + font-family: var(--font-sans); + background: var(--white); + color: var(--text-dark); + overflow-x: hidden; + line-height: 1.5; +} + +/* Framework specific base styles */ +[hidden] { display: none; } + +/* Global animations */ +.fade-up { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease-out, transform 0.6s ease-out; +} + +.fade-up.visible { + opacity: 1; + transform: translateY(0); +} + +@media (prefers-reduced-motion: reduce) { + .fade-up { + transition: none; + } +} + +/* ── SHARED HERO/HEADER STYLES ── */ + +.hero-visuals { + position: absolute; + inset: 0; + overflow: hidden; + pointer-events: none; + z-index: 0; } -/* Ensure custom elements are block-level before JS defines them (for SSR/DSD) */ -app-layout, app-router, app-navigation, app-counter, theme-toggle, local-state-display, -home-page, about-page, contact-page, dashboard-page, login-page, notfound-page, user-page { - display: block; +.hero-bg { + position: absolute; + inset: 0; + background: linear-gradient(160deg, #0a1825 0%, #0d2c42 40%, #1a4a6b 70%, #2B789D 100%); } -/* Prevent layout shifts during hydration */ -app-layout { - contain: layout style; +.hero-grid-lines { + position: absolute; + inset: -100px; + background-image: + linear-gradient(rgba(156,192,204,0.04) 1px, transparent 1px), + linear-gradient(90deg, rgba(156,192,204,0.04) 1px, transparent 1px); + background-size: 80px 80px; + animation: gridMove 40s linear infinite; } -/* Apply theme to web component host elements */ -:host { - --host-bg: var(--bg-color); - --host-text: var(--text-color); -} \ No newline at end of file +@keyframes gridMove { + 0% { transform: translate(0, 0); } + 100% { transform: translate(80px, 80px); } +} + +.hero-waves { + position: absolute; + bottom: 0; left: 0; right: 0; + height: 60%; + opacity: 0.08; + background-image: repeating-linear-gradient( + 0deg, + transparent, + transparent 28px, + rgba(156,192,204,0.6) 28px, + rgba(156,192,204,0.6) 29px + ); +} + +.page-header { + position: relative; + background: var(--navy); + padding: 160px 0 100px; + min-height: 400px; + display: flex; + align-items: center; + overflow: hidden; +} + +.page-title { + position: relative; + z-index: 1; + font-family: var(--font-serif); + font-size: clamp(40px, 5vw, 72px); + font-weight: 400; + color: #fff; + line-height: 1.1; +} + +.page-title em { + font-style: italic; + color: var(--teal-light); +} + +.section-inner { + position: relative; + z-index: 1; + max-width: 1280px; + margin: 0 auto; + padding: 0 56px; + width: 100%; +} diff --git a/index.html b/index.html index 350bb72..8f10e7a 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,9 @@ - Web Components with Routing + Estremar – Pesca + +