🆙 Detached Theme from original NitroV3

This commit is contained in:
duckietm
2026-06-10 07:23:02 +02:00
parent b2000ba1a9
commit e5ca4936ea
739 changed files with 49 additions and 7774 deletions
@@ -7,25 +7,16 @@ interface ChatInputCommandSelectorViewProps
selectedIndex: number;
onSelect: (command: CommandDefinition) => void;
onHover: (index: number) => void;
/**
* When true, render the flat minimalist look (gray list, dark-blue
* selection). When false / undefined (default) the picker wears the
* Habbo NitroCard chrome with the green :command header strip.
*/
newStyle?: boolean;
}
/**
* :command autocomplete popover. Two visual modes, both driven by the
* "New style" toggle in user settings (memenu.settings.other.catalog.classic.style):
*
* - newStyle = false (default): cream cardstock, habbo-green header,
* UbuntuCondensed names, green ":" tile, custom Habbo scrollbar.
* - newStyle = true: flat gray list, dark-blue selection, plain text rows.
* :command autocomplete popover. Wears the Habbo NitroCard chrome: cream
* cardstock, habbo-green header, UbuntuCondensed names, green ":" tile and
* the custom Habbo scrollbar.
*/
export const ChatInputCommandSelectorView: FC<ChatInputCommandSelectorViewProps> = props =>
{
const { commands = [], selectedIndex = 0, onSelect = null, onHover = null, newStyle = false } = props;
const { commands = [], selectedIndex = 0, onSelect = null, onHover = null } = props;
const listRef = useRef<HTMLDivElement>(null);
useEffect(() =>
@@ -37,25 +28,6 @@ export const ChatInputCommandSelectorView: FC<ChatInputCommandSelectorViewProps>
if(selected) selected.scrollIntoView({ block: 'nearest' });
}, [ selectedIndex ]);
if(newStyle)
{
return (
<div ref={ listRef } className="absolute bottom-full left-0 w-full bg-[#e8e8e8] border-2 border-black border-b-0 rounded-t-lg max-h-[240px] overflow-y-auto z-[1070]">
{ commands.map((cmd, index) => (
<div
key={ cmd.key }
className={ `px-3 py-1.5 cursor-pointer text-sm flex items-center gap-2 ${ index === selectedIndex ? 'bg-[#283F5D] text-white' : 'hover:bg-gray-300' }` }
onClick={ () => onSelect(cmd) }
onMouseEnter={ () => onHover(index) }
>
<span className="font-bold">:{ cmd.key }</span>
<span className={ `text-xs ${ index === selectedIndex ? 'text-gray-300' : 'text-gray-500' }` }>{ cmd.description }</span>
</div>
)) }
</div>
);
}
return (
<div className="chat-input-command-popover">
<div className="chat-input-command-popover-header">
@@ -8,28 +8,16 @@ interface ChatInputMentionSelectorViewProps
selectedIndex: number;
onSelect: (suggestion: MentionSuggestion) => void;
onHover: (index: number) => void;
/**
* When true, render the flat minimalist look (gray list, dark-blue
* selection, no header / no kind chip). When false / undefined (default)
* the picker wears the Habbo NitroCard chrome.
*/
newStyle?: boolean;
}
/**
* @-mention autocomplete popover. Two visual modes, both driven by the
* "New style" toggle in user settings (memenu.settings.other.catalog.classic.style):
*
* - newStyle = false (default): cream cardstock, habbo-blue header,
* UbuntuCondensed names, kind chips, custom Habbo scrollbar.
* - newStyle = true: flat gray list, dark-blue selection, plain text rows.
*
* Both modes share the same suggestion structure and keyboard contract -
* the difference is purely cosmetic.
* @-mention autocomplete popover. Wears the Habbo NitroCard chrome: cream
* cardstock, habbo-blue header, UbuntuCondensed names, kind chips and the
* custom Habbo scrollbar.
*/
export const ChatInputMentionSelectorView: FC<ChatInputMentionSelectorViewProps> = props =>
{
const { suggestions = [], selectedIndex = 0, onSelect = null, onHover = null, newStyle = false } = props;
const { suggestions = [], selectedIndex = 0, onSelect = null, onHover = null } = props;
const listRef = useRef<HTMLDivElement>(null);
useEffect(() =>
@@ -43,45 +31,6 @@ export const ChatInputMentionSelectorView: FC<ChatInputMentionSelectorViewProps>
if(suggestions.length === 0) return null;
if(newStyle)
{
return (
<div ref={ listRef } className="absolute bottom-full left-0 w-full bg-[#e8e8e8] border-2 border-black border-b-0 rounded-t-lg max-h-[240px] overflow-y-auto z-[1070]">
{ suggestions.map((suggestion, index) =>
{
const isSelected = (index === selectedIndex);
const rowClass = `px-3 py-1.5 cursor-pointer text-sm flex items-center gap-2 ${ isSelected ? 'bg-[#283F5D] text-white' : 'hover:bg-gray-300' }`;
return (
<div
key={ suggestion.key }
className={ rowClass }
onClick={ () => onSelect(suggestion) }
onMouseEnter={ () => onHover(index) }
>
{ suggestion.kind === 'user' && suggestion.figure
? (
<div className="relative h-11 w-11 shrink-0 overflow-hidden rounded-full bg-black/10">
<LayoutAvatarImageView
figure={ suggestion.figure }
direction={ 2 }
headOnly
style={ { backgroundSize: 'auto', backgroundPosition: '-22px -32px' } }
/>
</div>
)
: (
<div className="flex items-center justify-center h-11 w-11 rounded-full bg-black/20 text-white text-[14px] font-bold shrink-0">@</div>
) }
<span className="font-bold">@{ suggestion.name }</span>
{ suggestion.description && <span className={ `text-xs ${ isSelected ? 'text-gray-300' : 'text-gray-500' }` }>{ suggestion.description }</span> }
</div>
);
}) }
</div>
);
}
return (
<div className="chat-input-mention-popover">
<div className="chat-input-mention-popover-header">
@@ -3,7 +3,7 @@ import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { ChatMessageTypeEnum, GetClubMemberLevel, GetConfigurationValue, LocalizeText, RoomWidgetUpdateChatInputContentEvent } from '../../../../api';
import { Text } from '../../../../common';
import { useCatalogClassicStyle, useChatCommandSelector, useChatInputWidget, useChatMentions, useRoom, useSessionInfo, useUiEvent } from '../../../../hooks';
import { useChatCommandSelector, useChatInputWidget, useChatMentions, useRoom, useSessionInfo, useUiEvent } from '../../../../hooks';
import { ChatInputCommandSelectorView } from './ChatInputCommandSelectorView';
import { ChatInputEmojiSelectorView } from './ChatInputEmojiSelectorView';
import { ChatInputMentionSelectorView } from './ChatInputMentionSelectorView';
@@ -18,12 +18,6 @@ export const ChatInputView: FC<{}> = props =>
const inputRef = useRef<HTMLInputElement>(null);
const { isVisible: commandSelectorVisible, filteredCommands, selectedIndex, setSelectedIndex, moveUp, moveDown, selectCurrent, close: closeCommandSelector } = useChatCommandSelector(chatValue);
// The "New style" user-setting (memenu.settings.other.catalog.classic.style)
// drives BOTH the catalog layout and the mention-picker chrome:
// false (default) = Habbo old-school NitroCard cardstock look
// true = flat minimalist gray look
const [ newStyle ] = useCatalogClassicStyle();
const mention = useChatMentions(chatValue, setChatValue, inputRef, commandSelectorVisible);
const chatModeIdWhisper = useMemo(() => LocalizeText('widgets.chatinput.mode.whisper'), []);
@@ -329,7 +323,6 @@ export const ChatInputView: FC<{}> = props =>
setChatValue(':' + cmd.key + ' '); inputRef.current?.focus();
} }
onHover={ setSelectedIndex }
newStyle={ newStyle }
/> }
{ mention.visible && !commandSelectorVisible &&
<ChatInputMentionSelectorView
@@ -337,7 +330,6 @@ export const ChatInputView: FC<{}> = props =>
selectedIndex={ mention.selectedIndex }
onSelect={ mention.apply }
onHover={ mention.setSelectedIndex }
newStyle={ newStyle }
/> }
<div className="flex-1 items-center input-sizer">
{ !floodBlocked &&