@serhii.olishevskyi/docs 1.1.1 → 1.1.3

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  UserPopoverComponent,
3
3
  UserPopoverComponent_default
4
- } from "./chunk-BYGLCM3Z.mjs";
4
+ } from "./chunk-BAFKGCJJ.mjs";
5
5
  export {
6
6
  UserPopoverComponent,
7
7
  UserPopoverComponent_default as default
@@ -1871,7 +1871,7 @@ var Providers = {
1871
1871
  TranslationEdit: TranslationEditProvider,
1872
1872
  LocalizationProvider,
1873
1873
  PublicThemeProvider,
1874
- ThemeProvider,
1874
+ ProtectedThemeProvider: ThemeProvider,
1875
1875
  BreadcrumbProvider,
1876
1876
  ToastProvider,
1877
1877
  ConfirmationProvider,
package/dist/index.d.mts CHANGED
@@ -182,6 +182,14 @@ interface UserStatusChipComponentProps {
182
182
  };
183
183
  }
184
184
 
185
+ interface MyAvatarComponentProps {
186
+ size?: number;
187
+ disableBorder?: boolean;
188
+ disableShadow?: boolean;
189
+ disablePopover?: boolean;
190
+ sx?: SxProps<Theme>;
191
+ }
192
+
185
193
  declare const UI: {
186
194
  Inputs: {
187
195
  TextField: React$1.FC<TextFieldComponentProps>;
@@ -198,6 +206,11 @@ declare const UI: {
198
206
  UserPopover: React$1.FC<UserPopoverComponentProps>;
199
207
  UserRoleChip: React$1.FC<UserRoleChipComponentProps>;
200
208
  UserStatusChip: React$1.FC<UserStatusChipComponentProps>;
209
+ MyAvatar: React$1.FC<MyAvatarComponentProps>;
210
+ };
211
+ Widgets: {
212
+ ProtectedLanguageSelector: React$1.FC<{}>;
213
+ PublicLanguageSelector: React$1.FC<{}>;
201
214
  };
202
215
  };
203
216
 
@@ -462,7 +475,7 @@ declare const Providers: {
462
475
  readonly PublicThemeProvider: React$1.FC<{
463
476
  children: React.ReactNode;
464
477
  }>;
465
- readonly ThemeProvider: React$1.FC<{
478
+ readonly ProtectedThemeProvider: React$1.FC<{
466
479
  children: React.ReactNode;
467
480
  }>;
468
481
  readonly BreadcrumbProvider: React$1.FC<{
@@ -475,4 +488,4 @@ declare const Providers: {
475
488
  readonly AIProvider: React$1.FC<AIProviderProps>;
476
489
  };
477
490
 
478
- export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps as CopyClipboardButtonProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps as EmailInputProps, type Language, LocalizationProvider, type NumberInputComponentProps as NumberInputProps, Providers, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type TextFieldComponentProps as TextFieldProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps as TranslatableTooltipProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps as UserAvatarProps, type UserPopoverComponentProps as UserPopoverProps, type UserRoleChipComponentProps as UserRoleChipProps, UserSettingsProvider, type UserStatusChipComponentProps as UserStatusChipProps, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
491
+ export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps as CopyClipboardButtonProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps as EmailInputProps, type Language, LocalizationProvider, type MyAvatarComponentProps as MyAvatarProps, type NumberInputComponentProps as NumberInputProps, Providers, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type TextFieldComponentProps as TextFieldProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps as TranslatableTooltipProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps as UserAvatarProps, type UserPopoverComponentProps as UserPopoverProps, type UserRoleChipComponentProps as UserRoleChipProps, UserSettingsProvider, type UserStatusChipComponentProps as UserStatusChipProps, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
package/dist/index.d.ts CHANGED
@@ -182,6 +182,14 @@ interface UserStatusChipComponentProps {
182
182
  };
183
183
  }
184
184
 
185
+ interface MyAvatarComponentProps {
186
+ size?: number;
187
+ disableBorder?: boolean;
188
+ disableShadow?: boolean;
189
+ disablePopover?: boolean;
190
+ sx?: SxProps<Theme>;
191
+ }
192
+
185
193
  declare const UI: {
186
194
  Inputs: {
187
195
  TextField: React$1.FC<TextFieldComponentProps>;
@@ -198,6 +206,11 @@ declare const UI: {
198
206
  UserPopover: React$1.FC<UserPopoverComponentProps>;
199
207
  UserRoleChip: React$1.FC<UserRoleChipComponentProps>;
200
208
  UserStatusChip: React$1.FC<UserStatusChipComponentProps>;
209
+ MyAvatar: React$1.FC<MyAvatarComponentProps>;
210
+ };
211
+ Widgets: {
212
+ ProtectedLanguageSelector: React$1.FC<{}>;
213
+ PublicLanguageSelector: React$1.FC<{}>;
201
214
  };
202
215
  };
203
216
 
@@ -462,7 +475,7 @@ declare const Providers: {
462
475
  readonly PublicThemeProvider: React$1.FC<{
463
476
  children: React.ReactNode;
464
477
  }>;
465
- readonly ThemeProvider: React$1.FC<{
478
+ readonly ProtectedThemeProvider: React$1.FC<{
466
479
  children: React.ReactNode;
467
480
  }>;
468
481
  readonly BreadcrumbProvider: React$1.FC<{
@@ -475,4 +488,4 @@ declare const Providers: {
475
488
  readonly AIProvider: React$1.FC<AIProviderProps>;
476
489
  };
477
490
 
478
- export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps as CopyClipboardButtonProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps as EmailInputProps, type Language, LocalizationProvider, type NumberInputComponentProps as NumberInputProps, Providers, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type TextFieldComponentProps as TextFieldProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps as TranslatableTooltipProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps as UserAvatarProps, type UserPopoverComponentProps as UserPopoverProps, type UserRoleChipComponentProps as UserRoleChipProps, UserSettingsProvider, type UserStatusChipComponentProps as UserStatusChipProps, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
491
+ export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps as CopyClipboardButtonProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps as EmailInputProps, type Language, LocalizationProvider, type MyAvatarComponentProps as MyAvatarProps, type NumberInputComponentProps as NumberInputProps, Providers, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type TextFieldComponentProps as TextFieldProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps as TranslatableTooltipProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps as UserAvatarProps, type UserPopoverComponentProps as UserPopoverProps, type UserRoleChipComponentProps as UserRoleChipProps, UserSettingsProvider, type UserStatusChipComponentProps as UserStatusChipProps, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
package/dist/index.js CHANGED
@@ -2054,7 +2054,7 @@ var init_context = __esm({
2054
2054
  TranslationEdit: TranslationEditProvider,
2055
2055
  LocalizationProvider,
2056
2056
  PublicThemeProvider,
2057
- ThemeProvider,
2057
+ ProtectedThemeProvider: ThemeProvider,
2058
2058
  BreadcrumbProvider,
2059
2059
  ToastProvider,
2060
2060
  ConfirmationProvider,
@@ -3452,6 +3452,399 @@ init_CopyClipboardButtonComponent();
3452
3452
  init_UserRoleChipComponent();
3453
3453
  init_UserStatusChipComponent();
3454
3454
  init_UserPopoverComponent();
3455
+
3456
+ // src/UI/components/data.display/MyAvatarComponent.tsx
3457
+ var import_react23 = require("react");
3458
+ var import_material16 = require("@mui/material");
3459
+ init_context();
3460
+ var import_jsx_runtime26 = require("react/jsx-runtime");
3461
+ var getInitials2 = (name) => {
3462
+ if (!name) return "?";
3463
+ const parts = name.trim().split(" ");
3464
+ if (parts.length >= 2) {
3465
+ return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
3466
+ }
3467
+ return name[0].toUpperCase();
3468
+ };
3469
+ var MyAvatarComponent = ({
3470
+ size = 40,
3471
+ disableBorder = false,
3472
+ disableShadow = false,
3473
+ disablePopover = false,
3474
+ sx = {}
3475
+ }) => {
3476
+ const { profile: userProfile, loading: isLoading } = useAuth();
3477
+ const [anchorEl, setAnchorEl] = (0, import_react23.useState)(null);
3478
+ const handlePopoverOpen = (event) => {
3479
+ if (!disablePopover) {
3480
+ setAnchorEl(event.currentTarget);
3481
+ }
3482
+ };
3483
+ const handlePopoverClose = () => {
3484
+ setAnchorEl(null);
3485
+ };
3486
+ const isPopoverOpen = Boolean(anchorEl);
3487
+ if (isLoading) {
3488
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3489
+ import_material16.Skeleton,
3490
+ {
3491
+ variant: "circular",
3492
+ width: size,
3493
+ height: size,
3494
+ sx: { display: "inline-block", flexShrink: 0, ...sx }
3495
+ }
3496
+ );
3497
+ }
3498
+ const initials = getInitials2(userProfile?.display_name || "");
3499
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
3500
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3501
+ import_material16.Avatar,
3502
+ {
3503
+ src: userProfile?.avatar_url || void 0,
3504
+ alt: userProfile?.display_name || "User Avatar",
3505
+ onMouseEnter: handlePopoverOpen,
3506
+ onMouseLeave: handlePopoverClose,
3507
+ sx: {
3508
+ width: size,
3509
+ height: size,
3510
+ fontSize: size * 0.4,
3511
+ fontWeight: 600,
3512
+ bgcolor: "primary.main",
3513
+ color: "primary.contrastText",
3514
+ cursor: disablePopover ? void 0 : "pointer",
3515
+ transition: "transform 0.2s ease, box-shadow 0.2s ease",
3516
+ border: disableBorder ? "none" : "2px solid",
3517
+ borderColor: "background.paper",
3518
+ boxShadow: disableShadow ? "none" : 2,
3519
+ "&:hover": {
3520
+ transform: disablePopover ? "none" : "scale(1.05)"
3521
+ },
3522
+ ...sx
3523
+ },
3524
+ children: !userProfile?.avatar_url && initials
3525
+ }
3526
+ ),
3527
+ !disablePopover && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3528
+ import_material16.Popover,
3529
+ {
3530
+ id: `avatar-popover-${userProfile?.id}`,
3531
+ open: isPopoverOpen,
3532
+ anchorEl,
3533
+ anchorOrigin: {
3534
+ vertical: "bottom",
3535
+ horizontal: "center"
3536
+ },
3537
+ transformOrigin: {
3538
+ vertical: "top",
3539
+ horizontal: "center"
3540
+ },
3541
+ onClose: handlePopoverClose,
3542
+ disableRestoreFocus: true,
3543
+ disableAutoFocus: true,
3544
+ disableEnforceFocus: true,
3545
+ sx: {
3546
+ pointerEvents: "none",
3547
+ mt: 1
3548
+ },
3549
+ slotProps: {
3550
+ paper: {
3551
+ sx: {
3552
+ p: 1.5,
3553
+ borderRadius: 2,
3554
+ boxShadow: 3
3555
+ }
3556
+ }
3557
+ },
3558
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_material16.Box, { sx: { display: "flex", flexDirection: "column", alignItems: "center", gap: 0.5 }, children: [
3559
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material16.Typography, { variant: "subtitle2", sx: { fontWeight: 600 }, children: userProfile?.display_name }),
3560
+ userProfile?.email && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material16.Typography, { variant: "caption", color: "text.secondary", children: userProfile.email })
3561
+ ] })
3562
+ }
3563
+ )
3564
+ ] });
3565
+ };
3566
+
3567
+ // src/i18n/LanguageSelector.tsx
3568
+ var import_react24 = require("react");
3569
+ var import_react_i18next5 = require("react-i18next");
3570
+ var import_material17 = require("@mui/material");
3571
+ init_LocalizationProvider();
3572
+ init_UserSettingsProvider();
3573
+ init_SupabaseProvider();
3574
+ var import_jsx_runtime27 = require("react/jsx-runtime");
3575
+ var LanguageSelector = () => {
3576
+ const supabase = useSupabase();
3577
+ const { i18n: i18n2 } = (0, import_react_i18next5.useTranslation)();
3578
+ const [languages, setLanguages] = (0, import_react24.useState)([]);
3579
+ const [loading, setLoading] = (0, import_react24.useState)(true);
3580
+ const { changeLanguage } = useLocalization();
3581
+ const { settings: userSettings, setLanguage } = useUserSettings();
3582
+ const [anchorEl, setAnchorEl] = (0, import_react24.useState)(null);
3583
+ const open = Boolean(anchorEl);
3584
+ (0, import_react24.useEffect)(() => {
3585
+ const fetchLanguages = async () => {
3586
+ try {
3587
+ const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
3588
+ if (error) throw error;
3589
+ setLanguages(data || []);
3590
+ if (userSettings.language) changeLanguage(userSettings.language);
3591
+ } catch (err) {
3592
+ console.error("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u043C\u043E\u0432:", err);
3593
+ } finally {
3594
+ setLoading(false);
3595
+ }
3596
+ };
3597
+ fetchLanguages();
3598
+ }, []);
3599
+ const handleClick = (event) => {
3600
+ setAnchorEl(event.currentTarget);
3601
+ };
3602
+ const handleClose = () => {
3603
+ setAnchorEl(null);
3604
+ };
3605
+ const handleSelectLanguage = (langCode) => {
3606
+ changeLanguage(langCode);
3607
+ setLanguage(langCode);
3608
+ handleClose();
3609
+ };
3610
+ if (loading) {
3611
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
3612
+ }
3613
+ const rawCurrentLang = i18n2.language || "uk";
3614
+ const currentLangCode = rawCurrentLang.split("-")[0];
3615
+ const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
3616
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
3617
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.Tooltip, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3618
+ import_material17.IconButton,
3619
+ {
3620
+ onClick: handleClick,
3621
+ size: "small",
3622
+ "aria-controls": open ? "language-menu" : void 0,
3623
+ "aria-haspopup": "true",
3624
+ "aria-expanded": open ? "true" : void 0,
3625
+ sx: {
3626
+ p: 1,
3627
+ borderRadius: 2,
3628
+ transition: "background-color 0.2s",
3629
+ "&:hover": {
3630
+ backgroundColor: "action.hover"
3631
+ }
3632
+ },
3633
+ children: currentLang?.svg_flag && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3634
+ import_material17.Box,
3635
+ {
3636
+ sx: {
3637
+ width: 24,
3638
+ height: 16,
3639
+ borderRadius: "3px",
3640
+ overflow: "hidden",
3641
+ flexShrink: 0,
3642
+ boxShadow: "0 0 2px rgba(0,0,0,0.3)",
3643
+ display: "flex",
3644
+ alignItems: "center",
3645
+ justifyContent: "center",
3646
+ "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
3647
+ },
3648
+ dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
3649
+ }
3650
+ )
3651
+ }
3652
+ ) }),
3653
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3654
+ import_material17.Menu,
3655
+ {
3656
+ id: "language-menu",
3657
+ anchorEl,
3658
+ open,
3659
+ onClose: handleClose,
3660
+ slotProps: {
3661
+ paper: {
3662
+ elevation: 3,
3663
+ sx: {
3664
+ mt: 1,
3665
+ minWidth: 150,
3666
+ borderRadius: 2
3667
+ }
3668
+ }
3669
+ },
3670
+ transformOrigin: { horizontal: "right", vertical: "top" },
3671
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
3672
+ children: languages.map((lang) => {
3673
+ const isSelected = lang.code === currentLangCode;
3674
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3675
+ import_material17.MenuItem,
3676
+ {
3677
+ selected: isSelected,
3678
+ onClick: () => handleSelectLanguage(lang.code),
3679
+ sx: {
3680
+ display: "flex",
3681
+ alignItems: "center",
3682
+ gap: 1.5,
3683
+ py: 1,
3684
+ px: 2
3685
+ },
3686
+ children: [
3687
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3688
+ import_material17.Box,
3689
+ {
3690
+ sx: {
3691
+ width: 22,
3692
+ height: 15,
3693
+ borderRadius: "2px",
3694
+ overflow: "hidden",
3695
+ flexShrink: 0,
3696
+ boxShadow: "0 0 1px rgba(0,0,0,0.4)",
3697
+ "& svg": { width: "100%", height: "100%", display: "block" }
3698
+ },
3699
+ dangerouslySetInnerHTML: { __html: lang.svg_flag }
3700
+ }
3701
+ ),
3702
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.Typography, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
3703
+ ]
3704
+ },
3705
+ lang.code
3706
+ );
3707
+ })
3708
+ }
3709
+ )
3710
+ ] });
3711
+ };
3712
+ var PublicLanguageSelector = () => {
3713
+ const supabase = useSupabase();
3714
+ const { i18n: i18n2 } = (0, import_react_i18next5.useTranslation)();
3715
+ const { changeLanguage } = useLocalization();
3716
+ const [languages, setLanguages] = (0, import_react24.useState)([]);
3717
+ const [loading, setLoading] = (0, import_react24.useState)(true);
3718
+ const [anchorEl, setAnchorEl] = (0, import_react24.useState)(null);
3719
+ const open = Boolean(anchorEl);
3720
+ (0, import_react24.useEffect)(() => {
3721
+ const fetchLanguages = async () => {
3722
+ try {
3723
+ const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
3724
+ if (error) throw error;
3725
+ setLanguages(data || []);
3726
+ } catch (err) {
3727
+ console.error("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u043C\u043E\u0432:", err);
3728
+ } finally {
3729
+ setLoading(false);
3730
+ }
3731
+ };
3732
+ fetchLanguages();
3733
+ }, []);
3734
+ const handleClick = (event) => {
3735
+ setAnchorEl(event.currentTarget);
3736
+ };
3737
+ const handleClose = () => {
3738
+ setAnchorEl(null);
3739
+ };
3740
+ const handleSelectLanguage = (langCode) => {
3741
+ changeLanguage(langCode);
3742
+ handleClose();
3743
+ };
3744
+ if (loading) {
3745
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
3746
+ }
3747
+ const rawCurrentLang = i18n2.language || "uk";
3748
+ const currentLangCode = rawCurrentLang.split("-")[0];
3749
+ const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
3750
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
3751
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.Tooltip, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3752
+ import_material17.IconButton,
3753
+ {
3754
+ onClick: handleClick,
3755
+ size: "small",
3756
+ "aria-controls": open ? "language-menu" : void 0,
3757
+ "aria-haspopup": "true",
3758
+ "aria-expanded": open ? "true" : void 0,
3759
+ sx: {
3760
+ p: 1,
3761
+ borderRadius: 2,
3762
+ transition: "background-color 0.2s",
3763
+ "&:hover": {
3764
+ backgroundColor: "action.hover"
3765
+ }
3766
+ },
3767
+ children: currentLang?.svg_flag && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3768
+ import_material17.Box,
3769
+ {
3770
+ sx: {
3771
+ width: 24,
3772
+ height: 16,
3773
+ borderRadius: "3px",
3774
+ overflow: "hidden",
3775
+ flexShrink: 0,
3776
+ boxShadow: "0 0 2px rgba(0,0,0,0.3)",
3777
+ display: "flex",
3778
+ alignItems: "center",
3779
+ justifyContent: "center",
3780
+ "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
3781
+ },
3782
+ dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
3783
+ }
3784
+ )
3785
+ }
3786
+ ) }),
3787
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3788
+ import_material17.Menu,
3789
+ {
3790
+ id: "language-menu",
3791
+ anchorEl,
3792
+ open,
3793
+ onClose: handleClose,
3794
+ slotProps: {
3795
+ paper: {
3796
+ elevation: 3,
3797
+ sx: {
3798
+ mt: 1,
3799
+ minWidth: 150,
3800
+ borderRadius: 2
3801
+ }
3802
+ }
3803
+ },
3804
+ transformOrigin: { horizontal: "right", vertical: "top" },
3805
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
3806
+ children: languages.map((lang) => {
3807
+ const isSelected = lang.code === currentLangCode;
3808
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3809
+ import_material17.MenuItem,
3810
+ {
3811
+ selected: isSelected,
3812
+ onClick: () => handleSelectLanguage(lang.code),
3813
+ sx: {
3814
+ display: "flex",
3815
+ alignItems: "center",
3816
+ gap: 1.5,
3817
+ py: 1,
3818
+ px: 2
3819
+ },
3820
+ children: [
3821
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3822
+ import_material17.Box,
3823
+ {
3824
+ sx: {
3825
+ width: 22,
3826
+ height: 15,
3827
+ borderRadius: "2px",
3828
+ overflow: "hidden",
3829
+ flexShrink: 0,
3830
+ boxShadow: "0 0 1px rgba(0,0,0,0.4)",
3831
+ "& svg": { width: "100%", height: "100%", display: "block" }
3832
+ },
3833
+ dangerouslySetInnerHTML: { __html: lang.svg_flag }
3834
+ }
3835
+ ),
3836
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.Typography, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
3837
+ ]
3838
+ },
3839
+ lang.code
3840
+ );
3841
+ })
3842
+ }
3843
+ )
3844
+ ] });
3845
+ };
3846
+
3847
+ // src/UI/index.ts
3455
3848
  var UI = {
3456
3849
  Inputs: {
3457
3850
  TextField: TextFieldComponent,
@@ -3467,11 +3860,16 @@ var UI = {
3467
3860
  UserAvatar: UserAvatarComponent,
3468
3861
  UserPopover: UserPopoverComponent_default,
3469
3862
  UserRoleChip: UserRoleChipComponent,
3470
- UserStatusChip: UserStatusChipComponent
3471
- }
3863
+ UserStatusChip: UserStatusChipComponent,
3864
+ MyAvatar: MyAvatarComponent
3865
+ },
3472
3866
  /*Layout: {
3473
3867
  Row: FormRow,
3474
3868
  },*/
3869
+ Widgets: {
3870
+ ProtectedLanguageSelector: LanguageSelector,
3871
+ PublicLanguageSelector
3872
+ }
3475
3873
  };
