feat(settings): gear opens a multi-tab settings window with account management

Replace the gear dropdown with a single tabbed window: Audio / Chat / Altre /
Account. Audio/Chat/Altre reuse the existing volume + preference controls;
Account recovers UserAccountSettingsView (now embeddable via an 'embedded' prop
that renders its body without its own card). Removes the dropdown menu + dead css.
This commit is contained in:
simoleo89
2026-06-15 20:01:17 +02:00
parent c2be4dbed3
commit 63b92a4e65
4 changed files with 108 additions and 169 deletions
+2 -17
View File
@@ -1,5 +1,5 @@
import { CreateLinkEvent } from '@nitrots/nitro-renderer'; 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 { FaChartBar, FaCog, FaSignOutAlt } from 'react-icons/fa';
import { ClearRememberLogin, GetConfigurationValue, GetRememberLogin, LocalizeText } from '../../api'; import { ClearRememberLogin, GetConfigurationValue, GetRememberLogin, LocalizeText } from '../../api';
import { Column, LayoutCurrencyIcon } from '../../common'; import { Column, LayoutCurrencyIcon } from '../../common';
@@ -16,13 +16,6 @@ const localizeWithFallback = (key: string, fallback: string) =>
export const PurseView: FC<{}> = props => export const PurseView: FC<{}> = props =>
{ {
const { purse = null, hcDisabled = false } = usePurse(); 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<number[]>('system.currency.types', []), []); const displayedCurrencies = useMemo(() => GetConfigurationValue<number[]>('system.currency.types', []), []);
const currencyDisplayNumberShort = useMemo(() => GetConfigurationValue<boolean>('currency.display.number.short', false), []); const currencyDisplayNumberShort = useMemo(() => GetConfigurationValue<boolean>('currency.display.number.short', false), []);
@@ -130,21 +123,13 @@ export const PurseView: FC<{}> = props =>
</button> </button>
<button type="button" className="nitro-purse__btn nitro-purse__btn--icon nitro-purse__btn--settings" onClick={ event => <button type="button" className="nitro-purse__btn nitro-purse__btn--icon nitro-purse__btn--settings" onClick={ event =>
{ {
event.stopPropagation(); setSettingsMenuOpen(value => !value); event.stopPropagation(); CreateLinkEvent('user-settings/toggle');
} } title={ LocalizeText('widget.memenu.settings.title') }> } } title={ LocalizeText('widget.memenu.settings.title') }>
<FaCog /> <FaCog />
</button> </button>
</div> </div>
</div> </div>
</div> </div>
{ settingsMenuOpen &&
<div className="nitro-purse-menu">
<button type="button" className="nitro-purse-menu__item" onClick={ () => openSettingsSection('audio') }>Impostazioni Audio</button>
<button type="button" className="nitro-purse-menu__item nitro-purse-menu__item--disabled" disabled>Impostazioni Discord</button>
<button type="button" className="nitro-purse-menu__item" onClick={ () => openSettingsSection('chat') }>Impostazioni Chat</button>
<button type="button" className="nitro-purse-menu__item" onClick={ () => openSettingsSection('other') }>Altre Impostazioni</button>
<button type="button" className="nitro-purse-menu__item nitro-purse-menu__item--disabled" disabled>Filtro Parole</button>
</div> }
{ otherCurrencies.length > 0 && { otherCurrencies.length > 0 &&
<div className="nitro-purse__other"> <div className="nitro-purse__other">
{ otherCurrencies.map(type => <SeasonalView key={ type } type={ type } amount={ purse.activityPoints.get(type) || 0 } />) } { otherCurrencies.map(type => <SeasonalView key={ type } type={ type } amount={ purse.activityPoints.get(type) || 0 } />) }
@@ -34,7 +34,7 @@ const passwordStrength = (value: string): { score: number; labelKey: string; col
return { score: 4, labelKey: 'usersettings.strength.strong', color: 'bg-[#00800b]' }; 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 [ isVisible, setIsVisible ] = useState(false);
const [ section, setSection ] = useState<Section>('menu'); const [ section, setSection ] = useState<Section>('menu');
@@ -390,12 +390,10 @@ export const UserAccountSettingsView: FC<{}> = () =>
} }
}; };
if(!isVisible) return null; if(!embedded && !isVisible) return null;
return (
<NitroCardView className="user-account-settings-window w-[360px]" theme="primary-slim" uniqueKey="user-account-settings">
<NitroCardHeaderView headerText={ LocalizeText('usersettings.title') } onCloseClick={ close } />
const accountBody = (
<>
<div className="relative flex items-center gap-3 px-3 py-2 bg-[linear-gradient(180deg,#2e8fb8_0%,#1e7295_100%)] text-white"> <div className="relative flex items-center gap-3 px-3 py-2 bg-[linear-gradient(180deg,#2e8fb8_0%,#1e7295_100%)] text-white">
<div className="absolute inset-0 opacity-20 pointer-events-none [background-image:radial-gradient(rgba(255,255,255,0.5)_1px,transparent_1px)] [background-size:6px_6px]" /> <div className="absolute inset-0 opacity-20 pointer-events-none [background-image:radial-gradient(rgba(255,255,255,0.5)_1px,transparent_1px)] [background-size:6px_6px]" />
{ session.figure && ( { session.figure && (
@@ -753,6 +751,15 @@ export const UserAccountSettingsView: FC<{}> = () =>
</div> </div>
) } ) }
</NitroCardContentView> </NitroCardContentView>
</>
);
if(embedded) return accountBody;
return (
<NitroCardView className="user-account-settings-window w-[360px]" theme="primary-slim" uniqueKey="user-account-settings">
<NitroCardHeaderView headerText={ LocalizeText('usersettings.title') } onCloseClick={ close } />
{ accountBody }
</NitroCardView> </NitroCardView>
); );
}; };
+93 -107
View File
@@ -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 { 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 { 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 { useCatalogPlaceMultipleItems, useCatalogSkipPurchaseConfirmation, useChatWindow, useMessageEvent } from '../../hooks';
import { classNames } from '../../layout'; import { classNames } from '../../layout';
import { UserAccountSettingsView } from './UserAccountSettingsView';
const localizeWithFallback = (key: string, fallback: string) => const localizeWithFallback = (key: string, fallback: string) =>
{ {
@@ -12,14 +13,12 @@ const localizeWithFallback = (key: string, fallback: string) =>
return (text && text !== key) ? text : fallback; return (text && text !== key) ? text : fallback;
}; };
// null = full window (legacy). 'audio' | 'chat' | 'other' = focused section type SettingsTab = 'audio' | 'chat' | 'other' | 'account';
// opened from the purse gear dropdown.
type SettingsSection = null | 'audio' | 'chat' | 'other';
export const UserSettingsView: FC<{}> = props => export const UserSettingsView: FC<{}> = props =>
{ {
const [ isVisible, setIsVisible ] = useState(false); const [ isVisible, setIsVisible ] = useState(false);
const [ section, setSection ] = useState<SettingsSection>(null); const [ activeTab, setActiveTab ] = useState<SettingsTab>('audio');
const [ userSettings, setUserSettings ] = useState<NitroSettingsEvent>(null); const [ userSettings, setUserSettings ] = useState<NitroSettingsEvent>(null);
const [ catalogPlaceMultipleObjects, setCatalogPlaceMultipleObjects ] = useCatalogPlaceMultipleItems(); const [ catalogPlaceMultipleObjects, setCatalogPlaceMultipleObjects ] = useCatalogPlaceMultipleItems();
const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useCatalogSkipPurchaseConfirmation(); const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useCatalogSkipPurchaseConfirmation();
@@ -108,17 +107,19 @@ export const UserSettingsView: FC<{}> = props =>
if(parts.length < 2) return; if(parts.length < 2) return;
const tab = parts[2] as SettingsTab;
switch(parts[1]) switch(parts[1])
{ {
case 'show': case 'show':
setSection((parts[2] as SettingsSection) || null); if(tab) setActiveTab(tab);
setIsVisible(true); setIsVisible(true);
return; return;
case 'hide': case 'hide':
setIsVisible(false); setIsVisible(false);
return; return;
case 'toggle': case 'toggle':
setSection((parts[2] as SettingsSection) || null); if(tab) setActiveTab(tab);
setIsVisible(prevValue => !prevValue); setIsVisible(prevValue => !prevValue);
return; return;
} }
@@ -140,105 +141,90 @@ export const UserSettingsView: FC<{}> = props =>
if(!isVisible || !userSettings) return null; 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 ( return (
<NitroCardView className="user-settings-window" theme="primary-slim" uniqueKey="user-settings"> <NitroCardView className="user-settings-window w-[360px]" theme="primary-slim" uniqueKey="user-settings">
<NitroCardHeaderView headerText={ headerText } onCloseClick={ event => processAction('close_view') } /> <NitroCardHeaderView headerText={ LocalizeText('widget.memenu.settings.title') } onCloseClick={ event => processAction('close_view') } />
<NitroCardContentView className="text-black"> <NitroCardTabsView>
{ showChat && <NitroCardTabsItemView isActive={ activeTab === 'audio' } onClick={ () => setActiveTab('audio') }>
<div className="flex flex-col gap-1"> { localizeWithFallback('widget.memenu.settings.volume', 'Audio') }
<div className="flex items-center gap-1"> </NitroCardTabsItemView>
<input checked={ userSettings.oldChat } className="form-check-input" type="checkbox" onChange={ event => processAction('oldchat', event.target.checked) } /> <NitroCardTabsItemView isActive={ activeTab === 'chat' } onClick={ () => setActiveTab('chat') }>
<Text>{ LocalizeText('memenu.settings.chat.prefer.old.chat') }</Text> { localizeWithFallback('room.chat.settings.title', 'Chat') }
</div> </NitroCardTabsItemView>
<div className="flex items-center gap-1"> <NitroCardTabsItemView isActive={ activeTab === 'other' } onClick={ () => setActiveTab('other') }>
<input checked={ chatWindowEnabled } className="form-check-input" type="checkbox" onChange={ event => setChatWindowEnabled(event.target.checked) } /> { localizeWithFallback('memenu.settings.other', 'Altre') }
<Text>{ LocalizeText('memenu.settings.other.enable.chat.window') }</Text> </NitroCardTabsItemView>
</div> <NitroCardTabsItemView isActive={ activeTab === 'account' } onClick={ () => setActiveTab('account') }>
</div> } { localizeWithFallback('usersettings.account.label', 'Account') }
{ showOther && </NitroCardTabsItemView>
<div className="flex flex-col gap-1"> </NitroCardTabsView>
<div className="flex items-center gap-1"> { (activeTab === 'account')
<input checked={ userSettings.roomInvites } className="form-check-input" type="checkbox" onChange={ event => processAction('room_invites', event.target.checked) } /> ? <UserAccountSettingsView embedded />
<Text>{ LocalizeText('memenu.settings.other.ignore.room.invites') }</Text> : (
</div> <NitroCardContentView className="text-black">
<div className="flex items-center gap-1"> { (activeTab === 'chat') &&
<input checked={ userSettings.cameraFollow } className="form-check-input" type="checkbox" onChange={ event => processAction('camera_follow', event.target.checked) } /> <div className="flex flex-col gap-1">
<Text>{ LocalizeText('memenu.settings.other.disable.room.camera.follow') }</Text> <div className="flex items-center gap-1">
</div> <input checked={ userSettings.oldChat } className="form-check-input" type="checkbox" onChange={ event => processAction('oldchat', event.target.checked) } />
<div className="flex items-center gap-1"> <Text>{ LocalizeText('memenu.settings.chat.prefer.old.chat') }</Text>
<input checked={ catalogPlaceMultipleObjects } className="form-check-input" type="checkbox" onChange={ event => setCatalogPlaceMultipleObjects(event.target.checked) } /> </div>
<Text>{ LocalizeText('memenu.settings.other.place.multiple.objects') }</Text> <div className="flex items-center gap-1">
</div> <input checked={ chatWindowEnabled } className="form-check-input" type="checkbox" onChange={ event => setChatWindowEnabled(event.target.checked) } />
<div className="flex items-center gap-1"> <Text>{ LocalizeText('memenu.settings.other.enable.chat.window') }</Text>
<input checked={ catalogSkipPurchaseConfirmation } className="form-check-input" type="checkbox" onChange={ event => setCatalogSkipPurchaseConfirmation(event.target.checked) } /> </div>
<Text>{ LocalizeText('memenu.settings.other.skip.purchase.confirmation') }</Text> </div> }
</div> { (activeTab === 'other') &&
</div> } <div className="flex flex-col gap-1">
{ showAudio && <div className="flex items-center gap-1">
<div className="flex flex-col"> <input checked={ userSettings.roomInvites } className="form-check-input" type="checkbox" onChange={ event => processAction('room_invites', event.target.checked) } />
<Text bold>{ LocalizeText('widget.memenu.settings.volume') }</Text> <Text>{ LocalizeText('memenu.settings.other.ignore.room.invites') }</Text>
<div className="flex flex-col gap-1"> </div>
<Text>{ LocalizeText('widget.memenu.settings.volume.ui') }</Text> <div className="flex items-center gap-1">
<div className="flex items-center gap-1"> <input checked={ userSettings.cameraFollow } className="form-check-input" type="checkbox" onChange={ event => processAction('camera_follow', event.target.checked) } />
{ (userSettings.volumeSystem === 0) && <FaVolumeMute className={ classNames((userSettings.volumeSystem >= 50) && 'text-muted', 'fa-icon') } /> } <Text>{ LocalizeText('memenu.settings.other.disable.room.camera.follow') }</Text>
{ (userSettings.volumeSystem > 0) && <FaVolumeDown className={ classNames((userSettings.volumeSystem >= 50) && 'text-muted', 'fa-icon') } /> } </div>
<input className="custom-range w-full" id="volumeSystem" max="100" min="0" step="1" type="range" value={ userSettings.volumeSystem } onChange={ event => processAction('system_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } /> <div className="flex items-center gap-1">
<FaVolumeUp className={ classNames((userSettings.volumeSystem < 50) && 'text-muted', 'fa-icon') } /> <input checked={ catalogPlaceMultipleObjects } className="form-check-input" type="checkbox" onChange={ event => setCatalogPlaceMultipleObjects(event.target.checked) } />
</div> <Text>{ LocalizeText('memenu.settings.other.place.multiple.objects') }</Text>
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex items-center gap-1">
<Text>{ LocalizeText('widget.memenu.settings.volume.furni') }</Text> <input checked={ catalogSkipPurchaseConfirmation } className="form-check-input" type="checkbox" onChange={ event => setCatalogSkipPurchaseConfirmation(event.target.checked) } />
<div className="flex items-center gap-1"> <Text>{ LocalizeText('memenu.settings.other.skip.purchase.confirmation') }</Text>
{ (userSettings.volumeFurni === 0) && <FaVolumeMute className={ classNames((userSettings.volumeFurni >= 50) && 'text-muted', 'fa-icon') } /> } </div>
{ (userSettings.volumeFurni > 0) && <FaVolumeDown className={ classNames((userSettings.volumeFurni >= 50) && 'text-muted', 'fa-icon') } /> } </div> }
<input className="custom-range w-full" id="volumeFurni" max="100" min="0" step="1" type="range" value={ userSettings.volumeFurni } onChange={ event => processAction('furni_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } /> { (activeTab === 'audio') &&
<FaVolumeUp className={ classNames((userSettings.volumeFurni < 50) && 'text-muted', 'fa-icon') } /> <div className="flex flex-col">
</div> <Text bold>{ LocalizeText('widget.memenu.settings.volume') }</Text>
</div> <div className="flex flex-col gap-1">
<div className="flex flex-col gap-1"> <Text>{ LocalizeText('widget.memenu.settings.volume.ui') }</Text>
<Text>{ LocalizeText('widget.memenu.settings.volume.trax') }</Text> <div className="flex items-center gap-1">
<div className="flex items-center gap-1"> { (userSettings.volumeSystem === 0) && <FaVolumeMute className={ classNames((userSettings.volumeSystem >= 50) && 'text-muted', 'fa-icon') } /> }
{ (userSettings.volumeTrax === 0) && <FaVolumeMute className={ classNames((userSettings.volumeTrax >= 50) && 'text-muted', 'fa-icon') } /> } { (userSettings.volumeSystem > 0) && <FaVolumeDown className={ classNames((userSettings.volumeSystem >= 50) && 'text-muted', 'fa-icon') } /> }
{ (userSettings.volumeTrax > 0) && <FaVolumeDown className={ classNames((userSettings.volumeTrax >= 50) && 'text-muted', 'fa-icon') } /> } <input className="custom-range w-full" id="volumeSystem" max="100" min="0" step="1" type="range" value={ userSettings.volumeSystem } onChange={ event => processAction('system_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } />
<input className="custom-range w-full" id="volumeTrax" max="100" min="0" step="1" type="range" value={ userSettings.volumeTrax } onChange={ event => processAction('trax_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } /> <FaVolumeUp className={ classNames((userSettings.volumeSystem < 50) && 'text-muted', 'fa-icon') } />
<FaVolumeUp className={ classNames((userSettings.volumeTrax < 50) && 'text-muted', 'fa-icon') } /> </div>
</div> </div>
</div> <div className="flex flex-col gap-1">
</div> } <Text>{ LocalizeText('widget.memenu.settings.volume.furni') }</Text>
{ showAccountLink && <div className="flex items-center gap-1">
<div className="flex flex-col pt-2 mt-1 border-t border-black/10"> { (userSettings.volumeFurni === 0) && <FaVolumeMute className={ classNames((userSettings.volumeFurni >= 50) && 'text-muted', 'fa-icon') } /> }
<button { (userSettings.volumeFurni > 0) && <FaVolumeDown className={ classNames((userSettings.volumeFurni >= 50) && 'text-muted', 'fa-icon') } /> }
type="button" <input className="custom-range w-full" id="volumeFurni" max="100" min="0" step="1" type="range" value={ userSettings.volumeFurni } onChange={ event => processAction('furni_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } />
onClick={ () => CreateLinkEvent('user-account-settings/show') } <FaVolumeUp className={ classNames((userSettings.volumeFurni < 50) && 'text-muted', 'fa-icon') } />
className="group flex items-center gap-2 rounded-md border border-black/10 bg-white px-2 py-1.5 hover:bg-[#f5fbfd] hover:border-[#1e7295] transition-colors cursor-pointer text-left"> </div>
<div className="flex items-center justify-center w-7 h-7 rounded-full bg-[#1e7295] text-white shadow-[inset_0_2px_#ffffff26,inset_0_-2px_#0000001a]"> </div>
<FaUserCog size={ 12 } /> <div className="flex flex-col gap-1">
</div> <Text>{ LocalizeText('widget.memenu.settings.volume.trax') }</Text>
<div className="flex flex-col flex-1 leading-tight"> <div className="flex items-center gap-1">
<Text bold>{ LocalizeText('usersettings.open.title') }</Text> { (userSettings.volumeTrax === 0) && <FaVolumeMute className={ classNames((userSettings.volumeTrax >= 50) && 'text-muted', 'fa-icon') } /> }
<Text small className="text-black/60">{ LocalizeText('usersettings.open.subtitle') }</Text> { (userSettings.volumeTrax > 0) && <FaVolumeDown className={ classNames((userSettings.volumeTrax >= 50) && 'text-muted', 'fa-icon') } /> }
</div> <input className="custom-range w-full" id="volumeTrax" max="100" min="0" step="1" type="range" value={ userSettings.volumeTrax } onChange={ event => processAction('trax_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') } />
<span className="text-black/30 group-hover:text-[#1e7295] text-[10px]"></span> <FaVolumeUp className={ classNames((userSettings.volumeTrax < 50) && 'text-muted', 'fa-icon') } />
</button> </div>
</div> } </div>
{ (section !== null) && </div> }
<div className="flex pt-2 mt-1 border-t border-black/10"> </NitroCardContentView>
<Button variant="secondary" onClick={ event => processAction('close_view') }>{ localizeWithFallback('generic.back', 'Indietro') }</Button> ) }
</div> }
</NitroCardContentView>
</NitroCardView> </NitroCardView>
); );
}; };
-39
View File
@@ -230,45 +230,6 @@
object-fit: contain; 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) { @media (max-width: 640px) {
.nitro-purse { .nitro-purse {
max-width: 100%; max-width: 100%;