@product7/feedback-sdk 1.0.5 → 1.0.7

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.
@@ -591,12 +591,14 @@
591
591
  theme: this.sdk.config.theme,
592
592
  boardId: this.sdk.config.boardId,
593
593
  autoShow: false,
594
+ showBackdrop: true,
594
595
  customStyles: {},
595
596
  ...options,
596
597
  };
597
598
 
598
599
  this.element = null;
599
- this.modalElement = null;
600
+ this.panelElement = null;
601
+ this.backdropElement = null;
600
602
  this.mounted = false;
601
603
  this.destroyed = false;
602
604
 
@@ -654,23 +656,47 @@
654
656
  return this;
655
657
  }
656
658
 
657
- openModal() {
659
+ openPanel() {
658
660
  this.state.isOpen = true;
659
- this._renderModal();
661
+ this._renderPanel();
662
+
663
+ requestAnimationFrame(() => {
664
+ if (this.panelElement) {
665
+ this.panelElement.classList.add('open');
666
+ }
667
+ if (this.backdropElement) {
668
+ this.backdropElement.classList.add('show');
669
+ }
670
+ });
660
671
  }
661
672
 
662
- closeModal() {
663
- this.state.isOpen = false;
664
- if (this.modalElement) {
665
- this.modalElement.remove();
666
- this.modalElement = null;
673
+ closePanel() {
674
+ if (this.panelElement) {
675
+ this.panelElement.classList.remove('open');
676
+ }
677
+ if (this.backdropElement) {
678
+ this.backdropElement.classList.remove('show');
667
679
  }
668
- this._resetForm();
680
+
681
+ setTimeout(() => {
682
+ this.state.isOpen = false;
683
+ if (this.panelElement && this.panelElement.parentNode) {
684
+ this.panelElement.parentNode.removeChild(this.panelElement);
685
+ this.panelElement = null;
686
+ }
687
+ if (this.backdropElement && this.backdropElement.parentNode) {
688
+ this.backdropElement.parentNode.removeChild(this.backdropElement);
689
+ this.backdropElement = null;
690
+ }
691
+ this._resetForm();
692
+ }, 300);
669
693
  }
670
694
 
671
695
  async submitFeedback() {
672
696
  if (this.state.isSubmitting) return;
673
697
 
698
+ this._hideError();
699
+
674
700
  try {
675
701
  this.state.isSubmitting = true;
676
702
  this._updateSubmitButton();
@@ -691,7 +717,7 @@
691
717
  const response = await this.apiService.submitFeedback(payload);
692
718
 
693
719
  this._showSuccessMessage();
694
- this.closeModal();
720
+ this.closePanel();
695
721
 
696
722
  this.sdk.eventBus.emit('feedback:submitted', {
697
723
  widget: this,
@@ -717,7 +743,7 @@
717
743
  if (this.destroyed) return;
718
744
 
719
745
  this.onDestroy();
720
- this.closeModal();
746
+ this.closePanel();
721
747
 
722
748
  if (this.element && this.element.parentNode) {
723
749
  this.element.parentNode.removeChild(this.element);
@@ -740,38 +766,46 @@
740
766
  }
741
767
 
742
768
  _bindMethods() {
743
- this.openModal = this.openModal.bind(this);
744
- this.closeModal = this.closeModal.bind(this);
769
+ this.openPanel = this.openPanel.bind(this);
770
+ this.closePanel = this.closePanel.bind(this);
745
771
  this.submitFeedback = this.submitFeedback.bind(this);
746
772
  }
747
773
 
748
- _renderModal() {
749
- if (this.modalElement) return;
774
+ _renderPanel() {
775
+ if (this.panelElement) return;
750
776
 
751
- this.modalElement = document.createElement('div');
752
- this.modalElement.className = `feedback-modal theme-${this.options.theme}`;
753
- this.modalElement.innerHTML = this._getModalHTML();
777
+ if (this.options.showBackdrop) {
778
+ this.backdropElement = document.createElement('div');
779
+ this.backdropElement.className = 'feedback-panel-backdrop';
780
+ document.body.appendChild(this.backdropElement);
754
781
 
755
- document.body.appendChild(this.modalElement);
756
- this._attachModalEvents();
782
+ this.backdropElement.addEventListener('click', this.closePanel);
783
+ }
784
+
785
+ this.panelElement = document.createElement('div');
786
+ this.panelElement.className = `feedback-panel theme-${this.options.theme}`;
787
+ this.panelElement.innerHTML = this._getPanelHTML();
788
+
789
+ document.body.appendChild(this.panelElement);
790
+ this._attachPanelEvents();
757
791
 
758
- const firstInput = this.modalElement.querySelector('input, textarea');
792
+ const firstInput = this.panelElement.querySelector('input, textarea');
759
793
  if (firstInput) {
760
- setTimeout(() => firstInput.focus(), 100);
794
+ setTimeout(() => firstInput.focus(), 350);
761
795
  }
762
796
  }
763
797
 
764
- _getModalHTML() {
798
+ _getPanelHTML() {
765
799
  return `
766
- <div class="feedback-modal-overlay">
767
- <div class="feedback-modal-content">
768
- <div class="feedback-modal-header">
769
- <h3>Send Feedback</h3>
770
- <button class="feedback-modal-close" type="button">&times;</button>
771
- </div>
800
+ <div class="feedback-panel-content">
801
+ <div class="feedback-panel-header">
802
+ <h3>Send Feedback</h3>
803
+ <button class="feedback-panel-close" type="button" aria-label="Close">&times;</button>
804
+ </div>
805
+ <div class="feedback-panel-body">
772
806
  <form class="feedback-form">
773
807
  <div class="feedback-form-group">
774
- <label for="feedback-title-${this.id}">Title</label>
808
+ <label for="feedback-title-${this.id}">Title (optional)</label>
775
809
  <input
776
810
  type="text"
777
811
  id="feedback-title-${this.id}"
@@ -785,62 +819,59 @@
785
819
  <textarea
786
820
  id="feedback-content-${this.id}"
787
821
  name="content"
788
- placeholder="Tell us more about your feedback..."
822
+ placeholder="Tell us what you think..."
789
823
  required
790
824
  >${this.state.content}</textarea>
791
825
  </div>
826
+ <div class="feedback-error" role="alert"></div>
792
827
  <div class="feedback-form-actions">
793
- <button type="button" class="feedback-btn feedback-btn-cancel">Cancel</button>
794
828
  <button type="submit" class="feedback-btn feedback-btn-submit">
795
829
  ${this.state.isSubmitting ? 'Sending...' : 'Send Feedback'}
796
830
  </button>
797
831
  </div>
798
- <div class="feedback-error" style="display: none;"></div>
799
832
  </form>
800
833
  </div>
801
834
  </div>
802
835
  `;
803
836
  }
804
837
 
805
- _attachModalEvents() {
806
- const modal = this.modalElement;
807
-
808
- modal
809
- .querySelector('.feedback-modal-close')
810
- .addEventListener('click', this.closeModal);
811
- modal
812
- .querySelector('.feedback-btn-cancel')
813
- .addEventListener('click', this.closeModal);
814
- modal
815
- .querySelector('.feedback-modal-overlay')
816
- .addEventListener('click', (e) => {
817
- if (e.target === e.currentTarget) {
818
- this.closeModal();
819
- }
820
- });
838
+ _attachPanelEvents() {
839
+ const panel = this.panelElement;
840
+
841
+ panel
842
+ .querySelector('.feedback-panel-close')
843
+ .addEventListener('click', this.closePanel);
821
844
 
822
- const form = modal.querySelector('.feedback-form');
845
+ const form = panel.querySelector('.feedback-form');
823
846
  form.addEventListener('submit', (e) => {
824
847
  e.preventDefault();
825
848
  this.submitFeedback();
826
849
  });
827
850
 
828
- modal
851
+ panel
829
852
  .querySelector('input[name="title"]')
830
853
  .addEventListener('input', (e) => {
831
854
  this.state.title = e.target.value;
832
855
  });
833
856
 
834
- modal
857
+ panel
835
858
  .querySelector('textarea[name="content"]')
836
859
  .addEventListener('input', (e) => {
837
860
  this.state.content = e.target.value;
838
861
  });
862
+
863
+ const handleEscape = (e) => {
864
+ if (e.key === 'Escape') {
865
+ this.closePanel();
866
+ document.removeEventListener('keydown', handleEscape);
867
+ }
868
+ };
869
+ document.addEventListener('keydown', handleEscape);
839
870
  }
840
871
 
841
872
  _updateSubmitButton() {
842
- if (this.modalElement) {
843
- const submitBtn = this.modalElement.querySelector('.feedback-btn-submit');
873
+ if (this.panelElement) {
874
+ const submitBtn = this.panelElement.querySelector('.feedback-btn-submit');
844
875
  if (submitBtn) {
845
876
  submitBtn.textContent = this.state.isSubmitting
846
877
  ? 'Sending...'
@@ -851,15 +882,21 @@
851
882
  }
852
883
 
853
884
  _showError(message) {
854
- if (this.modalElement) {
855
- const errorElement = this.modalElement.querySelector('.feedback-error');
856
- errorElement.textContent = message;
857
- errorElement.style.display = 'block';
858
- setTimeout(() => {
859
- if (errorElement) {
860
- errorElement.style.display = 'none';
861
- }
862
- }, 5000);
885
+ if (this.panelElement) {
886
+ const errorElement = this.panelElement.querySelector('.feedback-error');
887
+ if (errorElement) {
888
+ errorElement.textContent = message;
889
+ errorElement.classList.add('show');
890
+ }
891
+ }
892
+ }
893
+
894
+ _hideError() {
895
+ if (this.panelElement) {
896
+ const errorElement = this.panelElement.querySelector('.feedback-error');
897
+ if (errorElement) {
898
+ errorElement.classList.remove('show');
899
+ }
863
900
  }
864
901
  }
865
902
 
@@ -868,26 +905,29 @@
868
905
  notification.className = 'feedback-success-notification';
869
906
  notification.innerHTML = `
870
907
  <div class="feedback-success-content">
871
- <span>✓ Feedback submitted successfully!</span>
872
- <button class="feedback-success-close">&times;</button>
908
+ <div class="feedback-success-icon">✓</div>
909
+ <span>Feedback submitted successfully!</span>
910
+ <button class="feedback-success-close" aria-label="Close">&times;</button>
873
911
  </div>
874
912
  `;
875
913
 
876
914
  document.body.appendChild(notification);
877
915
 
878
- setTimeout(() => {
916
+ const closeBtn = notification.querySelector('.feedback-success-close');
917
+ const closeNotification = () => {
879
918
  if (notification.parentNode) {
880
- notification.parentNode.removeChild(notification);
919
+ notification.style.opacity = '0';
920
+ setTimeout(() => {
921
+ if (notification.parentNode) {
922
+ notification.parentNode.removeChild(notification);
923
+ }
924
+ }, 300);
881
925
  }
882
- }, 3000);
926
+ };
883
927
 
884
- notification
885
- .querySelector('.feedback-success-close')
886
- .addEventListener('click', () => {
887
- if (notification.parentNode) {
888
- notification.parentNode.removeChild(notification);
889
- }
890
- });
928
+ closeBtn.addEventListener('click', closeNotification);
929
+
930
+ setTimeout(closeNotification, 4000);
891
931
  }
892
932
 
893
933
  _resetForm() {
@@ -904,13 +944,21 @@
904
944
  `theme-${this.options.theme}`
905
945
  );
906
946
  }
907
- if (this.modalElement) {
908
- this.modalElement.className = this.modalElement.className.replace(
947
+ if (this.panelElement) {
948
+ this.panelElement.className = this.panelElement.className.replace(
909
949
  /theme-\w+/,
910
950
  `theme-${this.options.theme}`
911
951
  );
912
952
  }
913
953
  }
954
+
955
+ openModal() {
956
+ this.openPanel();
957
+ }
958
+
959
+ closeModal() {
960
+ this.closePanel();
961
+ }
914
962
  }
915
963
 
916
964
  class ButtonWidget extends BaseWidget {
@@ -940,7 +988,7 @@
940
988
 
941
989
  _attachEvents() {
942
990
  const button = this.element.querySelector('.feedback-trigger-btn');
943
- button.addEventListener('click', this.openModal);
991
+ button.addEventListener('click', this.openPanel);
944
992
 
945
993
  button.addEventListener('mouseenter', () => {
946
994
  if (!this.state.isSubmitting) {
@@ -1541,7 +1589,7 @@
1541
1589
  font-weight: 500;
1542
1590
  font-family: inherit;
1543
1591
  cursor: pointer;
1544
- transition: all 0.3s duration;
1592
+ transition: all 0.3s ease;
1545
1593
  color: white;
1546
1594
  background: #155EEF;
1547
1595
  box-shadow: 0 1px 2px 0 rgba(16, 24, 40, 0.05);
@@ -1562,109 +1610,133 @@
1562
1610
  outline-offset: 2px;
1563
1611
  }
1564
1612
 
1565
- .feedback-modal {
1613
+ /* Side Panel Styles */
1614
+ .feedback-panel {
1566
1615
  position: fixed;
1567
- top: 0;
1568
- left: 0;
1569
- right: 0;
1570
- bottom: 0;
1616
+ bottom: 80px;
1617
+ right: 24px;
1618
+ width: 420px;
1619
+ max-height: 500px;
1571
1620
  z-index: 1000000;
1572
- display: flex;
1573
- align-items: center;
1574
- justify-content: center;
1621
+ transform: translateX(calc(100% + 24px));
1622
+ transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
1575
1623
  font-family: inherit;
1576
1624
  }
1577
1625
 
1578
- .feedback-modal-overlay {
1579
- position: absolute;
1626
+ .feedback-panel.open {
1627
+ transform: translateX(0);
1628
+ }
1629
+
1630
+ .feedback-panel-backdrop {
1631
+ position: fixed;
1580
1632
  top: 0;
1581
1633
  left: 0;
1582
1634
  right: 0;
1583
1635
  bottom: 0;
1584
- background: rgba(0, 0, 0, 0.5);
1585
- display: flex;
1586
- align-items: center;
1587
- justify-content: center;
1636
+ background: rgba(0, 0, 0, 0.1);
1637
+ opacity: 0;
1638
+ transition: opacity 0.3s ease;
1639
+ pointer-events: none;
1640
+ z-index: 999999;
1588
1641
  }
1589
1642
 
1590
- .feedback-modal-content {
1643
+ .feedback-panel-backdrop.show {
1644
+ opacity: 1;
1645
+ pointer-events: auto;
1646
+ }
1647
+
1648
+ .feedback-panel-content {
1591
1649
  background: white;
1592
- border-radius: 8px;
1593
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
1594
- min-width: 460px;
1595
- max-width: 500px;
1596
- width: 100%;
1597
- padding: 16px;
1598
- max-height: 85vh;
1599
- overflow-y: hidden;
1600
- position: relative;
1650
+ height: 100%;
1651
+ display: flex;
1652
+ flex-direction: column;
1653
+ border-radius: 16px;
1654
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
1655
+ 0 10px 10px -5px rgba(0, 0, 0, 0.04),
1656
+ 0 0 0 1px rgba(0, 0, 0, 0.05);
1601
1657
  }
1602
1658
 
1603
- .feedback-modal.theme-dark .feedback-modal-content {
1659
+ .feedback-panel.theme-dark .feedback-panel-content {
1604
1660
  background: #1F2937;
1605
1661
  color: white;
1606
1662
  }
1607
1663
 
1608
- .feedback-modal-header {
1664
+ .feedback-panel-header {
1609
1665
  display: flex;
1610
1666
  align-items: center;
1611
1667
  justify-content: space-between;
1612
- padding: 16px;
1613
- border-bottom: 1px solid #D1D5DB;
1668
+ padding: 24px;
1669
+ border-bottom: 1px solid #E5E7EB;
1614
1670
  flex-shrink: 0;
1615
1671
  }
1616
1672
 
1617
- .feedback-modal.theme-dark .feedback-modal-header {
1673
+ .feedback-panel.theme-dark .feedback-panel-header {
1618
1674
  border-bottom-color: #374151;
1619
1675
  }
1620
1676
 
1621
- .feedback-modal-header h3 {
1677
+ .feedback-panel-header h3 {
1622
1678
  margin: 0;
1623
- font-size: 16px;
1679
+ font-size: 18px;
1624
1680
  font-weight: 600;
1681
+ color: #111827;
1625
1682
  }
1626
1683
 
1627
- .feedback-modal-close {
1684
+ .feedback-panel.theme-dark .feedback-panel-header h3 {
1685
+ color: white;
1686
+ }
1687
+
1688
+ .feedback-panel-close {
1628
1689
  background: none;
1629
1690
  border: none;
1630
1691
  font-size: 24px;
1631
1692
  cursor: pointer;
1632
1693
  color: #6B7280;
1633
- padding: 0;
1634
- width: 24px;
1635
- height: 24px;
1694
+ padding: 4px;
1695
+ width: 32px;
1696
+ height: 32px;
1636
1697
  display: flex;
1637
1698
  align-items: center;
1638
1699
  justify-content: center;
1639
- transition: all 0.3s ease;
1700
+ border-radius: 6px;
1701
+ transition: all 0.2s ease;
1640
1702
  }
1641
1703
 
1642
- .feedback-modal-close:hover {
1643
- color: #374151;
1704
+ .feedback-panel-close:hover {
1705
+ background: #F3F4F6;
1706
+ color: #111827;
1644
1707
  }
1645
1708
 
1646
- .feedback-modal-close:focus-visible {
1709
+ .feedback-panel-close:focus-visible {
1647
1710
  outline: 2px solid #155EEF;
1648
1711
  outline-offset: 2px;
1649
1712
  }
1650
1713
 
1651
- .feedback-modal.theme-dark .feedback-modal-close {
1714
+ .feedback-panel.theme-dark .feedback-panel-close {
1652
1715
  color: #9CA3AF;
1653
1716
  }
1654
1717
 
1655
- .feedback-modal.theme-dark .feedback-modal-close:hover {
1656
- color: #D1D5DB;
1718
+ .feedback-panel.theme-dark .feedback-panel-close:hover {
1719
+ background: #374151;
1720
+ color: white;
1721
+ }
1722
+
1723
+ .feedback-panel-body {
1724
+ flex: 1;
1725
+ overflow-y: auto;
1726
+ padding: 24px;
1657
1727
  }
1658
1728
 
1659
1729
  .feedback-form {
1660
- padding: 16px;
1730
+ display: flex;
1731
+ flex-direction: column;
1732
+ height: 100%;
1661
1733
  }
1662
1734
 
1663
1735
  .feedback-form-group {
1664
1736
  display: flex;
1665
1737
  flex-direction: column;
1666
- gap: 4px;
1667
- margin-bottom: 12px;
1738
+ gap: 8px;
1739
+ margin-bottom: 20px;
1668
1740
  }
1669
1741
 
1670
1742
  .feedback-form-group:last-child {
@@ -1678,19 +1750,19 @@
1678
1750
  color: #374151;
1679
1751
  }
1680
1752
 
1681
- .feedback-modal.theme-dark .feedback-form-group label {
1753
+ .feedback-panel.theme-dark .feedback-form-group label {
1682
1754
  color: #D1D5DB;
1683
1755
  }
1684
1756
 
1685
1757
  .feedback-form-group input {
1686
- height: 40px;
1758
+ height: 44px;
1687
1759
  width: 100%;
1688
- border-radius: 6px;
1760
+ border-radius: 8px;
1689
1761
  border: 1px solid #D1D5DB;
1690
- padding: 2px 12px;
1691
- font-size: 14px;
1762
+ padding: 10px 14px;
1763
+ font-size: 15px;
1692
1764
  font-weight: 400;
1693
- line-height: 1.25;
1765
+ line-height: 1.5;
1694
1766
  color: #1F2937;
1695
1767
  font-family: inherit;
1696
1768
  outline: none;
@@ -1698,13 +1770,13 @@
1698
1770
  }
1699
1771
 
1700
1772
  .feedback-form-group input::placeholder {
1701
- font-size: 14px;
1702
- color: #6B7280;
1773
+ font-size: 15px;
1774
+ color: #9CA3AF;
1703
1775
  }
1704
1776
 
1705
1777
  .feedback-form-group input:focus {
1706
- border-color: #84ADFF;
1707
- box-shadow: 0 0 0 1px rgba(16, 24, 40, 0.05), 0 0 0 3px rgba(41, 112, 255, 0.2);
1778
+ border-color: #155EEF;
1779
+ box-shadow: 0 0 0 3px rgba(21, 94, 239, 0.1);
1708
1780
  }
1709
1781
 
1710
1782
  .feedback-form-group input:focus-visible {
@@ -1712,15 +1784,15 @@
1712
1784
  }
1713
1785
 
1714
1786
  .feedback-form-group textarea {
1715
- min-height: 100px;
1787
+ min-height: 200px;
1716
1788
  width: 100%;
1717
- resize: both;
1718
- border-radius: 6px;
1789
+ resize: vertical;
1790
+ border-radius: 8px;
1719
1791
  border: 1px solid #D1D5DB;
1720
- padding: 2px 12px;
1721
- font-size: 14px;
1792
+ padding: 10px 14px;
1793
+ font-size: 15px;
1722
1794
  font-weight: 400;
1723
- line-height: 1.25;
1795
+ line-height: 1.5;
1724
1796
  color: #1F2937;
1725
1797
  font-family: inherit;
1726
1798
  outline: none;
@@ -1728,37 +1800,42 @@
1728
1800
  }
1729
1801
 
1730
1802
  .feedback-form-group textarea::placeholder {
1731
- font-size: 14px;
1732
- color: #6B7280;
1803
+ font-size: 15px;
1804
+ color: #9CA3AF;
1733
1805
  }
1734
1806
 
1735
1807
  .feedback-form-group textarea:focus {
1736
- border-color: #84ADFF;
1737
- box-shadow: 0 0 0 1px rgba(16, 24, 40, 0.05), 0 0 0 3px rgba(41, 112, 255, 0.2);
1808
+ border-color: #155EEF;
1809
+ box-shadow: 0 0 0 3px rgba(21, 94, 239, 0.1);
1738
1810
  }
1739
1811
 
1740
1812
  .feedback-form-group textarea:focus-visible {
1741
1813
  outline: none;
1742
1814
  }
1743
1815
 
1744
- .feedback-modal.theme-dark .feedback-form-group input,
1745
- .feedback-modal.theme-dark .feedback-form-group textarea {
1816
+ .feedback-panel.theme-dark .feedback-form-group input,
1817
+ .feedback-panel.theme-dark .feedback-form-group textarea {
1746
1818
  background: #374151;
1747
1819
  border-color: #4B5563;
1748
1820
  color: white;
1749
1821
  }
1750
1822
 
1823
+ .feedback-panel.theme-dark .feedback-form-group input::placeholder,
1824
+ .feedback-panel.theme-dark .feedback-form-group textarea::placeholder {
1825
+ color: #6B7280;
1826
+ }
1827
+
1751
1828
  .feedback-btn {
1752
1829
  position: relative;
1753
1830
  display: inline-flex;
1754
1831
  align-items: center;
1755
1832
  justify-content: center;
1756
1833
  overflow: hidden;
1757
- border-radius: 6px;
1834
+ border-radius: 8px;
1758
1835
  border: none;
1759
- height: 40px;
1760
- padding: 2px 16px;
1761
- font-size: 14px;
1836
+ height: 44px;
1837
+ padding: 10px 18px;
1838
+ font-size: 15px;
1762
1839
  font-weight: 500;
1763
1840
  font-family: inherit;
1764
1841
  cursor: pointer;
@@ -1766,7 +1843,7 @@
1766
1843
  }
1767
1844
 
1768
1845
  .feedback-btn:disabled {
1769
- opacity: 0.7;
1846
+ opacity: 0.6;
1770
1847
  cursor: not-allowed;
1771
1848
  }
1772
1849
 
@@ -1778,10 +1855,15 @@
1778
1855
  .feedback-btn-submit {
1779
1856
  background: #155EEF;
1780
1857
  color: white;
1858
+ width: 100%;
1781
1859
  }
1782
1860
 
1783
1861
  .feedback-btn-submit:hover:not(:disabled) {
1784
- background: #004EEB;
1862
+ background: #1A56DB;
1863
+ }
1864
+
1865
+ .feedback-btn-submit:active:not(:disabled) {
1866
+ background: #1E429F;
1785
1867
  }
1786
1868
 
1787
1869
  .feedback-btn-cancel {
@@ -1796,103 +1878,84 @@
1796
1878
  color: #374151;
1797
1879
  }
1798
1880
 
1799
- .feedback-modal.theme-dark .feedback-btn-cancel {
1881
+ .feedback-panel.theme-dark .feedback-btn-cancel {
1800
1882
  color: #D1D5DB;
1801
1883
  border-color: #4B5563;
1802
1884
  }
1803
1885
 
1804
- .feedback-modal.theme-dark .feedback-btn-cancel:hover:not(:disabled) {
1886
+ .feedback-panel.theme-dark .feedback-btn-cancel:hover:not(:disabled) {
1805
1887
  background: #374151;
1806
1888
  }
1807
1889
 
1808
1890
  .feedback-form-actions {
1809
1891
  display: flex;
1810
- gap: 8px;
1811
- justify-content: flex-end;
1812
- margin-top: 16px;
1813
- padding-top: 4px;
1814
- }
1815
-
1816
- .feedback-loading {
1817
- width: 20px;
1818
- height: 20px;
1819
- border-radius: 50%;
1820
- mask: radial-gradient(transparent 62%, white 65%);
1821
- -webkit-mask: radial-gradient(transparent 62%, white 65%);
1822
- animation: feedbackRotate 0.7s linear infinite;
1823
- }
1824
-
1825
- .feedback-loading-white {
1826
- background: conic-gradient(from 0deg, rgba(255, 255, 255, 0.5), white);
1827
- }
1828
-
1829
- .feedback-loading-blue {
1830
- background: conic-gradient(from 0deg, #004EEB, #eff4ff);
1831
- }
1832
-
1833
- @keyframes feedbackRotate {
1834
- 0% { transform: rotate(0deg); }
1835
- 100% { transform: rotate(360deg); }
1892
+ flex-direction: column;
1893
+ gap: 12px;
1894
+ margin-top: auto;
1895
+ padding-top: 24px;
1836
1896
  }
1837
1897
 
1838
1898
  .feedback-error {
1839
- color: #F04438;
1899
+ color: #DC2626;
1840
1900
  font-size: 14px;
1841
1901
  font-weight: 400;
1842
- margin-top: 4px;
1843
- text-transform: capitalize;
1844
- }
1845
-
1846
- .feedback-form-error {
1847
- color: #F04438;
1848
- font-size: 14px;
1849
- margin-top: 12px;
1850
- padding: 8px 12px;
1902
+ margin-top: 8px;
1903
+ padding: 12px;
1851
1904
  background: #FEE2E2;
1852
1905
  border: 1px solid #FECACA;
1853
- border-radius: 6px;
1906
+ border-radius: 8px;
1907
+ display: none;
1908
+ }
1909
+
1910
+ .feedback-error.show {
1911
+ display: block;
1854
1912
  }
1855
1913
 
1856
- .feedback-modal.theme-dark .feedback-form-error {
1914
+ .feedback-panel.theme-dark .feedback-error {
1857
1915
  background: #7F1D1D;
1858
1916
  border-color: #991B1B;
1859
1917
  color: #FCA5A5;
1860
1918
  }
1861
1919
 
1862
- .feedback-form-group.error input,
1863
- .feedback-form-group.error textarea {
1864
- border-color: #FDA29B;
1865
- }
1866
-
1867
- .feedback-form-group.error input:focus,
1868
- .feedback-form-group.error textarea:focus {
1869
- border-color: #FDA29B;
1870
- box-shadow: 0 0 0 1px rgba(16, 24, 40, 0.05), 0 0 0 4px rgba(253, 162, 155, 0.3);
1871
- }
1872
-
1873
1920
  .feedback-success-notification {
1874
1921
  position: fixed;
1875
- top: 20px;
1876
- right: 20px;
1877
- z-index: 1000001;
1922
+ top: 24px;
1923
+ right: 24px;
1924
+ z-index: 1000002;
1878
1925
  background: white;
1879
1926
  border: 1px solid #D1FAE5;
1880
- border-radius: 8px;
1881
- box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
1882
- animation: slideInRight 0.3s ease-out;
1927
+ border-radius: 12px;
1928
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
1929
+ animation: slideInRight 0.3s cubic-bezier(0.4, 0, 0.2, 1);
1930
+ min-width: 320px;
1883
1931
  }
1884
1932
 
1885
1933
  .feedback-success-content {
1886
1934
  display: flex;
1887
1935
  align-items: center;
1888
- padding: 12px 16px;
1936
+ padding: 16px 20px;
1889
1937
  gap: 12px;
1890
1938
  }
1891
1939
 
1940
+ .feedback-success-icon {
1941
+ width: 20px;
1942
+ height: 20px;
1943
+ border-radius: 50%;
1944
+ background: #10B981;
1945
+ color: white;
1946
+ display: flex;
1947
+ align-items: center;
1948
+ justify-content: center;
1949
+ font-size: 12px;
1950
+ font-weight: 600;
1951
+ flex-shrink: 0;
1952
+ }
1953
+
1892
1954
  .feedback-success-content span {
1893
- color: #059669;
1955
+ color: #065F46;
1894
1956
  font-weight: 500;
1895
1957
  font-size: 14px;
1958
+ flex: 1;
1896
1959
  }
1897
1960
 
1898
1961
  .feedback-success-close {
@@ -1900,17 +1963,20 @@
1900
1963
  border: none;
1901
1964
  color: #6B7280;
1902
1965
  cursor: pointer;
1903
- font-size: 18px;
1966
+ font-size: 20px;
1904
1967
  padding: 0;
1905
- width: 20px;
1906
- height: 20px;
1968
+ width: 24px;
1969
+ height: 24px;
1907
1970
  display: flex;
1908
1971
  align-items: center;
1909
1972
  justify-content: center;
1910
- transition: all 0.3s ease;
1973
+ transition: all 0.2s ease;
1974
+ border-radius: 4px;
1975
+ flex-shrink: 0;
1911
1976
  }
1912
1977
 
1913
1978
  .feedback-success-close:hover {
1979
+ background: #F3F4F6;
1914
1980
  color: #374151;
1915
1981
  }
1916
1982
 
@@ -1921,7 +1987,7 @@
1921
1987
 
1922
1988
  @keyframes slideInRight {
1923
1989
  from {
1924
- transform: translateX(100%);
1990
+ transform: translateX(400px);
1925
1991
  opacity: 0;
1926
1992
  }
1927
1993
  to {
@@ -1935,56 +2001,58 @@
1935
2001
  to { opacity: 1; }
1936
2002
  }
1937
2003
 
1938
- .feedback-modal {
1939
- animation: fadeIn 0.2s ease-out;
1940
- }
1941
-
1942
- .feedback-modal-content {
1943
- animation: slideInUp 0.3s ease-out;
2004
+ .feedback-panel-backdrop {
2005
+ animation: fadeIn 0.3s ease;
1944
2006
  }
1945
2007
 
1946
- @keyframes slideInUp {
1947
- from {
1948
- transform: translateY(20px);
1949
- opacity: 0;
2008
+ @media (max-width: 768px) {
2009
+ .feedback-panel {
2010
+ width: 100%;
2011
+ top: auto;
2012
+ bottom: 0;
2013
+ right: 0;
2014
+ left: 0;
2015
+ height: 85vh;
2016
+ max-height: 85vh;
2017
+ transform: translateY(100%);
2018
+ border-radius: 20px 20px 0 0;
1950
2019
  }
1951
- to {
2020
+
2021
+ .feedback-panel.open {
1952
2022
  transform: translateY(0);
1953
- opacity: 1;
1954
- }
1955
- }
1956
-
1957
- @media (max-width: 640px) {
1958
- .feedback-modal {
1959
- padding: 8px;
1960
2023
  }
1961
2024
 
1962
- .feedback-modal-content {
1963
- min-width: 280px;
1964
- max-width: 100%;
1965
- max-height: 95vh;
2025
+ .feedback-panel-content {
2026
+ border-radius: 20px 20px 0 0;
1966
2027
  }
1967
2028
 
1968
- .feedback-form {
1969
- padding: 16px;
2029
+ .feedback-panel-header {
2030
+ padding: 20px;
2031
+ position: relative;
1970
2032
  }
1971
2033
 
1972
- .feedback-modal-header {
1973
- padding: 16px;
2034
+ .feedback-panel-header::before {
2035
+ content: '';
2036
+ position: absolute;
2037
+ top: 8px;
2038
+ left: 50%;
2039
+ transform: translateX(-50%);
2040
+ width: 40px;
2041
+ height: 4px;
2042
+ background: #D1D5DB;
2043
+ border-radius: 2px;
1974
2044
  }
1975
2045
 
1976
- .feedback-modal-header h3 {
1977
- font-size: 15px;
2046
+ .feedback-panel.theme-dark .feedback-panel-header::before {
2047
+ background: #4B5563;
1978
2048
  }
1979
2049
 
1980
- .feedback-form-actions {
1981
- flex-direction: column;
1982
- gap: 8px;
2050
+ .feedback-panel-body {
2051
+ padding: 20px;
1983
2052
  }
1984
2053
 
1985
- .feedback-btn {
1986
- width: 100%;
1987
- height: 40px;
2054
+ .feedback-form-group textarea {
2055
+ min-height: 150px;
1988
2056
  }
1989
2057
 
1990
2058
  .feedback-widget-button {
@@ -1996,48 +2064,29 @@
1996
2064
  left: 16px;
1997
2065
  }
1998
2066
 
1999
- .feedback-trigger-btn {
2000
- padding: 10px 16px;
2001
- font-size: 13px;
2002
- }
2003
-
2004
2067
  .feedback-success-notification {
2005
- top: 8px;
2006
- right: 8px;
2007
- left: 8px;
2008
- max-width: none;
2009
- }
2010
-
2011
- .feedback-form-group input {
2012
- height: 40px;
2013
- padding: 2px 12px;
2014
- }
2015
-
2016
- .feedback-form-group textarea {
2017
- min-height: 80px;
2018
- padding: 2px 12px;
2068
+ top: 16px;
2069
+ right: 16px;
2070
+ left: 16px;
2071
+ min-width: auto;
2019
2072
  }
2020
2073
  }
2021
2074
 
2022
2075
  @media (prefers-reduced-motion: reduce) {
2023
2076
  .feedback-trigger-btn,
2024
2077
  .feedback-btn,
2025
- .feedback-modal,
2026
- .feedback-modal-content,
2027
- .feedback-success-notification,
2028
- .feedback-loading {
2078
+ .feedback-panel,
2079
+ .feedback-panel-backdrop,
2080
+ .feedback-success-notification {
2029
2081
  transition: none;
2030
2082
  animation: none;
2031
2083
  }
2032
-
2033
- .feedback-trigger-btn:hover {
2034
- transform: none;
2035
- }
2036
2084
  }
2037
2085
 
2038
2086
  @media print {
2039
2087
  .feedback-widget,
2040
- .feedback-modal,
2088
+ .feedback-panel,
2089
+ .feedback-panel-backdrop,
2041
2090
  .feedback-success-notification {
2042
2091
  display: none !important;
2043
2092
  }