3476
3874
 
3477
3875
  // src/index.ts
package/dist/index.mjs CHANGED
@@ -32,7 +32,7 @@ import {
32
32
  useTranslationEdit,
33
33
  useTranslationNamespace,
34
34
  useUserSettings
35
- } from "./chunk-BYGLCM3Z.mjs";
35
+ } from "./chunk-BAFKGCJJ.mjs";
36
36
 
37
37
  // src/UI/components/inputs/TextFieldComponent.tsx
38
38
  import { useState } from "react";
@@ -730,7 +730,7 @@ var EmailInputComponent = ({
730
730
  import { useState as useState5, useEffect as useEffect2, lazy, Suspense } from "react";
731
731
  import { Avatar, Tooltip as Tooltip3, Typography as Typography2 } from "@mui/material";
732
732
  import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
733
- var LazyUserPopover = lazy(() => import("./UserPopoverComponent-BVCKRNGL.mjs"));
733
+ var LazyUserPopover = lazy(() => import("./UserPopoverComponent-64KAMDBO.mjs"));
734
734
  var getInitials = (name) => {
735
735
  if (!name) return "?";
736
736
  const parts = name.trim().split(" ");
@@ -844,6 +844,401 @@ var UserAvatarComponent = ({
844
844
  ] });
845
845
  };
846
846
 
847
+ // src/UI/components/data.display/MyAvatarComponent.tsx
848
+ import { useState as useState6 } from "react";
849
+ import { Avatar as Avatar2, Box as Box4, Popover as Popover2, Typography as Typography3, Skeleton } from "@mui/material";
850
+ import { Fragment as Fragment5, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
851
+ var getInitials2 = (name) => {
852
+ if (!name) return "?";
853
+ const parts = name.trim().split(" ");
854
+ if (parts.length >= 2) {
855
+ return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
856
+ }
857
+ return name[0].toUpperCase();
858
+ };
859
+ var MyAvatarComponent = ({
860
+ size = 40,
861
+ disableBorder = false,
862
+ disableShadow = false,
863
+ disablePopover = false,
864
+ sx = {}
865
+ }) => {
866
+ const { profile: userProfile, loading: isLoading } = useAuth();
867
+ const [anchorEl, setAnchorEl] = useState6(null);
868
+ const handlePopoverOpen = (event) => {
869
+ if (!disablePopover) {
870
+ setAnchorEl(event.currentTarget);
871
+ }
872
+ };
873
+ const handlePopoverClose = () => {
874
+ setAnchorEl(null);
875
+ };
876
+ const isPopoverOpen = Boolean(anchorEl);
877
+ if (isLoading) {
878
+ return /* @__PURE__ */ jsx6(
879
+ Skeleton,
880
+ {
881
+ variant: "circular",
882
+ width: size,
883
+ height: size,
884
+ sx: { display: "inline-block", flexShrink: 0, ...sx }
885
+ }
886
+ );
887
+ }
888
+ const initials = getInitials2(userProfile?.display_name || "");
889
+ return /* @__PURE__ */ jsxs5(Fragment5, { children: [
890
+ /* @__PURE__ */ jsx6(
891
+ Avatar2,
892
+ {
893
+ src: userProfile?.avatar_url || void 0,
894
+ alt: userProfile?.display_name || "User Avatar",
895
+ onMouseEnter: handlePopoverOpen,
896
+ onMouseLeave: handlePopoverClose,
897
+ sx: {
898
+ width: size,
899
+ height: size,
900
+ fontSize: size * 0.4,
901
+ fontWeight: 600,
902
+ bgcolor: "primary.main",
903
+ color: "primary.contrastText",
904
+ cursor: disablePopover ? void 0 : "pointer",
905
+ transition: "transform 0.2s ease, box-shadow 0.2s ease",
906
+ border: disableBorder ? "none" : "2px solid",
907
+ borderColor: "background.paper",
908
+ boxShadow: disableShadow ? "none" : 2,
909
+ "&:hover": {
910
+ transform: disablePopover ? "none" : "scale(1.05)"
911
+ },
912
+ ...sx
913
+ },
914
+ children: !userProfile?.avatar_url && initials
915
+ }
916
+ ),
917
+ !disablePopover && /* @__PURE__ */ jsx6(
918
+ Popover2,
919
+ {
920
+ id: `avatar-popover-${userProfile?.id}`,
921
+ open: isPopoverOpen,
922
+ anchorEl,
923
+ anchorOrigin: {
924
+ vertical: "bottom",
925
+ horizontal: "center"
926
+ },
927
+ transformOrigin: {
928
+ vertical: "top",
929
+ horizontal: "center"
930
+ },
931
+ onClose: handlePopoverClose,
932
+ disableRestoreFocus: true,
933
+ disableAutoFocus: true,
934
+ disableEnforceFocus: true,
935
+ sx: {
936
+ pointerEvents: "none",
937
+ mt: 1
938
+ },
939
+ slotProps: {
940
+ paper: {
941
+ sx: {
942
+ p: 1.5,
943
+ borderRadius: 2,
944
+ boxShadow: 3
945
+ }
946
+ }
947
+ },
948
+ children: /* @__PURE__ */ jsxs5(Box4, { sx: { display: "flex", flexDirection: "column", alignItems: "center", gap: 0.5 }, children: [
949
+ /* @__PURE__ */ jsx6(Typography3, { variant: "subtitle2", sx: { fontWeight: 600 }, children: userProfile?.display_name }),
950
+ userProfile?.email && /* @__PURE__ */ jsx6(Typography3, { variant: "caption", color: "text.secondary", children: userProfile.email })
951
+ ] })
952
+ }
953
+ )
954
+ ] });
955
+ };
956
+
957
+ // src/i18n/LanguageSelector.tsx
958
+ import { useEffect as useEffect3, useState as useState7 } from "react";
959
+ import { useTranslation as useTranslation2 } from "react-i18next";
960
+ import {
961
+ Box as Box5,
962
+ Typography as Typography4,
963
+ CircularProgress,
964
+ IconButton as IconButton4,
965
+ Menu,
966
+ MenuItem,
967
+ Tooltip as Tooltip4
968
+ } from "@mui/material";
969
+ import { Fragment as Fragment6, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
970
+ var LanguageSelector = () => {
971
+ const supabase = useSupabase();
972
+ const { i18n } = useTranslation2();
973
+ const [languages, setLanguages] = useState7([]);
974
+ const [loading, setLoading] = useState7(true);
975
+ const { changeLanguage } = useLocalization();
976
+ const { settings: userSettings, setLanguage } = useUserSettings();
977
+ const [anchorEl, setAnchorEl] = useState7(null);
978
+ const open = Boolean(anchorEl);
979
+ useEffect3(() => {
980
+ const fetchLanguages = async () => {
981
+ try {
982
+ const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
983
+ if (error) throw error;
984
+ setLanguages(data || []);
985
+ if (userSettings.language) changeLanguage(userSettings.language);
986
+ } catch (err) {
987
+ console.error("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u043C\u043E\u0432:", err);
988
+ } finally {
989
+ setLoading(false);
990
+ }
991
+ };
992
+ fetchLanguages();
993
+ }, []);
994
+ const handleClick = (event) => {
995
+ setAnchorEl(event.currentTarget);
996
+ };
997
+ const handleClose = () => {
998
+ setAnchorEl(null);
999
+ };
1000
+ const handleSelectLanguage = (langCode) => {
1001
+ changeLanguage(langCode);
1002
+ setLanguage(langCode);
1003
+ handleClose();
1004
+ };
1005
+ if (loading) {
1006
+ return /* @__PURE__ */ jsx7(CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
1007
+ }
1008
+ const rawCurrentLang = i18n.language || "uk";
1009
+ const currentLangCode = rawCurrentLang.split("-")[0];
1010
+ const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
1011
+ return /* @__PURE__ */ jsxs6(Fragment6, { children: [
1012
+ /* @__PURE__ */ jsx7(Tooltip4, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ jsx7(
1013
+ IconButton4,
1014
+ {
1015
+ onClick: handleClick,
1016
+ size: "small",
1017
+ "aria-controls": open ? "language-menu" : void 0,
1018
+ "aria-haspopup": "true",
1019
+ "aria-expanded": open ? "true" : void 0,
1020
+ sx: {
1021
+ p: 1,
1022
+ borderRadius: 2,
1023
+ transition: "background-color 0.2s",
1024
+ "&:hover": {
1025
+ backgroundColor: "action.hover"
1026
+ }
1027
+ },
1028
+ children: currentLang?.svg_flag && /* @__PURE__ */ jsx7(
1029
+ Box5,
1030
+ {
1031
+ sx: {
1032
+ width: 24,
1033
+ height: 16,
1034
+ borderRadius: "3px",
1035
+ overflow: "hidden",
1036
+ flexShrink: 0,
1037
+ boxShadow: "0 0 2px rgba(0,0,0,0.3)",
1038
+ display: "flex",
1039
+ alignItems: "center",
1040
+ justifyContent: "center",
1041
+ "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
1042
+ },
1043
+ dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
1044
+ }
1045
+ )
1046
+ }
1047
+ ) }),
1048
+ /* @__PURE__ */ jsx7(
1049
+ Menu,
1050
+ {
1051
+ id: "language-menu",
1052
+ anchorEl,
1053
+ open,
1054
+ onClose: handleClose,
1055
+ slotProps: {
1056
+ paper: {
1057
+ elevation: 3,
1058
+ sx: {
1059
+ mt: 1,
1060
+ minWidth: 150,
1061
+ borderRadius: 2
1062
+ }
1063
+ }
1064
+ },
1065
+ transformOrigin: { horizontal: "right", vertical: "top" },
1066
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
1067
+ children: languages.map((lang) => {
1068
+ const isSelected = lang.code === currentLangCode;
1069
+ return /* @__PURE__ */ jsxs6(
1070
+ MenuItem,
1071
+ {
1072
+ selected: isSelected,
1073
+ onClick: () => handleSelectLanguage(lang.code),
1074
+ sx: {
1075
+ display: "flex",
1076
+ alignItems: "center",
1077
+ gap: 1.5,
1078
+ py: 1,
1079
+ px: 2
1080
+ },
1081
+ children: [
1082
+ /* @__PURE__ */ jsx7(
1083
+ Box5,
1084
+ {
1085
+ sx: {
1086
+ width: 22,
1087
+ height: 15,
1088
+ borderRadius: "2px",
1089
+ overflow: "hidden",
1090
+ flexShrink: 0,
1091
+ boxShadow: "0 0 1px rgba(0,0,0,0.4)",
1092
+ "& svg": { width: "100%", height: "100%", display: "block" }
1093
+ },
1094
+ dangerouslySetInnerHTML: { __html: lang.svg_flag }
1095
+ }
1096
+ ),
1097
+ /* @__PURE__ */ jsx7(Typography4, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
1098
+ ]
1099
+ },
1100
+ lang.code
1101
+ );
1102
+ })
1103
+ }
1104
+ )
1105
+ ] });
1106
+ };
1107
+ var PublicLanguageSelector = () => {
1108
+ const supabase = useSupabase();
1109
+ const { i18n } = useTranslation2();
1110
+ const { changeLanguage } = useLocalization();
1111
+ const [languages, setLanguages] = useState7([]);
1112
+ const [loading, setLoading] = useState7(true);
1113
+ const [anchorEl, setAnchorEl] = useState7(null);
1114
+ const open = Boolean(anchorEl);
1115
+ useEffect3(() => {
1116
+ const fetchLanguages = async () => {
1117
+ try {
1118
+ const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
1119
+ if (error) throw error;
1120
+ setLanguages(data || []);
1121
+ } catch (err) {
1122
+ console.error("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u043C\u043E\u0432:", err);
1123
+ } finally {
1124
+ setLoading(false);
1125
+ }
1126
+ };
1127
+ fetchLanguages();
1128
+ }, []);
1129
+ const handleClick = (event) => {
1130
+ setAnchorEl(event.currentTarget);
1131
+ };
1132
+ const handleClose = () => {
1133
+ setAnchorEl(null);
1134
+ };
1135
+ const handleSelectLanguage = (langCode) => {
1136
+ changeLanguage(langCode);
1137
+ handleClose();
1138
+ };
1139
+ if (loading) {
1140
+ return /* @__PURE__ */ jsx7(CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
1141
+ }
1142
+ const rawCurrentLang = i18n.language || "uk";
1143
+ const currentLangCode = rawCurrentLang.split("-")[0];
1144
+ const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
1145
+ return /* @__PURE__ */ jsxs6(Fragment6, { children: [
1146
+ /* @__PURE__ */ jsx7(Tooltip4, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ jsx7(
1147
+ IconButton4,
1148
+ {
1149
+ onClick: handleClick,
1150
+ size: "small",
1151
+ "aria-controls": open ? "language-menu" : void 0,
1152
+ "aria-haspopup": "true",
1153
+ "aria-expanded": open ? "true" : void 0,
1154
+ sx: {
1155
+ p: 1,
1156
+ borderRadius: 2,
1157
+ transition: "background-color 0.2s",
1158
+ "&:hover": {
1159
+ backgroundColor: "action.hover"
1160
+ }
1161
+ },
1162
+ children: currentLang?.svg_flag && /* @__PURE__ */ jsx7(
1163
+ Box5,
1164
+ {
1165
+ sx: {
1166
+ width: 24,
1167
+ height: 16,
1168
+ borderRadius: "3px",
1169
+ overflow: "hidden",
1170
+ flexShrink: 0,
1171
+ boxShadow: "0 0 2px rgba(0,0,0,0.3)",
1172
+ display: "flex",
1173
+ alignItems: "center",
1174
+ justifyContent: "center",
1175
+ "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
1176
+ },
1177
+ dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
1178
+ }
1179
+ )
1180
+ }
1181
+ ) }),
1182
+ /* @__PURE__ */ jsx7(
1183
+ Menu,
1184
+ {
1185
+ id: "language-menu",
1186
+ anchorEl,
1187
+ open,
1188
+ onClose: handleClose,
1189
+ slotProps: {
1190
+ paper: {
1191
+ elevation: 3,
1192
+ sx: {
1193
+ mt: 1,
1194
+ minWidth: 150,
1195
+ borderRadius: 2
1196
+ }
1197
+ }
1198
+ },
1199
+ transformOrigin: { horizontal: "right", vertical: "top" },
1200
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
1201
+ children: languages.map((lang) => {
1202
+ const isSelected = lang.code === currentLangCode;
1203
+ return /* @__PURE__ */ jsxs6(
1204
+ MenuItem,
1205
+ {
1206
+ selected: isSelected,
1207
+ onClick: () => handleSelectLanguage(lang.code),
1208
+ sx: {
1209
+ display: "flex",
1210
+ alignItems: "center",
1211
+ gap: 1.5,
1212
+ py: 1,
1213
+ px: 2
1214
+ },
1215
+ children: [
1216
+ /* @__PURE__ */ jsx7(
1217
+ Box5,
1218
+ {
1219
+ sx: {
1220
+ width: 22,
1221
+ height: 15,
1222
+ borderRadius: "2px",
1223
+ overflow: "hidden",
1224
+ flexShrink: 0,
1225
+ boxShadow: "0 0 1px rgba(0,0,0,0.4)",
1226
+ "& svg": { width: "100%", height: "100%", display: "block" }
1227
+ },
1228
+ dangerouslySetInnerHTML: { __html: lang.svg_flag }
1229
+ }
1230
+ ),
1231
+ /* @__PURE__ */ jsx7(Typography4, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
1232
+ ]
1233
+ },
1234
+ lang.code
1235
+ );
1236
+ })
1237
+ }
1238
+ )
1239
+ ] });
1240
+ };
1241
+
847
1242
  // src/UI/index.ts
848
1243
  var UI = {
849
1244
  Inputs: {
@@ -860,11 +1255,16 @@ var UI = {
860
1255
  UserAvatar: UserAvatarComponent,
861
1256
  UserPopover: UserPopoverComponent_default,
862
1257
  UserRoleChip: UserRoleChipComponent,
863
- UserStatusChip: UserStatusChipComponent
864
- }
1258
+ UserStatusChip: UserStatusChipComponent,
1259
+ MyAvatar: MyAvatarComponent
1260
+ },
865
1261
  /*Layout: {
866
1262
  Row: FormRow,
867
1263
  },*/
1264
+ Widgets: {
1265
+ ProtectedLanguageSelector: LanguageSelector,
1266
+ PublicLanguageSelector
1267
+ }
868
1268
  };
869
1269
  export {
870
1270
  AIProvider,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serhii.olishevskyi/docs",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "DOCS.UA react packages",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",