@pelatform/starter.shared 0.2.14 → 0.2.16

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.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
- import { ReactNode, CSSProperties, ComponentProps, PropsWithChildren, ComponentType } from 'react';
3
+ import { ReactNode, ComponentProps, CSSProperties, PropsWithChildren, ComponentType } from 'react';
4
4
  import { MenuItem } from 'pelatform-ui';
5
5
  import { NavItem, LanguageSwitcherProps } from 'pelatform-ui/components';
6
6
  export { Logo as LogoDefault } from 'pelatform-ui/components';
@@ -35,6 +35,14 @@ declare function LayoutLoader({ children }: {
35
35
  children: ReactNode;
36
36
  }): string | number | bigint | boolean | react_jsx_runtime.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
37
37
 
38
+ declare function UserMenu({ homeUrl, hiddenSwitcher, side, align, sideOffset, }: {
39
+ homeUrl?: string;
40
+ hiddenSwitcher?: boolean;
41
+ side?: "bottom" | "top" | "right" | "left";
42
+ align?: "center" | "end" | "start";
43
+ sideOffset?: number;
44
+ }): react_jsx_runtime.JSX.Element;
45
+
38
46
  declare function Sidebar({ children }: {
39
47
  children: ReactNode;
40
48
  }): react_jsx_runtime.JSX.Element | null;
@@ -50,6 +58,10 @@ declare function SidebarContentMenu({ menu, type, }: {
50
58
  menu: MenuItem[];
51
59
  type?: "default" | "toggle";
52
60
  }): react_jsx_runtime.JSX.Element;
61
+ declare function SidebarFooter({ children, className, side, align, sideOffset, ...props }: ComponentProps<typeof UserMenu> & {
62
+ children?: ReactNode;
63
+ className?: string;
64
+ }): react_jsx_runtime.JSX.Element;
53
65
 
