@ansiversa/components 0.0.41 → 0.0.43

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": "@ansiversa/components",
3
- "version": "0.0.41",
3
+ "version": "0.0.43",
4
4
  "description": "Shared UI components and layouts for the Ansiversa ecosystem",
5
5
  "type": "module",
6
6
  "exports": {
@@ -3,23 +3,56 @@ import AvButton from "./AvButton.astro";
3
3
  import AvCard from "./AvCard.astro";
4
4
 
5
5
  interface Props {
6
- title: string;
6
+ // preferred Ansiversa naming
7
+ headline?: string;
8
+
9
+ // current naming (keep for backward compatibility)
10
+ title?: string;
11
+
7
12
  description?: string;
13
+
14
+ // CTA
8
15
  ctaLabel?: string;
9
- ctaHref?: string;
16
+ ctaHref?: string; // if provided => link CTA
17
+ ctaDisabled?: boolean; // if button CTA
18
+ className?: string;
10
19
  }
11
20
 
12
- const { title, description, ctaLabel, ctaHref } = Astro.props as Props;
21
+ const {
22
+ headline,
23
+ title,
24
+ description,
25
+ ctaLabel,
26
+ ctaHref,
27
+ ctaDisabled = false,
28
+ className = "",
29
+ ...attrs
30
+ } = Astro.props as Props & Record<string, any>;
31
+
32
+ const resolvedTitle = headline ?? title ?? "Empty";
13
33
  ---
14
34
 
15
- <AvCard className="av-empty-state">
35
+ <AvCard className={`av-empty-state ${className}`.trim()} {...attrs}>
16
36
  <div class="av-empty-state__body">
17
- <h3 class="av-empty-state__title">{title}</h3>
37
+ <h3 class="av-empty-state__title">{resolvedTitle}</h3>
38
+
18
39
  {description && <p class="av-empty-state__description">{description}</p>}
19
- {ctaLabel && ctaHref && (
20
- <AvButton href={ctaHref} variant="primary">
21
- {ctaLabel}
22
- </AvButton>
23
- )}
40
+
41
+ {ctaLabel ? (
42
+ ctaHref ? (
43
+ <AvButton href={ctaHref} variant="primary">
44
+ {ctaLabel}
45
+ </AvButton>
46
+ ) : (
47
+ <AvButton
48
+ type="button"
49
+ variant="primary"
50
+ disabled={ctaDisabled}
51
+ onclick="this.dispatchEvent(new CustomEvent('cta', { bubbles: true }))"
52
+ >
53
+ {ctaLabel}
54
+ </AvButton>
55
+ )
56
+ ) : null}
24
57
  </div>
25
58
  </AvCard>
@@ -0,0 +1,18 @@
1
+ ---
2
+ interface Props {
3
+ caption?: string;
4
+ className?: string;
5
+ dense?: boolean;
6
+ stickyHeader?: boolean;
7
+ scroll?: boolean; // enable x-scroll container
8
+ }
9
+
10
+ const { caption, className = "", dense = false, stickyHeader = false, scroll = true } = Astro.props as Props;
11
+ ---
12
+
13
+ <div class={`av-table ${scroll ? "av-table--scroll" : ""} ${dense ? "av-table--dense" : ""} ${stickyHeader ? "av-table--sticky" : ""} ${className}`}>
14
+ <table class="av-table__table">
15
+ {caption ? <caption class="av-table__caption">{caption}</caption> : null}
16
+ <slot />
17
+ </table>
18
+ </div>
@@ -0,0 +1,31 @@
1
+ ---
2
+ import AvButton from "./AvButton.astro";
3
+
4
+ interface Props {
5
+ page: number;
6
+ pageSize: number;
7
+ total: number;
8
+ prevHref?: string;
9
+ nextHref?: string;
10
+ }
11
+
12
+ const { page, pageSize, total, prevHref, nextHref } = Astro.props as Props;
13
+
14
+ const from = total === 0 ? 0 : (page - 1) * pageSize + 1;
15
+ const to = Math.min(page * pageSize, total);
16
+ ---
17
+
18
+ <div class="av-table-pager" role="navigation" aria-label="Pagination">
19
+ <div class="av-table-pager__meta">
20
+ {from}-{to} of {total}
21
+ </div>
22
+
23
+ <div class="av-table-pager__buttons">
24
+ <AvButton href={prevHref} variant="ghost" size="sm" className={!prevHref ? "av-is-disabled" : ""}>
25
+ Prev
26
+ </AvButton>
27
+ <AvButton href={nextHref} variant="ghost" size="sm" className={!nextHref ? "av-is-disabled" : ""}>
28
+ Next
29
+ </AvButton>
30
+ </div>
31
+ </div>
@@ -0,0 +1,32 @@
1
+ ---
2
+ import AvButton from "./AvButton.astro";
3
+
4
+ interface Props {
5
+ title: string;
6
+ subtitle?: string; // like "12 items"
7
+ className?: string;
8
+ }
9
+
10
+ const { title, subtitle, className = "" } = Astro.props as Props;
11
+ ---
12
+
13
+ <div class={`av-table-toolbar ${className}`}>
14
+ <div class="av-table-toolbar__left">
15
+ <h1 class="av-table-toolbar__title">{title}</h1>
16
+ {subtitle ? <p class="av-table-toolbar__subtitle">{subtitle}</p> : null}
17
+ </div>
18
+
19
+ <div class="av-table-toolbar__right">
20
+ <slot name="right" />
21
+ </div>
22
+ </div>
23
+
24
+ <div class="av-table-toolbar__row">
25
+ <div class="av-table-toolbar__search">
26
+ <slot name="search" />
27
+ </div>
28
+
29
+ <div class="av-table-toolbar__actions">
30
+ <slot name="actions" />
31
+ </div>
32
+ </div>
@@ -680,6 +680,142 @@
680
680
  @apply bg-rose-500/80 border-rose-200;
681
681
  }
