@repobit/dex-system-design 0.18.1 → 0.19.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.
@@ -10,30 +10,20 @@ import { localeMap } from './localeMap.js';
10
10
 
11
11
  export class BdFooterLP extends LitElement {
12
12
  static properties = {
13
- _countriesOpen : { state: true },
14
- selectedCountry : { state: true },
15
- currentLocale : { type: String },
16
- maxColumnsPerRow : { type: Number },
17
- _isMobile : { state: true },
18
- _countriesContainer: { state: true } // Referință la containerul cu țări
13
+ currentLocale: { type: String },
14
+ _isMobile : { state: true }
19
15
  };
20
16
 
21
17
  constructor() {
22
18
  super();
23
- this._countriesOpen = false;
24
- this.maxColumnsPerRow = 2;
25
19
  this.currentLocale = 'en';
26
- this.selectedCountry = 'Choose your country';
27
20
  this._isMobile = window.innerWidth <= 768;
28
- this._countriesContainer = null;
29
- console.log('Constructor - isMobile:', this._isMobile, 'Window width:', window.innerWidth);
30
21
  }
31
22
 
32
23
  connectedCallback() {
33
24
  super.connectedCallback();
34
- this._initLocaleFromUrl();
25
+ this._initLocaleFromUrl(); // Adaugă inițializarea locale-ului din URL
35
26
  window.addEventListener('resize', this._handleResize.bind(this));
36
- console.log('Connected - isMobile:', this._isMobile);
37
27
  }
38
28
 
39
29
  disconnectedCallback() {
@@ -43,54 +33,12 @@ export class BdFooterLP extends LitElement {
43
33
 
44
34
  firstUpdated() {
45
35
  super.firstUpdated();
46
- this._updateNavLinks();
47
- // Obține referința la containerul cu țări
48
- // this._countriesContainer = this.shadowRoot.querySelector('.footer-countries-container');
36
+ this._toggleImpressumVisibility(); // Apelează la initializare
49
37
  }
50
38
 
51
39
  updated(changedProps) {
52
40
  if (changedProps.has('currentLocale')) {
53
- this._updateNavLinks();
54
- }
55
-
56
- // Dacă s-a deschis lista de țări, fac scroll smooth către ea
57
- if (changedProps.has('_countriesOpen') && this._countriesOpen) {
58
- // Obține referința la containerul cu țări doar când este deschis
59
- this._countriesContainer = this.shadowRoot.querySelector('.footer-countries-container');
60
- this._scrollToCountries();
61
- }
62
- }
63
-
64
- _scrollToCountries() {
65
- // Obține referința la container doar atunci când este necesar
66
- const container = this.shadowRoot.querySelector('.footer-countries-container');
67
- if (container) {
68
- // Așteaptă ca render-ul să se finalizeze
69
- setTimeout(() => {
70
- container.scrollIntoView({
71
- behavior: 'smooth',
72
- block : 'start'
73
- });
74
- }, 100);
75
- }
76
- }
77
-
78
- _scrollToTop() {
79
- // Scroll smooth către începutul footer-ului
80
- this.scrollIntoView({
81
- behavior: 'smooth',
82
- block : 'start'
83
- });
84
- }
85
-
86
- _handleResize() {
87
- this._isMobile = window.innerWidth <= 768;
88
- const newIsMobile = window.innerWidth <= 768;
89
- console.log('Resize - Old isMobile:', this._isMobile, 'New isMobile:', newIsMobile, 'Window width:', window.innerWidth);
90
-
91
- if (this._isMobile !== newIsMobile) {
92
- this._isMobile = newIsMobile;
93
- console.log('isMobile changed to:', this._isMobile);
41
+ this._toggleImpressumVisibility(); // Apelează când se schimbă locale-ul
94
42
  }
95
43
  }
96
44
 
@@ -98,7 +46,6 @@ export class BdFooterLP extends LitElement {
98
46
  const urlLocale = window.location.pathname.split('/')[1]?.toLowerCase();
99
47
 
100
48
  if (!urlLocale) {
101
- this._updateNavLinks();
102
49
  return;
103
50
  }
104
51
 
@@ -150,134 +97,60 @@ export class BdFooterLP extends LitElement {
150
97
  }
151
98
  }
152
99
 
153
- // Setează valorile pentru țară și locale
154
- if (country) {
155
- this.selectedCountry = country;
156
- }
157
-
158
100
  if (this.currentLocale !== urlLocale) {
159
101
  const originalKey = Object.keys(localeMap).find(k =>
160
102
  k.toLowerCase() === urlLocale
161
103
  );
162
104
  this.currentLocale = originalKey || urlLocale;
163
105
  }
164
-
165
- // Actualizează linkurile de navigație
166
- this._updateNavLinks();
167
- }
168
-
169
- _toggleCountries() {
170
- this._countriesOpen = !this._countriesOpen;
171
-
172
- // Dacă se închide dropdown-ul, fac scroll înapoi sus
173
- if (!this._countriesOpen) {
174
- this._scrollToTop();
175
- }
176
- }
177
-
178
- _closeCountries() {
179
- this._countriesOpen = false;
180
-
181
- // Doar pentru desktop, facem scroll înapoi sus
182
- if (!this._isMobile) {
183
- this._scrollToTop();
184
- }
185
106
  }
186
107
 
187
- _handleCountryClick(e, countryLabel, locale) {
188
- e.preventDefault();
189
- this._selectCountry(countryLabel);
190
-
191
- // Redirect către pagina cu noul locale
192
- const newPath = `/${locale.toLowerCase()}/`;
193
- window.location.href = newPath;
194
- }
195
-
196
- _selectCountry(countryLabel) {
197
- this.selectedCountry = countryLabel;
198
- this._countriesOpen = false;
108
+ _toggleImpressumVisibility() {
109
+ const showImpressum = this.locale === 'de-de' || this.locale === 'de';
110
+ const slot = this.shadowRoot?.querySelector('slot[name="secondary-nav"]');
111
+ const assignedElements = slot?.assignedElements({ flatten: true }) || [];
112
+
113
+ if (assignedElements.length > 0) {
114
+ const footerNav = assignedElements[0];
115
+ const impressumLink = footerNav.querySelector('.impressum-link');
116
+
117
+ // Găsește separatorul care precede link-ul Impressum
118
+ let impressumDivider = null;
119
+ if (impressumLink) {
120
+ impressumDivider = impressumLink.previousElementSibling;
121
+
122
+ // Verifică dacă elementul anterior este un divider și este imediat înainte
123
+ if (impressumDivider && impressumDivider.tagName === 'BD-DIVIDER-VERTICAL' &&
124
+ impressumDivider.nextElementSibling === impressumLink) {
125
+ // Este separatorul corect
126
+ } else {
127
+ impressumDivider = null;
128
+ }
129
+ }
199
130
 
200
- // Găsește locale-ul corespunzător pentru țara selectată
201
- const localeEntry = Object.entries(localeMap).find(
202
- ([, country]) => country === countryLabel
203
- );
131
+ if (impressumLink) {
132
+ // Ascunde/afișează link-ul Impressum
133
+ impressumLink.style.display = showImpressum ? '' : 'none';
204
134
 
205
- if (localeEntry) {
206
- this.currentLocale = localeEntry[0];
135
+ // Ascunde/afișează și separatorul dinaintea lui
136
+ if (impressumDivider && impressumDivider.tagName === 'BD-DIVIDER-VERTICAL') {
137
+ impressumDivider.style.display = showImpressum ? '' : 'none';
138
+ }
139
+ }
207
140
  }
208
-
209
- this._updateNavLinks();
210
- this._scrollToTop();
211
- }
212
-
213
- getCountriesList() {
214
- return Object.entries(localeMap).map(([locale, country]) => ({
215
- locale,
216
- label: country
217
- }));
218
141
  }
219
142
 
220
- renderQuickLinksSection(slotName) {
221
- const assignedElements = this.shadowRoot?.querySelector(`slot[name="${slotName}"]`)?.assignedElements({ flatten: true }) || [];
222
- if (assignedElements.length === 0) return null;
223
-
224
- const maxCols = this.maxColumnsPerRow || 3;
225
- const rows = Math.ceil(assignedElements.length / maxCols);
226
-
227
- const groupedRows = Array.from({ length: rows }, (_, rowIndex) => {
228
- const start = rowIndex * maxCols;
229
- return assignedElements.slice(start, start + maxCols);
230
- });
231
-
232
- return html`
233
- <div class="quick-links-section" style="display: flex; flex-direction: column; gap: 1rem;">
234
- ${groupedRows.map(row => html`
235
- <div style="display: grid; grid-template-columns: repeat(${row.length}, 1fr); gap: 1rem;">
236
- ${row.map(el => html`${el}`)}
237
- </div>
238
- `)}
239
- </div>
240
- `;
143
+ _handleResize() {
144
+ this._isMobile = window.innerWidth <= 768;
241
145
  }
242
146
 
243
147
  get locale() {
244
- const val = (this.currentLocale || 'en').toLowerCase();
245
- return val;
246
- }
247
-
248
- _updateSlotStyles() {
249
- const isMobile = window.innerWidth <= 768;
250
- const slot = this.shadowRoot.querySelector('slot[name="nav"]');
251
- const assignedElements = slot.assignedElements();
252
-
253
- assignedElements.forEach(element => {
254
- if (isMobile) {
255
- element.style.color = '#151719';
256
- element.style.setProperty('color', '#151719', 'important');
257
- } else {
258
- element.style.color = '';
259
- element.style.removeProperty('color');
260
- }
261
- });
262
- }
263
-
264
- _updateNavLinks() {
265
- // Actualizează linkurile care sunt acum în shadow DOM
266
- const links = this.shadowRoot.querySelectorAll('.footer-nav-main a');
267
- const linkPaths = ['consumer', 'small-business', 'business', 'partners'];
268
- const currentLocale = this.locale;
269
-
270
- links.forEach((link, index) => {
271
- if (index < linkPaths.length) {
272
- link.href = `/${currentLocale}/${linkPaths[index]}/`;
273
- }
274
- });
148
+ return (this.currentLocale || 'en').toLowerCase();
275
149
  }
276
150
 
277
151
  render() {
278
152
  const year = new Date().getFullYear();
279
153
  const showAnpc = this.locale.startsWith('ro');
280
- const showImpressum = this.locale === 'de-de' || this.locale === 'de';
281
154
 
282
155
  const masterbrandUrl = this._isMobile
283
156
  ? '/assets/Bitdefender-Masterbrand_mobile.png'
@@ -289,8 +162,6 @@ export class BdFooterLP extends LitElement {
289
162
 
290
163
  const logoUrl = '/assets/BD_logo.png';
291
164
 
292
-
293
-
294
165
  return html`
295
166
  <div class="footer-top-bleed">
296
167
  <div class="container">
@@ -302,8 +173,8 @@ export class BdFooterLP extends LitElement {
302
173
  </div>
303
174
  <div class="footer-top-right">
304
175
  <slot name="top-right">
305
- <div slot="top-right">
306
- <span slot="logo">
176
+ <div>
177
+ <span>
307
178
  <img src="${masterbrandUrl}" alt="Bitdefender Masterbrand">
308
179
  </span>
309
180
  </div>
@@ -314,54 +185,66 @@ export class BdFooterLP extends LitElement {
314
185
  </div>
315
186
 
316
187
  <footer class="container">
317
-
318
- <div class="footer-middle-line-lp">
319
- <bd-footer-nav>
320
- <div class="footer-nav-main">
321
- <a href="legal/">Legal Information</a>
322
- <bd-divider-vertical color="white" height="18px"></bd-divider-vertical>
323
- <a href="site/view/legal-privacy-policy-for-bitdefender-websites/">Privacy Policy</a>
324
- <bd-divider-vertical color="white" height="18px"></bd-divider-vertical>
325
- <a href="sitemap/">Site Map</a>
326
- <bd-divider-vertical color="white" height="18px"></bd-divider-vertical>
327
- <a href="company/">Company</a>
328
- <bd-divider-vertical color="white" height="18px"></bd-divider-vertical>
329
- <a href="https://www.bitdefender.com/consumer/support/">Contact Us</a>
330
- <bd-divider-vertical color="white" height="18px"></bd-divider-vertical>
331
- <a href="#">Privacy Settings</a>
332
- ${showImpressum
333
- ? html`
334
- <bd-divider-vertical color="white" height="18px"></bd-divider-vertical>
335
- <a href="#" class="impressum-link">Impressum</a>
336
- `
337
- : ''}
338
- </div>
339
- </bd-footer-nav>
340
- <bd-divider-horizontal width="100%" color="white" opacity="0.25"></bd-divider-horizontal>
341
-
188
+ <div class="footer-main-content">
189
+ <slot name="content"></slot>
342
190
  </div>
343
191
 
344
-
192
+ <div class="footer-secondary-nav">
193
+ <slot name="secondary-nav"></slot>
194
+ </div>
195
+ <bd-divider-horizontal width="100%" color="white" opacity="0.25"></bd-divider-horizontal>
345
196
  <div class="footer-extra">
346
- <div class="footer-copy">Copyright © 1997 - ${year} Bitdefender</div>
197
+ <div class="footer-copy">
198
+ <slot name="copyright">
199
+ Copyright © 1997 - ${year} Bitdefender
200
+ </slot>
201
+ </div>
202
+
347
203
  ${showAnpc
348
204
  ? html`
349
205
  <div class="footer-anpc-lp">
350
206
  <slot name="anpc">
351
- <div slot="anpc">
352
- <img src="${anpcUrl}" alt="Certificat" />
353
- </div>
207
+ <img src="${anpcUrl}" alt="Certificat" />
354
208
  </slot>
355
209
  </div>
356
210
  `
357
- : null}
358
-
211
+ : ''}
359
212
  </div>
360
-
361
-
362
213
  </footer>
363
214
  `;
364
215
  }
216
+
217
+ // Metodă specifică pentru secondary-nav care verifică și elementele custom
218
+ _hasSecondaryNavContent() {
219
+ const slot = this.shadowRoot?.querySelector('slot[name="secondary-nav"]');
220
+ if (!slot) return false;
221
+
222
+ const assignedNodes = slot.assignedNodes({ flatten: true });
223
+
224
+ // Verifică dacă există noduri care nu sunt doar spații albe
225
+ const hasContent = assignedNodes.some(node => {
226
+ if (node.nodeType === Node.ELEMENT_NODE) {
227
+ return true;
228
+ }
229
+ if (node.nodeType === Node.TEXT_NODE) {
230
+ return node.textContent.trim() !== '';
231
+ }
232
+ return false;
233
+ });
234
+
235
+ return hasContent;
236
+ }
237
+
238
+ // Metodă helper pentru a verifica dacă un slot are conținut
239
+ _hasSlotContent(slotName) {
240
+ const slot = this.shadowRoot?.querySelector(`slot[name="${slotName}"]`);
241
+ if (!slot) return false;
242
+
243
+ const assignedNodes = slot.assignedNodes({ flatten: true });
244
+ return assignedNodes.length > 0 &&
245
+ !(assignedNodes.length === 1 && assignedNodes[0].nodeType === Node.TEXT_NODE && assignedNodes[0].textContent.trim() === '');
246
+ }
247
+
365
248
  static styles = [tokens, footerCSS];
366
249
  }
367
250
 
@@ -1,24 +1,38 @@
1
1
  import { css } from 'lit';
2
2
 
3
3
  export default css`
4
+ .footer-nav-main {
5
+ display: flex;
6
+ align-items: center;
7
+ justify-content: flex-start;
8
+ gap: var(--spacing-16);
9
+ flex-wrap: wrap;
10
+ font-size: var(--typography-body-regular-fontSize);
11
+ font-family: var(--typography-fontFamily-sans, 'IBM Plex Sans');
12
+ font-weight: var(--typography-label-default-fontWeight);
13
+ }
4
14
 
5
- .footer-nav-main {
6
- display: flex;
7
- align-items: center;
8
- justify-content: flex-start;
9
- gap: 1rem;
10
- flex-wrap: wrap;
11
- margin-top: 1rem;
12
- margin-bottom: 1rem;
13
- font-size: var(--typography-body-regular-fontSize);
14
- font-family: var(--typography-fontFamily-sans, 'IBM Plex Sans');
15
- font-weight: var(--typography-label-default-fontWeight)
16
- }
15
+ .footer-nav-main.footer-nav-bold {
16
+ font-weight: var(--typography-heading-h3-fontWeight);
17
+ }
17
18
 
18
- .footer-nav-main.footer-nav-bold {
19
- font-weight: var(--typography-heading-h3-fontWeight);
20
- }
21
- a{
22
- color: white;
23
- text-decoration: none}
24
- `;
19
+ /* Corect: stilizare pentru elementele slottate */
20
+ ::slotted(a) {
21
+ color: white !important;
22
+ text-decoration: none;
23
+ }
24
+
25
+ /* Stiluri pentru mobil */
26
+ @media (max-width: 768px) {
27
+ .footer-nav-main {
28
+ flex-direction: column;
29
+ align-items: flex-start;
30
+ gap: var(--spacing-16);
31
+ }
32
+
33
+ .footer-nav-main ::slotted(bd-divider-vertical) {
34
+ display: none !important;
35
+ }
36
+ }
37
+
38
+ `;
@@ -24,9 +24,9 @@ export class BdFooterNav extends LitElement {
24
24
  .join(' ');
25
25
 
26
26
  return html`
27
- <nav class=${classString}>
28
- <slot></slot>
29
- </nav>
27
+ <nav class=${classString} part="links">
28
+ <slot></slot>
29
+ </nav>
30
30
  `;
31
31
  }
32
32