54
66
  declare function SiteFooter({ disableProjectBy }: {
55
67
  disableProjectBy?: boolean;
@@ -77,11 +89,13 @@ interface LayoutWrapperProps {
77
89
  children: ReactNode;
78
90
  sidebarHeader: ReactNode;
79
91
  sidebarMenu: ReactNode;
92
+ sidebarFooter?: ReactNode;
80
93
  logoHeader?: ReactNode;
94
+ version?: "v1" | "v2";
81
95
  homeUrl?: string;
82
96
  studioUrl?: string;
83
97
  }
84
- declare function LayoutWrapper({ children, sidebarHeader, sidebarMenu, logoHeader, homeUrl, studioUrl, }: LayoutWrapperProps): react_jsx_runtime.JSX.Element;
98
+ declare function LayoutWrapper({ children, logoHeader, version, ...props }: LayoutWrapperProps): react_jsx_runtime.JSX.Element;
85
99
 
86
100
  /**
87
101
  * Props for the ConfigProvider component
@@ -135,8 +149,9 @@ interface LayoutProviderProps {
135
149
  bodyClassName?: string;
136
150
  className?: string;
137
151
  logoHeader?: ReactNode;
152
+ version?: "v1" | "v2";
138
153
  }
139
- declare function LayoutProvider({ children, style: customStyle, bodyClassName, className, logoHeader, }: LayoutProviderProps): react_jsx_runtime.JSX.Element;
154
+ declare function LayoutProvider({ children, style: customStyle, bodyClassName, className, logoHeader, version, }: LayoutProviderProps): react_jsx_runtime.JSX.Element;
140
155
 
141
156
  interface SharedProvidersProps {
142
157
  children: ReactNode;
@@ -278,11 +293,6 @@ declare function SignedInHint({ linkHref }: {
278
293
  linkHref?: string;
279
294
  }): react_jsx_runtime.JSX.Element;
280
295
 
281
- declare function UserMenu({ homeUrl, hiddenSwitcher, }: {
282
- homeUrl?: string;
283
- hiddenSwitcher?: boolean;
284
- }): react_jsx_runtime.JSX.Element;
285
-
286
296
  type ViewClassNames = {
287
297
  base?: string;
288
298
  content?: string;
@@ -406,4 +416,4 @@ type Provider = {
406
416
  icon?: ProviderIcon;
407
417
  };
408
418
 
409
- export { ApiKeyView, AuthLayout, type AvatarClassNames, type AvatarProps, CardActionComponent, type CardClassNames, CardComponent, type CardComponentProps, CardFooterComponent, CardHeaderComponent, ConfigProvider, type ConfigProviderProps, type DialogClassNames, DialogComponent, type DialogComponentProps, DialogFooterComponent, DisplayIdCard, EmptyState, type EmptyStateProps, Header, HeaderLeft, HeaderRight, HeaderSidebarMobile, LanguageSwitcher, LayoutLoader, LayoutProvider, type LayoutProviderProps, LayoutWrapper, LogoWithHref, LogoWithName, OTPInputGroup, PasswordInput, type Provider, type ProviderIcon, SharedProviders, type SharedProvidersProps, Sidebar, SidebarContent, SidebarContentMenu, SidebarHeaderBack, SignedInHint, SiteFooter, SiteHeader, SiteHeaderSecondary, SkeletonInputComponent, SkeletonViewComponent, Toolbar, UserAvatar, UserMenu, UserView, type ViewClassNames, type ViewProps, WorkspaceLogo, WorkspaceView, socialProviders };
419
+ export { ApiKeyView, AuthLayout, type AvatarClassNames, type AvatarProps, CardActionComponent, type CardClassNames, CardComponent, type CardComponentProps, CardFooterComponent, CardHeaderComponent, ConfigProvider, type ConfigProviderProps, type DialogClassNames, DialogComponent, type DialogComponentProps, DialogFooterComponent, DisplayIdCard, EmptyState, type EmptyStateProps, Header, HeaderLeft, HeaderRight, HeaderSidebarMobile, LanguageSwitcher, LayoutLoader, LayoutProvider, type LayoutProviderProps, LayoutWrapper, LogoWithHref, LogoWithName, OTPInputGroup, PasswordInput, type Provider, type ProviderIcon, SharedProviders, type SharedProvidersProps, Sidebar, SidebarContent, SidebarContentMenu, SidebarFooter, SidebarHeaderBack, SignedInHint, SiteFooter, SiteHeader, SiteHeaderSecondary, SkeletonInputComponent, SkeletonViewComponent, Toolbar, UserAvatar, UserMenu, UserView, type ViewClassNames, type ViewProps, WorkspaceLogo, WorkspaceView, socialProviders };
package/dist/index.js CHANGED
@@ -512,9 +512,12 @@ function WorkspaceView({ className, classNames, isPending, size, workspace }) {
512
512
  import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
513
513
  function UserMenu({
514
514
  homeUrl,
515
- hiddenSwitcher = false
515
+ hiddenSwitcher = false,
516
+ side = "bottom",
517
+ align = "end",
518
+ sideOffset = 11
516
519
  }) {
517
- const { features, path } = useConfig4();
520
+ const { auth, features, path } = useConfig4();
518
521
  const router = useRouter2();
519
522
  const t = useTranslations7();
520
523
  const { isPending: sessionPending, user } = useSession3();
@@ -534,13 +537,14 @@ function UserMenu({
534
537
  try {
535
538
  await setActiveSessionAsync({ sessionToken });
536
539
  router.refresh();
540
+ router.push(auth.redirectAfterSignIn || "/");
537
541
  setActiveSessionPending(false);
538
542
  } catch (error) {
539
543
  console.error("Error switching account:", error);
540
544
  setActiveSessionPending(false);
541
545
  }
542
546
  },
543
- [router, setActiveSessionAsync]
547
+ [router, setActiveSessionAsync, auth.redirectAfterSignIn]
544
548
  );
545
549
  useEffect(() => {
546
550
  if (!features.multiSession) return;
@@ -552,7 +556,7 @@ function UserMenu({
552
556
  const userRole = user?.role || "user";
553
557
  return /* @__PURE__ */ jsxs7(DropdownMenu, { children: [
554
558
  /* @__PURE__ */ jsx9(DropdownMenuTrigger, { className: "focus:outline-none focus:ring-0", children: isPending ? /* @__PURE__ */ jsx9(Skeleton3, { className: "size-8 shrink-0 rounded-full" }) : /* @__PURE__ */ jsx9(UserAvatar2, { className: "size-8", indicator: true, src: userAvatar, alt: userName }) }),
555
- /* @__PURE__ */ jsxs7(DropdownMenuContent, { className: "w-56", side: "bottom", align: "end", sideOffset: 11, children: [
559
+ /* @__PURE__ */ jsxs7(DropdownMenuContent, { className: "w-56", side, align, sideOffset, children: [
556
560
  /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3 px-3 py-2", children: [
557
561
  /* @__PURE__ */ jsx9(UserAvatar2, { src: userAvatar, alt: userName }),
558
562
  /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1 flex-col items-start", children: [
@@ -627,6 +631,10 @@ function UserMenu({
627
631
  // src/components/layouts/header.tsx
628
632
  import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
629
633
  function Header({ children }) {
634
+ const { version } = useLayout();
635
+ if (version === "v2") {
636
+ return /* @__PURE__ */ jsx10("header", { className: "fixed start-0 end-0 top-0 z-50 flex h-(--header-height-mobile) shrink-0 items-center bg-background/95 pe-[var(--removed-body-scroll-bar-size,0px)] backdrop-blur-sm transition-[start,end] duration-300 supports-backdrop-filter:bg-muted", children: /* @__PURE__ */ jsx10("div", { className: "@container flex grow items-stretch justify-between gap-2.5 pe-5", children }) });
637
+ }
630
638
  return /* @__PURE__ */ jsx10("header", { className: "fixed start-0 end-0 top-0 z-10 flex h-(--header-height-mobile) shrink-0 items-stretch border-border border-b bg-background/95 pe-(--removed-body-scroll-bar-size,0px) backdrop-blur-sm supports-backdrop-filter:bg-background/60 lg:h-(--header-height)", children: /* @__PURE__ */ jsx10("div", { className: "@container flex grow items-stretch justify-between gap-2.5 pe-5", children }) });
631
639
  }
632
640
  function HeaderLeft() {
@@ -681,6 +689,7 @@ import Link5 from "next/link";
681
689
  import { usePathname as usePathname3 } from "next/navigation";
682
690
  import { useLocale as useLocale3, useTranslations as useTranslations8 } from "next-intl";
683
691
  import { useLayout as useLayout2 } from "@pelatform/starter.hook";
692
+ import { cn as cn5 } from "pelatform-ui";
684
693
  import { BackLink } from "pelatform-ui/components";
685
694
  import {
686
695
  AccordionMenu,
@@ -696,10 +705,16 @@ import {
696
705
  } from "pelatform-ui/default";
697
706
  import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
698
707
  function Sidebar({ children }) {
699
- const { isMobile } = useLayout2();
708
+ const { isMobile, logoHeader, version } = useLayout2();
700
709
  if (isMobile) {
701
710
  return null;
702
711
  }
712
+ if (version === "v2") {
713
+ return /* @__PURE__ */ jsx11("aside", { className: "fixed start-2.5 top-2.5 bottom-2.5 z-20 flex in-data-[sidebar-open=false]:w-(--sidebar-width-collapsed) w-(--sidebar-width) shrink-0 items-stretch overflow-hidden rounded-xl border border-input bg-background transition-all duration-300", children: /* @__PURE__ */ jsxs9("div", { className: "w-(--sidebar-width) shrink-0 grow transition-all duration-300", children: [
714
+ /* @__PURE__ */ jsx11("div", { className: "flex h-14 shrink-0 items-center justify-center px-2.5 lg:h-15", children: logoHeader }),
715
+ children
716
+ ] }) });
717
+ }
703
718
  return /* @__PURE__ */ jsxs9("aside", { className: "fixed in-data-[sidebar-open=false]:-start-full start-0 top-(--header-height) bottom-0 flex w-(--sidebar-width) shrink-0 flex-col items-stretch border-border border-e transition-all duration-300", children: [
704
719
  children,
705
720
  /* @__PURE__ */ jsx11("div", {})
@@ -714,7 +729,19 @@ function SidebarHeaderBack({
714
729
  return /* @__PURE__ */ jsx11("div", { className: "flex h-14 shrink-0 items-center gap-2 border-border border-b px-2.5 lg:h-15", children: /* @__PURE__ */ jsx11(BackLink, { Link: Link5, href: linkHref, children: text ?? (admin ? t("common.actions.back") : t("ui.navigation.settings")) }) });
715
730
  }
716
731
  function SidebarContent({ children }) {
717
- return /* @__PURE__ */ jsx11(ScrollArea, { className: "mt-2 mb-2.5 h-[calc(100vh-5.5rem)] grow lg:mt-4 lg:mb-7.5 lg:h-[calc(100vh-4rem)]", children });
732
+ const { isMobile, version } = useLayout2();
733
+ if (version === "v2") {
734
+ return /* @__PURE__ */ jsx11(
735
+ ScrollArea,
736
+ {
737
+ className: cn5(
738
+ isMobile ? "my-2 h-[calc(100vh-5.5rem)] grow" : "my-2 h-[calc(100vh-1rem)] w-full shrink-0 lg:my-4 lg:h-[calc(100vh-14.7rem)]"
739
+ ),
740
+ children
741
+ }
742
+ );
743
+ }
744
+ return /* @__PURE__ */ jsx11(ScrollArea, { className: "my-2 h-[calc(100vh-5.5rem)] grow lg:my-4 lg:h-[calc(100vh-4rem)]", children });
718
745
  }
719
746
  function SidebarContentMenu({
720
747
  menu,
@@ -859,19 +886,41 @@ function SidebarContentMenu({
859
886
  }
860
887
  );
861
888
  }
889
+ function SidebarFooter({
890
+ children,
891
+ className,
892
+ side = "top",
893
+ align = "start",
894
+ sideOffset = 10,
895
+ ...props
896
+ }) {
897
+ return /* @__PURE__ */ jsxs9(
898
+ "div",
899
+ {
900
+ className: cn5(
901
+ "flex h-14 shrink-0 items-center gap-2 border-border border-t px-2.5 lg:h-15",
902
+ className
903
+ ),
904
+ children: [
905
+ /* @__PURE__ */ jsx11(UserMenu, { side, align, sideOffset, ...props }),
906
+ children
907
+ ]
908
+ }
909
+ );
910
+ }
862
911
 
863
912
  // src/components/layouts/site-footer.tsx
864
913
  import Link6 from "next/link";
865
914
  import { useTranslations as useTranslations9 } from "next-intl";
866
915
  import { useConfig as useConfig5 } from "@pelatform/starter.hook";
867
- import { cn as cn5 } from "pelatform-ui";
916
+ import { cn as cn6 } from "pelatform-ui";
868
917
  import { SiteFooter as UISiteFooter } from "pelatform-ui/components";
869
918
  import { Button as Button3 } from "pelatform-ui/default";
870
919
  import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
871
920
  function SiteFooter({ disableProjectBy = false }) {
872
921
  const { app } = useConfig5();
873
922
  const t = useTranslations9();
874
- return /* @__PURE__ */ jsxs10(UISiteFooter, { className: cn5("*:gap-2! *:py-0!", disableProjectBy ? "*:justify-center!" : ""), children: [
923
+ return /* @__PURE__ */ jsxs10(UISiteFooter, { className: cn6("*:gap-2! *:py-0!", disableProjectBy ? "*:justify-center!" : ""), children: [
875
924
  /* @__PURE__ */ jsxs10("div", { className: "text-balance text-center text-muted-foreground text-sm leading-loose md:text-left", children: [
876
925
  "\xA9 ",
877
926
  (/* @__PURE__ */ new Date()).getFullYear(),
@@ -1002,51 +1051,73 @@ function SiteHeaderSecondary({
1002
1051
  }
1003
1052
 
1004
1053
  // src/components/layouts/wrapper.tsx
1054
+ import { useEffect as useEffect4, useState as useState5 } from "react";
1005
1055
  import Link8 from "next/link";
1006
1056
  import { RocketIcon } from "lucide-react";
1007
- import { useSession as useSession5 } from "@pelatform/starter.hook";
1057
+ import { useLayout as useLayout3, useSession as useSession5 } from "@pelatform/starter.hook";
1058
+ import { cn as cn8 } from "pelatform-ui";
1008
1059
  import { Button as Button5 } from "pelatform-ui/default";
1009
1060
 
1010
1061
  // src/components/providers/layout.tsx
1011
- import { useEffect as useEffect3, useState as useState4 } from "react";
1062
+ import { useEffect as useEffect3, useMemo as useMemo2, useState as useState4 } from "react";
1012
1063
  import { LayoutContext } from "@pelatform/starter.hook";
1013
- import { cn as cn6 } from "pelatform-ui";
1064
+ import { cn as cn7 } from "pelatform-ui";
1065
+ import { TooltipProvider } from "pelatform-ui/default";
1014
1066
  import { useIsMobile } from "pelatform-ui/hooks";
1015
1067
  import { jsx as jsx14 } from "react/jsx-runtime";
1016
1068
  var SIDEBAR_WIDTH = "240px";
1017
1069
  var HEADER_HEIGHT = "54px";
1018
1070
  var SIDEBAR_WIDTH_MOBILE = "240px";
1019
1071
  var HEADER_HEIGHT_MOBILE = "54px";
1072
+ var SIDEBAR_WIDTH_V2 = "255px";
1073
+ var HEADER_HEIGHT_V2 = "60px";
1074
+ var SIDEBAR_WIDTH_MOBILE_V2 = "60px";
1075
+ var HEADER_HEIGHT_MOBILE_V2 = "60px";
1020
1076
  function LayoutProvider({
1021
1077
  children,
1022
1078
  style: customStyle,
1023
1079
  bodyClassName = "",
1024
1080
  className = "",
1025
- logoHeader = /* @__PURE__ */ jsx14(LogoWithHref, {})
1081
+ logoHeader = /* @__PURE__ */ jsx14(LogoWithHref, {}),
1082
+ version = "v1"
1026
1083
  }) {
1027
1084
  const isMobile = useIsMobile();
1028
1085
  const [isSidebarOpen, setIsSidebarOpen] = useState4(true);
1029
- const defaultStyle = {
1030
- "--sidebar-width": SIDEBAR_WIDTH,
1031
- "--header-height": HEADER_HEIGHT,
1032
- "--sidebar-width-mobile": SIDEBAR_WIDTH_MOBILE,
1033
- "--header-height-mobile": HEADER_HEIGHT_MOBILE
1034
- };
1035
- const style = {
1036
- ...defaultStyle,
1037
- ...customStyle
1038
- };
1086
+ const cssVariables = useMemo2(
1087
+ () => ({
1088
+ "--sidebar-width": version === "v1" ? SIDEBAR_WIDTH : SIDEBAR_WIDTH_V2,
1089
+ "--header-height": version === "v1" ? HEADER_HEIGHT : HEADER_HEIGHT_V2,
1090
+ "--sidebar-width-mobile": version === "v1" ? SIDEBAR_WIDTH_MOBILE : SIDEBAR_WIDTH_MOBILE_V2,
1091
+ "--header-height-mobile": version === "v1" ? HEADER_HEIGHT_MOBILE : HEADER_HEIGHT_MOBILE_V2,
1092
+ ...customStyle || {}
1093
+ }),
1094
+ [version, customStyle]
1095
+ );
1096
+ const style = useMemo2(
1097
+ () => ({
1098
+ ...cssVariables
1099
+ }),
1100
+ [cssVariables]
1101
+ );
1039
1102
  const sidebarToggle = () => setIsSidebarOpen((open) => !open);
1040
1103
  useEffect3(() => {
1104
+ const html = document.documentElement;
1105
+ const body = document.body;
1106
+ const originalHtmlStyle = html.style.cssText;
1107
+ const originalBodyClasses = body.className;
1108
+ Object.entries(cssVariables).forEach(([prop, val]) => {
1109
+ html.style.setProperty(prop, val);
1110
+ });
1041
1111
  if (bodyClassName) {
1042
- const body = document.body;
1043
- const existingClasses = body.className;
1044
- body.className = `${existingClasses} ${bodyClassName}`.trim();
1045
- return () => {
1046
- body.className = existingClasses;
1047
- };
1112
+ body.className = `${originalBodyClasses} ${bodyClassName}`.trim();
1048
1113
  }
1049
- }, [bodyClassName]);
1114
+ body.setAttribute("data-sidebar-open", isSidebarOpen.toString());
1115
+ return () => {
1116
+ html.style.cssText = originalHtmlStyle;
1117
+ body.className = originalBodyClasses;
1118
+ body.removeAttribute("data-sidebar-open");
1119
+ };
1120
+ }, [cssVariables, bodyClassName, isSidebarOpen]);
1050
1121
  return /* @__PURE__ */ jsx14(
1051
1122
  LayoutContext.Provider,
1052
1123
  {
@@ -1056,16 +1127,17 @@ function LayoutProvider({
1056
1127
  isMobile,
1057
1128
  isSidebarOpen,
1058
1129
  sidebarToggle,
1059
- logoHeader
1130
+ logoHeader,
1131
+ version
1060
1132
  },
1061
1133
  children: /* @__PURE__ */ jsx14(
1062
1134
  "div",
1063
1135
  {
1064
1136
  "data-slot": "layout-wrapper",
1065
- className: cn6("flex grow", className),
1137
+ className: cn7("flex grow", className),
1066
1138
  "data-sidebar-open": isSidebarOpen,
1067
1139
  style,
1068
- children
1140
+ children: /* @__PURE__ */ jsx14(TooltipProvider, { delayDuration: 0, children })
1069
1141
  }
1070
1142
  )
1071
1143
  }
@@ -1075,10 +1147,26 @@ function LayoutProvider({
1075
1147
  // src/components/layouts/wrapper.tsx
1076
1148
  import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1077
1149
  function LayoutWrapper({
1150
+ children,
1151
+ logoHeader,
1152
+ version = "v1",
1153
+ ...props
1154
+ }) {
1155
+ const isVersionV1 = version === "v1";
1156
+ return /* @__PURE__ */ jsx15(
1157
+ LayoutProvider,
1158
+ {
1159
+ logoHeader,
1160
+ version,
1161
+ bodyClassName: isVersionV1 ? "" : "bg-muted!",
1162
+ children: isVersionV1 ? /* @__PURE__ */ jsx15(ContentWrapper, { ...props, children }) : /* @__PURE__ */ jsx15(ContentWrapperV2, { ...props, children })
1163
+ }
1164
+ );
1165
+ }
1166
+ function ContentWrapper({
1078
1167
  children,
1079
1168
  sidebarHeader,
1080
1169
  sidebarMenu,
1081
- logoHeader,
1082
1170
  homeUrl,
1083
1171
  studioUrl
1084
1172
  }) {
@@ -1091,7 +1179,7 @@ function LayoutWrapper({
1091
1179
  /* @__PURE__ */ jsx15(RocketIcon, {}),
1092
1180
  " Studio"
1093
1181
  ] }) });
1094
- return /* @__PURE__ */ jsxs12(LayoutProvider, { logoHeader, children: [
1182
+ return /* @__PURE__ */ jsxs12(Fragment6, { children: [
1095
1183
  /* @__PURE__ */ jsxs12(Header, { children: [
1096
1184
  /* @__PURE__ */ jsx15(HeaderLeft, {}),
1097
1185
  /* @__PURE__ */ jsx15(
@@ -1109,9 +1197,60 @@ function LayoutWrapper({
1109
1197
  ] })
1110
1198
  ] });
1111
1199
  }
1200
+ function ContentWrapperV2({
1201
+ children,
1202
+ sidebarHeader,
1203
+ sidebarMenu,
1204
+ sidebarFooter,
1205
+ homeUrl,
1206
+ studioUrl
1207
+ }) {
1208
+ const { isMobile } = useLayout3();
1209
+ const { user } = useSession5();
1210
+ const [enableTransitions, setEnableTransitions] = useState5(false);
1211
+ useEffect4(() => {
1212
+ const id = requestAnimationFrame(() => setEnableTransitions(true));
1213
+ return () => cancelAnimationFrame(id);
1214
+ }, []);
1215
+ const sidebarContent = /* @__PURE__ */ jsxs12(Fragment6, { children: [
1216
+ sidebarHeader,
1217
+ /* @__PURE__ */ jsx15(SidebarContent, { children: sidebarMenu }),
1218
+ !isMobile && sidebarFooter
1219
+ ] });
1220
+ const studioButton = /* @__PURE__ */ jsx15(Button5, { variant: "mono", size: "sm", className: "rounded-full", asChild: true, children: /* @__PURE__ */ jsxs12(Link8, { href: studioUrl || "#", target: "_blank", children: [
1221
+ /* @__PURE__ */ jsx15(RocketIcon, {}),
1222
+ " Studio"
1223
+ ] }) });
1224
+ return /* @__PURE__ */ jsxs12("div", { className: "flex h-screen w-full [&_.container-fluid]:px-5", children: [
1225
+ /* @__PURE__ */ jsx15(Sidebar, { children: sidebarContent }),
1226
+ /* @__PURE__ */ jsxs12("div", { className: "flex w-full min-w-0 flex-1 flex-col pt-(--header-height-mobile) lg:pt-0", children: [
1227
+ isMobile && /* @__PURE__ */ jsxs12(Header, { children: [
1228
+ /* @__PURE__ */ jsx15(HeaderLeft, {}),
1229
+ /* @__PURE__ */ jsx15(
1230
+ HeaderRight,
1231
+ {
1232
+ sidebar: /* @__PURE__ */ jsx15(HeaderSidebarMobile, { children: sidebarContent }),
1233
+ button: studioUrl && user?.role === "admin" ? studioButton : null,
1234
+ homeUrl
1235
+ }
1236
+ )
1237
+ ] }),
1238
+ /* @__PURE__ */ jsx15("div", { className: "mx-5 flex grow py-2.5 lg:mx-2.5", children: /* @__PURE__ */ jsx15(
1239
+ "div",
1240
+ {
1241
+ className: cn8(
1242
+ "grow overflow-y-auto rounded-xl border border-input bg-background shadow-xs duration-300 lg:in-data-[sidebar-open=true]:ms-[calc(var(--sidebar-width)+0.6rem)] lg:ms-[calc(var(--sidebar-width-collapsed)+0.6rem)]",
1243
+ enableTransitions ? "transition-all duration-300" : "transition-none"
1244
+ ),
1245
+ children: /* @__PURE__ */ jsx15("main", { className: "grow", children })
1246
+ }
1247
+ ) })
1248
+ ] })
1249
+ ] });
1250
+ }
1112
1251
 
1113
1252
  // src/components/providers/config.tsx
1114
- import { useMemo as useMemo2 } from "react";
1253
+ import { useMemo as useMemo3 } from "react";
1115
1254
  import { defaultConfig, mergeConfig } from "@pelatform/starter.config";
1116
1255
  import {
1117
1256
  ConfigContext,
@@ -1127,7 +1266,7 @@ function ConfigProvider({
1127
1266
  workspaceLogo: workspaceLogoProp,
1128
1267
  ...props
1129
1268
  }) {
1130
- const mergedConfig = useMemo2(() => {
1269
+ const mergedConfig = useMemo3(() => {
1131
1270
  return mergeConfig(defaultConfig, configProp);
1132
1271
  }, [configProp]);
1133
1272
  const config = mergedConfig;
@@ -1136,7 +1275,7 @@ function ConfigProvider({
1136
1275
  extension: "png",
1137
1276
  size: 128
1138
1277
  };
1139
- const userAvatar = useMemo2(() => {
1278
+ const userAvatar = useMemo3(() => {
1140
1279
  if (!userAvatarProp) {
1141
1280
  return {
1142
1281
  extension: DEFAULT_IMAGE_OPTIONS.extension,
@@ -1150,7 +1289,7 @@ function ConfigProvider({
1150
1289
  size: userAvatarProp.size || (userAvatarProp.upload ? 256 : DEFAULT_IMAGE_OPTIONS.size)
1151
1290
  };
1152
1291
  }, [userAvatarProp]);
1153
- const workspaceLogo = useMemo2(() => {
1292
+ const workspaceLogo = useMemo3(() => {
1154
1293
  if (!workspaceLogoProp) {
1155
1294
  return {
1156
1295
  extension: DEFAULT_IMAGE_OPTIONS.extension,
@@ -1213,7 +1352,7 @@ function SharedProviders({
1213
1352
  }
1214
1353
 
1215
1354
  // src/components/utils/card.tsx
1216
- import { cn as cn7 } from "pelatform-ui";
1355
+ import { cn as cn9 } from "pelatform-ui";
1217
1356
  import { Button as Button6, Card, CardContent, CardFooter, Skeleton as Skeleton4, Spinner } from "pelatform-ui/default";
1218
1357
  import { Fragment as Fragment7, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
1219
1358
  function CardComponent({
@@ -1234,7 +1373,7 @@ function CardComponent({
1234
1373
  return /* @__PURE__ */ jsxs14(
1235
1374
  Card,
1236
1375
  {
1237
- className: cn7(
1376
+ className: cn9(
1238
1377
  "w-full overflow-hidden",
1239
1378
  isDestructive && "border-destructive/70",
1240
1379
  className,
@@ -1242,7 +1381,7 @@ function CardComponent({
1242
1381
  ),
1243
1382
  ...props,
1244
1383
  children: [
1245
- /* @__PURE__ */ jsxs14(CardContent, { className: cn7("space-y-6 p-5 sm:p-10", classNames?.content), children: [
1384
+ /* @__PURE__ */ jsxs14(CardContent, { className: cn9("space-y-6 p-5 sm:p-10", classNames?.content), children: [
1246
1385
  /* @__PURE__ */ jsx18(
1247
1386
  CardHeaderComponent,
1248
1387
  {
@@ -1278,12 +1417,12 @@ function CardHeaderComponent({
1278
1417
  description,
1279
1418
  isPending
1280
1419
  }) {
1281
- return /* @__PURE__ */ jsx18("div", { className: cn7("flex flex-col space-y-2", className, classNames?.header), children: isPending ? /* @__PURE__ */ jsxs14(Fragment7, { children: [
1282
- /* @__PURE__ */ jsx18(Skeleton4, { className: cn7("h-7 w-1/3", classNames?.skeleton) }),
1283
- description && /* @__PURE__ */ jsx18(Skeleton4, { className: cn7("h-5 w-2/3", classNames?.skeleton) })
1420
+ return /* @__PURE__ */ jsx18("div", { className: cn9("flex flex-col space-y-2", className, classNames?.header), children: isPending ? /* @__PURE__ */ jsxs14(Fragment7, { children: [
1421
+ /* @__PURE__ */ jsx18(Skeleton4, { className: cn9("h-7 w-1/3", classNames?.skeleton) }),
1422
+ description && /* @__PURE__ */ jsx18(Skeleton4, { className: cn9("h-5 w-2/3", classNames?.skeleton) })
1284
1423
  ] }) : /* @__PURE__ */ jsxs14(Fragment7, { children: [
1285
- /* @__PURE__ */ jsx18("h2", { className: cn7("font-medium text-xl", classNames?.title), children: title }),
1286
- description && /* @__PURE__ */ jsx18("p", { className: cn7("text-muted-foreground text-sm", classNames?.description), children: description })
1424
+ /* @__PURE__ */ jsx18("h2", { className: cn9("font-medium text-xl", classNames?.title), children: title }),
1425
+ description && /* @__PURE__ */ jsx18("p", { className: cn9("text-muted-foreground text-sm", classNames?.description), children: description })
1287
1426
  ] }) });
1288
1427
  }
1289
1428
  function CardFooterComponent({
@@ -1300,7 +1439,7 @@ function CardFooterComponent({
1300
1439
  return /* @__PURE__ */ jsx18(
1301
1440
  CardFooter,
1302
1441
  {
1303
- className: cn7(
1442
+ className: cn9(
1304
1443
  "flex items-center justify-between space-x-4 bg-muted p-3 sm:px-10",
1305
1444
  isDestructive && "border-destructive/70",
1306
1445
  className,
@@ -1310,7 +1449,7 @@ function CardFooterComponent({
1310
1449
  instructions && /* @__PURE__ */ jsx18(
1311
1450
  Skeleton4,
1312
1451
  {
1313
- className: cn7(
1452
+ className: cn9(
1314
1453
  "h-4 w-48 max-w-full bg-muted-foreground/10 md:h-5 md:w-60",
1315
1454
  classNames?.skeleton
1316
1455
  )
@@ -1319,14 +1458,14 @@ function CardFooterComponent({
1319
1458
  actionLabel && /* @__PURE__ */ jsx18(
1320
1459
  Skeleton4,
1321
1460
  {
1322
- className: cn7("h-8 w-20 bg-muted-foreground/10 md:ms-auto", classNames?.skeleton)
1461
+ className: cn9("h-8 w-20 bg-muted-foreground/10 md:ms-auto", classNames?.skeleton)
1323
1462
  }
1324
1463
  )
1325
1464
  ] }) : /* @__PURE__ */ jsxs14(Fragment7, { children: [
1326
1465
  instructions && /* @__PURE__ */ jsx18(
1327
1466
  "div",
1328
1467
  {
1329
- className: cn7("text-muted-foreground text-xs md:text-sm", classNames?.instructions),
1468
+ className: cn9("text-muted-foreground text-xs md:text-sm", classNames?.instructions),
1330
1469
  children: instructions
1331
1470
  }
1332
1471
  ),
@@ -1360,7 +1499,7 @@ function CardActionComponent({
1360
1499
  type: onClick ? "button" : "submit",
1361
1500
  variant: isDestructive ? "destructive" : "primary",
1362
1501
  size: "sm",
1363
- className: cn7(
1502
+ className: cn9(
1364
1503
  "ms-auto",
1365
1504
  isSubmitting || disabled ? "pointer-events-auto! cursor-not-allowed" : "",
1366
1505
  classNames?.button,
@@ -1379,7 +1518,7 @@ function CardActionComponent({
1379
1518
 
1380
1519
  // src/components/utils/dialog.tsx
1381
1520
  import { useTranslations as useTranslations11 } from "next-intl";
1382
- import { cn as cn8 } from "pelatform-ui";
1521
+ import { cn as cn10 } from "pelatform-ui";
1383
1522
  import {
1384
1523
  Button as Button7,
1385
1524
  Dialog,
@@ -1407,13 +1546,13 @@ function DialogComponent({
1407
1546
  DialogContent,
1408
1547
  {
1409
1548
  onOpenAutoFocus: (e) => e.preventDefault(),
1410
- className: cn8("bg-muted sm:max-w-md", classNames?.dialog?.content),
1549
+ className: cn10("bg-muted sm:max-w-md", classNames?.dialog?.content),
1411
1550
  showCloseButton,
1412
1551
  children: [
1413
1552
  /* @__PURE__ */ jsxs15(
1414
1553
  DialogHeader,
1415
1554
  {
1416
- className: cn8(
1555
+ className: cn10(
1417
1556
  "-ms-6 -me-6 -mt-6 space-y-2 rounded-t-lg bg-background p-6",
1418
1557
  classNames?.header
1419
1558
  ),
@@ -1447,13 +1586,13 @@ function DialogFooterComponent({
1447
1586
  button
1448
1587
  }) {
1449
1588
  const t = useTranslations11();
1450
- return /* @__PURE__ */ jsxs15(DialogFooter, { className: cn8(className, classNames?.dialog?.footer), children: [
1589
+ return /* @__PURE__ */ jsxs15(DialogFooter, { className: cn10(className, classNames?.dialog?.footer), children: [
1451
1590
  cancelButton && /* @__PURE__ */ jsx19(
1452
1591
  Button7,
1453
1592
  {
1454
1593
  type: "button",
1455
1594
  variant: "ghost",
1456
- className: cn8(classNames?.button),
1595
+ className: cn10(classNames?.button),
1457
1596
  onClick: () => onOpenChange?.(false),
1458
1597
  disabled: cancelButtonDisabled,
1459
1598
  children: t("common.actions.cancel")
@@ -1464,22 +1603,22 @@ function DialogFooterComponent({
1464
1603
  }
1465
1604
 
1466
1605
  // src/components/utils/skeleton.tsx
1467
- import { cn as cn9 } from "pelatform-ui";
1606
+ import { cn as cn11 } from "pelatform-ui";
1468
1607
  import { Card as Card2, Skeleton as Skeleton5 } from "pelatform-ui/default";
1469
1608
  import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
1470
1609
  function SkeletonViewComponent({ classNames }) {
1471
- return /* @__PURE__ */ jsxs16(Card2, { className: cn9("flex-row items-center gap-3 px-4 py-3", classNames?.cell), children: [
1610
+ return /* @__PURE__ */ jsxs16(Card2, { className: cn11("flex-row items-center gap-3 px-4 py-3", classNames?.cell), children: [
1472
1611
  /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", children: [
1473
- /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("size-5 rounded-full", classNames?.skeleton) }),
1474
- /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("h-4 w-32", classNames?.skeleton) }) })
1612
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn11("size-5 rounded-full", classNames?.skeleton) }),
1613
+ /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(Skeleton5, { className: cn11("h-4 w-32", classNames?.skeleton) }) })
1475
1614
  ] }),
1476
- /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("ms-auto size-8 w-16", classNames?.skeleton) })
1615
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn11("ms-auto size-8 w-16", classNames?.skeleton) })
1477
1616
  ] });
1478
1617
  }
1479
1618
  function SkeletonInputComponent({ classNames }) {
1480
1619
  return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1.5", children: [
1481
- /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("h-4 w-32", classNames?.skeleton) }),
1482
- /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("h-9 w-full", classNames?.skeleton) })
1620
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn11("h-4 w-32", classNames?.skeleton) }),
1621
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn11("h-9 w-full", classNames?.skeleton) })
1483
1622
  ] });
1484
1623
  }
1485
1624
 
@@ -1487,14 +1626,14 @@ function SkeletonInputComponent({ classNames }) {
1487
1626
  import { useRef } from "react";
1488
1627
  import { CheckIcon, CopyIcon } from "lucide-react";
1489
1628
  import { useTranslations as useTranslations12 } from "next-intl";
1490
- import { cn as cn10 } from "pelatform-ui";
1629
+ import { cn as cn12 } from "pelatform-ui";
1491
1630
  import {
1492
1631
  Button as Button8,
1493
1632
  Input,
1494
1633
  Skeleton as Skeleton6,
1495
1634
  Tooltip,
1496
1635
  TooltipContent,
1497
- TooltipProvider,
1636
+ TooltipProvider as TooltipProvider2,
1498
1637
  TooltipTrigger
1499
1638
  } from "pelatform-ui/default";
1500
1639
  import { useCopyToClipboard } from "pelatform-ui/hooks";
@@ -1525,17 +1664,17 @@ function DisplayIdCard({
1525
1664
  description,
1526
1665
  isPending,
1527
1666
  ...props,
1528
- children: isPending ? /* @__PURE__ */ jsx21(Skeleton6, { className: cn10("h-11.5 w-full max-w-md", classNames?.skeleton) }) : /* @__PURE__ */ jsxs17(
1667
+ children: isPending ? /* @__PURE__ */ jsx21(Skeleton6, { className: cn12("h-11.5 w-full max-w-md", classNames?.skeleton) }) : /* @__PURE__ */ jsxs17(
1529
1668
  "div",
1530
1669
  {
1531
- className: cn10(
1670
+ className: cn12(
1532
1671
  "flex w-full max-w-md items-center justify-between rounded-md border p-2",
1533
1672
  classNames?.grid
1534
1673
  ),
1535
1674
  children: [
1536
1675
  /* @__PURE__ */ jsx21(Input, { value: id, ref: inputRef, disabled: true, className: "border-none! bg-transparent!" }),
1537
- /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs17(Tooltip, { children: [
1538
- /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(Button8, { variant: "dim", onClick: handleCopy, disabled: copied, children: copied ? /* @__PURE__ */ jsx21(CheckIcon, { className: cn10("stroke-green-600", classNames?.icon) }) : /* @__PURE__ */ jsx21(CopyIcon, { className: classNames?.icon }) }) }),
1676
+ /* @__PURE__ */ jsx21(TooltipProvider2, { delayDuration: 0, children: /* @__PURE__ */ jsxs17(Tooltip, { children: [
1677
+ /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(Button8, { variant: "dim", onClick: handleCopy, disabled: copied, children: copied ? /* @__PURE__ */ jsx21(CheckIcon, { className: cn12("stroke-green-600", classNames?.icon) }) : /* @__PURE__ */ jsx21(CopyIcon, { className: classNames?.icon }) }) }),
1539
1678
  /* @__PURE__ */ jsx21(TooltipContent, { className: "px-2 py-1 text-xs", children: t("common.actions.copy") })
1540
1679
  ] }) })
1541
1680
  ]
@@ -1548,7 +1687,7 @@ function DisplayIdCard({
1548
1687
  // src/components/empty-state.tsx
1549
1688
  import Link9 from "next/link";
1550
1689
  import { useTranslations as useTranslations13 } from "next-intl";
1551
- import { cn as cn11 } from "pelatform-ui";
1690
+ import { cn as cn13 } from "pelatform-ui";
1552
1691
  import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
1553
1692
  function EmptyState({
1554
1693
  className,
@@ -1560,7 +1699,7 @@ function EmptyState({
1560
1699
  children
1561
1700
  }) {
1562
1701
  const t = useTranslations13();
1563
- return /* @__PURE__ */ jsxs18("div", { className: cn11("flex flex-col items-center justify-center gap-y-4", className), children: [
1702
+ return /* @__PURE__ */ jsxs18("div", { className: cn13("flex flex-col items-center justify-center gap-y-4", className), children: [
1564
1703
  Icon && /* @__PURE__ */ jsx22("div", { className: "flex size-14 items-center justify-center rounded-2xl border bg-muted", children: /* @__PURE__ */ jsx22(Icon, { className: "size-6 text-foreground" }) }),
1565
1704
  /* @__PURE__ */ jsx22("p", { className: "text-center font-medium text-base text-foreground", children: title }),
1566
1705
  description && /* @__PURE__ */ jsxs18("p", { className: "max-w-sm text-balance text-center text-muted-foreground text-sm", children: [
@@ -1630,9 +1769,9 @@ function OTPInputGroup({ otpSeparators = 0 }) {
1630
1769
  }
1631
1770
 
1632
1771
  // src/components/password-input.tsx
1633
- import { useState as useState5 } from "react";
1772
+ import { useState as useState6 } from "react";
1634
1773
  import { EyeIcon, EyeOffIcon } from "lucide-react";
1635
- import { cn as cn12 } from "pelatform-ui";
1774
+ import { cn as cn14 } from "pelatform-ui";
1636
1775
  import { Button as Button9, Input as Input2 } from "pelatform-ui/default";
1637
1776
  import { Fragment as Fragment9, jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
1638
1777
  function PasswordInput({
@@ -1642,15 +1781,15 @@ function PasswordInput({
1642
1781
  onChange,
1643
1782
  ...props
1644
1783
  }) {
1645
- const [disabled, setDisabled] = useState5(true);
1646
- const [isVisible, setIsVisible] = useState5(false);
1784
+ const [disabled, setDisabled] = useState6(true);
1785
+ const [isVisible, setIsVisible] = useState6(false);
1647
1786
  return /* @__PURE__ */ jsxs20("div", { className: "relative", children: [
1648
1787
  /* @__PURE__ */ jsx24(
1649
1788
  Input2,
1650
1789
  {
1651
1790
  type: isVisible && enableToggle ? "text" : "password",
1652
1791
  variant,
1653
- className: cn12(enableToggle && "pe-10", className),
1792
+ className: cn14(enableToggle && "pe-10", className),
1654
1793
  ...props,
1655
1794
  onChange: (event) => {
1656
1795
  setDisabled(!event.target.value);
@@ -1826,6 +1965,7 @@ export {
1826
1965
  Sidebar,
1827
1966
  SidebarContent,
1828
1967
  SidebarContentMenu,
1968
+ SidebarFooter,
1829
1969
  SidebarHeaderBack,
1830
1970
  SignedInHint,
1831
1971
  SiteFooter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pelatform/starter.shared",
3
- "version": "0.2.14",
3
+ "version": "0.2.16",
4
4
  "description": "A part of SaaS starter kit for Pelatform applications.",
5
5
  "author": "Pelatform",
6
6
  "license": "MIT",
@@ -36,15 +36,15 @@
36
36
  },
37
37
  "devDependencies": {
38
38
  "@pelatform/starter.config": "0.2.2",
39
- "@pelatform/starter.hook": "0.2.4",
40
- "@pelatform/starter.utils": "0.2.8",
39
+ "@pelatform/starter.hook": "0.2.5",
40
+ "@pelatform/starter.utils": "0.2.10",
41
41
  "@pelatform/tsconfig": "^0.1.4",
42
- "@types/react": "^19.2.7",
43
- "lucide-react": "^0.562.0",
44
- "next": "^16.1.1",
42
+ "@types/react": "^19.2.9",
43
+ "lucide-react": "^0.563.0",
44
+ "next": "^16.1.5",
45
45
  "next-intl": "^4.7.0",
46
- "pelatform-ui": "^1.1.15",
47
- "react": "^19.2.3",
46
+ "pelatform-ui": "^1.1.19",
47
+ "react": "^19.2.4",
48
48
  "tsup": "^8.5.1"
49
49
  },
50
50
  "peerDependencies": {