@dmitriikapustin/ui 0.2.7 → 0.2.9

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/index.cjs CHANGED
@@ -915,40 +915,61 @@ function IconButton(_a) {
915
915
  }
916
916
 
917
917
  // css-inject-scss:/Users/dimakozh/Desktop/projects/kapustin.cc/packages/ui/src/atoms/Logo.module.scss
918
- __styleInject(`.Logo-module_short {
919
- width: 19px;
920
- height: 20px;
921
- }
922
-
923
- .Logo-module_full {
924
- height: 20px;
925
- width: 130px;
926
- }
927
-
928
- .Logo-module_third {
929
- display: flex;
918
+ __styleInject(`.Logo-module_root {
919
+ display: inline-flex;
930
920
  align-items: center;
931
921
  gap: 0.375rem;
932
922
  }
933
923
 
934
- .Logo-module_thirdText {
935
- font-size: 13px;
936
- font-weight: 500;
924
+ .Logo-module_image {
925
+ display: block;
926
+ }
927
+
928
+ .Logo-module_text {
929
+ font-size: 16px;
930
+ font-weight: 600;
937
931
  color: var(--fg);
938
932
  letter-spacing: -0.25px;
933
+ line-height: 1;
934
+ }
935
+
936
+ .Logo-module_accent {
937
+ color: var(--brand-primary);
939
938
  }`);
940
- var __default11 = { "short": "Logo-module_short", "full": "Logo-module_full", "third": "Logo-module_third", "thirdText": "Logo-module_thirdText" };
941
- function Logo({ version = "short", className = "" }) {
942
- if (version === "short") {
943
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${__default11.short}${className ? ` ${className}` : ""}`, children: /* @__PURE__ */ jsxRuntime.jsx("img", { className: "logo-img", src: "/assets/logos/logo-short.svg", alt: "aiacade.me", width: 19, height: 20 }) });
944
- }
945
- if (version === "third") {
946
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${__default11.third}${className ? ` ${className}` : ""}`, children: [
947
- /* @__PURE__ */ jsxRuntime.jsx("img", { className: "logo-img", src: "/assets/logos/logo-icon.svg", alt: "", width: 20, height: 20 }),
948
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: __default11.thirdText, children: "aiacade.me" })
949
- ] });
939
+ var __default11 = { "root": "Logo-module_root", "image": "Logo-module_image", "text": "Logo-module_text", "accent": "Logo-module_accent" };
940
+ function Logo({
941
+ children,
942
+ src,
943
+ alt = "",
944
+ width,
945
+ height,
946
+ text,
947
+ accent,
948
+ className = ""
949
+ }) {
950
+ const rootClass = `${__default11.root}${className ? ` ${className}` : ""}`;
951
+ if (children) {
952
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: rootClass, children });
953
+ }
954
+ if (src) {
955
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: rootClass, children: /* @__PURE__ */ jsxRuntime.jsx("img", { className: __default11.image, src, alt, width, height }) });
956
+ }
957
+ if (text) {
958
+ const accentText = accent != null ? accent : text.charAt(0);
959
+ const idx = accent ? text.indexOf(accent) : 0;
960
+ if (idx >= 0 && accentText) {
961
+ const before = text.slice(0, idx);
962
+ const middle = text.slice(idx, idx + accentText.length);
963
+ const after = text.slice(idx + accentText.length);
964
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: rootClass, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: __default11.text, children: [
965
+ before,
966
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: __default11.accent, children: middle }),
967
+ after
968
+ ] }) });
969
+ }
970
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: rootClass, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: __default11.text, children: text }) });
950
971
  }
951
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${__default11.full}${className ? ` ${className}` : ""}`, children: /* @__PURE__ */ jsxRuntime.jsx("img", { className: "logo-img", src: "/assets/logos/logo-full.svg", alt: "aiacade.me", width: 130, height: 20 }) });
972
+ return null;
952
973
  }
953
974
 
954
975
  // css-inject-scss:/Users/dimakozh/Desktop/projects/kapustin.cc/packages/ui/src/atoms/StatBadge.module.scss
