@gudhub/ssg-web-components-library 1.0.43 → 1.0.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gudhub/ssg-web-components-library",
3
- "version": "1.0.43",
3
+ "version": "1.0.45",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -110,7 +110,7 @@ class CommentsComponent extends GHComponent {
110
110
  }
111
111
 
112
112
  if (comment.name && comment.text) {
113
- const { api_app_id } = window.getConfig().chapters.blog;
113
+ const { api_app_id } = window.getConfig().chapters.blog || window.getConfig().componentsConfigs.chapters.blog;
114
114
  const response = await fetch(`https://gudhub.com/api/services/prod/api/${api_app_id}/add-comment`, {
115
115
  method: 'POST',
116
116
  headers: {
@@ -0,0 +1,5 @@
1
+ export const htmlTextFromEditorJs = {
2
+ tag: 'html-text-from-editor-js',
3
+ src: '@gudhub/ssg-web-components-library/src/components/html-text-from-editor-js/html-text-from-editor-js.js',
4
+ serverOnly: false
5
+ }
@@ -0,0 +1,9 @@
1
+ <section class="html-text-from-editor-js-component">
2
+ <div class="container">
3
+ <div class="html-text-from-editor-js-wrapper"></div>
4
+ ${ isCollapsible
5
+ ? `<toggle-read-more-button-component></toggle-read-more-button-component>`
6
+ : ''
7
+ }
8
+ </div>
9
+ </section>
@@ -0,0 +1,99 @@
1
+ import html from './html-text-from-editor-js.html';
2
+ import './html-text-from-editor-js.scss';
3
+
4
+ import jsonTemplate from './html-text-from-editor-js.json';
5
+
6
+ class HtmlTextFromEditorJs extends GHComponent {
7
+ constructor() {
8
+ super();
9
+
10
+ // If we doesn't have all attributes which we need - we set default data from jsonTemplate file
11
+ super.setDefaultData(jsonTemplate.html);
12
+ }
13
+
14
+ async onServerRender() {
15
+ this.isCollapsible = this.getAttribute("isCollapsible");
16
+
17
+ this.appId = this.getAttribute("appId");
18
+ this.fieldId = this.getAttribute("fieldId");
19
+ this.interpretationId = this.getAttribute("interpretationId");
20
+
21
+ // Extends from GH Component
22
+ super.render(html);
23
+
24
+ this.toggleHtmlTextWrapper(this.isCollapsible);
25
+
26
+ await this.appendHtmlText();
27
+ }
28
+
29
+ async getInterpretationById() {
30
+ const appItems = await this.getGudHubAppItems(this.appId) || null;
31
+ const currentItemId = this.findCurrentItemId(appItems);
32
+
33
+ const htmlText = await this.getGudHubInterpretationById(this.appId, currentItemId, this.fieldId, this.interpretationId) || null;
34
+ return htmlText;
35
+ }
36
+
37
+ async appendHtmlText() {
38
+ const container = this.querySelector('.html-text-from-editor-js-wrapper');
39
+
40
+ const htmlText = await this.getInterpretationById() ?? jsonTemplate?.html;
41
+
42
+ container.innerHTML = htmlText;
43
+ }
44
+
45
+ findCurrentItemId(appItems) {
46
+ const href = new URL(window.location.href);
47
+ const pathname = href.searchParams.get('path');
48
+
49
+ let matchingItemId = null;
50
+
51
+ if (appItems) {
52
+ for (const item of appItems) {
53
+ const { fields } = item;
54
+
55
+ for (const field of fields) {
56
+ if (field.field_value === pathname) {
57
+ matchingItemId = item.item_id;
58
+ break;
59
+ }
60
+ }
61
+
62
+ if (matchingItemId) {
63
+ break;
64
+ }
65
+ }
66
+ return matchingItemId;
67
+ } else {
68
+ return null;
69
+ }
70
+ }
71
+
72
+ async getGudHubAppItems(appId) {
73
+ const appIdValue = appId;
74
+ const data = await gudhub.getApp(appIdValue);
75
+
76
+ return data?.items_list;
77
+ }
78
+
79
+ async getGudHubInterpretationById(appId, itemId, fieldId, interpretationId) {
80
+ const data = await gudhub.getInterpretationById(appId, itemId, fieldId, interpretationId);
81
+ return data;
82
+ }
83
+
84
+ toggleHtmlTextWrapper(isCollapsible) {
85
+ const htmlTextFromEditorJsWrapper = this.querySelector('.html-text-from-editor-js-wrapper');
86
+
87
+ if (htmlTextFromEditorJsWrapper) {
88
+ if (isCollapsible) {
89
+ htmlTextFromEditorJsWrapper.classList.add('collapsed');
90
+ htmlTextFromEditorJsWrapper.classList.remove('expanded');
91
+ } else {
92
+ htmlTextFromEditorJsWrapper.classList.add('expanded');
93
+ htmlTextFromEditorJsWrapper.classList.remove('collapsed');
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ window.customElements.define('html-text-from-editor-js', HtmlTextFromEditorJs);
@@ -0,0 +1,3 @@
1
+ {
2
+ "html": "<p>Test Text From Json File</p>"
3
+ }
@@ -0,0 +1,66 @@
1
+ html-text-from-editor-js {
2
+ --titleColor: #1A1A1A;
3
+ --subtitleColor: #525252;
4
+ --textColor: #525252;
5
+ .html-text-from-editor-js-wrapper {
6
+ // max-width: 890px;
7
+ color: var(--textColor);
8
+ line-height: 25px;
9
+ margin-top: 82px;
10
+ padding: 12px 0;
11
+ overflow: hidden;
12
+ transition: max-height 0.3s ease;
13
+ & h2 {
14
+ color: var(--titleColor);
15
+ font-size: 36px;
16
+ font-weight: 400;
17
+ line-height: 40px;
18
+ text-align: left;
19
+ margin-bottom: 30px;
20
+ }
21
+
22
+ & h3 {
23
+ color: var(--subtitleColor);
24
+ font-size: 18px;
25
+ font-weight: bold;
26
+ text-align: left;
27
+ margin: 30px 0 20px 0;
28
+ }
29
+
30
+ & p + p {
31
+ margin-top: 15px;
32
+ }
33
+
34
+ & ol, & ul {
35
+ padding-left: 30px;
36
+ }
37
+
38
+ & p + ol > li,
39
+ & p + ul > li {
40
+ margin-bottom: 15px;
41
+ }
42
+
43
+ & p + ol,
44
+ & p + ul {
45
+ margin-top: 15px;
46
+ }
47
+
48
+ & h3 + ol > li,
49
+ & h3 + ul > li {
50
+ margin-bottom: 15px;
51
+ }
52
+
53
+ & h3 + ol,
54
+ & h3 + ul {
55
+ margin-top: 15px;
56
+ }
57
+ }
58
+
59
+ .collapsed {
60
+ max-height: calc(1.5em * 10.3);
61
+ }
62
+
63
+ .expanded {
64
+ max-height: none;
65
+ }
66
+ }
@@ -0,0 +1,5 @@
1
+ export const toggleReadMoreButtonComponent = {
2
+ tag: 'toggle-read-more-button-component',
3
+ src: '@gudhub/ssg-web-components-library/src/components/html-text-from-editor-js/toggle-read-more-button-component/toggle-read-more-button-component.js',
4
+ serverOnly: false
5
+ }
@@ -0,0 +1,5 @@
1
+ <section class="toggle-read-more-button-component">
2
+ <div class="toggle-read-more-button-component__container">
3
+ <button class="toggle-read-more-button-component__button">Read More</button>
4
+ </div>
5
+ </section>
@@ -0,0 +1,45 @@
1
+ import html from './toggle-read-more-button-component.html';
2
+ import './toggle-read-more-button-component.scss';
3
+
4
+ class ToggleReadMoreButtonComponent extends GHComponent {
5
+ constructor() {
6
+ super();
7
+ }
8
+
9
+ async onClientRender() {
10
+ // Extends from GH Component
11
+ super.render(html);
12
+
13
+ this.initializeEventListeners();
14
+ }
15
+
16
+ initializeEventListeners() {
17
+ this.isShowReadMoreButton();
18
+ }
19
+
20
+ isShowReadMoreButton() {
21
+ const textContainer = document.querySelector('.html-text-from-editor-js-wrapper');
22
+ const toggleReadMoreButtonElement = this.querySelector('.toggle-read-more-button-component');
23
+ const toggleButton = this.querySelector('.toggle-read-more-button-component__button');
24
+
25
+ if (!textContainer.textContent) {
26
+ toggleReadMoreButtonElement.style.display = 'none';
27
+ }
28
+
29
+ toggleButton.addEventListener('click', () => {
30
+ if (textContainer.classList.contains('collapsed')) {
31
+ textContainer.classList.remove('collapsed');
32
+ textContainer.classList.add('expanded');
33
+
34
+ toggleButton.textContent = 'Read Less';
35
+ } else {
36
+ textContainer.classList.remove('expanded');
37
+ textContainer.classList.add('collapsed');
38
+
39
+ toggleButton.textContent = 'Read More';
40
+ }
41
+ });
42
+ }
43
+ }
44
+
45
+ window.customElements.define('toggle-read-more-button-component', ToggleReadMoreButtonComponent);
@@ -0,0 +1,27 @@
1
+ toggle-read-more-button-component {
2
+ section {
3
+ padding: 0 !important;
4
+ }
5
+
6
+ .toggle-read-more-button-component {
7
+ &__container {
8
+ text-align: center;
9
+ }
10
+
11
+ &__button {
12
+ color: #1A1A1A;
13
+ margin-top: 40px;
14
+ padding: 0 23px 4px 23px;
15
+ font-size: 16px;
16
+ font-weight: 500;
17
+ border-bottom: 1px solid #1A1A1A;
18
+ transition: all 0.3s ease-in-out;
19
+ background: transparent;
20
+ cursor: pointer;
21
+ &:hover {
22
+ color: #B38F55;
23
+ border-color: #B38F55;
24
+ }
25
+ }
26
+ }
27
+ }
@@ -85,14 +85,14 @@ class ImageComponent extends GHComponent {
85
85
  this.image.setAttribute('src', this.src);
86
86
  });
87
87
  } catch (error) {
88
- console.error(`11111111111111111 Image load failed "${this.src}". Attempt "${attempts + 1}"`);
88
+ console.error(`Image load failed "${this.src}". Attempt "${attempts + 1}"`);
89
89
  attempts++;
90
90
  }
91
91
  }
92
92
  if (imageLoaded) {
93
93
  super.render(html);
94
94
  } else {
95
- console.error(`11111111111111111 Image load failed "${this.src}".`);
95
+ console.error(`Image load failed "${this.src}".`);
96
96
  }
97
97
  // caller == 'client' ? this.clientRender() : super.render(html);
98
98
  }
@@ -0,0 +1,5 @@
1
+ export const liqPayComponent = {
2
+ tag: 'liqpay-component',
3
+ src: '@gudhub/ssg-web-components-library/src/components/liqpay-component/liqpay-component.js',
4
+ serverOnly: false
5
+ }
@@ -0,0 +1,18 @@
1
+ <section class="liqpay-component liqpay">
2
+ <div class="pay-button__wrapper">
3
+ <button class="pay-button__button" id="pay-button">Купити</button>
4
+ </div>
5
+
6
+ <div class="liqpay__container liqpay-sidebar">
7
+ <div class="liqpay-sidebar__overlay"></div>
8
+
9
+ <div id="liqpay-container" class="liqpay-sidebar__wrapper">
10
+ <div class="liqpay-sidebar__header">
11
+ <p>Оплата</p>
12
+ <svg id="close-icon" class="liqpay-sidebar__close-icon" xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 13 13" fill="none">
13
+ <path d="M13 1L12 0L6.5 5.5L1 0L0 1L5.5 6.5L0 12L1 13L6.5 7.5L12 13L13 12L7.5 6.5L13 1Z" fill="#A6A6A6"/>
14
+ </svg>
15
+ </div>
16
+ </div>
17
+ </div>
18
+ </section>
@@ -0,0 +1,127 @@
1
+ import html from './liqpay-component.html';
2
+ import './liqpay-component.scss';
3
+
4
+ class LiqPayComponent extends GHComponent {
5
+ constructor() {
6
+ super();
7
+ }
8
+
9
+ async onServerRender() {
10
+ this.amount = this.getAttribute('amount') || '1';
11
+ this.description = this.getAttribute('description') || '';
12
+
13
+ // Extends from GH Component
14
+ super.render(html);
15
+
16
+ await this.loadLiqPay();
17
+ }
18
+
19
+ async onClientRender() {
20
+ this.toggleSidebarVisibility();
21
+ }
22
+
23
+ async initLiqPayLibrary() {
24
+ if (!document.querySelector('script#liqpay_script')) {
25
+ const script = document.createElement('script');
26
+ script.setAttribute('id', 'liqpay_script');
27
+ script.setAttribute('src', 'https://static.liqpay.ua/libjs/checkout.js');
28
+ script.async = true;
29
+
30
+ return new Promise((resolve, reject) => {
31
+ script.onload = () => {
32
+ if (window.LiqPayCheckout) {
33
+ resolve();
34
+ } else {
35
+ reject(new Error('LiqPayCheckout is not defined after script load.'));
36
+ }
37
+ };
38
+ script.onerror = reject;
39
+ document.body.appendChild(script);
40
+ });
41
+ }
42
+ return Promise.resolve();
43
+ }
44
+
45
+ async loadLiqPay() {
46
+ await this.initLiqPayLibrary();
47
+
48
+ const data = window.getConfig()?.liqPayConfig?.data;
49
+
50
+ const dataFromAttributes = { amount: this.amount, description: this.description };
51
+ const fullApiData = JSON.stringify({ ...data, ...dataFromAttributes });
52
+
53
+ const privateKey = window.getConfig()?.liqPayConfig?.privateKey;
54
+
55
+ const generateSignature = async (data, privateKey) => {
56
+ const combinedData = privateKey + data + privateKey;
57
+
58
+ const encoder = new TextEncoder();
59
+ const dataBuffer = encoder.encode(combinedData);
60
+
61
+ const hashBuffer = await crypto.subtle.digest("SHA-1", dataBuffer);
62
+
63
+ const base64String = btoa(String.fromCharCode(...new Uint8Array(hashBuffer)));
64
+ return base64String;
65
+ }
66
+
67
+ const signature = await generateSignature(fullApiData, privateKey);
68
+
69
+ if (window.LiqPayCheckout) {
70
+ await LiqPayCheckout.init({
71
+ data: fullApiData,
72
+ signature: signature,
73
+ embedTo: '#liqpay-container',
74
+ mode: 'embed'
75
+ }).on('liqpay.callback', (data) => {
76
+ console.log('data:', data);
77
+
78
+ if (data.status === 'success') {
79
+ alert('Payment success!');
80
+ } else if (data.status === 'failure') {
81
+ alert('Payment failed. Please try again.');
82
+ }
83
+ }).on('liqpay.ready', () => {
84
+ console.log('LiqPay is ready.');
85
+ }).on('liqpay.close', () => {
86
+ console.log('LiqPay widget closed.');
87
+ });
88
+ }
89
+ }
90
+
91
+ toggleSidebarVisibility() {
92
+ const body = document.body;
93
+ const liqPayWrapper = document.querySelector('.liqpay-sidebar__wrapper');
94
+ const overlay = document.querySelector('.liqpay-sidebar__overlay');
95
+ const openBtns = document.querySelectorAll('.pay-button__button');
96
+ const closeBtn = document.querySelector('.liqpay-sidebar__close-icon');
97
+
98
+ const toggleSidebar = () => {
99
+ const isOpen = liqPayWrapper.classList.toggle('open');
100
+ overlay.classList.toggle('visible', isOpen);
101
+ body.classList.toggle('no-scroll', isOpen);
102
+
103
+ if (isOpen) {
104
+ console.log("Sidebar opened at:", new Date());
105
+ }
106
+ };
107
+
108
+ openBtns.forEach(btn => {
109
+ if (!btn._isBound) {
110
+ btn.addEventListener('click', toggleSidebar);
111
+ btn._isBound = true;
112
+ }
113
+ });
114
+
115
+ if (closeBtn && !closeBtn._isBound) {
116
+ closeBtn.addEventListener('click', toggleSidebar);
117
+ closeBtn._isBound = true;
118
+ }
119
+
120
+ if (overlay && !overlay._isBound) {
121
+ overlay.addEventListener('click', toggleSidebar);
122
+ overlay._isBound = true;
123
+ }
124
+ }
125
+ }
126
+
127
+ window.customElements.define('liqpay-component', LiqPayComponent);
@@ -0,0 +1,81 @@
1
+ liqpay-component {
2
+ #liqpay-container {
3
+ background: #eff1f3;
4
+ }
5
+
6
+ .liqpay-sidebar {
7
+ &__overlay {
8
+ position: fixed;
9
+ top: 0;
10
+ left: 0;
11
+ width: 100%;
12
+ height: 100%;
13
+ background: rgba(0, 0, 0, 0);
14
+ z-index: 51;
15
+ transition: 0.5s;
16
+ pointer-events: none;
17
+ }
18
+
19
+ &__overlay.visible {
20
+ background: rgba(0, 0, 0, 0.7);
21
+ pointer-events: all;
22
+ }
23
+
24
+ &__wrapper {
25
+ padding: 0 20px 20px 20px;
26
+ height: 100%;
27
+ width: 450px;
28
+ position: fixed;
29
+ top: 0;
30
+ right: 0;
31
+ background: white;
32
+ z-index: 52;
33
+ user-select: none;
34
+ visibility: hidden;
35
+ overflow-x: hidden;
36
+ transform: translateX(100%);
37
+ transition: transform 0.5s ease, visibility 0s 0.5s;
38
+ }
39
+
40
+ &__wrapper.open {
41
+ visibility: visible;
42
+ transform: translateX(0);
43
+ transition: transform 0.5s ease, visibility 0s;
44
+ }
45
+
46
+ &__header {
47
+ position: relative;
48
+ display: flex;
49
+ justify-content: center;
50
+ align-items: center;
51
+ padding: 18px 0;
52
+ font-size: 22px;
53
+ font-weight: 600;
54
+ color: #1F1F1F;
55
+ }
56
+
57
+ &__close-icon {
58
+ position: absolute;
59
+ top: 38%;
60
+ right: 15px;
61
+ cursor: pointer;
62
+ }
63
+ }
64
+
65
+ .pay-button {
66
+ &__button {
67
+ padding: 10px 30px;
68
+ font-size: 16px;
69
+ font-weight: 600500;
70
+ background: white;
71
+ border-radius: 7px;
72
+ border: 2px solid black;
73
+ transition: all 0.3s ease-in-out;
74
+ cursor: pointer;
75
+ }
76
+ }
77
+ }
78
+
79
+ body.no-scroll {
80
+ overflow: hidden;
81
+ }
@@ -178,13 +178,13 @@ class MasonryGallery extends GHComponent {
178
178
 
179
179
  const promise = new Promise((res, rej) => {
180
180
  const img = document.createElement('img');
181
- img.setAttribute('src', imageSrc);
181
+ img.setAttribute('src', typeof(+imageSrc) === 'number' ? `https://gudhub.com/userdata/35113/${imageSrc}.jpg` : imageSrc);
182
182
  img.setAttribute('alt', imageAlt);
183
183
  img.setAttribute('title', imageTitle);
184
184
 
185
185
  if (fullImageSrc) {
186
186
  img.classList.add('open-modal');
187
- img.setAttribute('data-modal-image', fullImageSrc);
187
+ img.setAttribute('data-modal-image', typeof(+imageSrc) === 'number' ? `https://gudhub.com/userdata/35113/${fullImageSrc}.jpg` : fullImageSrc);
188
188
  }
189
189
 
190
190
  img.setAttribute('data-image-loading', 'true');
@@ -51,8 +51,15 @@ class CanonicalComponent extends GHComponent {
51
51
  const getCurrentChapter = await window?.getCurrentChapter();
52
52
  const currentChapter = getCurrentChapter ? getCurrentChapter : 'pages';
53
53
 
54
- let ids = await super.findIds(currentChapter);
55
- await this.findCanonical(ids.appId, ids.itemId, false);
54
+ let slug = false;
55
+
56
+ // this code fix problem with blog pagination page ("/blog/page/${index}"), findIds was trying to search item with "slug", but as we know paginaton slug is computed (doesnt exist in gudhub)
57
+ if (chapter == 'pages' && path.includes("/blog/page/")) {
58
+ slug = "/blog/";
59
+ }
60
+
61
+ let ids = await super.findIds(currentChapter, slug);
62
+ await this.findCanonical(ids.appId, ids.itemId, slug);
56
63
  }
57
64
  }
58
65
 
@@ -56,8 +56,15 @@ class MetaTag extends GHComponent {
56
56
  const getCurrentChapter = await window?.getCurrentChapter();
57
57
  const currentChapter = getCurrentChapter ? getCurrentChapter : 'pages';
58
58
 
59
- let ids = await super.findIds(currentChapter);
60
- await this.addTag(ids.appId, ids.itemId, false, currentChapter);
59
+ let slug = false;
60
+
61
+ // this code fix problem with blog pagination page ("/blog/page/${index}"), findIds was trying to search item with "slug", but as we know paginaton slug is computed (doesnt exist in gudhub)
62
+ if (chapter == 'pages' && path.includes("/blog/page/")) {
63
+ slug = "/blog/";
64
+ }
65
+
66
+ let ids = await super.findIds(currentChapter, slug);
67
+ await this.addTag(ids.appId, ids.itemId, slug, currentChapter);
61
68
  }
62
69
  }
63
70
  }