softui-css 1.2.0 → 1.4.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/dist/softui.css CHANGED
@@ -8669,3 +8669,300 @@ a.sui-btn-warning:visited {
8669
8669
  display: none;
8670
8670
  }
8671
8671
  }
8672
+
8673
+ /* ===========================================
8674
+ Stat Card
8675
+ =========================================== */
8676
+ .sui-stat {
8677
+ display: flex;
8678
+ flex-direction: column;
8679
+ gap: 2px;
8680
+ padding: 20px;
8681
+ background: var(--sui-bg);
8682
+ border-radius: var(--sui-radius);
8683
+ box-shadow: var(--sui-shadow-raised-sm);
8684
+ transition: var(--sui-transition);
8685
+ }
8686
+
8687
+ .sui-stat:hover {
8688
+ box-shadow: var(--sui-shadow-raised-lg);
8689
+ transform: translateY(-4px);
8690
+ }
8691
+
8692
+ .sui-stat-label {
8693
+ font-size: 13px;
8694
+ font-weight: 500;
8695
+ color: var(--sui-text-muted);
8696
+ margin: 0;
8697
+ line-height: 1.3;
8698
+ }
8699
+
8700
+ .sui-stat-value {
8701
+ font-size: 28px;
8702
+ font-weight: 700;
8703
+ color: var(--sui-text);
8704
+ margin: 4px 0 2px;
8705
+ line-height: 1.2;
8706
+ }
8707
+
8708
+ .sui-stat-trend {
8709
+ display: flex;
8710
+ align-items: center;
8711
+ gap: 6px;
8712
+ font-size: 12px;
8713
+ color: var(--sui-text-muted);
8714
+ white-space: nowrap;
8715
+ }
8716
+
8717
+ .sui-stat-change {
8718
+ display: inline-flex;
8719
+ align-items: center;
8720
+ gap: 2px;
8721
+ font-weight: 600;
8722
+ font-size: 12px;
8723
+ }
8724
+
8725
+ .sui-stat-change-up { color: var(--sui-success); }
8726
+ .sui-stat-change-down { color: var(--sui-danger); }
8727
+ .sui-stat-change-flat { color: var(--sui-warning); }
8728
+
8729
+ /* --- With Icon --- */
8730
+ .sui-stat-header {
8731
+ display: flex;
8732
+ align-items: flex-start;
8733
+ justify-content: space-between;
8734
+ gap: 12px;
8735
+ }
8736
+
8737
+
8738
+ .sui-stat-icon {
8739
+ width: 40px;
8740
+ height: 40px;
8741
+ display: flex;
8742
+ align-items: center;
8743
+ justify-content: center;
8744
+ border-radius: var(--sui-radius-sm);
8745
+ background: var(--sui-bg);
8746
+ box-shadow: var(--sui-shadow-raised-sm);
8747
+ flex-shrink: 0;
8748
+ }
8749
+
8750
+ .sui-stat-icon svg {
8751
+ width: 20px;
8752
+ height: 20px;
8753
+ stroke: var(--sui-text-muted);
8754
+ fill: none;
8755
+ stroke-width: 2;
8756
+ stroke-linecap: round;
8757
+ stroke-linejoin: round;
8758
+ }
8759
+
8760
+ .sui-stat-icon-primary { background: rgba(91, 84, 224, 0.1); }
8761
+ .sui-stat-icon-primary svg { stroke: var(--sui-primary); }
8762
+
8763
+ .sui-stat-icon-success { background: rgba(45, 206, 137, 0.1); }
8764
+ .sui-stat-icon-success svg { stroke: var(--sui-success); }
8765
+
8766
+ .sui-stat-icon-danger { background: rgba(231, 76, 111, 0.1); }
8767
+ .sui-stat-icon-danger svg { stroke: var(--sui-danger); }
8768
+
8769
+ .sui-stat-icon-warning { background: rgba(245, 166, 35, 0.1); }
8770
+ .sui-stat-icon-warning svg { stroke: var(--sui-warning); }
8771
+
8772
+ .sui-stat-icon-info { background: rgba(54, 163, 247, 0.1); }
8773
+ .sui-stat-icon-info svg { stroke: var(--sui-info); }
8774
+
8775
+ /* --- With Progress --- */
8776
+ .sui-stat .sui-progress {
8777
+ margin-top: 12px;
8778
+ }
8779
+
8780
+ /* --- Bordered accent --- */
8781
+ .sui-stat-bordered {
8782
+ border-left: 3px solid var(--sui-bg-dark);
8783
+ }
8784
+
8785
+ .sui-stat-bordered-primary { border-left-color: var(--sui-primary); }
8786
+ .sui-stat-bordered-success { border-left-color: var(--sui-success); }
8787
+ .sui-stat-bordered-danger { border-left-color: var(--sui-danger); }
8788
+ .sui-stat-bordered-warning { border-left-color: var(--sui-warning); }
8789
+ .sui-stat-bordered-info { border-left-color: var(--sui-info); }
8790
+
8791
+ /* --- Inset --- */
8792
+ .sui-stat-inset {
8793
+ box-shadow: var(--sui-shadow-inset);
8794
+ }
8795
+
8796
+ .sui-stat-inset:hover {
8797
+ box-shadow: var(--sui-shadow-inset), var(--sui-shadow-raised-lg);
8798
+ transform: translateY(-4px);
8799
+ }
8800
+
8801
+ /* --- Flat --- */
8802
+ .sui-stat-flat {
8803
+ box-shadow: none;
8804
+ border: 1px solid var(--sui-bg-dark);
8805
+ }
8806
+
8807
+ .sui-stat-flat:hover {
8808
+ box-shadow: var(--sui-shadow-raised-lg);
8809
+ transform: translateY(-4px);
8810
+ }
8811
+
8812
+ /* --- Compact --- */
8813
+ .sui-stat-compact {
8814
+ padding: 14px 16px;
8815
+ gap: 0;
8816
+ }
8817
+
8818
+ .sui-stat-compact .sui-stat-value {
8819
+ font-size: 22px;
8820
+ margin: 2px 0;
8821
+ }
8822
+
8823
+ .sui-stat-compact .sui-stat-label {
8824
+ font-size: 12px;
8825
+ }
8826
+
8827
+ .sui-stat-compact .sui-stat-icon {
8828
+ width: 34px;
8829
+ height: 34px;
8830
+ }
8831
+
8832
+ .sui-stat-compact .sui-stat-icon svg {
8833
+ width: 16px;
8834
+ height: 16px;
8835
+ }
8836
+
8837
+ .sui-stat-compact .sui-progress {
8838
+ margin-top: 8px;
8839
+ }
8840
+
8841
+ /* =========================================
8842
+ Rating
8843
+ ========================================= */
8844
+ .sui-rating {
8845
+ display: inline-flex;
8846
+ align-items: center;
8847
+ gap: 2px;
8848
+ }
8849
+
8850
+ .sui-rating-star {
8851
+ width: 24px;
8852
+ height: 24px;
8853
+ cursor: pointer;
8854
+ color: var(--sui-bg-dark);
8855
+ transition: color 0.15s ease, transform 0.15s ease;
8856
+ flex-shrink: 0;
8857
+ }
8858
+
8859
+ .sui-rating-star svg {
8860
+ width: 100%;
8861
+ height: 100%;
8862
+ fill: currentColor;
8863
+ stroke: none;
8864
+ }
8865
+
8866
+ .sui-rating-star:hover {
8867
+ transform: scale(1.15);
8868
+ }
8869
+
8870
+ .sui-rating-star.active {
8871
+ color: var(--sui-warning);
8872
+ }
8873
+
8874
+ .sui-rating-star.hover {
8875
+ color: var(--sui-warning);
8876
+ opacity: 0.7;
8877
+ }
8878
+
8879
+ .sui-rating-primary .sui-rating-star.hover { color: var(--sui-primary); }
8880
+ .sui-rating-success .sui-rating-star.hover { color: var(--sui-success); }
8881
+ .sui-rating-danger .sui-rating-star.hover { color: var(--sui-danger); }
8882
+ .sui-rating-info .sui-rating-star.hover { color: var(--sui-info); }
8883
+
8884
+ /* Read-only */
8885
+ .sui-rating-readonly .sui-rating-star {
8886
+ cursor: default;
8887
+ }
8888
+
8889
+ .sui-rating-readonly .sui-rating-star:hover {
8890
+ transform: none;
8891
+ }
8892
+
8893
+ /* Half star — uses two layered SVGs: filled (clipped left) + empty (behind) */
8894
+ .sui-rating-star.half,
8895
+ .sui-rating-star.hover-half {
8896
+ position: relative;
8897
+ color: var(--sui-bg-dark);
8898
+ }
8899
+
8900
+ .sui-rating-star.hover-half {
8901
+ opacity: 0.7;
8902
+ }
8903
+
8904
+ .sui-rating-star.half svg:last-child,
8905
+ .sui-rating-star.hover-half svg:last-child {
8906
+ position: absolute;
8907
+ top: 0;
8908
+ left: 0;
8909
+ width: 100%;
8910
+ height: 100%;
8911
+ }
8912
+
8913
+ .sui-rating-star.half svg:first-child,
8914
+ .sui-rating-star.hover-half svg:first-child {
8915
+ clip-path: inset(0 50% 0 0);
8916
+ color: var(--sui-warning);
8917
+ position: relative;
8918
+ z-index: 1;
8919
+ }
8920
+
8921
+ /* Sizes */
8922
+ .sui-rating-sm .sui-rating-star {
8923
+ width: 16px;
8924
+ height: 16px;
8925
+ }
8926
+
8927
+ .sui-rating-sm .sui-rating-star:hover {
8928
+ transform: scale(1.05);
8929
+ }
8930
+
8931
+ .sui-rating-lg .sui-rating-star {
8932
+ width: 32px;
8933
+ height: 32px;
8934
+ }
8935
+
8936
+ /* Colors */
8937
+ .sui-rating-primary .sui-rating-star.active { color: var(--sui-primary); }
8938
+ .sui-rating-primary .sui-rating-star.half svg:first-child { color: var(--sui-primary); }
8939
+ .sui-rating-primary .sui-rating-star.hover-half svg:first-child { color: var(--sui-primary); }
8940
+
8941
+ .sui-rating-success .sui-rating-star.active { color: var(--sui-success); }
8942
+ .sui-rating-success .sui-rating-star.half svg:first-child { color: var(--sui-success); }
8943
+ .sui-rating-success .sui-rating-star.hover-half svg:first-child { color: var(--sui-success); }
8944
+
8945
+ .sui-rating-danger .sui-rating-star.active { color: var(--sui-danger); }
8946
+ .sui-rating-danger .sui-rating-star.half svg:first-child { color: var(--sui-danger); }
8947
+ .sui-rating-danger .sui-rating-star.hover-half svg:first-child { color: var(--sui-danger); }
8948
+
8949
+ .sui-rating-info .sui-rating-star.active { color: var(--sui-info); }
8950
+ .sui-rating-info .sui-rating-star.half svg:first-child { color: var(--sui-info); }
8951
+ .sui-rating-info .sui-rating-star.hover-half svg:first-child { color: var(--sui-info); }
8952
+
8953
+ /* With count */
8954
+ .sui-rating-count {
8955
+ margin-left: 6px;
8956
+ font-size: 13px;
8957
+ color: var(--sui-text-muted);
8958
+ font-weight: 500;
8959
+ }
8960
+
8961
+ /* Inset style */
8962
+ .sui-rating-inset {
8963
+ background: var(--sui-bg);
8964
+ box-shadow: var(--sui-shadow-inset-sm);
8965
+ border-radius: var(--sui-radius);
8966
+ padding: 6px 10px;
8967
+ gap: 4px;
8968
+ }
package/dist/softui.js CHANGED
@@ -2898,5 +2898,90 @@ const SoftUI = (() => {
2898
2898
  return { collapse: collapse, expand: expand, toggle: toggle, isCollapsed: isCollapsed, el: el };
2899
2899
  }
2900
2900
 
2901
+ // =========================================
2902
+ // Rating
2903
+ // =========================================
2904
+ function ratingIsHalf(star, e) {
2905
+ var rect = star.getBoundingClientRect();
2906
+ return e.clientX < rect.left + rect.width / 2;
2907
+ }
2908
+
2909
+ function ratingEnsureDualSvg(star) {
2910
+ var svgs = star.querySelectorAll('svg');
2911
+ if (svgs.length < 2) {
2912
+ var clone = svgs[0].cloneNode(true);
2913
+ star.appendChild(clone);
2914
+ }
2915
+ }
2916
+
2917
+ function ratingResetSvg(star) {
2918
+ var svgs = star.querySelectorAll('svg');
2919
+ if (svgs.length > 1) {
2920
+ for (var i = svgs.length - 1; i > 0; i--) { svgs[i].remove(); }
2921
+ }
2922
+ }
2923
+
2924
+ document.addEventListener('click', function(e) {
2925
+ var star = e.target.closest('.sui-rating:not(.sui-rating-readonly) .sui-rating-star');
2926
+ if (!star) return;
2927
+ var rating = star.closest('.sui-rating');
2928
+ var stars = Array.from(rating.querySelectorAll('.sui-rating-star'));
2929
+ var index = stars.indexOf(star);
2930
+ var allowHalf = rating.classList.contains('sui-rating-half');
2931
+ var isHalf = allowHalf && ratingIsHalf(star, e);
2932
+ var value = isHalf ? index + 0.5 : index + 1;
2933
+ stars.forEach(function(s, i) {
2934
+ s.classList.remove('active', 'half', 'hover', 'hover-half');
2935
+ ratingResetSvg(s);
2936
+ if (i < index) {
2937
+ s.classList.add('active');
2938
+ } else if (i === index) {
2939
+ if (isHalf) {
2940
+ ratingEnsureDualSvg(s);
2941
+ s.classList.add('half');
2942
+ } else {
2943
+ s.classList.add('active');
2944
+ }
2945
+ }
2946
+ });
2947
+ rating.setAttribute('data-value', value);
2948
+ rating.dispatchEvent(new CustomEvent('sui-rating-change', { detail: { value: value } }));
2949
+ });
2950
+
2951
+ document.addEventListener('mousemove', function(e) {
2952
+ var star = e.target.closest('.sui-rating:not(.sui-rating-readonly) .sui-rating-star');
2953
+ if (!star) return;
2954
+ var rating = star.closest('.sui-rating');
2955
+ var stars = Array.from(rating.querySelectorAll('.sui-rating-star'));
2956
+ var index = stars.indexOf(star);
2957
+ var allowHalf = rating.classList.contains('sui-rating-half');
2958
+ var isHalf = allowHalf && ratingIsHalf(star, e);
2959
+ stars.forEach(function(s, i) {
2960
+ s.classList.remove('hover', 'hover-half');
2961
+ ratingResetSvg(s);
2962
+ if (i < index) {
2963
+ s.classList.add('hover');
2964
+ } else if (i === index) {
2965
+ if (isHalf) {
2966
+ ratingEnsureDualSvg(s);
2967
+ s.classList.add('hover-half');
2968
+ } else {
2969
+ s.classList.add('hover');
2970
+ }
2971
+ }
2972
+ });
2973
+ });
2974
+
2975
+ document.addEventListener('mouseout', function(e) {
2976
+ var star = e.target.closest('.sui-rating:not(.sui-rating-readonly) .sui-rating-star');
2977
+ if (!star) return;
2978
+ var rating = star.closest('.sui-rating');
2979
+ var stars = Array.from(rating.querySelectorAll('.sui-rating-star'));
2980
+ stars.forEach(function(s) {
2981
+ s.classList.remove('hover', 'hover-half');
2982
+ if (!s.classList.contains('half')) { ratingResetSvg(s); }
2983
+ });
2984
+ });
2985
+
2901
2986
  return { modal, sheet, toast, carousel, sidebar };
2902
2987
  })();