diff --git a/src/components/purse/PurseView.tsx b/src/components/purse/PurseView.tsx index f673f1a..32d2fe8 100644 --- a/src/components/purse/PurseView.tsx +++ b/src/components/purse/PurseView.tsx @@ -1,5 +1,5 @@ import { CreateLinkEvent } from '@nitrots/nitro-renderer'; -import { FC, useCallback, useMemo, useState } from 'react'; +import { FC, useCallback, useMemo } from 'react'; import { FaChartBar, FaCog, FaSignOutAlt } from 'react-icons/fa'; import { ClearRememberLogin, GetConfigurationValue, GetRememberLogin, LocalizeText } from '../../api'; import { Column, LayoutCurrencyIcon } from '../../common'; @@ -16,13 +16,6 @@ const localizeWithFallback = (key: string, fallback: string) => export const PurseView: FC<{}> = props => { const { purse = null, hcDisabled = false } = usePurse(); - const [ settingsMenuOpen, setSettingsMenuOpen ] = useState(false); - - const openSettingsSection = useCallback((section: string) => - { - CreateLinkEvent('user-settings/show/' + section); - setSettingsMenuOpen(false); - }, []); const displayedCurrencies = useMemo(() => GetConfigurationValue('system.currency.types', []), []); const currencyDisplayNumberShort = useMemo(() => GetConfigurationValue('currency.display.number.short', false), []); @@ -130,21 +123,13 @@ export const PurseView: FC<{}> = props => - { settingsMenuOpen && -
- - - - - -
} { otherCurrencies.length > 0 &&
{ otherCurrencies.map(type => ) } diff --git a/src/components/user-settings/UserAccountSettingsView.tsx b/src/components/user-settings/UserAccountSettingsView.tsx index 68678ab..bcf3adb 100644 --- a/src/components/user-settings/UserAccountSettingsView.tsx +++ b/src/components/user-settings/UserAccountSettingsView.tsx @@ -34,7 +34,7 @@ const passwordStrength = (value: string): { score: number; labelKey: string; col return { score: 4, labelKey: 'usersettings.strength.strong', color: 'bg-[#00800b]' }; }; -export const UserAccountSettingsView: FC<{}> = () => +export const UserAccountSettingsView: FC<{ embedded?: boolean }> = ({ embedded = false }) => { const [ isVisible, setIsVisible ] = useState(false); const [ section, setSection ] = useState
('menu'); @@ -390,12 +390,10 @@ export const UserAccountSettingsView: FC<{}> = () => } }; - if(!isVisible) return null; - - return ( - - + if(!embedded && !isVisible) return null; + const accountBody = ( + <>
{ session.figure && ( @@ -753,6 +751,15 @@ export const UserAccountSettingsView: FC<{}> = () =>
) } + + ); + + if(embedded) return accountBody; + + return ( + + + { accountBody } ); }; diff --git a/src/components/user-settings/UserSettingsView.tsx b/src/components/user-settings/UserSettingsView.tsx index 7d4acf5..b8a55af 100644 --- a/src/components/user-settings/UserSettingsView.tsx +++ b/src/components/user-settings/UserSettingsView.tsx @@ -1,10 +1,11 @@ -import { AddLinkEventTracker, CreateLinkEvent, ILinkEventTracker, NitroSettingsEvent, RemoveLinkEventTracker, UserSettingsCameraFollowComposer, UserSettingsEvent, UserSettingsOldChatComposer, UserSettingsRoomInvitesComposer, UserSettingsSoundComposer } from '@nitrots/nitro-renderer'; +import { AddLinkEventTracker, ILinkEventTracker, NitroSettingsEvent, RemoveLinkEventTracker, UserSettingsCameraFollowComposer, UserSettingsEvent, UserSettingsOldChatComposer, UserSettingsRoomInvitesComposer, UserSettingsSoundComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; -import { FaUserCog, FaVolumeDown, FaVolumeMute, FaVolumeUp } from 'react-icons/fa'; +import { FaVolumeDown, FaVolumeMute, FaVolumeUp } from 'react-icons/fa'; import { DispatchMainEvent, DispatchUiEvent, LocalizeText, SendMessageComposer } from '../../api'; -import { Button, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView, Text } from '../../common'; import { useCatalogPlaceMultipleItems, useCatalogSkipPurchaseConfirmation, useChatWindow, useMessageEvent } from '../../hooks'; import { classNames } from '../../layout'; +import { UserAccountSettingsView } from './UserAccountSettingsView'; const localizeWithFallback = (key: string, fallback: string) => { @@ -12,14 +13,12 @@ const localizeWithFallback = (key: string, fallback: string) => return (text && text !== key) ? text : fallback; }; -// null = full window (legacy). 'audio' | 'chat' | 'other' = focused section -// opened from the purse gear dropdown. -type SettingsSection = null | 'audio' | 'chat' | 'other'; +type SettingsTab = 'audio' | 'chat' | 'other' | 'account'; export const UserSettingsView: FC<{}> = props => { const [ isVisible, setIsVisible ] = useState(false); - const [ section, setSection ] = useState(null); + const [ activeTab, setActiveTab ] = useState('audio'); const [ userSettings, setUserSettings ] = useState(null); const [ catalogPlaceMultipleObjects, setCatalogPlaceMultipleObjects ] = useCatalogPlaceMultipleItems(); const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useCatalogSkipPurchaseConfirmation(); @@ -108,17 +107,19 @@ export const UserSettingsView: FC<{}> = props => if(parts.length < 2) return; + const tab = parts[2] as SettingsTab; + switch(parts[1]) { case 'show': - setSection((parts[2] as SettingsSection) || null); + if(tab) setActiveTab(tab); setIsVisible(true); return; case 'hide': setIsVisible(false); return; case 'toggle': - setSection((parts[2] as SettingsSection) || null); + if(tab) setActiveTab(tab); setIsVisible(prevValue => !prevValue); return; } @@ -140,105 +141,90 @@ export const UserSettingsView: FC<{}> = props => if(!isVisible || !userSettings) return null; - const showChat = (section === null || section === 'chat'); - const showOther = (section === null || section === 'other'); - const showAudio = (section === null || section === 'audio'); - const showAccountLink = (section === null); - - const headerText = (section === 'audio') - ? localizeWithFallback('widget.memenu.settings.volume', 'Audio settings') - : (section === 'chat') - ? localizeWithFallback('room.chat.settings.title', 'Chat settings') - : (section === 'other') - ? localizeWithFallback('memenu.settings.other', 'Other settings') - : LocalizeText('widget.memenu.settings.title'); - return ( - - processAction('close_view') } /> - - { showChat && -
-
- processAction('oldchat', event.target.checked) } /> - { LocalizeText('memenu.settings.chat.prefer.old.chat') } -
-
- setChatWindowEnabled(event.target.checked) } /> - { LocalizeText('memenu.settings.other.enable.chat.window') } -
-
} - { showOther && -
-
- processAction('room_invites', event.target.checked) } /> - { LocalizeText('memenu.settings.other.ignore.room.invites') } -
-
- processAction('camera_follow', event.target.checked) } /> - { LocalizeText('memenu.settings.other.disable.room.camera.follow') } -
-
- setCatalogPlaceMultipleObjects(event.target.checked) } /> - { LocalizeText('memenu.settings.other.place.multiple.objects') } -
-
- setCatalogSkipPurchaseConfirmation(event.target.checked) } /> - { LocalizeText('memenu.settings.other.skip.purchase.confirmation') } -
-
} - { showAudio && -
- { LocalizeText('widget.memenu.settings.volume') } -
- { LocalizeText('widget.memenu.settings.volume.ui') } -
- { (userSettings.volumeSystem === 0) && = 50) && 'text-muted', 'fa-icon') } /> } - { (userSettings.volumeSystem > 0) && = 50) && 'text-muted', 'fa-icon') } /> } - processAction('system_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } /> - -
-
-
- { LocalizeText('widget.memenu.settings.volume.furni') } -
- { (userSettings.volumeFurni === 0) && = 50) && 'text-muted', 'fa-icon') } /> } - { (userSettings.volumeFurni > 0) && = 50) && 'text-muted', 'fa-icon') } /> } - processAction('furni_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } /> - -
-
-
- { LocalizeText('widget.memenu.settings.volume.trax') } -
- { (userSettings.volumeTrax === 0) && = 50) && 'text-muted', 'fa-icon') } /> } - { (userSettings.volumeTrax > 0) && = 50) && 'text-muted', 'fa-icon') } /> } - processAction('trax_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } /> - -
-
-
} - { showAccountLink && -
- -
} - { (section !== null) && -
- -
} -
+ + processAction('close_view') } /> + + setActiveTab('audio') }> + { localizeWithFallback('widget.memenu.settings.volume', 'Audio') } + + setActiveTab('chat') }> + { localizeWithFallback('room.chat.settings.title', 'Chat') } + + setActiveTab('other') }> + { localizeWithFallback('memenu.settings.other', 'Altre') } + + setActiveTab('account') }> + { localizeWithFallback('usersettings.account.label', 'Account') } + + + { (activeTab === 'account') + ? + : ( + + { (activeTab === 'chat') && +
+
+ processAction('oldchat', event.target.checked) } /> + { LocalizeText('memenu.settings.chat.prefer.old.chat') } +
+
+ setChatWindowEnabled(event.target.checked) } /> + { LocalizeText('memenu.settings.other.enable.chat.window') } +
+
} + { (activeTab === 'other') && +
+
+ processAction('room_invites', event.target.checked) } /> + { LocalizeText('memenu.settings.other.ignore.room.invites') } +
+
+ processAction('camera_follow', event.target.checked) } /> + { LocalizeText('memenu.settings.other.disable.room.camera.follow') } +
+
+ setCatalogPlaceMultipleObjects(event.target.checked) } /> + { LocalizeText('memenu.settings.other.place.multiple.objects') } +
+
+ setCatalogSkipPurchaseConfirmation(event.target.checked) } /> + { LocalizeText('memenu.settings.other.skip.purchase.confirmation') } +
+
} + { (activeTab === 'audio') && +
+ { LocalizeText('widget.memenu.settings.volume') } +
+ { LocalizeText('widget.memenu.settings.volume.ui') } +
+ { (userSettings.volumeSystem === 0) && = 50) && 'text-muted', 'fa-icon') } /> } + { (userSettings.volumeSystem > 0) && = 50) && 'text-muted', 'fa-icon') } /> } + processAction('system_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } /> + +
+
+
+ { LocalizeText('widget.memenu.settings.volume.furni') } +
+ { (userSettings.volumeFurni === 0) && = 50) && 'text-muted', 'fa-icon') } /> } + { (userSettings.volumeFurni > 0) && = 50) && 'text-muted', 'fa-icon') } /> } + processAction('furni_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } /> + +
+
+
+ { LocalizeText('widget.memenu.settings.volume.trax') } +
+ { (userSettings.volumeTrax === 0) && = 50) && 'text-muted', 'fa-icon') } /> } + { (userSettings.volumeTrax > 0) && = 50) && 'text-muted', 'fa-icon') } /> } + processAction('trax_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } /> + +
+
+
} +
+ ) }
); }; diff --git a/src/css/purse/PurseView.css b/src/css/purse/PurseView.css index f6a1294..b60fe8b 100644 --- a/src/css/purse/PurseView.css +++ b/src/css/purse/PurseView.css @@ -230,45 +230,6 @@ object-fit: contain; } -/* ---- Settings dropdown (gear menu) ---- */ -.nitro-purse-menu { - width: 100%; - max-width: 200px; - margin-top: 4px; - margin-left: auto; - display: flex; - flex-direction: column; - overflow: hidden; - border: 2px solid #41403c; - border-radius: 8px; - background: rgba(10, 10, 12, 0.92); - box-shadow: 0 8px 18px rgba(0, 0, 0, 0.3); - pointer-events: all; -} - -.nitro-purse-menu__item { - padding: 6px 10px; - text-align: left; - font-size: 0.78rem; - font-weight: 500; - color: rgba(255, 255, 255, 0.9); - background: transparent; - border: 0; - cursor: pointer; - transition: background 0.12s ease; -} - -.nitro-purse-menu__item:hover { - background: rgba(255, 255, 255, 0.08); -} - -.nitro-purse-menu__item--disabled, -.nitro-purse-menu__item--disabled:hover { - color: rgba(255, 255, 255, 0.35); - background: transparent; - cursor: default; -} - @media (max-width: 640px) { .nitro-purse { max-width: 100%;