@@ -3415,12 +3436,16 @@ function DropdownMenu({
3415
3436
  }
3416
3437
 
3417
3438
  // css-inject-scss:/Users/dimakozh/Desktop/projects/kapustin.cc/packages/ui/src/organisms/Header.module.scss
3418
- __styleInject(`.Header-module_root {
3419
- border-bottom: 1px solid var(--border-color);
3439
+ __styleInject(`@charset "UTF-8";
3440
+ /* Header \u2014 pill-style (border + radius + margin) by default */
3441
+ .Header-module_root {
3442
+ margin: clamp(8px, 2vw, 24px);
3443
+ border: 1px solid var(--border-color);
3444
+ border-radius: var(--radius-2xl);
3420
3445
  background: color-mix(in srgb, var(--bg) 80%, transparent);
3421
3446
  backdrop-filter: blur(12px);
3422
3447
  position: sticky;
3423
- top: 0;
3448
+ top: clamp(8px, 2vw, 24px);
3424
3449
  z-index: 50;
3425
3450
  }
3426
3451
 
@@ -3453,16 +3478,6 @@ __styleInject(`.Header-module_root {
3453
3478
  gap: 2rem;
3454
3479
  }
3455
3480
 
3456
- .Header-module_logoFallback {
3457
- font-size: 1.125rem;
3458
- font-weight: 700;
3459
- color: var(--fg);
3460
- }
3461
-
3462
- .Header-module_logoBrand {
3463
- color: var(--brand-primary);
3464
- }
3465
-
3466
3481
  .Header-module_desktopNav {
3467
3482
  display: none;
3468
3483
  align-items: center;
@@ -3499,14 +3514,6 @@ __styleInject(`.Header-module_root {
3499
3514
 
3500
3515
  .Header-module_mobileToggle {
3501
3516
  display: block;
3502
- padding: 0.5rem;
3503
- color: var(--fg-secondary);
3504
- cursor: pointer;
3505
- background: none;
3506
- border: none;
3507
- }
3508
- .Header-module_mobileToggle:hover {
3509
- color: var(--fg);
3510
3517
  }
3511
3518
  @media (min-width: 768px) {
3512
3519
  .Header-module_mobileToggle {
@@ -3540,16 +3547,13 @@ __styleInject(`.Header-module_root {
3540
3547
  padding-top: 1rem;
3541
3548
  border-top: 1px solid var(--border-color);
3542
3549
  }`);
3543
- var __default42 = { "root": "Header-module_root", "container": "Header-module_container", "bar": "Header-module_bar", "leftGroup": "Header-module_leftGroup", "logoFallback": "Header-module_logoFallback", "logoBrand": "Header-module_logoBrand", "desktopNav": "Header-module_desktopNav", "navLink": "Header-module_navLink", "desktopActions": "Header-module_desktopActions", "mobileToggle": "Header-module_mobileToggle", "mobileMenu": "Header-module_mobileMenu", "mobileNav": "Header-module_mobileNav", "mobileActions": "Header-module_mobileActions" };
3544
- function Header({ logo, navItems = [], className = "" }) {
3550
+ var __default42 = { "root": "Header-module_root", "container": "Header-module_container", "bar": "Header-module_bar", "leftGroup": "Header-module_leftGroup", "desktopNav": "Header-module_desktopNav", "navLink": "Header-module_navLink", "desktopActions": "Header-module_desktopActions", "mobileToggle": "Header-module_mobileToggle", "mobileMenu": "Header-module_mobileMenu", "mobileNav": "Header-module_mobileNav", "mobileActions": "Header-module_mobileActions" };
3551
+ function Header({ logo, navItems = [], actions, className = "" }) {
3545
3552
  const [mobileOpen, setMobileOpen] = react.useState(false);
3546
3553
  return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: `${__default42.root}${className ? ` ${className}` : ""}`, children: [
3547
3554
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: __default42.container, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: __default42.bar, children: [
3548
3555
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: __default42.leftGroup, children: [
3549
- logo || /* @__PURE__ */ jsxRuntime.jsxs("span", { className: __default42.logoFallback, children: [
3550
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: __default42.logoBrand, children: "K" }),
3551
- "apustin"
3552
- ] }),
3556
+ logo,
3553
3557
  /* @__PURE__ */ jsxRuntime.jsx("nav", { className: __default42.desktopNav, children: navItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
3554
3558
  "a",
3555
3559
  {
@@ -3560,10 +3564,7 @@ function Header({ logo, navItems = [], className = "" }) {
3560
3564
  item.label
3561
3565
  )) })
3562
3566
  ] }),
3563
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: __default42.desktopActions, children: [
3564
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "md", children: "Sign in" }),
3565
- /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "md", children: "Get started" })
3566
- ] }),
3567
+ actions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: __default42.desktopActions, children: actions }),
3567
3568
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: __default42.mobileToggle, children: /* @__PURE__ */ jsxRuntime.jsx(
3568
3569
  IconButton,
3569
3570
  {
@@ -3584,18 +3585,20 @@ function Header({ logo, navItems = [], className = "" }) {
3584
3585
  },
3585
3586
  item.label
3586
3587
  )) }),
3587
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: __default42.mobileActions, children: [
3588
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "md", children: "Sign in" }),
3589
- /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "md", children: "Get started" })
3590
- ] })
3588
+ actions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: __default42.mobileActions, children: actions })
3591
3589
  ] })
3592
3590
  ] });
3593
3591
  }
3594
3592
 
3595
3593
  // css-inject-scss:/Users/dimakozh/Desktop/projects/kapustin.cc/packages/ui/src/organisms/Footer.module.scss
