@sudobility/building_blocks 0.0.15 → 0.0.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.
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React, { type ReactNode, type ComponentType } from 'react';
|
|
2
|
+
import { Theme, FontSize } from './appearance-settings';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for a settings section in the navigation.
|
|
5
|
+
*/
|
|
6
|
+
export interface SettingsSectionConfig {
|
|
7
|
+
/** Unique identifier for the section */
|
|
8
|
+
id: string;
|
|
9
|
+
/** Icon component to display */
|
|
10
|
+
icon: ComponentType<{
|
|
11
|
+
className?: string;
|
|
12
|
+
}>;
|
|
13
|
+
/** Display label */
|
|
14
|
+
label: string;
|
|
15
|
+
/** Short description shown below label */
|
|
16
|
+
description: string;
|
|
17
|
+
/** The content to render when this section is selected */
|
|
18
|
+
content: ReactNode;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Translation keys used by GlobalSettingsPage.
|
|
22
|
+
*/
|
|
23
|
+
export interface GlobalSettingsPageTranslations {
|
|
24
|
+
title: string;
|
|
25
|
+
backButton: string;
|
|
26
|
+
appearanceLabel: string;
|
|
27
|
+
appearanceDescription: string;
|
|
28
|
+
}
|
|
29
|
+
export interface GlobalSettingsPageProps {
|
|
30
|
+
/** Current theme value */
|
|
31
|
+
theme: Theme | string;
|
|
32
|
+
/** Current font size value */
|
|
33
|
+
fontSize: FontSize | string;
|
|
34
|
+
/** Callback when theme changes */
|
|
35
|
+
onThemeChange: (theme: Theme) => void;
|
|
36
|
+
/** Callback when font size changes */
|
|
37
|
+
onFontSizeChange: (fontSize: FontSize) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Additional settings sections to display after Appearance.
|
|
40
|
+
* Each section needs an id, icon, label, description, and content.
|
|
41
|
+
*/
|
|
42
|
+
additionalSections?: SettingsSectionConfig[];
|
|
43
|
+
/**
|
|
44
|
+
* Optional translation function.
|
|
45
|
+
* Falls back to default English strings if not provided.
|
|
46
|
+
*/
|
|
47
|
+
t?: (key: string, fallback?: string) => string;
|
|
48
|
+
/**
|
|
49
|
+
* Translation function for AppearanceSettings.
|
|
50
|
+
* If provided, will be passed to AppearanceSettings component.
|
|
51
|
+
*/
|
|
52
|
+
appearanceT?: (key: string, fallback?: string) => string;
|
|
53
|
+
/** Optional className for the container */
|
|
54
|
+
className?: string;
|
|
55
|
+
/** Whether to show the info box in appearance settings */
|
|
56
|
+
showAppearanceInfoBox?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* GlobalSettingsPage - A reusable settings page with master-detail layout.
|
|
60
|
+
*
|
|
61
|
+
* Features:
|
|
62
|
+
* - Appearance settings built-in as the first section
|
|
63
|
+
* - Extensible via additionalSections prop
|
|
64
|
+
* - Responsive master-detail layout
|
|
65
|
+
* - Mobile-friendly with back navigation
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```tsx
|
|
69
|
+
* // Basic usage
|
|
70
|
+
* <GlobalSettingsPage
|
|
71
|
+
* theme={theme}
|
|
72
|
+
* fontSize={fontSize}
|
|
73
|
+
* onThemeChange={setTheme}
|
|
74
|
+
* onFontSizeChange={setFontSize}
|
|
75
|
+
* />
|
|
76
|
+
*
|
|
77
|
+
* // With additional sections
|
|
78
|
+
* <GlobalSettingsPage
|
|
79
|
+
* theme={theme}
|
|
80
|
+
* fontSize={fontSize}
|
|
81
|
+
* onThemeChange={setTheme}
|
|
82
|
+
* onFontSizeChange={setFontSize}
|
|
83
|
+
* additionalSections={[
|
|
84
|
+
* {
|
|
85
|
+
* id: 'notifications',
|
|
86
|
+
* icon: BellIcon,
|
|
87
|
+
* label: 'Notifications',
|
|
88
|
+
* description: 'Manage notification preferences',
|
|
89
|
+
* content: <NotificationSettings />,
|
|
90
|
+
* },
|
|
91
|
+
* ]}
|
|
92
|
+
* />
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export declare const GlobalSettingsPage: React.FC<GlobalSettingsPageProps>;
|
|
96
|
+
export default GlobalSettingsPage;
|
|
@@ -1 +1,2 @@
|
|
|
1
1
|
export { AppearanceSettings, Theme, FontSize, type AppearanceSettingsProps, type AppearanceSettingsTranslations, } from './appearance-settings';
|
|
2
|
+
export { GlobalSettingsPage, type GlobalSettingsPageProps, type GlobalSettingsPageTranslations, type SettingsSectionConfig, } from './global-settings-page';
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import React, { useState, useRef, useMemo, useCallback, useEffect } from "react"
|
|
|
3
3
|
import { TopbarProvider, Topbar, TopbarLeft, TopbarNavigation, TopbarLogo, Logo, TopbarCenter, TopbarRight, TopbarActions, TopbarMobileContent, BreadcrumbSection, Footer, FooterCompact, FooterCompactLeft, FooterVersion, FooterCopyright, FooterCompactRight, FooterGrid, FooterLinkSection, FooterLink, FooterBottom, FooterBrand, FooterSocialLinks, LayoutProvider, Label, Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@sudobility/components";
|
|
4
4
|
import { clsx } from "clsx";
|
|
5
5
|
import { twMerge } from "tailwind-merge";
|
|
6
|
-
import { ChevronDownIcon, CalendarDaysIcon } from "@heroicons/react/24/outline";
|
|
6
|
+
import { ChevronDownIcon, CalendarDaysIcon, PaintBrushIcon, ChevronLeftIcon } from "@heroicons/react/24/outline";
|
|
7
7
|
import { GRADIENT_CLASSES, textVariants } from "@sudobility/design";
|
|
8
8
|
import { cva } from "class-variance-authority";
|
|
9
9
|
function cn(...inputs) {
|
|
@@ -761,7 +761,7 @@ var FontSize = /* @__PURE__ */ ((FontSize2) => {
|
|
|
761
761
|
FontSize2["LARGE"] = "large";
|
|
762
762
|
return FontSize2;
|
|
763
763
|
})(FontSize || {});
|
|
764
|
-
const defaultTranslations = {
|
|
764
|
+
const defaultTranslations$1 = {
|
|
765
765
|
heading: "Appearance",
|
|
766
766
|
description: "Customize the look and feel of the application.",
|
|
767
767
|
themeLabel: "Theme",
|
|
@@ -789,7 +789,7 @@ const AppearanceSettings = ({
|
|
|
789
789
|
showInfoBox = true
|
|
790
790
|
}) => {
|
|
791
791
|
const getText = (key) => {
|
|
792
|
-
const fallback = defaultTranslations[key];
|
|
792
|
+
const fallback = defaultTranslations$1[key];
|
|
793
793
|
return t ? t(key, fallback) : fallback;
|
|
794
794
|
};
|
|
795
795
|
return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
@@ -880,6 +880,130 @@ const AppearanceSettings = ({
|
|
|
880
880
|
] })
|
|
881
881
|
] }) });
|
|
882
882
|
};
|
|
883
|
+
const defaultTranslations = {
|
|
884
|
+
title: "Settings",
|
|
885
|
+
backButton: "Back",
|
|
886
|
+
appearanceLabel: "Appearance",
|
|
887
|
+
appearanceDescription: "Theme and font size settings"
|
|
888
|
+
};
|
|
889
|
+
const GlobalSettingsPage = ({
|
|
890
|
+
theme,
|
|
891
|
+
fontSize,
|
|
892
|
+
onThemeChange,
|
|
893
|
+
onFontSizeChange,
|
|
894
|
+
additionalSections = [],
|
|
895
|
+
t,
|
|
896
|
+
appearanceT,
|
|
897
|
+
className,
|
|
898
|
+
showAppearanceInfoBox = true
|
|
899
|
+
}) => {
|
|
900
|
+
const [selectedSection, setSelectedSection] = useState("appearance");
|
|
901
|
+
const [mobileView, setMobileView] = useState(
|
|
902
|
+
"navigation"
|
|
903
|
+
);
|
|
904
|
+
const getText = useCallback(
|
|
905
|
+
(key) => {
|
|
906
|
+
const fallback = defaultTranslations[key];
|
|
907
|
+
return t ? t(key, fallback) : fallback;
|
|
908
|
+
},
|
|
909
|
+
[t]
|
|
910
|
+
);
|
|
911
|
+
const allSections = useMemo(
|
|
912
|
+
() => [
|
|
913
|
+
{
|
|
914
|
+
id: "appearance",
|
|
915
|
+
icon: PaintBrushIcon,
|
|
916
|
+
label: getText("appearanceLabel"),
|
|
917
|
+
description: getText("appearanceDescription"),
|
|
918
|
+
content: /* @__PURE__ */ jsx(
|
|
919
|
+
AppearanceSettings,
|
|
920
|
+
{
|
|
921
|
+
theme,
|
|
922
|
+
fontSize,
|
|
923
|
+
onThemeChange,
|
|
924
|
+
onFontSizeChange,
|
|
925
|
+
t: appearanceT,
|
|
926
|
+
showInfoBox: showAppearanceInfoBox
|
|
927
|
+
}
|
|
928
|
+
)
|
|
929
|
+
},
|
|
930
|
+
...additionalSections
|
|
931
|
+
],
|
|
932
|
+
[
|
|
933
|
+
additionalSections,
|
|
934
|
+
getText,
|
|
935
|
+
theme,
|
|
936
|
+
fontSize,
|
|
937
|
+
onThemeChange,
|
|
938
|
+
onFontSizeChange,
|
|
939
|
+
appearanceT,
|
|
940
|
+
showAppearanceInfoBox
|
|
941
|
+
]
|
|
942
|
+
);
|
|
943
|
+
const currentSection = allSections.find((s) => s.id === selectedSection) || allSections[0];
|
|
944
|
+
const handleSectionSelect = (sectionId) => {
|
|
945
|
+
setSelectedSection(sectionId);
|
|
946
|
+
setMobileView("content");
|
|
947
|
+
};
|
|
948
|
+
const handleBackToNavigation = () => {
|
|
949
|
+
setMobileView("navigation");
|
|
950
|
+
};
|
|
951
|
+
const navigationList = /* @__PURE__ */ jsx("div", { className: "space-y-0", children: allSections.map((section) => {
|
|
952
|
+
const Icon = section.icon;
|
|
953
|
+
const isSelected = selectedSection === section.id;
|
|
954
|
+
return /* @__PURE__ */ jsxs(
|
|
955
|
+
"div",
|
|
956
|
+
{
|
|
957
|
+
onClick: () => handleSectionSelect(section.id),
|
|
958
|
+
className: cn(
|
|
959
|
+
"flex items-start p-4 cursor-pointer transition-colors",
|
|
960
|
+
"border-b border-gray-200 dark:border-gray-700 last:border-b-0",
|
|
961
|
+
isSelected ? "bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400" : "hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300"
|
|
962
|
+
),
|
|
963
|
+
children: [
|
|
964
|
+
/* @__PURE__ */ jsx(Icon, { className: "h-5 w-5 mt-0.5 mr-3 flex-shrink-0" }),
|
|
965
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
966
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium", children: section.label }),
|
|
967
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500 dark:text-gray-400 mt-0.5", children: section.description })
|
|
968
|
+
] })
|
|
969
|
+
]
|
|
970
|
+
},
|
|
971
|
+
section.id
|
|
972
|
+
);
|
|
973
|
+
}) });
|
|
974
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex-1", className), children: [
|
|
975
|
+
/* @__PURE__ */ jsxs("div", { className: "hidden md:flex h-full", children: [
|
|
976
|
+
/* @__PURE__ */ jsxs("div", { className: "w-80 flex-shrink-0 border-r border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900", children: [
|
|
977
|
+
/* @__PURE__ */ jsx("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-gray-900 dark:text-white", children: getText("title") }) }),
|
|
978
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-y-auto", children: navigationList })
|
|
979
|
+
] }),
|
|
980
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto bg-gray-50 dark:bg-gray-800", children: /* @__PURE__ */ jsxs("div", { className: "p-6", children: [
|
|
981
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-900 dark:text-white mb-6", children: currentSection.label }),
|
|
982
|
+
currentSection.content
|
|
983
|
+
] }) })
|
|
984
|
+
] }),
|
|
985
|
+
/* @__PURE__ */ jsx("div", { className: "md:hidden", children: mobileView === "navigation" ? /* @__PURE__ */ jsxs("div", { className: "bg-white dark:bg-gray-900 min-h-full", children: [
|
|
986
|
+
/* @__PURE__ */ jsx("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-gray-900 dark:text-white", children: getText("title") }) }),
|
|
987
|
+
navigationList
|
|
988
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "bg-white dark:bg-gray-900 min-h-full", children: [
|
|
989
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700 flex items-center", children: [
|
|
990
|
+
/* @__PURE__ */ jsxs(
|
|
991
|
+
"button",
|
|
992
|
+
{
|
|
993
|
+
onClick: handleBackToNavigation,
|
|
994
|
+
className: "flex items-center text-blue-600 dark:text-blue-400 mr-4",
|
|
995
|
+
children: [
|
|
996
|
+
/* @__PURE__ */ jsx(ChevronLeftIcon, { className: "h-5 w-5 mr-1" }),
|
|
997
|
+
/* @__PURE__ */ jsx("span", { children: getText("backButton") })
|
|
998
|
+
]
|
|
999
|
+
}
|
|
1000
|
+
),
|
|
1001
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: currentSection.label })
|
|
1002
|
+
] }),
|
|
1003
|
+
/* @__PURE__ */ jsx("div", { className: "p-4", children: currentSection.content })
|
|
1004
|
+
] }) })
|
|
1005
|
+
] });
|
|
1006
|
+
};
|
|
883
1007
|
export {
|
|
884
1008
|
AppBreadcrumbs,
|
|
885
1009
|
AppFooter,
|
|
@@ -893,6 +1017,7 @@ export {
|
|
|
893
1017
|
ChainType,
|
|
894
1018
|
DEFAULT_LANGUAGES,
|
|
895
1019
|
FontSize,
|
|
1020
|
+
GlobalSettingsPage,
|
|
896
1021
|
LanguageSelector,
|
|
897
1022
|
RTL_LANGUAGES,
|
|
898
1023
|
Theme,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/utils/index.ts","../src/constants/languages.ts","../src/components/topbar/language-selector.tsx","../src/components/topbar/app-topbar.tsx","../src/components/topbar/app-topbar-with-firebase-auth.tsx","../src/components/topbar/app-topbar-with-wallet.tsx","../src/components/breadcrumbs/app-breadcrumbs.tsx","../src/components/footer/app-footer.tsx","../src/components/footer/app-footer-for-home-page.tsx","../src/components/layout/app-page-layout.tsx","../src/components/settings/appearance-settings.tsx"],"sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge class names with Tailwind CSS classes.\n * Combines clsx for conditional classes and tailwind-merge for deduplication.\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","export interface LanguageConfig {\n code: string;\n name: string;\n flag: string;\n}\n\n/**\n * Default set of 16 supported languages with their flags.\n * Apps can override this list by passing their own languages prop.\n */\nexport const DEFAULT_LANGUAGES: LanguageConfig[] = [\n { code: 'en', name: 'English', flag: '🇺🇸' },\n { code: 'ar', name: 'العربية', flag: '🇸🇦' },\n { code: 'de', name: 'Deutsch', flag: '🇩🇪' },\n { code: 'es', name: 'Español', flag: '🇪🇸' },\n { code: 'fr', name: 'Français', flag: '🇫🇷' },\n { code: 'it', name: 'Italiano', flag: '🇮🇹' },\n { code: 'ja', name: '日本語', flag: '🇯🇵' },\n { code: 'ko', name: '한국어', flag: '🇰🇷' },\n { code: 'pt', name: 'Português', flag: '🇵🇹' },\n { code: 'ru', name: 'Русский', flag: '🇷🇺' },\n { code: 'sv', name: 'Svenska', flag: '🇸🇪' },\n { code: 'th', name: 'ไทย', flag: '🇹🇭' },\n { code: 'uk', name: 'Українська', flag: '🇺🇦' },\n { code: 'vi', name: 'Tiếng Việt', flag: '🇻🇳' },\n { code: 'zh', name: '简体中文', flag: '🇨🇳' },\n { code: 'zh-hant', name: '繁體中文', flag: '🇹🇼' },\n];\n\n/**\n * Languages that use right-to-left text direction.\n */\nexport const RTL_LANGUAGES = ['ar'];\n\n/**\n * Check if a language code is RTL.\n */\nexport function isRTL(languageCode: string): boolean {\n return RTL_LANGUAGES.includes(languageCode);\n}\n","import React, {\n useState,\n useCallback,\n useMemo,\n useRef,\n useEffect,\n} from 'react';\nimport { ChevronDownIcon } from '@heroicons/react/24/outline';\nimport { cn } from '../../utils';\nimport {\n DEFAULT_LANGUAGES,\n type LanguageConfig,\n} from '../../constants/languages';\n\nexport interface LanguageSelectorProps {\n /** Available languages (defaults to 16 built-in languages) */\n languages?: LanguageConfig[];\n /** Current language code */\n currentLanguage?: string;\n /** Language change handler */\n onLanguageChange?: (languageCode: string) => void;\n /** Variant: 'compact' for topbar, 'full' for settings */\n variant?: 'compact' | 'full';\n /** Custom className */\n className?: string;\n /** Label text for full variant */\n label?: string;\n /** Helper text for full variant */\n helperText?: string;\n}\n\n/**\n * LanguageSelector component with dropdown for switching languages.\n * Uses default 16 languages if none provided.\n */\nexport const LanguageSelector: React.FC<LanguageSelectorProps> = ({\n languages = DEFAULT_LANGUAGES,\n currentLanguage = 'en',\n onLanguageChange,\n variant = 'compact',\n className,\n label = 'Language',\n helperText = 'Select your preferred language',\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Sort languages alphabetically by name\n const sortedLanguages = useMemo(\n () => [...languages].sort((a, b) => a.name.localeCompare(b.name)),\n [languages]\n );\n\n const currentLang = useMemo(\n () => languages.find(lang => lang.code === currentLanguage) || languages[0],\n [languages, currentLanguage]\n );\n\n const handleLanguageChange = useCallback(\n (langCode: string) => {\n if (langCode !== currentLanguage) {\n onLanguageChange?.(langCode);\n }\n setIsOpen(false);\n },\n [currentLanguage, onLanguageChange]\n );\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n return () =>\n document.removeEventListener('mousedown', handleClickOutside);\n }\n }, [isOpen]);\n\n // Close dropdown on escape\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }\n }, [isOpen]);\n\n if (variant === 'compact') {\n return (\n <div ref={dropdownRef} className={cn('relative', className)}>\n <button\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n 'flex items-center gap-2 px-3 py-2 h-10 rounded-lg',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors'\n )}\n aria-label='Select language'\n aria-expanded={isOpen}\n aria-haspopup='listbox'\n >\n <span className='text-lg leading-none'>{currentLang?.flag}</span>\n <span className='hidden sm:block text-sm font-medium text-gray-700 dark:text-gray-300'>\n {currentLang?.name}\n </span>\n <ChevronDownIcon\n className={cn(\n 'h-4 w-4 text-gray-500 dark:text-gray-400 transition-transform',\n isOpen && 'rotate-180'\n )}\n />\n </button>\n\n {isOpen && (\n <div\n className={cn(\n 'absolute right-0 mt-2 w-48 py-1 z-50',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-200 dark:border-gray-700',\n 'rounded-lg shadow-lg'\n )}\n role='listbox'\n aria-label='Languages'\n >\n {sortedLanguages.map(lang => (\n <button\n key={lang.code}\n onClick={() => handleLanguageChange(lang.code)}\n className={cn(\n 'w-full flex items-center gap-3 px-3 py-2 text-left',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors',\n lang.code === currentLanguage &&\n 'bg-gray-100 dark:bg-gray-700 font-medium'\n )}\n role='option'\n aria-selected={lang.code === currentLanguage}\n >\n <span className='text-lg leading-none'>{lang.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {lang.name}\n </span>\n </button>\n ))}\n </div>\n )}\n </div>\n );\n }\n\n // Full variant for settings pages\n return (\n <div ref={dropdownRef} className={cn('space-y-2', className)}>\n <label className='text-sm font-medium text-gray-700 dark:text-gray-300 flex items-center gap-2'>\n <span>{label}</span>\n </label>\n\n <div className='relative'>\n <button\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n 'flex items-center justify-between w-full px-3 py-2 text-left',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-300 dark:border-gray-600',\n 'rounded-md',\n 'hover:bg-gray-50 dark:hover:bg-gray-700',\n 'transition-colors'\n )}\n aria-expanded={isOpen}\n aria-haspopup='listbox'\n >\n <div className='flex items-center gap-2'>\n <span className='text-lg leading-none'>{currentLang?.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {currentLang?.name}\n </span>\n </div>\n <ChevronDownIcon\n className={cn(\n 'h-4 w-4 text-gray-500 dark:text-gray-400 transition-transform',\n isOpen && 'rotate-180'\n )}\n />\n </button>\n\n {isOpen && (\n <div\n className={cn(\n 'absolute left-0 right-0 mt-1 py-1 z-50',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-200 dark:border-gray-700',\n 'rounded-md shadow-lg'\n )}\n role='listbox'\n aria-label='Languages'\n >\n {sortedLanguages.map(lang => (\n <button\n key={lang.code}\n onClick={() => handleLanguageChange(lang.code)}\n className={cn(\n 'w-full flex items-center gap-3 px-3 py-2 text-left',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors',\n lang.code === currentLanguage &&\n 'bg-gray-100 dark:bg-gray-700 font-medium'\n )}\n role='option'\n aria-selected={lang.code === currentLanguage}\n >\n <span className='text-lg leading-none'>{lang.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {lang.name}\n </span>\n </button>\n ))}\n </div>\n )}\n </div>\n\n {helperText && (\n <p className='text-xs text-gray-500 dark:text-gray-400'>{helperText}</p>\n )}\n </div>\n );\n};\n\nexport default LanguageSelector;\n","import React, { useMemo, type ComponentType, type ReactNode } from 'react';\nimport {\n Topbar,\n TopbarProvider,\n TopbarLeft,\n TopbarCenter,\n TopbarRight,\n TopbarLogo,\n TopbarNavigation,\n TopbarActions,\n TopbarMobileContent,\n Logo,\n type TopbarNavItem,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport {\n LanguageSelector,\n type LanguageSelectorProps,\n} from './language-selector';\nimport type {\n MenuItemConfig,\n LogoConfig,\n LanguageConfig,\n LinkComponentProps,\n} from '../../types';\nimport { DEFAULT_LANGUAGES } from '../../constants/languages';\n\nexport interface AppTopBarProps {\n /** Logo configuration */\n logo: LogoConfig;\n\n /** Navigation menu items */\n menuItems: MenuItemConfig[];\n\n /** Available languages for selector (defaults to 16 built-in languages) */\n languages?: LanguageConfig[];\n\n /** Current language code */\n currentLanguage?: string;\n\n /** Language change handler */\n onLanguageChange?: (languageCode: string) => void;\n\n /** Hide language selector */\n hideLanguageSelector?: boolean;\n\n /** Language selector props override */\n languageSelectorProps?: Partial<LanguageSelectorProps>;\n\n /** Breakpoint to collapse navigation to hamburger menu */\n collapseBelow?: 'sm' | 'md' | 'lg' | 'xl';\n\n /** Render prop for account/auth section (right side of topbar) */\n renderAccountSection?: () => ReactNode;\n\n /** Render prop for center section (e.g., search bar) - shown on desktop */\n renderCenterSection?: () => ReactNode;\n\n /** Render prop for mobile-specific content (e.g., mobile search) - shown below main topbar on mobile */\n renderMobileContent?: () => ReactNode;\n\n /** Custom Link component for navigation (for react-router-dom, Next.js, etc.) */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Optional sticky positioning */\n sticky?: boolean;\n\n /** Optional variant */\n variant?: 'default' | 'app';\n\n /** Mobile menu label for accessibility */\n mobileMenuLabel?: string;\n\n /** Custom className for topbar */\n className?: string;\n\n /** z-index level */\n zIndex?: 'default' | 'highest' | 'high';\n\n /** Aria label for navigation */\n ariaLabel?: string;\n}\n\n/**\n * Default Link component that renders a plain anchor tag.\n * Apps should provide their own LinkComponent for router integration.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * AppTopBar - Base topbar component for Sudobility apps.\n *\n * Features:\n * - Logo with app name on the left\n * - Navigation menu items with icons\n * - Language selector\n * - Render prop for center section (e.g., search bar)\n * - Render prop for account/auth section\n * - Render prop for mobile-specific content\n * - Responsive with hamburger menu on mobile\n * - Dark mode support\n */\nexport const AppTopBar: React.FC<AppTopBarProps> = ({\n logo,\n menuItems,\n languages = DEFAULT_LANGUAGES,\n currentLanguage = 'en',\n onLanguageChange,\n hideLanguageSelector = false,\n languageSelectorProps,\n collapseBelow = 'lg',\n renderAccountSection,\n renderCenterSection,\n renderMobileContent,\n LinkComponent = DefaultLinkComponent,\n sticky = true,\n variant = 'default',\n mobileMenuLabel = 'Menu',\n className,\n zIndex = 'highest',\n ariaLabel = 'Main navigation',\n}) => {\n // Filter menu items that should be shown\n const visibleMenuItems = useMemo(\n () => menuItems.filter(item => item.show !== false),\n [menuItems]\n );\n\n // Convert MenuItemConfig to TopbarNavItem\n const navItems: TopbarNavItem[] = useMemo(\n () =>\n visibleMenuItems.map(item => ({\n id: item.id,\n label: item.label,\n icon: item.icon,\n href: item.href,\n })),\n [visibleMenuItems]\n );\n\n // Wrapper to adapt LinkComponent to TopbarNavigation expected interface\n const LinkWrapper: ComponentType<{\n href: string;\n className?: string;\n children: ReactNode;\n }> = useMemo(\n () =>\n ({ href, className, children }) => (\n <LinkComponent href={href} className={className}>\n {children}\n </LinkComponent>\n ),\n [LinkComponent]\n );\n\n const handleLogoClick = () => {\n logo.onClick?.();\n };\n\n return (\n <TopbarProvider variant={variant} sticky={sticky}>\n <Topbar\n variant={variant}\n sticky={sticky}\n zIndex={zIndex}\n aria-label={ariaLabel}\n className={cn(className)}\n >\n <TopbarLeft>\n <TopbarNavigation\n items={navItems}\n collapseBelow={collapseBelow}\n LinkComponent={LinkWrapper}\n mobileMenuLabel={mobileMenuLabel}\n >\n <TopbarLogo onClick={handleLogoClick} size='md'>\n <Logo\n size='md'\n logoSrc={logo.src}\n logoText={logo.appName}\n logoAlt={logo.alt || logo.appName}\n showText={true}\n />\n </TopbarLogo>\n </TopbarNavigation>\n </TopbarLeft>\n\n {renderCenterSection && (\n <TopbarCenter>{renderCenterSection()}</TopbarCenter>\n )}\n\n <TopbarRight>\n <TopbarActions gap='md'>\n {!hideLanguageSelector && (\n <LanguageSelector\n languages={languages}\n currentLanguage={currentLanguage}\n onLanguageChange={onLanguageChange}\n variant='compact'\n {...languageSelectorProps}\n />\n )}\n {renderAccountSection?.()}\n </TopbarActions>\n </TopbarRight>\n\n {renderMobileContent && (\n <TopbarMobileContent>{renderMobileContent()}</TopbarMobileContent>\n )}\n </Topbar>\n </TopbarProvider>\n );\n};\n\nexport default AppTopBar;\n","import React, { type ReactNode, type ComponentType } from 'react';\nimport { AppTopBar, type AppTopBarProps } from './app-topbar';\nimport { cn } from '../../utils';\nimport { GRADIENT_CLASSES } from '@sudobility/design';\n\n/**\n * Auth menu item for the authenticated user dropdown.\n * This matches the AuthMenuItem interface from @sudobility/auth-components.\n */\nexport interface AuthMenuItem {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Icon element (typically a small SVG) */\n icon?: ReactNode;\n /** Click handler */\n onClick?: () => void;\n /** Show divider after this item */\n dividerAfter?: boolean;\n}\n\n/**\n * Props for the AuthAction component from @sudobility/auth-components.\n */\nexport interface AuthActionProps {\n /** Avatar size in pixels */\n avatarSize?: number;\n /** Dropdown alignment */\n dropdownAlign?: 'left' | 'right';\n /** Login button click handler */\n onLoginClick?: () => void;\n /** Menu items for authenticated user dropdown */\n menuItems?: AuthMenuItem[];\n /** Custom login button text */\n loginButtonText?: string;\n /** Custom className for login button */\n loginButtonClassName?: string;\n}\n\nexport interface AppTopBarWithFirebaseAuthProps extends Omit<\n AppTopBarProps,\n 'renderAccountSection'\n> {\n /**\n * AuthAction component from @sudobility/auth-components.\n * This is passed as a prop to avoid hard dependency on auth-components.\n */\n AuthActionComponent: ComponentType<AuthActionProps>;\n\n /** Additional menu items for authenticated users */\n authenticatedMenuItems?: AuthMenuItem[];\n\n /** Login button click handler */\n onLoginClick?: () => void;\n\n /** Avatar size in pixels */\n avatarSize?: number;\n\n /** Dropdown alignment */\n dropdownAlign?: 'left' | 'right';\n\n /** Custom login button text */\n loginButtonText?: string;\n\n /** Custom login button className */\n loginButtonClassName?: string;\n}\n\n/**\n * AppTopBarWithFirebaseAuth - TopBar with Firebase authentication integration.\n *\n * This component wraps AppTopBar and provides the AuthAction component\n * from @sudobility/auth-components for the account section.\n *\n * Note: The AuthAction component must be passed as a prop to avoid\n * hard dependency on @sudobility/auth-components.\n *\n * @example\n * ```tsx\n * import { AuthAction } from '@sudobility/auth-components';\n *\n * <AppTopBarWithFirebaseAuth\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={[...]}\n * AuthActionComponent={AuthAction}\n * onLoginClick={() => navigate('/login')}\n * authenticatedMenuItems={[\n * { id: 'dashboard', label: 'Dashboard', onClick: () => navigate('/dashboard') },\n * ]}\n * />\n * ```\n */\nexport const AppTopBarWithFirebaseAuth: React.FC<\n AppTopBarWithFirebaseAuthProps\n> = ({\n AuthActionComponent,\n authenticatedMenuItems = [],\n onLoginClick,\n avatarSize = 32,\n dropdownAlign = 'right',\n loginButtonText,\n loginButtonClassName,\n ...topBarProps\n}) => {\n const renderAccountSection = () => (\n <AuthActionComponent\n avatarSize={avatarSize}\n dropdownAlign={dropdownAlign}\n onLoginClick={onLoginClick}\n menuItems={authenticatedMenuItems}\n loginButtonText={loginButtonText}\n loginButtonClassName={cn(\n GRADIENT_CLASSES.headerButton,\n loginButtonClassName\n )}\n />\n );\n\n return (\n <AppTopBar {...topBarProps} renderAccountSection={renderAccountSection} />\n );\n};\n\nexport default AppTopBarWithFirebaseAuth;\n","import React, { type ReactNode, type ComponentType } from 'react';\nimport { AppTopBar, type AppTopBarProps } from './app-topbar';\nimport { cn } from '../../utils';\nimport { GRADIENT_CLASSES } from '@sudobility/design';\n\n/**\n * Wallet menu item for the connected wallet dropdown.\n */\nexport interface WalletMenuItem {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Icon component */\n icon?: ComponentType<{ className?: string }>;\n /** Click handler */\n onClick: () => void;\n /** Whether this is a separator */\n separator?: boolean;\n}\n\n/**\n * Auth status enum matching @sudobility/types.\n */\nexport enum AuthStatus {\n DISCONNECTED = 'disconnected',\n CONNECTED = 'connected',\n VERIFIED = 'verified',\n}\n\n/**\n * Chain type enum matching @sudobility/types.\n */\nexport enum ChainType {\n EVM = 'evm',\n SOLANA = 'solana',\n}\n\n/**\n * Props for the WalletDropdownMenu component from @sudobility/web3-components.\n */\nexport interface WalletDropdownMenuProps {\n walletAddress: string;\n authStatus: AuthStatus | string;\n chainType: ChainType | string | 'unknown';\n menuItems: WalletMenuItem[];\n avatar?: string;\n displayName?: string;\n statusLabels?: {\n verified?: string;\n connected?: string;\n disconnected?: string;\n };\n}\n\nexport interface AppTopBarWithWalletProps extends Omit<\n AppTopBarProps,\n 'renderAccountSection'\n> {\n /**\n * WalletDropdownMenu component from @sudobility/web3-components.\n * This is passed as a prop to avoid hard dependency on web3-components.\n */\n WalletDropdownMenuComponent?: ComponentType<WalletDropdownMenuProps>;\n\n /** Whether wallet is connected */\n isConnected: boolean;\n\n /** Connected wallet address */\n walletAddress?: string;\n\n /** Authentication status */\n authStatus?: AuthStatus | string;\n\n /** Chain type (EVM, Solana, etc.) */\n chainType?: ChainType | string | 'unknown';\n\n /** Connect button click handler */\n onConnect: () => void;\n\n /** Disconnect handler */\n onDisconnect: () => Promise<void>;\n\n /** Custom menu items for wallet dropdown */\n walletMenuItems?: WalletMenuItem[];\n\n /** Connect button content (default: \"Connect Wallet\") */\n connectButtonContent?: ReactNode;\n\n /** Connect button className (supports gradient classes from @sudobility/design) */\n connectButtonClassName?: string;\n\n /** Use gradient styling for connect button */\n useGradientButton?: boolean;\n\n /** Optional user avatar */\n avatar?: string;\n\n /** Optional display name */\n displayName?: string;\n\n /** Custom status labels */\n statusLabels?: {\n verified?: string;\n connected?: string;\n disconnected?: string;\n };\n}\n\n/**\n * Default connect button when WalletDropdownMenuComponent is not provided\n * or when wallet is not connected.\n */\nconst DefaultConnectButton: React.FC<{\n onClick: () => void;\n content?: ReactNode;\n className?: string;\n useGradient?: boolean;\n}> = ({ onClick, content = 'Connect Wallet', className, useGradient }) => (\n <button\n onClick={onClick}\n className={cn(\n useGradient\n ? GRADIENT_CLASSES.headerButton\n : 'px-4 py-2 text-sm font-medium rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition-colors',\n className\n )}\n >\n {content}\n </button>\n);\n\n/**\n * Simple fallback wallet display when WalletDropdownMenuComponent is not provided.\n */\nconst FallbackWalletDisplay: React.FC<{\n walletAddress: string;\n onDisconnect: () => Promise<void>;\n}> = ({ walletAddress, onDisconnect }) => {\n const truncatedAddress = `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}`;\n\n return (\n <div className='flex items-center gap-2'>\n <span className='text-sm font-medium text-gray-700 dark:text-gray-300'>\n {truncatedAddress}\n </span>\n <button\n onClick={() => onDisconnect()}\n className='text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'\n >\n Disconnect\n </button>\n </div>\n );\n};\n\n/**\n * AppTopBarWithWallet - TopBar with wallet connection integration.\n *\n * This component wraps AppTopBar and provides wallet connection UI\n * for the account section. Uses WalletDropdownMenu from @sudobility/web3-components\n * when provided.\n *\n * @example\n * ```tsx\n * import { WalletDropdownMenu } from '@sudobility/web3-components';\n *\n * <AppTopBarWithWallet\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={[...]}\n * WalletDropdownMenuComponent={WalletDropdownMenu}\n * isConnected={isConnected}\n * walletAddress={walletAddress}\n * authStatus={authStatus}\n * chainType={chainType}\n * onConnect={() => navigate('/connect')}\n * onDisconnect={handleDisconnect}\n * walletMenuItems={[\n * { id: 'copy', label: 'Copy Address', icon: ClipboardIcon, onClick: handleCopy },\n * { id: 'disconnect', label: 'Disconnect', icon: LogoutIcon, onClick: handleDisconnect },\n * ]}\n * />\n * ```\n */\nexport const AppTopBarWithWallet: React.FC<AppTopBarWithWalletProps> = ({\n WalletDropdownMenuComponent,\n isConnected,\n walletAddress,\n authStatus = AuthStatus.DISCONNECTED,\n chainType = 'unknown',\n onConnect,\n onDisconnect,\n walletMenuItems = [],\n connectButtonContent,\n connectButtonClassName,\n useGradientButton = true,\n avatar,\n displayName,\n statusLabels,\n ...topBarProps\n}) => {\n const renderAccountSection = () => {\n // Not connected - show connect button\n if (!isConnected || !walletAddress) {\n return (\n <DefaultConnectButton\n onClick={onConnect}\n content={connectButtonContent}\n className={connectButtonClassName}\n useGradient={useGradientButton}\n />\n );\n }\n\n // Connected with WalletDropdownMenu component\n if (WalletDropdownMenuComponent) {\n return (\n <WalletDropdownMenuComponent\n walletAddress={walletAddress}\n authStatus={authStatus}\n chainType={chainType}\n menuItems={walletMenuItems}\n avatar={avatar}\n displayName={displayName}\n statusLabels={statusLabels}\n />\n );\n }\n\n // Connected without WalletDropdownMenu - fallback display\n return (\n <FallbackWalletDisplay\n walletAddress={walletAddress}\n onDisconnect={onDisconnect}\n />\n );\n };\n\n return (\n <AppTopBar {...topBarProps} renderAccountSection={renderAccountSection} />\n );\n};\n\nexport default AppTopBarWithWallet;\n","import React, { type ComponentType } from 'react';\nimport { BreadcrumbSection } from '@sudobility/components';\nimport { CalendarDaysIcon } from '@heroicons/react/24/outline';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils';\nimport type {\n BreadcrumbItem,\n ShareConfig,\n TalkToFounderConfig,\n LinkComponentProps,\n} from '../../types';\n\nconst breadcrumbContainerVariants = cva('border-b', {\n variants: {\n variant: {\n default: 'bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700',\n transparent: 'bg-transparent border-transparent',\n subtle:\n 'bg-gray-50 dark:bg-gray-900/50 border-gray-200 dark:border-gray-700',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n});\n\nexport interface AppBreadcrumbsProps extends VariantProps<\n typeof breadcrumbContainerVariants\n> {\n /** Breadcrumb items */\n items: BreadcrumbItem[];\n\n /** Share configuration (shows social share buttons on right) */\n shareConfig?: ShareConfig;\n\n /** Talk to founder button configuration */\n talkToFounder?: TalkToFounderConfig;\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Custom className for the container */\n className?: string;\n\n /** Custom className for the inner content */\n contentClassName?: string;\n}\n\n/**\n * Default Talk to Founder button.\n */\nconst TalkToFounderButton: React.FC<{\n config: TalkToFounderConfig;\n}> = ({ config }) => {\n const IconComponent = config.icon || CalendarDaysIcon;\n const buttonText = config.buttonText || 'Talk to Founder';\n\n return (\n <a\n href={config.meetingUrl}\n target='_blank'\n rel='noopener noreferrer'\n className={cn(\n 'inline-flex items-center gap-2 px-3 py-1.5',\n 'text-sm font-medium',\n 'text-blue-600 dark:text-blue-400',\n 'hover:text-blue-700 dark:hover:text-blue-300',\n 'bg-blue-50 dark:bg-blue-900/20',\n 'hover:bg-blue-100 dark:hover:bg-blue-900/30',\n 'rounded-full',\n 'border border-blue-200 dark:border-blue-800',\n 'transition-colors'\n )}\n >\n <IconComponent className='h-4 w-4' />\n <span>{buttonText}</span>\n </a>\n );\n};\n\n/**\n * AppBreadcrumbs - Breadcrumb navigation with social share and \"Talk to Founder\" button.\n *\n * Features:\n * - Breadcrumb trail with links\n * - Social share buttons on the right\n * - Optional \"Talk to Founder\" meeting button\n * - Always renders at max-w-7xl width\n * - Dark mode support\n *\n * @example\n * ```tsx\n * <AppBreadcrumbs\n * items={[\n * { label: 'Home', href: '/' },\n * { label: 'Products', href: '/products' },\n * { label: 'Widget', current: true },\n * ]}\n * shareConfig={{\n * title: 'Check out this widget',\n * description: 'Amazing widget for your needs',\n * hashtags: ['widget', 'product'],\n * }}\n * talkToFounder={{\n * meetingUrl: 'https://calendly.com/founder/30min',\n * buttonText: 'Book a call',\n * }}\n * />\n * ```\n */\nexport const AppBreadcrumbs: React.FC<AppBreadcrumbsProps> = ({\n items,\n shareConfig,\n talkToFounder,\n variant = 'default',\n className,\n contentClassName,\n}) => {\n // Don't render if no items or only home\n if (!items || items.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(breadcrumbContainerVariants({ variant }), className)}>\n <div className={cn('max-w-7xl mx-auto px-4 py-3', contentClassName)}>\n <div className='flex items-center justify-between gap-4'>\n {/* Breadcrumb trail */}\n <div className='flex-1 min-w-0'>\n <BreadcrumbSection items={items} shareConfig={shareConfig} />\n </div>\n\n {/* Right side: Talk to Founder + Share (if shareConfig, share is handled by BreadcrumbSection) */}\n {talkToFounder && (\n <div className='flex items-center gap-3 flex-shrink-0'>\n <TalkToFounderButton config={talkToFounder} />\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n\nexport default AppBreadcrumbs;\n","import React, { type ComponentType } from 'react';\nimport {\n Footer as FooterContainer,\n FooterCompact,\n FooterCompactLeft,\n FooterCompactRight,\n FooterVersion,\n FooterCopyright,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport type {\n StatusIndicatorConfig,\n LinkComponentProps,\n FooterLinkItem,\n} from '../../types';\n\n/**\n * Props for the SystemStatusIndicator component from @sudobility/devops-components.\n */\nexport interface SystemStatusIndicatorProps {\n statusPageUrl: string;\n apiEndpoint?: string;\n refreshInterval?: number;\n size?: 'sm' | 'md' | 'lg';\n version?: string;\n isNetworkOnline?: boolean;\n}\n\nexport interface AppFooterProps {\n /** App version string */\n version?: string;\n\n /** Copyright year or range (e.g., \"2025\" or \"2025-2026\") */\n copyrightYear?: string;\n\n /** Company name */\n companyName: string;\n\n /** Company URL (optional - creates a link if provided) */\n companyUrl?: string;\n\n /** Rights text (e.g., \"All rights reserved\") */\n rightsText?: string;\n\n /** Status indicator config (optional) */\n statusIndicator?: StatusIndicatorConfig;\n\n /**\n * SystemStatusIndicator component from @sudobility/devops-components.\n * Pass this to enable status indicator functionality.\n */\n StatusIndicatorComponent?: ComponentType<SystemStatusIndicatorProps>;\n\n /** Right-side links (e.g., Privacy, Terms) */\n links?: FooterLinkItem[];\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Sticky positioning (sticks to bottom of viewport) */\n sticky?: boolean;\n\n /** Network online status (for status indicator) */\n isNetworkOnline?: boolean;\n\n /** Custom className */\n className?: string;\n}\n\n/**\n * Default link component that renders a plain anchor.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * Helper to get copyright year or range.\n */\nfunction getCopyrightYear(startYear = 2025): string {\n const currentYear = new Date().getFullYear();\n if (currentYear === startYear) {\n return String(startYear);\n } else if (currentYear > startYear) {\n return `${startYear}-${currentYear}`;\n }\n return String(startYear);\n}\n\n/**\n * AppFooter - Compact footer for app pages.\n *\n * Features:\n * - Version display\n * - Copyright with company name\n * - System status indicator (optional)\n * - Right-side links (Privacy, Terms, etc.)\n * - Sticky positioning option\n * - Dark mode support\n *\n * @example\n * ```tsx\n * import { SystemStatusIndicator } from '@sudobility/devops-components';\n *\n * <AppFooter\n * version=\"1.0.0\"\n * companyName=\"Sudobility Inc.\"\n * companyUrl=\"/\"\n * rightsText=\"All rights reserved\"\n * statusIndicator={{\n * statusPageUrl: 'https://status.example.com',\n * apiEndpoint: 'https://status.example.com/api/v1/status',\n * }}\n * StatusIndicatorComponent={SystemStatusIndicator}\n * links={[\n * { label: 'Privacy', href: '/privacy' },\n * { label: 'Terms', href: '/terms' },\n * ]}\n * sticky\n * />\n * ```\n */\nexport const AppFooter: React.FC<AppFooterProps> = ({\n version,\n copyrightYear,\n companyName,\n companyUrl,\n rightsText = 'All rights reserved',\n statusIndicator,\n StatusIndicatorComponent,\n links = [],\n LinkComponent = DefaultLinkComponent,\n sticky = true,\n isNetworkOnline = true,\n className,\n}) => {\n const year = copyrightYear || getCopyrightYear();\n\n const companyLink = companyUrl ? (\n <LinkComponent\n href={companyUrl}\n className='text-blue-400 hover:text-blue-300 transition-colors'\n >\n {companyName}\n </LinkComponent>\n ) : undefined;\n\n return (\n <FooterContainer\n variant='compact'\n sticky={sticky}\n className={cn(className)}\n >\n <FooterCompact>\n <FooterCompactLeft>\n {version && <FooterVersion version={version} />}\n <FooterCopyright\n year={year}\n companyName={companyName}\n rightsText={rightsText}\n companyLink={companyLink}\n />\n {statusIndicator && StatusIndicatorComponent && (\n <StatusIndicatorComponent\n statusPageUrl={statusIndicator.statusPageUrl}\n apiEndpoint={statusIndicator.apiEndpoint}\n refreshInterval={statusIndicator.refreshInterval || 60000}\n size='sm'\n version={version}\n isNetworkOnline={isNetworkOnline}\n />\n )}\n </FooterCompactLeft>\n <FooterCompactRight>\n {links.map((link, index) => (\n <React.Fragment key={link.href || index}>\n {link.onClick ? (\n <button\n onClick={link.onClick}\n className='text-gray-400 hover:text-white transition-colors'\n >\n {link.label}\n </button>\n ) : (\n <LinkComponent\n href={link.href}\n className='text-gray-400 hover:text-white transition-colors'\n >\n {link.label}\n </LinkComponent>\n )}\n </React.Fragment>\n ))}\n </FooterCompactRight>\n </FooterCompact>\n </FooterContainer>\n );\n};\n\nexport default AppFooter;\n","import React, { type ComponentType } from 'react';\nimport {\n Logo,\n Footer as FooterContainer,\n FooterGrid,\n FooterBrand,\n FooterLinkSection,\n FooterLink,\n FooterBottom,\n FooterVersion,\n FooterCopyright,\n FooterSocialLinks,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport type {\n StatusIndicatorConfig,\n LinkComponentProps,\n FooterLinkSection as FooterLinkSectionConfig,\n SocialLinksConfig,\n} from '../../types';\nimport type { SystemStatusIndicatorProps } from './app-footer';\n\nexport interface AppFooterForHomePageProps {\n /** App logo configuration */\n logo: {\n /** Logo image src (optional - if not provided, uses Logo component) */\n src?: string;\n /** App name */\n appName: string;\n };\n\n /** Footer link sections (columns of links) */\n linkSections: FooterLinkSectionConfig[];\n\n /** Social media links */\n socialLinks?: SocialLinksConfig;\n\n /** System status indicator configuration */\n statusIndicator?: StatusIndicatorConfig;\n\n /**\n * SystemStatusIndicator component from @sudobility/devops-components.\n * Pass this to enable status indicator functionality.\n */\n StatusIndicatorComponent?: ComponentType<SystemStatusIndicatorProps>;\n\n /** App version string */\n version?: string;\n\n /** Copyright year or range */\n copyrightYear?: string;\n\n /** Company name for copyright */\n companyName: string;\n\n /** Company link URL (optional) */\n companyUrl?: string;\n\n /** Footer description text (below logo) */\n description?: string;\n\n /** Rights text (e.g., \"All rights reserved\") */\n rightsText?: string;\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Network online status (for status indicator) */\n isNetworkOnline?: boolean;\n\n /** Custom className */\n className?: string;\n\n /** Number of columns for link grid (default: auto based on section count) */\n gridColumns?: 2 | 3 | 4 | 5;\n}\n\n/**\n * Default link component that renders a plain anchor.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * Helper to get copyright year or range.\n */\nfunction getCopyrightYear(startYear = 2025): string {\n const currentYear = new Date().getFullYear();\n if (currentYear === startYear) {\n return String(startYear);\n } else if (currentYear > startYear) {\n return `${startYear}-${currentYear}`;\n }\n return String(startYear);\n}\n\n/**\n * Get grid columns class based on section count.\n */\nfunction getGridColumnsClass(sectionCount: number, explicit?: number): string {\n const cols = explicit || Math.min(sectionCount, 4);\n switch (cols) {\n case 2:\n return 'md:grid-cols-2';\n case 3:\n return 'md:grid-cols-3';\n case 4:\n return 'md:grid-cols-4';\n case 5:\n return 'md:grid-cols-5';\n default:\n return 'md:grid-cols-4';\n }\n}\n\n/**\n * AppFooterForHomePage - Full footer for home/landing pages.\n *\n * Features:\n * - Multiple link sections in a grid\n * - Logo and brand description\n * - Social media links\n * - System status indicator (optional)\n * - Version and copyright\n * - Dark mode support\n *\n * @example\n * ```tsx\n * import { SystemStatusIndicator } from '@sudobility/devops-components';\n *\n * <AppFooterForHomePage\n * logo={{ appName: 'My App' }}\n * linkSections={[\n * {\n * title: 'Product',\n * links: [\n * { label: 'Features', href: '/features' },\n * { label: 'Pricing', href: '/pricing' },\n * ],\n * },\n * {\n * title: 'Company',\n * links: [\n * { label: 'About', href: '/about' },\n * { label: 'Contact', href: '/contact' },\n * ],\n * },\n * ]}\n * socialLinks={{\n * twitterUrl: 'https://twitter.com/myapp',\n * discordUrl: 'https://discord.gg/myapp',\n * }}\n * statusIndicator={{\n * statusPageUrl: 'https://status.example.com',\n * }}\n * StatusIndicatorComponent={SystemStatusIndicator}\n * version=\"1.0.0\"\n * companyName=\"Sudobility Inc.\"\n * description=\"Building the future of web3 communication\"\n * />\n * ```\n */\nexport const AppFooterForHomePage: React.FC<AppFooterForHomePageProps> = ({\n logo,\n linkSections,\n socialLinks,\n statusIndicator,\n StatusIndicatorComponent,\n version,\n copyrightYear,\n companyName,\n companyUrl,\n description,\n rightsText = 'All rights reserved',\n LinkComponent = DefaultLinkComponent,\n isNetworkOnline = true,\n className,\n gridColumns,\n}) => {\n const year = copyrightYear || getCopyrightYear();\n const gridClass = getGridColumnsClass(linkSections.length, gridColumns);\n\n const companyLink = companyUrl ? (\n <LinkComponent\n href={companyUrl}\n className='text-blue-400 hover:text-blue-300 transition-colors'\n >\n {companyName}\n </LinkComponent>\n ) : undefined;\n\n return (\n <FooterContainer variant='full' className={cn(className)}>\n <FooterGrid className={gridClass}>\n {linkSections.map((section, sectionIndex) => (\n <FooterLinkSection\n key={section.title || sectionIndex}\n title={section.title}\n >\n {section.links.map((link, linkIndex) => (\n <FooterLink key={link.href || linkIndex}>\n {link.onClick ? (\n <button onClick={link.onClick} className='text-left'>\n {link.label}\n </button>\n ) : (\n <LinkComponent href={link.href}>{link.label}</LinkComponent>\n )}\n </FooterLink>\n ))}\n </FooterLinkSection>\n ))}\n </FooterGrid>\n\n <FooterBottom>\n <FooterBrand\n description={description}\n className='flex flex-col items-center'\n >\n <LinkComponent\n href='/'\n className='text-white hover:opacity-80 transition-opacity'\n >\n {logo.src ? (\n <img\n src={logo.src}\n alt={logo.appName}\n className='h-8 object-contain'\n />\n ) : (\n <Logo size='md' showText={true} logoText={logo.appName} />\n )}\n </LinkComponent>\n </FooterBrand>\n {version && <FooterVersion version={version} />}\n <FooterCopyright\n year={year}\n companyName={companyName}\n rightsText={rightsText}\n companyLink={companyLink}\n />\n {statusIndicator && StatusIndicatorComponent && (\n <StatusIndicatorComponent\n statusPageUrl={statusIndicator.statusPageUrl}\n apiEndpoint={statusIndicator.apiEndpoint}\n refreshInterval={statusIndicator.refreshInterval || 60000}\n size='sm'\n version={version}\n isNetworkOnline={isNetworkOnline}\n />\n )}\n </FooterBottom>\n\n {socialLinks && (\n <div className='flex justify-center mt-4'>\n <FooterSocialLinks\n twitterUrl={socialLinks.twitterUrl}\n discordUrl={socialLinks.discordUrl}\n linkedinUrl={socialLinks.linkedinUrl}\n githubUrl={socialLinks.githubUrl}\n redditUrl={socialLinks.redditUrl}\n farcasterUrl={socialLinks.farcasterUrl}\n telegramUrl={socialLinks.telegramUrl}\n />\n </div>\n )}\n </FooterContainer>\n );\n};\n\nexport default AppFooterForHomePage;\n","import React, { type ReactNode } from 'react';\nimport { LayoutProvider } from '@sudobility/components';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils';\nimport {\n AppBreadcrumbs,\n type AppBreadcrumbsProps,\n} from '../breadcrumbs/app-breadcrumbs';\nimport type { MaxWidth, ContentPadding, BackgroundVariant } from '../../types';\n\nconst layoutVariants = cva('min-h-screen flex flex-col', {\n variants: {\n background: {\n default: 'bg-gray-50 dark:bg-gray-900',\n white: 'bg-white dark:bg-gray-900',\n gradient:\n 'bg-gradient-to-br from-gray-50 to-blue-50 dark:from-gray-900 dark:to-gray-800',\n },\n },\n defaultVariants: {\n background: 'default',\n },\n});\n\nconst maxWidthClasses: Record<MaxWidth, string> = {\n sm: 'max-w-sm',\n md: 'max-w-md',\n lg: 'max-w-lg',\n xl: 'max-w-xl',\n '2xl': 'max-w-2xl',\n '4xl': 'max-w-4xl',\n '7xl': 'max-w-7xl',\n full: 'max-w-full',\n};\n\nconst paddingClasses: Record<ContentPadding, string> = {\n none: '',\n sm: 'px-4 sm:px-6 py-6',\n md: 'px-4 py-8',\n lg: 'px-4 py-12',\n};\n\nexport interface AppPageLayoutProps extends VariantProps<\n typeof layoutVariants\n> {\n /** Page content */\n children: ReactNode;\n\n /** TopBar slot - pass an AppTopBar variant or custom component */\n topBar: ReactNode;\n\n /** Breadcrumbs configuration (optional) */\n breadcrumbs?: AppBreadcrumbsProps;\n\n /** Footer slot - pass an AppFooter variant or custom component */\n footer?: ReactNode;\n\n /** Max width for content area (default: '7xl') */\n maxWidth?: MaxWidth;\n\n /** Content padding (default: 'md') */\n contentPadding?: ContentPadding;\n\n /** Background variant */\n background?: BackgroundVariant;\n\n /** Layout mode for LayoutProvider */\n layoutMode?: 'standard';\n\n /** Custom className for the layout container */\n className?: string;\n\n /** Custom className for the content area */\n contentClassName?: string;\n\n /** Custom className for the main element */\n mainClassName?: string;\n}\n\n/**\n * AppPageLayout - Layout wrapper combining TopBar, Breadcrumbs, Content, and Footer.\n *\n * Features:\n * - Flexible slots for TopBar and Footer\n * - Optional breadcrumbs with share and \"Talk to Founder\"\n * - Configurable content max-width and padding\n * - Background variants\n * - Dark mode support\n * - Sticky footer behavior\n *\n * @example\n * ```tsx\n * <AppPageLayout\n * topBar={\n * <AppTopBarWithFirebaseAuth\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={menuItems}\n * AuthActionComponent={AuthAction}\n * onLoginClick={() => navigate('/login')}\n * />\n * }\n * breadcrumbs={{\n * items: breadcrumbItems,\n * shareConfig: { title: 'Page', description: 'Description', hashtags: [] },\n * }}\n * footer={\n * <AppFooter\n * version=\"1.0.0\"\n * companyName=\"My Company\"\n * links={[{ label: 'Privacy', href: '/privacy' }]}\n * />\n * }\n * maxWidth=\"7xl\"\n * background=\"default\"\n * >\n * <h1>Page Content</h1>\n * </AppPageLayout>\n * ```\n */\nexport const AppPageLayout: React.FC<AppPageLayoutProps> = ({\n children,\n topBar,\n breadcrumbs,\n footer,\n maxWidth = '7xl',\n contentPadding = 'md',\n background = 'default',\n layoutMode = 'standard',\n className,\n contentClassName,\n mainClassName,\n}) => {\n return (\n <LayoutProvider mode={layoutMode}>\n <div className={cn(layoutVariants({ background }), className)}>\n {/* Header Section */}\n <header>{topBar}</header>\n\n {/* Breadcrumb Section */}\n {breadcrumbs && breadcrumbs.items && breadcrumbs.items.length > 0 && (\n <AppBreadcrumbs {...breadcrumbs} />\n )}\n\n {/* Main Content */}\n <main className={cn('flex-1 overflow-auto', mainClassName)}>\n <div\n className={cn(\n 'mx-auto',\n maxWidthClasses[maxWidth],\n paddingClasses[contentPadding],\n contentClassName\n )}\n >\n {children}\n </div>\n </main>\n\n {/* Footer */}\n {footer && <footer>{footer}</footer>}\n </div>\n </LayoutProvider>\n );\n};\n\nexport default AppPageLayout;\n","import React from 'react';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Label,\n} from '@sudobility/components';\nimport { textVariants } from '@sudobility/design';\n\n/**\n * Theme options for appearance settings.\n */\nexport enum Theme {\n LIGHT = 'light',\n DARK = 'dark',\n SYSTEM = 'system',\n}\n\n/**\n * Font size options for appearance settings.\n */\nexport enum FontSize {\n SMALL = 'small',\n MEDIUM = 'medium',\n LARGE = 'large',\n}\n\n/**\n * Translation keys used by AppearanceSettings.\n * Provide a translation function to customize labels.\n */\nexport interface AppearanceSettingsTranslations {\n heading: string;\n description: string;\n themeLabel: string;\n themeSelectPlaceholder: string;\n themeLight: string;\n themeDark: string;\n themeSystem: string;\n themeDescription: string;\n fontSizeLabel: string;\n fontSizeSelectPlaceholder: string;\n fontSizeSmall: string;\n fontSizeMedium: string;\n fontSizeLarge: string;\n fontSizeDescription: string;\n infoHeading: string;\n infoDescription: string;\n}\n\nconst defaultTranslations: AppearanceSettingsTranslations = {\n heading: 'Appearance',\n description: 'Customize the look and feel of the application.',\n themeLabel: 'Theme',\n themeSelectPlaceholder: 'Select theme',\n themeLight: 'Light',\n themeDark: 'Dark',\n themeSystem: 'System',\n themeDescription: 'Choose your preferred color theme.',\n fontSizeLabel: 'Font Size',\n fontSizeSelectPlaceholder: 'Select font size',\n fontSizeSmall: 'Small',\n fontSizeMedium: 'Medium',\n fontSizeLarge: 'Large',\n fontSizeDescription: 'Adjust the text size for better readability.',\n infoHeading: 'About Settings',\n infoDescription:\n 'Your appearance preferences are saved locally and will be applied automatically on your next visit.',\n};\n\nexport interface AppearanceSettingsProps {\n /** Current theme value */\n theme: Theme | string;\n\n /** Current font size value */\n fontSize: FontSize | string;\n\n /** Callback when theme changes */\n onThemeChange: (theme: Theme) => void;\n\n /** Callback when font size changes */\n onFontSizeChange: (fontSize: FontSize) => void;\n\n /**\n * Optional translation function.\n * If provided, will be called with a key from AppearanceSettingsTranslations.\n * Falls back to default English strings if not provided.\n */\n t?: (key: string, fallback?: string) => string;\n\n /** Optional className for the container */\n className?: string;\n\n /** Whether to show the information box at the bottom */\n showInfoBox?: boolean;\n}\n\n/**\n * AppearanceSettings - A reusable component for theme and font size settings.\n *\n * This component can be used across different apps to provide consistent\n * appearance customization options.\n *\n * @example\n * ```tsx\n * // Basic usage with useTheme hook\n * const { theme, fontSize, setTheme, setFontSize } = useTheme();\n *\n * <AppearanceSettings\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * />\n *\n * // With i18n translation\n * const { t } = useTranslation('settings');\n *\n * <AppearanceSettings\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * t={(key, fallback) => t(`appearance.${key}`, fallback)}\n * />\n * ```\n */\nexport const AppearanceSettings: React.FC<AppearanceSettingsProps> = ({\n theme,\n fontSize,\n onThemeChange,\n onFontSizeChange,\n t,\n className,\n showInfoBox = true,\n}) => {\n // Helper to get translated string with fallback\n const getText = (key: keyof AppearanceSettingsTranslations): string => {\n const fallback = defaultTranslations[key];\n return t ? t(key, fallback) : fallback;\n };\n\n return (\n <div className={className}>\n <div className='space-y-6'>\n <div>\n <h2 className={`${textVariants.heading.h4()} mb-2`}>\n {getText('heading')}\n </h2>\n <p\n className={`${textVariants.body.sm()} text-gray-600 dark:text-gray-400`}\n >\n {getText('description')}\n </p>\n </div>\n\n <div className='space-y-6'>\n {/* Theme Setting */}\n <div className='space-y-2'>\n <Label\n htmlFor='theme-select'\n className={textVariants.label.default()}\n >\n {getText('themeLabel')}\n </Label>\n <Select\n value={theme}\n onValueChange={(value: string) => onThemeChange(value as Theme)}\n >\n <SelectTrigger id='theme-select'>\n <SelectValue placeholder={getText('themeSelectPlaceholder')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={Theme.LIGHT}>\n {getText('themeLight')}\n </SelectItem>\n <SelectItem value={Theme.DARK}>\n {getText('themeDark')}\n </SelectItem>\n <SelectItem value={Theme.SYSTEM}>\n {getText('themeSystem')}\n </SelectItem>\n </SelectContent>\n </Select>\n <p\n className={`${textVariants.body.xs()} text-gray-500 dark:text-gray-400`}\n >\n {getText('themeDescription')}\n </p>\n </div>\n\n {/* Font Size Setting */}\n <div className='space-y-2'>\n <Label\n htmlFor='font-size-select'\n className={textVariants.label.default()}\n >\n {getText('fontSizeLabel')}\n </Label>\n <Select\n value={fontSize}\n onValueChange={(value: string) =>\n onFontSizeChange(value as FontSize)\n }\n >\n <SelectTrigger id='font-size-select'>\n <SelectValue\n placeholder={getText('fontSizeSelectPlaceholder')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={FontSize.SMALL}>\n {getText('fontSizeSmall')}\n </SelectItem>\n <SelectItem value={FontSize.MEDIUM}>\n {getText('fontSizeMedium')}\n </SelectItem>\n <SelectItem value={FontSize.LARGE}>\n {getText('fontSizeLarge')}\n </SelectItem>\n </SelectContent>\n </Select>\n <p\n className={`${textVariants.body.xs()} text-gray-500 dark:text-gray-400`}\n >\n {getText('fontSizeDescription')}\n </p>\n </div>\n </div>\n\n {/* Information Box */}\n {showInfoBox && (\n <div className='bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4 border border-blue-200 dark:border-blue-800'>\n <h4 className='text-sm font-medium text-blue-900 dark:text-blue-100 mb-2'>\n {getText('infoHeading')}\n </h4>\n <p className='text-sm text-blue-700 dark:text-blue-300'>\n {getText('infoDescription')}\n </p>\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default AppearanceSettings;\n"],"names":["DefaultLinkComponent","className","AuthStatus","ChainType","getCopyrightYear","FooterContainer","Theme","FontSize"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/utils/index.ts","../src/constants/languages.ts","../src/components/topbar/language-selector.tsx","../src/components/topbar/app-topbar.tsx","../src/components/topbar/app-topbar-with-firebase-auth.tsx","../src/components/topbar/app-topbar-with-wallet.tsx","../src/components/breadcrumbs/app-breadcrumbs.tsx","../src/components/footer/app-footer.tsx","../src/components/footer/app-footer-for-home-page.tsx","../src/components/layout/app-page-layout.tsx","../src/components/settings/appearance-settings.tsx","../src/components/settings/global-settings-page.tsx"],"sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge class names with Tailwind CSS classes.\n * Combines clsx for conditional classes and tailwind-merge for deduplication.\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","export interface LanguageConfig {\n code: string;\n name: string;\n flag: string;\n}\n\n/**\n * Default set of 16 supported languages with their flags.\n * Apps can override this list by passing their own languages prop.\n */\nexport const DEFAULT_LANGUAGES: LanguageConfig[] = [\n { code: 'en', name: 'English', flag: '🇺🇸' },\n { code: 'ar', name: 'العربية', flag: '🇸🇦' },\n { code: 'de', name: 'Deutsch', flag: '🇩🇪' },\n { code: 'es', name: 'Español', flag: '🇪🇸' },\n { code: 'fr', name: 'Français', flag: '🇫🇷' },\n { code: 'it', name: 'Italiano', flag: '🇮🇹' },\n { code: 'ja', name: '日本語', flag: '🇯🇵' },\n { code: 'ko', name: '한국어', flag: '🇰🇷' },\n { code: 'pt', name: 'Português', flag: '🇵🇹' },\n { code: 'ru', name: 'Русский', flag: '🇷🇺' },\n { code: 'sv', name: 'Svenska', flag: '🇸🇪' },\n { code: 'th', name: 'ไทย', flag: '🇹🇭' },\n { code: 'uk', name: 'Українська', flag: '🇺🇦' },\n { code: 'vi', name: 'Tiếng Việt', flag: '🇻🇳' },\n { code: 'zh', name: '简体中文', flag: '🇨🇳' },\n { code: 'zh-hant', name: '繁體中文', flag: '🇹🇼' },\n];\n\n/**\n * Languages that use right-to-left text direction.\n */\nexport const RTL_LANGUAGES = ['ar'];\n\n/**\n * Check if a language code is RTL.\n */\nexport function isRTL(languageCode: string): boolean {\n return RTL_LANGUAGES.includes(languageCode);\n}\n","import React, {\n useState,\n useCallback,\n useMemo,\n useRef,\n useEffect,\n} from 'react';\nimport { ChevronDownIcon } from '@heroicons/react/24/outline';\nimport { cn } from '../../utils';\nimport {\n DEFAULT_LANGUAGES,\n type LanguageConfig,\n} from '../../constants/languages';\n\nexport interface LanguageSelectorProps {\n /** Available languages (defaults to 16 built-in languages) */\n languages?: LanguageConfig[];\n /** Current language code */\n currentLanguage?: string;\n /** Language change handler */\n onLanguageChange?: (languageCode: string) => void;\n /** Variant: 'compact' for topbar, 'full' for settings */\n variant?: 'compact' | 'full';\n /** Custom className */\n className?: string;\n /** Label text for full variant */\n label?: string;\n /** Helper text for full variant */\n helperText?: string;\n}\n\n/**\n * LanguageSelector component with dropdown for switching languages.\n * Uses default 16 languages if none provided.\n */\nexport const LanguageSelector: React.FC<LanguageSelectorProps> = ({\n languages = DEFAULT_LANGUAGES,\n currentLanguage = 'en',\n onLanguageChange,\n variant = 'compact',\n className,\n label = 'Language',\n helperText = 'Select your preferred language',\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Sort languages alphabetically by name\n const sortedLanguages = useMemo(\n () => [...languages].sort((a, b) => a.name.localeCompare(b.name)),\n [languages]\n );\n\n const currentLang = useMemo(\n () => languages.find(lang => lang.code === currentLanguage) || languages[0],\n [languages, currentLanguage]\n );\n\n const handleLanguageChange = useCallback(\n (langCode: string) => {\n if (langCode !== currentLanguage) {\n onLanguageChange?.(langCode);\n }\n setIsOpen(false);\n },\n [currentLanguage, onLanguageChange]\n );\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n return () =>\n document.removeEventListener('mousedown', handleClickOutside);\n }\n }, [isOpen]);\n\n // Close dropdown on escape\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }\n }, [isOpen]);\n\n if (variant === 'compact') {\n return (\n <div ref={dropdownRef} className={cn('relative', className)}>\n <button\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n 'flex items-center gap-2 px-3 py-2 h-10 rounded-lg',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors'\n )}\n aria-label='Select language'\n aria-expanded={isOpen}\n aria-haspopup='listbox'\n >\n <span className='text-lg leading-none'>{currentLang?.flag}</span>\n <span className='hidden sm:block text-sm font-medium text-gray-700 dark:text-gray-300'>\n {currentLang?.name}\n </span>\n <ChevronDownIcon\n className={cn(\n 'h-4 w-4 text-gray-500 dark:text-gray-400 transition-transform',\n isOpen && 'rotate-180'\n )}\n />\n </button>\n\n {isOpen && (\n <div\n className={cn(\n 'absolute right-0 mt-2 w-48 py-1 z-50',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-200 dark:border-gray-700',\n 'rounded-lg shadow-lg'\n )}\n role='listbox'\n aria-label='Languages'\n >\n {sortedLanguages.map(lang => (\n <button\n key={lang.code}\n onClick={() => handleLanguageChange(lang.code)}\n className={cn(\n 'w-full flex items-center gap-3 px-3 py-2 text-left',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors',\n lang.code === currentLanguage &&\n 'bg-gray-100 dark:bg-gray-700 font-medium'\n )}\n role='option'\n aria-selected={lang.code === currentLanguage}\n >\n <span className='text-lg leading-none'>{lang.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {lang.name}\n </span>\n </button>\n ))}\n </div>\n )}\n </div>\n );\n }\n\n // Full variant for settings pages\n return (\n <div ref={dropdownRef} className={cn('space-y-2', className)}>\n <label className='text-sm font-medium text-gray-700 dark:text-gray-300 flex items-center gap-2'>\n <span>{label}</span>\n </label>\n\n <div className='relative'>\n <button\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n 'flex items-center justify-between w-full px-3 py-2 text-left',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-300 dark:border-gray-600',\n 'rounded-md',\n 'hover:bg-gray-50 dark:hover:bg-gray-700',\n 'transition-colors'\n )}\n aria-expanded={isOpen}\n aria-haspopup='listbox'\n >\n <div className='flex items-center gap-2'>\n <span className='text-lg leading-none'>{currentLang?.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {currentLang?.name}\n </span>\n </div>\n <ChevronDownIcon\n className={cn(\n 'h-4 w-4 text-gray-500 dark:text-gray-400 transition-transform',\n isOpen && 'rotate-180'\n )}\n />\n </button>\n\n {isOpen && (\n <div\n className={cn(\n 'absolute left-0 right-0 mt-1 py-1 z-50',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-200 dark:border-gray-700',\n 'rounded-md shadow-lg'\n )}\n role='listbox'\n aria-label='Languages'\n >\n {sortedLanguages.map(lang => (\n <button\n key={lang.code}\n onClick={() => handleLanguageChange(lang.code)}\n className={cn(\n 'w-full flex items-center gap-3 px-3 py-2 text-left',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors',\n lang.code === currentLanguage &&\n 'bg-gray-100 dark:bg-gray-700 font-medium'\n )}\n role='option'\n aria-selected={lang.code === currentLanguage}\n >\n <span className='text-lg leading-none'>{lang.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {lang.name}\n </span>\n </button>\n ))}\n </div>\n )}\n </div>\n\n {helperText && (\n <p className='text-xs text-gray-500 dark:text-gray-400'>{helperText}</p>\n )}\n </div>\n );\n};\n\nexport default LanguageSelector;\n","import React, { useMemo, type ComponentType, type ReactNode } from 'react';\nimport {\n Topbar,\n TopbarProvider,\n TopbarLeft,\n TopbarCenter,\n TopbarRight,\n TopbarLogo,\n TopbarNavigation,\n TopbarActions,\n TopbarMobileContent,\n Logo,\n type TopbarNavItem,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport {\n LanguageSelector,\n type LanguageSelectorProps,\n} from './language-selector';\nimport type {\n MenuItemConfig,\n LogoConfig,\n LanguageConfig,\n LinkComponentProps,\n} from '../../types';\nimport { DEFAULT_LANGUAGES } from '../../constants/languages';\n\nexport interface AppTopBarProps {\n /** Logo configuration */\n logo: LogoConfig;\n\n /** Navigation menu items */\n menuItems: MenuItemConfig[];\n\n /** Available languages for selector (defaults to 16 built-in languages) */\n languages?: LanguageConfig[];\n\n /** Current language code */\n currentLanguage?: string;\n\n /** Language change handler */\n onLanguageChange?: (languageCode: string) => void;\n\n /** Hide language selector */\n hideLanguageSelector?: boolean;\n\n /** Language selector props override */\n languageSelectorProps?: Partial<LanguageSelectorProps>;\n\n /** Breakpoint to collapse navigation to hamburger menu */\n collapseBelow?: 'sm' | 'md' | 'lg' | 'xl';\n\n /** Render prop for account/auth section (right side of topbar) */\n renderAccountSection?: () => ReactNode;\n\n /** Render prop for center section (e.g., search bar) - shown on desktop */\n renderCenterSection?: () => ReactNode;\n\n /** Render prop for mobile-specific content (e.g., mobile search) - shown below main topbar on mobile */\n renderMobileContent?: () => ReactNode;\n\n /** Custom Link component for navigation (for react-router-dom, Next.js, etc.) */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Optional sticky positioning */\n sticky?: boolean;\n\n /** Optional variant */\n variant?: 'default' | 'app';\n\n /** Mobile menu label for accessibility */\n mobileMenuLabel?: string;\n\n /** Custom className for topbar */\n className?: string;\n\n /** z-index level */\n zIndex?: 'default' | 'highest' | 'high';\n\n /** Aria label for navigation */\n ariaLabel?: string;\n}\n\n/**\n * Default Link component that renders a plain anchor tag.\n * Apps should provide their own LinkComponent for router integration.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * AppTopBar - Base topbar component for Sudobility apps.\n *\n * Features:\n * - Logo with app name on the left\n * - Navigation menu items with icons\n * - Language selector\n * - Render prop for center section (e.g., search bar)\n * - Render prop for account/auth section\n * - Render prop for mobile-specific content\n * - Responsive with hamburger menu on mobile\n * - Dark mode support\n */\nexport const AppTopBar: React.FC<AppTopBarProps> = ({\n logo,\n menuItems,\n languages = DEFAULT_LANGUAGES,\n currentLanguage = 'en',\n onLanguageChange,\n hideLanguageSelector = false,\n languageSelectorProps,\n collapseBelow = 'lg',\n renderAccountSection,\n renderCenterSection,\n renderMobileContent,\n LinkComponent = DefaultLinkComponent,\n sticky = true,\n variant = 'default',\n mobileMenuLabel = 'Menu',\n className,\n zIndex = 'highest',\n ariaLabel = 'Main navigation',\n}) => {\n // Filter menu items that should be shown\n const visibleMenuItems = useMemo(\n () => menuItems.filter(item => item.show !== false),\n [menuItems]\n );\n\n // Convert MenuItemConfig to TopbarNavItem\n const navItems: TopbarNavItem[] = useMemo(\n () =>\n visibleMenuItems.map(item => ({\n id: item.id,\n label: item.label,\n icon: item.icon,\n href: item.href,\n })),\n [visibleMenuItems]\n );\n\n // Wrapper to adapt LinkComponent to TopbarNavigation expected interface\n const LinkWrapper: ComponentType<{\n href: string;\n className?: string;\n children: ReactNode;\n }> = useMemo(\n () =>\n ({ href, className, children }) => (\n <LinkComponent href={href} className={className}>\n {children}\n </LinkComponent>\n ),\n [LinkComponent]\n );\n\n const handleLogoClick = () => {\n logo.onClick?.();\n };\n\n return (\n <TopbarProvider variant={variant} sticky={sticky}>\n <Topbar\n variant={variant}\n sticky={sticky}\n zIndex={zIndex}\n aria-label={ariaLabel}\n className={cn(className)}\n >\n <TopbarLeft>\n <TopbarNavigation\n items={navItems}\n collapseBelow={collapseBelow}\n LinkComponent={LinkWrapper}\n mobileMenuLabel={mobileMenuLabel}\n >\n <TopbarLogo onClick={handleLogoClick} size='md'>\n <Logo\n size='md'\n logoSrc={logo.src}\n logoText={logo.appName}\n logoAlt={logo.alt || logo.appName}\n showText={true}\n />\n </TopbarLogo>\n </TopbarNavigation>\n </TopbarLeft>\n\n {renderCenterSection && (\n <TopbarCenter>{renderCenterSection()}</TopbarCenter>\n )}\n\n <TopbarRight>\n <TopbarActions gap='md'>\n {!hideLanguageSelector && (\n <LanguageSelector\n languages={languages}\n currentLanguage={currentLanguage}\n onLanguageChange={onLanguageChange}\n variant='compact'\n {...languageSelectorProps}\n />\n )}\n {renderAccountSection?.()}\n </TopbarActions>\n </TopbarRight>\n\n {renderMobileContent && (\n <TopbarMobileContent>{renderMobileContent()}</TopbarMobileContent>\n )}\n </Topbar>\n </TopbarProvider>\n );\n};\n\nexport default AppTopBar;\n","import React, { type ReactNode, type ComponentType } from 'react';\nimport { AppTopBar, type AppTopBarProps } from './app-topbar';\nimport { cn } from '../../utils';\nimport { GRADIENT_CLASSES } from '@sudobility/design';\n\n/**\n * Auth menu item for the authenticated user dropdown.\n * This matches the AuthMenuItem interface from @sudobility/auth-components.\n */\nexport interface AuthMenuItem {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Icon element (typically a small SVG) */\n icon?: ReactNode;\n /** Click handler */\n onClick?: () => void;\n /** Show divider after this item */\n dividerAfter?: boolean;\n}\n\n/**\n * Props for the AuthAction component from @sudobility/auth-components.\n */\nexport interface AuthActionProps {\n /** Avatar size in pixels */\n avatarSize?: number;\n /** Dropdown alignment */\n dropdownAlign?: 'left' | 'right';\n /** Login button click handler */\n onLoginClick?: () => void;\n /** Menu items for authenticated user dropdown */\n menuItems?: AuthMenuItem[];\n /** Custom login button text */\n loginButtonText?: string;\n /** Custom className for login button */\n loginButtonClassName?: string;\n}\n\nexport interface AppTopBarWithFirebaseAuthProps extends Omit<\n AppTopBarProps,\n 'renderAccountSection'\n> {\n /**\n * AuthAction component from @sudobility/auth-components.\n * This is passed as a prop to avoid hard dependency on auth-components.\n */\n AuthActionComponent: ComponentType<AuthActionProps>;\n\n /** Additional menu items for authenticated users */\n authenticatedMenuItems?: AuthMenuItem[];\n\n /** Login button click handler */\n onLoginClick?: () => void;\n\n /** Avatar size in pixels */\n avatarSize?: number;\n\n /** Dropdown alignment */\n dropdownAlign?: 'left' | 'right';\n\n /** Custom login button text */\n loginButtonText?: string;\n\n /** Custom login button className */\n loginButtonClassName?: string;\n}\n\n/**\n * AppTopBarWithFirebaseAuth - TopBar with Firebase authentication integration.\n *\n * This component wraps AppTopBar and provides the AuthAction component\n * from @sudobility/auth-components for the account section.\n *\n * Note: The AuthAction component must be passed as a prop to avoid\n * hard dependency on @sudobility/auth-components.\n *\n * @example\n * ```tsx\n * import { AuthAction } from '@sudobility/auth-components';\n *\n * <AppTopBarWithFirebaseAuth\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={[...]}\n * AuthActionComponent={AuthAction}\n * onLoginClick={() => navigate('/login')}\n * authenticatedMenuItems={[\n * { id: 'dashboard', label: 'Dashboard', onClick: () => navigate('/dashboard') },\n * ]}\n * />\n * ```\n */\nexport const AppTopBarWithFirebaseAuth: React.FC<\n AppTopBarWithFirebaseAuthProps\n> = ({\n AuthActionComponent,\n authenticatedMenuItems = [],\n onLoginClick,\n avatarSize = 32,\n dropdownAlign = 'right',\n loginButtonText,\n loginButtonClassName,\n ...topBarProps\n}) => {\n const renderAccountSection = () => (\n <AuthActionComponent\n avatarSize={avatarSize}\n dropdownAlign={dropdownAlign}\n onLoginClick={onLoginClick}\n menuItems={authenticatedMenuItems}\n loginButtonText={loginButtonText}\n loginButtonClassName={cn(\n GRADIENT_CLASSES.headerButton,\n loginButtonClassName\n )}\n />\n );\n\n return (\n <AppTopBar {...topBarProps} renderAccountSection={renderAccountSection} />\n );\n};\n\nexport default AppTopBarWithFirebaseAuth;\n","import React, { type ReactNode, type ComponentType } from 'react';\nimport { AppTopBar, type AppTopBarProps } from './app-topbar';\nimport { cn } from '../../utils';\nimport { GRADIENT_CLASSES } from '@sudobility/design';\n\n/**\n * Wallet menu item for the connected wallet dropdown.\n */\nexport interface WalletMenuItem {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Icon component */\n icon?: ComponentType<{ className?: string }>;\n /** Click handler */\n onClick: () => void;\n /** Whether this is a separator */\n separator?: boolean;\n}\n\n/**\n * Auth status enum matching @sudobility/types.\n */\nexport enum AuthStatus {\n DISCONNECTED = 'disconnected',\n CONNECTED = 'connected',\n VERIFIED = 'verified',\n}\n\n/**\n * Chain type enum matching @sudobility/types.\n */\nexport enum ChainType {\n EVM = 'evm',\n SOLANA = 'solana',\n}\n\n/**\n * Props for the WalletDropdownMenu component from @sudobility/web3-components.\n */\nexport interface WalletDropdownMenuProps {\n walletAddress: string;\n authStatus: AuthStatus | string;\n chainType: ChainType | string | 'unknown';\n menuItems: WalletMenuItem[];\n avatar?: string;\n displayName?: string;\n statusLabels?: {\n verified?: string;\n connected?: string;\n disconnected?: string;\n };\n}\n\nexport interface AppTopBarWithWalletProps extends Omit<\n AppTopBarProps,\n 'renderAccountSection'\n> {\n /**\n * WalletDropdownMenu component from @sudobility/web3-components.\n * This is passed as a prop to avoid hard dependency on web3-components.\n */\n WalletDropdownMenuComponent?: ComponentType<WalletDropdownMenuProps>;\n\n /** Whether wallet is connected */\n isConnected: boolean;\n\n /** Connected wallet address */\n walletAddress?: string;\n\n /** Authentication status */\n authStatus?: AuthStatus | string;\n\n /** Chain type (EVM, Solana, etc.) */\n chainType?: ChainType | string | 'unknown';\n\n /** Connect button click handler */\n onConnect: () => void;\n\n /** Disconnect handler */\n onDisconnect: () => Promise<void>;\n\n /** Custom menu items for wallet dropdown */\n walletMenuItems?: WalletMenuItem[];\n\n /** Connect button content (default: \"Connect Wallet\") */\n connectButtonContent?: ReactNode;\n\n /** Connect button className (supports gradient classes from @sudobility/design) */\n connectButtonClassName?: string;\n\n /** Use gradient styling for connect button */\n useGradientButton?: boolean;\n\n /** Optional user avatar */\n avatar?: string;\n\n /** Optional display name */\n displayName?: string;\n\n /** Custom status labels */\n statusLabels?: {\n verified?: string;\n connected?: string;\n disconnected?: string;\n };\n}\n\n/**\n * Default connect button when WalletDropdownMenuComponent is not provided\n * or when wallet is not connected.\n */\nconst DefaultConnectButton: React.FC<{\n onClick: () => void;\n content?: ReactNode;\n className?: string;\n useGradient?: boolean;\n}> = ({ onClick, content = 'Connect Wallet', className, useGradient }) => (\n <button\n onClick={onClick}\n className={cn(\n useGradient\n ? GRADIENT_CLASSES.headerButton\n : 'px-4 py-2 text-sm font-medium rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition-colors',\n className\n )}\n >\n {content}\n </button>\n);\n\n/**\n * Simple fallback wallet display when WalletDropdownMenuComponent is not provided.\n */\nconst FallbackWalletDisplay: React.FC<{\n walletAddress: string;\n onDisconnect: () => Promise<void>;\n}> = ({ walletAddress, onDisconnect }) => {\n const truncatedAddress = `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}`;\n\n return (\n <div className='flex items-center gap-2'>\n <span className='text-sm font-medium text-gray-700 dark:text-gray-300'>\n {truncatedAddress}\n </span>\n <button\n onClick={() => onDisconnect()}\n className='text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'\n >\n Disconnect\n </button>\n </div>\n );\n};\n\n/**\n * AppTopBarWithWallet - TopBar with wallet connection integration.\n *\n * This component wraps AppTopBar and provides wallet connection UI\n * for the account section. Uses WalletDropdownMenu from @sudobility/web3-components\n * when provided.\n *\n * @example\n * ```tsx\n * import { WalletDropdownMenu } from '@sudobility/web3-components';\n *\n * <AppTopBarWithWallet\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={[...]}\n * WalletDropdownMenuComponent={WalletDropdownMenu}\n * isConnected={isConnected}\n * walletAddress={walletAddress}\n * authStatus={authStatus}\n * chainType={chainType}\n * onConnect={() => navigate('/connect')}\n * onDisconnect={handleDisconnect}\n * walletMenuItems={[\n * { id: 'copy', label: 'Copy Address', icon: ClipboardIcon, onClick: handleCopy },\n * { id: 'disconnect', label: 'Disconnect', icon: LogoutIcon, onClick: handleDisconnect },\n * ]}\n * />\n * ```\n */\nexport const AppTopBarWithWallet: React.FC<AppTopBarWithWalletProps> = ({\n WalletDropdownMenuComponent,\n isConnected,\n walletAddress,\n authStatus = AuthStatus.DISCONNECTED,\n chainType = 'unknown',\n onConnect,\n onDisconnect,\n walletMenuItems = [],\n connectButtonContent,\n connectButtonClassName,\n useGradientButton = true,\n avatar,\n displayName,\n statusLabels,\n ...topBarProps\n}) => {\n const renderAccountSection = () => {\n // Not connected - show connect button\n if (!isConnected || !walletAddress) {\n return (\n <DefaultConnectButton\n onClick={onConnect}\n content={connectButtonContent}\n className={connectButtonClassName}\n useGradient={useGradientButton}\n />\n );\n }\n\n // Connected with WalletDropdownMenu component\n if (WalletDropdownMenuComponent) {\n return (\n <WalletDropdownMenuComponent\n walletAddress={walletAddress}\n authStatus={authStatus}\n chainType={chainType}\n menuItems={walletMenuItems}\n avatar={avatar}\n displayName={displayName}\n statusLabels={statusLabels}\n />\n );\n }\n\n // Connected without WalletDropdownMenu - fallback display\n return (\n <FallbackWalletDisplay\n walletAddress={walletAddress}\n onDisconnect={onDisconnect}\n />\n );\n };\n\n return (\n <AppTopBar {...topBarProps} renderAccountSection={renderAccountSection} />\n );\n};\n\nexport default AppTopBarWithWallet;\n","import React, { type ComponentType } from 'react';\nimport { BreadcrumbSection } from '@sudobility/components';\nimport { CalendarDaysIcon } from '@heroicons/react/24/outline';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils';\nimport type {\n BreadcrumbItem,\n ShareConfig,\n TalkToFounderConfig,\n LinkComponentProps,\n} from '../../types';\n\nconst breadcrumbContainerVariants = cva('border-b', {\n variants: {\n variant: {\n default: 'bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700',\n transparent: 'bg-transparent border-transparent',\n subtle:\n 'bg-gray-50 dark:bg-gray-900/50 border-gray-200 dark:border-gray-700',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n});\n\nexport interface AppBreadcrumbsProps extends VariantProps<\n typeof breadcrumbContainerVariants\n> {\n /** Breadcrumb items */\n items: BreadcrumbItem[];\n\n /** Share configuration (shows social share buttons on right) */\n shareConfig?: ShareConfig;\n\n /** Talk to founder button configuration */\n talkToFounder?: TalkToFounderConfig;\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Custom className for the container */\n className?: string;\n\n /** Custom className for the inner content */\n contentClassName?: string;\n}\n\n/**\n * Default Talk to Founder button.\n */\nconst TalkToFounderButton: React.FC<{\n config: TalkToFounderConfig;\n}> = ({ config }) => {\n const IconComponent = config.icon || CalendarDaysIcon;\n const buttonText = config.buttonText || 'Talk to Founder';\n\n return (\n <a\n href={config.meetingUrl}\n target='_blank'\n rel='noopener noreferrer'\n className={cn(\n 'inline-flex items-center gap-2 px-3 py-1.5',\n 'text-sm font-medium',\n 'text-blue-600 dark:text-blue-400',\n 'hover:text-blue-700 dark:hover:text-blue-300',\n 'bg-blue-50 dark:bg-blue-900/20',\n 'hover:bg-blue-100 dark:hover:bg-blue-900/30',\n 'rounded-full',\n 'border border-blue-200 dark:border-blue-800',\n 'transition-colors'\n )}\n >\n <IconComponent className='h-4 w-4' />\n <span>{buttonText}</span>\n </a>\n );\n};\n\n/**\n * AppBreadcrumbs - Breadcrumb navigation with social share and \"Talk to Founder\" button.\n *\n * Features:\n * - Breadcrumb trail with links\n * - Social share buttons on the right\n * - Optional \"Talk to Founder\" meeting button\n * - Always renders at max-w-7xl width\n * - Dark mode support\n *\n * @example\n * ```tsx\n * <AppBreadcrumbs\n * items={[\n * { label: 'Home', href: '/' },\n * { label: 'Products', href: '/products' },\n * { label: 'Widget', current: true },\n * ]}\n * shareConfig={{\n * title: 'Check out this widget',\n * description: 'Amazing widget for your needs',\n * hashtags: ['widget', 'product'],\n * }}\n * talkToFounder={{\n * meetingUrl: 'https://calendly.com/founder/30min',\n * buttonText: 'Book a call',\n * }}\n * />\n * ```\n */\nexport const AppBreadcrumbs: React.FC<AppBreadcrumbsProps> = ({\n items,\n shareConfig,\n talkToFounder,\n variant = 'default',\n className,\n contentClassName,\n}) => {\n // Don't render if no items or only home\n if (!items || items.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(breadcrumbContainerVariants({ variant }), className)}>\n <div className={cn('max-w-7xl mx-auto px-4 py-3', contentClassName)}>\n <div className='flex items-center justify-between gap-4'>\n {/* Breadcrumb trail */}\n <div className='flex-1 min-w-0'>\n <BreadcrumbSection items={items} shareConfig={shareConfig} />\n </div>\n\n {/* Right side: Talk to Founder + Share (if shareConfig, share is handled by BreadcrumbSection) */}\n {talkToFounder && (\n <div className='flex items-center gap-3 flex-shrink-0'>\n <TalkToFounderButton config={talkToFounder} />\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n\nexport default AppBreadcrumbs;\n","import React, { type ComponentType } from 'react';\nimport {\n Footer as FooterContainer,\n FooterCompact,\n FooterCompactLeft,\n FooterCompactRight,\n FooterVersion,\n FooterCopyright,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport type {\n StatusIndicatorConfig,\n LinkComponentProps,\n FooterLinkItem,\n} from '../../types';\n\n/**\n * Props for the SystemStatusIndicator component from @sudobility/devops-components.\n */\nexport interface SystemStatusIndicatorProps {\n statusPageUrl: string;\n apiEndpoint?: string;\n refreshInterval?: number;\n size?: 'sm' | 'md' | 'lg';\n version?: string;\n isNetworkOnline?: boolean;\n}\n\nexport interface AppFooterProps {\n /** App version string */\n version?: string;\n\n /** Copyright year or range (e.g., \"2025\" or \"2025-2026\") */\n copyrightYear?: string;\n\n /** Company name */\n companyName: string;\n\n /** Company URL (optional - creates a link if provided) */\n companyUrl?: string;\n\n /** Rights text (e.g., \"All rights reserved\") */\n rightsText?: string;\n\n /** Status indicator config (optional) */\n statusIndicator?: StatusIndicatorConfig;\n\n /**\n * SystemStatusIndicator component from @sudobility/devops-components.\n * Pass this to enable status indicator functionality.\n */\n StatusIndicatorComponent?: ComponentType<SystemStatusIndicatorProps>;\n\n /** Right-side links (e.g., Privacy, Terms) */\n links?: FooterLinkItem[];\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Sticky positioning (sticks to bottom of viewport) */\n sticky?: boolean;\n\n /** Network online status (for status indicator) */\n isNetworkOnline?: boolean;\n\n /** Custom className */\n className?: string;\n}\n\n/**\n * Default link component that renders a plain anchor.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * Helper to get copyright year or range.\n */\nfunction getCopyrightYear(startYear = 2025): string {\n const currentYear = new Date().getFullYear();\n if (currentYear === startYear) {\n return String(startYear);\n } else if (currentYear > startYear) {\n return `${startYear}-${currentYear}`;\n }\n return String(startYear);\n}\n\n/**\n * AppFooter - Compact footer for app pages.\n *\n * Features:\n * - Version display\n * - Copyright with company name\n * - System status indicator (optional)\n * - Right-side links (Privacy, Terms, etc.)\n * - Sticky positioning option\n * - Dark mode support\n *\n * @example\n * ```tsx\n * import { SystemStatusIndicator } from '@sudobility/devops-components';\n *\n * <AppFooter\n * version=\"1.0.0\"\n * companyName=\"Sudobility Inc.\"\n * companyUrl=\"/\"\n * rightsText=\"All rights reserved\"\n * statusIndicator={{\n * statusPageUrl: 'https://status.example.com',\n * apiEndpoint: 'https://status.example.com/api/v1/status',\n * }}\n * StatusIndicatorComponent={SystemStatusIndicator}\n * links={[\n * { label: 'Privacy', href: '/privacy' },\n * { label: 'Terms', href: '/terms' },\n * ]}\n * sticky\n * />\n * ```\n */\nexport const AppFooter: React.FC<AppFooterProps> = ({\n version,\n copyrightYear,\n companyName,\n companyUrl,\n rightsText = 'All rights reserved',\n statusIndicator,\n StatusIndicatorComponent,\n links = [],\n LinkComponent = DefaultLinkComponent,\n sticky = true,\n isNetworkOnline = true,\n className,\n}) => {\n const year = copyrightYear || getCopyrightYear();\n\n const companyLink = companyUrl ? (\n <LinkComponent\n href={companyUrl}\n className='text-blue-400 hover:text-blue-300 transition-colors'\n >\n {companyName}\n </LinkComponent>\n ) : undefined;\n\n return (\n <FooterContainer\n variant='compact'\n sticky={sticky}\n className={cn(className)}\n >\n <FooterCompact>\n <FooterCompactLeft>\n {version && <FooterVersion version={version} />}\n <FooterCopyright\n year={year}\n companyName={companyName}\n rightsText={rightsText}\n companyLink={companyLink}\n />\n {statusIndicator && StatusIndicatorComponent && (\n <StatusIndicatorComponent\n statusPageUrl={statusIndicator.statusPageUrl}\n apiEndpoint={statusIndicator.apiEndpoint}\n refreshInterval={statusIndicator.refreshInterval || 60000}\n size='sm'\n version={version}\n isNetworkOnline={isNetworkOnline}\n />\n )}\n </FooterCompactLeft>\n <FooterCompactRight>\n {links.map((link, index) => (\n <React.Fragment key={link.href || index}>\n {link.onClick ? (\n <button\n onClick={link.onClick}\n className='text-gray-400 hover:text-white transition-colors'\n >\n {link.label}\n </button>\n ) : (\n <LinkComponent\n href={link.href}\n className='text-gray-400 hover:text-white transition-colors'\n >\n {link.label}\n </LinkComponent>\n )}\n </React.Fragment>\n ))}\n </FooterCompactRight>\n </FooterCompact>\n </FooterContainer>\n );\n};\n\nexport default AppFooter;\n","import React, { type ComponentType } from 'react';\nimport {\n Logo,\n Footer as FooterContainer,\n FooterGrid,\n FooterBrand,\n FooterLinkSection,\n FooterLink,\n FooterBottom,\n FooterVersion,\n FooterCopyright,\n FooterSocialLinks,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport type {\n StatusIndicatorConfig,\n LinkComponentProps,\n FooterLinkSection as FooterLinkSectionConfig,\n SocialLinksConfig,\n} from '../../types';\nimport type { SystemStatusIndicatorProps } from './app-footer';\n\nexport interface AppFooterForHomePageProps {\n /** App logo configuration */\n logo: {\n /** Logo image src (optional - if not provided, uses Logo component) */\n src?: string;\n /** App name */\n appName: string;\n };\n\n /** Footer link sections (columns of links) */\n linkSections: FooterLinkSectionConfig[];\n\n /** Social media links */\n socialLinks?: SocialLinksConfig;\n\n /** System status indicator configuration */\n statusIndicator?: StatusIndicatorConfig;\n\n /**\n * SystemStatusIndicator component from @sudobility/devops-components.\n * Pass this to enable status indicator functionality.\n */\n StatusIndicatorComponent?: ComponentType<SystemStatusIndicatorProps>;\n\n /** App version string */\n version?: string;\n\n /** Copyright year or range */\n copyrightYear?: string;\n\n /** Company name for copyright */\n companyName: string;\n\n /** Company link URL (optional) */\n companyUrl?: string;\n\n /** Footer description text (below logo) */\n description?: string;\n\n /** Rights text (e.g., \"All rights reserved\") */\n rightsText?: string;\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Network online status (for status indicator) */\n isNetworkOnline?: boolean;\n\n /** Custom className */\n className?: string;\n\n /** Number of columns for link grid (default: auto based on section count) */\n gridColumns?: 2 | 3 | 4 | 5;\n}\n\n/**\n * Default link component that renders a plain anchor.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * Helper to get copyright year or range.\n */\nfunction getCopyrightYear(startYear = 2025): string {\n const currentYear = new Date().getFullYear();\n if (currentYear === startYear) {\n return String(startYear);\n } else if (currentYear > startYear) {\n return `${startYear}-${currentYear}`;\n }\n return String(startYear);\n}\n\n/**\n * Get grid columns class based on section count.\n */\nfunction getGridColumnsClass(sectionCount: number, explicit?: number): string {\n const cols = explicit || Math.min(sectionCount, 4);\n switch (cols) {\n case 2:\n return 'md:grid-cols-2';\n case 3:\n return 'md:grid-cols-3';\n case 4:\n return 'md:grid-cols-4';\n case 5:\n return 'md:grid-cols-5';\n default:\n return 'md:grid-cols-4';\n }\n}\n\n/**\n * AppFooterForHomePage - Full footer for home/landing pages.\n *\n * Features:\n * - Multiple link sections in a grid\n * - Logo and brand description\n * - Social media links\n * - System status indicator (optional)\n * - Version and copyright\n * - Dark mode support\n *\n * @example\n * ```tsx\n * import { SystemStatusIndicator } from '@sudobility/devops-components';\n *\n * <AppFooterForHomePage\n * logo={{ appName: 'My App' }}\n * linkSections={[\n * {\n * title: 'Product',\n * links: [\n * { label: 'Features', href: '/features' },\n * { label: 'Pricing', href: '/pricing' },\n * ],\n * },\n * {\n * title: 'Company',\n * links: [\n * { label: 'About', href: '/about' },\n * { label: 'Contact', href: '/contact' },\n * ],\n * },\n * ]}\n * socialLinks={{\n * twitterUrl: 'https://twitter.com/myapp',\n * discordUrl: 'https://discord.gg/myapp',\n * }}\n * statusIndicator={{\n * statusPageUrl: 'https://status.example.com',\n * }}\n * StatusIndicatorComponent={SystemStatusIndicator}\n * version=\"1.0.0\"\n * companyName=\"Sudobility Inc.\"\n * description=\"Building the future of web3 communication\"\n * />\n * ```\n */\nexport const AppFooterForHomePage: React.FC<AppFooterForHomePageProps> = ({\n logo,\n linkSections,\n socialLinks,\n statusIndicator,\n StatusIndicatorComponent,\n version,\n copyrightYear,\n companyName,\n companyUrl,\n description,\n rightsText = 'All rights reserved',\n LinkComponent = DefaultLinkComponent,\n isNetworkOnline = true,\n className,\n gridColumns,\n}) => {\n const year = copyrightYear || getCopyrightYear();\n const gridClass = getGridColumnsClass(linkSections.length, gridColumns);\n\n const companyLink = companyUrl ? (\n <LinkComponent\n href={companyUrl}\n className='text-blue-400 hover:text-blue-300 transition-colors'\n >\n {companyName}\n </LinkComponent>\n ) : undefined;\n\n return (\n <FooterContainer variant='full' className={cn(className)}>\n <FooterGrid className={gridClass}>\n {linkSections.map((section, sectionIndex) => (\n <FooterLinkSection\n key={section.title || sectionIndex}\n title={section.title}\n >\n {section.links.map((link, linkIndex) => (\n <FooterLink key={link.href || linkIndex}>\n {link.onClick ? (\n <button onClick={link.onClick} className='text-left'>\n {link.label}\n </button>\n ) : (\n <LinkComponent href={link.href}>{link.label}</LinkComponent>\n )}\n </FooterLink>\n ))}\n </FooterLinkSection>\n ))}\n </FooterGrid>\n\n <FooterBottom>\n <FooterBrand\n description={description}\n className='flex flex-col items-center'\n >\n <LinkComponent\n href='/'\n className='text-white hover:opacity-80 transition-opacity'\n >\n {logo.src ? (\n <img\n src={logo.src}\n alt={logo.appName}\n className='h-8 object-contain'\n />\n ) : (\n <Logo size='md' showText={true} logoText={logo.appName} />\n )}\n </LinkComponent>\n </FooterBrand>\n {version && <FooterVersion version={version} />}\n <FooterCopyright\n year={year}\n companyName={companyName}\n rightsText={rightsText}\n companyLink={companyLink}\n />\n {statusIndicator && StatusIndicatorComponent && (\n <StatusIndicatorComponent\n statusPageUrl={statusIndicator.statusPageUrl}\n apiEndpoint={statusIndicator.apiEndpoint}\n refreshInterval={statusIndicator.refreshInterval || 60000}\n size='sm'\n version={version}\n isNetworkOnline={isNetworkOnline}\n />\n )}\n </FooterBottom>\n\n {socialLinks && (\n <div className='flex justify-center mt-4'>\n <FooterSocialLinks\n twitterUrl={socialLinks.twitterUrl}\n discordUrl={socialLinks.discordUrl}\n linkedinUrl={socialLinks.linkedinUrl}\n githubUrl={socialLinks.githubUrl}\n redditUrl={socialLinks.redditUrl}\n farcasterUrl={socialLinks.farcasterUrl}\n telegramUrl={socialLinks.telegramUrl}\n />\n </div>\n )}\n </FooterContainer>\n );\n};\n\nexport default AppFooterForHomePage;\n","import React, { type ReactNode } from 'react';\nimport { LayoutProvider } from '@sudobility/components';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils';\nimport {\n AppBreadcrumbs,\n type AppBreadcrumbsProps,\n} from '../breadcrumbs/app-breadcrumbs';\nimport type { MaxWidth, ContentPadding, BackgroundVariant } from '../../types';\n\nconst layoutVariants = cva('min-h-screen flex flex-col', {\n variants: {\n background: {\n default: 'bg-gray-50 dark:bg-gray-900',\n white: 'bg-white dark:bg-gray-900',\n gradient:\n 'bg-gradient-to-br from-gray-50 to-blue-50 dark:from-gray-900 dark:to-gray-800',\n },\n },\n defaultVariants: {\n background: 'default',\n },\n});\n\nconst maxWidthClasses: Record<MaxWidth, string> = {\n sm: 'max-w-sm',\n md: 'max-w-md',\n lg: 'max-w-lg',\n xl: 'max-w-xl',\n '2xl': 'max-w-2xl',\n '4xl': 'max-w-4xl',\n '7xl': 'max-w-7xl',\n full: 'max-w-full',\n};\n\nconst paddingClasses: Record<ContentPadding, string> = {\n none: '',\n sm: 'px-4 sm:px-6 py-6',\n md: 'px-4 py-8',\n lg: 'px-4 py-12',\n};\n\nexport interface AppPageLayoutProps extends VariantProps<\n typeof layoutVariants\n> {\n /** Page content */\n children: ReactNode;\n\n /** TopBar slot - pass an AppTopBar variant or custom component */\n topBar: ReactNode;\n\n /** Breadcrumbs configuration (optional) */\n breadcrumbs?: AppBreadcrumbsProps;\n\n /** Footer slot - pass an AppFooter variant or custom component */\n footer?: ReactNode;\n\n /** Max width for content area (default: '7xl') */\n maxWidth?: MaxWidth;\n\n /** Content padding (default: 'md') */\n contentPadding?: ContentPadding;\n\n /** Background variant */\n background?: BackgroundVariant;\n\n /** Layout mode for LayoutProvider */\n layoutMode?: 'standard';\n\n /** Custom className for the layout container */\n className?: string;\n\n /** Custom className for the content area */\n contentClassName?: string;\n\n /** Custom className for the main element */\n mainClassName?: string;\n}\n\n/**\n * AppPageLayout - Layout wrapper combining TopBar, Breadcrumbs, Content, and Footer.\n *\n * Features:\n * - Flexible slots for TopBar and Footer\n * - Optional breadcrumbs with share and \"Talk to Founder\"\n * - Configurable content max-width and padding\n * - Background variants\n * - Dark mode support\n * - Sticky footer behavior\n *\n * @example\n * ```tsx\n * <AppPageLayout\n * topBar={\n * <AppTopBarWithFirebaseAuth\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={menuItems}\n * AuthActionComponent={AuthAction}\n * onLoginClick={() => navigate('/login')}\n * />\n * }\n * breadcrumbs={{\n * items: breadcrumbItems,\n * shareConfig: { title: 'Page', description: 'Description', hashtags: [] },\n * }}\n * footer={\n * <AppFooter\n * version=\"1.0.0\"\n * companyName=\"My Company\"\n * links={[{ label: 'Privacy', href: '/privacy' }]}\n * />\n * }\n * maxWidth=\"7xl\"\n * background=\"default\"\n * >\n * <h1>Page Content</h1>\n * </AppPageLayout>\n * ```\n */\nexport const AppPageLayout: React.FC<AppPageLayoutProps> = ({\n children,\n topBar,\n breadcrumbs,\n footer,\n maxWidth = '7xl',\n contentPadding = 'md',\n background = 'default',\n layoutMode = 'standard',\n className,\n contentClassName,\n mainClassName,\n}) => {\n return (\n <LayoutProvider mode={layoutMode}>\n <div className={cn(layoutVariants({ background }), className)}>\n {/* Header Section */}\n <header>{topBar}</header>\n\n {/* Breadcrumb Section */}\n {breadcrumbs && breadcrumbs.items && breadcrumbs.items.length > 0 && (\n <AppBreadcrumbs {...breadcrumbs} />\n )}\n\n {/* Main Content */}\n <main className={cn('flex-1 overflow-auto', mainClassName)}>\n <div\n className={cn(\n 'mx-auto',\n maxWidthClasses[maxWidth],\n paddingClasses[contentPadding],\n contentClassName\n )}\n >\n {children}\n </div>\n </main>\n\n {/* Footer */}\n {footer && <footer>{footer}</footer>}\n </div>\n </LayoutProvider>\n );\n};\n\nexport default AppPageLayout;\n","import React from 'react';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Label,\n} from '@sudobility/components';\nimport { textVariants } from '@sudobility/design';\n\n/**\n * Theme options for appearance settings.\n */\nexport enum Theme {\n LIGHT = 'light',\n DARK = 'dark',\n SYSTEM = 'system',\n}\n\n/**\n * Font size options for appearance settings.\n */\nexport enum FontSize {\n SMALL = 'small',\n MEDIUM = 'medium',\n LARGE = 'large',\n}\n\n/**\n * Translation keys used by AppearanceSettings.\n * Provide a translation function to customize labels.\n */\nexport interface AppearanceSettingsTranslations {\n heading: string;\n description: string;\n themeLabel: string;\n themeSelectPlaceholder: string;\n themeLight: string;\n themeDark: string;\n themeSystem: string;\n themeDescription: string;\n fontSizeLabel: string;\n fontSizeSelectPlaceholder: string;\n fontSizeSmall: string;\n fontSizeMedium: string;\n fontSizeLarge: string;\n fontSizeDescription: string;\n infoHeading: string;\n infoDescription: string;\n}\n\nconst defaultTranslations: AppearanceSettingsTranslations = {\n heading: 'Appearance',\n description: 'Customize the look and feel of the application.',\n themeLabel: 'Theme',\n themeSelectPlaceholder: 'Select theme',\n themeLight: 'Light',\n themeDark: 'Dark',\n themeSystem: 'System',\n themeDescription: 'Choose your preferred color theme.',\n fontSizeLabel: 'Font Size',\n fontSizeSelectPlaceholder: 'Select font size',\n fontSizeSmall: 'Small',\n fontSizeMedium: 'Medium',\n fontSizeLarge: 'Large',\n fontSizeDescription: 'Adjust the text size for better readability.',\n infoHeading: 'About Settings',\n infoDescription:\n 'Your appearance preferences are saved locally and will be applied automatically on your next visit.',\n};\n\nexport interface AppearanceSettingsProps {\n /** Current theme value */\n theme: Theme | string;\n\n /** Current font size value */\n fontSize: FontSize | string;\n\n /** Callback when theme changes */\n onThemeChange: (theme: Theme) => void;\n\n /** Callback when font size changes */\n onFontSizeChange: (fontSize: FontSize) => void;\n\n /**\n * Optional translation function.\n * If provided, will be called with a key from AppearanceSettingsTranslations.\n * Falls back to default English strings if not provided.\n */\n t?: (key: string, fallback?: string) => string;\n\n /** Optional className for the container */\n className?: string;\n\n /** Whether to show the information box at the bottom */\n showInfoBox?: boolean;\n}\n\n/**\n * AppearanceSettings - A reusable component for theme and font size settings.\n *\n * This component can be used across different apps to provide consistent\n * appearance customization options.\n *\n * @example\n * ```tsx\n * // Basic usage with useTheme hook\n * const { theme, fontSize, setTheme, setFontSize } = useTheme();\n *\n * <AppearanceSettings\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * />\n *\n * // With i18n translation\n * const { t } = useTranslation('settings');\n *\n * <AppearanceSettings\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * t={(key, fallback) => t(`appearance.${key}`, fallback)}\n * />\n * ```\n */\nexport const AppearanceSettings: React.FC<AppearanceSettingsProps> = ({\n theme,\n fontSize,\n onThemeChange,\n onFontSizeChange,\n t,\n className,\n showInfoBox = true,\n}) => {\n // Helper to get translated string with fallback\n const getText = (key: keyof AppearanceSettingsTranslations): string => {\n const fallback = defaultTranslations[key];\n return t ? t(key, fallback) : fallback;\n };\n\n return (\n <div className={className}>\n <div className='space-y-6'>\n <div>\n <h2 className={`${textVariants.heading.h4()} mb-2`}>\n {getText('heading')}\n </h2>\n <p\n className={`${textVariants.body.sm()} text-gray-600 dark:text-gray-400`}\n >\n {getText('description')}\n </p>\n </div>\n\n <div className='space-y-6'>\n {/* Theme Setting */}\n <div className='space-y-2'>\n <Label\n htmlFor='theme-select'\n className={textVariants.label.default()}\n >\n {getText('themeLabel')}\n </Label>\n <Select\n value={theme}\n onValueChange={(value: string) => onThemeChange(value as Theme)}\n >\n <SelectTrigger id='theme-select'>\n <SelectValue placeholder={getText('themeSelectPlaceholder')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={Theme.LIGHT}>\n {getText('themeLight')}\n </SelectItem>\n <SelectItem value={Theme.DARK}>\n {getText('themeDark')}\n </SelectItem>\n <SelectItem value={Theme.SYSTEM}>\n {getText('themeSystem')}\n </SelectItem>\n </SelectContent>\n </Select>\n <p\n className={`${textVariants.body.xs()} text-gray-500 dark:text-gray-400`}\n >\n {getText('themeDescription')}\n </p>\n </div>\n\n {/* Font Size Setting */}\n <div className='space-y-2'>\n <Label\n htmlFor='font-size-select'\n className={textVariants.label.default()}\n >\n {getText('fontSizeLabel')}\n </Label>\n <Select\n value={fontSize}\n onValueChange={(value: string) =>\n onFontSizeChange(value as FontSize)\n }\n >\n <SelectTrigger id='font-size-select'>\n <SelectValue\n placeholder={getText('fontSizeSelectPlaceholder')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={FontSize.SMALL}>\n {getText('fontSizeSmall')}\n </SelectItem>\n <SelectItem value={FontSize.MEDIUM}>\n {getText('fontSizeMedium')}\n </SelectItem>\n <SelectItem value={FontSize.LARGE}>\n {getText('fontSizeLarge')}\n </SelectItem>\n </SelectContent>\n </Select>\n <p\n className={`${textVariants.body.xs()} text-gray-500 dark:text-gray-400`}\n >\n {getText('fontSizeDescription')}\n </p>\n </div>\n </div>\n\n {/* Information Box */}\n {showInfoBox && (\n <div className='bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4 border border-blue-200 dark:border-blue-800'>\n <h4 className='text-sm font-medium text-blue-900 dark:text-blue-100 mb-2'>\n {getText('infoHeading')}\n </h4>\n <p className='text-sm text-blue-700 dark:text-blue-300'>\n {getText('infoDescription')}\n </p>\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default AppearanceSettings;\n","import React, {\n useState,\n useMemo,\n useCallback,\n type ReactNode,\n type ComponentType,\n} from 'react';\nimport { PaintBrushIcon, ChevronLeftIcon } from '@heroicons/react/24/outline';\nimport { cn } from '../../utils';\nimport { AppearanceSettings } from './appearance-settings';\nimport { Theme, FontSize } from './appearance-settings';\n\n/**\n * Configuration for a settings section in the navigation.\n */\nexport interface SettingsSectionConfig {\n /** Unique identifier for the section */\n id: string;\n /** Icon component to display */\n icon: ComponentType<{ className?: string }>;\n /** Display label */\n label: string;\n /** Short description shown below label */\n description: string;\n /** The content to render when this section is selected */\n content: ReactNode;\n}\n\n/**\n * Translation keys used by GlobalSettingsPage.\n */\nexport interface GlobalSettingsPageTranslations {\n title: string;\n backButton: string;\n appearanceLabel: string;\n appearanceDescription: string;\n}\n\nconst defaultTranslations: GlobalSettingsPageTranslations = {\n title: 'Settings',\n backButton: 'Back',\n appearanceLabel: 'Appearance',\n appearanceDescription: 'Theme and font size settings',\n};\n\nexport interface GlobalSettingsPageProps {\n /** Current theme value */\n theme: Theme | string;\n\n /** Current font size value */\n fontSize: FontSize | string;\n\n /** Callback when theme changes */\n onThemeChange: (theme: Theme) => void;\n\n /** Callback when font size changes */\n onFontSizeChange: (fontSize: FontSize) => void;\n\n /**\n * Additional settings sections to display after Appearance.\n * Each section needs an id, icon, label, description, and content.\n */\n additionalSections?: SettingsSectionConfig[];\n\n /**\n * Optional translation function.\n * Falls back to default English strings if not provided.\n */\n t?: (key: string, fallback?: string) => string;\n\n /**\n * Translation function for AppearanceSettings.\n * If provided, will be passed to AppearanceSettings component.\n */\n appearanceT?: (key: string, fallback?: string) => string;\n\n /** Optional className for the container */\n className?: string;\n\n /** Whether to show the info box in appearance settings */\n showAppearanceInfoBox?: boolean;\n}\n\n/**\n * GlobalSettingsPage - A reusable settings page with master-detail layout.\n *\n * Features:\n * - Appearance settings built-in as the first section\n * - Extensible via additionalSections prop\n * - Responsive master-detail layout\n * - Mobile-friendly with back navigation\n *\n * @example\n * ```tsx\n * // Basic usage\n * <GlobalSettingsPage\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * />\n *\n * // With additional sections\n * <GlobalSettingsPage\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * additionalSections={[\n * {\n * id: 'notifications',\n * icon: BellIcon,\n * label: 'Notifications',\n * description: 'Manage notification preferences',\n * content: <NotificationSettings />,\n * },\n * ]}\n * />\n * ```\n */\nexport const GlobalSettingsPage: React.FC<GlobalSettingsPageProps> = ({\n theme,\n fontSize,\n onThemeChange,\n onFontSizeChange,\n additionalSections = [],\n t,\n appearanceT,\n className,\n showAppearanceInfoBox = true,\n}) => {\n const [selectedSection, setSelectedSection] = useState('appearance');\n const [mobileView, setMobileView] = useState<'navigation' | 'content'>(\n 'navigation'\n );\n\n // Helper to get translated string with fallback\n const getText = useCallback(\n (key: keyof GlobalSettingsPageTranslations): string => {\n const fallback = defaultTranslations[key];\n return t ? t(key, fallback) : fallback;\n },\n [t]\n );\n\n // Build all sections with appearance first\n const allSections: SettingsSectionConfig[] = useMemo(\n () => [\n {\n id: 'appearance',\n icon: PaintBrushIcon,\n label: getText('appearanceLabel'),\n description: getText('appearanceDescription'),\n content: (\n <AppearanceSettings\n theme={theme}\n fontSize={fontSize}\n onThemeChange={onThemeChange}\n onFontSizeChange={onFontSizeChange}\n t={appearanceT}\n showInfoBox={showAppearanceInfoBox}\n />\n ),\n },\n ...additionalSections,\n ],\n [\n additionalSections,\n getText,\n theme,\n fontSize,\n onThemeChange,\n onFontSizeChange,\n appearanceT,\n showAppearanceInfoBox,\n ]\n );\n\n const currentSection =\n allSections.find(s => s.id === selectedSection) || allSections[0];\n\n const handleSectionSelect = (sectionId: string) => {\n setSelectedSection(sectionId);\n setMobileView('content');\n };\n\n const handleBackToNavigation = () => {\n setMobileView('navigation');\n };\n\n // Navigation list\n const navigationList = (\n <div className='space-y-0'>\n {allSections.map(section => {\n const Icon = section.icon;\n const isSelected = selectedSection === section.id;\n return (\n <div\n key={section.id}\n onClick={() => handleSectionSelect(section.id)}\n className={cn(\n 'flex items-start p-4 cursor-pointer transition-colors',\n 'border-b border-gray-200 dark:border-gray-700 last:border-b-0',\n isSelected\n ? 'bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400'\n : 'hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300'\n )}\n >\n <Icon className='h-5 w-5 mt-0.5 mr-3 flex-shrink-0' />\n <div>\n <div className='font-medium'>{section.label}</div>\n <div className='text-xs text-gray-500 dark:text-gray-400 mt-0.5'>\n {section.description}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n );\n\n return (\n <div className={cn('flex-1', className)}>\n {/* Desktop Layout */}\n <div className='hidden md:flex h-full'>\n {/* Master (Navigation) */}\n <div className='w-80 flex-shrink-0 border-r border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900'>\n <div className='p-4 border-b border-gray-200 dark:border-gray-700'>\n <h1 className='text-xl font-semibold text-gray-900 dark:text-white'>\n {getText('title')}\n </h1>\n </div>\n <div className='overflow-y-auto'>{navigationList}</div>\n </div>\n\n {/* Detail (Content) */}\n <div className='flex-1 overflow-y-auto bg-gray-50 dark:bg-gray-800'>\n <div className='p-6'>\n <h2 className='text-lg font-semibold text-gray-900 dark:text-white mb-6'>\n {currentSection.label}\n </h2>\n {currentSection.content}\n </div>\n </div>\n </div>\n\n {/* Mobile Layout */}\n <div className='md:hidden'>\n {mobileView === 'navigation' ? (\n <div className='bg-white dark:bg-gray-900 min-h-full'>\n <div className='p-4 border-b border-gray-200 dark:border-gray-700'>\n <h1 className='text-xl font-semibold text-gray-900 dark:text-white'>\n {getText('title')}\n </h1>\n </div>\n {navigationList}\n </div>\n ) : (\n <div className='bg-white dark:bg-gray-900 min-h-full'>\n <div className='p-4 border-b border-gray-200 dark:border-gray-700 flex items-center'>\n <button\n onClick={handleBackToNavigation}\n className='flex items-center text-blue-600 dark:text-blue-400 mr-4'\n >\n <ChevronLeftIcon className='h-5 w-5 mr-1' />\n <span>{getText('backButton')}</span>\n </button>\n <h2 className='text-lg font-semibold text-gray-900 dark:text-white'>\n {currentSection.label}\n </h2>\n </div>\n <div className='p-4'>{currentSection.content}</div>\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default GlobalSettingsPage;\n"],"names":["DefaultLinkComponent","className","AuthStatus","ChainType","getCopyrightYear","FooterContainer","Theme","FontSize","defaultTranslations"],"mappings":"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"}
|