@repobit/dex-system-design 0.23.95 → 0.23.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +4 -4
  3. package/src/blog/assets/articles/fbi-crypto-scam-1.jpeg +0 -0
  4. package/src/blog/assets/articles/fbi-crypto-scam-cover.png +0 -0
  5. package/src/blog/assets/fonts/IBMPlexSans-Bold.woff2 +0 -0
  6. package/src/blog/assets/fonts/IBMPlexSans-BoldItalic.woff2 +0 -0
  7. package/src/blog/assets/fonts/IBMPlexSans-Italic.woff2 +0 -0
  8. package/src/blog/assets/fonts/IBMPlexSans-Light.woff2 +0 -0
  9. package/src/blog/assets/fonts/IBMPlexSans-LightItalic.woff2 +0 -0
  10. package/src/blog/assets/fonts/IBMPlexSans-Medium.woff2 +0 -0
  11. package/src/blog/assets/fonts/IBMPlexSans-MediumItalic.woff2 +0 -0
  12. package/src/blog/assets/fonts/IBMPlexSans-Regular.woff2 +0 -0
  13. package/src/blog/assets/fonts/IBMPlexSans-SemiBold.woff2 +0 -0
  14. package/src/blog/assets/fonts/IBMPlexSans-SemiBoldItalic.woff2 +0 -0
  15. package/src/blog/assets/fonts/IBMPlexSansCondensed-Bold.woff2 +0 -0
  16. package/src/blog/assets/fonts/IBMPlexSansCondensed-BoldItalic.woff2 +0 -0
  17. package/src/blog/assets/fonts/IBMPlexSansCondensed-Italic.woff2 +0 -0
  18. package/src/blog/assets/fonts/IBMPlexSansCondensed-Light.woff2 +0 -0
  19. package/src/blog/assets/fonts/IBMPlexSansCondensed-LightItalic.woff2 +0 -0
  20. package/src/blog/assets/fonts/IBMPlexSansCondensed-Medium.woff2 +0 -0
  21. package/src/blog/assets/fonts/IBMPlexSansCondensed-MediumItalic.woff2 +0 -0
  22. package/src/blog/assets/fonts/IBMPlexSansCondensed-Regular.woff2 +0 -0
  23. package/src/blog/assets/fonts/IBMPlexSansCondensed-SemiBold.woff2 +0 -0
  24. package/src/blog/assets/fonts/IBMPlexSansCondensed-SemiBoldItalic.woff2 +0 -0
  25. package/src/blog/assets/global-scam-intelligence-report-2026.png +0 -0
  26. package/src/blog/assets/psd-4.jpg +0 -0
  27. package/src/blog/src/articles/FBI warns of crypto investment scam that sends couriers to collect victims' cash-editedAB.docx +0 -0
  28. package/src/blog/src/articles/FBI-crypto-scam-courier-cash.png +0 -0
  29. package/src/blog/src/articles/fbi-crypto-scam.js +324 -0
  30. package/src/blog/src/articles/~$I warns of crypto investment scam that sends couriers to collect victims' cash-editedAB.docx +0 -0
  31. package/src/blog/src/atoms/blog-abstract.js +51 -0
  32. package/src/blog/src/atoms/blog-atoms.stories.js +519 -0
  33. package/src/blog/src/atoms/blog-authors.js +70 -0
  34. package/src/blog/src/atoms/blog-avatar.js +44 -0
  35. package/src/blog/src/atoms/blog-blockquote.js +92 -0
  36. package/src/blog/src/atoms/blog-caption.js +31 -0
  37. package/src/blog/src/atoms/blog-code-block.js +89 -0
  38. package/src/blog/src/atoms/blog-dek.js +30 -0
  39. package/src/blog/src/atoms/blog-featured-image.js +65 -0
  40. package/src/blog/src/atoms/blog-heading.js +63 -0
  41. package/src/blog/src/atoms/blog-image.js +50 -0
  42. package/src/blog/src/atoms/blog-key-takeaways.js +101 -0
  43. package/src/blog/src/atoms/blog-link.js +68 -0
  44. package/src/blog/src/atoms/blog-meta.js +87 -0
  45. package/src/blog/src/atoms/blog-most-popular.js +146 -0
  46. package/src/blog/src/atoms/blog-newsletter-signup.js +342 -0
  47. package/src/blog/src/atoms/blog-paragraph.js +61 -0
  48. package/src/blog/src/atoms/blog-product-upsell.js +168 -0
  49. package/src/blog/src/atoms/blog-related-articles.js +326 -0
  50. package/src/blog/src/atoms/blog-related-label.js +30 -0
  51. package/src/blog/src/atoms/blog-report-promo.js +250 -0
  52. package/src/blog/src/atoms/blog-standout.js +78 -0
  53. package/src/blog/src/atoms/blog-subhead.js +32 -0
  54. package/src/blog/src/atoms/blog-table-of-contents.js +447 -0
  55. package/src/blog/src/atoms/blog-tag.js +86 -0
  56. package/src/blog/src/atoms/blog-title.js +31 -0
  57. package/src/blog/src/base/blog-element.js +10 -0
  58. package/src/blog/src/breakpoints.js +23 -0
  59. package/src/blog/src/content/blog-article.js +736 -0
  60. package/src/blog/src/content/blog-atoms-showcase.js +401 -0
  61. package/src/blog/src/content/blog-page-layout.js +73 -0
  62. package/src/blog/src/content/blog-pages.stories.js +101 -0
  63. package/src/blog/src/content/render-inline-content.js +18 -0
  64. package/src/blog/src/data/popular-articles.js +43 -0
  65. package/src/blog/src/data/related-articles.js +58 -0
  66. package/src/blog/src/index.js +104 -0
  67. package/src/blog/src/lib/article-toc.js +206 -0
  68. package/src/blog/src/lib/load-prism.js +23 -0
  69. package/src/blog/src/shell/blog-shell.js +31 -0
  70. package/src/blog/src/styles/prism-theme.js +65 -0
  71. package/src/blog/src/tokens/blog.js +406 -0
  72. package/src/blog/src/tokens/core.js +811 -0
  73. package/src/blog/src/tokens/fonts.css +241 -0
  74. package/src/blog/src/tokens/index.js +27 -0
  75. package/src/blog/src/tokens/legacy.js +58 -0
  76. package/src/blog/tokens/blog.js +406 -0
  77. package/src/blog/tokens/core.js +811 -0
  78. package/src/blog/tokens/fonts.css +241 -0
  79. package/src/blog/tokens/index.js +27 -0
  80. package/src/blog/tokens/legacy.js +58 -0
  81. package/src/blog/tokens.css +1512 -0
  82. package/src/blog/tokens.js +1 -0
  83. package/src/blog/vendor/prism/prism.css +120 -0
  84. package/src/blog/vendor/prism/prism.js +300 -0