3596
- __styleInject(`.Footer-module_root {
3597
- border-top: 1px solid var(--border-color);
3594
+ __styleInject(`@charset "UTF-8";
3595
+ /* Footer \u2014 pill-style (border + radius + margin) by default */
3596
+ .Footer-module_root {
3597
+ margin: clamp(8px, 2vw, 24px);
3598
+ border: 1px solid var(--border-color);
3599
+ border-radius: var(--radius-2xl);
3598
3600
  background: var(--bg);
3601
+ overflow: hidden;
3599
3602
  }
3600
3603
 
3601
3604
  .Footer-module_container {
@@ -3625,18 +3628,13 @@ __styleInject(`.Footer-module_root {
3625
3628
  }
3626
3629
  }
3627
3630
 
3628
- .Footer-module_brand {
3629
- font-size: 1.125rem;
3630
- font-weight: 700;
3631
- color: var(--fg);
3632
- }
3633
-
3634
- .Footer-module_brandAccent {
3635
- color: var(--brand-primary);
3631
+ .Footer-module_brandCell {
3632
+ display: flex;
3633
+ flex-direction: column;
3636
3634
  }
3637
3635
 
3638
3636
  .Footer-module_tagline {
3639
- margin-top: 0.75rem;
3637
+ margin: 0.75rem 0 0 0;
3640
3638
  font-size: 13px;
3641
3639
  color: var(--fg-muted);
3642
3640
  line-height: 1.625;
@@ -3690,6 +3688,7 @@ __styleInject(`.Footer-module_root {
3690
3688
  font-size: 13px;
3691
3689
  color: var(--fg-muted);
3692
3690
  letter-spacing: -0.25px;
3691
+ margin: 0;
3693
3692
  }
3694
3693
 
3695
3694
  .Footer-module_socials {
@@ -3706,72 +3705,38 @@ __styleInject(`.Footer-module_root {
3706
3705
  .Footer-module_socialLink:hover {
3707
3706
  color: var(--fg);
3708
3707
  }`);
3709
- var __default43 = { "root": "Footer-module_root", "container": "Footer-module_container", "grid": "Footer-module_grid", "brand": "Footer-module_brand", "brandAccent": "Footer-module_brandAccent", "tagline": "Footer-module_tagline", "columnTitle": "Footer-module_columnTitle", "linkList": "Footer-module_linkList", "link": "Footer-module_link", "bottom": "Footer-module_bottom", "copyright": "Footer-module_copyright", "socials": "Footer-module_socials", "socialLink": "Footer-module_socialLink" };
3710
- var defaultColumns = [
3711
- {
3712
- title: "Product",
3713
- links: [
3714
- { label: "Components", href: "#" },
3715
- { label: "Templates", href: "#" },
3716
- { label: "Pricing", href: "#" },
3717
- { label: "Changelog", href: "#" }
3718
- ]
3719
- },
3720
- {
3721
- title: "Resources",
3722
- links: [
3723
- { label: "Documentation", href: "#" },
3724
- { label: "Guides", href: "#" },
3725
- { label: "API Reference", href: "#" },
3726
- { label: "Blog", href: "#" }
3727
- ]
3728
- },
3729
- {
3730
- title: "Company",
3731
- links: [
3732
- { label: "About", href: "#" },
3733
- { label: "Careers", href: "#" },
3734
- { label: "Contact", href: "#" },
3735
- { label: "Legal", href: "#" }
3736
- ]
3737
- }
3738
- ];
3739
- function Footer({ columns = defaultColumns, className = "" }) {
3708
+ var __default43 = { "root": "Footer-module_root", "container": "Footer-module_container", "grid": "Footer-module_grid", "brandCell": "Footer-module_brandCell", "tagline": "Footer-module_tagline", "columnTitle": "Footer-module_columnTitle", "linkList": "Footer-module_linkList", "link": "Footer-module_link", "bottom": "Footer-module_bottom", "copyright": "Footer-module_copyright", "socials": "Footer-module_socials", "socialLink": "Footer-module_socialLink" };
3709
+ function Footer({
3710
+ brand,
3711
+ columns,
3712
+ socials,
3713
+ copyright,
3714
+ className = ""
3715
+ }) {
3716
+ const hasBrand = !!(brand && (brand.logo || brand.tagline));
3717
+ const hasGrid = hasBrand || columns && columns.length > 0;
3718
+ const hasBottom = !!copyright || socials && socials.length > 0;
3740
3719
  return /* @__PURE__ */ jsxRuntime.jsx("footer", { className: `${__default43.root}${className ? ` ${className}` : ""}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: __default43.container, children: [
3741
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: __default43.grid, children: [
3742
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3743
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: __default43.brand, children: [
3744
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: __default43.brandAccent, children: "K" }),
3745
- "apustin"
3746
- ] }),
3747
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: __default43.tagline, children: "A modern design system for building beautiful interfaces." })
3720
+ hasGrid && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: __default43.grid, children: [
3721
+ hasBrand && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: __default43.brandCell, children: [
3722
+ brand == null ? void 0 : brand.logo,
3723
+ (brand == null ? void 0 : brand.tagline) && /* @__PURE__ */ jsxRuntime.jsx("p", { className: __default43.tagline, children: brand.tagline })
3748
3724
  ] }),
3749
- columns.map((col) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3725
+ columns == null ? void 0 : columns.map((col) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3750
3726
  /* @__PURE__ */ jsxRuntime.jsx("h4", { className: __default43.columnTitle, children: col.title }),
3751
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: __default43.linkList, children: col.links.map((link) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
3752
- "a",
3753
- {
3754
- href: link.href,
3755
- className: __default43.link,
3756
- children: link.label
3757
- }
3758
- ) }, link.label)) })
3727
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: __default43.linkList, children: col.links.map((link) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: link.href, className: __default43.link, children: link.label }) }, link.label)) })
3759
3728
  ] }, col.title))
3760
3729
  ] }),
3761
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: __default43.bottom, children: [
3762
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: __default43.copyright, children: [
3763
- "\xA9 ",
3764
- (/* @__PURE__ */ new Date()).getFullYear(),
3765
- " Kapustin Team. All rights reserved."
3766
- ] }),
3767
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: __default43.socials, children: ["Twitter", "GitHub", "Discord"].map((social) => /* @__PURE__ */ jsxRuntime.jsx(
3730
+ hasBottom && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: __default43.bottom, children: [
3731
+ copyright && /* @__PURE__ */ jsxRuntime.jsx("p", { className: __default43.copyright, children: copyright }),
3732
+ socials && socials.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: __default43.socials, children: socials.map((social) => /* @__PURE__ */ jsxRuntime.jsx(
3768
3733
  "a",
3769
3734
  {
3770
- href: "#",
3735
+ href: social.href,
3771
3736
  className: __default43.socialLink,
3772
- children: social
3737
+ children: social.label
3773
3738
  },
3774
- social
3739
+ social.label
3775
3740
  )) })
3776
3741
  ] })
3777
3742
  ] }) });
@@ -3865,6 +3830,7 @@ function PricingCard({
3865
3830
  features,
3866
3831
  highlighted = false,
3867
3832
  badge,
3833
+ cta,
3868
3834
  className = ""
3869
3835
  }) {
3870
3836
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -3885,7 +3851,15 @@ function PricingCard({
3885
3851
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: __default44.featureIcon, children: /* @__PURE__ */ jsxRuntime.jsx(IconlyCheck, { size: 16 }) }),
3886
3852
  feature
3887
3853
  ] }, i)) }),
3888
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: highlighted ? "primary" : "outline", className: __default44.cta, children: "Get started" })
3854
+ cta && /* @__PURE__ */ jsxRuntime.jsx(
3855
+ Button,
3856
+ {
3857
+ variant: highlighted ? "primary" : "outline",
3858
+ className: __default44.cta,
3859
+ onClick: cta.onClick,
3860
+ children: cta.label
3861
+ }
3862
+ )
3889
3863
  ]
3890
3864
  }
3891
3865
  );
package/dist/index.d.cts CHANGED
@@ -89,12 +89,24 @@ interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
89
89
  }
90
90
  declare function IconButton({ icon, variant, className, disabled, ...props }: IconButtonProps): react_jsx_runtime.JSX.Element;
91
91
 
92
- type LogoVersion = 'short' | 'full' | 'third';
93
92
  interface LogoProps {
94
- version?: LogoVersion;
93
+ /** Полный override через произвольный JSX. Имеет приоритет над text/src. */
94
+ children?: ReactNode;
95
+ /** URL картинки-логотипа. */
96
+ src?: string;
97
+ /** alt для картинки. */
98
+ alt?: string;
99
+ /** Ширина картинки. */
100
+ width?: number;
101
+ /** Высота картинки. */
102
+ height?: number;
103
+ /** Текстовый brand-name. */
104
+ text?: string;
105
+ /** Подстрока внутри text, выделяемая accent-цветом (первое вхождение). По умолчанию — первая буква text. */
106
+ accent?: string;
95
107
  className?: string;
96
108
  }
97
- declare function Logo({ version, className }: LogoProps): react_jsx_runtime.JSX.Element;
109
+ declare function Logo({ children, src, alt, width, height, text, accent, className, }: LogoProps): react_jsx_runtime.JSX.Element | null;
98
110
 
99
111
  interface StatBadgeProps {
100
112
  value: string;
@@ -440,11 +452,13 @@ interface NavItem {
440
452
  href: string;
441
453
  }
442
454
  interface HeaderProps {
443
- logo?: React.ReactNode;
455
+ logo?: ReactNode;
444
456
  navItems?: NavItem[];
457
+ /** Кнопки/контент справа (CTA). Если undefined — блок не рендерится. */
458
+ actions?: ReactNode;
445
459
  className?: string;
446
460
  }
447
- declare function Header({ logo, navItems, className }: HeaderProps): react_jsx_runtime.JSX.Element;
461
+ declare function Header({ logo, navItems, actions, className }: HeaderProps): react_jsx_runtime.JSX.Element;
448
462
 
449
463
  interface FooterColumn {
450
464
  title: string;
@@ -453,11 +467,28 @@ interface FooterColumn {
453
467
  href: string;
454
468
  }[];
455
469
  }
470
+ interface FooterSocial {
471
+ label: string;
472
+ href: string;
473
+ }
474
+ interface FooterBrand {
475
+ /** Логотип / brand-mark — любой JSX. */
476
+ logo?: ReactNode;
477
+ /** Tagline под логотипом. Применяется внутренний дизайн-стиль (13px, fg-muted, отступ сверху). */
478
+ tagline?: string;
479
+ }
456
480
  interface FooterProps {
481
+ /** Brand-cell слева в grid. Если undefined — ячейка не рендерится. */
482
+ brand?: FooterBrand;
483
+ /** Колонки навигации. */
457
484
  columns?: FooterColumn[];
485
+ /** Соц-ссылки в нижнем баре. Если undefined / [] — не рендерится. */
486
+ socials?: FooterSocial[];
487
+ /** Copyright-строка. Если undefined / null — не рендерится. */
488
+ copyright?: string | null;
458
489
  className?: string;
459
490
  }
460
- declare function Footer({ columns, className }: FooterProps): react_jsx_runtime.JSX.Element;
491
+ declare function Footer({ brand, columns, socials, copyright, className, }: FooterProps): react_jsx_runtime.JSX.Element;
461
492
 
462
493
  interface PricingCardProps {
463
494
  plan: string;
@@ -467,9 +498,15 @@ interface PricingCardProps {
467
498
  features: string[];
468
499
  highlighted?: boolean;
469
500
  badge?: string;
501
+ /** CTA-кнопка. Если undefined — кнопка не рендерится. */
502
+ cta?: {
503
+ label: string;
504
+ href?: string;
505
+ onClick?: () => void;
506
+ };
470
507
  className?: string;
471
508
  }
472
- declare function PricingCard({ plan, price, period, description, features, highlighted, badge, className, }: PricingCardProps): react_jsx_runtime.JSX.Element;
509
+ declare function PricingCard({ plan, price, period, description, features, highlighted, badge, cta, className, }: PricingCardProps): react_jsx_runtime.JSX.Element;
473
510
 
474
511
  interface TestimonialCardProps {
475
512
  quote: string;
package/dist/index.d.ts CHANGED
@@ -89,12 +89,24 @@ interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
89
89
  }
90
90
  declare function IconButton({ icon, variant, className, disabled, ...props }: IconButtonProps): react_jsx_runtime.JSX.Element;
91
91
 
92
- type LogoVersion = 'short' | 'full' | 'third';
93
92
  interface LogoProps {
94
- version?: LogoVersion;
93
+ /** Полный override через произвольный JSX. Имеет приоритет над text/src. */
94
+ children?: ReactNode;
95
+ /** URL картинки-логотипа. */
96
+ src?: string;
97
+ /** alt для картинки. */
98
+ alt?: string;
99
+ /** Ширина картинки. */
100
+ width?: number;
101
+ /** Высота картинки. */
102
+ height?: number;
103
+ /** Текстовый brand-name. */
104
+ text?: string;
105
+ /** Подстрока внутри text, выделяемая accent-цветом (первое вхождение). По умолчанию — первая буква text. */
106
+ accent?: string;
95
107
  className?: string;
96
108
  }
97
- declare function Logo({ version, className }: LogoProps): react_jsx_runtime.JSX.Element;
109
+ declare function Logo({ children, src, alt, width, height, text, accent, className, }: LogoProps): react_jsx_runtime.JSX.Element | null;
98
110
 
99
111
  interface StatBadgeProps {
100
112
  value: string;
@@ -440,11 +452,13 @@ interface NavItem {
440
452
  href: string;
441
453
  }
442
454
  interface HeaderProps {
443
- logo?: React.ReactNode;
455
+ logo?: ReactNode;
444
456
  navItems?: NavItem[];
457
+ /** Кнопки/контент справа (CTA). Если undefined — блок не рендерится. */
458
+ actions?: ReactNode;
445
459
  className?: string;
446
460
  }
447
- declare function Header({ logo, navItems, className }: HeaderProps): react_jsx_runtime.JSX.Element;
461
+ declare function Header({ logo, navItems, actions, className }: HeaderProps): react_jsx_runtime.JSX.Element;
448
462
 
449
463
  interface FooterColumn {
450
464
  title: string;
@@ -453,11 +467,28 @@ interface FooterColumn {
453
467
  href: string;
454
468
  }[];
455
469
  }
470
+ interface FooterSocial {
471
+ label: string;
472
+ href: string;
473
+ }
474
+ interface FooterBrand {
475
+ /** Логотип / brand-mark — любой JSX. */
476
+ logo?: ReactNode;
477
+ /** Tagline под логотипом. Применяется внутренний дизайн-стиль (13px, fg-muted, отступ сверху). */
478
+ tagline?: string;
479
+ }
456
480
  interface FooterProps {
481
+ /** Brand-cell слева в grid. Если undefined — ячейка не рендерится. */
482
+ brand?: FooterBrand;
483
+ /** Колонки навигации. */
457
484
  columns?: FooterColumn[];
485
+ /** Соц-ссылки в нижнем баре. Если undefined / [] — не рендерится. */
486
+ socials?: FooterSocial[];
487
+ /** Copyright-строка. Если undefined / null — не рендерится. */
488
+ copyright?: string | null;
458
489
  className?: string;
459
490
  }
460
- declare function Footer({ columns, className }: FooterProps): react_jsx_runtime.JSX.Element;
491
+ declare function Footer({ brand, columns, socials, copyright, className, }: FooterProps): react_jsx_runtime.JSX.Element;
461
492
 
462
493
  interface PricingCardProps {
463
494
  plan: string;
@@ -467,9 +498,15 @@ interface PricingCardProps {
467
498
  features: string[];
468
499
  highlighted?: boolean;
469
500
  badge?: string;
501
+ /** CTA-кнопка. Если undefined — кнопка не рендерится. */
502
+ cta?: {
503
+ label: string;
504
+ href?: string;
505
+ onClick?: () => void;
506
+ };
470
507
  className?: string;
471
508
  }
472
- declare function PricingCard({ plan, price, period, description, features, highlighted, badge, className, }: PricingCardProps): react_jsx_runtime.JSX.Element;
509
+ declare function PricingCard({ plan, price, period, description, features, highlighted, badge, cta, className, }: PricingCardProps): react_jsx_runtime.JSX.Element;
473
510
 
474
511
  interface TestimonialCardProps {
475
512
  quote: string;
package/dist/index.js CHANGED
@@ -909,40 +909,61 @@ function IconButton(_a) {
909
909
  }
910
910
 
911
911
  // css-inject-scss:/Users/dimakozh/Desktop/projects/kapustin.cc/packages/ui/src/atoms/Logo.module.scss
912
- __styleInject(`.Logo-module_short {
913
- width: 19px;
914
- height: 20px;
915
- }
916
-
917
- .Logo-module_full {
918
- height: 20px;
919
- width: 130px;
920
- }
921
-
922
- .Logo-module_third {
923
- display: flex;
912
+ __styleInject(`.Logo-module_root {
913
+ display: inline-flex;
924
914
  align-items: center;
925
915
  gap: 0.375rem;
926
916
  }
927
917
 
928
- .Logo-module_thirdText {
929
- font-size: 13px;
930
- font-weight: 500;
918
+ .Logo-module_image {
919
+ display: block;
920
+ }
921
+
922
+ .Logo-module_text {
923
+ font-size: 16px;
924
+ font-weight: 600;
931
925
  color: var(--fg);
932
926
  letter-spacing: -0.25px;
927
+ line-height: 1;
928
+ }
929
+
930
+ .Logo-module_accent {
931
+ color: var(--brand-primary);
933
932
  }`);
934
- var __default11 = { "short": "Logo-module_short", "full": "Logo-module_full", "third": "Logo-module_third", "thirdText": "Logo-module_thirdText" };
935
- function Logo({ version = "short", className = "" }) {
936
- if (version === "short") {
937
- return /* @__PURE__ */ jsx("div", { className: `${__default11.short}${className ? ` ${className}` : ""}`, children: /* @__PURE__ */ jsx("img", { className: "logo-img", src: "/assets/logos/logo-short.svg", alt: "aiacade.me", width: 19, height: 20 }) });
938
- }
939
- if (version === "third") {
940
- return /* @__PURE__ */ jsxs("div", { className: `${__default11.third}${className ? ` ${className}` : ""}`, children: [
941
- /* @__PURE__ */ jsx("img", { className: "logo-img", src: "/assets/logos/logo-icon.svg", alt: "", width: 20, height: 20 }),
942
- /* @__PURE__ */ jsx("span", { className: __default11.thirdText, children: "aiacade.me" })
943
- ] });
933
+ var __default11 = { "root": "Logo-module_root", "image": "Logo-module_image", "text": "Logo-module_text", "accent": "Logo-module_accent" };
934
+ function Logo({
935
+ children,
936
+ src,
937
+ alt = "",
938
+ width,
939
+ height,
940
+ text,
941
+ accent,
942
+ className = ""
943
+ }) {
944
+ const rootClass = `${__default11.root}${className ? ` ${className}` : ""}`;
945
+ if (children) {
946
+ return /* @__PURE__ */ jsx("span", { className: rootClass, children });
947
+ }
948
+ if (src) {
949
+ return /* @__PURE__ */ jsx("span", { className: rootClass, children: /* @__PURE__ */ jsx("img", { className: __default11.image, src, alt, width, height }) });
950
+ }
951
+ if (text) {
952
+ const accentText = accent != null ? accent : text.charAt(0);
953
+ const idx = accent ? text.indexOf(accent) : 0;
954
+ if (idx >= 0 && accentText) {
955
+ const before = text.slice(0, idx);
956
+ const middle = text.slice(idx, idx + accentText.length);
957
+ const after = text.slice(idx + accentText.length);
958
+ return /* @__PURE__ */ jsx("span", { className: rootClass, children: /* @__PURE__ */ jsxs("span", { className: __default11.text, children: [
959
+ before,
960
+ /* @__PURE__ */ jsx("span", { className: __default11.accent, children: middle }),
961
+ after
962
+ ] }) });
963
+ }
964
+ return /* @__PURE__ */ jsx("span", { className: rootClass, children: /* @__PURE__ */ jsx("span", { className: __default11.text, children: text }) });
944
965
  }
945
- return /* @__PURE__ */ jsx("div", { className: `${__default11.full}${className ? ` ${className}` : ""}`, children: /* @__PURE__ */ jsx("img", { className: "logo-img", src: "/assets/logos/logo-full.svg", alt: "aiacade.me", width: 130, height: 20 }) });
966
+ return null;
946
967
  }
947
968
 
948
969
  // css-inject-scss:/Users/dimakozh/Desktop/projects/kapustin.cc/packages/ui/src/atoms/StatBadge.module.scss
@@ -3409,12 +3430,16 @@ function DropdownMenu({
3409
3430
  }
3410
3431
 
3411
3432
  // css-inject-scss:/Users/dimakozh/Desktop/projects/kapustin.cc/packages/ui/src/organisms/Header.module.scss
3412
- __styleInject(`.Header-module_root {
3413
- border-bottom: 1px solid var(--border-color);
3433
+ __styleInject(`@charset "UTF-8";
3434
+ /* Header \u2014 pill-style (border + radius + margin) by default */
3435
+ .Header-module_root {
3436
+ margin: clamp(8px, 2vw, 24px);
3437
+ border: 1px solid var(--border-color);
3438
+ border-radius: var(--radius-2xl);
3414
3439
  background: color-mix(in srgb, var(--bg) 80%, transparent);
3415
3440
  backdrop-filter: blur(12px);
3416
3441
  position: sticky;
3417
- top: 0;
3442
+ top: clamp(8px, 2vw, 24px);
3418
3443
  z-index: 50;
3419
3444
  }
3420
3445
 
@@ -3447,16 +3472,6 @@ __styleInject(`.Header-module_root {
3447
3472
  gap: 2rem;
3448
3473
  }
3449
3474
 
3450
- .Header-module_logoFallback {
3451
- font-size: 1.125rem;
3452
- font-weight: 700;
3453
- color: var(--fg);
3454
- }
3455
-
3456
- .Header-module_logoBrand {
3457
- color: var(--brand-primary);
3458
- }
3459
-
3460
3475
  .Header-module_desktopNav {
3461
3476
  display: none;
3462
3477
  align-items: center;
@@ -3493,14 +3508,6 @@ __styleInject(`.Header-module_root {
3493
3508
 
3494
3509
  .Header-module_mobileToggle {
3495
3510
  display: block;
3496
- padding: 0.5rem;
3497
- color: var(--fg-secondary);
3498
- cursor: pointer;
3499
- background: none;
3500
- border: none;
3501
- }
3502
- .Header-module_mobileToggle:hover {
3503
- color: var(--fg);
3504
3511
  }
3505
3512
  @media (min-width: 768px) {
3506
3513
  .Header-module_mobileToggle {
@@ -3534,16 +3541,13 @@ __styleInject(`.Header-module_root {
3534
3541
  padding-top: 1rem;
3535
3542
  border-top: 1px solid var(--border-color);
3536
3543
  }`);
3537
- var __default42 = { "root": "Header-module_root", "container": "Header-module_container", "bar": "Header-module_bar", "leftGroup": "Header-module_leftGroup", "logoFallback": "Header-module_logoFallback", "logoBrand": "Header-module_logoBrand", "desktopNav": "Header-module_desktopNav", "navLink": "Header-module_navLink", "desktopActions": "Header-module_desktopActions", "mobileToggle": "Header-module_mobileToggle", "mobileMenu": "Header-module_mobileMenu", "mobileNav": "Header-module_mobileNav", "mobileActions": "Header-module_mobileActions" };
3538
- function Header({ logo, navItems = [], className = "" }) {
3544
+ var __default42 = { "root": "Header-module_root", "container": "Header-module_container", "bar": "Header-module_bar", "leftGroup": "Header-module_leftGroup", "desktopNav": "Header-module_desktopNav", "navLink": "Header-module_navLink", "desktopActions": "Header-module_desktopActions", "mobileToggle": "Header-module_mobileToggle", "mobileMenu": "Header-module_mobileMenu", "mobileNav": "Header-module_mobileNav", "mobileActions": "Header-module_mobileActions" };
3545
+ function Header({ logo, navItems = [], actions, className = "" }) {
3539
3546
  const [mobileOpen, setMobileOpen] = useState(false);
3540
3547
  return /* @__PURE__ */ jsxs("header", { className: `${__default42.root}${className ? ` ${className}` : ""}`, children: [
3541
3548
  /* @__PURE__ */ jsx("div", { className: __default42.container, children: /* @__PURE__ */ jsxs("div", { className: __default42.bar, children: [
3542
3549
  /* @__PURE__ */ jsxs("div", { className: __default42.leftGroup, children: [
3543
- logo || /* @__PURE__ */ jsxs("span", { className: __default42.logoFallback, children: [
3544
- /* @__PURE__ */ jsx("span", { className: __default42.logoBrand, children: "K" }),
3545
- "apustin"
3546
- ] }),
3550
+ logo,
3547
3551
  /* @__PURE__ */ jsx("nav", { className: __default42.desktopNav, children: navItems.map((item) => /* @__PURE__ */ jsx(
3548
3552
  "a",
3549
3553
  {
@@ -3554,10 +3558,7 @@ function Header({ logo, navItems = [], className = "" }) {
3554
3558
  item.label
3555
3559
  )) })
3556
3560
  ] }),
3557
- /* @__PURE__ */ jsxs("div", { className: __default42.desktopActions, children: [
3558
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "md", children: "Sign in" }),
3559
- /* @__PURE__ */ jsx(Button, { size: "md", children: "Get started" })
3560
- ] }),
3561
+ actions && /* @__PURE__ */ jsx("div", { className: __default42.desktopActions, children: actions }),
3561
3562
  /* @__PURE__ */ jsx("div", { className: __default42.mobileToggle, children: /* @__PURE__ */ jsx(
3562
3563
  IconButton,
3563
3564
  {
@@ -3578,18 +3579,20 @@ function Header({ logo, navItems = [], className = "" }) {
3578
3579
  },
3579
3580
  item.label
3580
3581
  )) }),
3581
- /* @__PURE__ */ jsxs("div", { className: __default42.mobileActions, children: [
3582
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "md", children: "Sign in" }),
3583
- /* @__PURE__ */ jsx(Button, { size: "md", children: "Get started" })
3584
- ] })
3582
+ actions && /* @__PURE__ */ jsx("div", { className: __default42.mobileActions, children: actions })
3585
3583
  ] })
3586
3584
  ] });
3587
3585
  }
3588
3586
 
3589
3587
  // css-inject-scss:/Users/dimakozh/Desktop/projects/kapustin.cc/packages/ui/src/organisms/Footer.module.scss
3590
- __styleInject(`.Footer-module_root {
3591
- border-top: 1px solid var(--border-color);
3588
+ __styleInject(`@charset "UTF-8";
3589
+ /* Footer \u2014 pill-style (border + radius + margin) by default */
3590
+ .Footer-module_root {
3591
+ margin: clamp(8px, 2vw, 24px);
3592
+ border: 1px solid var(--border-color);
3593
+ border-radius: var(--radius-2xl);
3592
3594
  background: var(--bg);
3595
+ overflow: hidden;
3593
3596
  }
3594
3597
 
3595
3598
  .Footer-module_container {
@@ -3619,18 +3622,13 @@ __styleInject(`.Footer-module_root {
3619
3622
  }
3620
3623
  }
3621
3624
 
3622
- .Footer-module_brand {
3623
- font-size: 1.125rem;
3624
- font-weight: 700;
3625
- color: var(--fg);
3626
- }
3627
-
3628
- .Footer-module_brandAccent {
3629
- color: var(--brand-primary);
3625
+ .Footer-module_brandCell {
3626
+ display: flex;
3627
+ flex-direction: column;
3630
3628
  }
3631
3629
 
3632
3630
  .Footer-module_tagline {
3633
- margin-top: 0.75rem;
3631
+ margin: 0.75rem 0 0 0;
3634
3632
  font-size: 13px;
3635
3633
  color: var(--fg-muted);
3636
3634
  line-height: 1.625;
@@ -3684,6 +3682,7 @@ __styleInject(`.Footer-module_root {
3684
3682
  font-size: 13px;
3685
3683
  color: var(--fg-muted);
3686
3684
  letter-spacing: -0.25px;
3685
+ margin: 0;
3687
3686
  }
3688
3687
 
3689
3688
  .Footer-module_socials {
@@ -3700,72 +3699,38 @@ __styleInject(`.Footer-module_root {
3700
3699
  .Footer-module_socialLink:hover {
3701
3700
  color: var(--fg);
3702
3701
  }`);
3703
- var __default43 = { "root": "Footer-module_root", "container": "Footer-module_container", "grid": "Footer-module_grid", "brand": "Footer-module_brand", "brandAccent": "Footer-module_brandAccent", "tagline": "Footer-module_tagline", "columnTitle": "Footer-module_columnTitle", "linkList": "Footer-module_linkList", "link": "Footer-module_link", "bottom": "Footer-module_bottom", "copyright": "Footer-module_copyright", "socials": "Footer-module_socials", "socialLink": "Footer-module_socialLink" };
3704
- var defaultColumns = [
3705
- {
3706
- title: "Product",
3707
- links: [
3708
- { label: "Components", href: "#" },
3709
- { label: "Templates", href: "#" },
3710
- { label: "Pricing", href: "#" },
3711
- { label: "Changelog", href: "#" }
3712
- ]
3713
- },
3714
- {
3715
- title: "Resources",
3716
- links: [
3717
- { label: "Documentation", href: "#" },
3718
- { label: "Guides", href: "#" },
3719
- { label: "API Reference", href: "#" },
3720
- { label: "Blog", href: "#" }
3721
- ]
3722
- },
3723
- {
3724
- title: "Company",
3725
- links: [
3726
- { label: "About", href: "#" },
3727
- { label: "Careers", href: "#" },
3728
- { label: "Contact", href: "#" },
3729
- { label: "Legal", href: "#" }
3730
- ]
3731
- }
3732
- ];
3733
- function Footer({ columns = defaultColumns, className = "" }) {
3702
+ var __default43 = { "root": "Footer-module_root", "container": "Footer-module_container", "grid": "Footer-module_grid", "brandCell": "Footer-module_brandCell", "tagline": "Footer-module_tagline", "columnTitle": "Footer-module_columnTitle", "linkList": "Footer-module_linkList", "link": "Footer-module_link", "bottom": "Footer-module_bottom", "copyright": "Footer-module_copyright", "socials": "Footer-module_socials", "socialLink": "Footer-module_socialLink" };
3703
+ function Footer({
3704
+ brand,
3705
+ columns,
3706
+ socials,
3707
+ copyright,
3708
+ className = ""
3709
+ }) {
3710
+ const hasBrand = !!(brand && (brand.logo || brand.tagline));
3711
+ const hasGrid = hasBrand || columns && columns.length > 0;
3712
+ const hasBottom = !!copyright || socials && socials.length > 0;
3734
3713
  return /* @__PURE__ */ jsx("footer", { className: `${__default43.root}${className ? ` ${className}` : ""}`, children: /* @__PURE__ */ jsxs("div", { className: __default43.container, children: [
3735
- /* @__PURE__ */ jsxs("div", { className: __default43.grid, children: [
3736
- /* @__PURE__ */ jsxs("div", { children: [
3737
- /* @__PURE__ */ jsxs("span", { className: __default43.brand, children: [
3738
- /* @__PURE__ */ jsx("span", { className: __default43.brandAccent, children: "K" }),
3739
- "apustin"
3740
- ] }),
3741
- /* @__PURE__ */ jsx("p", { className: __default43.tagline, children: "A modern design system for building beautiful interfaces." })
3714
+ hasGrid && /* @__PURE__ */ jsxs("div", { className: __default43.grid, children: [
3715
+ hasBrand && /* @__PURE__ */ jsxs("div", { className: __default43.brandCell, children: [
3716
+ brand == null ? void 0 : brand.logo,
3717
+ (brand == null ? void 0 : brand.tagline) && /* @__PURE__ */ jsx("p", { className: __default43.tagline, children: brand.tagline })
3742
3718
  ] }),
3743
- columns.map((col) => /* @__PURE__ */ jsxs("div", { children: [
3719
+ columns == null ? void 0 : columns.map((col) => /* @__PURE__ */ jsxs("div", { children: [
3744
3720
  /* @__PURE__ */ jsx("h4", { className: __default43.columnTitle, children: col.title }),
3745
- /* @__PURE__ */ jsx("ul", { className: __default43.linkList, children: col.links.map((link) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
3746
- "a",
3747
- {
3748
- href: link.href,
3749
- className: __default43.link,
3750
- children: link.label
3751
- }
3752
- ) }, link.label)) })
3721
+ /* @__PURE__ */ jsx("ul", { className: __default43.linkList, children: col.links.map((link) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: link.href, className: __default43.link, children: link.label }) }, link.label)) })
3753
3722
  ] }, col.title))
3754
3723
  ] }),
3755
- /* @__PURE__ */ jsxs("div", { className: __default43.bottom, children: [
3756
- /* @__PURE__ */ jsxs("p", { className: __default43.copyright, children: [
3757
- "\xA9 ",
3758
- (/* @__PURE__ */ new Date()).getFullYear(),
3759
- " Kapustin Team. All rights reserved."
3760
- ] }),
3761
- /* @__PURE__ */ jsx("div", { className: __default43.socials, children: ["Twitter", "GitHub", "Discord"].map((social) => /* @__PURE__ */ jsx(
3724
+ hasBottom && /* @__PURE__ */ jsxs("div", { className: __default43.bottom, children: [
3725
+ copyright && /* @__PURE__ */ jsx("p", { className: __default43.copyright, children: copyright }),
3726
+ socials && socials.length > 0 && /* @__PURE__ */ jsx("div", { className: __default43.socials, children: socials.map((social) => /* @__PURE__ */ jsx(
3762
3727
  "a",
3763
3728
  {
3764
- href: "#",
3729
+ href: social.href,
3765
3730
  className: __default43.socialLink,
3766
- children: social
3731
+ children: social.label
3767
3732
  },
3768
- social
3733
+ social.label
3769
3734
  )) })
3770
3735
  ] })
3771
3736
  ] }) });
@@ -3859,6 +3824,7 @@ function PricingCard({
3859
3824
  features,
3860
3825
  highlighted = false,
3861
3826
  badge,
3827
+ cta,
3862
3828
  className = ""
3863
3829
  }) {
3864
3830
  return /* @__PURE__ */ jsxs(
@@ -3879,7 +3845,15 @@ function PricingCard({
3879
3845
  /* @__PURE__ */ jsx("span", { className: __default44.featureIcon, children: /* @__PURE__ */ jsx(IconlyCheck, { size: 16 }) }),
3880
3846
  feature
3881
3847
  ] }, i)) }),
3882
- /* @__PURE__ */ jsx(Button, { variant: highlighted ? "primary" : "outline", className: __default44.cta, children: "Get started" })
3848
+ cta && /* @__PURE__ */ jsx(
3849
+ Button,
3850
+ {
3851
+ variant: highlighted ? "primary" : "outline",
3852
+ className: __default44.cta,
3853
+ onClick: cta.onClick,
3854
+ children: cta.label
3855
+ }
3856
+ )
3883
3857
  ]
3884
3858
  }
3885
3859
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dmitriikapustin/ui",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Universal UI/UX Kit — React 19 component library with Atomic Design, CSS custom properties, and SCSS modules",
5
5
  "author": "Kapustin Team",
6
6
  "license": "MIT",