@dotrino/support 0.6.0 → 0.7.0

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/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @dotrino/support
2
2
 
3
+ > **Parte del ecosistema [Dotrino](https://dotrino.com).** Misión: aplicaciones que resuelven problemas comunes, respetando tu privacidad — sin anuncios, sin cookies, sin rastreo de datos, sin vender tu identidad a nadie.
4
+
3
5
  Web Component (`<dotrino-support>`) con un **modal de soporte/donaciones**
4
6
  reutilizable por **cualquier app del ecosistema Dotrino**: las hechas en
5
7
  Vue 3 y las vanilla (HTML/JS), porque es un *custom element* estándar.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/support",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Web Component (custom element) de modal de soporte/donaciones reutilizable por cualquier app del ecosistema Dotrino. Autohosteado, sin JS de terceros ni cookies.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -44,6 +44,7 @@ const I18N = {
44
44
  'Si esta herramienta te resulta útil, puedes dar una pequeña contribución. Las apps del ecosistema Dotrino son gratuitas y autohosteadas. ¡Gracias!',
45
45
  close: 'Cerrar',
46
46
  defaultLink: 'Donar',
47
+ contact: 'Contacto',
47
48
  hint: 'Donar/Compartir',
48
49
  shareHeading: 'Compartir',
49
50
  shareText: '¡Mira esto!',
@@ -64,6 +65,7 @@ const I18N = {
64
65
  'If you find this tool useful, you can make a small contribution. The Dotrino ecosystem apps are free and self-hosted. Thank you!',
65
66
  close: 'Close',
66
67
  defaultLink: 'Donate',
68
+ contact: 'Contact',
67
69
  hint: 'Donate/Share',
68
70
  shareHeading: 'Share',
69
71
  shareText: 'Check this out!',
@@ -340,6 +342,19 @@ const STYLE = `
340
342
  .link-ico { display: inline-flex; width: 1.4rem; height: 1.4rem; }
341
343
  .link-ico img { width: 100%; height: 100%; display: block; object-fit: contain; }
342
344
 
345
+ /* Botón de Contacto (opt-in), arriba de las donaciones. Contorno para
346
+ diferenciarlo del botón lleno de "Donar". */
347
+ .contact-cta {
348
+ display: inline-flex; align-items: center; justify-content: center;
349
+ min-width: 220px; margin: 0 auto 0.9rem; padding: 0.7rem 1.4rem;
350
+ font-family: inherit; font-weight: 600; font-size: 0.95rem;
351
+ border-radius: 50px; cursor: pointer;
352
+ background: transparent; color: var(--ds-accent, #3498db);
353
+ border: 1.5px solid var(--ds-accent, #3498db);
354
+ transition: all 0.25s ease;
355
+ }
356
+ .contact-cta:hover { background: var(--ds-accent, #3498db); color: #fff; transform: translateY(-2px); box-shadow: 0 6px 20px rgba(52, 152, 219, 0.3); }
357
+
343
358
  /* Sección de compartir */
344
359
  .share {
345
360
  margin-top: 1.5rem;
@@ -477,7 +492,7 @@ function recordAppOpen(appId) {
477
492
 
478
493
  class DotrinoSupport extends HTMLElement {
479
494
  static get observedAttributes() {
480
- return ['href', 'links', 'cta', 'no-trigger', 'heading', 'message', 'lang', 'variant', 'inline', 'hint', 'coin', 'no-bubble', 'bubble-timeout', 'share-url', 'share-text', 'no-share', 'repo', 'bug-href', 'discord', 'app', 'no-count']
495
+ return ['href', 'links', 'cta', 'no-trigger', 'heading', 'message', 'lang', 'variant', 'inline', 'hint', 'coin', 'no-bubble', 'bubble-timeout', 'share-url', 'share-text', 'no-share', 'repo', 'bug-href', 'discord', 'app', 'no-count', 'contact', 'contact-label']
481
496
  }
482
497
 
483
498
  constructor() {
@@ -731,6 +746,15 @@ class DotrinoSupport extends HTMLElement {
731
746
  )
732
747
  .join('')
733
748
 
749
+ // Botón de Contacto (opt-in con el atributo `contact`), ARRIBA de las
750
+ // donaciones. No abre un enlace: dispara `cc-support-contact` (la app decide
751
+ // qué hacer, p. ej. abrir su formulario) y cierra el modal.
752
+ const wantsContact = this.hasAttribute('contact')
753
+ const contactLabel = this.getAttribute('contact-label') || t.contact
754
+ const contactHtml = wantsContact
755
+ ? `<button type="button" class="contact-cta" part="contact">${escapeHtml(contactLabel)}</button>`
756
+ : ''
757
+
734
758
  const wantsShare = !this.hasAttribute('no-share')
735
759
  const shareHtml = wantsShare
736
760
  ? `<div class="share" part="share">
@@ -771,6 +795,7 @@ class DotrinoSupport extends HTMLElement {
771
795
  <button type="button" class="close" aria-label="${escapeAttr(t.close)}">&times;</button>
772
796
  <h2 class="heading">${escapeHtml(heading)}</h2>
773
797
  <p class="message">${escapeHtml(message)}</p>
798
+ ${contactHtml}
774
799
  <div class="links">${linksHtml}</div>
775
800
  ${shareHtml}
776
801
  ${discordHtml}
@@ -792,6 +817,15 @@ class DotrinoSupport extends HTMLElement {
792
817
  )
793
818
  this.shadowRoot.querySelector('.close').addEventListener('click', () => this.close())
794
819
 
820
+ // Botón de Contacto: cierra el modal y avisa a la app (que abre su formulario).
821
+ const contactBtn = this.shadowRoot.querySelector('.contact-cta')
822
+ if (contactBtn) {
823
+ contactBtn.addEventListener('click', () => {
824
+ this.close()
825
+ this.dispatchEvent(new CustomEvent('cc-support-contact', { bubbles: true, composed: true }))
826
+ })
827
+ }
828
+
795
829
  // Compartir: el botón sin href (Instagram) copia el enlace al portapapeles.
796
830
  this.shadowRoot.querySelectorAll('.share-btn[data-share]').forEach((btn) => {
797
831
  btn.addEventListener('click', () => this._copyShareUrl())