@streamoid/settings 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +195 -34
- package/dist/index.mjs +195 -34
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -104,6 +104,10 @@ interface SettingsAuthUser {
|
|
|
104
104
|
"unspecified" = explicit skip; otherwise one of the host-defined ids
|
|
105
105
|
(e.g. "design", "merchandising"). */
|
|
106
106
|
userSpecialization?: string;
|
|
107
|
+
/** Preferred UI language as a code from `USER_LANGUAGES` (e.g. "en", "kn").
|
|
108
|
+
Absent or empty means the account has never chosen one, which reads as
|
|
109
|
+
`DEFAULT_USER_LANGUAGE` rather than as blank. */
|
|
110
|
+
language?: string;
|
|
107
111
|
}
|
|
108
112
|
/** Option shape returned by `auth.getSpecializations` — drives the
|
|
109
113
|
Specialization dropdown in Settings → Account. The host adapter is the
|
|
@@ -121,6 +125,7 @@ interface SettingsAuthAdapter {
|
|
|
121
125
|
name?: string;
|
|
122
126
|
imageUrl?: string | null;
|
|
123
127
|
userSpecialization?: string;
|
|
128
|
+
language?: string;
|
|
124
129
|
}) => Promise<void>;
|
|
125
130
|
clearAuth: () => void;
|
|
126
131
|
logout: () => Promise<void>;
|
|
@@ -978,6 +983,40 @@ declare function TokensContent({ embedded, showRevokedOverride, onShowRevokedCha
|
|
|
978
983
|
onCreateOpenChange?: (v: boolean) => void;
|
|
979
984
|
}): react.JSX.Element;
|
|
980
985
|
|
|
986
|
+
/**
|
|
987
|
+
* The account-level language preference, shared by every Streamoid dashboard.
|
|
988
|
+
*
|
|
989
|
+
* Stored as the code and never as the label. `Intl`, the `lang` attribute and
|
|
990
|
+
* every translation API want "kn"; and a label reworded later ("Portuguese" →
|
|
991
|
+
* "Português (Brasil)") should be an edit here, not a migration across every
|
|
992
|
+
* user row. Hosts that want to show the language render the label from this
|
|
993
|
+
* list rather than keeping a map of their own — one list, so two dashboards
|
|
994
|
+
* cannot disagree about what "pt" is called.
|
|
995
|
+
*
|
|
996
|
+
* Mirrors `userLanguages` in the unified backend, which is the source of truth
|
|
997
|
+
* and rejects anything outside it.
|
|
998
|
+
*/
|
|
999
|
+
interface UserLanguage {
|
|
1000
|
+
code: string;
|
|
1001
|
+
/** The English name — "Kannada". What the picker shows. */
|
|
1002
|
+
label: string;
|
|
1003
|
+
}
|
|
1004
|
+
declare const USER_LANGUAGES: readonly UserLanguage[];
|
|
1005
|
+
/**
|
|
1006
|
+
* English until somebody says otherwise.
|
|
1007
|
+
*
|
|
1008
|
+
* Unlike a specialization — where "" means never-answered, and the dashboard
|
|
1009
|
+
* has a reason to keep asking — an unanswered language already has a sensible
|
|
1010
|
+
* answer: the language these dashboards are written in. So a profile with no
|
|
1011
|
+
* language reads as English rather than as blank, and the dropdown is never
|
|
1012
|
+
* shown empty.
|
|
1013
|
+
*/
|
|
1014
|
+
declare const DEFAULT_USER_LANGUAGE = "en";
|
|
1015
|
+
/** The label for a code, falling back to the code itself for one this build
|
|
1016
|
+
does not know — a newer dashboard may have written it, and showing "sw" is
|
|
1017
|
+
better than showing nothing. */
|
|
1018
|
+
declare function userLanguageLabel(code: string | undefined | null): string;
|
|
1019
|
+
|
|
981
1020
|
interface ProfileAvatarProps {
|
|
982
1021
|
name: string;
|
|
983
1022
|
profileImage?: string;
|
|
@@ -1234,4 +1273,4 @@ declare function SettingsAdaptersProvider({ adapters, children, }: {
|
|
|
1234
1273
|
*/
|
|
1235
1274
|
declare function useSettingsAdapters(): SettingsAdapters;
|
|
1236
1275
|
|
|
1237
|
-
export { APP_KEYS, type ApiToken, type AppKey, type AvailableCreditsResponse, BillingContent, type BillingEventPayload, type BillingProduct, type BillingSubscription, BuyCreditsModal, type BuyCreditsPayload, type BuyCreditsResponse, ConfirmDeleteModal, ConfirmLeaveModal, type CreatedToken, type CustomCreditInfo, type CustomCreditResponse, DEFAULT_PERMISSIONS, ExportDateModal, InviteUpdateModal, type InvoicePdfResponse, MemberListFrame, type MemberListFrameProps, type MemberListTab, MemberListToolbar, type MemberListToolbarProps, type MemberPermissionsPayload, OrgMembershipTag, OrganizationContent, type OrganizationData, type OrganizationInvite, OrganizationInviteModal, type OrganizationInviteModalProps, type OrganizationJoinRequest, type OrganizationMember, OrganizationModal, type OrganizationView, type OrganizationWorkspaceItem, type Price, type PriceMetadata, type ProductsResponse, ProfileAvatar, ProfileTab, ReferralTab, SCOPE_LABELS, ScopeHeader, type ScopeHeaderProps, type ServiceItem, type SettingsAdapters, SettingsAdaptersProvider, type SettingsApiAdapter, type SettingsAuthAdapter, type SettingsAuthUser, SettingsContent, type SettingsContentProps, type SettingsImageUploadAdapter, type SettingsNavigationAdapter, type SettingsOrganizationAdapter, type SettingsOrganizationCurrent, type SettingsOrganizationListItem, type SettingsScope, type SettingsTab, type SettingsToastAdapter, SettingsTooltip, type SettingsTooltipPlacement, type SettingsTooltipProps, type SettingsWorkspaceAdapter, type SettingsWorkspaceCurrent, type SettingsWorkspaceListItem, SiconKey, type StoreItem, type SubscriptionPlan, type SubscriptionResponse, TAB_DESCRIPTIONS, TAB_LABELS, TAB_SCOPE, TAB_TO_URL, type TeamMember, TeamsContent, type TokenExpiry, TokensContent, URL_TO_TAB, type UpdateSubscriptionPayload, type UpdateSubscriptionResponse, type UsageHistoryItem, type UsageHistoryResponse, type UserPermissions, type WorkspaceData, WorkspaceGeneralTab, type WorkspaceGeneralTabProps, type WorkspaceInvite, WorkspaceListTab, type WorkspaceMember, WorkspaceModal, WorkspaceTab, countLabel, resolveSettingsTabFromPath, useSettingsAdapters };
|
|
1276
|
+
export { APP_KEYS, type ApiToken, type AppKey, type AvailableCreditsResponse, BillingContent, type BillingEventPayload, type BillingProduct, type BillingSubscription, BuyCreditsModal, type BuyCreditsPayload, type BuyCreditsResponse, ConfirmDeleteModal, ConfirmLeaveModal, type CreatedToken, type CustomCreditInfo, type CustomCreditResponse, DEFAULT_PERMISSIONS, DEFAULT_USER_LANGUAGE, ExportDateModal, InviteUpdateModal, type InvoicePdfResponse, MemberListFrame, type MemberListFrameProps, type MemberListTab, MemberListToolbar, type MemberListToolbarProps, type MemberPermissionsPayload, OrgMembershipTag, OrganizationContent, type OrganizationData, type OrganizationInvite, OrganizationInviteModal, type OrganizationInviteModalProps, type OrganizationJoinRequest, type OrganizationMember, OrganizationModal, type OrganizationView, type OrganizationWorkspaceItem, type Price, type PriceMetadata, type ProductsResponse, ProfileAvatar, ProfileTab, ReferralTab, SCOPE_LABELS, ScopeHeader, type ScopeHeaderProps, type ServiceItem, type SettingsAdapters, SettingsAdaptersProvider, type SettingsApiAdapter, type SettingsAuthAdapter, type SettingsAuthUser, SettingsContent, type SettingsContentProps, type SettingsImageUploadAdapter, type SettingsNavigationAdapter, type SettingsOrganizationAdapter, type SettingsOrganizationCurrent, type SettingsOrganizationListItem, type SettingsScope, type SettingsTab, type SettingsToastAdapter, SettingsTooltip, type SettingsTooltipPlacement, type SettingsTooltipProps, type SettingsWorkspaceAdapter, type SettingsWorkspaceCurrent, type SettingsWorkspaceListItem, SiconKey, type StoreItem, type SubscriptionPlan, type SubscriptionResponse, TAB_DESCRIPTIONS, TAB_LABELS, TAB_SCOPE, TAB_TO_URL, type TeamMember, TeamsContent, type TokenExpiry, TokensContent, URL_TO_TAB, USER_LANGUAGES, type UpdateSubscriptionPayload, type UpdateSubscriptionResponse, type UsageHistoryItem, type UsageHistoryResponse, type UserLanguage, type UserPermissions, type WorkspaceData, WorkspaceGeneralTab, type WorkspaceGeneralTabProps, type WorkspaceInvite, WorkspaceListTab, type WorkspaceMember, WorkspaceModal, WorkspaceTab, countLabel, resolveSettingsTabFromPath, useSettingsAdapters, userLanguageLabel };
|
package/dist/index.d.ts
CHANGED
|
@@ -104,6 +104,10 @@ interface SettingsAuthUser {
|
|
|
104
104
|
"unspecified" = explicit skip; otherwise one of the host-defined ids
|
|
105
105
|
(e.g. "design", "merchandising"). */
|
|
106
106
|
userSpecialization?: string;
|
|
107
|
+
/** Preferred UI language as a code from `USER_LANGUAGES` (e.g. "en", "kn").
|
|
108
|
+
Absent or empty means the account has never chosen one, which reads as
|
|
109
|
+
`DEFAULT_USER_LANGUAGE` rather than as blank. */
|
|
110
|
+
language?: string;
|
|
107
111
|
}
|
|
108
112
|
/** Option shape returned by `auth.getSpecializations` — drives the
|
|
109
113
|
Specialization dropdown in Settings → Account. The host adapter is the
|
|
@@ -121,6 +125,7 @@ interface SettingsAuthAdapter {
|
|
|
121
125
|
name?: string;
|
|
122
126
|
imageUrl?: string | null;
|
|
123
127
|
userSpecialization?: string;
|
|
128
|
+
language?: string;
|
|
124
129
|
}) => Promise<void>;
|
|
125
130
|
clearAuth: () => void;
|
|
126
131
|
logout: () => Promise<void>;
|
|
@@ -978,6 +983,40 @@ declare function TokensContent({ embedded, showRevokedOverride, onShowRevokedCha
|
|
|
978
983
|
onCreateOpenChange?: (v: boolean) => void;
|
|
979
984
|
}): react.JSX.Element;
|
|
980
985
|
|
|
986
|
+
/**
|
|
987
|
+
* The account-level language preference, shared by every Streamoid dashboard.
|
|
988
|
+
*
|
|
989
|
+
* Stored as the code and never as the label. `Intl`, the `lang` attribute and
|
|
990
|
+
* every translation API want "kn"; and a label reworded later ("Portuguese" →
|
|
991
|
+
* "Português (Brasil)") should be an edit here, not a migration across every
|
|
992
|
+
* user row. Hosts that want to show the language render the label from this
|
|
993
|
+
* list rather than keeping a map of their own — one list, so two dashboards
|
|
994
|
+
* cannot disagree about what "pt" is called.
|
|
995
|
+
*
|
|
996
|
+
* Mirrors `userLanguages` in the unified backend, which is the source of truth
|
|
997
|
+
* and rejects anything outside it.
|
|
998
|
+
*/
|
|
999
|
+
interface UserLanguage {
|
|
1000
|
+
code: string;
|
|
1001
|
+
/** The English name — "Kannada". What the picker shows. */
|
|
1002
|
+
label: string;
|
|
1003
|
+
}
|
|
1004
|
+
declare const USER_LANGUAGES: readonly UserLanguage[];
|
|
1005
|
+
/**
|
|
1006
|
+
* English until somebody says otherwise.
|
|
1007
|
+
*
|
|
1008
|
+
* Unlike a specialization — where "" means never-answered, and the dashboard
|
|
1009
|
+
* has a reason to keep asking — an unanswered language already has a sensible
|
|
1010
|
+
* answer: the language these dashboards are written in. So a profile with no
|
|
1011
|
+
* language reads as English rather than as blank, and the dropdown is never
|
|
1012
|
+
* shown empty.
|
|
1013
|
+
*/
|
|
1014
|
+
declare const DEFAULT_USER_LANGUAGE = "en";
|
|
1015
|
+
/** The label for a code, falling back to the code itself for one this build
|
|
1016
|
+
does not know — a newer dashboard may have written it, and showing "sw" is
|
|
1017
|
+
better than showing nothing. */
|
|
1018
|
+
declare function userLanguageLabel(code: string | undefined | null): string;
|
|
1019
|
+
|
|
981
1020
|
interface ProfileAvatarProps {
|
|
982
1021
|
name: string;
|
|
983
1022
|
profileImage?: string;
|
|
@@ -1234,4 +1273,4 @@ declare function SettingsAdaptersProvider({ adapters, children, }: {
|
|
|
1234
1273
|
*/
|
|
1235
1274
|
declare function useSettingsAdapters(): SettingsAdapters;
|
|
1236
1275
|
|
|
1237
|
-
export { APP_KEYS, type ApiToken, type AppKey, type AvailableCreditsResponse, BillingContent, type BillingEventPayload, type BillingProduct, type BillingSubscription, BuyCreditsModal, type BuyCreditsPayload, type BuyCreditsResponse, ConfirmDeleteModal, ConfirmLeaveModal, type CreatedToken, type CustomCreditInfo, type CustomCreditResponse, DEFAULT_PERMISSIONS, ExportDateModal, InviteUpdateModal, type InvoicePdfResponse, MemberListFrame, type MemberListFrameProps, type MemberListTab, MemberListToolbar, type MemberListToolbarProps, type MemberPermissionsPayload, OrgMembershipTag, OrganizationContent, type OrganizationData, type OrganizationInvite, OrganizationInviteModal, type OrganizationInviteModalProps, type OrganizationJoinRequest, type OrganizationMember, OrganizationModal, type OrganizationView, type OrganizationWorkspaceItem, type Price, type PriceMetadata, type ProductsResponse, ProfileAvatar, ProfileTab, ReferralTab, SCOPE_LABELS, ScopeHeader, type ScopeHeaderProps, type ServiceItem, type SettingsAdapters, SettingsAdaptersProvider, type SettingsApiAdapter, type SettingsAuthAdapter, type SettingsAuthUser, SettingsContent, type SettingsContentProps, type SettingsImageUploadAdapter, type SettingsNavigationAdapter, type SettingsOrganizationAdapter, type SettingsOrganizationCurrent, type SettingsOrganizationListItem, type SettingsScope, type SettingsTab, type SettingsToastAdapter, SettingsTooltip, type SettingsTooltipPlacement, type SettingsTooltipProps, type SettingsWorkspaceAdapter, type SettingsWorkspaceCurrent, type SettingsWorkspaceListItem, SiconKey, type StoreItem, type SubscriptionPlan, type SubscriptionResponse, TAB_DESCRIPTIONS, TAB_LABELS, TAB_SCOPE, TAB_TO_URL, type TeamMember, TeamsContent, type TokenExpiry, TokensContent, URL_TO_TAB, type UpdateSubscriptionPayload, type UpdateSubscriptionResponse, type UsageHistoryItem, type UsageHistoryResponse, type UserPermissions, type WorkspaceData, WorkspaceGeneralTab, type WorkspaceGeneralTabProps, type WorkspaceInvite, WorkspaceListTab, type WorkspaceMember, WorkspaceModal, WorkspaceTab, countLabel, resolveSettingsTabFromPath, useSettingsAdapters };
|
|
1276
|
+
export { APP_KEYS, type ApiToken, type AppKey, type AvailableCreditsResponse, BillingContent, type BillingEventPayload, type BillingProduct, type BillingSubscription, BuyCreditsModal, type BuyCreditsPayload, type BuyCreditsResponse, ConfirmDeleteModal, ConfirmLeaveModal, type CreatedToken, type CustomCreditInfo, type CustomCreditResponse, DEFAULT_PERMISSIONS, DEFAULT_USER_LANGUAGE, ExportDateModal, InviteUpdateModal, type InvoicePdfResponse, MemberListFrame, type MemberListFrameProps, type MemberListTab, MemberListToolbar, type MemberListToolbarProps, type MemberPermissionsPayload, OrgMembershipTag, OrganizationContent, type OrganizationData, type OrganizationInvite, OrganizationInviteModal, type OrganizationInviteModalProps, type OrganizationJoinRequest, type OrganizationMember, OrganizationModal, type OrganizationView, type OrganizationWorkspaceItem, type Price, type PriceMetadata, type ProductsResponse, ProfileAvatar, ProfileTab, ReferralTab, SCOPE_LABELS, ScopeHeader, type ScopeHeaderProps, type ServiceItem, type SettingsAdapters, SettingsAdaptersProvider, type SettingsApiAdapter, type SettingsAuthAdapter, type SettingsAuthUser, SettingsContent, type SettingsContentProps, type SettingsImageUploadAdapter, type SettingsNavigationAdapter, type SettingsOrganizationAdapter, type SettingsOrganizationCurrent, type SettingsOrganizationListItem, type SettingsScope, type SettingsTab, type SettingsToastAdapter, SettingsTooltip, type SettingsTooltipPlacement, type SettingsTooltipProps, type SettingsWorkspaceAdapter, type SettingsWorkspaceCurrent, type SettingsWorkspaceListItem, SiconKey, type StoreItem, type SubscriptionPlan, type SubscriptionResponse, TAB_DESCRIPTIONS, TAB_LABELS, TAB_SCOPE, TAB_TO_URL, type TeamMember, TeamsContent, type TokenExpiry, TokensContent, URL_TO_TAB, USER_LANGUAGES, type UpdateSubscriptionPayload, type UpdateSubscriptionResponse, type UsageHistoryItem, type UsageHistoryResponse, type UserLanguage, type UserPermissions, type WorkspaceData, WorkspaceGeneralTab, type WorkspaceGeneralTabProps, type WorkspaceInvite, WorkspaceListTab, type WorkspaceMember, WorkspaceModal, WorkspaceTab, countLabel, resolveSettingsTabFromPath, useSettingsAdapters, userLanguageLabel };
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
ConfirmDeleteModal: () => ConfirmDeleteModal,
|
|
27
27
|
ConfirmLeaveModal: () => ConfirmLeaveModal,
|
|
28
28
|
DEFAULT_PERMISSIONS: () => DEFAULT_PERMISSIONS,
|
|
29
|
+
DEFAULT_USER_LANGUAGE: () => DEFAULT_USER_LANGUAGE,
|
|
29
30
|
ExportDateModal: () => ExportDateModal,
|
|
30
31
|
InviteUpdateModal: () => InviteUpdateModal,
|
|
31
32
|
MemberListFrame: () => MemberListFrame,
|
|
@@ -50,13 +51,15 @@ __export(index_exports, {
|
|
|
50
51
|
TeamsContent: () => TeamsContent,
|
|
51
52
|
TokensContent: () => TokensContent,
|
|
52
53
|
URL_TO_TAB: () => URL_TO_TAB,
|
|
54
|
+
USER_LANGUAGES: () => USER_LANGUAGES,
|
|
53
55
|
WorkspaceGeneralTab: () => WorkspaceGeneralTab,
|
|
54
56
|
WorkspaceListTab: () => WorkspaceListTab,
|
|
55
57
|
WorkspaceModal: () => WorkspaceModal,
|
|
56
58
|
WorkspaceTab: () => WorkspaceTab,
|
|
57
59
|
countLabel: () => countLabel,
|
|
58
60
|
resolveSettingsTabFromPath: () => resolveSettingsTabFromPath,
|
|
59
|
-
useSettingsAdapters: () => useSettingsAdapters
|
|
61
|
+
useSettingsAdapters: () => useSettingsAdapters,
|
|
62
|
+
userLanguageLabel: () => userLanguageLabel
|
|
60
63
|
});
|
|
61
64
|
module.exports = __toCommonJS(index_exports);
|
|
62
65
|
|
|
@@ -91,6 +94,27 @@ var SiconKey = ({ color = "currentColor", strokeWidth = 1.25, size = 24, ...prop
|
|
|
91
94
|
};
|
|
92
95
|
var SiconKey_default = SiconKey;
|
|
93
96
|
|
|
97
|
+
// src/languages.ts
|
|
98
|
+
var USER_LANGUAGES = [
|
|
99
|
+
{ code: "en", label: "English" },
|
|
100
|
+
{ code: "es", label: "Spanish" },
|
|
101
|
+
{ code: "fr", label: "French" },
|
|
102
|
+
{ code: "pt", label: "Portuguese" },
|
|
103
|
+
{ code: "hi", label: "Hindi" },
|
|
104
|
+
{ code: "kn", label: "Kannada" },
|
|
105
|
+
{ code: "te", label: "Telugu" },
|
|
106
|
+
{ code: "ta", label: "Tamil" },
|
|
107
|
+
{ code: "mr", label: "Marathi" },
|
|
108
|
+
{ code: "gu", label: "Gujarati" },
|
|
109
|
+
{ code: "bn", label: "Bengali" },
|
|
110
|
+
{ code: "ar", label: "Arabic" }
|
|
111
|
+
];
|
|
112
|
+
var DEFAULT_USER_LANGUAGE = "en";
|
|
113
|
+
function userLanguageLabel(code) {
|
|
114
|
+
const resolved = (code || "").trim() || DEFAULT_USER_LANGUAGE;
|
|
115
|
+
return USER_LANGUAGES.find((lang) => lang.code === resolved)?.label ?? resolved;
|
|
116
|
+
}
|
|
117
|
+
|
|
94
118
|
// src/workspace-modal.tsx
|
|
95
119
|
var import_react3 = require("react");
|
|
96
120
|
|
|
@@ -2151,7 +2175,7 @@ function OrganizationAffiliationCard({
|
|
|
2151
2175
|
"Failed to change visibility"
|
|
2152
2176
|
);
|
|
2153
2177
|
},
|
|
2154
|
-
children: opt === "private" ? "Only
|
|
2178
|
+
children: opt === "private" ? "Only workspace members" : "Everyone in the organization"
|
|
2155
2179
|
},
|
|
2156
2180
|
opt
|
|
2157
2181
|
);
|
|
@@ -10311,25 +10335,25 @@ function SettingsNavGroupHeader({
|
|
|
10311
10335
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
10312
10336
|
"div",
|
|
10313
10337
|
{
|
|
10314
|
-
className: "flex
|
|
10315
|
-
style: { gap:
|
|
10338
|
+
className: "flex flex-col w-full min-w-0",
|
|
10339
|
+
style: { gap: 2, padding: "2px var(--spacing-xl) var(--spacing-sm)" },
|
|
10316
10340
|
children: [
|
|
10317
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10328
|
-
|
|
10329
|
-
|
|
10330
|
-
|
|
10331
|
-
|
|
10332
|
-
),
|
|
10341
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
10342
|
+
"span",
|
|
10343
|
+
{
|
|
10344
|
+
style: {
|
|
10345
|
+
fontFamily: "var(--font-family-font-family-body)",
|
|
10346
|
+
fontSize: "var(--font-size-font-size-xxs, 10px)",
|
|
10347
|
+
fontWeight: 500,
|
|
10348
|
+
letterSpacing: "0.08em",
|
|
10349
|
+
textTransform: "uppercase",
|
|
10350
|
+
color: MUTED_COLOR2
|
|
10351
|
+
},
|
|
10352
|
+
children: eyebrow
|
|
10353
|
+
}
|
|
10354
|
+
),
|
|
10355
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center min-w-0", style: { gap: "var(--spacing-md)" }, children: [
|
|
10356
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "shrink-0 flex items-center", children: icon }),
|
|
10333
10357
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
10334
10358
|
"span",
|
|
10335
10359
|
{
|
|
@@ -10371,26 +10395,26 @@ function SettingsNav({
|
|
|
10371
10395
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
10372
10396
|
"div",
|
|
10373
10397
|
{
|
|
10374
|
-
className: "flex flex-col items-start shrink-0 relative",
|
|
10398
|
+
className: "flex flex-col items-start shrink-0 relative overflow-y-auto",
|
|
10375
10399
|
style: {
|
|
10376
10400
|
backgroundColor: "var(--alias-surface-base)",
|
|
10377
10401
|
borderRadius: "var(--radius-3xl)",
|
|
10378
10402
|
padding: "var(--spacing-md)",
|
|
10379
10403
|
width: 216,
|
|
10380
|
-
|
|
10404
|
+
maxHeight: "100%",
|
|
10405
|
+
/* A REAL BORDER, not the absolutely-positioned overlay that used to
|
|
10406
|
+
* sit inside this box. Now that the nav scrolls, an `absolute inset-0`
|
|
10407
|
+
* child is positioned against the scrolled CONTENT, so the outline
|
|
10408
|
+
* would slide up out of view and leave the card unbounded. `border`
|
|
10409
|
+
* belongs to the box itself and cannot drift; `box-sizing: border-box`
|
|
10410
|
+
* keeps the 216px width. */
|
|
10411
|
+
border: "1px solid var(--alias-border-subtle)",
|
|
10412
|
+
/* Was `--spacing-xl` (12). The groups and the rules between them sat
|
|
10413
|
+
* closer to each other than the rows inside a group did to their own
|
|
10414
|
+
* heading, so the divisions read as weaker than what they divided. */
|
|
10415
|
+
gap: "var(--spacing-5xl)"
|
|
10381
10416
|
},
|
|
10382
10417
|
children: [
|
|
10383
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
10384
|
-
"div",
|
|
10385
|
-
{
|
|
10386
|
-
"aria-hidden": "true",
|
|
10387
|
-
className: "absolute inset-0 pointer-events-none",
|
|
10388
|
-
style: {
|
|
10389
|
-
border: "1px solid var(--alias-border-subtle)",
|
|
10390
|
-
borderRadius: "var(--radius-3xl)"
|
|
10391
|
-
}
|
|
10392
|
-
}
|
|
10393
|
-
),
|
|
10394
10418
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex flex-col w-full", style: { gap: "var(--spacing-md)" }, children: item("profile", (color) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_icons12.SiconUser, { className: "w-6 h-6", color })) }),
|
|
10395
10419
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_ui11.ScHDivider, {}),
|
|
10396
10420
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col w-full", style: { gap: "var(--spacing-md)" }, children: [
|
|
@@ -10619,13 +10643,134 @@ function SpecializationDropdown({
|
|
|
10619
10643
|
}
|
|
10620
10644
|
);
|
|
10621
10645
|
}
|
|
10646
|
+
function LanguageDropdown({
|
|
10647
|
+
value,
|
|
10648
|
+
onChange,
|
|
10649
|
+
disabled
|
|
10650
|
+
}) {
|
|
10651
|
+
const [open, setOpen] = (0, import_react16.useState)(false);
|
|
10652
|
+
const containerRef = (0, import_react16.useRef)(null);
|
|
10653
|
+
(0, import_react16.useEffect)(() => {
|
|
10654
|
+
if (!open) return;
|
|
10655
|
+
function handleMouseDown(e) {
|
|
10656
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
10657
|
+
setOpen(false);
|
|
10658
|
+
}
|
|
10659
|
+
}
|
|
10660
|
+
function handleKeyDown(e) {
|
|
10661
|
+
if (e.key === "Escape") setOpen(false);
|
|
10662
|
+
}
|
|
10663
|
+
document.addEventListener("mousedown", handleMouseDown);
|
|
10664
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
10665
|
+
return () => {
|
|
10666
|
+
document.removeEventListener("mousedown", handleMouseDown);
|
|
10667
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
10668
|
+
};
|
|
10669
|
+
}, [open]);
|
|
10670
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
10671
|
+
"div",
|
|
10672
|
+
{
|
|
10673
|
+
ref: containerRef,
|
|
10674
|
+
className: "w-full",
|
|
10675
|
+
style: { position: "relative" },
|
|
10676
|
+
children: [
|
|
10677
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("style", { children: DROPDOWN_TRIGGER_STYLES }),
|
|
10678
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
10679
|
+
"div",
|
|
10680
|
+
{
|
|
10681
|
+
className: "spec-dropdown-trigger",
|
|
10682
|
+
"data-disabled": disabled ? "true" : "false",
|
|
10683
|
+
onClick: () => !disabled && setOpen((v) => !v),
|
|
10684
|
+
"aria-haspopup": "listbox",
|
|
10685
|
+
"aria-expanded": open,
|
|
10686
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
10687
|
+
import_ui12.ScTextField,
|
|
10688
|
+
{
|
|
10689
|
+
label: "Language",
|
|
10690
|
+
labelGroup: "label",
|
|
10691
|
+
value: userLanguageLabel(value),
|
|
10692
|
+
placeholderFilled: "Select language",
|
|
10693
|
+
tfGroup: "icon-right",
|
|
10694
|
+
tfRightIcon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
10695
|
+
"span",
|
|
10696
|
+
{
|
|
10697
|
+
style: {
|
|
10698
|
+
display: "flex",
|
|
10699
|
+
alignItems: "center",
|
|
10700
|
+
justifyContent: "center",
|
|
10701
|
+
transform: open ? "rotate(180deg)" : "none",
|
|
10702
|
+
transition: "transform 120ms ease-out"
|
|
10703
|
+
},
|
|
10704
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_icons12.SiconDown, {})
|
|
10705
|
+
}
|
|
10706
|
+
),
|
|
10707
|
+
className: "sc-text-field-full-width",
|
|
10708
|
+
style: { width: "100%" },
|
|
10709
|
+
readOnly: true,
|
|
10710
|
+
disabled
|
|
10711
|
+
}
|
|
10712
|
+
)
|
|
10713
|
+
}
|
|
10714
|
+
),
|
|
10715
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
10716
|
+
"div",
|
|
10717
|
+
{
|
|
10718
|
+
role: "listbox",
|
|
10719
|
+
style: {
|
|
10720
|
+
position: "absolute",
|
|
10721
|
+
top: "calc(100% + 4px)",
|
|
10722
|
+
left: 0,
|
|
10723
|
+
right: 0,
|
|
10724
|
+
zIndex: 50,
|
|
10725
|
+
// The list is longer than the specialization one, so it scrolls
|
|
10726
|
+
// rather than running off the bottom of the panel.
|
|
10727
|
+
maxHeight: 280,
|
|
10728
|
+
overflowY: "auto",
|
|
10729
|
+
background: "var(--alias-surface-subtle, #1a1a1a)",
|
|
10730
|
+
border: "0.5px solid var(--alias-border-subtle, #242424)",
|
|
10731
|
+
borderRadius: "var(--radius-4xl, 18px)",
|
|
10732
|
+
padding: "var(--spacing-md, 8px)",
|
|
10733
|
+
display: "flex",
|
|
10734
|
+
flexDirection: "column",
|
|
10735
|
+
gap: 8,
|
|
10736
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.4)",
|
|
10737
|
+
backdropFilter: "blur(42px)"
|
|
10738
|
+
},
|
|
10739
|
+
children: USER_LANGUAGES.map((lang) => {
|
|
10740
|
+
const isActive = lang.code === value;
|
|
10741
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
10742
|
+
import_ui11.ScMenuOptions,
|
|
10743
|
+
{
|
|
10744
|
+
text: lang.label,
|
|
10745
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_jsx_runtime20.Fragment, {}),
|
|
10746
|
+
hover: isActive ? "true" : "false",
|
|
10747
|
+
variant: "default",
|
|
10748
|
+
role: "option",
|
|
10749
|
+
"aria-selected": isActive,
|
|
10750
|
+
onClick: () => {
|
|
10751
|
+
onChange(lang.code);
|
|
10752
|
+
setOpen(false);
|
|
10753
|
+
},
|
|
10754
|
+
style: { width: "100%", cursor: "pointer" }
|
|
10755
|
+
},
|
|
10756
|
+
lang.code
|
|
10757
|
+
);
|
|
10758
|
+
})
|
|
10759
|
+
}
|
|
10760
|
+
)
|
|
10761
|
+
]
|
|
10762
|
+
}
|
|
10763
|
+
);
|
|
10764
|
+
}
|
|
10622
10765
|
function ProfileTab() {
|
|
10623
10766
|
const { auth, imageUpload, toast } = useSettingsAdapters();
|
|
10624
10767
|
const user = auth.user;
|
|
10625
10768
|
const derivedName = user?.name ?? "";
|
|
10626
10769
|
const derivedSpec = user?.userSpecialization ?? "";
|
|
10770
|
+
const derivedLanguage = user?.language?.trim() || DEFAULT_USER_LANGUAGE;
|
|
10627
10771
|
const [fullName, setFullName] = (0, import_react16.useState)(derivedName);
|
|
10628
10772
|
const [selectedSpec, setSelectedSpec] = (0, import_react16.useState)(derivedSpec);
|
|
10773
|
+
const [selectedLanguage, setSelectedLanguage] = (0, import_react16.useState)(derivedLanguage);
|
|
10629
10774
|
const [saving, setSaving] = (0, import_react16.useState)(false);
|
|
10630
10775
|
const [imageSaving, setImageSaving] = (0, import_react16.useState)(false);
|
|
10631
10776
|
const [imagePreview, setImagePreview] = (0, import_react16.useState)(
|
|
@@ -10636,7 +10781,7 @@ function ProfileTab() {
|
|
|
10636
10781
|
const profileImage = imagePreview ?? getUserProfileImage(user);
|
|
10637
10782
|
const profileInitial = profileDisplayName.charAt(0).toUpperCase();
|
|
10638
10783
|
const disableAllActions = saving || imageSaving;
|
|
10639
|
-
const dirty = fullName.trim() !== derivedName || selectedSpec !== derivedSpec;
|
|
10784
|
+
const dirty = fullName.trim() !== derivedName || selectedSpec !== derivedSpec || selectedLanguage !== derivedLanguage;
|
|
10640
10785
|
(0, import_react16.useEffect)(() => {
|
|
10641
10786
|
setFullName(derivedName);
|
|
10642
10787
|
setImagePreview(void 0);
|
|
@@ -10644,6 +10789,9 @@ function ProfileTab() {
|
|
|
10644
10789
|
(0, import_react16.useEffect)(() => {
|
|
10645
10790
|
setSelectedSpec(derivedSpec);
|
|
10646
10791
|
}, [derivedSpec]);
|
|
10792
|
+
(0, import_react16.useEffect)(() => {
|
|
10793
|
+
setSelectedLanguage(derivedLanguage);
|
|
10794
|
+
}, [derivedLanguage]);
|
|
10647
10795
|
const handleSave = async () => {
|
|
10648
10796
|
if (disableAllActions || !dirty) return;
|
|
10649
10797
|
setSaving(true);
|
|
@@ -10651,6 +10799,8 @@ function ProfileTab() {
|
|
|
10651
10799
|
const patch = {};
|
|
10652
10800
|
if (fullName.trim() !== derivedName) patch.name = fullName.trim();
|
|
10653
10801
|
if (selectedSpec !== derivedSpec) patch.userSpecialization = selectedSpec;
|
|
10802
|
+
if (selectedLanguage !== derivedLanguage)
|
|
10803
|
+
patch.language = selectedLanguage;
|
|
10654
10804
|
await auth.updateProfile(patch);
|
|
10655
10805
|
await auth.refreshProfile();
|
|
10656
10806
|
toast.success("Profile updated");
|
|
@@ -10870,6 +11020,17 @@ function ProfileTab() {
|
|
|
10870
11020
|
}
|
|
10871
11021
|
) })
|
|
10872
11022
|
] }),
|
|
11023
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-start w-full", style: { gap: "var(--spacing-3xl)" }, children: [
|
|
11024
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
11025
|
+
LanguageDropdown,
|
|
11026
|
+
{
|
|
11027
|
+
value: selectedLanguage,
|
|
11028
|
+
onChange: setSelectedLanguage,
|
|
11029
|
+
disabled: disableAllActions
|
|
11030
|
+
}
|
|
11031
|
+
) }),
|
|
11032
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex-1 min-w-0" })
|
|
11033
|
+
] }),
|
|
10873
11034
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "w-full", style: { overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
10874
11035
|
import_ui12.ScTextField,
|
|
10875
11036
|
{
|
package/dist/index.mjs
CHANGED
|
@@ -58,6 +58,27 @@ var SiconKey = ({ color = "currentColor", strokeWidth = 1.25, size = 24, ...prop
|
|
|
58
58
|
};
|
|
59
59
|
var SiconKey_default = SiconKey;
|
|
60
60
|
|
|
61
|
+
// src/languages.ts
|
|
62
|
+
var USER_LANGUAGES = [
|
|
63
|
+
{ code: "en", label: "English" },
|
|
64
|
+
{ code: "es", label: "Spanish" },
|
|
65
|
+
{ code: "fr", label: "French" },
|
|
66
|
+
{ code: "pt", label: "Portuguese" },
|
|
67
|
+
{ code: "hi", label: "Hindi" },
|
|
68
|
+
{ code: "kn", label: "Kannada" },
|
|
69
|
+
{ code: "te", label: "Telugu" },
|
|
70
|
+
{ code: "ta", label: "Tamil" },
|
|
71
|
+
{ code: "mr", label: "Marathi" },
|
|
72
|
+
{ code: "gu", label: "Gujarati" },
|
|
73
|
+
{ code: "bn", label: "Bengali" },
|
|
74
|
+
{ code: "ar", label: "Arabic" }
|
|
75
|
+
];
|
|
76
|
+
var DEFAULT_USER_LANGUAGE = "en";
|
|
77
|
+
function userLanguageLabel(code) {
|
|
78
|
+
const resolved = (code || "").trim() || DEFAULT_USER_LANGUAGE;
|
|
79
|
+
return USER_LANGUAGES.find((lang) => lang.code === resolved)?.label ?? resolved;
|
|
80
|
+
}
|
|
81
|
+
|
|
61
82
|
// src/workspace-modal.tsx
|
|
62
83
|
import { useState, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
63
84
|
|
|
@@ -2118,7 +2139,7 @@ function OrganizationAffiliationCard({
|
|
|
2118
2139
|
"Failed to change visibility"
|
|
2119
2140
|
);
|
|
2120
2141
|
},
|
|
2121
|
-
children: opt === "private" ? "Only
|
|
2142
|
+
children: opt === "private" ? "Only workspace members" : "Everyone in the organization"
|
|
2122
2143
|
},
|
|
2123
2144
|
opt
|
|
2124
2145
|
);
|
|
@@ -10322,25 +10343,25 @@ function SettingsNavGroupHeader({
|
|
|
10322
10343
|
return /* @__PURE__ */ jsxs18(
|
|
10323
10344
|
"div",
|
|
10324
10345
|
{
|
|
10325
|
-
className: "flex
|
|
10326
|
-
style: { gap:
|
|
10346
|
+
className: "flex flex-col w-full min-w-0",
|
|
10347
|
+
style: { gap: 2, padding: "2px var(--spacing-xl) var(--spacing-sm)" },
|
|
10327
10348
|
children: [
|
|
10328
|
-
/* @__PURE__ */ jsx20(
|
|
10329
|
-
|
|
10330
|
-
|
|
10331
|
-
|
|
10332
|
-
|
|
10333
|
-
|
|
10334
|
-
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
|
|
10341
|
-
|
|
10342
|
-
|
|
10343
|
-
),
|
|
10349
|
+
/* @__PURE__ */ jsx20(
|
|
10350
|
+
"span",
|
|
10351
|
+
{
|
|
10352
|
+
style: {
|
|
10353
|
+
fontFamily: "var(--font-family-font-family-body)",
|
|
10354
|
+
fontSize: "var(--font-size-font-size-xxs, 10px)",
|
|
10355
|
+
fontWeight: 500,
|
|
10356
|
+
letterSpacing: "0.08em",
|
|
10357
|
+
textTransform: "uppercase",
|
|
10358
|
+
color: MUTED_COLOR2
|
|
10359
|
+
},
|
|
10360
|
+
children: eyebrow
|
|
10361
|
+
}
|
|
10362
|
+
),
|
|
10363
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-center min-w-0", style: { gap: "var(--spacing-md)" }, children: [
|
|
10364
|
+
/* @__PURE__ */ jsx20("span", { className: "shrink-0 flex items-center", children: icon }),
|
|
10344
10365
|
/* @__PURE__ */ jsx20(
|
|
10345
10366
|
"span",
|
|
10346
10367
|
{
|
|
@@ -10382,26 +10403,26 @@ function SettingsNav({
|
|
|
10382
10403
|
return /* @__PURE__ */ jsxs18(
|
|
10383
10404
|
"div",
|
|
10384
10405
|
{
|
|
10385
|
-
className: "flex flex-col items-start shrink-0 relative",
|
|
10406
|
+
className: "flex flex-col items-start shrink-0 relative overflow-y-auto",
|
|
10386
10407
|
style: {
|
|
10387
10408
|
backgroundColor: "var(--alias-surface-base)",
|
|
10388
10409
|
borderRadius: "var(--radius-3xl)",
|
|
10389
10410
|
padding: "var(--spacing-md)",
|
|
10390
10411
|
width: 216,
|
|
10391
|
-
|
|
10412
|
+
maxHeight: "100%",
|
|
10413
|
+
/* A REAL BORDER, not the absolutely-positioned overlay that used to
|
|
10414
|
+
* sit inside this box. Now that the nav scrolls, an `absolute inset-0`
|
|
10415
|
+
* child is positioned against the scrolled CONTENT, so the outline
|
|
10416
|
+
* would slide up out of view and leave the card unbounded. `border`
|
|
10417
|
+
* belongs to the box itself and cannot drift; `box-sizing: border-box`
|
|
10418
|
+
* keeps the 216px width. */
|
|
10419
|
+
border: "1px solid var(--alias-border-subtle)",
|
|
10420
|
+
/* Was `--spacing-xl` (12). The groups and the rules between them sat
|
|
10421
|
+
* closer to each other than the rows inside a group did to their own
|
|
10422
|
+
* heading, so the divisions read as weaker than what they divided. */
|
|
10423
|
+
gap: "var(--spacing-5xl)"
|
|
10392
10424
|
},
|
|
10393
10425
|
children: [
|
|
10394
|
-
/* @__PURE__ */ jsx20(
|
|
10395
|
-
"div",
|
|
10396
|
-
{
|
|
10397
|
-
"aria-hidden": "true",
|
|
10398
|
-
className: "absolute inset-0 pointer-events-none",
|
|
10399
|
-
style: {
|
|
10400
|
-
border: "1px solid var(--alias-border-subtle)",
|
|
10401
|
-
borderRadius: "var(--radius-3xl)"
|
|
10402
|
-
}
|
|
10403
|
-
}
|
|
10404
|
-
),
|
|
10405
10426
|
/* @__PURE__ */ jsx20("div", { className: "flex flex-col w-full", style: { gap: "var(--spacing-md)" }, children: item("profile", (color) => /* @__PURE__ */ jsx20(SiconUser, { className: "w-6 h-6", color })) }),
|
|
10406
10427
|
/* @__PURE__ */ jsx20(ScHDivider, {}),
|
|
10407
10428
|
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col w-full", style: { gap: "var(--spacing-md)" }, children: [
|
|
@@ -10630,13 +10651,134 @@ function SpecializationDropdown({
|
|
|
10630
10651
|
}
|
|
10631
10652
|
);
|
|
10632
10653
|
}
|
|
10654
|
+
function LanguageDropdown({
|
|
10655
|
+
value,
|
|
10656
|
+
onChange,
|
|
10657
|
+
disabled
|
|
10658
|
+
}) {
|
|
10659
|
+
const [open, setOpen] = useState14(false);
|
|
10660
|
+
const containerRef = useRef7(null);
|
|
10661
|
+
useEffect12(() => {
|
|
10662
|
+
if (!open) return;
|
|
10663
|
+
function handleMouseDown(e) {
|
|
10664
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
10665
|
+
setOpen(false);
|
|
10666
|
+
}
|
|
10667
|
+
}
|
|
10668
|
+
function handleKeyDown(e) {
|
|
10669
|
+
if (e.key === "Escape") setOpen(false);
|
|
10670
|
+
}
|
|
10671
|
+
document.addEventListener("mousedown", handleMouseDown);
|
|
10672
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
10673
|
+
return () => {
|
|
10674
|
+
document.removeEventListener("mousedown", handleMouseDown);
|
|
10675
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
10676
|
+
};
|
|
10677
|
+
}, [open]);
|
|
10678
|
+
return /* @__PURE__ */ jsxs18(
|
|
10679
|
+
"div",
|
|
10680
|
+
{
|
|
10681
|
+
ref: containerRef,
|
|
10682
|
+
className: "w-full",
|
|
10683
|
+
style: { position: "relative" },
|
|
10684
|
+
children: [
|
|
10685
|
+
/* @__PURE__ */ jsx20("style", { children: DROPDOWN_TRIGGER_STYLES }),
|
|
10686
|
+
/* @__PURE__ */ jsx20(
|
|
10687
|
+
"div",
|
|
10688
|
+
{
|
|
10689
|
+
className: "spec-dropdown-trigger",
|
|
10690
|
+
"data-disabled": disabled ? "true" : "false",
|
|
10691
|
+
onClick: () => !disabled && setOpen((v) => !v),
|
|
10692
|
+
"aria-haspopup": "listbox",
|
|
10693
|
+
"aria-expanded": open,
|
|
10694
|
+
children: /* @__PURE__ */ jsx20(
|
|
10695
|
+
ScTextField,
|
|
10696
|
+
{
|
|
10697
|
+
label: "Language",
|
|
10698
|
+
labelGroup: "label",
|
|
10699
|
+
value: userLanguageLabel(value),
|
|
10700
|
+
placeholderFilled: "Select language",
|
|
10701
|
+
tfGroup: "icon-right",
|
|
10702
|
+
tfRightIcon: /* @__PURE__ */ jsx20(
|
|
10703
|
+
"span",
|
|
10704
|
+
{
|
|
10705
|
+
style: {
|
|
10706
|
+
display: "flex",
|
|
10707
|
+
alignItems: "center",
|
|
10708
|
+
justifyContent: "center",
|
|
10709
|
+
transform: open ? "rotate(180deg)" : "none",
|
|
10710
|
+
transition: "transform 120ms ease-out"
|
|
10711
|
+
},
|
|
10712
|
+
children: /* @__PURE__ */ jsx20(SiconDown, {})
|
|
10713
|
+
}
|
|
10714
|
+
),
|
|
10715
|
+
className: "sc-text-field-full-width",
|
|
10716
|
+
style: { width: "100%" },
|
|
10717
|
+
readOnly: true,
|
|
10718
|
+
disabled
|
|
10719
|
+
}
|
|
10720
|
+
)
|
|
10721
|
+
}
|
|
10722
|
+
),
|
|
10723
|
+
open && /* @__PURE__ */ jsx20(
|
|
10724
|
+
"div",
|
|
10725
|
+
{
|
|
10726
|
+
role: "listbox",
|
|
10727
|
+
style: {
|
|
10728
|
+
position: "absolute",
|
|
10729
|
+
top: "calc(100% + 4px)",
|
|
10730
|
+
left: 0,
|
|
10731
|
+
right: 0,
|
|
10732
|
+
zIndex: 50,
|
|
10733
|
+
// The list is longer than the specialization one, so it scrolls
|
|
10734
|
+
// rather than running off the bottom of the panel.
|
|
10735
|
+
maxHeight: 280,
|
|
10736
|
+
overflowY: "auto",
|
|
10737
|
+
background: "var(--alias-surface-subtle, #1a1a1a)",
|
|
10738
|
+
border: "0.5px solid var(--alias-border-subtle, #242424)",
|
|
10739
|
+
borderRadius: "var(--radius-4xl, 18px)",
|
|
10740
|
+
padding: "var(--spacing-md, 8px)",
|
|
10741
|
+
display: "flex",
|
|
10742
|
+
flexDirection: "column",
|
|
10743
|
+
gap: 8,
|
|
10744
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.4)",
|
|
10745
|
+
backdropFilter: "blur(42px)"
|
|
10746
|
+
},
|
|
10747
|
+
children: USER_LANGUAGES.map((lang) => {
|
|
10748
|
+
const isActive = lang.code === value;
|
|
10749
|
+
return /* @__PURE__ */ jsx20(
|
|
10750
|
+
ScMenuOptions,
|
|
10751
|
+
{
|
|
10752
|
+
text: lang.label,
|
|
10753
|
+
icon: /* @__PURE__ */ jsx20(Fragment12, {}),
|
|
10754
|
+
hover: isActive ? "true" : "false",
|
|
10755
|
+
variant: "default",
|
|
10756
|
+
role: "option",
|
|
10757
|
+
"aria-selected": isActive,
|
|
10758
|
+
onClick: () => {
|
|
10759
|
+
onChange(lang.code);
|
|
10760
|
+
setOpen(false);
|
|
10761
|
+
},
|
|
10762
|
+
style: { width: "100%", cursor: "pointer" }
|
|
10763
|
+
},
|
|
10764
|
+
lang.code
|
|
10765
|
+
);
|
|
10766
|
+
})
|
|
10767
|
+
}
|
|
10768
|
+
)
|
|
10769
|
+
]
|
|
10770
|
+
}
|
|
10771
|
+
);
|
|
10772
|
+
}
|
|
10633
10773
|
function ProfileTab() {
|
|
10634
10774
|
const { auth, imageUpload, toast } = useSettingsAdapters();
|
|
10635
10775
|
const user = auth.user;
|
|
10636
10776
|
const derivedName = user?.name ?? "";
|
|
10637
10777
|
const derivedSpec = user?.userSpecialization ?? "";
|
|
10778
|
+
const derivedLanguage = user?.language?.trim() || DEFAULT_USER_LANGUAGE;
|
|
10638
10779
|
const [fullName, setFullName] = useState14(derivedName);
|
|
10639
10780
|
const [selectedSpec, setSelectedSpec] = useState14(derivedSpec);
|
|
10781
|
+
const [selectedLanguage, setSelectedLanguage] = useState14(derivedLanguage);
|
|
10640
10782
|
const [saving, setSaving] = useState14(false);
|
|
10641
10783
|
const [imageSaving, setImageSaving] = useState14(false);
|
|
10642
10784
|
const [imagePreview, setImagePreview] = useState14(
|
|
@@ -10647,7 +10789,7 @@ function ProfileTab() {
|
|
|
10647
10789
|
const profileImage = imagePreview ?? getUserProfileImage(user);
|
|
10648
10790
|
const profileInitial = profileDisplayName.charAt(0).toUpperCase();
|
|
10649
10791
|
const disableAllActions = saving || imageSaving;
|
|
10650
|
-
const dirty = fullName.trim() !== derivedName || selectedSpec !== derivedSpec;
|
|
10792
|
+
const dirty = fullName.trim() !== derivedName || selectedSpec !== derivedSpec || selectedLanguage !== derivedLanguage;
|
|
10651
10793
|
useEffect12(() => {
|
|
10652
10794
|
setFullName(derivedName);
|
|
10653
10795
|
setImagePreview(void 0);
|
|
@@ -10655,6 +10797,9 @@ function ProfileTab() {
|
|
|
10655
10797
|
useEffect12(() => {
|
|
10656
10798
|
setSelectedSpec(derivedSpec);
|
|
10657
10799
|
}, [derivedSpec]);
|
|
10800
|
+
useEffect12(() => {
|
|
10801
|
+
setSelectedLanguage(derivedLanguage);
|
|
10802
|
+
}, [derivedLanguage]);
|
|
10658
10803
|
const handleSave = async () => {
|
|
10659
10804
|
if (disableAllActions || !dirty) return;
|
|
10660
10805
|
setSaving(true);
|
|
@@ -10662,6 +10807,8 @@ function ProfileTab() {
|
|
|
10662
10807
|
const patch = {};
|
|
10663
10808
|
if (fullName.trim() !== derivedName) patch.name = fullName.trim();
|
|
10664
10809
|
if (selectedSpec !== derivedSpec) patch.userSpecialization = selectedSpec;
|
|
10810
|
+
if (selectedLanguage !== derivedLanguage)
|
|
10811
|
+
patch.language = selectedLanguage;
|
|
10665
10812
|
await auth.updateProfile(patch);
|
|
10666
10813
|
await auth.refreshProfile();
|
|
10667
10814
|
toast.success("Profile updated");
|
|
@@ -10881,6 +11028,17 @@ function ProfileTab() {
|
|
|
10881
11028
|
}
|
|
10882
11029
|
) })
|
|
10883
11030
|
] }),
|
|
11031
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-start w-full", style: { gap: "var(--spacing-3xl)" }, children: [
|
|
11032
|
+
/* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx20(
|
|
11033
|
+
LanguageDropdown,
|
|
11034
|
+
{
|
|
11035
|
+
value: selectedLanguage,
|
|
11036
|
+
onChange: setSelectedLanguage,
|
|
11037
|
+
disabled: disableAllActions
|
|
11038
|
+
}
|
|
11039
|
+
) }),
|
|
11040
|
+
/* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0" })
|
|
11041
|
+
] }),
|
|
10884
11042
|
/* @__PURE__ */ jsx20("div", { className: "w-full", style: { overflow: "hidden" }, children: /* @__PURE__ */ jsx20(
|
|
10885
11043
|
ScTextField,
|
|
10886
11044
|
{
|
|
@@ -11983,6 +12141,7 @@ export {
|
|
|
11983
12141
|
ConfirmDeleteModal,
|
|
11984
12142
|
ConfirmLeaveModal,
|
|
11985
12143
|
DEFAULT_PERMISSIONS,
|
|
12144
|
+
DEFAULT_USER_LANGUAGE,
|
|
11986
12145
|
ExportDateModal,
|
|
11987
12146
|
InviteUpdateModal,
|
|
11988
12147
|
MemberListFrame,
|
|
@@ -12007,11 +12166,13 @@ export {
|
|
|
12007
12166
|
TeamsContent,
|
|
12008
12167
|
TokensContent,
|
|
12009
12168
|
URL_TO_TAB,
|
|
12169
|
+
USER_LANGUAGES,
|
|
12010
12170
|
WorkspaceGeneralTab,
|
|
12011
12171
|
WorkspaceListTab,
|
|
12012
12172
|
WorkspaceModal,
|
|
12013
12173
|
WorkspaceTab,
|
|
12014
12174
|
countLabel,
|
|
12015
12175
|
resolveSettingsTabFromPath,
|
|
12016
|
-
useSettingsAdapters
|
|
12176
|
+
useSettingsAdapters,
|
|
12177
|
+
userLanguageLabel
|
|
12017
12178
|
};
|