From 3e92e718e5ee1e5856943c5e66ef1c8bb668dcb1 Mon Sep 17 00:00:00 2001 From: duckietm Date: Tue, 9 Jun 2026 07:11:28 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=86=99=20Fix=20avatar=20head=20in=20f?= =?UTF-8?q?riends=20chat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/friends/FriendsView.css | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/css/friends/FriendsView.css b/src/css/friends/FriendsView.css index 7f1404a..ff13749 100644 --- a/src/css/friends/FriendsView.css +++ b/src/css/friends/FriendsView.css @@ -637,19 +637,19 @@ & .message-avatar { position: relative; flex-shrink: 0; - overflow: visible; + overflow: hidden; width: 36px; height: 36px; & .avatar-image { - position: absolute; - left: 50%; - top: 56%; - width: 54px; - height: 54px; + position: absolute; + inset: 0; + width: 100%; + height: 100%; margin: 0; - background-position: center center !important; - transform: translate(-50%, -50%) scale(.95); + background-size: 74px auto !important; + background-position: -18px -24px !important; + transform: none; } } From 3ea6ec70a4f29d30d6e96e99aed5e1c7fc9629ed Mon Sep 17 00:00:00 2001 From: duckietm Date: Tue, 9 Jun 2026 13:55:33 +0200 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=86=99=20Update=20Purse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/purse/PurseClassicView.tsx | 164 ++++++++ src/components/purse/PurseModernView.tsx | 138 +++++++ src/components/purse/PurseView.tsx | 164 +------- src/components/purse/views/SeasonalView.tsx | 6 +- src/components/right-side/RightSideView.tsx | 2 +- src/css/purse/PurseClassicView.css | 412 ++++++++++++++++++++ src/css/purse/PurseView.css | 399 ++++++------------- src/index.tsx | 2 + 8 files changed, 841 insertions(+), 446 deletions(-) create mode 100644 src/components/purse/PurseClassicView.tsx create mode 100644 src/components/purse/PurseModernView.tsx create mode 100644 src/css/purse/PurseClassicView.css diff --git a/src/components/purse/PurseClassicView.tsx b/src/components/purse/PurseClassicView.tsx new file mode 100644 index 0000000..f183e69 --- /dev/null +++ b/src/components/purse/PurseClassicView.tsx @@ -0,0 +1,164 @@ +import { CreateLinkEvent, HabboClubLevelEnum } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { FaChevronDown, FaLanguage, FaQuestionCircle, FaSignOutAlt } from 'react-icons/fa'; +import { ClearRememberLogin, FriendlyTime, GetConfigurationValue, GetRememberLogin, LocalizeText } from '../../api'; +import { Column, Flex, LayoutCurrencyIcon, Text } from '../../common'; +import { usePurse } from '../../hooks'; +import purseIcon from '../../assets/images/rightside/purse.gif'; +import { CurrencyView } from './views/CurrencyView'; +import { SeasonalView } from './views/SeasonalView'; + +export const PurseClassicView: FC<{}> = props => +{ + const { purse = null, hcDisabled = false } = usePurse(); + const [ isOpen, setIsOpen ] = useState(true); + const [ isCompact, setIsCompact ] = useState(false); + + const displayedCurrencies = useMemo(() => GetConfigurationValue('system.currency.types', []), []); + const currencyDisplayNumberShort = useMemo(() => GetConfigurationValue('currency.display.number.short', false), []); + + const getClubText = (() => + { + if (!purse) return null; + + const totalDays = ((purse.clubPeriods * 31) + purse.clubDays); + const minutesUntilExpiration = purse.minutesUntilExpiration; + + if (purse.clubLevel === HabboClubLevelEnum.NO_CLUB) return LocalizeText('purse.clubdays.zero.amount.text'); + else if ((minutesUntilExpiration > -1) && (minutesUntilExpiration < (60 * 24))) return FriendlyTime.shortFormat(minutesUntilExpiration * 60); + else return FriendlyTime.shortFormat(totalDays * 86400); + })(); + + const currencyTypes = useMemo(() => + { + if (!purse || !purse.activityPoints || !purse.activityPoints.size) return []; + + const types = Array.from(purse.activityPoints.keys()).filter(type => (displayedCurrencies.indexOf(type) >= 0)); + types.sort((a, b) => + { + if (a === 0) return -1; + if (b === 0) return 1; + if (a === 5) return -1; + if (b === 5) return 1; + return a - b; + }); + + return types; + }, [ displayedCurrencies, purse ]); + + const primaryCurrencies = currencyTypes.slice(0, 2); + const seasonalCurrencies = currencyTypes.slice(2); + + useEffect(() => + { + if(isOpen) + { + setIsCompact(false); + return; + } + + const timeout = window.setTimeout(() => setIsCompact(true), 220); + + return () => window.clearTimeout(timeout); + }, [ isOpen ]); + + const handleLogout = useCallback(async (event: React.MouseEvent) => + { + event.stopPropagation(); + + const logoutUrl = GetConfigurationValue('login.logout.endpoint', '/api/auth/logout'); + const ssoTicket = (window.NitroConfig?.['sso.ticket'] as string) ?? ''; + const rememberToken = GetRememberLogin()?.token || ''; + + try + { + await fetch(logoutUrl, { + method: 'POST', + credentials: 'include', + keepalive: true, + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'X-Requested-With': 'NitroPurseLogout' + }, + body: JSON.stringify({ ssoTicket, rememberToken }) + }); + } + catch {} + + ClearRememberLogin(); + if(window.NitroConfig) window.NitroConfig['sso.ticket'] = ''; + window.location.reload(); + }, []); + + if (!purse) return null; + + return ( + +
+
+
+
setIsOpen(value => !value) }> + +
+ +
+
+
+ +
+
+
+
+
+ + { primaryCurrencies.map(type => ) } +
+ { !hcDisabled && +
+ { + event.stopPropagation(); CreateLinkEvent('catalog/open/' + GetConfigurationValue>('catalog.links')?.['hc.buy_hc']); + } }> +
+ +
+
+ HC + { getClubText } +
+
} +
+ + + + +
+
+
+
+
+
+ { seasonalCurrencies.length > 0 && +
+ { seasonalCurrencies.map(type => ) } +
} +
+ ); +}; diff --git a/src/components/purse/PurseModernView.tsx b/src/components/purse/PurseModernView.tsx new file mode 100644 index 0000000..adbd851 --- /dev/null +++ b/src/components/purse/PurseModernView.tsx @@ -0,0 +1,138 @@ +import { CreateLinkEvent } from '@nitrots/nitro-renderer'; +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'; +import { usePurse } from '../../hooks'; +import { CurrencyView } from './views/CurrencyView'; +import { SeasonalView } from './views/SeasonalView'; + +const localizeWithFallback = (key: string, fallback: string) => +{ + const text = LocalizeText(key); + return (text && text !== key) ? text : fallback; +}; + +export const PurseModernView: FC<{}> = props => +{ + const { purse = null, hcDisabled = false } = usePurse(); + + const displayedCurrencies = useMemo(() => GetConfigurationValue('system.currency.types', []), []); + const currencyDisplayNumberShort = useMemo(() => GetConfigurationValue('currency.display.number.short', false), []); + + const currencyTypes = useMemo(() => + { + if (!purse || !purse.activityPoints || !purse.activityPoints.size) return []; + + const types = Array.from(purse.activityPoints.keys()).filter(type => (displayedCurrencies.indexOf(type) >= 0)); + types.sort((a, b) => + { + if (a === 0) return -1; + if (b === 0) return 1; + if (a === 5) return -1; + if (b === 5) return 1; + return a - b; + }); + + return types; + }, [ displayedCurrencies, purse ]); + + const hasDiamonds = currencyTypes.indexOf(5) >= 0; + const hasDuckets = currencyTypes.indexOf(0) >= 0; + const otherCurrencies = currencyTypes.filter(type => (type !== 0 && type !== 5)); + + const joinLabel = useMemo(() => localizeWithFallback('purse.join', 'Join'), []); + const earningsLabel = useMemo(() => localizeWithFallback('earnings.title', 'Earnings'), []); + const helpLabel = useMemo(() => localizeWithFallback('help.button.name', 'Help'), []); + + const openClub = useCallback((event: React.MouseEvent) => + { + event.stopPropagation(); + + const page = GetConfigurationValue('hc.buy_hc', 'habbo_club'); + CreateLinkEvent('catalog/open/' + page); + }, []); + + const openEarnings = useCallback((event: React.MouseEvent) => + { + event.stopPropagation(); + CreateLinkEvent('habboUI/open/vault'); + }, []); + + const handleLogout = useCallback(async (event: React.MouseEvent) => + { + event.stopPropagation(); + + const logoutUrl = GetConfigurationValue('login.logout.endpoint', '/api/auth/logout'); + const ssoTicket = (window.NitroConfig?.['sso.ticket'] as string) ?? ''; + const rememberToken = GetRememberLogin()?.token || ''; + + try + { + await fetch(logoutUrl, { + method: 'POST', + credentials: 'include', + keepalive: true, + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'X-Requested-With': 'NitroPurseLogout' + }, + body: JSON.stringify({ ssoTicket, rememberToken }) + }); + } + catch { } + + ClearRememberLogin(); + if(window.NitroConfig) window.NitroConfig['sso.ticket'] = ''; + window.location.reload(); + }, []); + + if (!purse) return null; + + return ( + +
+
+
+ { hasDiamonds && } + + { hasDuckets && } +
+
+ { !hcDisabled && + } + +
+
+ + + +
+
+
+ { otherCurrencies.length > 0 && +
+ { otherCurrencies.map(type => ) } +
} +
+ ); +}; diff --git a/src/components/purse/PurseView.tsx b/src/components/purse/PurseView.tsx index 51ab0c7..32362e6 100644 --- a/src/components/purse/PurseView.tsx +++ b/src/components/purse/PurseView.tsx @@ -1,163 +1,11 @@ -import { CreateLinkEvent, HabboClubLevelEnum } from '@nitrots/nitro-renderer'; -import { FC, useCallback, useEffect, useMemo, useState } from 'react'; -import { FaChevronDown, FaLanguage, FaQuestionCircle, FaSignOutAlt } from 'react-icons/fa'; -import { ClearRememberLogin, FriendlyTime, GetConfigurationValue, GetRememberLogin, LocalizeText } from '../../api'; -import { Column, Flex, LayoutCurrencyIcon, Text } from '../../common'; -import { usePurse } from '../../hooks'; -import purseIcon from '../../assets/images/rightside/purse.gif'; -import { CurrencyView } from './views/CurrencyView'; -import { SeasonalView } from './views/SeasonalView'; +import { FC } from 'react'; +import { useCatalogClassicStyle } from '../../hooks'; +import { PurseClassicView } from './PurseClassicView'; +import { PurseModernView } from './PurseModernView'; export const PurseView: FC<{}> = props => { - const { purse = null, hcDisabled = false } = usePurse(); - const [ isOpen, setIsOpen ] = useState(true); - const [ isCompact, setIsCompact ] = useState(false); + const [ classicStyle ] = useCatalogClassicStyle(); - const displayedCurrencies = useMemo(() => GetConfigurationValue('system.currency.types', []), []); - const currencyDisplayNumberShort = useMemo(() => GetConfigurationValue('currency.display.number.short', false), []); - - const getClubText = (() => - { - if (!purse) return null; - - const totalDays = ((purse.clubPeriods * 31) + purse.clubDays); - const minutesUntilExpiration = purse.minutesUntilExpiration; - - if (purse.clubLevel === HabboClubLevelEnum.NO_CLUB) return LocalizeText('purse.clubdays.zero.amount.text'); - else if ((minutesUntilExpiration > -1) && (minutesUntilExpiration < (60 * 24))) return FriendlyTime.shortFormat(minutesUntilExpiration * 60); - else return FriendlyTime.shortFormat(totalDays * 86400); - })(); - - const currencyTypes = useMemo(() => - { - if (!purse || !purse.activityPoints || !purse.activityPoints.size) return []; - - const types = Array.from(purse.activityPoints.keys()).filter(type => (displayedCurrencies.indexOf(type) >= 0)); - types.sort((a, b) => - { - if (a === 0) return -1; - if (b === 0) return 1; - if (a === 5) return -1; - if (b === 5) return 1; - return a - b; - }); - - return types; - }, [ displayedCurrencies, purse ]); - - const primaryCurrencies = currencyTypes.slice(0, 2); - const seasonalCurrencies = currencyTypes.slice(2); - - useEffect(() => - { - if(isOpen) - { - setIsCompact(false); - return; - } - - const timeout = window.setTimeout(() => setIsCompact(true), 220); - - return () => window.clearTimeout(timeout); - }, [ isOpen ]); - - const handleLogout = useCallback(async (event: React.MouseEvent) => - { - event.stopPropagation(); - - const logoutUrl = GetConfigurationValue('login.logout.endpoint', '/api/auth/logout'); - const ssoTicket = (window.NitroConfig?.['sso.ticket'] as string) ?? ''; - const rememberToken = GetRememberLogin()?.token || ''; - - try - { - await fetch(logoutUrl, { - method: 'POST', - credentials: 'include', - keepalive: true, - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'X-Requested-With': 'NitroPurseLogout' - }, - body: JSON.stringify({ ssoTicket, rememberToken }) - }); - } - catch - { /* best-effort — proceed with local logout regardless */ } - - ClearRememberLogin(); - if(window.NitroConfig) window.NitroConfig['sso.ticket'] = ''; - window.location.reload(); - }, []); - - if (!purse) return null; - - return ( - -
-
-
setIsOpen(value => !value) }> - -
- -
-
-
- -
-
-
-
-
- - { primaryCurrencies.map(type => ) } -
- { !hcDisabled && -
- { - event.stopPropagation(); CreateLinkEvent('habboUI/open/hccenter'); - } }> -
- -
-
- HC - { getClubText } -
-
} -
- - - - -
-
- { seasonalCurrencies.length > 0 && -
- { seasonalCurrencies.map(type => ) } -
} -
-
-
-
- ); + return classicStyle ? : ; }; diff --git a/src/components/purse/views/SeasonalView.tsx b/src/components/purse/views/SeasonalView.tsx index de942a3..6cbfb8b 100644 --- a/src/components/purse/views/SeasonalView.tsx +++ b/src/components/purse/views/SeasonalView.tsx @@ -21,9 +21,6 @@ export const SeasonalView: FC = props => className={`nitro-purse-seasonal-currency nitro-notification ${seasonalColor}`} > - - - {LocalizeText(`purse.seasonal.currency.${type}`)} @@ -34,6 +31,9 @@ export const SeasonalView: FC = props => > {formattedAmount} + + + ); diff --git a/src/components/right-side/RightSideView.tsx b/src/components/right-side/RightSideView.tsx index d4e31b0..2b94363 100644 --- a/src/components/right-side/RightSideView.tsx +++ b/src/components/right-side/RightSideView.tsx @@ -10,7 +10,7 @@ import { RoomPromotesWidgetView } from '../room/widgets/room-promotes/RoomPromot export const RightSideView: FC<{}> = props => { return ( -
+
diff --git a/src/css/purse/PurseClassicView.css b/src/css/purse/PurseClassicView.css new file mode 100644 index 0000000..c92a8ba --- /dev/null +++ b/src/css/purse/PurseClassicView.css @@ -0,0 +1,412 @@ +.nitro-purse-classic { + width: 100%; +} + +.nitro-purse__other--classic { + max-width: 125px; +} + +.nitro-purse__other--classic .nitro-purse-seasonal-currency { + border: 0; +} + +.nitro-purse-classic .nitro-purse-shell { + width: 100%; + max-width: 188px; + margin-top: 6px; + margin-left: auto; +} + +.nitro-purse-classic .nitro-purse-shell.is-closed { + width: 52px; + max-width: 52px; +} + +.nitro-purse-classic .nitro-purse { + width: 100%; + max-width: none; + margin: 0; + overflow: hidden; + border: 1px solid rgba(255, 255, 255, 0.07); + border-radius: 10px; + background: rgba(10, 10, 12, 0.58); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.05), + 0 8px 18px rgba(0, 0, 0, 0.14); + transition: width 0.24s cubic-bezier(0.22, 1, 0.36, 1), max-width 0.24s cubic-bezier(0.22, 1, 0.36, 1), border-color 0.2s ease; +} + +.nitro-purse-classic .nitro-purse.is-closed { + width: 52px; +} + +.nitro-purse-classic .nitro-purse__header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + padding: 5px 7px; + cursor: pointer; + border-bottom: 1px solid rgba(255, 255, 255, 0.06); + background: linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.03)); + transition: background-color 0.2s ease, border-color 0.2s ease; +} + +.nitro-purse-classic .nitro-purse__header.is-closed { + justify-content: flex-end; + gap: 5px; + padding: 5px 6px; +} + +.nitro-purse-classic .nitro-purse__header-main { + display: inline-flex; + align-items: center; +} + +.nitro-purse-classic .nitro-purse__header-main.is-closed { + margin-right: 0; +} + +.nitro-purse-classic .nitro-purse__header-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + opacity: 0.9; +} + +.nitro-purse-classic .nitro-purse__header-image { + display: block; + width: auto; + height: 14px; + object-fit: contain; +} + +.nitro-purse-classic .nitro-purse__header-title { + font-size: 0.82rem; + font-weight: 700; + line-height: 1; + color: rgba(255, 255, 255, 0.92) !important; + letter-spacing: 0.01em; +} + +.nitro-purse-classic .nitro-purse__header-toggle { + display: inline-flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + border-radius: 6px; + color: rgba(255, 255, 255, 0.82); + background: rgba(255, 255, 255, 0.06); + transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1), background-color 0.2s ease; +} + +.nitro-purse-classic .nitro-purse__header-toggle.is-open { + transform: rotate(180deg); +} + +.nitro-purse-classic .nitro-purse__content { + display: flex; + flex-direction: column; + gap: 5px; + padding: 6px; + overflow: hidden; + transform-origin: top; + transition: + max-height 0.58s cubic-bezier(0.16, 1, 0.3, 1), + opacity 0.38s ease-out, + transform 0.58s cubic-bezier(0.16, 1, 0.3, 1), + padding 0.4s ease-out; + max-height: 280px; + opacity: 1; + transform: translateY(0); + background: transparent; +} + +.nitro-purse-classic .nitro-purse__content.is-closed { + max-height: 0; + opacity: 0; + transform: translateY(-8px) scaleY(0.95); + padding-top: 0; + padding-bottom: 0; + pointer-events: none; +} + +.nitro-purse-classic .nitro-purse__summary, +.nitro-purse-classic .nitro-purse__seasonal { + transition: + opacity 0.32s ease-out, + transform 0.48s cubic-bezier(0.16, 1, 0.3, 1); +} + +.nitro-purse-classic .nitro-purse__summary { + transition-delay: 0.08s; +} + +.nitro-purse-classic .nitro-purse__seasonal { + transition-delay: 0.16s; +} + +.nitro-purse-classic .nitro-purse__content.is-closed .nitro-purse__summary, +.nitro-purse-classic .nitro-purse__content.is-closed .nitro-purse__seasonal { + opacity: 0; + transform: translateY(-6px); + transition-delay: 0s; +} + +.nitro-purse-classic .nitro-purse__summary { + display: grid; + grid-template-columns: minmax(0, 1fr) 30px 26px; + gap: 5px; + align-items: stretch; +} + +.nitro-purse-classic .nitro-purse__summary.is-no-hc { + grid-template-columns: minmax(0, 1fr) 26px; +} + +.nitro-purse-classic .nitro-purse__primary, +.nitro-purse-classic .nitro-purse__seasonal { + display: flex; + flex-direction: column; + gap: 3px; +} + +.nitro-purse-classic .nitro-purse .nitro-purse-button, +.nitro-purse-classic .nitro-purse-seasonal-currency { + min-height: 22px; + padding: 2px 0; + border: 0 !important; + border-radius: 0 !important; + background: transparent !important; + box-shadow: none !important; +} + +.nitro-purse-classic .nitro-purse .allcurrencypurse, +.nitro-purse-classic .nitro-purse-seasonal-currency { + position: relative; +} + +.nitro-purse-classic .nitro-purse .allcurrencypurse::after, +.nitro-purse-classic .nitro-purse-seasonal-currency::after { + content: ''; + position: absolute; + left: 0; + right: 0; + bottom: -1px; + height: 1px; + background: rgba(255, 255, 255, 0.08); +} + +.nitro-purse-classic .nitro-purse__primary > :last-child::after, +.nitro-purse-classic .nitro-purse__seasonal > :last-child::after { + display: none; +} + +.nitro-purse-classic .nitro-purse .allcurrencypurse .text-white { + font-size: 0.76rem; + font-weight: 700; + line-height: 1; + letter-spacing: 0.01em; + color: rgba(255, 255, 255, 0.88) !important; +} + +.nitro-purse-classic .nitro-purse .nitro-purse-button.currency--1 .text-white { + color: #7fdcff !important; +} + +.nitro-purse-classic .nitro-purse .nitro-purse-button.currency-0 .text-white { + color: #ffd76d !important; +} + +.nitro-purse-classic .nitro-purse .nitro-purse-button.currency-5 .text-white { + color: #df95ff !important; +} + +.nitro-purse-classic .nitro-purse-subscription { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 2px; + min-height: 62px; + cursor: pointer; + border-left: 1px solid rgba(255, 255, 255, 0.08); + border-right: 1px solid rgba(255, 255, 255, 0.08); + background: rgba(255, 255, 255, 0.02); +} + +.nitro-purse-classic .nitro-purse-subscription__icon { + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + opacity: 0.95; +} + +.nitro-purse-classic .nitro-purse-subscription__copy { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: 1px; +} + +.nitro-purse-classic .nitro-purse-subscription__label { + font-size: 0.5rem; + font-weight: 700; + color: rgba(255, 255, 255, 0.62) !important; + letter-spacing: 0.08em; +} + +.nitro-purse-classic .nitro-purse-subscription__value { + font-size: 0.54rem; + font-weight: 700; + line-height: 1.05; + color: #ffffff !important; +} + +.nitro-purse-classic .nitro-purse__actions { + display: grid; + grid-template-columns: 1fr; + gap: 3px; +} + +.nitro-purse-classic .nitro-purse__action-button { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 20px; + padding: 0; + border: 1px solid rgba(7, 23, 31, 0.82); + border-radius: 7px; + color: rgba(255, 255, 255, 0.88); + background: rgba(255, 255, 255, 0.05); + box-shadow: none; + transition: background-color 0.18s ease, transform 0.18s ease; +} + +.nitro-purse-classic .nitro-purse__action-button:hover { + background: rgba(255, 255, 255, 0.1); + transform: translateY(-1px); +} + +.nitro-purse-classic .nitro-purse__action-button .nitro-icon { + transform: scale(0.82); +} + +.nitro-purse-classic .nitro-purse-seasonal-currency > div { + align-items: center; + gap: 6px; + padding: 0; +} + +.nitro-purse-classic .seasonal-row { + min-width: 0; +} + +.nitro-purse-classic .seasonal-text-padding, +.nitro-purse-classic .seasonal-amount { + display: flex; + align-items: center; + margin-left: 0; +} + +.nitro-purse-classic .seasonal-text { + min-width: 0; + font-size: 0.76rem; + font-weight: 700; + color: rgba(255, 255, 255, 0.76) !important; + line-height: 1; + letter-spacing: 0.01em; +} + +.nitro-purse-classic .seasonal-amount { + margin-left: auto; + white-space: nowrap; + flex: 0 0 auto; + font-size: 0.76rem; + font-weight: 700; + line-height: 1; + color: rgba(255, 255, 255, 0.96) !important; +} + +.nitro-purse-classic .seasonal-image-padding { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; + border-radius: 0; + background: transparent; + flex: 0 0 auto; +} + +.nitro-purse-classic .seasonal-image { + display: block; + width: auto; + height: 14px; + object-fit: contain; +} + +@media (max-width: 640px) { + .nitro-purse-classic .nitro-purse-shell { + max-width: 100%; + } + + .nitro-purse-classic .nitro-purse-shell.is-closed { + max-width: 52px; + } + + .nitro-purse-classic .nitro-purse { + border-radius: 9px; + } + + .nitro-purse-classic .nitro-purse__content { + padding: 6px; + } + + .nitro-purse-classic .nitro-purse__summary { + grid-template-columns: minmax(0, 1fr) 28px 24px; + gap: 4px; + } + + .nitro-purse-classic .nitro-purse__summary.is-no-hc { + grid-template-columns: minmax(0, 1fr) 24px; + } + + .nitro-purse-classic .nitro-purse-subscription { + min-height: 58px; + } + + .nitro-purse-classic .nitro-purse .allcurrencypurse .text-white, + .nitro-purse-classic .seasonal-text, + .nitro-purse-classic .seasonal-amount { + font-size: 0.72rem; + } + + .nitro-purse-classic .nitro-purse__header-title { + font-size: 0.78rem; + } +} + +@media (max-width: 420px) { + .nitro-purse-classic .nitro-purse__summary { + grid-template-columns: minmax(0, 1fr) 26px 22px; + gap: 4px; + } + + .nitro-purse-classic .nitro-purse__summary.is-no-hc { + grid-template-columns: minmax(0, 1fr) 22px; + } + + .nitro-purse-classic .nitro-purse-subscription { + min-height: 54px; + } + + .nitro-purse-classic .nitro-purse-subscription__value { + font-size: 0.55rem; + } +} diff --git a/src/css/purse/PurseView.css b/src/css/purse/PurseView.css index ebbe69e..bc07713 100644 --- a/src/css/purse/PurseView.css +++ b/src/css/purse/PurseView.css @@ -3,171 +3,38 @@ pointer-events: all; } -.nitro-purse-shell { - width: 100%; - max-width: 188px; - margin-top: 6px; - margin-left: auto; -} - -.nitro-purse-shell.is-closed { - width: 52px; - max-width: 52px; -} - .nitro-purse { width: 100%; + max-width: 234px; + margin-left: auto; overflow: hidden; - border: 1px solid rgba(255, 255, 255, 0.07); - border-radius: 10px; + border: 0; + border-left: 2px solid #41403c; + border-bottom: 2px solid #41403c; + border-radius: 0 0 0 10px; background: rgba(10, 10, 12, 0.58); - box-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.05), - 0 8px 18px rgba(0, 0, 0, 0.14); - transition: width 0.24s cubic-bezier(0.22, 1, 0.36, 1), max-width 0.24s cubic-bezier(0.22, 1, 0.36, 1), border-color 0.2s ease; + box-shadow: 0 8px 18px rgba(0, 0, 0, 0.14); } -.nitro-purse.is-closed { - width: 52px; -} - -.nitro-purse__header { +.nitro-purse__body { display: flex; - align-items: center; - justify-content: space-between; - gap: 0.5rem; - padding: 5px 7px; - cursor: pointer; - border-bottom: 1px solid rgba(255, 255, 255, 0.06); - background: linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.03)); - transition: background-color 0.2s ease, border-color 0.2s ease; -} - -.nitro-purse__header.is-closed { - justify-content: flex-end; - gap: 5px; - padding: 5px 6px; -} - -.nitro-purse__header-main { - display: inline-flex; - align-items: center; -} - -.nitro-purse__header-main.is-closed { - margin-right: 0; -} - -.nitro-purse__header-icon { - display: inline-flex; - align-items: center; - justify-content: center; - width: 16px; - height: 16px; - opacity: 0.9; -} - -.nitro-purse__header-image { - display: block; - width: auto; - height: 14px; - object-fit: contain; -} - -.nitro-purse__header-title { - font-size: 0.82rem; - font-weight: 700; - line-height: 1; - color: rgba(255, 255, 255, 0.92) !important; - letter-spacing: 0.01em; -} - -.nitro-purse__header-toggle { - display: inline-flex; - align-items: center; - justify-content: center; - width: 20px; - height: 20px; - border-radius: 6px; - color: rgba(255, 255, 255, 0.82); - background: rgba(255, 255, 255, 0.06); - transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1), background-color 0.2s ease; -} - -.nitro-purse__header-toggle.is-open { - transform: rotate(180deg); -} - -.nitro-purse__content { - display: flex; - flex-direction: column; - gap: 5px; - padding: 6px; - overflow: hidden; - transform-origin: top; - transition: - max-height 0.58s cubic-bezier(0.16, 1, 0.3, 1), - opacity 0.38s ease-out, - transform 0.58s cubic-bezier(0.16, 1, 0.3, 1), - padding 0.4s ease-out; - max-height: 280px; - opacity: 1; - transform: translateY(0); - background: transparent; -} - -.nitro-purse__content.is-closed { - max-height: 0; - opacity: 0; - transform: translateY(-8px) scaleY(0.95); - padding-top: 0; - padding-bottom: 0; - pointer-events: none; -} - -.nitro-purse__summary, -.nitro-purse__seasonal { - transition: - opacity 0.32s ease-out, - transform 0.48s cubic-bezier(0.16, 1, 0.3, 1); -} - -.nitro-purse__summary { - transition-delay: 0.08s; -} - -.nitro-purse__seasonal { - transition-delay: 0.16s; -} - -.nitro-purse__content.is-closed .nitro-purse__summary, -.nitro-purse__content.is-closed .nitro-purse__seasonal { - opacity: 0; - transform: translateY(-6px); - transition-delay: 0s; -} - -.nitro-purse__summary { - display: grid; - grid-template-columns: minmax(0, 1fr) 30px 26px; - gap: 5px; + gap: 6px; align-items: stretch; + padding: 6px; } -.nitro-purse__summary.is-no-hc { - grid-template-columns: minmax(0, 1fr) 26px; -} - -.nitro-purse__primary, -.nitro-purse__seasonal { +.nitro-purse__currencies { display: flex; + flex: 1 1 0; flex-direction: column; - gap: 3px; + justify-content: center; + gap: 2px; + min-width: 0; } -.nitro-purse .nitro-purse-button, -.nitro-purse-seasonal-currency { - min-height: 22px; +.nitro-purse .nitro-purse-button { + align-items: center; + min-height: 20px; padding: 2px 0; border: 0 !important; border-radius: 0 !important; @@ -175,27 +42,6 @@ box-shadow: none !important; } -.nitro-purse .allcurrencypurse, -.nitro-purse-seasonal-currency { - position: relative; -} - -.nitro-purse .allcurrencypurse::after, -.nitro-purse-seasonal-currency::after { - content: ''; - position: absolute; - left: 0; - right: 0; - bottom: -1px; - height: 1px; - background: rgba(255, 255, 255, 0.08); -} - -.nitro-purse__primary > :last-child::after, -.nitro-purse__seasonal > :last-child::after { - display: none; -} - .nitro-purse .allcurrencypurse .text-white { font-size: 0.76rem; font-weight: 700; @@ -216,79 +62,118 @@ color: #df95ff !important; } -.nitro-purse-subscription { +.nitro-purse__col { display: flex; + flex: 0 0 auto; flex-direction: column; - align-items: center; - justify-content: center; - gap: 2px; - min-height: 62px; - cursor: pointer; - border-left: 1px solid rgba(255, 255, 255, 0.08); - border-right: 1px solid rgba(255, 255, 255, 0.08); - background: rgba(255, 255, 255, 0.02); + align-items: stretch; + gap: 4px; } -.nitro-purse-subscription__icon { - display: flex; - align-items: center; - justify-content: center; - width: 16px; - height: 16px; - opacity: 0.95; -} - -.nitro-purse-subscription__copy { - display: flex; - flex-direction: column; - align-items: center; - text-align: center; - gap: 1px; -} - -.nitro-purse-subscription__label { - font-size: 0.5rem; - font-weight: 700; - color: rgba(255, 255, 255, 0.62) !important; - letter-spacing: 0.08em; -} - -.nitro-purse-subscription__value { - font-size: 0.54rem; - font-weight: 700; - line-height: 1.05; - color: #ffffff !important; -} - -.nitro-purse__actions { - display: grid; - grid-template-columns: 1fr; - gap: 3px; -} - -.nitro-purse__action-button { +.nitro-purse__btn { display: inline-flex; align-items: center; justify-content: center; - min-height: 20px; - padding: 0; - border: 1px solid rgba(7, 23, 31, 0.82); + gap: 5px; + flex: 1 1 0; + width: 100%; + min-height: 22px; + padding: 0 8px; + border: 1px solid transparent; border-radius: 7px; - color: rgba(255, 255, 255, 0.88); - background: rgba(255, 255, 255, 0.05); - box-shadow: none; - transition: background-color 0.18s ease, transform 0.18s ease; + color: #ffffff; + font-size: 0.72rem; + font-weight: 700; + line-height: 1; + letter-spacing: 0.01em; + white-space: nowrap; + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.2), + inset 0 -2px 0 rgba(0, 0, 0, 0.16); + transition: filter 0.15s ease, transform 0.15s ease; } -.nitro-purse__action-button:hover { - background: rgba(255, 255, 255, 0.1); +.nitro-purse__btn:hover { + filter: brightness(1.07); transform: translateY(-1px); } -.nitro-purse__action-button .nitro-icon { +.nitro-purse__btn:active { + transform: translateY(0); + filter: brightness(0.96); +} + +.nitro-purse__btn--icon { + gap: 0; + padding: 0; +} + +.nitro-purse__btn-icon { + flex: 0 0 auto; + color: #ff6ad0; +} + +.nitro-purse__btn .nitro-icon { transform: scale(0.82); } +.nitro-purse__btn--join { + border-color: rgba(255, 255, 255, 0.1); + background: #33312c; +} + +.nitro-purse__btn--earnings { + border-color: rgba(255, 255, 255, 0.1); + background: #33312c; +} + +.nitro-purse__btn--help { + border-color: #14526b; + background: linear-gradient(180deg, #2790b6 0%, #1e7295 100%); +} + +.nitro-purse__btn--logout { + border-color: #7c1414; + background: linear-gradient(180deg, #d23b3b 0%, #b32424 100%); +} + +.nitro-purse__btn--settings { + border-color: #565064; + background: #716a85; +} + +/* Action column buttons: square corners */ +.nitro-purse__col--actions .nitro-purse__btn { + border-radius: 0; +} + +/* Gear icon rendered white */ +.nitro-purse__btn--settings svg { + color: #ffffff; +} + +/* ---- Other currencies: separate container(s) below the purse ---- */ +.nitro-purse__other { + width: 100%; + max-width: 156px; + margin-top: 4px; + margin-left: auto; + display: flex; + flex-direction: column; + gap: 4px; +} + +.nitro-purse__other .nitro-purse-seasonal-currency { + padding: 5px 8px; + border: 0; + border-top: 2px solid #41403c; + border-left: 2px solid #41403c; + border-bottom: 2px solid #41403c; + border-radius: 10px 0 0 10px; + background: rgba(10, 10, 12, 0.58); + box-shadow: 0 8px 18px rgba(0, 0, 0, 0.14); +} + .nitro-purse-seasonal-currency > div { align-items: center; gap: 6px; @@ -343,61 +228,7 @@ } @media (max-width: 640px) { - .nitro-purse-shell { + .nitro-purse { max-width: 100%; } - - .nitro-purse-shell.is-closed { - max-width: 52px; - } - - .nitro-purse { - border-radius: 9px; - } - - .nitro-purse__content { - padding: 6px; - } - - .nitro-purse__summary { - grid-template-columns: minmax(0, 1fr) 28px 24px; - gap: 4px; - } - - .nitro-purse__summary.is-no-hc { - grid-template-columns: minmax(0, 1fr) 24px; - } - - .nitro-purse-subscription { - min-height: 58px; - } - - .nitro-purse .allcurrencypurse .text-white, - .seasonal-text, - .seasonal-amount { - font-size: 0.72rem; - } - - .nitro-purse__header-title { - font-size: 0.78rem; - } -} - -@media (max-width: 420px) { - .nitro-purse__summary { - grid-template-columns: minmax(0, 1fr) 26px 22px; - gap: 4px; - } - - .nitro-purse__summary.is-no-hc { - grid-template-columns: minmax(0, 1fr) 22px; - } - - .nitro-purse-subscription { - min-height: 54px; - } - - .nitro-purse-subscription__value { - font-size: 0.55rem; - } } diff --git a/src/index.tsx b/src/index.tsx index a06be73..ba151ea 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -56,6 +56,8 @@ import './css/notification/NotificationCenterView.css'; import './css/purse/PurseView.css'; +import './css/purse/PurseClassicView.css'; + import './css/room/InfoStand.css'; import './css/room/NavigatorRoomSettings.css'; import './css/room/RoomWidgets.css';