@customerjourney/cj-linkin-bio 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/linkinbio.png ADDED
Binary file
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@customerjourney/cj-linkin-bio",
3
+ "version": "1.5.1",
4
+ "description": "link in bio component of the CustomerJourneyJS project",
5
+ "main": "dist/index.js",
6
+ "module": "src/index.js",
7
+ "scripts": {
8
+ "prod": "esbuild src/index.js --bundle --minify --outfile=dist/index.min.js",
9
+ "build": "esbuild src/index.js --bundle --outfile=dist/index.js",
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/antoniofregoso/cj-linkin-bio.git"
15
+ },
16
+ "author": "Antonio Fregoso <antoniofregoso@protonmail.com>",
17
+ "license": "GPL-3.0-or-later",
18
+ "devDependencies": {
19
+ "esbuild": "^0.20.1"
20
+ },
21
+ "dependencies": {
22
+ "@customerjourney/bj-core": "^1.0.1",
23
+ "@fortawesome/fontawesome-svg-core": "^6.5.2",
24
+ "@fortawesome/free-brands-svg-icons": "^6.5.2",
25
+ "@fortawesome/free-solid-svg-icons": "^6.5.2"
26
+ },
27
+ "bugs": {
28
+ "url": "https://github.com/antoniofregoso/cj-linkin-bio.git/issues"
29
+ },
30
+ "homepage": "https://customerjourney.ninja/documentation/linkin-bio/",
31
+ "keywords": [
32
+ "vanilla-javascripts",
33
+ "link in bio",
34
+ "funnels",
35
+ "touchpoints"
36
+ ]
37
+ }
@@ -0,0 +1,68 @@
1
+ import { AppElement } from "@customerjourney/cj-core";
2
+ import { Remarkable } from "remarkable";
3
+
4
+
5
+ export class AboutMe extends AppElement {
6
+
7
+ #default = {
8
+ context:{
9
+ lang:"en"
10
+ }
11
+ };
12
+
13
+
14
+ constructor(props={}){
15
+ super();
16
+ this.eventName = "user:click-modal-box";
17
+ this.state =this.initState(this.#default,props);
18
+ this.getAttribute("id")||this.setAttribute("id",this.state.id||`component-${Math.floor(Math.random() * 100)}`);
19
+ this.md = new Remarkable();
20
+ }
21
+
22
+ static get observedAttributes() {
23
+ return ["active"];
24
+ }
25
+
26
+ attributeChangedCallback(name, old, now) {
27
+ console.log(name, old, now)
28
+ if (name=='active'&&now==='1'){
29
+ this.querySelector('.modal').classList.add('is-active')
30
+ }
31
+ }
32
+
33
+ handleEvent(event){
34
+ if (event.type === "click") {
35
+ if (event.target.ariaLabel==='close'){
36
+ this.querySelector(".modal").classList.remove("is-active");
37
+ this.removeAttribute('active');
38
+ }
39
+ }
40
+ }
41
+
42
+ #getContent(){
43
+ return /*HTML*/`
44
+ <div class="modal-card">
45
+ <header class="modal-card-head">
46
+ <p class="modal-card-title">${this.state.title?.text[this.state.context.lang]}</p>
47
+ <button class="delete" aria-label="close"></button>
48
+ </header>
49
+ <section class="modal-card-body content">
50
+ ${this.md.render(this.state.content?.text[this.state.context.lang])}
51
+ </section>
52
+ </div>
53
+ `;
54
+ }
55
+
56
+
57
+ render(){this.innerHTML = /* html */`
58
+ <div class="modal">
59
+ <div class="modal-background"></div>
60
+ ${this.#getContent()}
61
+ </div>
62
+ `;
63
+ this.addEvents();
64
+ }
65
+
66
+ }
67
+
68
+ customElements.define("about-me", AboutMe)
@@ -0,0 +1,242 @@
1
+ import { AppElement } from "@customerjourney/cj-core";
2
+ import { icon } from "@fortawesome/fontawesome-svg-core";
3
+ import { faEnvelope, faCircleCheck, faEllipsisVertical} from '@fortawesome/free-solid-svg-icons';
4
+ import { faSquareXTwitter, faSquareFacebook, faSquareThreads, faSquareInstagram, faYoutube, faLinkedin, faVk,
5
+ faDiscord, faTwitch, faTiktok, faSquareWhatsapp, faSquareGithub, faSquareGitlab} from '@fortawesome/free-brands-svg-icons';
6
+
7
+ export class LinkinBio extends AppElement {
8
+ #default = {
9
+ cardsWidth:4,
10
+ buttons:[]
11
+ };
12
+
13
+ /**
14
+ *
15
+ * @param {Object} state - {props:{...}, context:{...}}
16
+ */
17
+ constructor(state={}){
18
+ super();
19
+ this.eventName = "user:click-linkin-bio";
20
+ this.state =this.initState(this.#default,state);
21
+ this.getAttribute("id")||this.setAttribute("id",this.state.id||`component-${Math.floor(Math.random() * 100)}`);
22
+ }
23
+
24
+ #ok = icon(faCircleCheck, {classes: ['fa-1x', 'has-text-link']}).html[0];
25
+
26
+ handleEvent(event) {
27
+ if(this.state?.eventName!=undefined){
28
+ this.eventName = this.state.eventName
29
+ }
30
+ if (event.type === "click") {
31
+ if (event.target.tagName==='path'||event.target.tagName==='svg'||event.target.tagName==='P'&&event.target.classList.contains( 'option' )){
32
+ const bjClick = new CustomEvent(this.eventName,{
33
+ detail:{link:event.target.closest('p').dataset.share, type:'share', source:event.target.closest('p').dataset.source},
34
+ bubbles: true,
35
+ composed: true
36
+ });
37
+ this.dispatchEvent(bjClick);
38
+ }else if (event.target.tagName==='IMG'||event.target.tagName==='P'&&event.target.classList.contains( 'action' )){
39
+ const bjClick = new CustomEvent(this.eventName,{
40
+ detail:{source:event.target.closest('BUTTON').dataset.source, type:'action'},
41
+ bubbles: true,
42
+ composed: true
43
+ });
44
+ this.dispatchEvent(bjClick);
45
+ }else if(event.target.classList.contains( 'lang' )){
46
+ const bjClick = new CustomEvent(this.eventName,{
47
+ detail:{source:event.target.id.slice(4), type:'lang'},
48
+ bubbles: true,
49
+ composed: true
50
+ });
51
+ this.dispatchEvent(bjClick);
52
+ }
53
+ }
54
+ }
55
+
56
+ addEvents(){
57
+ let buttons = this.querySelectorAll("button");
58
+ if (buttons.length>0){
59
+ buttons.forEach((item)=>{
60
+ item.addEventListener("click",this)
61
+ });
62
+ };
63
+ let actions = this.querySelectorAll(".option");
64
+ if (actions.length>0){
65
+ actions.forEach((item)=>{
66
+ item.addEventListener("click",this)
67
+ });
68
+ };
69
+ if (this.state.i18n?.lang!=undefined){
70
+ Object.entries(this.state.i18n.lang).forEach(([key, value])=>{
71
+ this.querySelector(`#btn-${key}`).addEventListener("click",this)
72
+ });
73
+ }
74
+ }
75
+
76
+ #getSocialBar(){
77
+ let iconClasses = {classes: ['fa-2x', this.state.socialBar?.iconsColor!=undefined?this.state.socialBar.iconsColor:'has-text-white']};
78
+ let icons = ''
79
+ if(this.state.socialBar?.networks.length>0){
80
+ this.state.socialBar?.networks.forEach(el=>{
81
+ if (el.includes('x.com')){
82
+ icons += `<a class="p-1" href="${el}">${icon(faSquareXTwitter, iconClasses).html[0]}</a>`
83
+ }else if (el.includes('threads')){
84
+ icons += `<a class="p-1" href="${el}">${icon(faSquareThreads, iconClasses).html[0]}</a>`
85
+ }else if (el.includes('instagram')){
86
+ icons += `<a class="p-1" href="${el}">${icon(faSquareInstagram, iconClasses).html[0]}</a>`
87
+ }else if (el.includes('facebook')){
88
+ icons += `<a class="p-1" href="${el}">${icon(faSquareFacebook, iconClasses).html[0]}</a>`
89
+ }else if (el.includes('youtube')){
90
+ icons += `<a class="p-1" href="${el}">${icon(faYoutube, iconClasses).html[0]}</a>`
91
+ }else if (el.includes('linkedin')){
92
+ icons += `<a class="p-1" href="${el}">${icon(faLinkedin, iconClasses).html[0]}</a>`
93
+ }else if (el.includes('vk')){
94
+ icons += `<a class="p-1" href="${el}">${icon(faVk, iconClasses).html[0]}</a>`
95
+ }else if (el.includes('discord')){
96
+ icons += `<a class="p-1" href="${el}">${icon(faDiscord, iconClasses).html[0]}</a>`
97
+ }else if (el.includes('twitch')){
98
+ icons += `<a class="p-1" href="${el}">${icon(faTwitch, iconClasses).html[0]}</a>`
99
+ }else if (el.includes('tiktok')){
100
+ icons += `<a class="p-1" href="${el}">${icon(faTiktok, iconClasses).html[0]}</a>`
101
+ }else if (el.includes('whatsapp')){
102
+ icons += `<a class="p-1" href="${el}">${icon(faSquareWhatsapp, iconClasses).html[0]}</a>`
103
+ }else if (el.includes('github')){
104
+ icons += `<a class="p-1" href="${el}">${icon(faSquareGithub, iconClasses).html[0]}</a>`
105
+ }else if (el.includes('gitlab')){
106
+ icons += `<a class="p-1" href="${el}">${icon(faSquareGitlab, iconClasses).html[0]}</a>`
107
+ }else if (el.includes('mailto:')){
108
+ icons += `<a class="p-1" href="${el}">${icon(faEnvelope, iconClasses).html[0]}</a>`
109
+ }
110
+ });
111
+ }
112
+
113
+ return /* html */`
114
+ <div class="card" style="box-shadow: none; background-color:transparent;">
115
+ <div class="card-content p-1">
116
+ <div class="media">
117
+ <div class="media-content pt-3" style="height:48px">
118
+ ${icons}
119
+ </div>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ `
124
+ }
125
+
126
+ #getLang(){
127
+ let lngButtons = ``;
128
+ if(this.state.i18n?.lang!=undefined){
129
+ Object.entries(this.state.i18n.lang).forEach(([key, value])=>{
130
+ let focus = ['button', 'lang'];
131
+ if (key === this.state.context.lang ){
132
+ if (this.state.i18n?.selectedClassList!=undefined){
133
+ lngButtons += `<button id="btn-${key}" ${this.getClasses(focus, this.state.i18n?.selectedClassList)}>${value}</button>`
134
+ }else {
135
+ focus.push('is-focused')
136
+ lngButtons += `<button id="btn-${key}" ${this.getClasses(focus, this.state.i18n?.classList)}>${value}</button>`
137
+ }
138
+ focus.push('is-focused')
139
+ }else {
140
+ lngButtons += `<button id="btn-${key}" ${this.getClasses(focus, this.state.i18n?.classList)}>${value}</button>`
141
+ }
142
+
143
+ });
144
+ };
145
+ return lngButtons;
146
+ }
147
+
148
+ #geti18n(){
149
+ return /* html */`
150
+ <div class="buttons buttons are-small is-centered">
151
+ ${this.#getLang()}
152
+ </div>
153
+ `
154
+ }
155
+
156
+ #getLinks(){
157
+ let links = ``;
158
+ if(this.state.links?.cards.length>0){
159
+ this.state.links.cards.forEach(el=>{
160
+ let link = /* html */ `
161
+ <div ${typeof el.id === 'undefined'?``:`id="${el.id}" style="cursor: pointer;" `} ${this.getClasses(["card","mt-5"], this.state.links.classList)} ${this.setAnimation(this.state.links.animation)}>
162
+ <div class="card-content p-2">
163
+ <div class="media">
164
+ ${el.imgSrc!=undefined?`
165
+ <figure class="media-left">
166
+ ${el.href===undefined?`<button style="width:100%" data-source="${el.id}">`:`<a href="${el.href}">`}
167
+ <p class="image is-48x48 action">
168
+ <img class="action" src="${el.imgSrc}" />
169
+ </p>${el.href===undefined?`</button>`:`</a>`}
170
+ `:''}
171
+ </figure>
172
+ <div class="media-content pt-3" style="min-height:48px">
173
+ ${el.href===undefined?`<button style="width:100%" data-source="${el.id}">`:`<a href="${el.href}" style="color: inherit; text-decoration: none;">`}
174
+ <p id="content-${el.id}" class="is-6 action">${el.text[this.state.context.lang]}</p>
175
+ ${el.href===undefined?`</button>`:`</a>`}
176
+ </div>
177
+ <figure class="media-right pt-1">
178
+ <p class="icon is-48x48 pt-3 option" data-source="content-${el.id}" data-share="${el.href===undefined?'/':el.href}">
179
+ ${icon(faEllipsisVertical).html[0]}
180
+ </p>
181
+ </figure>
182
+ </div>
183
+ </div>
184
+ </div>
185
+ `
186
+ links += link;
187
+ if (typeof el.id != 'undefined'){
188
+ this.state.buttons.push(el.id)
189
+ }
190
+ })
191
+
192
+ }else{
193
+ console.error('No links to render');
194
+ }
195
+ return links;
196
+ }
197
+
198
+ render(){
199
+
200
+ console.log('state', this.state);
201
+ this.innerHTML = /* html */`
202
+ <div class="columns is-centered">
203
+ <div class="column is-5 has-text-centered px-5" >
204
+ <figure class="image is-96x96 is-inline-block mt-6 " ${this.setAnimation(this.state.avatar?.animation)}>
205
+ <img ${this.getClasses([], this.state.avatar?.classList)} src="${this.state.avatar?.src}">
206
+ </figure>
207
+ <div class="card" style="box-shadow: none; background-color:transparent;">
208
+ <div class="card-content p-1">
209
+ <div class="media">
210
+ <div class="media-content pt-3" style="min-height:44px">
211
+ <p ${this.getClasses(["title","is-5","mb-0"], this.state.title?.classList)} ${this.setAnimation(this.state.title?.animation)}>${this.state.title?.text[this.state.context.lang]}${this.state.verified===true?`${this.#ok}`:``}</p>
212
+ <p ${this.getClasses([], this.state.subtitle?.classList)} ${this.setAnimation(this.state.subtitle?.animation)} >${this.state.subtitle?.text[this.state.context.lang]}</p>
213
+ </div>
214
+ </div>
215
+ </div>
216
+ </div>
217
+ ${this.state.i18n?.up===true?this.#geti18n():``}
218
+ ${this.state.socialBar?.up===true?this.#getSocialBar():``}
219
+ ${this.#getLinks()}
220
+ ${this.state.socialBar?.up!=true?this.#getSocialBar():``}
221
+ ${this.state.i18n?.up!=true?this.#geti18n():``}
222
+ ${this.state.footer?.src===undefined?``:`
223
+ <div class="card mt-1" style="box-shadow: none; background-color:transparent;">
224
+ <div class="card-content">
225
+ <div class="media">
226
+ <div class="media-content has-text-centered " >
227
+ <figure class="image is-inline-block" style="width:100px">
228
+ <span ${this.getClasses([], this.state.footer?.message?.classList)}>${this.state.footer?.message?.text[this.state.context.lang]}</span>
229
+ ${this.state.footer?.url===undefined?``:`<a href="${this.state.footer.url}">`}<img src="${this.state.footer.src}" alt="${this.state.footer?.alt[this.state.context.lang]}">${this.state.footer?.url===undefined?``:`</a>`}
230
+ </figure>
231
+ </div>
232
+ </div>
233
+ </div>
234
+ </div>`}
235
+ </div>
236
+ </div>
237
+ `;
238
+ this.addEvents();
239
+ }
240
+ }
241
+
242
+ customElements.define("linkin-bio", LinkinBio)
@@ -0,0 +1,87 @@
1
+ import { AppElement, slugify } from "@customerjourney/cj-core";
2
+ import { icon } from "@fortawesome/fontawesome-svg-core";
3
+ import { faEnvelope, faShare } from '@fortawesome/free-solid-svg-icons';
4
+ import {faSquareXTwitter, faSquareFacebook, faSquareThreads, faLinkedin, faSquareWhatsapp, faTelegram} from '@fortawesome/free-brands-svg-icons';
5
+
6
+ export class ShareLink extends AppElement {
7
+
8
+ #default = {
9
+ context:{
10
+ lang:"en"
11
+ },
12
+ share:{
13
+ en:"Share on",
14
+ es:"Compartir en",
15
+ fr:"Partager sur"
16
+ }
17
+ };
18
+
19
+
20
+ constructor(props={}){
21
+ super();
22
+ this.eventName = "user:click-modal-box";
23
+ this.state =this.initState(this.#default,props);
24
+ this.getAttribute("id")||this.setAttribute("id",this.state.id||`component-${Math.floor(Math.random() * 100)}`);
25
+ }
26
+
27
+ static get observedAttributes() {
28
+ return ["active"];
29
+ }
30
+
31
+ attributeChangedCallback(name, old, now) {
32
+ if (name=='active'&&now==='1'){
33
+ this.target = this.getAttribute("target");
34
+ this.title = slugify(document.querySelector(`#${this.getAttribute("source")}`).textContent);
35
+ this.render();
36
+ this.querySelector('.modal').classList.add('is-active');
37
+ }
38
+ }
39
+
40
+ handleEvent(event){
41
+ if (event.type === "click") {
42
+ if (event.target.ariaLabel==='close'){
43
+ this.querySelector(".modal").classList.remove("is-active");
44
+ this.removeAttribute('active');
45
+ }
46
+ }
47
+
48
+ }
49
+
50
+ #getContent(){
51
+ return /*HTML*/`
52
+ <div class="modal-card">
53
+ <header class="modal-card-head">
54
+ <p class="modal-card-title">${this.state.title?.text[this.state.context.lang]}</p>
55
+ <button class="delete" aria-label="close"></button>
56
+ </header>
57
+ <section class="modal-card-body">
58
+ <aside class="menu">
59
+ <ul class="menu-list is-size-5">
60
+ <li ><a href="https://www.linkedin.com/shareArticle?mini=true&url=${this.target}&title=${this.title}">${icon(faLinkedin).html[0]} ${this.state.share[this.state.context.lang]} Linkedin <span class="is-pulled-right">${icon(faShare).html[0]}</span></a></li>
61
+ <li><a href="https://x.com/intent/tweet?text=${this.title}&url=${this.target}">${icon(faSquareXTwitter).html[0]} ${this.state.share[this.state.context.lang]} X <span class="is-pulled-right">${icon(faShare).html[0]}</span></a></li>
62
+ <li><a href="https://www.facebook.com/sharer/sharer.php?u=${this.target}">${icon(faSquareFacebook).html[0]} ${this.state.share[this.state.context.lang]} Facebook <span class="is-pulled-right">${icon(faShare).html[0]}</span></a></li>
63
+ <li><a href="https://api.whatsapp.com/send?text=${this.title}%20${this.target}">${icon(faSquareWhatsapp).html[0]} ${this.state.share[this.state.context.lang]} Whatsapp <span class="is-pulled-right">${icon(faShare).html[0]}</span></a></li>
64
+ <li><a href="https://t.me/share/url?url=${this.target}&text=${this.title}">${icon(faTelegram).html[0]} ${this.state.share[this.state.context.lang]} Telegram <span class="is-pulled-right">${icon(faShare).html[0]}</span></a></li>
65
+ <li><a href="mailto:?subject=${this.title}&body=${this.target}">${icon(faEnvelope).html[0]} ${this.state.share[this.state.context.lang]} eMail <span class="is-pulled-right">${icon(faShare).html[0]}</span></a></li>
66
+ </ul>
67
+ </aside>
68
+ </section>
69
+ </div>
70
+ `;
71
+ }
72
+
73
+
74
+ render(){
75
+ this.innerHTML = /* html */`
76
+ <div class="modal">
77
+ <div class="modal-background"></div>
78
+ ${this.#getContent()}
79
+ </div>
80
+ `;
81
+ this.addEvents();
82
+
83
+ }
84
+
85
+ }
86
+
87
+ customElements.define("share-link", ShareLink)
package/src/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './components/ShareLink';
2
+ export * from './components/LinkinBio';
3
+ export * from './components/AboutMe';