@@ -0,0 +1,146 @@
1
+ import { css, html } from 'lit';
2
+ import { BlogElement } from '../base/blog-element.js';
3
+
4
+ /**
5
+ * Page-level popular articles — thumbnail, title, and date.
6
+ *
7
+ * @property {string} title
8
+ * @property {Array<{ title: string, href: string, date?: string, datetime?: string, image?: string, imageAlt?: string }>} items
9
+ */
10
+ export class BlogMostPopular extends BlogElement {
11
+ static properties = {
12
+ title: { type: String },
13
+ items: { type: Array }
14
+ };
15
+
16
+ constructor() {
17
+ super();
18
+ this.title = 'Most popular';
19
+ this.items = [];
20
+ }
21
+
22
+ static styles = [
23
+ ...BlogElement.styles,
24
+ css`
25
+ :host {
26
+ display: block;
27
+ }
28
+
29
+ .popular__title {
30
+ margin: 0 0 var(--blog-popular-title-spacing-bottom);
31
+ font-family: var(--blog-popular-title-fontFamily);
32
+ font-size: var(--blog-popular-title-fontSize);
33
+ font-weight: var(--blog-popular-title-fontWeight);
34
+ line-height: var(--blog-popular-title-lineHeight);
35
+ color: var(--blog-popular-title-color);
36
+ }
37
+
38
+ .popular__list {
39
+ margin: 0;
40
+ padding: 0;
41
+ list-style: none;
42
+ }
43
+
44
+ .popular__list li + li {
45
+ margin-top: var(--blog-popular-item-gap);
46
+ }
47
+
48
+ .popular__link {
49
+ display: flex;
50
+ align-items: flex-start;
51
+ gap: var(--blog-popular-item-inner-gap);
52
+ color: inherit;
53
+ text-decoration: none;
54
+ }
55
+
56
+ .popular__link:hover .popular__item-title {
57
+ color: var(--blog-popular-link-hover-color);
58
+ text-decoration: underline;
59
+ }
60
+
61
+ .popular__link:focus-visible {
62
+ outline: var(--focus-outline-traditional);
63
+ outline-offset: var(--focus-outline-offset);
64
+ border-radius: var(--radius-sm);
65
+ }
66
+
67
+ .popular__thumb {
68
+ flex: 0 0 var(--blog-popular-thumb-width);
69
+ width: var(--blog-popular-thumb-width);
70
+ aspect-ratio: var(--blog-popular-thumb-aspect-ratio);
71
+ border-radius: var(--blog-popular-thumb-borderRadius);
72
+ object-fit: cover;
73
+ background: var(--blog-popular-thumb-background);
74
+ }
75
+
76
+ .popular__item-body {
77
+ min-width: 0;
78
+ }
79
+
80
+ .popular__item-title {
81
+ margin: 0 0 var(--spacing-4);
82
+ font-family: var(--blog-popular-item-title-fontFamily);
83
+ font-size: var(--blog-popular-item-title-fontSize);
84
+ font-weight: var(--blog-popular-item-title-fontWeight);
85
+ line-height: var(--blog-popular-item-title-lineHeight);
86
+ color: var(--blog-popular-item-title-color);
87
+ }
88
+
89
+ .popular__item-date {
90
+ font-family: var(--typography-fontFamily-sans);
91
+ font-size: var(--blog-popular-item-date-fontSize);
92
+ font-weight: var(--typography-fontWeight-normal);
93
+ line-height: var(--typography-lineHeight-normal);
94
+ color: var(--blog-popular-item-date-color);
95
+ text-transform: uppercase;
96
+ letter-spacing: var(--typography-letterSpacing-wide);
97
+ }
98
+ `
99
+ ];
100
+
101
+ render() {
102
+ if (!this.items.length) {
103
+ return null;
104
+ }
105
+
106
+ return html`
107
+ <section class="popular" part="popular" aria-label=${this.title}>
108
+ <h2 class="popular__title" part="title">${this.title}</h2>
109
+ <ol class="popular__list" part="list">
110
+ ${this.items.map(
111
+ (item) => html`
112
+ <li part="item">
113
+ <a class="popular__link" part="link" href=${item.href}>
114
+ ${item.image
115
+ ? html`<img
116
+ class="popular__thumb"
117
+ part="thumb"
118
+ src=${item.image}
119
+ alt=${item.imageAlt ?? ''}
120
+ loading="lazy"
121
+ />`
122
+ : null}
123
+ <span class="popular__item-body">
124
+ <p class="popular__item-title" part="item-title">
125
+ ${item.title}
126
+ </p>
127
+ ${item.date
128
+ ? html`<time
129
+ class="popular__item-date"
130
+ part="item-date"
131
+ datetime=${item.datetime ?? ''}
132
+ >${item.date}</time
133
+ >`
134
+ : null}
135
+ </span>
136
+ </a>
137
+ </li>
138
+ `
139
+ )}
140
+ </ol>
141
+ </section>
142
+ `;
143
+ }
144
+ }
145
+
146
+ customElements.define('blog-most-popular', BlogMostPopular);
@@ -0,0 +1,342 @@
1
+ import { css, html, nothing, unsafeCSS } from 'lit';
2
+ import { BlogElement } from '../base/blog-element.js';
3
+ import { minWidth } from '../breakpoints.js';
4
+
5
+ /**
6
+ * Newsletter signup card — email capture with heading, description, and privacy disclaimer.
7
+ *
8
+ * @property {string} headingBefore - Heading text before the emphasized word
9
+ * @property {string} headingEmphasis - Italic-emphasized word in the heading
10
+ * @property {string} headingAfter - Heading text after the emphasized word
11
+ * @property {string} description - Supporting copy below the heading
12
+ * @property {string} disclaimerBefore - Disclaimer text before the privacy policy link
13
+ * @property {string} privacyHref - URL for the privacy policy link
14
+ * @property {string} privacyLabel - Link text for the privacy policy
15
+ * @property {string} disclaimerAfter - Disclaimer text after the privacy policy link
16
+ * @property {string} buttonLabel - Subscribe button label
17
+ * @property {string} placeholder - Email input placeholder
18
+ */
19
+ export class BlogNewsletterSignup extends BlogElement {
20
+ static properties = {
21
+ headingBefore : { type: String, attribute: 'heading-before' },
22
+ headingEmphasis : { type: String, attribute: 'heading-emphasis' },
23
+ headingAfter : { type: String, attribute: 'heading-after' },
24
+ description : { type: String },
25
+ disclaimerBefore: { type: String, attribute: 'disclaimer-before' },
26
+ privacyHref : { type: String, attribute: 'privacy-href' },
27
+ privacyLabel : { type: String, attribute: 'privacy-label' },
28
+ disclaimerAfter : { type: String, attribute: 'disclaimer-after' },
29
+ buttonLabel : { type: String, attribute: 'button-label' },
30
+ placeholder : { type: String },
31
+ _error : { type: String, state: true },
32
+ _submitted : { type: Boolean, state: true }
33
+ };
34
+
35
+ constructor() {
36
+ super();
37
+ this.headingBefore = 'The one cybersecurity newsletter you ';
38
+ this.headingEmphasis = 'actually';
39
+ this.headingAfter = ' need';
40
+ this.description =
41
+ 'Relevant tips, real-world scams explained, and actionable advice...all in one place!';
42
+ this.disclaimerBefore =
43
+ 'I confirm that I am the owner of the provided email address and I agree with ';
44
+ this.privacyHref = '#';
45
+ this.privacyLabel = 'Privacy Policy';
46
+ this.disclaimerAfter = '.';
47
+ this.buttonLabel = 'Subscribe';
48
+ this.placeholder = 'Your best email';
49
+ this._error = '';
50
+ this._submitted = false;
51
+ }
52
+
53
+ static styles = [
54
+ ...BlogElement.styles,
55
+ css`
56
+ :host {
57
+ display: block;
58
+ }
59
+
60
+ .newsletter {
61
+ display: flex;
62
+ flex-direction: column;
63
+ align-items: center;
64
+ justify-content: center;
65
+ height: 100%;
66
+ box-sizing: border-box;
67
+ text-align: center;
68
+ padding: var(--blog-newsletter-padding);
69
+ border: var(--blog-newsletter-border-width) solid
70
+ var(--blog-newsletter-border-color);
71
+ border-radius: var(--blog-newsletter-borderRadius);
72
+ background: var(--blog-newsletter-background);
73
+ gap: var(--blog-newsletter-gap);
74
+ }
75
+
76
+ .newsletter__icon {
77
+ display: flex;
78
+ align-items: center;
79
+ justify-content: center;
80
+ width: var(--blog-newsletter-icon-size);
81
+ height: var(--blog-newsletter-icon-size);
82
+ color: var(--blog-newsletter-icon-color);
83
+ }
84
+
85
+ .newsletter__icon svg {
86
+ width: 100%;
87
+ height: 100%;
88
+ }
89
+
90
+ .newsletter__heading {
91
+ margin: 0;
92
+ max-width: var(--blog-newsletter-heading-max-width);
93
+ font-family: var(--blog-newsletter-heading-fontFamily);
94
+ font-size: var(--blog-newsletter-heading-fontSize);
95
+ font-weight: var(--blog-newsletter-heading-fontWeight);
96
+ line-height: var(--blog-newsletter-heading-lineHeight);
97
+ color: var(--blog-newsletter-heading-color);
98
+ }
99
+
100
+ .newsletter__emphasis {
101
+ font-style: var(--blog-newsletter-heading-emphasis-fontStyle);
102
+ }
103
+
104
+ .newsletter__description {
105
+ margin: 0;
106
+ max-width: var(--blog-newsletter-description-max-width);
107
+ font-family: var(--blog-newsletter-description-fontFamily);
108
+ font-size: var(--blog-newsletter-description-fontSize);
109
+ font-weight: var(--blog-newsletter-description-fontWeight);
110
+ line-height: var(--blog-newsletter-description-lineHeight);
111
+ color: var(--blog-newsletter-description-color);
112
+ }
113
+
114
+ .newsletter__form {
115
+ display: flex;
116
+ flex-direction: column;
117
+ width: 100%;
118
+ max-width: var(--blog-newsletter-form-max-width);
119
+ gap: var(--blog-newsletter-form-gap);
120
+ }
121
+
122
+ ${unsafeCSS(minWidth('sm'))} {
123
+ .newsletter__form {
124
+ flex-direction: row;
125
+ align-items: stretch;
126
+ }
127
+ }
128
+
129
+ .newsletter__input {
130
+ flex: 1;
131
+ min-width: 0;
132
+ // height: var(--form-input-medium-height);
133
+ // padding: var(--form-input-medium-padding);
134
+ border: var(--form-input-default-borderWidth) solid
135
+ var(--form-input-default-borderColor);
136
+ border-radius: var(--form-input-medium-borderRadius);
137
+ background: var(--form-input-default-backgroundColor);
138
+ font-family: var(--form-input-default-fontFamily);
139
+ font-size: var(--form-input-medium-fontSize);
140
+ line-height: var(--form-input-default-lineHeight);
141
+ color: var(--form-input-default-color);
142
+ padding-left: var(--spacing-16)
143
+
144
+ }
145
+
146
+ .newsletter__input::placeholder {
147
+ color: var(--color-text-muted);
148
+ }
149
+
150
+ .newsletter__input:focus {
151
+ outline: none;
152
+ border-color: var(--form-input-focus-borderColor);
153
+ box-shadow: var(--form-input-focus-boxShadow);
154
+ }
155
+
156
+ :host([invalid]) .newsletter__input {
157
+ border-color: var(--form-input-error-borderColor);
158
+ background: var(--form-input-error-backgroundColor);
159
+ }
160
+
161
+ .newsletter__button {
162
+ flex-shrink: 0;
163
+ height: var(--button-size-medium-height);
164
+ padding: var(--button-size-medium-padding-vertical)
165
+ var(--button-size-medium-padding-horizontal);
166
+ border: var(--button-shared-borderWidth) solid
167
+ var(--button-primary-border-default);
168
+ border-radius: var(--button-size-medium-borderRadius);
169
+ background: var(--button-primary-background-default);
170
+ font-family: var(--button-shared-fontFamily);
171
+ font-size: var(--button-size-medium-fontSize);
172
+ font-weight: var(--button-shared-fontWeight);
173
+ line-height: var(--button-shared-lineHeight);
174
+ color: var(--button-primary-text-default);
175
+ cursor: pointer;
176
+ transition: background-color var(--button-shared-transition-duration)
177
+ var(--button-shared-transition-easing);
178
+ }
179
+
180
+ .newsletter__button:hover {
181
+ background: var(--button-primary-background-hover);
182
+ border-color: var(--button-primary-border-hover);
183
+ }
184
+
185
+ .newsletter__button:focus-visible {
186
+ outline: var(--button-shared-focus-outline);
187
+ outline-offset: var(--button-shared-focus-outlineOffset);
188
+ }
189
+
190
+ .newsletter__error {
191
+ margin: 0;
192
+ width: 100%;
193
+ max-width: var(--blog-newsletter-form-max-width);
194
+ font-family: var(--typography-fontFamily-sans);
195
+ font-size: var(--form-help-text-default-fontSize);
196
+ color: var(--form-help-text-error-color);
197
+ text-align: left;
198
+ }
199
+
200
+ .newsletter__disclaimer {
201
+ margin: 0;
202
+ max-width: var(--blog-newsletter-disclaimer-max-width);
203
+ font-family: var(--blog-newsletter-disclaimer-fontFamily);
204
+ font-size: var(--blog-newsletter-disclaimer-fontSize);
205
+ font-weight: var(--blog-newsletter-disclaimer-fontWeight);
206
+ line-height: var(--blog-newsletter-disclaimer-lineHeight);
207
+ color: var(--blog-newsletter-disclaimer-color);
208
+ }
209
+
210
+ .newsletter__disclaimer a {
211
+ color: var(--color-text-link);
212
+ text-decoration: var(
213
+ --typography-link-default-textDecoration-default
214
+ );
215
+ }
216
+
217
+ .newsletter__disclaimer a:hover {
218
+ color: var(--color-text-link-hover);
219
+ text-decoration: var(
220
+ --typography-link-default-textDecoration-hover
221
+ );
222
+ }
223
+
224
+ .newsletter__disclaimer a:focus-visible {
225
+ outline: var(--focus-outline-traditional);
226
+ outline-offset: var(--focus-outline-offset);
227
+ }
228
+ `
229
+ ];
230
+
231
+ updated(changed) {
232
+ if (changed.has('_error')) {
233
+ if (this._error) {
234
+ this.setAttribute('invalid', '');
235
+ } else {
236
+ this.removeAttribute('invalid');
237
+ }
238
+ }
239
+ }
240
+
241
+ /** @param {SubmitEvent} event */
242
+ _handleSubmit(event) {
243
+ event.preventDefault();
244
+ this._submitted = false;
245
+
246
+ const form = event.target;
247
+ if (!(form instanceof HTMLFormElement)) {
248
+ return;
249
+ }
250
+
251
+ const data = new FormData(form);
252
+ const email = String(data.get('email') ?? '').trim();
253
+
254
+ if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
255
+ this._error = 'Please enter a valid email address.';
256
+ return;
257
+ }
258
+
259
+ this._error = '';
260
+ this._submitted = true;
261
+ form.reset();
262
+ }
263
+
264
+ _renderEnvelopeIcon() {
265
+ return html`
266
+ <svg
267
+ viewBox="0 0 48 48"
268
+ fill="none"
269
+ xmlns="http://www.w3.org/2000/svg"
270
+ aria-hidden="true"
271
+ >
272
+ <rect
273
+ x="4"
274
+ y="10"
275
+ width="40"
276
+ height="28"
277
+ rx="4"
278
+ stroke="currentColor"
279
+ stroke-width="2"
280
+ />
281
+ <path
282
+ d="M4 14L24 28L44 14"
283
+ stroke="currentColor"
284
+ stroke-width="2"
285
+ stroke-linecap="round"
286
+ stroke-linejoin="round"
287
+ />
288
+ </svg>
289
+ `;
290
+ }
291
+
292
+ render() {
293
+ return html`
294
+ <section class="newsletter" part="newsletter" aria-label="Newsletter signup">
295
+ <div class="newsletter__icon" part="icon">${this._renderEnvelopeIcon()}</div>
296
+
297
+ <h2 class="newsletter__heading" part="heading">
298
+ ${this.headingBefore}
299
+ <em class="newsletter__emphasis" part="emphasis">${this.headingEmphasis}</em>
300
+ ${this.headingAfter}
301
+ </h2>
302
+
303
+ <p class="newsletter__description" part="description">${this.description}</p>
304
+
305
+ <form
306
+ class="newsletter__form"
307
+ part="form"
308
+ @submit=${this._handleSubmit}
309
+ novalidate
310
+ >
311
+ <input
312
+ class="newsletter__input"
313
+ part="input"
314
+ type="email"
315
+ name="email"
316
+ autocomplete="email"
317
+ placeholder=${this.placeholder}
318
+ aria-label=${this.placeholder}
319
+ aria-invalid=${this._error ? 'true' : 'false'}
320
+ ?disabled=${this._submitted}
321
+ />
322
+ <button class="newsletter__button" part="button" type="submit">
323
+ ${this.buttonLabel}
324
+ </button>
325
+ </form>
326
+
327
+ ${this._error
328
+ ? html`<p class="newsletter__error" part="error" role="alert">
329
+ ${this._error}
330
+ </p>`
331
+ : nothing}
332
+
333
+ <p class="newsletter__disclaimer" part="disclaimer">
334
+ ${this.disclaimerBefore}
335
+ <a href=${this.privacyHref} part="privacy-link">${this.privacyLabel}</a>${this.disclaimerAfter}
336
+ </p>
337
+ </section>
338
+ `;
339
+ }
340
+ }
341
+
342
+ customElements.define('blog-newsletter-signup', BlogNewsletterSignup);
@@ -0,0 +1,61 @@
1
+ import { css, html } from 'lit';
2
+ import { BlogElement } from '../base/blog-element.js';
3
+ import { renderInlineContent } from '../content/render-inline-content.js';
4
+
5
+ /** Body prose paragraph */
6
+ export class BlogParagraph extends BlogElement {
7
+ static properties = {
8
+ emphasis: { type: String, reflect: true },
9
+ content : { type: Array }
10
+ };
11
+
12
+ constructor() {
13
+ super();
14
+ this.content = [];
15
+ }
16
+ static styles = [
17
+ ...BlogElement.styles,
18
+ css`
19
+ :host {
20
+ display: block;
21
+ }
22
+
23
+ p {
24
+ margin: 0;
25
+ font-family: var(--typography-fontFamily-sans);
26
+ font-size: var(--blog-prose-fontSize);
27
+ font-weight: var(--typography-body-regular-fontWeight);
28
+ line-height: var(--blog-prose-lineHeight);
29
+ color: var(--blog-prose-color);
30
+ }
31
+
32
+ :host([emphasis='italic']) p {
33
+ font-style: italic;
34
+ }
35
+
36
+ :host([emphasis='bold']) p {
37
+ font-weight: var(--typography-fontWeight-bold);
38
+ }
39
+
40
+ :host([emphasis='bold-italic']) p {
41
+ font-weight: var(--typography-fontWeight-bold);
42
+ font-style: italic;
43
+ }
44
+
45
+ ::slotted(blog-link),
46
+ blog-link {
47
+ display: inline;
48
+ }
49
+ `
50
+ ];
51
+
52
+ render() {
53
+ const hasLinks = this.content.some((segment) => segment.type === 'link');
54
+
55
+ return html`<p part="paragraph">
56
+ ${hasLinks ? renderInlineContent(this.content) : html`<slot></slot>`}
57
+ </p>`;
58
+ }
59
+ }
60
+
61
+ customElements.define('blog-paragraph', BlogParagraph);