682
682
 
683
+ /* TABLE */
684
+ .av-table {
685
+ border: 1px solid var(--ans-border);
686
+ border-radius: var(--ans-radius-lg);
687
+ background: var(--ans-surface);
688
+ overflow: hidden;
689
+ }
690
+
691
+ .av-table--scroll {
692
+ overflow-x: auto;
693
+ }
694
+
695
+ .av-table__table {
696
+ width: 100%;
697
+ border-collapse: separate;
698
+ border-spacing: 0;
699
+ min-width: 720px;
700
+ }
701
+
702
+ .av-table--dense .av-table__table th,
703
+ .av-table--dense .av-table__table td {
704
+ padding-top: 0.55rem;
705
+ padding-bottom: 0.55rem;
706
+ }
707
+
708
+ .av-table__caption {
709
+ text-align: left;
710
+ padding: 0.75rem 1rem;
711
+ color: var(--ans-muted);
712
+ font-size: 0.875rem;
713
+ }
714
+
715
+ .av-table__table thead th {
716
+ text-align: left;
717
+ font-weight: 600;
718
+ color: var(--ans-text);
719
+ background: var(--ans-surface-2);
720
+ border-bottom: 1px solid var(--ans-border);
721
+ padding: 0.8rem 1rem;
722
+ white-space: nowrap;
723
+ }
724
+
725
+ .av-table--sticky thead th {
726
+ position: sticky;
727
+ top: 0;
728
+ z-index: 1;
729
+ }
730
+
731
+ .av-table__table tbody td {
732
+ padding: 0.9rem 1rem;
733
+ border-bottom: 1px solid var(--ans-border);
734
+ color: var(--ans-text);
735
+ vertical-align: top;
736
+ }
737
+
738
+ .av-table__table tbody tr:hover td {
739
+ background: var(--ans-surface-2);
740
+ }
741
+
742
+ .av-table__cell-muted {
743
+ color: var(--ans-muted);
744
+ }
745
+
746
+ .av-table__cell-actions {
747
+ display: flex;
748
+ gap: 0.5rem;
749
+ justify-content: flex-end;
750
+ white-space: nowrap;
751
+ }
752
+
753
+ /* TOOLBAR */
754
+ .av-table-toolbar {
755
+ display: flex;
756
+ align-items: flex-end;
757
+ justify-content: space-between;
758
+ gap: 1rem;
759
+ margin-bottom: 0.75rem;
760
+ }
761
+
762
+ .av-table-toolbar__title {
763
+ font-size: 1.25rem;
764
+ font-weight: 700;
765
+ line-height: 1.2;
766
+ }
767
+
768
+ .av-table-toolbar__subtitle {
769
+ margin-top: 0.25rem;
770
+ color: var(--ans-muted);
771
+ font-size: 0.875rem;
772
+ }
773
+
774
+ .av-table-toolbar__row {
775
+ display: flex;
776
+ align-items: center;
777
+ justify-content: space-between;
778
+ gap: 0.75rem;
779
+ margin-bottom: 1rem;
780
+ flex-wrap: wrap;
781
+ }
782
+
783
+ .av-table-toolbar__search {
784
+ min-width: 260px;
785
+ flex: 1;
786
+ }
787
+
788
+ .av-table-toolbar__actions {
789
+ display: flex;
790
+ gap: 0.5rem;
791
+ justify-content: flex-end;
792
+ }
793
+
794
+ /* PAGER */
795
+ .av-table-pager {
796
+ display: flex;
797
+ align-items: center;
798
+ justify-content: space-between;
799
+ gap: 0.75rem;
800
+ margin-top: 1rem;
801
+ }
802
+
803
+ .av-table-pager__meta {
804
+ color: var(--ans-muted);
805
+ font-size: 0.875rem;
806
+ }
807
+
808
+ .av-table-pager__buttons {
809
+ display: flex;
810
+ gap: 0.5rem;
811
+ }
812
+
813
+ /* DISABLED ANCHOR/BUTTON HELPER */
814
+ .av-is-disabled {
815
+ pointer-events: none;
816
+ opacity: 0.5;
817
+ }
818
+
683
819
  /* Forms ------------------------------------------------- */
684
820
 
685
821
  .av-text-error {