diff --git a/Coolui v3 test/.browserslistrc b/Coolui v3 test/.browserslistrc new file mode 100644 index 0000000000..3e5809a308 --- /dev/null +++ b/Coolui v3 test/.browserslistrc @@ -0,0 +1,11 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# You can see what browsers were selected by your queries by running: +# npx browserslist + +last 1 Chrome version +last 1 Firefox version +last 1 Edge major versions +last 2 Safari major versions +last 2 iOS major versions diff --git a/Coolui v3 test/.editorconfig b/Coolui v3 test/.editorconfig new file mode 100644 index 0000000000..0792692308 --- /dev/null +++ b/Coolui v3 test/.editorconfig @@ -0,0 +1,16 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/Coolui v3 test/index.html b/Coolui v3 test/index.html new file mode 100644 index 0000000000..d9362e5893 --- /dev/null +++ b/Coolui v3 test/index.html @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + Nitro + + + +
+
+ + + + diff --git a/Coolui v3 test/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx b/Coolui v3 test/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx new file mode 100644 index 0000000000..2dcdd3e079 --- /dev/null +++ b/Coolui v3 test/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx @@ -0,0 +1,176 @@ +import { CallForHelpTopicData, DefaultSanctionMessageComposer, ModAlertMessageComposer, ModBanMessageComposer, ModKickMessageComposer, ModMessageMessageComposer, ModMuteMessageComposer, ModTradingLockMessageComposer } from '@nitrots/nitro-renderer'; +import { FC, useMemo, useState } from 'react'; +import { ISelectedUser, LocalizeText, ModActionDefinition, NotificationAlertType, SendMessageComposer } from '../../../../api'; +import { Button, DraggableWindowPosition, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; +import { useModTools, useNotification } from '../../../../hooks'; + +interface ModToolsUserModActionViewProps +{ + user: ISelectedUser; + onCloseClick: () => void; +} + +const MOD_ACTION_DEFINITIONS = [ + new ModActionDefinition(1, 'Alert', ModActionDefinition.ALERT, 1, 0), + new ModActionDefinition(2, 'Mute 1h', ModActionDefinition.MUTE, 2, 0), + new ModActionDefinition(3, 'Ban 18h', ModActionDefinition.BAN, 3, 0), + new ModActionDefinition(4, 'Ban 7 days', ModActionDefinition.BAN, 4, 0), + new ModActionDefinition(5, 'Ban 30 days (step 1)', ModActionDefinition.BAN, 5, 0), + new ModActionDefinition(7, 'Ban 30 days (step 2)', ModActionDefinition.BAN, 7, 0), + new ModActionDefinition(6, 'Ban 100 years', ModActionDefinition.BAN, 6, 0), + new ModActionDefinition(106, 'Ban avatar-only 100 years', ModActionDefinition.BAN, 6, 0), + new ModActionDefinition(101, 'Kick', ModActionDefinition.KICK, 0, 0), + new ModActionDefinition(102, 'Lock trade 1 week', ModActionDefinition.TRADE_LOCK, 0, 168), + new ModActionDefinition(104, 'Lock trade permanent', ModActionDefinition.TRADE_LOCK, 0, 876000), + new ModActionDefinition(105, 'Message', ModActionDefinition.MESSAGE, 0, 0), +]; + +export const ModToolsUserModActionView: FC = props => +{ + const { user = null, onCloseClick = null } = props; + const [ selectedTopic, setSelectedTopic ] = useState(-1); + const [ selectedAction, setSelectedAction ] = useState(-1); + const [ message, setMessage ] = useState(''); + const { cfhCategories = null, settings = null } = useModTools(); + const { simpleAlert = null } = useNotification(); + + const topics = useMemo(() => + { + const values: CallForHelpTopicData[] = []; + + if(cfhCategories && cfhCategories.length) + { + for(const category of cfhCategories) + { + for(const topic of category.topics) values.push(topic); + } + } + + return values; + }, [ cfhCategories ]); + + const sendAlert = (message: string) => simpleAlert(message, NotificationAlertType.DEFAULT, null, null, 'Error'); + + const sendDefaultSanction = () => + { + let errorMessage: string = null; + + const category = topics[selectedTopic]; + + if(selectedTopic === -1) errorMessage = 'You must select a CFH topic'; + + if(errorMessage) return sendAlert(errorMessage); + + const messageOrDefault = (message.trim().length === 0) ? LocalizeText(`help.cfh.topic.${ category.id }`) : message; + + SendMessageComposer(new DefaultSanctionMessageComposer(user.userId, selectedTopic, messageOrDefault)); + + onCloseClick(); + }; + + const sendSanction = () => + { + let errorMessage: string = null; + + const category = topics[selectedTopic]; + const sanction = MOD_ACTION_DEFINITIONS[selectedAction]; + + if((selectedTopic === -1) || (selectedAction === -1)) errorMessage = 'You must select a CFH topic and Sanction'; + else if(!settings || !settings.cfhPermission) errorMessage = 'You do not have permission to do this'; + else if(!category) errorMessage = 'You must select a CFH topic'; + else if(!sanction) errorMessage = 'You must select a sanction'; + + if(errorMessage) + { + sendAlert(errorMessage); + + return; + } + + const messageOrDefault = (message.trim().length === 0) ? LocalizeText(`help.cfh.topic.${ category.id }`) : message; + + switch(sanction.actionType) + { + case ModActionDefinition.ALERT: { + if(!settings.alertPermission) + { + sendAlert('You have insufficient permissions'); + + return; + } + + SendMessageComposer(new ModAlertMessageComposer(user.userId, messageOrDefault, category.id)); + break; + } + case ModActionDefinition.MUTE: + SendMessageComposer(new ModMuteMessageComposer(user.userId, messageOrDefault, category.id)); + break; + case ModActionDefinition.BAN: { + if(!settings.banPermission) + { + sendAlert('You have insufficient permissions'); + + return; + } + + SendMessageComposer(new ModBanMessageComposer(user.userId, messageOrDefault, category.id, selectedAction, (sanction.actionId === 106))); + break; + } + case ModActionDefinition.KICK: { + if(!settings.kickPermission) + { + sendAlert('You have insufficient permissions'); + return; + } + + SendMessageComposer(new ModKickMessageComposer(user.userId, messageOrDefault, category.id)); + break; + } + case ModActionDefinition.TRADE_LOCK: { + const numSeconds = (sanction.actionLengthHours * 60); + + SendMessageComposer(new ModTradingLockMessageComposer(user.userId, messageOrDefault, numSeconds, category.id)); + break; + } + case ModActionDefinition.MESSAGE: { + if(message.trim().length === 0) + { + sendAlert('Please write a message to user'); + + return; + } + + SendMessageComposer(new ModMessageMessageComposer(user.userId, message, category.id)); + break; + } + } + + onCloseClick(); + }; + + if(!user) return null; + + return ( + + onCloseClick() } /> + + + +
+ Optional message type, overrides default + + + + + ); +}; diff --git a/Coolui v3 test/src/components/mod-tools/views/user/ModToolsUserView.tsx b/Coolui v3 test/src/components/mod-tools/views/user/ModToolsUserView.tsx new file mode 100644 index 0000000000..6f65700c58 --- /dev/null +++ b/Coolui v3 test/src/components/mod-tools/views/user/ModToolsUserView.tsx @@ -0,0 +1,156 @@ +import { CreateLinkEvent, GetModeratorUserInfoMessageComposer, ModeratorUserInfoData, ModeratorUserInfoEvent } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useMemo, useState } from 'react'; +import { FriendlyTime, LocalizeText, SendMessageComposer } from '../../../../api'; +import { Button, Column, DraggableWindowPosition, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; +import { useMessageEvent } from '../../../../hooks'; +import { ModToolsUserModActionView } from './ModToolsUserModActionView'; +import { ModToolsUserRoomVisitsView } from './ModToolsUserRoomVisitsView'; +import { ModToolsUserSendMessageView } from './ModToolsUserSendMessageView'; + +interface ModToolsUserViewProps +{ + userId: number; + onCloseClick: () => void; +} + +export const ModToolsUserView: FC = props => +{ + const { onCloseClick = null, userId = null } = props; + const [ userInfo, setUserInfo ] = useState(null); + const [ sendMessageVisible, setSendMessageVisible ] = useState(false); + const [ modActionVisible, setModActionVisible ] = useState(false); + const [ roomVisitsVisible, setRoomVisitsVisible ] = useState(false); + + const userProperties = useMemo(() => + { + if(!userInfo) return null; + + return [ + { + localeKey: 'modtools.userinfo.userName', + value: userInfo.userName, + showOnline: true + }, + { + localeKey: 'modtools.userinfo.cfhCount', + value: userInfo.cfhCount.toString() + }, + { + localeKey: 'modtools.userinfo.abusiveCfhCount', + value: userInfo.abusiveCfhCount.toString() + }, + { + localeKey: 'modtools.userinfo.cautionCount', + value: userInfo.cautionCount.toString() + }, + { + localeKey: 'modtools.userinfo.banCount', + value: userInfo.banCount.toString() + }, + { + localeKey: 'modtools.userinfo.lastSanctionTime', + value: userInfo.lastSanctionTime + }, + { + localeKey: 'modtools.userinfo.tradingLockCount', + value: userInfo.tradingLockCount.toString() + }, + { + localeKey: 'modtools.userinfo.tradingExpiryDate', + value: userInfo.tradingExpiryDate + }, + { + localeKey: 'modtools.userinfo.minutesSinceLastLogin', + value: FriendlyTime.format(userInfo.minutesSinceLastLogin * 60, '.ago', 2) + }, + { + localeKey: 'modtools.userinfo.lastPurchaseDate', + value: userInfo.lastPurchaseDate + }, + { + localeKey: 'modtools.userinfo.primaryEmailAddress', + value: userInfo.primaryEmailAddress + }, + { + localeKey: 'modtools.userinfo.identityRelatedBanCount', + value: userInfo.identityRelatedBanCount.toString() + }, + { + localeKey: 'modtools.userinfo.registrationAgeInMinutes', + value: FriendlyTime.format(userInfo.registrationAgeInMinutes * 60, '.ago', 2) + }, + { + localeKey: 'modtools.userinfo.userClassification', + value: userInfo.userClassification + } + ]; + }, [ userInfo ]); + + useMessageEvent(ModeratorUserInfoEvent, event => + { + const parser = event.getParser(); + + if(!parser || parser.data.userId !== userId) return; + + setUserInfo(parser.data); + }); + + useEffect(() => + { + SendMessageComposer(new GetModeratorUserInfoMessageComposer(userId)); + }, [ userId ]); + + if(!userInfo) return null; + + return ( + <> + + onCloseClick() } /> + + + + + + { userProperties.map( (property, index) => + { + + return ( + + + + + ); + }) } + +
{ LocalizeText(property.localeKey) } + { property.value } + { property.showOnline && + } +
+
+ + + + + + +
+
+
+ { sendMessageVisible && + setSendMessageVisible(false) } /> } + { modActionVisible && + setModActionVisible(false) } /> } + { roomVisitsVisible && + setRoomVisitsVisible(false) } /> } + + ); +}; diff --git a/Coolui v3 test/src/components/navigator/NavigatorView.tsx b/Coolui v3 test/src/components/navigator/NavigatorView.tsx new file mode 100644 index 0000000000..813c390e5e --- /dev/null +++ b/Coolui v3 test/src/components/navigator/NavigatorView.tsx @@ -0,0 +1,240 @@ +import { NitroCard } from '@layout/NitroCard'; +import { AddLinkEventTracker, ConvertGlobalRoomIdMessageComposer, HabboWebTools, ILinkEventTracker, LegacyExternalInterface, NavigatorInitComposer, NavigatorSearchComposer, RemoveLinkEventTracker, RoomSessionEvent } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useEffect, useRef, useState } from 'react'; +import { FaPlus } from 'react-icons/fa'; +import { LocalizeText, SendMessageComposer, TryVisitRoom } from '../../api'; +import { useNavigator, useNitroEvent } from '../../hooks'; +import { NavigatorDoorStateView } from './views/NavigatorDoorStateView'; +import { NavigatorRoomCreatorView } from './views/NavigatorRoomCreatorView'; +import { NavigatorRoomInfoView } from './views/NavigatorRoomInfoView'; +import { NavigatorRoomLinkView } from './views/NavigatorRoomLinkView'; +import { NavigatorRoomSettingsView } from './views/room-settings/NavigatorRoomSettingsView'; +import { NavigatorSearchResultView } from './views/search/NavigatorSearchResultView'; +import { NavigatorSearchView } from './views/search/NavigatorSearchView'; + +export const NavigatorView: FC<{}> = props => +{ + const [ isVisible, setIsVisible ] = useState(false); + const [ isReady, setIsReady ] = useState(false); + const [ isCreatorOpen, setCreatorOpen ] = useState(false); + const [ isRoomInfoOpen, setRoomInfoOpen ] = useState(false); + const [ isRoomLinkOpen, setRoomLinkOpen ] = useState(false); + const [ isLoading, setIsLoading ] = useState(false); + const [ needsInit, setNeedsInit ] = useState(true); + const [ needsSearch, setNeedsSearch ] = useState(false); + const { searchResult = null, topLevelContext = null, topLevelContexts = null, navigatorData = null } = useNavigator(); + const pendingSearch = useRef<{ value: string, code: string }>(null); + const elementRef = useRef(); + + useNitroEvent(RoomSessionEvent.CREATED, event => + { + setIsVisible(false); + setCreatorOpen(false); + }); + + const sendSearch = useCallback((searchValue: string, contextCode: string) => + { + setCreatorOpen(false); + + SendMessageComposer(new NavigatorSearchComposer(contextCode, searchValue)); + + setIsLoading(true); + }, []); + + const reloadCurrentSearch = useCallback(() => + { + if(!isReady) + { + setNeedsSearch(true); + + return; + } + + if(pendingSearch.current) + { + sendSearch(pendingSearch.current.value, pendingSearch.current.code); + + pendingSearch.current = null; + + return; + } + + if(searchResult) + { + sendSearch(searchResult.data, searchResult.code); + + return; + } + + if(!topLevelContext) return; + + sendSearch('', topLevelContext.code); + }, [ isReady, searchResult, topLevelContext, sendSearch ]); + + useEffect(() => + { + const linkTracker: ILinkEventTracker = { + linkReceived: (url: string) => + { + const parts = url.split('/'); + + if(parts.length < 2) return; + + switch(parts[1]) + { + case 'show': { + setIsVisible(true); + setNeedsSearch(true); + return; + } + case 'hide': + setIsVisible(false); + return; + case 'toggle': { + if(isVisible) + { + setIsVisible(false); + + return; + } + + setIsVisible(true); + setNeedsSearch(true); + return; + } + case 'toggle-room-info': + setRoomInfoOpen(value => !value); + return; + case 'toggle-room-link': + setRoomLinkOpen(value => !value); + return; + case 'goto': + if(parts.length <= 2) return; + + switch(parts[2]) + { + case 'home': + if(navigatorData.homeRoomId <= 0) return; + + TryVisitRoom(navigatorData.homeRoomId); + break; + default: { + const roomId = parseInt(parts[2]); + + TryVisitRoom(roomId); + } + } + return; + case 'create': + setIsVisible(true); + setCreatorOpen(true); + return; + case 'search': + if(parts.length > 2) + { + const topLevelContextCode = parts[2]; + + let searchValue = ''; + + if(parts.length > 3) searchValue = parts[3]; + + pendingSearch.current = { value: searchValue, code: topLevelContextCode }; + + setIsVisible(true); + setNeedsSearch(true); + } + return; + } + }, + eventUrlPrefix: 'navigator/' + }; + + AddLinkEventTracker(linkTracker); + + return () => RemoveLinkEventTracker(linkTracker); + }, [ isVisible, navigatorData ]); + + useEffect(() => + { + if(!searchResult) return; + + setIsLoading(false); + + if(elementRef && elementRef.current) elementRef.current.scrollTop = 0; + }, [ searchResult ]); + + useEffect(() => + { + if(!isVisible || !isReady || !needsSearch) return; + + reloadCurrentSearch(); + + setNeedsSearch(false); + }, [ isVisible, isReady, needsSearch, reloadCurrentSearch ]); + + useEffect(() => + { + if(isReady || !topLevelContext) return; + + setIsReady(true); + }, [ isReady, topLevelContext ]); + + useEffect(() => + { + if(!isVisible || !needsInit) return; + + SendMessageComposer(new NavigatorInitComposer()); + + setNeedsInit(false); + }, [ isVisible, needsInit ]); + + useEffect(() => + { + LegacyExternalInterface.addCallback(HabboWebTools.OPENROOM, (k: string, _arg_2: boolean = false, _arg_3: string = null) => SendMessageComposer(new ConvertGlobalRoomIdMessageComposer(k))); + }, []); + + return ( + <> + { isVisible && + + setIsVisible(false) } /> + + { topLevelContexts && (topLevelContexts.length > 0) && topLevelContexts.map((context, index) => + { + return ( + sendSearch('', context.code) }> + { LocalizeText(('navigator.toplevelview.' + context.code)) } + + ); + }) } + setCreatorOpen(true) }> + + + + + { !isCreatorOpen && + <> + +
+ { (searchResult && searchResult.results.map((result, index) => )) } +
+ } + { isCreatorOpen && } +
+
} + + { isRoomInfoOpen && setRoomInfoOpen(false) } /> } + { isRoomLinkOpen && setRoomLinkOpen(false) } /> } + + + ); +}; diff --git a/Coolui v3 test/src/components/navigator/views/NavigatorDoorStateView.tsx b/Coolui v3 test/src/components/navigator/views/NavigatorDoorStateView.tsx new file mode 100644 index 0000000000..0dcaa45c99 --- /dev/null +++ b/Coolui v3 test/src/components/navigator/views/NavigatorDoorStateView.tsx @@ -0,0 +1,111 @@ +import { FC, useEffect, useState } from 'react'; +import { CreateRoomSession, DoorStateType, GoToDesktop, LocalizeText } from '../../../api'; +import { Button, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../common'; +import { useNavigator } from '../../../hooks'; +import { NitroInput } from '../../../layout'; + +const VISIBLE_STATES = [ DoorStateType.START_DOORBELL, DoorStateType.STATE_WAITING, DoorStateType.STATE_NO_ANSWER, DoorStateType.START_PASSWORD, DoorStateType.STATE_WRONG_PASSWORD ]; +const DOORBELL_STATES = [ DoorStateType.START_DOORBELL, DoorStateType.STATE_WAITING, DoorStateType.STATE_NO_ANSWER ]; +const PASSWORD_STATES = [ DoorStateType.START_PASSWORD, DoorStateType.STATE_WRONG_PASSWORD ]; + +export const NavigatorDoorStateView: FC<{}> = props => +{ + const [ password, setPassword ] = useState(''); + const { doorData = null, setDoorData = null } = useNavigator(); + + const onClose = () => + { + if(doorData && (doorData.state === DoorStateType.STATE_WAITING)) GoToDesktop(); + + setDoorData(null); + }; + + const ring = () => + { + if(!doorData || !doorData.roomInfo) return; + + CreateRoomSession(doorData.roomInfo.roomId); + + setDoorData(prevValue => + { + const newValue = { ...prevValue }; + + newValue.state = DoorStateType.STATE_PENDING_SERVER; + + return newValue; + }); + }; + + const tryEntering = () => + { + if(!doorData || !doorData.roomInfo) return; + + CreateRoomSession(doorData.roomInfo.roomId, password); + + setDoorData(prevValue => + { + const newValue = { ...prevValue }; + + newValue.state = DoorStateType.STATE_PENDING_SERVER; + + return newValue; + }); + }; + + useEffect(() => + { + if(!doorData || (doorData.state !== DoorStateType.STATE_NO_ANSWER)) return; + + GoToDesktop(); + }, [ doorData ]); + + if(!doorData || (doorData.state === DoorStateType.NONE) || (VISIBLE_STATES.indexOf(doorData.state) === -1)) return null; + + const isDoorbell = (DOORBELL_STATES.indexOf(doorData.state) >= 0); + + return ( + + + +
+ { doorData && doorData.roomInfo && doorData.roomInfo.roomName } + { (doorData.state === DoorStateType.START_DOORBELL) && + { LocalizeText('navigator.doorbell.info') } } + { (doorData.state === DoorStateType.STATE_WAITING) && + { LocalizeText('navigator.doorbell.waiting') } } + { (doorData.state === DoorStateType.STATE_NO_ANSWER) && + { LocalizeText('navigator.doorbell.no.answer') } } + { (doorData.state === DoorStateType.START_PASSWORD) && + { LocalizeText('navigator.password.info') } } + { (doorData.state === DoorStateType.STATE_WRONG_PASSWORD) && + { LocalizeText('navigator.password.retryinfo') } } +
+ { isDoorbell && +
+ { (doorData.state === DoorStateType.START_DOORBELL) && + } + +
} + { !isDoorbell && + <> +
+ { LocalizeText('navigator.password.enter') } + setPassword(event.target.value) } /> +
+
+ + +
+ } +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/navigator/views/NavigatorRoomCreatorView.tsx b/Coolui v3 test/src/components/navigator/views/NavigatorRoomCreatorView.tsx new file mode 100644 index 0000000000..8469af36f6 --- /dev/null +++ b/Coolui v3 test/src/components/navigator/views/NavigatorRoomCreatorView.tsx @@ -0,0 +1,123 @@ + +import { CreateFlatMessageComposer, HabboClubLevelEnum } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useState } from 'react'; +import { GetClubMemberLevel, GetConfigurationValue, IRoomModel, LocalizeText, SendMessageComposer } from '../../../api'; +import { Button, Flex, Grid, LayoutCurrencyIcon, LayoutGridItem, Text } from '../../../common'; +import { useNavigator } from '../../../hooks'; +import { NitroInput } from '../../../layout'; + +export const NavigatorRoomCreatorView: FC<{}> = props => +{ + const [ maxVisitorsList, setMaxVisitorsList ] = useState(null); + const [ name, setName ] = useState(null); + const [ description, setDescription ] = useState(null); + const [ category, setCategory ] = useState(null); + const [ visitorsCount, setVisitorsCount ] = useState(null); + const [ tradesSetting, setTradesSetting ] = useState(0); + const [ roomModels, setRoomModels ] = useState([]); + const [ selectedModelName, setSelectedModelName ] = useState(''); + const { categories = null } = useNavigator(); + + const hcDisabled = GetConfigurationValue('hc.disabled', false); + + const getRoomModelImage = (name: string) => GetConfigurationValue('images.url') + `/navigator/models/model_${ name }.png`; + + const selectModel = (model: IRoomModel, index: number) => + { + if(!model || (model.clubLevel > GetClubMemberLevel())) return; + + setSelectedModelName(roomModels[index].name); + }; + + const createRoom = () => + { + SendMessageComposer(new CreateFlatMessageComposer(name, description, 'model_' + selectedModelName, Number(category), Number(visitorsCount), tradesSetting)); + }; + + useEffect(() => + { + if(!maxVisitorsList) + { + const list = []; + + for(let i = 10; i <= 100; i = i + 10) list.push(i); + + setMaxVisitorsList(list); + setVisitorsCount(list[0]); + } + }, [ maxVisitorsList ]); + + useEffect(() => + { + if(categories && categories.length) setCategory(categories[0].id); + }, [ categories ]); + + useEffect(() => + { + const models = GetConfigurationValue('navigator.room.models'); + + if(models && models.length) + { + setRoomModels(models); + setSelectedModelName(models[0].name); + } + }, []); + + return ( +
+ +
+
+ { LocalizeText('navigator.createroom.roomnameinfo') } + setName(event.target.value) } /> +
+
+ { LocalizeText('navigator.createroom.roomdescinfo') } + +
+
+ + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/FurnitureStackHeightView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/FurnitureStackHeightView.tsx new file mode 100644 index 0000000000..741a35eee8 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/FurnitureStackHeightView.tsx @@ -0,0 +1,58 @@ +import { FurnitureStackHeightComposer } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { LocalizeText, SendMessageComposer } from '../../../../api'; +import { Button, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; +import { useFurnitureStackHeightWidget } from '../../../../hooks'; + +export const FurnitureStackHeightView: FC<{}> = props => +{ + const { objectId = -1, height = 0, maxHeight = 40, onClose = null, updateHeight = null } = useFurnitureStackHeightWidget(); + const [ tempHeight, setTempHeight ] = useState(''); + + const updateTempHeight = (value: string) => + { + setTempHeight(value); + + const newValue = parseFloat(value); + + if(isNaN(newValue) || (newValue === height)) return; + + updateHeight(newValue); + }; + + useEffect(() => + { + setTempHeight(height.toString()); + }, [ height ]); + + if(objectId === -1) return null; + + return ( + + + + { LocalizeText('widget.custom.stack.height.text') } +
+
{ state.valueNow }
} + step={ 0.01 } + value={ height } + onChange={ event => updateHeight(event) } /> + updateTempHeight(event.target.value) } /> +
+
+ + +
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/FurnitureStickieView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/FurnitureStickieView.tsx new file mode 100644 index 0000000000..fec4845484 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/FurnitureStickieView.tsx @@ -0,0 +1,66 @@ +import { FC, useEffect, useState } from 'react'; +import { ColorUtils } from '../../../../api'; +import { DraggableWindow, DraggableWindowPosition } from '../../../../common'; +import { useFurnitureStickieWidget } from '../../../../hooks'; + +const STICKIE_COLORS = [ '9CCEFF', 'FF9CFF', '9CFF9C', 'FFFF33' ]; +const STICKIE_COLOR_NAMES = [ 'blue', 'pink', 'green', 'yellow' ]; +const STICKIE_TYPES = [ 'post_it', 'post_it_shakesp', 'post_it_dreams', 'post_it_xmas', 'post_it_vd', 'post_it_juninas' ]; +const STICKIE_TYPE_NAMES = [ 'post_it', 'shakesp', 'dreams', 'christmas', 'heart', 'juninas' ]; + +const getStickieColorName = (color: string) => +{ + let index = STICKIE_COLORS.indexOf(color); + + if(index === -1) index = 0; + + return STICKIE_COLOR_NAMES[index]; +}; + +const getStickieTypeName = (type: string) => +{ + let index = STICKIE_TYPES.indexOf(type); + + if(index === -1) index = 0; + + return STICKIE_TYPE_NAMES[index]; +}; + +export const FurnitureStickieView: FC<{}> = props => +{ + const { objectId = -1, color = '0', text = '', type = '', canModify = false, updateColor = null, updateText = null, trash = null, onClose = null } = useFurnitureStickieWidget(); + const [ isEditing, setIsEditing ] = useState(false); + + useEffect(() => + { + setIsEditing(false); + }, [ objectId, color, text, type ]); + + if(objectId === -1) return null; + + return ( + +
+
+
+ { canModify && + <> +
+ { type == 'post_it' && + <> + { STICKIE_COLORS.map(color => + { + return
updateColor(color) } />; + }) } + } + } +
+
+
+
+ { (!isEditing || !canModify) ?
(canModify && setIsEditing(true)) }>{ text }
: } +
+
+ + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/FurnitureTrophyView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/FurnitureTrophyView.tsx new file mode 100644 index 0000000000..2e08af0658 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/FurnitureTrophyView.tsx @@ -0,0 +1,12 @@ +import { FC } from 'react'; +import { LayoutTrophyView } from '../../../../common'; +import { useFurnitureTrophyWidget } from '../../../../hooks'; + +export const FurnitureTrophyView: FC<{}> = props => +{ + const { objectId = -1, color = '1', senderName = '', date = '', message = '', onClose = null } = useFurnitureTrophyWidget(); + + if(objectId === -1) return null; + + return ; +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx new file mode 100644 index 0000000000..8c6dba25e6 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx @@ -0,0 +1,47 @@ +import { FC } from 'react'; +import { FurnitureBackgroundColorView } from './FurnitureBackgroundColorView'; +import { FurnitureBadgeDisplayView } from './FurnitureBadgeDisplayView'; +import { FurnitureCraftingView } from './FurnitureCraftingView'; +import { FurnitureDimmerView } from './FurnitureDimmerView'; +import { FurnitureExchangeCreditView } from './FurnitureExchangeCreditView'; +import { FurnitureExternalImageView } from './FurnitureExternalImageView'; +import { FurnitureFriendFurniView } from './FurnitureFriendFurniView'; +import { FurnitureGiftOpeningView } from './FurnitureGiftOpeningView'; +import { FurnitureHighScoreView } from './FurnitureHighScoreView'; +import { FurnitureInternalLinkView } from './FurnitureInternalLinkView'; +import { FurnitureMannequinView } from './FurnitureMannequinView'; +import { FurnitureRoomLinkView } from './FurnitureRoomLinkView'; +import { FurnitureSpamWallPostItView } from './FurnitureSpamWallPostItView'; +import { FurnitureStackHeightView } from './FurnitureStackHeightView'; +import { FurnitureStickieView } from './FurnitureStickieView'; +import { FurnitureTrophyView } from './FurnitureTrophyView'; +import { FurnitureYoutubeDisplayView } from './FurnitureYoutubeDisplayView'; +import { FurnitureContextMenuView } from './context-menu/FurnitureContextMenuView'; +import { FurniturePlaylistEditorWidgetView } from './playlist-editor/FurniturePlaylistEditorWidgetView'; + +export const FurnitureWidgetsView: FC<{}> = props => +{ + return ( + <> + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/FurnitureYoutubeDisplayView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/FurnitureYoutubeDisplayView.tsx new file mode 100644 index 0000000000..0d8dd5e32d --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/FurnitureYoutubeDisplayView.tsx @@ -0,0 +1,109 @@ +import { FC, useEffect, useState } from 'react'; +import YouTube, { Options } from 'react-youtube'; +import { YouTubePlayer } from 'youtube-player/dist/types'; +import { LocalizeText, YoutubeVideoPlaybackStateEnum } from '../../../../api'; +import { AutoGrid, AutoGridProps, LayoutGridItem, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; +import { useFurnitureYoutubeWidget } from '../../../../hooks'; + +interface FurnitureYoutubeDisplayViewProps extends AutoGridProps +{ + +} + +export const FurnitureYoutubeDisplayView: FC<{}> = FurnitureYoutubeDisplayViewProps => +{ + const [ player, setPlayer ] = useState(null); + const { objectId = -1, videoId = null, videoStart = 0, videoEnd = 0, currentVideoState = null, selectedVideo = null, playlists = [], onClose = null, previous = null, next = null, pause = null, play = null, selectVideo = null } = useFurnitureYoutubeWidget(); + + const onStateChange = (event: { target: YouTubePlayer; data: number }) => + { + setPlayer(event.target); + + if(objectId === -1) return; + + switch(event.target.getPlayerState()) + { + case -1: + case 1: + if(currentVideoState === 2) + { + //event.target.pauseVideo(); + } + + if(currentVideoState !== 1) play(); + return; + case 2: + if(currentVideoState !== 2) pause(); + } + }; + + useEffect(() => + { + if((currentVideoState === null) || !player) return; + + if((currentVideoState === YoutubeVideoPlaybackStateEnum.PLAYING) && (player.getPlayerState() !== YoutubeVideoPlaybackStateEnum.PLAYING)) + { + player.playVideo(); + + return; + } + + if((currentVideoState === YoutubeVideoPlaybackStateEnum.PAUSED) && (player.getPlayerState() !== YoutubeVideoPlaybackStateEnum.PAUSED)) + { + player.pauseVideo(); + + return; + } + }, [ currentVideoState, player ]); + + if(objectId === -1) return null; + + const youtubeOptions: Options = { + height: '375', + width: '500', + playerVars: { + autoplay: 1, + disablekb: 1, + controls: 0, + origin: window.origin, + modestbranding: 1, + start: videoStart, + end: videoEnd + } + }; + + return ( + + + +
+
+ { (videoId && videoId.length > 0) && + setPlayer(event.target) } onStateChange={ onStateChange } /> + } + { (!videoId || videoId.length === 0) && +
{ LocalizeText('widget.furni.video_viewer.no_videos') }
+ } +
+
+ + + + +
{ LocalizeText('widget.furni.video_viewer.playlists') }
+ + { playlists && playlists.map((entry, index) => + { + return ( + selectVideo(entry.video) }> + { entry.title } + + ); + }) } + +
+
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/context-menu/EffectBoxConfirmView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/context-menu/EffectBoxConfirmView.tsx new file mode 100644 index 0000000000..a818152b3f --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/context-menu/EffectBoxConfirmView.tsx @@ -0,0 +1,40 @@ +import { FC } from 'react'; +import { LocalizeText } from '../../../../../api'; +import { Button, Column, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../../common'; +import { useRoom } from '../../../../../hooks'; + +interface EffectBoxConfirmViewProps +{ + objectId: number; + onClose: () => void; +} + +export const EffectBoxConfirmView: FC = props => +{ + const { objectId = -1, onClose = null } = props; + const { roomSession = null } = useRoom(); + + const useProduct = () => + { + roomSession.useMultistateItem(objectId); + + onClose(); + }; + + return ( + + + +
+ + { LocalizeText('effectbox.header.description') } +
+ + +
+
+
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx new file mode 100644 index 0000000000..7976d99ce9 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx @@ -0,0 +1,130 @@ +import { ContextMenuEnum, CustomUserNotificationMessageEvent, GetSessionDataManager, RoomObjectCategory } from '@nitrots/nitro-renderer'; +import { FC } from 'react'; +import { GetGroupInformation, LocalizeText } from '../../../../../api'; +import { EFFECTBOX_OPEN, GROUP_FURNITURE, MONSTERPLANT_SEED_CONFIRMATION, MYSTERYTROPHY_OPEN_DIALOG, PURCHASABLE_CLOTHING_CONFIRMATION, useFurnitureContextMenuWidget, useMessageEvent, useNotification } from '../../../../../hooks'; +import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView'; +import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView'; +import { ContextMenuView } from '../../context-menu/ContextMenuView'; +import { FurnitureMysteryBoxOpenDialogView } from '../FurnitureMysteryBoxOpenDialogView'; +import { FurnitureMysteryTrophyOpenDialogView } from '../FurnitureMysteryTrophyOpenDialogView'; +import { EffectBoxConfirmView } from './EffectBoxConfirmView'; +import { MonsterPlantSeedConfirmView } from './MonsterPlantSeedConfirmView'; +import { PurchasableClothingConfirmView } from './PurchasableClothingConfirmView'; + +export const FurnitureContextMenuView: FC<{}> = props => +{ + const { closeConfirm = null, processAction = null, onClose = null, objectId = -1, mode = null, confirmMode = null, confirmingObjectId = -1, groupData = null, isGroupMember = false, objectOwnerId = -1 } = useFurnitureContextMenuWidget(); + const { simpleAlert = null } = useNotification(); + + useMessageEvent(CustomUserNotificationMessageEvent, event => + { + const parser = event.getParser(); + + if(!parser) return; + + // HOPPER_NO_COSTUME = 1; HOPPER_NO_HC = 2; GATE_NO_HC = 3; STARS_NOT_CANDIDATE = 4 (not coded in Emulator); STARS_NOT_ENOUGH_USERS = 5 (not coded in Emulator); + + switch(parser.count) + { + case 1: + simpleAlert(LocalizeText('costumehopper.costumerequired.bodytext'), null, 'catalog/open/temporary_effects' , LocalizeText('costumehopper.costumerequired.buy'), LocalizeText('costumehopper.costumerequired.header'), null); + break; + case 2: + simpleAlert(LocalizeText('viphopper.viprequired.bodytext'), null, 'catalog/open/habbo_club' , LocalizeText('viprequired.buy.vip'), LocalizeText('viprequired.header'), null); + break; + case 3: + simpleAlert(LocalizeText('gate.viprequired.bodytext'), null, 'catalog/open/habbo_club' , LocalizeText('viprequired.buy.vip'), LocalizeText('gate.viprequired.title'), null); + break; + } + }); + + const isOwner = GetSessionDataManager().userId === objectOwnerId; + + return ( + <> + { (confirmMode === MONSTERPLANT_SEED_CONFIRMATION) && + } + { (confirmMode === PURCHASABLE_CLOTHING_CONFIRMATION) && + } + { (confirmMode === EFFECTBOX_OPEN) && + } + { (confirmMode === MYSTERYTROPHY_OPEN_DIALOG) && + } + + { (objectId >= 0) && mode && + + { (mode === ContextMenuEnum.FRIEND_FURNITURE) && + <> + + { LocalizeText('friendfurni.context.title') } + + processAction('use_friend_furni') }> + { LocalizeText('friendfurni.context.use') } + + } + { (mode === ContextMenuEnum.MONSTERPLANT_SEED) && + <> + + { LocalizeText('furni.mnstr_seed.name') } + + processAction('use_monsterplant_seed') }> + { LocalizeText('widget.monsterplant_seed.button.use') } + + } + { (mode === ContextMenuEnum.RANDOM_TELEPORT) && + <> + + { LocalizeText('furni.random_teleport.name') } + + processAction('use_random_teleport') }> + { LocalizeText('widget.random_teleport.button.use') } + + } + { (mode === ContextMenuEnum.PURCHASABLE_CLOTHING) && + <> + + { LocalizeText('furni.generic_usable.name') } + + processAction('use_purchaseable_clothing') }> + { LocalizeText('widget.generic_usable.button.use') } + + } + { (mode === ContextMenuEnum.MYSTERY_BOX) && + <> + + { LocalizeText('mysterybox.context.title') } + + processAction('use_mystery_box') }> + { LocalizeText('mysterybox.context.' + ((isOwner) ? 'owner' : 'other') + '.use') } + + } + { (mode === ContextMenuEnum.MYSTERY_TROPHY) && + <> + + { LocalizeText('mysterytrophy.header.title') } + + processAction('use_mystery_trophy') }> + { LocalizeText('friendfurni.context.use') } + + } + { (mode === GROUP_FURNITURE) && groupData && + <> + GetGroupInformation(groupData.guildId) }> + { groupData.guildName } + + { !isGroupMember && + processAction('join_group') }> + { LocalizeText('widget.furniture.button.join.group') } + } + processAction('go_to_group_homeroom') }> + { LocalizeText('widget.furniture.button.go.to.group.home.room') } + + { groupData.guildHasReadableForum && + processAction('open_forum') }> + { LocalizeText('widget.furniture.button.open_group_forum') } + } + } + } + + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/context-menu/MonsterPlantSeedConfirmView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/context-menu/MonsterPlantSeedConfirmView.tsx new file mode 100644 index 0000000000..4a5ed984ee --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/context-menu/MonsterPlantSeedConfirmView.tsx @@ -0,0 +1,85 @@ +import { IFurnitureData, RoomObjectCategory } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useState } from 'react'; +import { FurniCategory, GetFurnitureDataForRoomObject, LocalizeText } from '../../../../../api'; +import { Button, Column, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../../common'; +import { useRoom } from '../../../../../hooks'; + +interface MonsterPlantSeedConfirmViewProps +{ + objectId: number; + onClose: () => void; +} + +const MODE_DEFAULT: number = -1; +const MODE_MONSTERPLANT_SEED: number = 0; + +export const MonsterPlantSeedConfirmView: FC = props => +{ + const { objectId = -1, onClose = null } = props; + const [ furniData, setFurniData ] = useState(null); + const [ mode, setMode ] = useState(MODE_DEFAULT); + const { roomSession = null } = useRoom(); + + const useProduct = () => + { + roomSession.useMultistateItem(objectId); + + onClose(); + }; + + useEffect(() => + { + if(!roomSession || (objectId === -1)) return; + + const furniData = GetFurnitureDataForRoomObject(roomSession.roomId, objectId, RoomObjectCategory.FLOOR); + + if(!furniData) return; + + setFurniData(furniData); + + let mode = MODE_DEFAULT; + + switch(furniData.specialType) + { + case FurniCategory.MONSTERPLANT_SEED: + mode = MODE_MONSTERPLANT_SEED; + break; + } + + if(mode === MODE_DEFAULT) + { + onClose(); + + return; + } + + setMode(mode); + }, [ roomSession, objectId, onClose ]); + + if(mode === MODE_DEFAULT) return null; + + return ( + + + +
+
+
+
+
+
+
+ + { LocalizeText('useproduct.widget.text.plant_seed', [ 'productName' ], [ furniData.name ]) } + { LocalizeText('useproduct.widget.info.plant_seed') } + +
+ + +
+
+
+ + + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/context-menu/PurchasableClothingConfirmView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/context-menu/PurchasableClothingConfirmView.tsx new file mode 100644 index 0000000000..85a6f8062e --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/context-menu/PurchasableClothingConfirmView.tsx @@ -0,0 +1,104 @@ +import { AvatarFigurePartType, GetAvatarRenderManager, GetSessionDataManager, RedeemItemClothingComposer, RoomObjectCategory, UserFigureComposer } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useState } from 'react'; +import { FurniCategory, GetFurnitureDataForRoomObject, LocalizeText, SendMessageComposer } from '../../../../../api'; +import { Button, Column, LayoutAvatarImageView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../../common'; +import { useRoom } from '../../../../../hooks'; + +interface PurchasableClothingConfirmViewProps +{ + objectId: number; + onClose: () => void; +} + +const MODE_DEFAULT: number = -1; +const MODE_PURCHASABLE_CLOTHING: number = 0; + +export const PurchasableClothingConfirmView: FC = props => +{ + const { objectId = -1, onClose = null } = props; + const [ mode, setMode ] = useState(MODE_DEFAULT); + const [ gender, setGender ] = useState(AvatarFigurePartType.MALE); + const [ newFigure, setNewFigure ] = useState(null); + const { roomSession = null } = useRoom(); + + const useProduct = () => + { + SendMessageComposer(new RedeemItemClothingComposer(objectId)); + SendMessageComposer(new UserFigureComposer(gender, newFigure)); + + onClose(); + }; + + useEffect(() => + { + let mode = MODE_DEFAULT; + + const figure = GetSessionDataManager().figure; + const gender = GetSessionDataManager().gender; + const validSets: number[] = []; + + if(roomSession && (objectId >= 0)) + { + const furniData = GetFurnitureDataForRoomObject(roomSession.roomId, objectId, RoomObjectCategory.FLOOR); + + if(furniData) + { + switch(furniData.specialType) + { + case FurniCategory.FIGURE_PURCHASABLE_SET: + mode = MODE_PURCHASABLE_CLOTHING; + + const setIds = furniData.customParams.split(',').map(part => parseInt(part)); + + for(const setId of setIds) + { + if(GetAvatarRenderManager().isValidFigureSetForGender(setId, gender)) validSets.push(setId); + } + + break; + } + } + } + + if(mode === MODE_DEFAULT) + { + onClose(); + + return; + } + + setGender(gender); + setNewFigure(GetAvatarRenderManager().getFigureStringWithFigureIds(figure, gender, validSets)); + + // if owns clothing, change to it + + setMode(mode); + }, [ roomSession, objectId, onClose ]); + + if(mode === MODE_DEFAULT) return null; + + return ( + + + +
+
+
+ +
+
+
+ + { LocalizeText('useproduct.widget.text.bind_clothing') } + { LocalizeText('useproduct.widget.info.bind_clothing') } + +
+ + +
+
+
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/playlist-editor/DiskInventoryView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/playlist-editor/DiskInventoryView.tsx new file mode 100644 index 0000000000..7550af9bf4 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/playlist-editor/DiskInventoryView.tsx @@ -0,0 +1,94 @@ +import { CreateLinkEvent, GetSoundManager, IAdvancedMap, MusicPriorities } from '@nitrots/nitro-renderer'; +import { FC, MouseEvent, useCallback, useEffect, useState } from 'react'; +import { CatalogPageName, GetConfigurationValue, GetDiskColor, LocalizeText } from '../../../../../api'; +import { AutoGrid, Button, Flex, LayoutGridItem, Text } from '../../../../../common'; + +export interface DiskInventoryViewProps +{ + diskInventory: IAdvancedMap; + addToPlaylist: (diskId: number, slotNumber: number) => void; +} + +export const DiskInventoryView: FC = props => +{ + const { diskInventory = null, addToPlaylist = null } = props; + const [ selectedItem, setSelectedItem ] = useState(-1); + const [ previewSongId, setPreviewSongId ] = useState(-1); + + const previewSong = useCallback((event: MouseEvent, songId: number) => + { + event.stopPropagation(); + + setPreviewSongId(prevValue => (prevValue === songId) ? -1 : songId); + }, []); + + const addSong = useCallback((event: MouseEvent, diskId: number) => + { + event.stopPropagation(); + + addToPlaylist(diskId, GetSoundManager().musicController?.getRoomItemPlaylist()?.length); + }, [ addToPlaylist ]); + + const openCatalogPage = () => + { + CreateLinkEvent('catalog/open/' + CatalogPageName.TRAX_SONGS); + }; + + useEffect(() => + { + if(previewSongId === -1) return; + + GetSoundManager().musicController?.playSong(previewSongId, MusicPriorities.PRIORITY_SONG_PLAY, 0, 0, 0, 0); + + return () => + { + GetSoundManager().musicController?.stop(MusicPriorities.PRIORITY_SONG_PLAY); + }; + }, [ previewSongId ]); + + useEffect(() => + { + return () => setPreviewSongId(-1); + }, []); + + return (<> +
+ +

{ LocalizeText('playlist.editor.my.music') }

+
+
+ + { diskInventory && diskInventory.getKeys().map((key, index) => + { + const diskId = diskInventory.getKey(index); + const songId = diskInventory.getWithIndex(index); + const songInfo = GetSoundManager().musicController?.getSongInfo(songId); + + return ( + setSelectedItem(prev => prev === index ? -1 : index) }> +
+
+ { songInfo?.name } + { (selectedItem === index) && + + + + + } +
); + }) } +
+
+
+
{ LocalizeText('playlist.editor.text.get.more.music') }
+
{ LocalizeText('playlist.editor.text.you.have.no.songdisks.available') }
+
{ LocalizeText('playlist.editor.text.you.can.buy.some.from.the.catalogue') }
+ +
+ + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/playlist-editor/FurniturePlaylistEditorWidgetView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/playlist-editor/FurniturePlaylistEditorWidgetView.tsx new file mode 100644 index 0000000000..611eba2195 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/playlist-editor/FurniturePlaylistEditorWidgetView.tsx @@ -0,0 +1,29 @@ +import { FC } from 'react'; +import { LocalizeText } from '../../../../../api'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../common'; +import { useFurniturePlaylistEditorWidget } from '../../../../../hooks'; +import { DiskInventoryView } from './DiskInventoryView'; +import { SongPlaylistView } from './SongPlaylistView'; + +export const FurniturePlaylistEditorWidgetView: FC<{}> = props => +{ + const { objectId = -1, currentPlayingIndex = -1, playlist = null, diskInventory = null, onClose = null, togglePlayPause = null, removeFromPlaylist = null, addToPlaylist = null } = useFurniturePlaylistEditorWidget(); + + if(objectId === -1) return null; + + return ( + + + +
+
+ +
+
+ +
+
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/furniture/playlist-editor/SongPlaylistView.tsx b/Coolui v3 test/src/components/room/widgets/furniture/playlist-editor/SongPlaylistView.tsx new file mode 100644 index 0000000000..95289a7266 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/furniture/playlist-editor/SongPlaylistView.tsx @@ -0,0 +1,78 @@ +import { ISongInfo } from '@nitrots/nitro-renderer'; +import { FC, useState } from 'react'; +import { GetConfigurationValue, GetDiskColor, LocalizeText } from '../../../../../api'; +import { Button, Text } from '../../../../../common'; + +export interface SongPlaylistViewProps +{ + furniId: number; + playlist: ISongInfo[]; + currentPlayingIndex: number; + removeFromPlaylist(slotNumber: number): void; + togglePlayPause(furniId: number, position: number): void; +} + +export const SongPlaylistView: FC = props => +{ + const { furniId = -1, playlist = null, currentPlayingIndex = -1, removeFromPlaylist = null, togglePlayPause = null } = props; + const [ selectedItem, setSelectedItem ] = useState(-1); + + const action = (index: number) => + { + if(selectedItem === index) removeFromPlaylist(index); + }; + + const playPause = (furniId: number, selectedItem: number) => + { + togglePlayPause(furniId, selectedItem !== -1 ? selectedItem : 0); + }; + + return (<> +
+ +

{ LocalizeText('playlist.editor.playlist') }

+
+
+
+ { playlist && playlist.map((songInfo, index) => + { + return
setSelectedItem(prev => prev === index ? -1 : index) }> +
action(index) } /> + { songInfo.name } +
; + }) } + +
+
+ { (!playlist || playlist.length === 0) && + <>
+
{ LocalizeText('playlist.editor.add.songs.to.your.playlist') }
+
{ LocalizeText('playlist.editor.text.click.song.to.choose.click.again.to.move') }
+
+ + } + { (playlist && playlist.length > 0) && + <> + { (currentPlayingIndex === -1) && + + } + { (currentPlayingIndex !== -1) && +
+ +
+ { LocalizeText('playlist.editor.text.now.playing.in.your.room') } + + { playlist[currentPlayingIndex]?.name + ' - ' + playlist[currentPlayingIndex]?.creator } + +
+
+ } + + } + + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/mysterybox/MysteryBoxExtensionView.tsx b/Coolui v3 test/src/components/room/widgets/mysterybox/MysteryBoxExtensionView.tsx new file mode 100644 index 0000000000..1e1828627b --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/mysterybox/MysteryBoxExtensionView.tsx @@ -0,0 +1,67 @@ +import { MysteryBoxKeysUpdateEvent } from '@nitrots/nitro-renderer'; +import { FC, useState } from 'react'; +import { FaChevronDown, FaChevronUp } from 'react-icons/fa'; +import { ColorUtils, LocalizeText } from '../../../../api'; +import { Flex, LayoutGridItem, Text } from '../../../../common'; +import { useNitroEvent } from '../../../../hooks'; + +const colorMap = { + 'purple': 9452386, + 'blue': 3891856, + 'green': 6459451, + 'yellow': 10658089, + 'lilac': 6897548, + 'orange': 10841125, + 'turquoise': 2661026, + 'red': 10104881 +}; + +export const MysteryBoxExtensionView: FC<{}> = props => +{ + const [ isOpen, setIsOpen ] = useState(true); + const [ keyColor, setKeyColor ] = useState(''); + const [ boxColor, setBoxColor ] = useState(''); + + useNitroEvent(MysteryBoxKeysUpdateEvent.MYSTERY_BOX_KEYS_UPDATE, event => + { + setKeyColor(event.keyColor); + setBoxColor(event.boxColor); + }); + + const getRgbColor = (color: string) => + { + const colorInt = colorMap[color]; + + return ColorUtils.int2rgb(colorInt); + }; + + if(keyColor === '' && boxColor === '') return null; + + return ( +
+
+ setIsOpen(value => !value) }> + { LocalizeText('mysterybox.tracker.title') } + { isOpen && } + { !isOpen && } + + { isOpen && + <> + { LocalizeText('mysterybox.tracker.description') } +
+ +
+
+
+ + +
+
+
+ +
+ } +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/object-location/ObjectLocationView.tsx b/Coolui v3 test/src/components/room/widgets/object-location/ObjectLocationView.tsx new file mode 100644 index 0000000000..0bd1a4837f --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/object-location/ObjectLocationView.tsx @@ -0,0 +1,61 @@ +import { GetTicker } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useRef, useState } from 'react'; +import { GetRoomObjectBounds, GetRoomSession } from '../../../../api'; +import { BaseProps } from '../../../../common'; + +interface ObjectLocationViewProps extends BaseProps +{ + objectId: number; + category: number; + noFollow?: boolean; +} + +export const ObjectLocationView: FC = props => +{ + const { objectId = -1, category = -1, noFollow = false, ...rest } = props; + const [ pos, setPos ] = useState<{ x: number, y: number }>({ x: -1, y: -1 }); + const elementRef = useRef(); + + useEffect(() => + { + let remove = false; + + const getObjectLocation = () => + { + const roomSession = GetRoomSession(); + const objectBounds = GetRoomObjectBounds(roomSession.roomId, objectId, category, 1); + + return objectBounds; + }; + + const updatePosition = () => + { + const bounds = getObjectLocation(); + + if(!bounds || !elementRef.current) return; + + setPos({ + x: Math.round(((bounds.left + (bounds.width / 2)) - (elementRef.current.offsetWidth / 2))), + y: Math.round((bounds.top - elementRef.current.offsetHeight) + 10) + }); + }; + + if(noFollow) + { + updatePosition(); + } + else + { + remove = true; + + GetTicker().add(updatePosition); + } + + return () => + { + if(remove) GetTicker().remove(updatePosition); + }; + }, [ objectId, category, noFollow ]); + + return
-1) ? 'visible' : 'hidden' } } { ...rest } />; +}; diff --git a/Coolui v3 test/src/components/room/widgets/pet-package/PetPackageWidgetView.tsx b/Coolui v3 test/src/components/room/widgets/pet-package/PetPackageWidgetView.tsx new file mode 100644 index 0000000000..9b4ff4a166 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/pet-package/PetPackageWidgetView.tsx @@ -0,0 +1,41 @@ +import { FC } from 'react'; +import { GetConfigurationValue, LocalizeText } from '../../../../api'; +import { Button, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; +import { usePetPackageWidget } from '../../../../hooks'; + +export const PetPackageWidgetView: FC<{}> = props => +{ + const { isVisible = false, errorResult = null, petName = null, objectType = null, onChangePetName = null, onConfirm = null, onClose = null } = usePetPackageWidget(); + + return ( + <> + { isVisible && + + onClose() } /> + +
+
+
+ { objectType === 'gnome_box' ? LocalizeText('widgets.gnomepackage.name.title') : LocalizeText('furni.petpackage') } +
+
+
+
+
+ onChangePetName(event.target.value) } /> +
+
+ { (errorResult.length > 0) && +
{ errorResult }
} +
+ onClose() }>{ LocalizeText('cancel') } + +
+
+
+
+
+ } + + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/room-filter-words/RoomFilterWordsWidgetView.tsx b/Coolui v3 test/src/components/room/widgets/room-filter-words/RoomFilterWordsWidgetView.tsx new file mode 100644 index 0000000000..bbed44b1f8 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/room-filter-words/RoomFilterWordsWidgetView.tsx @@ -0,0 +1,75 @@ +import { UpdateRoomFilterMessageComposer } from '@nitrots/nitro-renderer'; +import { FC, useState } from 'react'; +import { LocalizeText, SendMessageComposer } from '../../../../api'; +import { Button, Column, Flex, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; +import { useFilterWordsWidget, useNavigator } from '../../../../hooks'; +import { NitroInput, classNames } from '../../../../layout'; + +export const RoomFilterWordsWidgetView: FC<{}> = props => +{ + const [ word, setWord ] = useState('bobba'); + const [ selectedWord, setSelectedWord ] = useState(''); + const [ isSelectingWord, setIsSelectingWord ] = useState(false); + const { wordsFilter = [], isVisible = null, setWordsFilter, onClose = null } = useFilterWordsWidget(); + const { navigatorData = null } = useNavigator(); + + const processAction = (isAddingWord: boolean) => + { + if((isSelectingWord) ? (!selectedWord) : (!word)) return; + + SendMessageComposer(new UpdateRoomFilterMessageComposer(navigatorData.enteredGuestRoom.roomId, isAddingWord, (isSelectingWord ? selectedWord : word))); + setSelectedWord(''); + setWord('bobba'); + setIsSelectingWord(false); + + if(isAddingWord && wordsFilter.includes((isSelectingWord ? selectedWord : word))) return; + + setWordsFilter(prevValue => + { + const newWords = [ ...prevValue ]; + + isAddingWord ? newWords.push((isSelectingWord ? selectedWord : word)) : newWords.splice(newWords.indexOf((isSelectingWord ? selectedWord : word)), 1); + + return newWords; + }); + }; + + const onTyping = (word: string) => + { + setWord(word); + setIsSelectingWord(false); + }; + + const onSelectedWord = (word: string) => + { + setSelectedWord(word); + setIsSelectingWord(true); + }; + + if(!isVisible) return null; + + return ( + + onClose() } /> + + + onTyping(event.target.value) } /> + + + + { wordsFilter && (wordsFilter.length > 0) && wordsFilter.map((word, index) => + { + return ( + onSelectedWord(word) }> + { word } + + ); + }) } + + + + + + + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/room-promotes/RoomPromotesWidgetView.tsx b/Coolui v3 test/src/components/room/widgets/room-promotes/RoomPromotesWidgetView.tsx new file mode 100644 index 0000000000..07cf84185d --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/room-promotes/RoomPromotesWidgetView.tsx @@ -0,0 +1,55 @@ +import { DesktopViewEvent, GetSessionDataManager } from '@nitrots/nitro-renderer'; +import { FC, useState } from 'react'; +import { FaChevronDown, FaChevronUp } from 'react-icons/fa'; +import { Flex, Text } from '../../../../common'; +import { useMessageEvent, useRoomPromote } from '../../../../hooks'; +import { RoomPromoteEditWidgetView, RoomPromoteMyOwnEventWidgetView, RoomPromoteOtherEventWidgetView } from './views'; + +export const RoomPromotesWidgetView: FC<{}> = props => +{ + const [ isEditingPromote, setIsEditingPromote ] = useState(false); + const [ isOpen, setIsOpen ] = useState(true); + const { promoteInformation, setPromoteInformation } = useRoomPromote(); + + useMessageEvent(DesktopViewEvent, event => + { + setPromoteInformation(null); + }); + + if(!promoteInformation) return null; + + return ( + <> + { promoteInformation.data.adId !== -1 && +
+
+ setIsOpen(value => !value) }> + { promoteInformation.data.eventName } + { isOpen && } + { !isOpen && } + + { (isOpen && GetSessionDataManager().userId !== promoteInformation.data.ownerAvatarId) && + + } + { (isOpen && GetSessionDataManager().userId === promoteInformation.data.ownerAvatarId) && + setIsEditingPromote(true) } + /> + } + { isEditingPromote && + setIsEditingPromote(false) } + /> + } +
+
+ } + + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/room-promotes/views/RoomPromoteEditWidgetView.tsx b/Coolui v3 test/src/components/room/widgets/room-promotes/views/RoomPromoteEditWidgetView.tsx new file mode 100644 index 0000000000..bb3e6102d2 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/room-promotes/views/RoomPromoteEditWidgetView.tsx @@ -0,0 +1,45 @@ +import { EditEventMessageComposer } from '@nitrots/nitro-renderer'; +import { FC, useState } from 'react'; +import { LocalizeText, SendMessageComposer } from '../../../../../api'; +import { Button, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../../common'; +import { NitroInput } from '../../../../../layout'; + +interface RoomPromoteEditWidgetViewProps +{ + eventId: number; + eventName: string; + eventDescription: string; + setIsEditingPromote: (value: boolean) => void; +} + +export const RoomPromoteEditWidgetView: FC = props => +{ + const { eventId = -1, eventName = '', eventDescription = '', setIsEditingPromote = null } = props; + const [ newEventName, setNewEventName ] = useState(eventName); + const [ newEventDescription, setNewEventDescription ] = useState(eventDescription); + + const updatePromote = () => + { + SendMessageComposer(new EditEventMessageComposer(eventId, newEventName, newEventDescription)); + setIsEditingPromote(false); + }; + + return ( + + setIsEditingPromote(false) } /> + +
+ { LocalizeText('navigator.eventsettings.name') } + setNewEventName(event.target.value) } /> +
+
+ { LocalizeText('navigator.eventsettings.desc') } + +
+
+ +
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/room-promotes/views/RoomPromoteMyOwnEventWidgetView.tsx b/Coolui v3 test/src/components/room/widgets/room-promotes/views/RoomPromoteMyOwnEventWidgetView.tsx new file mode 100644 index 0000000000..e53497d036 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/room-promotes/views/RoomPromoteMyOwnEventWidgetView.tsx @@ -0,0 +1,36 @@ +import { CreateLinkEvent } from '@nitrots/nitro-renderer'; +import { FC } from 'react'; +import { LocalizeText } from '../../../../../api'; +import { Button, Flex, Grid, Text } from '../../../../../common'; +import { useRoomPromote } from '../../../../../hooks'; + +interface RoomPromoteMyOwnEventWidgetViewProps +{ + eventDescription: string; + setIsEditingPromote: (value: boolean) => void; +} + +export const RoomPromoteMyOwnEventWidgetView: FC = props => +{ + const { eventDescription = '', setIsEditingPromote = null } = props; + const { setIsExtended } = useRoomPromote(); + + const extendPromote = () => + { + setIsExtended(true); + CreateLinkEvent('catalog/open/room_event'); + }; + + return ( + <> + + { eventDescription } + +

+ + + + + + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/room-promotes/views/RoomPromoteOtherEventWidgetView.tsx b/Coolui v3 test/src/components/room/widgets/room-promotes/views/RoomPromoteOtherEventWidgetView.tsx new file mode 100644 index 0000000000..3a3ed08af4 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/room-promotes/views/RoomPromoteOtherEventWidgetView.tsx @@ -0,0 +1,30 @@ +import { FC } from 'react'; +import { LocalizeText } from '../../../../../api'; +import { Column, Flex, Text } from '../../../../../common'; + +interface RoomPromoteOtherEventWidgetViewProps +{ + eventDescription: string; +} + +export const RoomPromoteOtherEventWidgetView: FC = props => +{ + const { eventDescription = '' } = props; + + return ( + <> + + { eventDescription } + +

+ +
+
+ { LocalizeText('navigator.eventinprogress') } +
+   +
+
+ + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/room-promotes/views/index.ts b/Coolui v3 test/src/components/room/widgets/room-promotes/views/index.ts new file mode 100644 index 0000000000..da746917f6 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/room-promotes/views/index.ts @@ -0,0 +1,3 @@ +export * from './RoomPromoteEditWidgetView'; +export * from './RoomPromoteMyOwnEventWidgetView'; +export * from './RoomPromoteOtherEventWidgetView'; diff --git a/Coolui v3 test/src/components/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx b/Coolui v3 test/src/components/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx new file mode 100644 index 0000000000..a14744c259 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx @@ -0,0 +1,41 @@ +import { GetRoomEngine, NitroRenderTexture } from '@nitrots/nitro-renderer'; +import { FC, useState } from 'react'; +import { LayoutMiniCameraView } from '../../../../common'; +import { RoomWidgetThumbnailEvent } from '../../../../events'; +import { useRoom, useUiEvent } from '../../../../hooks'; + +export const RoomThumbnailWidgetView: FC<{}> = props => +{ + const [ isVisible, setIsVisible ] = useState(false); + const { roomSession = null } = useRoom(); + + useUiEvent([ + RoomWidgetThumbnailEvent.SHOW_THUMBNAIL, + RoomWidgetThumbnailEvent.HIDE_THUMBNAIL, + RoomWidgetThumbnailEvent.TOGGLE_THUMBNAIL ], event => + { + switch(event.type) + { + case RoomWidgetThumbnailEvent.SHOW_THUMBNAIL: + setIsVisible(true); + return; + case RoomWidgetThumbnailEvent.HIDE_THUMBNAIL: + setIsVisible(false); + return; + case RoomWidgetThumbnailEvent.TOGGLE_THUMBNAIL: + setIsVisible(value => !value); + return; + } + }); + + const receiveTexture = async (texture: NitroRenderTexture) => + { + await GetRoomEngine().saveTextureAsScreenshot(texture, true); + + setIsVisible(false); + }; + + if(!isVisible) return null; + + return setIsVisible(false) } />; +}; diff --git a/Coolui v3 test/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx b/Coolui v3 test/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx new file mode 100644 index 0000000000..19d382ac8f --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx @@ -0,0 +1,162 @@ +import { CreateLinkEvent, GetGuestRoomResultEvent, GetRoomEngine, NavigatorSearchComposer, RateFlatMessageComposer } from '@nitrots/nitro-renderer'; +import { AnimatePresence, motion } from 'framer-motion'; +import { classNames } from '../../../../layout'; +import { FC, useEffect, useState } from 'react'; +import { GetConfigurationValue, LocalizeText, SendMessageComposer, SetLocalStorage, TryVisitRoom } from '../../../../api'; +import { Text } from '../../../../common'; +import { useMessageEvent, useNavigator, useRoom } from '../../../../hooks'; + +export const RoomToolsWidgetView: FC<{}> = props => { + const [areBubblesMuted, setAreBubblesMuted] = useState(false); + const [isZoomedIn, setIsZoomedIn] = useState(false); + const [roomName, setRoomName] = useState(null); + const [roomOwner, setRoomOwner] = useState(null); + const [roomTags, setRoomTags] = useState(null); + const [isOpen, setIsOpen] = useState(false); + const [isOpenHistory, setIsOpenHistory] = useState(false); + const [roomHistory, setRoomHistory] = useState<{ roomId: number, roomName: string }[]>([]); + const { navigatorData = null } = useNavigator(); + const { roomSession = null } = useRoom(); + + const handleToolClick = (action: string, value?: string) => { + if (!roomSession) return; + + switch (action) { + case 'settings': + CreateLinkEvent('navigator/toggle-room-info'); + return; + case 'zoom': + setIsZoomedIn(prevValue => { + if (GetConfigurationValue('room.zoom.enabled', true)) { + const scale = GetRoomEngine().getRoomInstanceRenderingCanvasScale(roomSession.roomId, 1); + GetRoomEngine().setRoomInstanceRenderingCanvasScale(roomSession.roomId, 1, scale === 1 ? 0.5 : 1); + } else { + const geometry = GetRoomEngine().getRoomInstanceGeometry(roomSession.roomId, 1); + if (geometry) geometry.performZoom(); + } + return !prevValue; + }); + return; + case 'chat_history': + CreateLinkEvent('chat-history/toggle'); + return; + case 'hiddenbubbles': + CreateLinkEvent('nitrobubblehidden/toggle'); + setAreBubblesMuted(prev => !prev); + return; + case 'like_room': + SendMessageComposer(new RateFlatMessageComposer(1)); + return; + case 'toggle_room_link': + CreateLinkEvent('navigator/toggle-room-link'); + return; + case 'navigator_search_tag': + CreateLinkEvent(`navigator/search/${value}`); + SendMessageComposer(new NavigatorSearchComposer('hotel_view', `tag:${value}`)); + return; + case 'room_history': + if (roomHistory.length > 0) setIsOpenHistory(prev => !prev); + return; + case 'room_history_back': + const prevIndex = roomHistory.findIndex(room => room.roomId === navigatorData.currentRoomId) - 1; + if (prevIndex >= 0) TryVisitRoom(roomHistory[prevIndex].roomId); + return; + case 'room_history_next': + const nextIndex = roomHistory.findIndex(room => room.roomId === navigatorData.currentRoomId) + 1; + if (nextIndex < roomHistory.length) TryVisitRoom(roomHistory[nextIndex].roomId); + return; + } + }; + + const onChangeRoomHistory = (roomId: number, roomName: string) => { + let newStorage = JSON.parse(window.localStorage.getItem('nitro.room.history') || '[]'); + if (newStorage.some((room: { roomId: number }) => room.roomId === roomId)) return; + + if (newStorage.length >= 10) newStorage.shift(); + newStorage = [...newStorage, { roomId, roomName }]; + + setRoomHistory(newStorage); + SetLocalStorage('nitro.room.history', newStorage); + }; + + useMessageEvent(GetGuestRoomResultEvent, event => { + const parser = event.getParser(); + if (!parser.roomEnter || (parser.data.roomId !== roomSession.roomId)) return; + + if (roomName !== parser.data.roomName) setRoomName(parser.data.roomName); + if (roomOwner !== parser.data.ownerName) setRoomOwner(parser.data.ownerName); + if (roomTags !== parser.data.tags) setRoomTags(parser.data.tags); + onChangeRoomHistory(parser.data.roomId, parser.data.roomName); + }); + + useEffect(() => { + setIsOpen(true); + const timeout = setTimeout(() => setIsOpen(false), 5000); + return () => clearTimeout(timeout); + }, [roomName, roomOwner, roomTags]); + + useEffect(() => { + setRoomHistory(JSON.parse(window.localStorage.getItem('nitro.room.history') || '[]')); + }, []); + + useEffect(() => { + const handleTabClose = () => { + window.localStorage.removeItem('nitro.room.history'); + }; + window.addEventListener('beforeunload', handleTabClose); + return () => window.removeEventListener('beforeunload', handleTabClose); + }, []); + + return ( +
+
+
handleToolClick('settings')} /> +
handleToolClick('zoom')} /> +
handleToolClick('chat_history')} /> +
handleToolClick('hiddenbubbles')} /> + + {navigatorData.canRate && ( +
handleToolClick('like_room')} /> + )} +
handleToolClick('toggle_room_link')} /> +
handleToolClick('room_history')} /> +
+
+ + {isOpen && ( + +
+
+
+ {roomName} + {roomOwner} +
+ {roomTags && roomTags.length > 0 && ( +
+ {roomTags.map((tag, index) => ( + handleToolClick('navigator_search_tag', tag)}> + #{tag} + + ))} +
+ )} +
+
+
+ )} + {isOpenHistory && ( + +
+ {roomHistory.map(history => ( + TryVisitRoom(history.roomId)}> + {history.roomName} + + ))} +
+
+ )} +
+
+
+ ); +}; \ No newline at end of file diff --git a/Coolui v3 test/src/components/room/widgets/user-location/UserLocationView.tsx b/Coolui v3 test/src/components/room/widgets/user-location/UserLocationView.tsx new file mode 100644 index 0000000000..f7b9daac42 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/user-location/UserLocationView.tsx @@ -0,0 +1,24 @@ +import { RoomObjectCategory } from '@nitrots/nitro-renderer'; +import { FC } from 'react'; +import { BaseProps } from '../../../../common'; +import { useRoom } from '../../../../hooks'; +import { ObjectLocationView } from '../object-location/ObjectLocationView'; + +interface UserLocationViewProps extends BaseProps +{ + userId: number; +} + +export const UserLocationView: FC = props => +{ + const { userId = -1, ...rest } = props; + const { roomSession = null } = useRoom(); + + if((userId === -1) || !roomSession) return null; + + const userData = roomSession.userDataManager.getUserData(userId); + + if(!userData) return null; + + return ; +}; diff --git a/Coolui v3 test/src/components/room/widgets/word-quiz/WordQuizQuestionView.tsx b/Coolui v3 test/src/components/room/widgets/word-quiz/WordQuizQuestionView.tsx new file mode 100644 index 0000000000..92f0b9605b --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/word-quiz/WordQuizQuestionView.tsx @@ -0,0 +1,44 @@ +import { FC } from 'react'; +import { VALUE_KEY_DISLIKE, VALUE_KEY_LIKE } from '../../../../api'; +import { Column, Flex, Text } from '../../../../common'; + +interface WordQuizQuestionViewProps +{ + question: string; + canVote: boolean; + vote(value: string): void; + noVotes: number; + yesVotes: number; +} + +export const WordQuizQuestionView: FC = props => +{ + const { question = null, canVote = null, vote = null, noVotes = null, yesVotes = null } = props; + + return ( + + { !canVote && +
+
+ { noVotes } +
+ { question } +
+ { yesVotes } +
+
} + { canVote && +
+ { question } +
+ vote(VALUE_KEY_DISLIKE) }> +
+ + vote(VALUE_KEY_LIKE) }> +
+ +
+
} + + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/word-quiz/WordQuizVoteView.tsx b/Coolui v3 test/src/components/room/widgets/word-quiz/WordQuizVoteView.tsx new file mode 100644 index 0000000000..b1925a0c80 --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/word-quiz/WordQuizVoteView.tsx @@ -0,0 +1,24 @@ +import { RoomObjectCategory } from '@nitrots/nitro-renderer'; +import { FC } from 'react'; +import { VALUE_KEY_DISLIKE } from '../../../../api'; +import { BaseProps } from '../../../../common'; +import { ObjectLocationView } from '../object-location/ObjectLocationView'; + +interface WordQuizVoteViewProps extends BaseProps +{ + userIndex: number; + vote: string; +} + +export const WordQuizVoteView: FC = props => +{ + const { userIndex = null, vote = null, ...rest } = props; + + return ( + +
+
+
+ + ); +}; diff --git a/Coolui v3 test/src/components/room/widgets/word-quiz/WordQuizWidgetView.tsx b/Coolui v3 test/src/components/room/widgets/word-quiz/WordQuizWidgetView.tsx new file mode 100644 index 0000000000..d433d3504c --- /dev/null +++ b/Coolui v3 test/src/components/room/widgets/word-quiz/WordQuizWidgetView.tsx @@ -0,0 +1,19 @@ +import { FC } from 'react'; +import { VALUE_KEY_DISLIKE, VALUE_KEY_LIKE } from '../../../../api'; +import { useWordQuizWidget } from '../../../../hooks'; +import { WordQuizQuestionView } from './WordQuizQuestionView'; +import { WordQuizVoteView } from './WordQuizVoteView'; + +export const WordQuizWidgetView: FC<{}> = props => +{ + const { question = null, answerSent = false, answerCounts = null, userAnswers = null, vote = null } = useWordQuizWidget(); + + return ( + <> + { question && + } + { userAnswers && + Array.from(userAnswers.entries()).map(([ key, value ], index) => ) } + + ); +}; diff --git a/Coolui v3 test/src/components/toolbar/ToolbarItemView.tsx b/Coolui v3 test/src/components/toolbar/ToolbarItemView.tsx new file mode 100644 index 0000000000..3a0822a2a3 --- /dev/null +++ b/Coolui v3 test/src/components/toolbar/ToolbarItemView.tsx @@ -0,0 +1,22 @@ +import { DetailedHTMLProps, forwardRef, HTMLAttributes, PropsWithChildren } from 'react'; +import { classNames } from '../../layout'; + +export const ToolbarItemView = forwardRef & DetailedHTMLProps, HTMLDivElement>>((props, ref) => +{ + const { icon = null, className = null, ...rest } = props; + + return ( +
+ ); +}); + +ToolbarItemView.displayName = 'ToolbarItemView'; diff --git a/Coolui v3 test/src/components/toolbar/ToolbarMeView.tsx b/Coolui v3 test/src/components/toolbar/ToolbarMeView.tsx new file mode 100644 index 0000000000..c420fce84f --- /dev/null +++ b/Coolui v3 test/src/components/toolbar/ToolbarMeView.tsx @@ -0,0 +1,49 @@ +import { CreateLinkEvent, GetRoomEngine, GetSessionDataManager, MouseEventType, RoomObjectCategory } from '@nitrots/nitro-renderer'; +import { Dispatch, FC, PropsWithChildren, SetStateAction, useEffect, useRef } from 'react'; +import { DispatchUiEvent, GetConfigurationValue, GetRoomSession, GetUserProfile } from '../../api'; +import { Flex, LayoutItemCountView } from '../../common'; +import { GuideToolEvent } from '../../events'; + +export const ToolbarMeView: FC>; +}>> = props => +{ + const { useGuideTool = false, unseenAchievementCount = 0, setMeExpanded = null, children = null, ...rest } = props; + const elementRef = useRef(); + + useEffect(() => + { + const roomSession = GetRoomSession(); + + if(!roomSession) return; + + GetRoomEngine().selectRoomObject(roomSession.roomId, roomSession.ownRoomIndex, RoomObjectCategory.UNIT); + }, []); + + useEffect(() => + { + const onClick = (event: MouseEvent) => setMeExpanded(false); + + document.addEventListener('click', onClick); + + return () => document.removeEventListener(MouseEventType.MOUSE_CLICK, onClick); + }, [ setMeExpanded ]); + + return ( + + { (GetConfigurationValue('guides.enabled') && useGuideTool) && +
DispatchUiEvent(new GuideToolEvent(GuideToolEvent.TOGGLE_GUIDE_TOOL)) } /> } +
CreateLinkEvent('achievements/toggle') }> + { (unseenAchievementCount > 0) && + } +
+
GetUserProfile(GetSessionDataManager().userId) } /> +
CreateLinkEvent('navigator/search/myworld_view') } /> +
CreateLinkEvent('avatar-editor/toggle') } /> +
CreateLinkEvent('user-settings/toggle') } /> + { children } + + ); +}; diff --git a/Coolui v3 test/src/components/toolbar/ToolbarView.tsx b/Coolui v3 test/src/components/toolbar/ToolbarView.tsx new file mode 100644 index 0000000000..27e6a4ab33 --- /dev/null +++ b/Coolui v3 test/src/components/toolbar/ToolbarView.tsx @@ -0,0 +1,117 @@ +import { CreateLinkEvent, Dispose, DropBounce, EaseOut, GetSessionDataManager, JumpBy, Motions, NitroToolbarAnimateIconEvent, PerkAllowancesMessageEvent, PerkEnum, Queue, Wait } from '@nitrots/nitro-renderer'; +import { AnimatePresence, motion } from 'framer-motion'; +import { FC, useState } from 'react'; +import { GetConfigurationValue, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api'; +import { Flex, LayoutAvatarImageView, LayoutItemCountView } from '../../common'; +import { useAchievements, useFriends, useInventoryUnseenTracker, useMessageEvent, useMessenger, useNitroEvent, useSessionInfo } from '../../hooks'; +import { ToolbarItemView } from './ToolbarItemView'; +import { ToolbarMeView } from './ToolbarMeView'; + +export const ToolbarView: FC<{ isInRoom: boolean }> = props => +{ + const { isInRoom } = props; + const [ isMeExpanded, setMeExpanded ] = useState(false); + const [ useGuideTool, setUseGuideTool ] = useState(false); + const { userFigure = null } = useSessionInfo(); + const { getFullCount = 0 } = useInventoryUnseenTracker(); + const { getTotalUnseen = 0 } = useAchievements(); + const { requests = [] } = useFriends(); + const { iconState = MessengerIconState.HIDDEN } = useMessenger(); + const isMod = GetSessionDataManager().isModerator; + + useMessageEvent(PerkAllowancesMessageEvent, event => + { + setUseGuideTool(event.getParser().isAllowed(PerkEnum.USE_GUIDE_TOOL)); + }); + + useNitroEvent(NitroToolbarAnimateIconEvent.ANIMATE_ICON, event => + { + const animationIconToToolbar = (iconName: string, image: HTMLImageElement, x: number, y: number) => + { + const target = (document.body.getElementsByClassName(iconName)[0] as HTMLElement); + + if(!target) return; + + image.className = 'toolbar-icon-animation'; + image.style.visibility = 'visible'; + image.style.left = (x + 'px'); + image.style.top = (y + 'px'); + + document.body.append(image); + + const targetBounds = target.getBoundingClientRect(); + const imageBounds = image.getBoundingClientRect(); + + const left = (imageBounds.x - targetBounds.x); + const top = (imageBounds.y - targetBounds.y); + const squared = Math.sqrt(((left * left) + (top * top))); + const wait = (500 - Math.abs(((((1 / squared) * 100) * 500) * 0.5))); + const height = 20; + + const motionName = (`ToolbarBouncing[${ iconName }]`); + + if(!Motions.getMotionByTag(motionName)) + { + Motions.runMotion(new Queue(new Wait((wait + 8)), new DropBounce(target, 400, 12))).tag = motionName; + } + + const motion = new Queue(new EaseOut(new JumpBy(image, wait, ((targetBounds.x - imageBounds.x) + height), (targetBounds.y - imageBounds.y), 100, 1), 1), new Dispose(image)); + + Motions.runMotion(motion); + }; + + animationIconToToolbar('icon-inventory', event.image, event.x, event.y); + }); + + return ( + <> + { isMeExpanded && ( + + )} + + + + + + { + setMeExpanded(!isMeExpanded); + event.stopPropagation(); + } }> + + { (getTotalUnseen > 0) && + } + + { isInRoom && + VisitDesktop() } /> } + { !isInRoom && + CreateLinkEvent('navigator/goto/home') } /> } + CreateLinkEvent('navigator/toggle') } /> + { GetConfigurationValue('game.center.enabled') && + CreateLinkEvent('games/toggle') } /> } + CreateLinkEvent('catalog/toggle') } /> + CreateLinkEvent('inventory/toggle') }> + { (getFullCount > 0) && + } + + { isInRoom && + CreateLinkEvent('camera/toggle') } /> } + { isMod && + CreateLinkEvent('mod-tools/toggle') } /> } + + + + + + CreateLinkEvent('friends/toggle') }> + { (requests.length > 0) && + } + + { ((iconState === MessengerIconState.SHOW) || (iconState === MessengerIconState.UNREAD)) && + OpenMessengerChat() } /> } + +
+ + + + ); +}; diff --git a/Coolui v3 test/src/components/user-profile/FriendsContainerView.tsx b/Coolui v3 test/src/components/user-profile/FriendsContainerView.tsx new file mode 100644 index 0000000000..b92b82d014 --- /dev/null +++ b/Coolui v3 test/src/components/user-profile/FriendsContainerView.tsx @@ -0,0 +1,27 @@ +import { RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer'; +import { FC } from 'react'; +import { LocalizeText } from '../../api'; +import { RelationshipsContainerView } from './RelationshipsContainerView'; + +interface FriendsContainerViewProps +{ + relationships: RelationshipStatusInfoMessageParser; + friendsCount: number; +} + +export const FriendsContainerView: FC = props => +{ + const { relationships = null, friendsCount = null } = props; + + return ( +
+

+ { LocalizeText('extendedprofile.friends.count') } { friendsCount } +

+
+

{ LocalizeText('extendedprofile.relstatus') }

+ +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/user-profile/GroupsContainerView.tsx b/Coolui v3 test/src/components/user-profile/GroupsContainerView.tsx new file mode 100644 index 0000000000..3ffd78745f --- /dev/null +++ b/Coolui v3 test/src/components/user-profile/GroupsContainerView.tsx @@ -0,0 +1,90 @@ +import { GroupInformationComposer, GroupInformationEvent, GroupInformationParser, HabboGroupEntryData } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useState } from 'react'; +import { SendMessageComposer, ToggleFavoriteGroup } from '../../api'; +import { AutoGrid, Column, Grid, GridProps, LayoutBadgeImageView, LayoutGridItem } from '../../common'; +import { useMessageEvent } from '../../hooks'; +import { GroupInformationView } from '../groups/views/GroupInformationView'; + +interface GroupsContainerViewProps extends GridProps +{ + itsMe: boolean; + groups: HabboGroupEntryData[]; + onLeaveGroup: () => void; +} + +export const GroupsContainerView: FC = props => +{ + const { itsMe = null, groups = null, onLeaveGroup = null, overflow = 'hidden', gap = 2, ...rest } = props; + const [ selectedGroupId, setSelectedGroupId ] = useState(null); + const [ groupInformation, setGroupInformation ] = useState(null); + + useMessageEvent(GroupInformationEvent, event => + { + const parser = event.getParser(); + + if(!selectedGroupId || (selectedGroupId !== parser.id) || parser.flag) return; + + setGroupInformation(parser); + }); + + useEffect(() => + { + if(!selectedGroupId) return; + + SendMessageComposer(new GroupInformationComposer(selectedGroupId, false)); + }, [ selectedGroupId ]); + + useEffect(() => + { + setGroupInformation(null); + + if(groups.length > 0) + { + setSelectedGroupId(prevValue => + { + if(prevValue === groups[0].groupId) + { + SendMessageComposer(new GroupInformationComposer(groups[0].groupId, false)); + } + + return groups[0].groupId; + }); + } + }, [ groups ]); + + if(!groups || !groups.length) + { + return ( + +
+
+
+
+
+ + ); + } + + return ( + + + + { groups.map((group, index) => + { + return ( + setSelectedGroupId(group.groupId) }> + { itsMe && + ToggleFavoriteGroup(group) } /> } + + + ); + }) } + + + + { groupInformation && + } + + + ); +}; diff --git a/Coolui v3 test/src/components/user-profile/RelationshipsContainerView.tsx b/Coolui v3 test/src/components/user-profile/RelationshipsContainerView.tsx new file mode 100644 index 0000000000..7bdca660a8 --- /dev/null +++ b/Coolui v3 test/src/components/user-profile/RelationshipsContainerView.tsx @@ -0,0 +1,62 @@ +import { RelationshipStatusEnum, RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer'; +import { FC } from 'react'; +import { GetUserProfile, LocalizeText } from '../../api'; +import { Flex, LayoutAvatarImageView } from '../../common'; + +interface RelationshipsContainerViewProps +{ + relationships: RelationshipStatusInfoMessageParser; +} + +interface RelationshipsContainerRelationshipViewProps +{ + type: number; +} + +export const RelationshipsContainerView: FC = props => +{ + const { relationships = null } = props; + + const RelationshipComponent = ({ type }: RelationshipsContainerRelationshipViewProps) => + { + const relationshipInfo = (relationships && relationships.relationshipStatusMap.hasKey(type)) ? relationships.relationshipStatusMap.getValue(type) : null; + const relationshipName = RelationshipStatusEnum.RELATIONSHIP_NAMES[type].toLocaleLowerCase(); + + return ( +
+ + + +
+
+

(relationshipInfo && (relationshipInfo.randomFriendId >= 1) && GetUserProfile(relationshipInfo.randomFriendId)) }> + { (!relationshipInfo || (relationshipInfo.friendCount === 0)) && + LocalizeText('extendedprofile.add.friends') } + { (relationshipInfo && (relationshipInfo.friendCount >= 1)) && + relationshipInfo.randomFriendName } +

+ { (relationshipInfo && (relationshipInfo.friendCount >= 1)) && +
+ +
} +
+

+ { (!relationshipInfo || (relationshipInfo.friendCount === 0)) && + LocalizeText('extendedprofile.no.friends.in.this.category') } + { (relationshipInfo && (relationshipInfo.friendCount > 1)) && + LocalizeText(`extendedprofile.relstatus.others.${ relationshipName }`, [ 'count' ], [ (relationshipInfo.friendCount - 1).toString() ]) } +   +

+
+
+ ); + }; + + return ( + <> + + + + + ); +}; diff --git a/Coolui v3 test/src/components/user-profile/UserContainerView.tsx b/Coolui v3 test/src/components/user-profile/UserContainerView.tsx new file mode 100644 index 0000000000..20d0768c76 --- /dev/null +++ b/Coolui v3 test/src/components/user-profile/UserContainerView.tsx @@ -0,0 +1,71 @@ +import { GetSessionDataManager, RequestFriendComposer, UserProfileParser } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useState } from 'react'; +import { FriendlyTime, LocalizeText, SendMessageComposer } from '../../api'; +import { LayoutAvatarImageView, Text } from '../../common'; + +export const UserContainerView: FC<{ + userProfile: UserProfileParser; +}> = props => +{ + const { userProfile = null } = props; + const [ requestSent, setRequestSent ] = useState(userProfile.requestSent); + const isOwnProfile = (userProfile.id === GetSessionDataManager().userId); + const canSendFriendRequest = !requestSent && (!isOwnProfile && !userProfile.isMyFriend && !userProfile.requestSent); + + const addFriend = () => + { + setRequestSent(true); + + SendMessageComposer(new RequestFriendComposer(userProfile.username)); + }; + + useEffect(() => + { + setRequestSent(userProfile.requestSent); + }, [ userProfile ]); + + return ( +
+
+ +
+
+
+

{ userProfile.username }

+

{ userProfile.motto }

+
+
+

+ { LocalizeText('extendedprofile.created') } { userProfile.registration } +

+

+ { LocalizeText('extendedprofile.last.login') } { FriendlyTime.format(userProfile.secondsSinceLastVisit, '.ago', 2) } +

+

+ { LocalizeText('extendedprofile.achievementscore') } { userProfile.achievementPoints } +

+
+
+ { userProfile.isOnline && + } + { !userProfile.isOnline && + } +
+ { canSendFriendRequest && + { LocalizeText('extendedprofile.addasafriend') } } + { !canSendFriendRequest && + <> + + { isOwnProfile && +

{ LocalizeText('extendedprofile.me') }

} + { userProfile.isMyFriend && +

{ LocalizeText('extendedprofile.friend') }

} + { (requestSent || userProfile.requestSent) && +

{ LocalizeText('extendedprofile.friendrequestsent') }

} + } +
+
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/user-profile/UserProfileView.tsx b/Coolui v3 test/src/components/user-profile/UserProfileView.tsx new file mode 100644 index 0000000000..f57612be77 --- /dev/null +++ b/Coolui v3 test/src/components/user-profile/UserProfileView.tsx @@ -0,0 +1,125 @@ +import { CreateLinkEvent, ExtendedProfileChangedMessageEvent, GetSessionDataManager, RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, RoomEngineObjectEvent, RoomObjectCategory, RoomObjectType, UserCurrentBadgesComposer, UserCurrentBadgesEvent, UserProfileEvent, UserProfileParser, UserRelationshipsComposer } from '@nitrots/nitro-renderer'; +import { FC, useState } from 'react'; +import { GetRoomSession, GetUserProfile, LocalizeText, SendMessageComposer } from '../../api'; +import { Flex, Grid, LayoutBadgeImageView, Text } from '../../common'; +import { useMessageEvent, useNitroEvent } from '../../hooks'; +import { NitroCard } from '../../layout'; +import { FriendsContainerView } from './FriendsContainerView'; +import { GroupsContainerView } from './GroupsContainerView'; +import { UserContainerView } from './UserContainerView'; + +export const UserProfileView: FC<{}> = props => +{ + const [ userProfile, setUserProfile ] = useState(null); + const [ userBadges, setUserBadges ] = useState([]); + const [ userRelationships, setUserRelationships ] = useState(null); + + const onClose = () => + { + setUserProfile(null); + setUserBadges([]); + setUserRelationships(null); + }; + + const onLeaveGroup = () => + { + if(!userProfile || (userProfile.id !== GetSessionDataManager().userId)) return; + + GetUserProfile(userProfile.id); + }; + + useMessageEvent(UserCurrentBadgesEvent, event => + { + const parser = event.getParser(); + + if(!userProfile || (parser.userId !== userProfile.id)) return; + + setUserBadges(parser.badges); + }); + + useMessageEvent(RelationshipStatusInfoEvent, event => + { + const parser = event.getParser(); + + if(!userProfile || (parser.userId !== userProfile.id)) return; + + setUserRelationships(parser); + }); + + useMessageEvent(UserProfileEvent, event => + { + const parser = event.getParser(); + + let isSameProfile = false; + + setUserProfile(prevValue => + { + if(prevValue && prevValue.id) isSameProfile = (prevValue.id === parser.id); + + return parser; + }); + + if(!isSameProfile) + { + setUserBadges([]); + setUserRelationships(null); + } + + SendMessageComposer(new UserCurrentBadgesComposer(parser.id)); + SendMessageComposer(new UserRelationshipsComposer(parser.id)); + }); + + useMessageEvent(ExtendedProfileChangedMessageEvent, event => + { + const parser = event.getParser(); + + if(parser.userId != userProfile?.id) return; + + GetUserProfile(parser.userId); + }); + + useNitroEvent(RoomEngineObjectEvent.SELECTED, event => + { + if(!userProfile) return; + + if(event.category !== RoomObjectCategory.UNIT) return; + + const userData = GetRoomSession().userDataManager.getUserDataByIndex(event.objectId); + + if(userData.type !== RoomObjectType.USER) return; + + GetUserProfile(userData.webID); + }); + + if(!userProfile) return null; + + return ( + + + + +
+ +
+ { userBadges && (userBadges.length > 0) && userBadges.map((badge, index) => ) } +
+
+
+ { userRelationships && + } +
+
+ + CreateLinkEvent(`navigator/search/hotel_view/owner:${ userProfile.username }`) }> + + { LocalizeText('extendedprofile.rooms') } + + + +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/user-settings/UserSettingsView.tsx b/Coolui v3 test/src/components/user-settings/UserSettingsView.tsx new file mode 100644 index 0000000000..d52df7438f --- /dev/null +++ b/Coolui v3 test/src/components/user-settings/UserSettingsView.tsx @@ -0,0 +1,188 @@ +import { AddLinkEventTracker, ILinkEventTracker, NitroSettingsEvent, RemoveLinkEventTracker, UserSettingsCameraFollowComposer, UserSettingsEvent, UserSettingsOldChatComposer, UserSettingsRoomInvitesComposer, UserSettingsSoundComposer } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useState } from 'react'; +import { FaVolumeDown, FaVolumeMute, FaVolumeUp } from 'react-icons/fa'; +import { DispatchMainEvent, DispatchUiEvent, LocalizeText, SendMessageComposer } from '../../api'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common'; +import { useCatalogPlaceMultipleItems, useCatalogSkipPurchaseConfirmation, useMessageEvent } from '../../hooks'; +import { classNames } from '../../layout'; + +export const UserSettingsView: FC<{}> = props => +{ + const [ isVisible, setIsVisible ] = useState(false); + const [ userSettings, setUserSettings ] = useState(null); + const [ catalogPlaceMultipleObjects, setCatalogPlaceMultipleObjects ] = useCatalogPlaceMultipleItems(); + const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useCatalogSkipPurchaseConfirmation(); + + const processAction = (type: string, value?: boolean | number | string) => + { + let doUpdate = true; + + const clone = userSettings.clone(); + + switch(type) + { + case 'close_view': + setIsVisible(false); + doUpdate = false; + return; + case 'oldchat': + clone.oldChat = value as boolean; + SendMessageComposer(new UserSettingsOldChatComposer(clone.oldChat)); + break; + case 'room_invites': + clone.roomInvites = value as boolean; + SendMessageComposer(new UserSettingsRoomInvitesComposer(clone.roomInvites)); + break; + case 'camera_follow': + clone.cameraFollow = value as boolean; + SendMessageComposer(new UserSettingsCameraFollowComposer(clone.cameraFollow)); + break; + case 'system_volume': + clone.volumeSystem = value as number; + clone.volumeSystem = Math.max(0, clone.volumeSystem); + clone.volumeSystem = Math.min(100, clone.volumeSystem); + break; + case 'furni_volume': + clone.volumeFurni = value as number; + clone.volumeFurni = Math.max(0, clone.volumeFurni); + clone.volumeFurni = Math.min(100, clone.volumeFurni); + break; + case 'trax_volume': + clone.volumeTrax = value as number; + clone.volumeTrax = Math.max(0, clone.volumeTrax); + clone.volumeTrax = Math.min(100, clone.volumeTrax); + break; + } + + if(doUpdate) setUserSettings(clone); + + DispatchMainEvent(clone); + }; + + const saveRangeSlider = (type: string) => + { + switch(type) + { + case 'volume': + SendMessageComposer(new UserSettingsSoundComposer(Math.round(userSettings.volumeSystem), Math.round(userSettings.volumeFurni), Math.round(userSettings.volumeTrax))); + break; + } + }; + + useMessageEvent(UserSettingsEvent, event => + { + const parser = event.getParser(); + const settingsEvent = new NitroSettingsEvent(); + + settingsEvent.volumeSystem = parser.volumeSystem; + settingsEvent.volumeFurni = parser.volumeFurni; + settingsEvent.volumeTrax = parser.volumeTrax; + settingsEvent.oldChat = parser.oldChat; + settingsEvent.roomInvites = parser.roomInvites; + settingsEvent.cameraFollow = parser.cameraFollow; + settingsEvent.flags = parser.flags; + settingsEvent.chatType = parser.chatType; + + setUserSettings(settingsEvent); + DispatchMainEvent(settingsEvent); + }); + + useEffect(() => + { + const linkTracker: ILinkEventTracker = { + linkReceived: (url: string) => + { + const parts = url.split('/'); + + if(parts.length < 2) return; + + switch(parts[1]) + { + case 'show': + setIsVisible(true); + return; + case 'hide': + setIsVisible(false); + return; + case 'toggle': + setIsVisible(prevValue => !prevValue); + return; + } + }, + eventUrlPrefix: 'user-settings/' + }; + + AddLinkEventTracker(linkTracker); + + return () => RemoveLinkEventTracker(linkTracker); + }, []); + + useEffect(() => + { + if(!userSettings) return; + + DispatchUiEvent(userSettings); + }, [ userSettings ]); + + if(!isVisible || !userSettings) return null; + + return ( + + processAction('close_view') } /> + +
+
+ processAction('oldchat', event.target.checked) } /> + { LocalizeText('memenu.settings.chat.prefer.old.chat') } +
+
+ 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') } +
+
+
+ { 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/Coolui v3 test/src/components/wired/WiredView.tsx b/Coolui v3 test/src/components/wired/WiredView.tsx new file mode 100644 index 0000000000..0f073abdd1 --- /dev/null +++ b/Coolui v3 test/src/components/wired/WiredView.tsx @@ -0,0 +1,21 @@ +import { ConditionDefinition, TriggerDefinition, WiredActionDefinition } from '@nitrots/nitro-renderer'; +import { FC } from 'react'; +import { useWired } from '../../hooks'; +import { WiredActionLayoutView } from './views/actions/WiredActionLayoutView'; +import { WiredConditionLayoutView } from './views/conditions/WiredConditionLayoutView'; +import { WiredTriggerLayoutView } from './views/triggers/WiredTriggerLayoutView'; + +export const WiredView: FC<{}> = props => +{ + const { trigger = null } = useWired(); + + if(!trigger) return null; + + if(trigger instanceof WiredActionDefinition) return WiredActionLayoutView(trigger.code); + + if(trigger instanceof TriggerDefinition) return WiredTriggerLayoutView(trigger.code); + + if(trigger instanceof ConditionDefinition) return WiredConditionLayoutView(trigger.code); + + return null; +}; diff --git a/Coolui v3 test/src/components/wired/views/WiredBaseView.tsx b/Coolui v3 test/src/components/wired/views/WiredBaseView.tsx new file mode 100644 index 0000000000..8e8fb374fc --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/WiredBaseView.tsx @@ -0,0 +1,114 @@ +import { GetSessionDataManager } from '@nitrots/nitro-renderer'; +import { FC, PropsWithChildren, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType, WiredSelectionVisualizer } from '../../../api'; +import { Button, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../common'; +import { useWired } from '../../../hooks'; +import { WiredFurniSelectorView } from './WiredFurniSelectorView'; + +export interface WiredBaseViewProps +{ + wiredType: string; + requiresFurni: number; + hasSpecialInput: boolean; + save: () => void; + validate?: () => boolean; +} + +export const WiredBaseView: FC> = props => +{ + const { wiredType = '', requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, children = null, hasSpecialInput = false } = props; + const [ wiredName, setWiredName ] = useState(null); + const [ wiredDescription, setWiredDescription ] = useState(null); + const [ needsSave, setNeedsSave ] = useState(false); + const { trigger = null, setTrigger = null, setIntParams = null, setStringParam = null, setFurniIds = null, setAllowsFurni = null, saveWired = null } = useWired(); + + const onClose = () => setTrigger(null); + + const onSave = () => + { + if(validate && !validate()) return; + + if(save) save(); + + setNeedsSave(true); + }; + + useEffect(() => + { + if(!needsSave) return; + + saveWired(); + + setNeedsSave(false); + }, [ needsSave, saveWired ]); + + useEffect(() => + { + if(!trigger) return; + + const spriteId = (trigger.spriteId || -1); + const furniData = GetSessionDataManager().getFloorItemData(spriteId); + + if(!furniData) + { + setWiredName(('NAME: ' + spriteId)); + setWiredDescription(('NAME: ' + spriteId)); + } + else + { + setWiredName(furniData.name); + setWiredDescription(furniData.description); + } + + if(hasSpecialInput) + { + setIntParams(trigger.intData); + setStringParam(trigger.stringData); + } + + if(requiresFurni > WiredFurniType.STUFF_SELECTION_OPTION_NONE) + { + setFurniIds(prevValue => + { + if(prevValue && prevValue.length) WiredSelectionVisualizer.clearSelectionShaderFromFurni(prevValue); + + if(trigger.selectedItems && trigger.selectedItems.length) + { + WiredSelectionVisualizer.applySelectionShaderToFurni(trigger.selectedItems); + + return trigger.selectedItems; + } + + return []; + }); + } + + setAllowsFurni(requiresFurni); + }, [ trigger, hasSpecialInput, requiresFurni, setIntParams, setStringParam, setFurniIds, setAllowsFurni ]); + + return ( + + + +
+
+ + { wiredName } +
+ { wiredDescription } +
+ { !!children &&
} + { children } + { (requiresFurni > WiredFurniType.STUFF_SELECTION_OPTION_NONE) && + <> +
+ + } +
+ + +
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/WiredFurniSelectorView.tsx b/Coolui v3 test/src/components/wired/views/WiredFurniSelectorView.tsx new file mode 100644 index 0000000000..1363326bda --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/WiredFurniSelectorView.tsx @@ -0,0 +1,16 @@ +import { FC } from 'react'; +import { LocalizeText } from '../../../api'; +import { Text } from '../../../common'; +import { useWired } from '../../../hooks'; + +export const WiredFurniSelectorView: FC<{}> = props => +{ + const { trigger = null, furniIds = [] } = useWired(); + + return ( +
+ { LocalizeText('wiredfurni.pickfurnis.caption', [ 'count', 'limit' ], [ furniIds.length.toString(), trigger.maximumItemSelectionCount.toString() ]) } + { LocalizeText('wiredfurni.pickfurnis.desc') } +
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionBaseView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionBaseView.tsx new file mode 100644 index 0000000000..aef1cdbaab --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionBaseView.tsx @@ -0,0 +1,41 @@ +import { WiredActionDefinition } from '@nitrots/nitro-renderer'; +import { FC, PropsWithChildren, useEffect } from 'react'; +import ReactSlider from 'react-slider'; +import { GetWiredTimeLocale, LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredBaseView } from '../WiredBaseView'; + +export interface WiredActionBaseViewProps +{ + hasSpecialInput: boolean; + requiresFurni: number; + save: () => void; +} + +export const WiredActionBaseView: FC> = props => +{ + const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null } = props; + const { trigger = null, actionDelay = 0, setActionDelay = null } = useWired(); + + useEffect(() => + { + setActionDelay((trigger as WiredActionDefinition).delayInPulses); + }, [ trigger, setActionDelay ]); + + return ( + + { children } + { !!children &&
} +
+ { LocalizeText('wiredfurni.params.delay', [ 'seconds' ], [ GetWiredTimeLocale(actionDelay) ]) } + setActionDelay(event) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionBotChangeFigureView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotChangeFigureView.tsx new file mode 100644 index 0000000000..e359037f67 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotChangeFigureView.tsx @@ -0,0 +1,39 @@ +import { GetSessionDataManager } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WIRED_STRING_DELIMETER, WiredFurniType } from '../../../../api'; +import { Button, LayoutAvatarImageView, Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +const DEFAULT_FIGURE: string = 'hd-180-1.ch-210-66.lg-270-82.sh-290-81'; + +export const WiredActionBotChangeFigureView: FC<{}> = props => +{ + const [ botName, setBotName ] = useState(''); + const [ figure, setFigure ] = useState(''); + const { trigger = null, setStringParam = null } = useWired(); + + const save = () => setStringParam((botName + WIRED_STRING_DELIMETER + figure)); + + useEffect(() => + { + const data = trigger.stringData.split(WIRED_STRING_DELIMETER); + + if(data.length > 0) setBotName(data[0]); + if(data.length > 1) setFigure(data[1].length > 0 ? data[1] : DEFAULT_FIGURE); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.bot.name') } + setBotName(event.target.value) } /> +
+
+ + +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionBotFollowAvatarView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotFollowAvatarView.tsx new file mode 100644 index 0000000000..9576ea04dc --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotFollowAvatarView.tsx @@ -0,0 +1,44 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionBotFollowAvatarView: FC<{}> = props => +{ + const [ botName, setBotName ] = useState(''); + const [ followMode, setFollowMode ] = useState(-1); + const { trigger = null, setStringParam = null, setIntParams = null } = useWired(); + + const save = () => + { + setStringParam(botName); + setIntParams([ followMode ]); + }; + + useEffect(() => + { + setBotName(trigger.stringData); + setFollowMode((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.bot.name') } + setBotName(event.target.value) } /> +
+
+
+ setFollowMode(1) } /> + { LocalizeText('wiredfurni.params.start.following') } +
+
+ setFollowMode(0) } /> + { LocalizeText('wiredfurni.params.stop.following') } +
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionBotGiveHandItemView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotGiveHandItemView.tsx new file mode 100644 index 0000000000..0dc2bc480f --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotGiveHandItemView.tsx @@ -0,0 +1,43 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +const ALLOWED_HAND_ITEM_IDS: number[] = [ 2, 5, 7, 8, 9, 10, 27 ]; + +export const WiredActionBotGiveHandItemView: FC<{}> = props => +{ + const [ botName, setBotName ] = useState(''); + const [ handItemId, setHandItemId ] = useState(-1); + const { trigger = null, setStringParam = null, setIntParams = null } = useWired(); + + const save = () => + { + setStringParam(botName); + setIntParams([ handItemId ]); + }; + + useEffect(() => + { + setBotName(trigger.stringData); + setHandItemId((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.bot.name') } + setBotName(event.target.value) } /> +
+
+ { LocalizeText('wiredfurni.params.handitem') } + +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionBotMoveView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotMoveView.tsx new file mode 100644 index 0000000000..644b34e1e6 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotMoveView.tsx @@ -0,0 +1,28 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionBotMoveView: FC<{}> = props => +{ + const [ botName, setBotName ] = useState(''); + const { trigger = null, setStringParam = null } = useWired(); + + const save = () => setStringParam(botName); + + useEffect(() => + { + setBotName(trigger.stringData); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.bot.name') } + setBotName(event.target.value) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionBotTalkToAvatarView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotTalkToAvatarView.tsx new file mode 100644 index 0000000000..b69a9724d0 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotTalkToAvatarView.tsx @@ -0,0 +1,53 @@ +import { FC, useEffect, useState } from 'react'; +import { GetConfigurationValue, LocalizeText, WIRED_STRING_DELIMETER, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionBotTalkToAvatarView: FC<{}> = props => +{ + const [ botName, setBotName ] = useState(''); + const [ message, setMessage ] = useState(''); + const [ talkMode, setTalkMode ] = useState(-1); + const { trigger = null, setStringParam = null, setIntParams = null } = useWired(); + + const save = () => + { + setStringParam(botName + WIRED_STRING_DELIMETER + message); + setIntParams([ talkMode ]); + }; + + useEffect(() => + { + const data = trigger.stringData.split(WIRED_STRING_DELIMETER); + + if(data.length > 0) setBotName(data[0]); + if(data.length > 1) setMessage(data[1].length > 0 ? data[1] : ''); + + setTalkMode((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.bot.name') } + setBotName(event.target.value) } /> +
+
+ { LocalizeText('wiredfurni.params.message') } + ('wired.action.bot.talk.to.avatar.max.length', 64) } type="text" value={ message } onChange={ event => setMessage(event.target.value) } /> +
+
+
+ setTalkMode(0) } /> + { LocalizeText('wiredfurni.params.talk') } +
+
+ setTalkMode(1) } /> + { LocalizeText('wiredfurni.params.whisper') } +
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionBotTalkView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotTalkView.tsx new file mode 100644 index 0000000000..31b6a14ce3 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotTalkView.tsx @@ -0,0 +1,53 @@ +import { FC, useEffect, useState } from 'react'; +import { GetConfigurationValue, LocalizeText, WIRED_STRING_DELIMETER, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionBotTalkView: FC<{}> = props => +{ + const [ botName, setBotName ] = useState(''); + const [ message, setMessage ] = useState(''); + const [ talkMode, setTalkMode ] = useState(-1); + const { trigger = null, setStringParam = null, setIntParams = null } = useWired(); + + const save = () => + { + setStringParam(botName + WIRED_STRING_DELIMETER + message); + setIntParams([ talkMode ]); + }; + + useEffect(() => + { + const data = trigger.stringData.split(WIRED_STRING_DELIMETER); + + if(data.length > 0) setBotName(data[0]); + if(data.length > 1) setMessage(data[1].length > 0 ? data[1] : ''); + + setTalkMode((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.bot.name') } + setBotName(event.target.value) } /> +
+
+ { LocalizeText('wiredfurni.params.message') } + ('wired.action.bot.talk.max.length', 64) } type="text" value={ message } onChange={ event => setMessage(event.target.value) } /> +
+
+
+ setTalkMode(0) } /> + { LocalizeText('wiredfurni.params.talk') } +
+
+ setTalkMode(1) } /> + { LocalizeText('wiredfurni.params.shout') } +
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionBotTeleportView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotTeleportView.tsx new file mode 100644 index 0000000000..1979930dca --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionBotTeleportView.tsx @@ -0,0 +1,28 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionBotTeleportView: FC<{}> = props => +{ + const [ botName, setBotName ] = useState(''); + const { trigger = null, setStringParam = null } = useWired(); + + const save = () => setStringParam(botName); + + useEffect(() => + { + setBotName(trigger.stringData); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.bot.name') } + setBotName(event.target.value) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionCallAnotherStackView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionCallAnotherStackView.tsx new file mode 100644 index 0000000000..69c17fe1f5 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionCallAnotherStackView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionCallAnotherStackView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionChaseView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionChaseView.tsx new file mode 100644 index 0000000000..d0e1c419f8 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionChaseView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionChaseView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionChatView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionChatView.tsx new file mode 100644 index 0000000000..8f622c2bc3 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionChatView.tsx @@ -0,0 +1,28 @@ +import { FC, useEffect, useState } from 'react'; +import { GetConfigurationValue, LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionChatView: FC<{}> = props => +{ + const [ message, setMessage ] = useState(''); + const { trigger = null, setStringParam = null } = useWired(); + + const save = () => setStringParam(message); + + useEffect(() => + { + setMessage(trigger.stringData); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.message') } + ('wired.action.chat.max.length', 100) } type="text" value={ message } onChange={ event => setMessage(event.target.value) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionFleeView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionFleeView.tsx new file mode 100644 index 0000000000..e3e5776082 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionFleeView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionFleeView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionGiveRewardView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionGiveRewardView.tsx new file mode 100644 index 0000000000..8e8716761d --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionGiveRewardView.tsx @@ -0,0 +1,161 @@ +import { FC, useEffect, useState } from 'react'; +import { FaPlus, FaTrash } from 'react-icons/fa'; +import ReactSlider from 'react-slider'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Button, Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionGiveRewardView: FC<{}> = props => +{ + const [ limitEnabled, setLimitEnabled ] = useState(false); + const [ rewardTime, setRewardTime ] = useState(1); + const [ uniqueRewards, setUniqueRewards ] = useState(false); + const [ rewardsLimit, setRewardsLimit ] = useState(1); + const [ limitationInterval, setLimitationInterval ] = useState(1); + const [ rewards, setRewards ] = useState<{ isBadge: boolean, itemCode: string, probability: number }[]>([]); + const { trigger = null, setIntParams = null, setStringParam = null } = useWired(); + + const addReward = () => setRewards(rewards => [ ...rewards, { isBadge: false, itemCode: '', probability: null } ]); + + const removeReward = (index: number) => + { + setRewards(prevValue => + { + const newValues = Array.from(prevValue); + + newValues.splice(index, 1); + + return newValues; + }); + }; + + const updateReward = (index: number, isBadge: boolean, itemCode: string, probability: number) => + { + const rewardsClone = Array.from(rewards); + const reward = rewardsClone[index]; + + if(!reward) return; + + reward.isBadge = isBadge; + reward.itemCode = itemCode; + reward.probability = probability; + + setRewards(rewardsClone); + }; + + const save = () => + { + let stringRewards = []; + + for(const reward of rewards) + { + if(!reward.itemCode) continue; + + const rewardsString = [ reward.isBadge ? '0' : '1', reward.itemCode, reward.probability.toString() ]; + stringRewards.push(rewardsString.join(',')); + } + + if(stringRewards.length > 0) + { + setStringParam(stringRewards.join(';')); + setIntParams([ rewardTime, uniqueRewards ? 1 : 0, rewardsLimit, limitationInterval ]); + } + }; + + useEffect(() => + { + const readRewards: { isBadge: boolean, itemCode: string, probability: number }[] = []; + + if(trigger.stringData.length > 0 && trigger.stringData.includes(';')) + { + const splittedRewards = trigger.stringData.split(';'); + + for(const rawReward of splittedRewards) + { + const reward = rawReward.split(','); + + if(reward.length !== 3) continue; + + readRewards.push({ isBadge: reward[0] === '0', itemCode: reward[1], probability: Number(reward[2]) }); + } + } + + if(readRewards.length === 0) readRewards.push({ isBadge: false, itemCode: '', probability: null }); + + setRewardTime((trigger.intData.length > 0) ? trigger.intData[0] : 0); + setUniqueRewards((trigger.intData.length > 1) ? (trigger.intData[1] === 1) : false); + setRewardsLimit((trigger.intData.length > 2) ? trigger.intData[2] : 0); + setLimitationInterval((trigger.intData.length > 3) ? trigger.intData[3] : 0); + setLimitEnabled((trigger.intData.length > 3) ? trigger.intData[3] > 0 : false); + setRewards(readRewards); + }, [ trigger ]); + + return ( + +
+ setLimitEnabled(event.target.checked) } /> + { LocalizeText('wiredfurni.params.prizelimit', [ 'amount' ], [ limitEnabled ? rewardsLimit.toString() : '' ]) } +
+ { !limitEnabled && + + Reward limit not set. Make sure rewards are badges or non-tradeable items. + } + { limitEnabled && + setRewardsLimit(event) } /> } +
+
+ How often can a user be rewarded? +
+ + { (rewardTime > 0) && setLimitationInterval(Number(event.target.value)) } /> } +
+
+
+
+ setUniqueRewards(e.target.checked) } /> + Unique rewards +
+ + If checked each reward will be given once to each user. This will disable the probabilities option. + +
+
+ Rewards + +
+
+ { rewards && rewards.map((reward, index) => + { + return ( +
+
+ updateReward(index, e.target.checked, reward.itemCode, reward.probability) } /> + Badge? +
+ updateReward(index, reward.isBadge, e.target.value, reward.probability) } /> + updateReward(index, reward.isBadge, reward.itemCode, Number(e.target.value)) } /> + { (index > 0) && + } +
+ ); + }) } +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionGiveScoreToPredefinedTeamView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionGiveScoreToPredefinedTeamView.tsx new file mode 100644 index 0000000000..02d228112a --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionGiveScoreToPredefinedTeamView.tsx @@ -0,0 +1,67 @@ +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionGiveScoreToPredefinedTeamView: FC<{}> = props => +{ + const [ points, setPoints ] = useState(1); + const [ time, setTime ] = useState(1); + const [ selectedTeam, setSelectedTeam ] = useState(1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ points, time, selectedTeam ]); + + useEffect(() => + { + if(trigger.intData.length >= 2) + { + setPoints(trigger.intData[0]); + setTime(trigger.intData[1]); + setSelectedTeam(trigger.intData[2]); + } + else + { + setPoints(1); + setTime(1); + setSelectedTeam(1); + } + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.setpoints', [ 'points' ], [ points.toString() ]) } + setPoints(event) } /> +
+
+ { LocalizeText('wiredfurni.params.settimesingame', [ 'times' ], [ time.toString() ]) } + setTime(event) } /> +
+
+ { LocalizeText('wiredfurni.params.team') } + { [ 1, 2, 3, 4 ].map(value => + { + return ( +
+ setSelectedTeam(value) } /> + { LocalizeText('wiredfurni.params.team.' + value) } +
+ ); + }) } +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionGiveScoreView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionGiveScoreView.tsx new file mode 100644 index 0000000000..a2b9f86bee --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionGiveScoreView.tsx @@ -0,0 +1,52 @@ +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionGiveScoreView: FC<{}> = props => +{ + const [ points, setPoints ] = useState(1); + const [ time, setTime ] = useState(1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ points, time ]); + + useEffect(() => + { + if(trigger.intData.length >= 2) + { + setPoints(trigger.intData[0]); + setTime(trigger.intData[1]); + } + else + { + setPoints(1); + setTime(1); + } + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.setpoints', [ 'points' ], [ points.toString() ]) } + setPoints(event) } /> +
+
+ { LocalizeText('wiredfurni.params.settimesingame', [ 'times' ], [ time.toString() ]) } + setTime(event) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionJoinTeamView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionJoinTeamView.tsx new file mode 100644 index 0000000000..10b8c24f2c --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionJoinTeamView.tsx @@ -0,0 +1,35 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionJoinTeamView: FC<{}> = props => +{ + const [ selectedTeam, setSelectedTeam ] = useState(-1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ selectedTeam ]); + + useEffect(() => + { + setSelectedTeam((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.team') } + { [ 1, 2, 3, 4 ].map(team => + { + return ( +
+ setSelectedTeam(team) } /> + { LocalizeText(`wiredfurni.params.team.${ team }`) } +
+ ); + }) } +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionKickFromRoomView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionKickFromRoomView.tsx new file mode 100644 index 0000000000..002426d089 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionKickFromRoomView.tsx @@ -0,0 +1,28 @@ +import { FC, useEffect, useState } from 'react'; +import { GetConfigurationValue, LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionKickFromRoomView: FC<{}> = props => +{ + const [ message, setMessage ] = useState(''); + const { trigger = null, setStringParam = null } = useWired(); + + const save = () => setStringParam(message); + + useEffect(() => + { + setMessage(trigger.stringData); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.message') } + ('wired.action.kick.from.room.max.length', 100) } type="text" value={ message } onChange={ event => setMessage(event.target.value) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionLayoutView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionLayoutView.tsx new file mode 100644 index 0000000000..36d14d4936 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionLayoutView.tsx @@ -0,0 +1,85 @@ +import { WiredActionLayoutCode } from '../../../../api'; +import { WiredActionBotChangeFigureView } from './WiredActionBotChangeFigureView'; +import { WiredActionBotFollowAvatarView } from './WiredActionBotFollowAvatarView'; +import { WiredActionBotGiveHandItemView } from './WiredActionBotGiveHandItemView'; +import { WiredActionBotMoveView } from './WiredActionBotMoveView'; +import { WiredActionBotTalkToAvatarView } from './WiredActionBotTalkToAvatarView'; +import { WiredActionBotTalkView } from './WiredActionBotTalkView'; +import { WiredActionBotTeleportView } from './WiredActionBotTeleportView'; +import { WiredActionCallAnotherStackView } from './WiredActionCallAnotherStackView'; +import { WiredActionChaseView } from './WiredActionChaseView'; +import { WiredActionChatView } from './WiredActionChatView'; +import { WiredActionFleeView } from './WiredActionFleeView'; +import { WiredActionGiveRewardView } from './WiredActionGiveRewardView'; +import { WiredActionGiveScoreToPredefinedTeamView } from './WiredActionGiveScoreToPredefinedTeamView'; +import { WiredActionGiveScoreView } from './WiredActionGiveScoreView'; +import { WiredActionJoinTeamView } from './WiredActionJoinTeamView'; +import { WiredActionKickFromRoomView } from './WiredActionKickFromRoomView'; +import { WiredActionLeaveTeamView } from './WiredActionLeaveTeamView'; +import { WiredActionMoveAndRotateFurniView } from './WiredActionMoveAndRotateFurniView'; +import { WiredActionMoveFurniToView } from './WiredActionMoveFurniToView'; +import { WiredActionMoveFurniView } from './WiredActionMoveFurniView'; +import { WiredActionMuteUserView } from './WiredActionMuteUserView'; +import { WiredActionResetView } from './WiredActionResetView'; +import { WiredActionSetFurniStateToView } from './WiredActionSetFurniStateToView'; +import { WiredActionTeleportView } from './WiredActionTeleportView'; +import { WiredActionToggleFurniStateView } from './WiredActionToggleFurniStateView'; + +export const WiredActionLayoutView = (code: number) => +{ + switch(code) + { + case WiredActionLayoutCode.BOT_CHANGE_FIGURE: + return ; + case WiredActionLayoutCode.BOT_FOLLOW_AVATAR: + return ; + case WiredActionLayoutCode.BOT_GIVE_HAND_ITEM: + return ; + case WiredActionLayoutCode.BOT_MOVE: + return ; + case WiredActionLayoutCode.BOT_TALK: + return ; + case WiredActionLayoutCode.BOT_TALK_DIRECT_TO_AVTR: + return ; + case WiredActionLayoutCode.BOT_TELEPORT: + return ; + case WiredActionLayoutCode.CALL_ANOTHER_STACK: + return ; + case WiredActionLayoutCode.CHASE: + return ; + case WiredActionLayoutCode.CHAT: + return ; + case WiredActionLayoutCode.FLEE: + return ; + case WiredActionLayoutCode.GIVE_REWARD: + return ; + case WiredActionLayoutCode.GIVE_SCORE: + return ; + case WiredActionLayoutCode.GIVE_SCORE_TO_PREDEFINED_TEAM: + return ; + case WiredActionLayoutCode.JOIN_TEAM: + return ; + case WiredActionLayoutCode.KICK_FROM_ROOM: + return ; + case WiredActionLayoutCode.LEAVE_TEAM: + return ; + case WiredActionLayoutCode.MOVE_FURNI: + return ; + case WiredActionLayoutCode.MOVE_AND_ROTATE_FURNI: + return ; + case WiredActionLayoutCode.MOVE_FURNI_TO: + return ; + case WiredActionLayoutCode.MUTE_USER: + return ; + case WiredActionLayoutCode.RESET: + return ; + case WiredActionLayoutCode.SET_FURNI_STATE: + return ; + case WiredActionLayoutCode.TELEPORT: + return ; + case WiredActionLayoutCode.TOGGLE_FURNI_STATE: + return ; + } + + return null; +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionLeaveTeamView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionLeaveTeamView.tsx new file mode 100644 index 0000000000..9202ed34b5 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionLeaveTeamView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionLeaveTeamView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionMoveAndRotateFurniView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionMoveAndRotateFurniView.tsx new file mode 100644 index 0000000000..d30b43bb42 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionMoveAndRotateFurniView.tsx @@ -0,0 +1,82 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +const directionOptions: { value: number, icon: string }[] = [ + { + value: 0, + icon: 'ne' + }, + { + value: 2, + icon: 'se' + }, + { + value: 4, + icon: 'sw' + }, + { + value: 6, + icon: 'nw' + } +]; + +const rotationOptions: number[] = [ 0, 1, 2, 3, 4, 5, 6 ]; + +export const WiredActionMoveAndRotateFurniView: FC<{}> = props => +{ + const [ movement, setMovement ] = useState(-1); + const [ rotation, setRotation ] = useState(-1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ movement, rotation ]); + + useEffect(() => + { + if(trigger.intData.length >= 2) + { + setMovement(trigger.intData[0]); + setRotation(trigger.intData[1]); + } + else + { + setMovement(-1); + setRotation(-1); + } + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.startdir') } +
+ { directionOptions.map(option => + { + return ( +
+ setMovement(option.value) } /> + + + +
+ ); + }) } +
+
+
+ { LocalizeText('wiredfurni.params.turn') } + { rotationOptions.map(option => + { + return ( +
+ setRotation(option) } /> + { LocalizeText(`wiredfurni.params.turn.${ option }`) } +
+ ); + }) } +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionMoveFurniToView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionMoveFurniToView.tsx new file mode 100644 index 0000000000..0b6d78155e --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionMoveFurniToView.tsx @@ -0,0 +1,76 @@ +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +const directionOptions: { value: number, icon: string }[] = [ + { + value: 0, + icon: 'ne' + }, + { + value: 2, + icon: 'se' + }, + { + value: 4, + icon: 'sw' + }, + { + value: 6, + icon: 'nw' + } +]; + +export const WiredActionMoveFurniToView: FC<{}> = props => +{ + const [ spacing, setSpacing ] = useState(-1); + const [ movement, setMovement ] = useState(-1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ movement, spacing ]); + + useEffect(() => + { + if(trigger.intData.length >= 2) + { + setSpacing(trigger.intData[1]); + setMovement(trigger.intData[0]); + } + else + { + setSpacing(-1); + setMovement(-1); + } + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.emptytiles', [ 'tiles' ], [ spacing.toString() ]) } + setSpacing(event) } /> +
+
+ { LocalizeText('wiredfurni.params.startdir') } +
+ { directionOptions.map(value => + { + return ( +
+ setMovement(value.value) } /> + +
+ ); + }) } +
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionMoveFurniView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionMoveFurniView.tsx new file mode 100644 index 0000000000..1a7c0edf72 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionMoveFurniView.tsx @@ -0,0 +1,100 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +const directionOptions: { value: number, icon: string }[] = [ + { + value: 4, + icon: 'ne' + }, + { + value: 5, + icon: 'se' + }, + { + value: 6, + icon: 'sw' + }, + { + value: 7, + icon: 'nw' + }, + { + value: 2, + icon: 'mv-2' + }, + { + value: 3, + icon: 'mv-3' + }, + { + value: 1, + icon: 'mv-1' + } +]; + +const rotationOptions: number[] = [ 0, 1, 2, 3 ]; + +export const WiredActionMoveFurniView: FC<{}> = props => +{ + const [ movement, setMovement ] = useState(-1); + const [ rotation, setRotation ] = useState(-1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ movement, rotation ]); + + useEffect(() => + { + if(trigger.intData.length >= 2) + { + setMovement(trigger.intData[0]); + setRotation(trigger.intData[1]); + } + else + { + setMovement(-1); + setRotation(-1); + } + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.movefurni') } +
+ setMovement(0) } /> + { LocalizeText('wiredfurni.params.movefurni.0') } +
+
+ { directionOptions.map(option => + { + return ( +
+ setMovement(option.value) } /> + +
+ ); + }) } +
+
+
+
+ { LocalizeText('wiredfurni.params.rotatefurni') } + { rotationOptions.map(option => + { + return ( +
+ setRotation(option) } /> + + { [ 1, 2 ].includes(option) && } + { LocalizeText(`wiredfurni.params.rotatefurni.${ option }`) } + +
+ ); + }) } +
+ + ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionMuteUserView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionMuteUserView.tsx new file mode 100644 index 0000000000..a5e2a3df51 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionMuteUserView.tsx @@ -0,0 +1,44 @@ +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { GetConfigurationValue, LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionMuteUserView: FC<{}> = props => +{ + const [ time, setTime ] = useState(-1); + const [ message, setMessage ] = useState(''); + const { trigger = null, setIntParams = null, setStringParam = null } = useWired(); + + const save = () => + { + setIntParams([ time ]); + setStringParam(message); + }; + + useEffect(() => + { + setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0); + setMessage(trigger.stringData); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.length.minutes', [ 'minutes' ], [ time.toString() ]) } + setTime(event) } /> +
+
+ { LocalizeText('wiredfurni.params.message') } + ('wired.action.mute.user.max.length', 100) } type="text" value={ message } onChange={ event => setMessage(event.target.value) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionResetView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionResetView.tsx new file mode 100644 index 0000000000..eed03e3ac2 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionResetView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionResetView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionSetFurniStateToView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionSetFurniStateToView.tsx new file mode 100644 index 0000000000..96b7237bc6 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionSetFurniStateToView.tsx @@ -0,0 +1,42 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionSetFurniStateToView: FC<{}> = props => +{ + const [ stateFlag, setStateFlag ] = useState(0); + const [ directionFlag, setDirectionFlag ] = useState(0); + const [ positionFlag, setPositionFlag ] = useState(0); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ stateFlag, directionFlag, positionFlag ]); + + useEffect(() => + { + setStateFlag(trigger.getBoolean(0) ? 1 : 0); + setDirectionFlag(trigger.getBoolean(1) ? 1 : 0); + setPositionFlag(trigger.getBoolean(2) ? 1 : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.conditions') } +
+ setStateFlag(event.target.checked ? 1 : 0) } /> + { LocalizeText('wiredfurni.params.condition.state') } +
+
+ setDirectionFlag(event.target.checked ? 1 : 0) } /> + { LocalizeText('wiredfurni.params.condition.direction') } +
+
+ setPositionFlag(event.target.checked ? 1 : 0) } /> + { LocalizeText('wiredfurni.params.condition.position') } +
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionTeleportView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionTeleportView.tsx new file mode 100644 index 0000000000..04ef42de8c --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionTeleportView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionTeleportView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/actions/WiredActionToggleFurniStateView.tsx b/Coolui v3 test/src/components/wired/views/actions/WiredActionToggleFurniStateView.tsx new file mode 100644 index 0000000000..486aa8e237 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/actions/WiredActionToggleFurniStateView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +export const WiredActionToggleFurniStateView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorHasHandItem.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorHasHandItem.tsx new file mode 100644 index 0000000000..5c6c391bfb --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorHasHandItem.tsx @@ -0,0 +1,34 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +const ALLOWED_HAND_ITEM_IDS: number[] = [ 2, 5, 7, 8, 9, 10, 27 ]; + +export const WiredConditionActorHasHandItemView: FC<{}> = props => +{ + const [ handItemId, setHandItemId ] = useState(-1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ handItemId ]); + + useEffect(() => + { + setHandItemId((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.handitem') } + +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsGroupMemberView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsGroupMemberView.tsx new file mode 100644 index 0000000000..0f425f3529 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsGroupMemberView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionActorIsGroupMemberView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsOnFurniView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsOnFurniView.tsx new file mode 100644 index 0000000000..9aedea64f4 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsOnFurniView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionActorIsOnFurniView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsTeamMemberView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsTeamMemberView.tsx new file mode 100644 index 0000000000..7fc69ba625 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsTeamMemberView.tsx @@ -0,0 +1,37 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +const teamIds: number[] = [ 1, 2, 3, 4 ]; + +export const WiredConditionActorIsTeamMemberView: FC<{}> = props => +{ + const [ selectedTeam, setSelectedTeam ] = useState(-1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ selectedTeam ]); + + useEffect(() => + { + setSelectedTeam((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.team') } + { teamIds.map(value => + { + return ( +
+ setSelectedTeam(value) } /> + { LocalizeText(`wiredfurni.params.team.${ value }`) } +
+ ); + }) } +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsWearingBadgeView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsWearingBadgeView.tsx new file mode 100644 index 0000000000..5a46f6448e --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsWearingBadgeView.tsx @@ -0,0 +1,28 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionActorIsWearingBadgeView: FC<{}> = props => +{ + const [ badge, setBadge ] = useState(''); + const { trigger = null, setStringParam = null } = useWired(); + + const save = () => setStringParam(badge); + + useEffect(() => + { + setBadge(trigger.stringData); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.badgecode') } + setBadge(event.target.value) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsWearingEffectView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsWearingEffectView.tsx new file mode 100644 index 0000000000..42188cc078 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionActorIsWearingEffectView.tsx @@ -0,0 +1,28 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionActorIsWearingEffectView: FC<{}> = props => +{ + const [ effect, setEffect ] = useState(-1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ effect ]); + + useEffect(() => + { + setEffect(trigger?.intData[0] ?? 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.tooltip.effectid') } + setEffect(parseInt(event.target.value)) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionBaseView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionBaseView.tsx new file mode 100644 index 0000000000..5782942cb3 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionBaseView.tsx @@ -0,0 +1,23 @@ +import { FC, PropsWithChildren } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredBaseView } from '../WiredBaseView'; + +export interface WiredConditionBaseViewProps +{ + hasSpecialInput: boolean; + requiresFurni: number; + save: () => void; +} + +export const WiredConditionBaseView: FC> = props => +{ + const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null } = props; + + const onSave = () => (save && save()); + + return ( + + { children } + + ); +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionDateRangeView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionDateRangeView.tsx new file mode 100644 index 0000000000..8eedbf3ba3 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionDateRangeView.tsx @@ -0,0 +1,59 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredDateToString, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionDateRangeView: FC<{}> = props => +{ + const [ startDate, setStartDate ] = useState(''); + const [ endDate, setEndDate ] = useState(''); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => + { + let startDateMili = 0; + let endDateMili = 0; + + const startDateInstance = new Date(startDate); + const endDateInstance = new Date(endDate); + + if(startDateInstance && endDateInstance) + { + startDateMili = startDateInstance.getTime() / 1000; + endDateMili = endDateInstance.getTime() / 1000; + } + + setIntParams([ startDateMili, endDateMili ]); + }; + + useEffect(() => + { + if(trigger.intData.length >= 2) + { + let startDate = new Date(); + let endDate = new Date(); + + if(trigger.intData[0] > 0) startDate = new Date((trigger.intData[0] * 1000)); + + if(trigger.intData[1] > 0) endDate = new Date((trigger.intData[1] * 1000)); + + setStartDate(WiredDateToString(startDate)); + setEndDate(WiredDateToString(endDate)); + } + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.startdate') } + setStartDate(e.target.value) } /> +
+
+ { LocalizeText('wiredfurni.params.enddate') } + setEndDate(e.target.value) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniHasAvatarOnView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniHasAvatarOnView.tsx new file mode 100644 index 0000000000..5575e13e98 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniHasAvatarOnView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionFurniHasAvatarOnView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniHasFurniOnView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniHasFurniOnView.tsx new file mode 100644 index 0000000000..7759f94740 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniHasFurniOnView.tsx @@ -0,0 +1,35 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionFurniHasFurniOnView: FC<{}> = props => +{ + const [ requireAll, setRequireAll ] = useState(-1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ requireAll ]); + + useEffect(() => + { + setRequireAll((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.requireall') } + { [ 0, 1 ].map(value => + { + return ( +
+ setRequireAll(value) } /> + { LocalizeText('wiredfurni.params.requireall.' + value) } +
+ ); + }) } +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniHasNotFurniOnView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniHasNotFurniOnView.tsx new file mode 100644 index 0000000000..44c193595d --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniHasNotFurniOnView.tsx @@ -0,0 +1,35 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionFurniHasNotFurniOnView: FC<{}> = props => +{ + const [ requireAll, setRequireAll ] = useState(-1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ requireAll ]); + + useEffect(() => + { + setRequireAll((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.not_requireall') } + { [ 0, 1 ].map(value => + { + return ( +
+ setRequireAll(value) } /> + { LocalizeText(`wiredfurni.params.not_requireall.${ value }`) } +
+ ); + }) } +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniIsOfTypeView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniIsOfTypeView.tsx new file mode 100644 index 0000000000..5cda9f79c4 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniIsOfTypeView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionFurniIsOfTypeView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniMatchesSnapshotView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniMatchesSnapshotView.tsx new file mode 100644 index 0000000000..176a0e6707 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionFurniMatchesSnapshotView.tsx @@ -0,0 +1,42 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionFurniMatchesSnapshotView: FC<{}> = props => +{ + const [ stateFlag, setStateFlag ] = useState(0); + const [ directionFlag, setDirectionFlag ] = useState(0); + const [ positionFlag, setPositionFlag ] = useState(0); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ stateFlag, directionFlag, positionFlag ]); + + useEffect(() => + { + setStateFlag(trigger.getBoolean(0) ? 1 : 0); + setDirectionFlag(trigger.getBoolean(1) ? 1 : 0); + setPositionFlag(trigger.getBoolean(2) ? 1 : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.conditions') } +
+ setStateFlag(event.target.checked ? 1 : 0) } /> + { LocalizeText('wiredfurni.params.condition.state') } +
+
+ setDirectionFlag(event.target.checked ? 1 : 0) } /> + { LocalizeText('wiredfurni.params.condition.direction') } +
+
+ setPositionFlag(event.target.checked ? 1 : 0) } /> + { LocalizeText('wiredfurni.params.condition.position') } +
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionLayoutView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionLayoutView.tsx new file mode 100644 index 0000000000..a1a88c2a95 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionLayoutView.tsx @@ -0,0 +1,64 @@ +import { WiredConditionlayout } from '../../../../api'; +import { WiredConditionActorHasHandItemView } from './WiredConditionActorHasHandItem'; +import { WiredConditionActorIsGroupMemberView } from './WiredConditionActorIsGroupMemberView'; +import { WiredConditionActorIsOnFurniView } from './WiredConditionActorIsOnFurniView'; +import { WiredConditionActorIsTeamMemberView } from './WiredConditionActorIsTeamMemberView'; +import { WiredConditionActorIsWearingBadgeView } from './WiredConditionActorIsWearingBadgeView'; +import { WiredConditionActorIsWearingEffectView } from './WiredConditionActorIsWearingEffectView'; +import { WiredConditionDateRangeView } from './WiredConditionDateRangeView'; +import { WiredConditionFurniHasAvatarOnView } from './WiredConditionFurniHasAvatarOnView'; +import { WiredConditionFurniHasFurniOnView } from './WiredConditionFurniHasFurniOnView'; +import { WiredConditionFurniHasNotFurniOnView } from './WiredConditionFurniHasNotFurniOnView'; +import { WiredConditionFurniIsOfTypeView } from './WiredConditionFurniIsOfTypeView'; +import { WiredConditionFurniMatchesSnapshotView } from './WiredConditionFurniMatchesSnapshotView'; +import { WiredConditionTimeElapsedLessView } from './WiredConditionTimeElapsedLessView'; +import { WiredConditionTimeElapsedMoreView } from './WiredConditionTimeElapsedMoreView'; +import { WiredConditionUserCountInRoomView } from './WiredConditionUserCountInRoomView'; + +export const WiredConditionLayoutView = (code: number) => +{ + switch(code) + { + case WiredConditionlayout.ACTOR_HAS_HANDITEM: + return ; + case WiredConditionlayout.ACTOR_IS_GROUP_MEMBER: + case WiredConditionlayout.NOT_ACTOR_IN_GROUP: + return ; + case WiredConditionlayout.ACTOR_IS_ON_FURNI: + case WiredConditionlayout.NOT_ACTOR_ON_FURNI: + return ; + case WiredConditionlayout.ACTOR_IS_IN_TEAM: + case WiredConditionlayout.NOT_ACTOR_IN_TEAM: + return ; + case WiredConditionlayout.ACTOR_IS_WEARING_BADGE: + case WiredConditionlayout.NOT_ACTOR_WEARS_BADGE: + return ; + case WiredConditionlayout.ACTOR_IS_WEARING_EFFECT: + case WiredConditionlayout.NOT_ACTOR_WEARING_EFFECT: + return ; + case WiredConditionlayout.DATE_RANGE_ACTIVE: + return ; + case WiredConditionlayout.FURNIS_HAVE_AVATARS: + case WiredConditionlayout.FURNI_NOT_HAVE_HABBO: + return ; + case WiredConditionlayout.HAS_STACKED_FURNIS: + return ; + case WiredConditionlayout.NOT_HAS_STACKED_FURNIS: + return ; + case WiredConditionlayout.STUFF_TYPE_MATCHES: + case WiredConditionlayout.NOT_FURNI_IS_OF_TYPE: + return ; + case WiredConditionlayout.STATES_MATCH: + case WiredConditionlayout.NOT_STATES_MATCH: + return ; + case WiredConditionlayout.TIME_ELAPSED_LESS: + return ; + case WiredConditionlayout.TIME_ELAPSED_MORE: + return ; + case WiredConditionlayout.USER_COUNT_IN: + case WiredConditionlayout.NOT_USER_COUNT_IN: + return ; + } + + return null; +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionTimeElapsedLessView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionTimeElapsedLessView.tsx new file mode 100644 index 0000000000..9054fe3d83 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionTimeElapsedLessView.tsx @@ -0,0 +1,33 @@ +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { GetWiredTimeLocale, LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionTimeElapsedLessView: FC<{}> = props => +{ + const [ time, setTime ] = useState(-1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ time ]); + + useEffect(() => + { + setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.allowbefore', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) } + setTime(event) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionTimeElapsedMoreView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionTimeElapsedMoreView.tsx new file mode 100644 index 0000000000..a31efdb986 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionTimeElapsedMoreView.tsx @@ -0,0 +1,33 @@ +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { GetWiredTimeLocale, LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionTimeElapsedMoreView: FC<{}> = props => +{ + const [ time, setTime ] = useState(-1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ time ]); + + useEffect(() => + { + setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.allowafter', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) } + setTime(event) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/conditions/WiredConditionUserCountInRoomView.tsx b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionUserCountInRoomView.tsx new file mode 100644 index 0000000000..d6557213f0 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/conditions/WiredConditionUserCountInRoomView.tsx @@ -0,0 +1,52 @@ +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +export const WiredConditionUserCountInRoomView: FC<{}> = props => +{ + const [ min, setMin ] = useState(1); + const [ max, setMax ] = useState(0); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ min, max ]); + + useEffect(() => + { + if(trigger.intData.length >= 2) + { + setMin(trigger.intData[0]); + setMax(trigger.intData[1]); + } + else + { + setMin(1); + setMax(0); + } + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.usercountmin', [ 'value' ], [ min.toString() ]) } + setMin(event) } /> +
+
+ { LocalizeText('wiredfurni.params.usercountmax', [ 'value' ], [ max.toString() ]) } + setMax(event) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarEnterRoomView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarEnterRoomView.tsx new file mode 100644 index 0000000000..2d948a4b52 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarEnterRoomView.tsx @@ -0,0 +1,39 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggerAvatarEnterRoomView: FC<{}> = props => +{ + const [ username, setUsername ] = useState(''); + const [ avatarMode, setAvatarMode ] = useState(0); + const { trigger = null, setStringParam = null } = useWired(); + + const save = () => setStringParam((avatarMode === 1) ? username : ''); + + useEffect(() => + { + setUsername(trigger.stringData); + setAvatarMode(trigger.stringData ? 1 : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.picktriggerer') } +
+ setAvatarMode(0) } /> + { LocalizeText('wiredfurni.params.anyavatar') } +
+
+ setAvatarMode(1) } /> + { LocalizeText('wiredfurni.params.certainavatar') } +
+ { (avatarMode === 1) && + setUsername(event.target.value) } /> } +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarSaysSomethingView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarSaysSomethingView.tsx new file mode 100644 index 0000000000..e2d9dd35c8 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarSaysSomethingView.tsx @@ -0,0 +1,46 @@ +import { GetSessionDataManager } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggerAvatarSaysSomethingView: FC<{}> = props => +{ + const [ message, setMessage ] = useState(''); + const [ triggererAvatar, setTriggererAvatar ] = useState(-1); + const { trigger = null, setStringParam = null, setIntParams = null } = useWired(); + + const save = () => + { + setStringParam(message); + setIntParams([ triggererAvatar ]); + }; + + useEffect(() => + { + setMessage(trigger.stringData); + setTriggererAvatar((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.whatissaid') } + setMessage(event.target.value) } /> +
+
+ { LocalizeText('wiredfurni.params.picktriggerer') } +
+ setTriggererAvatar(0) } /> + { LocalizeText('wiredfurni.params.anyavatar') } +
+
+ setTriggererAvatar(1) } /> + { GetSessionDataManager().userName } +
+
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarWalksOffFurniView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarWalksOffFurniView.tsx new file mode 100644 index 0000000000..fc6c198480 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarWalksOffFurniView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggerAvatarWalksOffFurniView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarWalksOnFurni.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarWalksOnFurni.tsx new file mode 100644 index 0000000000..217cbd58bb --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerAvatarWalksOnFurni.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggerAvatarWalksOnFurniView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerBaseView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerBaseView.tsx new file mode 100644 index 0000000000..7590d9aa86 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerBaseView.tsx @@ -0,0 +1,23 @@ +import { FC, PropsWithChildren } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredBaseView } from '../WiredBaseView'; + +export interface WiredTriggerBaseViewProps +{ + hasSpecialInput: boolean; + requiresFurni: number; + save: () => void; +} + +export const WiredTriggerBaseView: FC> = props => +{ + const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null } = props; + + const onSave = () => (save && save()); + + return ( + + { children } + + ); +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerBotReachedAvatarView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerBotReachedAvatarView.tsx new file mode 100644 index 0000000000..6aa3fde546 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerBotReachedAvatarView.tsx @@ -0,0 +1,28 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggerBotReachedAvatarView: FC<{}> = props => +{ + const [ botName, setBotName ] = useState(''); + const { trigger = null, setStringParam = null } = useWired(); + + const save = () => setStringParam(botName); + + useEffect(() => + { + setBotName(trigger.stringData); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.bot.name') } + setBotName(event.target.value) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerBotReachedStuffView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerBotReachedStuffView.tsx new file mode 100644 index 0000000000..0034603a11 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerBotReachedStuffView.tsx @@ -0,0 +1,28 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { NitroInput } from '../../../../layout'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggerBotReachedStuffView: FC<{}> = props => +{ + const [ botName, setBotName ] = useState(''); + const { trigger = null, setStringParam = null } = useWired(); + + const save = () => setStringParam(botName); + + useEffect(() => + { + setBotName(trigger.stringData); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.bot.name') } + setBotName(event.target.value) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerCollisionView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerCollisionView.tsx new file mode 100644 index 0000000000..d7efc34074 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerCollisionView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggerCollisionView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerExecuteOnceView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerExecuteOnceView.tsx new file mode 100644 index 0000000000..0b91a905c4 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerExecuteOnceView.tsx @@ -0,0 +1,33 @@ +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { GetWiredTimeLocale, LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggeExecuteOnceView: FC<{}> = props => +{ + const [ time, setTime ] = useState(1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ time ]); + + useEffect(() => + { + setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.settime', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) } + setTime(event) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerExecutePeriodicallyLongView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerExecutePeriodicallyLongView.tsx new file mode 100644 index 0000000000..b20e7ed708 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerExecutePeriodicallyLongView.tsx @@ -0,0 +1,33 @@ +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { FriendlyTime, LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggeExecutePeriodicallyLongView: FC<{}> = props => +{ + const [ time, setTime ] = useState(1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ time ]); + + useEffect(() => + { + setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.setlongtime', [ 'time' ], [ FriendlyTime.format(time * 5).toString() ]) } + setTime(event) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerExecutePeriodicallyView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerExecutePeriodicallyView.tsx new file mode 100644 index 0000000000..35471ce79d --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerExecutePeriodicallyView.tsx @@ -0,0 +1,33 @@ +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { GetWiredTimeLocale, LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggeExecutePeriodicallyView: FC<{}> = props => +{ + const [ time, setTime ] = useState(1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ time ]); + + useEffect(() => + { + setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.settime', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) } + setTime(event) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerGameEndsView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerGameEndsView.tsx new file mode 100644 index 0000000000..476ed70335 --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerGameEndsView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggerGameEndsView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerGameStartsView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerGameStartsView.tsx new file mode 100644 index 0000000000..5c9b93789e --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerGameStartsView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggerGameStartsView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerLayoutView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerLayoutView.tsx new file mode 100644 index 0000000000..0b0192244b --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerLayoutView.tsx @@ -0,0 +1,52 @@ +import { WiredTriggerLayout } from '../../../../api'; +import { WiredTriggerAvatarEnterRoomView } from './WiredTriggerAvatarEnterRoomView'; +import { WiredTriggerAvatarSaysSomethingView } from './WiredTriggerAvatarSaysSomethingView'; +import { WiredTriggerAvatarWalksOffFurniView } from './WiredTriggerAvatarWalksOffFurniView'; +import { WiredTriggerAvatarWalksOnFurniView } from './WiredTriggerAvatarWalksOnFurni'; +import { WiredTriggerBotReachedAvatarView } from './WiredTriggerBotReachedAvatarView'; +import { WiredTriggerBotReachedStuffView } from './WiredTriggerBotReachedStuffView'; +import { WiredTriggerCollisionView } from './WiredTriggerCollisionView'; +import { WiredTriggeExecuteOnceView } from './WiredTriggerExecuteOnceView'; +import { WiredTriggeExecutePeriodicallyLongView } from './WiredTriggerExecutePeriodicallyLongView'; +import { WiredTriggeExecutePeriodicallyView } from './WiredTriggerExecutePeriodicallyView'; +import { WiredTriggerGameEndsView } from './WiredTriggerGameEndsView'; +import { WiredTriggerGameStartsView } from './WiredTriggerGameStartsView'; +import { WiredTriggeScoreAchievedView } from './WiredTriggerScoreAchievedView'; +import { WiredTriggerToggleFurniView } from './WiredTriggerToggleFurniView'; + +export const WiredTriggerLayoutView = (code: number) => +{ + switch(code) + { + case WiredTriggerLayout.AVATAR_ENTERS_ROOM: + return ; + case WiredTriggerLayout.AVATAR_SAYS_SOMETHING: + return ; + case WiredTriggerLayout.AVATAR_WALKS_OFF_FURNI: + return ; + case WiredTriggerLayout.AVATAR_WALKS_ON_FURNI: + return ; + case WiredTriggerLayout.BOT_REACHED_AVATAR: + return ; + case WiredTriggerLayout.BOT_REACHED_STUFF: + return ; + case WiredTriggerLayout.COLLISION: + return ; + case WiredTriggerLayout.EXECUTE_ONCE: + return ; + case WiredTriggerLayout.EXECUTE_PERIODICALLY: + return ; + case WiredTriggerLayout.EXECUTE_PERIODICALLY_LONG: + return ; + case WiredTriggerLayout.GAME_ENDS: + return ; + case WiredTriggerLayout.GAME_STARTS: + return ; + case WiredTriggerLayout.SCORE_ACHIEVED: + return ; + case WiredTriggerLayout.TOGGLE_FURNI: + return ; + } + + return null; +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerScoreAchievedView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerScoreAchievedView.tsx new file mode 100644 index 0000000000..0c4c7385ca --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerScoreAchievedView.tsx @@ -0,0 +1,33 @@ +import { FC, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggeScoreAchievedView: FC<{}> = props => +{ + const [ points, setPoints ] = useState(1); + const { trigger = null, setIntParams = null } = useWired(); + + const save = () => setIntParams([ points ]); + + useEffect(() => + { + setPoints((trigger.intData.length > 0) ? trigger.intData[0] : 0); + }, [ trigger ]); + + return ( + +
+ { LocalizeText('wiredfurni.params.setscore', [ 'points' ], [ points.toString() ]) } + setPoints(event) } /> +
+
+ ); +}; diff --git a/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerToggleFurniView.tsx b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerToggleFurniView.tsx new file mode 100644 index 0000000000..474848174f --- /dev/null +++ b/Coolui v3 test/src/components/wired/views/triggers/WiredTriggerToggleFurniView.tsx @@ -0,0 +1,8 @@ +import { FC } from 'react'; +import { WiredFurniType } from '../../../../api'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +export const WiredTriggerToggleFurniView: FC<{}> = props => +{ + return ; +}; diff --git a/Coolui v3 test/src/css/backgrounds/BackgroundsView.css b/Coolui v3 test/src/css/backgrounds/BackgroundsView.css new file mode 100644 index 0000000000..d71a52c520 --- /dev/null +++ b/Coolui v3 test/src/css/backgrounds/BackgroundsView.css @@ -0,0 +1,947 @@ +.backgrounds-view-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 100; + pointer-events: none; +} + +@keyframes fadeIn { + to { opacity: 1; } +} + +.non-selectable { + cursor: default; +} + +.non-selectable .profile-background { + filter: opacity(0.5); + transition: linear 0.25s; +} + +.non-selectable .profile-background:hover { + filter: opacity(1); +} + +.background-edit-icon { + background-image: url('@/assets/images/infostand/icon_edit.gif'); + width: 19px; + height: 19px; + pointer-events: auto; + cursor: pointer; + z-index: 10; + display: block; + transition: opacity 0.2s ease; +} + +.background-edit-icon:hover { + opacity: 0.8; +} + +.background-edit-position { + position: absolute; + left: 8px; +} + +.profile-background { + background-repeat: no-repeat; + background-position: center; + height: 135px; + width: 68px; +} + +.profile-background.background-default { + background-color: #f0f0f0; +} + +.profile-stand { + background-repeat: no-repeat; + background-position: center; + height: 135px; + width: 68px; +} + +.profile-stand.stand-default { + background: none; +} + +.profile-overlay { + background-repeat: no-repeat; + background-position: center; + height: 135px; + width: 68px; +} + +.profile-overlay.overlay-default { + background: none; +} + +.profile-background { + background-repeat: no-repeat; + background-position: center; + height: 135px; + width: 68px; + + &.background-0 { + background-image: url('@/assets/images/backgrounds/background/bg_0.png'); + } + + &.background-1 { + background-image: url('@/assets/images/backgrounds/background/bg_1.gif'); + } + + &.background-2 { + background-image: url('@/assets/images/backgrounds/background/bg_2.png'); + } + + &.background-3 { + background-image: url('@/assets/images/backgrounds/background/bg_3.png'); + } + + &.background-4 { + background-image: url('@/assets/images/backgrounds/background/bg_4.png'); + } + + &.background-5 { + background-image: url('@/assets/images/backgrounds/background/bg_5.png'); + } + + &.background-6 { + background-image: url('@/assets/images/backgrounds/background/bg_6.png'); + } + + &.background-7 { + background-image: url('@/assets/images/backgrounds/background/bg_7.png'); + } + + &.background-8 { + background-image: url('@/assets/images/backgrounds/background/bg_8.png'); + } + + &.background-9 { + background-image: url('@/assets/images/backgrounds/background/bg_9.png'); + } + + &.background-10 { + background-image: url('@/assets/images/backgrounds/background/bg_10.png'); + } + + &.background-11 { + background-image: url('@/assets/images/backgrounds/background/bg_11.png'); + } + + &.background-12 { + background-image: url('@/assets/images/backgrounds/background/bg_12.png'); + } + + &.background-13 { + background-image: url('@/assets/images/backgrounds/background/bg_13.png'); + } + + &.background-14 { + background-image: url('@/assets/images/backgrounds/background/bg_14.png'); + } + + &.background-15 { + background-image: url('@/assets/images/backgrounds/background/bg_15.png'); + } + + &.background-16 { + background-image: url('@/assets/images/backgrounds/background/bg_16.png'); + } + + &.background-17 { + background-image: url('@/assets/images/backgrounds/background/bg_17.png'); + } + + &.background-18 { + background-image: url('@/assets/images/backgrounds/background/bg_18.png'); + } + + &.background-19 { + background-image: url('@/assets/images/backgrounds/background/bg_19.png'); + } + + &.background-20 { + background-image: url('@/assets/images/backgrounds/background/bg_20.png'); + } + + &.background-21 { + background-image: url('@/assets/images/backgrounds/background/bg_21.png'); + } + + &.background-22 { + background-image: url('@/assets/images/backgrounds/background/bg_22.png'); + } + + &.background-23 { + background-image: url('@/assets/images/backgrounds/background/bg_23.png'); + } + + &.background-24 { + background-image: url('@/assets/images/backgrounds/background/bg_24.png'); + } + + &.background-25 { + background-image: url('@/assets/images/backgrounds/background/bg_25.png'); + } + + &.background-26 { + background-image: url('@/assets/images/backgrounds/background/bg_26.png'); + } + + &.background-27 { + background-image: url('@/assets/images/backgrounds/background/bg_27.png'); + } + + &.background-28 { + background-image: url('@/assets/images/backgrounds/background/bg_28.png'); + } + + &.background-29 { + background-image: url('@/assets/images/backgrounds/background/bg_29.png'); + } + + &.background-30 { + background-image: url('@/assets/images/backgrounds/background/bg_30.png'); + } + + &.background-31 { + background-image: url('@/assets/images/backgrounds/background/bg_31.png'); + } + + &.background-32 { + background-image: url('@/assets/images/backgrounds/background/bg_32.png'); + } + + &.background-33 { + background-image: url('@/assets/images/backgrounds/background/bg_33.png'); + } + + &.background-34 { + background-image: url('@/assets/images/backgrounds/background/bg_34.png'); + } + + &.background-35 { + background-image: url('@/assets/images/backgrounds/background/bg_35.png'); + } + + &.background-36 { + background-image: url('@/assets/images/backgrounds/background/bg_36.gif'); + } + + &.background-37 { + background-image: url('@/assets/images/backgrounds/background/bg_37.png'); + } + + &.background-38 { + background-image: url('@/assets/images/backgrounds/background/bg_38.png'); + } + + &.background-39 { + background-image: url('@/assets/images/backgrounds/background/bg_39.png'); + } + + &.background-40 { + background-image: url('@/assets/images/backgrounds/background/bg_40.png'); + } + + &.background-41 { + background-image: url('@/assets/images/backgrounds/background/bg_41.png'); + } + + &.background-42 { + background-image: url('@/assets/images/backgrounds/background/bg_42.png'); + } + + &.background-43 { + background-image: url('@/assets/images/backgrounds/background/bg_43.png'); + } + + &.background-44 { + background-image: url('@/assets/images/backgrounds/background/bg_44.png'); + } + + &.background-45 { + background-image: url('@/assets/images/backgrounds/background/bg_45.png'); + } + + &.background-46 { + background-image: url('@/assets/images/backgrounds/background/bg_46.png'); + } + + &.background-47 { + background-image: url('@/assets/images/backgrounds/background/bg_47.png'); + } + + &.background-48 { + background-image: url('@/assets/images/backgrounds/background/bg_48.png'); + } + + &.background-49 { + background-image: url('@/assets/images/backgrounds/background/bg_49.png'); + } + + &.background-50 { + background-image: url('@/assets/images/backgrounds/background/bg_50.png'); + } + + &.background-51 { + background-image: url('@/assets/images/backgrounds/background/bg_51.gif'); + } + + &.background-52 { + background-image: url('@/assets/images/backgrounds/background/bg_52.gif'); + } + + &.background-53 { + background-image: url('@/assets/images/backgrounds/background/bg_53.gif'); + } + + &.background-54 { + background-image: url('@/assets/images/backgrounds/background/bg_54.gif'); + } + + &.background-55 { + background-image: url('@/assets/images/backgrounds/background/bg_55.gif'); + } + + &.background-56 { + background-image: url('@/assets/images/backgrounds/background/bg_56.gif'); + } + + &.background-57 { + background-image: url('@/assets/images/backgrounds/background/bg_57.gif'); + } + + &.background-58 { + background-image: url('@/assets/images/backgrounds/background/bg_58.gif'); + } + + &.background-59 { + background-image: url('@/assets/images/backgrounds/background/bg_59.gif'); + } + + &.background-60 { + background-image: url('@/assets/images/backgrounds/background/bg_60.gif'); + } + + &.background-61 { + background-image: url('@/assets/images/backgrounds/background/bg_61.gif'); + } + + &.background-62 { + background-image: url('@/assets/images/backgrounds/background/bg_62.gif'); + } + + &.background-63 { + background-image: url('@/assets/images/backgrounds/background/bg_63.gif'); + } + + &.background-64 { + background-image: url('@/assets/images/backgrounds/background/bg_64.gif'); + } + + &.background-65 { + background-image: url('@/assets/images/backgrounds/background/bg_65.gif'); + } + + &.background-66 { + background-image: url('@/assets/images/backgrounds/background/bg_66.gif'); + } + + &.background-67 { + background-image: url('@/assets/images/backgrounds/background/bg_67.gif'); + } + + &.background-68 { + background-image: url('@/assets/images/backgrounds/background/bg_68.gif'); + } + + &.background-69 { + background-image: url('@/assets/images/backgrounds/background/bg_69.gif'); + } + + &.background-70 { + background-image: url('@/assets/images/backgrounds/background/bg_70.gif'); + } + + &.background-71 { + background-image: url('@/assets/images/backgrounds/background/bg_71.gif'); + } + + &.background-72 { + background-image: url('@/assets/images/backgrounds/background/bg_72.gif'); + } + + &.background-73 { + background-image: url('@/assets/images/backgrounds/background/bg_73.gif'); + } + + &.background-74 { + background-image: url('@/assets/images/backgrounds/background/bg_74.gif'); + } + + &.background-75 { + background-image: url('@/assets/images/backgrounds/background/bg_75.gif'); + } + + &.background-76 { + background-image: url('@/assets/images/backgrounds/background/bg_76.gif'); + } + + &.background-77 { + background-image: url('@/assets/images/backgrounds/background/bg_77.gif'); + } + + &.background-78 { + background-image: url('@/assets/images/backgrounds/background/bg_78.gif'); + } + + &.background-79 { + background-image: url('@/assets/images/backgrounds/background/bg_79.gif'); + } + + &.background-80 { + background-image: url('@/assets/images/backgrounds/background/bg_80.gif'); + } + + &.background-81 { + background-image: url('@/assets/images/backgrounds/background/bg_81.gif'); + } + + &.background-82 { + background-image: url('@/assets/images/backgrounds/background/bg_82.gif'); + } + + &.background-83 { + background-image: url('@/assets/images/backgrounds/background/bg_83.gif'); + } + + &.background-84 { + background-image: url('@/assets/images/backgrounds/background/bg_84.gif'); + } + + &.background-85 { + background-image: url('@/assets/images/backgrounds/background/bg_85.gif'); + } + + &.background-86 { + background-image: url('@/assets/images/backgrounds/background/bg_86.png'); + } + + &.background-87 { + background-image: url('@/assets/images/backgrounds/background/bg_87.gif'); + } + + &.background-88 { + background-image: url('@/assets/images/backgrounds/background/bg_88.gif'); + } + + &.background-89 { + background-image: url('@/assets/images/backgrounds/background/bg_89.gif'); + } + + &.background-90 { + background-image: url('@/assets/images/backgrounds/background/bg_90.gif'); + } + + &.background-91 { + background-image: url('@/assets/images/backgrounds/background/bg_91.gif'); + } + + &.background-92 { + background-image: url('@/assets/images/backgrounds/background/bg_92.gif'); + } + + &.background-93 { + background-image: url('@/assets/images/backgrounds/background/bg_93.gif'); + } + + &.background-94 { + background-image: url('@/assets/images/backgrounds/background/bg_94.gif'); + } + + &.background-95 { + background-image: url('@/assets/images/backgrounds/background/bg_95.gif'); + } + + &.background-96 { + background-image: url('@/assets/images/backgrounds/background/bg_96.gif'); + } + + &.background-97 { + background-image: url('@/assets/images/backgrounds/background/bg_97.gif'); + } + + &.background-98 { + background-image: url('@/assets/images/backgrounds/background/bg_98.gif'); + } + + &.background-99 { + background-image: url('@/assets/images/backgrounds/background/bg_99.gif'); + } + + &.background-100 { + background-image: url('@/assets/images/backgrounds/background/bg_100.gif'); + } + + &.background-101 { + background-image: url('@/assets/images/backgrounds/background/bg_101.png'); + } + + &.background-102 { + background-image: url('@/assets/images/backgrounds/background/bg_102.gif'); + } + + &.background-103 { + background-image: url('@/assets/images/backgrounds/background/bg_103.gif'); + } + + &.background-104 { + background-image: url('@/assets/images/backgrounds/background/bg_104.gif'); + } + + &.background-105 { + background-image: url('@/assets/images/backgrounds/background/bg_105.gif'); + } + + &.background-106 { + background-image: url('@/assets/images/backgrounds/background/bg_106.gif'); + } + + &.background-107 { + background-image: url('@/assets/images/backgrounds/background/bg_107.gif'); + } + + &.background-108 { + background-image: url('@/assets/images/backgrounds/background/bg_108.gif'); + } + + &.background-109 { + background-image: url('@/assets/images/backgrounds/background/bg_109.gif'); + } + + &.background-110 { + background-image: url('@/assets/images/backgrounds/background/bg_110.gif'); + } + + &.background-111 { + background-image: url('@/assets/images/backgrounds/background/bg_111.gif'); + } + + &.background-112 { + background-image: url('@/assets/images/backgrounds/background/bg_112.gif'); + } + + &.background-113 { + background-image: url('@/assets/images/backgrounds/background/bg_113.gif'); + } + + &.background-114 { + background-image: url('@/assets/images/backgrounds/background/bg_114.gif'); + } + + &.background-115 { + background-image: url('@/assets/images/backgrounds/background/bg_115.gif'); + } + + &.background-116 { + background-image: url('@/assets/images/backgrounds/background/bg_116.gif'); + } + + &.background-117 { + background-image: url('@/assets/images/backgrounds/background/bg_117.gif'); + } + + &.background-118 { + background-image: url('@/assets/images/backgrounds/background/bg_118.gif'); + } + + &.background-119 { + background-image: url('@/assets/images/backgrounds/background/bg_119.gif'); + } + + &.background-120 { + background-image: url('@/assets/images/backgrounds/background/bg_120.gif'); + } + + &.background-121 { + background-image: url('@/assets/images/backgrounds/background/bg_121.gif'); + } + + &.background-122 { + background-image: url('@/assets/images/backgrounds/background/bg_122.gif'); + } + + &.background-123 { + background-image: url('@/assets/images/backgrounds/background/bg_123.gif'); + } + + &.background-124 { + background-image: url('@/assets/images/backgrounds/background/bg_124.gif'); + } + + &.background-125 { + background-image: url('@/assets/images/backgrounds/background/bg_125.gif'); + } + + &.background-126 { + background-image: url('@/assets/images/backgrounds/background/bg_126.gif'); + } + + &.background-127 { + background-image: url('@/assets/images/backgrounds/background/bg_127.gif'); + } + + &.background-128 { + background-image: url('@/assets/images/backgrounds/background/bg_128.gif'); + } + + &.background-129 { + background-image: url('@/assets/images/backgrounds/background/bg_129.gif'); + } + + &.background-130 { + background-image: url('@/assets/images/backgrounds/background/bg_130.gif'); + } + + &.background-131 { + background-image: url('@/assets/images/backgrounds/background/bg_131.gif'); + } + + &.background-132 { + background-image: url('@/assets/images/backgrounds/background/bg_132.gif'); + } + + &.background-133 { + background-image: url('@/assets/images/backgrounds/background/bg_133.gif'); + } + + &.background-134 { + background-image: url('@/assets/images/backgrounds/background/bg_134.gif'); + } + + &.background-135 { + background-image: url('@/assets/images/backgrounds/background/bg_135.gif'); + } + + &.background-136 { + background-image: url('@/assets/images/backgrounds/background/bg_136.gif'); + } + + &.background-137 { + background-image: url('@/assets/images/backgrounds/background/bg_137.gif'); + } + + &.background-138 { + background-image: url('@/assets/images/backgrounds/background/bg_138.gif'); + } + + &.background-139 { + background-image: url('@/assets/images/backgrounds/background/bg_139.gif'); + } + + &.background-140 { + background-image: url('@/assets/images/backgrounds/background/bg_140.gif'); + } + + &.background-141 { + background-image: url('@/assets/images/backgrounds/background/bg_141.gif'); + } + + &.background-142 { + background-image: url('@/assets/images/backgrounds/background/bg_142.gif'); + } + + &.background-143 { + background-image: url('@/assets/images/backgrounds/background/bg_143.gif'); + } + + &.background-144 { + background-image: url('@/assets/images/backgrounds/background/bg_144.gif'); + } + + &.background-145 { + background-image: url('@/assets/images/backgrounds/background/bg_145.gif'); + } + + &.background-146 { + background-image: url('@/assets/images/backgrounds/background/bg_146.gif'); + } + + &.background-147 { + background-image: url('@/assets/images/backgrounds/background/bg_147.gif'); + } + + &.background-148 { + background-image: url('@/assets/images/backgrounds/background/bg_148.gif'); + } + + &.background-149 { + background-image: url('@/assets/images/backgrounds/background/bg_149.gif'); + } + + &.background-150 { + background-image: url('@/assets/images/backgrounds/background/bg_150.gif'); + } + + &.background-151 { + background-image: url('@/assets/images/backgrounds/background/bg_151.gif'); + } + + &.background-152 { + background-image: url('@/assets/images/backgrounds/background/bg_152.gif'); + } + + &.background-153 { + background-image: url('@/assets/images/backgrounds/background/bg_153.gif'); + } + + &.background-154 { + background-image: url('@/assets/images/backgrounds/background/bg_154.gif'); + } + + &.background-155 { + background-image: url('@/assets/images/backgrounds/background/bg_155.gif'); + } + + &.background-156 { + background-image: url('@/assets/images/backgrounds/background/bg_156.gif'); + } + + &.background-157 { + background-image: url('@/assets/images/backgrounds/background/bg_157.gif'); + } + + &.background-158 { + background-image: url('@/assets/images/backgrounds/background/bg_158.gif'); + } + + &.background-159 { + background-image: url('@/assets/images/backgrounds/background/bg_159.gif'); + } + + &.background-160 { + background-image: url('@/assets/images/backgrounds/background/bg_160.gif'); + } + + &.background-161 { + background-image: url('@/assets/images/backgrounds/background/bg_161.gif'); + } + + &.background-162 { + background-image: url('@/assets/images/backgrounds/background/bg_162.gif'); + } + + &.background-163 { + background-image: url('@/assets/images/backgrounds/background/bg_163.gif'); + } + + &.background-164 { + background-image: url('@/assets/images/backgrounds/background/bg_164.gif'); + } + + &.background-165 { + background-image: url('@/assets/images/backgrounds/background/bg_165.gif'); + } + + &.background-166 { + background-image: url('@/assets/images/backgrounds/background/bg_166.gif'); + } + + &.background-167 { + background-image: url('@/assets/images/backgrounds/background/bg_167.gif'); + } + + &.background-168 { + background-image: url('@/assets/images/backgrounds/background/bg_168.gif'); + } + + &.background-169 { + background-image: url('@/assets/images/backgrounds/background/bg_169.gif'); + } + + &.background-170 { + background-image: url('@/assets/images/backgrounds/background/bg_170.png'); + } + + &.background-171 { + background-image: url('@/assets/images/backgrounds/background/bg_171.png'); + } + + &.background-172 { + background-image: url('@/assets/images/backgrounds/background/bg_172.png'); + } + + &.background-173 { + background-image: url('@/assets/images/backgrounds/background/bg_173.png'); + } + + &.background-174 { + background-image: url('@/assets/images/backgrounds/background/bg_174.png'); + } + + &.background-175 { + background-image: url('@/assets/images/backgrounds/background/bg_175.png'); + } + + &.background-176 { + background-image: url('@/assets/images/backgrounds/background/bg_176.png'); + } + + &.background-177 { + background-image: url('@/assets/images/backgrounds/background/bg_177.gif'); + } + + &.background-178 { + background-image: url('@/assets/images/backgrounds/background/bg_178.png'); + } + + &.background-179 { + background-image: url('@/assets/images/backgrounds/background/bg_179.png'); + } + + &.background-180 { + background-image: url('@/assets/images/backgrounds/background/bg_180.png'); + } + + &.background-181 { + background-image: url('@/assets/images/backgrounds/background/bg_181.png'); + } + + &.background-182 { + background-image: url('@/assets/images/backgrounds/background/bg_182.png'); + } + + &.background-183 { + background-image: url('@/assets/images/backgrounds/background/bg_183.png'); + } + + &.background-184 { + background-image: url('@/assets/images/backgrounds/background/bg_184.png'); + } + + &.background-185 { + background-image: url('@/assets/images/backgrounds/background/bg_185.png'); + } + + &.background-186 { + background-image: url('@/assets/images/backgrounds/background/bg_186.png'); + } + + &.background-187 { + background-image: url('@/assets/images/backgrounds/background/bg_187.gif'); + } +} + +.profile-stand { + background-repeat: no-repeat; + background-position: center; + height: 135px; + width: 68px; + + &.stand-0 { + background-image: url('@/assets/images/backgrounds/stand_0.png'); + } + &.stand-1 { + background-image: url('@/assets/images/backgrounds/stand_1.png'); + } + &.stand-2 { + background-image: url('@/assets/images/backgrounds/stand_2.png'); + } + &.stand-3 { + background-image: url('@/assets/images/backgrounds/stand_3.png'); + } + &.stand-4 { + background-image: url('@/assets/images/backgrounds/stand_4.png'); + } + &.stand-5 { + background-image: url('@/assets/images/backgrounds/stand_5.png'); + } + &.stand-6 { + background-image: url('@/assets/images/backgrounds/stand_6.png'); + } + &.stand-7 { + background-image: url('@/assets/images/backgrounds/stand_7.png'); + } + &.stand-8 { + background-image: url('@/assets/images/backgrounds/stand_8.png'); + } + &.stand-9 { + background-image: url('@/assets/images/backgrounds/stand_9.png'); + } + &.stand-10 { + background-image: url('@/assets/images/backgrounds/stand_10.png'); + } + &.stand-11 { + background-image: url('@/assets/images/backgrounds/stand_11.png'); + } + &.stand-12 { + background-image: url('@/assets/images/backgrounds/stand_12.png'); + } + &.stand-13 { + background-image: url('@/assets/images/backgrounds/stand_13.png'); + } + &.stand-14 { + background-image: url('@/assets/images/backgrounds/stand_14.png'); + } + &.stand-15 { + background-image: url('@/assets/images/backgrounds/stand_15.png'); + } + &.stand-16 { + background-image: url('@/assets/images/backgrounds/stand_16.png'); + } + &.stand-17 { + background-image: url('@/assets/images/backgrounds/stand_17.png'); + } + &.stand-18 { + background-image: url('@/assets/images/backgrounds/stand_18.png'); + } + &.stand-19 { + background-image: url('@/assets/images/backgrounds/stand_19.png'); + } + &.stand-20 { + background-image: url('@/assets/images/backgrounds/stand_20.png'); + } + &.stand-21 { + background-image: url('@/assets/images/backgrounds/stand_21.gif'); + } +} + +.profile-overlay { + background-repeat: no-repeat; + background-position: center; + height: 135px; + width: 68px; + + &.overlay-0 { + background-image: url('@/assets/images/backgrounds/overlay/overlay_0.png'); + } + &.overlay-1 { + background-image: url('@/assets/images/backgrounds/overlay/overlay_1.png'); + } + &.overlay-2 { + background-image: url('@/assets/images/backgrounds/overlay/overlay_2.png'); + } + &.overlay-3 { + background-image: url('@/assets/images/backgrounds/overlay/overlay_3.png'); + } + &.overlay-4 { + background-image: url('@/assets/images/backgrounds/overlay/overlay_4.png'); + } + &.overlay-5 { + background-image: url('@/assets/images/backgrounds/overlay/overlay_5.gif'); + } + &.overlay-6 { + background-image: url('@/assets/images/backgrounds/overlay/overlay_6.png'); + } + &.overlay-7 { + background-image: url('@/assets/images/backgrounds/overlay/overlay_7.png'); + } + &.overlay-8 { + background-image: url('@/assets/images/backgrounds/overlay/overlay_8.png'); + } +} \ No newline at end of file diff --git a/Coolui v3 test/src/css/chat/ChatHistoryView.css b/Coolui v3 test/src/css/chat/ChatHistoryView.css new file mode 100644 index 0000000000..815aafd666 --- /dev/null +++ b/Coolui v3 test/src/css/chat/ChatHistoryView.css @@ -0,0 +1,28 @@ +.nitro-chat-history { + background-color: #f0f0f0; + width: 400px; + height: 400px; + } + +.nitro-chat-history .nitro-card-content { + height: 100%; + background-image: url('@/assets/images/chat/chathistory_background.png'); + background-repeat: repeat; + background-size: auto; + background-color: #f0f0f0; +} + +.nitro-chat-history .p-1.slide-in { + animation: slideIn 0.3s ease-out; +} + +@keyframes slideIn { + 0% { + transform: translateY(-20px); + opacity: 0; + } + 100% { + transform: translateY(0); + opacity: 1; + } +} \ No newline at end of file diff --git a/Coolui v3 test/src/css/chat/chats.css b/Coolui v3 test/src/css/chat/chats.css new file mode 100644 index 0000000000..7d9c1738f3 --- /dev/null +++ b/Coolui v3 test/src/css/chat/chats.css @@ -0,0 +1,856 @@ +.bubble-container { + transition: top 0.2s ease 0s; + + .chat-bubble { + border-image-slice: 17 6 6 29 fill; + border-image-width: 17px 6px 6px 29px; + border-image-outset: 2px 0px 0px 0px; + border-image-repeat: repeat repeat; + + &.type-0 { + + // normal + .message { + font-weight: 400; + } + } + + &.type-1 { + + // whisper + .message { + font-weight: 400; + font-style: italic; + color: #595959; + } + } + + &.type-2 { + + // shout + .message { + font-weight: 700; + } + } + + &.bubble-0 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_0_transparent.png'); + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png'); + bottom: -5px; + } + } + + &.bubble-1 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_1.png'); + + border-image-slice: 18 6 6 29 fill; + border-image-width: 18px 6px 6px 29px; + border-image-outset: 3px 0px 0px 0px; + + .user-container { + display: none; + } + + .username { + display: none; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png'); + } + } + + &.bubble-2, + &.bubble-31 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_2.png'); + + .user-container { + display: none; + } + + .username { + color: rgba(#FFF, 1); + } + + .message { + color: rgba(#FFF, 1) !important; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_2_31_pointer.png'); + height: 7px; + } + } + + &.bubble-3 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_3.png'); + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_3_pointer.png'); + } + } + + &.bubble-4 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_4.png'); + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_4_pointer.png'); + } + } + + &.bubble-5 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_5.png'); + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_5_pointer.png'); + } + } + + &.bubble-6 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_6.png'); + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_6_pointer.png'); + } + } + + &.bubble-7 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_7.png'); + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_7_pointer.png'); + } + } + + &.bubble-8 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_8.png'); + + border-image-slice: 20 6 6 27 fill; + border-image-width: 20px 6px 6px 27px; + border-image-outset: 5px 0px 0px 0px; + + .chat-content { + color: #fff; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_8_pointer.png'); + } + } + + &.bubble-9 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_9.png'); + + border-image-slice: 17 18 12 19 fill; + border-image-width: 17px 18px 12px 19px; + border-image-outset: 7px 7px 0px 9px; + + .chat-content { + margin-left: 20px; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_9_pointer.png'); + width: 7px; + height: 10px; + bottom: -6px; + } + } + + &.bubble-10 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_10.png'); + + border-image-slice: 29 18 8 37 fill; + border-image-width: 29px 18px 8px 37px; + border-image-outset: 12px 7px 1px 5px; + + .chat-content { + margin-left: 24px; + color: #fff; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_10_pointer.png'); + width: 7px; + height: 8px; + bottom: -3px; + } + } + + &.bubble-11 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_11.png'); + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_11_pointer.png'); + } + } + + &.bubble-12 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_12.png'); + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_12_pointer.png'); + } + } + + &.bubble-13 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_13.png'); + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_13_pointer.png'); + } + } + + &.bubble-14 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_14.png'); + + .chat-content { + color: #fff; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_14_pointer.png'); + } + } + + &.bubble-15 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_15.png'); + + .chat-content { + color: #fff; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_15_pointer.png'); + } + } + + &.bubble-16 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_16.png'); + + border-image-slice: 13 6 10 31 fill; + border-image-width: 13px 6px 10px 31px; + border-image-outset: 6px 0px 0px 0px; + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_16_pointer.png'); + height: 8px; + } + } + + &.bubble-17 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_17.png'); + + border-image-slice: 24 6 8 35 fill; + border-image-width: 24px 6px 8px 35px; + border-image-outset: 9px 0px 2px 5px; + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_17_pointer.png'); + } + } + + &.bubble-18 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_18.png'); + + border-image-slice: 7 16 8 16 fill; + border-image-width: 7px 16px 8px 16px; + border-image-outset: 3px 10px 2px 11px; + + .chat-content { + margin-left: 20px; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_18_pointer.png'); + height: 8px; + } + } + + &.bubble-19 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_19.png'); + + border-image-slice: 17 6 9 19 fill; + border-image-width: 17px 6px 9px 19px; + border-image-outset: 5px 0px 0px 8px; + + .chat-content { + margin-left: 20px; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_19_20_pointer.png'); + } + } + + &.bubble-20 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_20.png'); + + border-image-slice: 18 6 8 19 fill; + border-image-width: 18px 6px 8px 19px; + border-image-outset: 5px 0px 0px 8px; + + .chat-content { + margin-left: 20px; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_19_20_pointer.png'); + } + } + + &.bubble-21 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_21.png'); + + border-image-slice: 20 6 12 24 fill; + border-image-width: 20px 6px 12px 24px; + border-image-outset: 13px 2px 1px 3px; + + .chat-content { + margin-left: 20px; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_21_pointer.png'); + bottom: -4px; + } + } + + &.bubble-22 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_22.png'); + + border-image-slice: 18 19 11 33 fill; + border-image-width: 18px 19px 11px 33px; + border-image-outset: 7px 1px 1px 5px; + + .chat-content { + margin-left: 20px; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_22_pointer.png'); + } + } + + &.bubble-23 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_23.png'); + + border-image-slice: 16 6 7 32 fill; + border-image-width: 16px 6px 7px 32px; + border-image-outset: 5px 0px 0px 3px; + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_23_37_pointer.png'); + } + } + + &.bubble-24 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_24.png'); + + border-image-slice: 23 8 6 40 fill; + border-image-width: 23px 8px 6px 40px; + border-image-outset: 6px 0px 0px 6px; + + .chat-content { + margin-left: 30px; + color: #fff; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_24_pointer.png'); + bottom: -4px; + } + } + + &.bubble-25 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_25.png'); + + border-image-slice: 10 13 8 28 fill; + border-image-width: 10px 13px 8px 28px; + border-image-outset: 6px 3px 2px 0px; + + .chat-content { + color: #fff; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_25_pointer.png'); + height: 9px; + bottom: -7px; + } + } + + &.bubble-26 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_26.png'); + + border-image-slice: 16 9 8 29 fill; + border-image-width: 16px 9px 8px 29px; + border-image-outset: 2px 2px 2px 0px; + + .chat-content { + color: #c59432; + text-shadow: 1px 1px rgba(0, 0, 0, 0.3); + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_26_pointer.png'); + height: 10px; + bottom: -6px; + } + } + + &.bubble-27 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_27.png'); + + border-image-slice: 25 6 5 36 fill; + border-image-width: 25px 6px 5px 36px; + border-image-outset: 8px 0px 0px 5px; + + .chat-content { + margin-left: 30px; + color: #fff; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_27_pointer.png'); + } + } + + &.bubble-28 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_28.png'); + + border-image-slice: 16 7 7 27 fill; + border-image-width: 16px 7px 7px 27px; + border-image-outset: 3px 0px 0px 0px; + + .chat-content { + margin-left: 25px; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_28_pointer.png'); + } + } + + &.bubble-29 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_29.png'); + + border-image-slice: 10 7 15 31 fill; + border-image-width: 10px 7px 15px 31px; + border-image-outset: 2px 0px 0px 1px; + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_29_pointer.png'); + bottom: -4px; + } + } + + &.bubble-30 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_30.png'); + + .user-container { + display: none; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_30_pointer.png'); + height: 7px; + } + } + + &.bubble-32 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_32.png'); + + border-image-slice: 15 7 7 30 fill; + border-image-width: 15px 7px 7px 30px; + border-image-outset: 2px 0px 0px 0px; + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_32_pointer.png'); + } + } + + &.bubble-33 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_33_34.png'); + + border-image-slice: 7 6 6 39 fill; + border-image-width: 7px 6px 6px 39px; + border-image-outset: 2px 0px 0px 0px; + + .user-container { + display: none; + } + + .chat-content { + margin-left: 35px; + } + + &::before { + content: ' '; + position: absolute; + width: 19px; + height: 19px; + left: 9px; + top: 2px; + background: url('@/assets/images/chat/chatbubbles/bubble_33_extra.png'); + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png'); + } + } + + &.bubble-34 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_33_34.png'); + + border-image-slice: 7 6 6 39 fill; + border-image-width: 7px 6px 6px 39px; + border-image-outset: 2px 0px 0px 0px; + + &.type-1 { + .message { + font-style: unset; + color: inherit; + } + } + + .user-container { + display: none; + } + + .username { + display: none; + } + + .chat-content { + margin-left: 35px; + } + + &::before { + content: ' '; + position: absolute; + width: 19px; + height: 19px; + left: 9px; + top: 2px; + background: url('@/assets/images/chat/chatbubbles/bubble_34_extra.png'); + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png'); + } + } + + &.bubble-35 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_35.png'); + + border-image-slice: 19 6 5 29 fill; + border-image-width: 19px 6px 5px 29px; + border-image-outset: 4px 0px 0px 0px; + + .user-container { + display: none; + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_35_pointer.png'); + } + } + + &.bubble-36 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_36.png'); + + border-image-slice: 17 7 5 30 fill; + border-image-width: 17px 7px 5px 30px; + border-image-outset: 2px 0px 0px 0px; + + .user-container { + display: none; + } + + &::before { + content: ' '; + position: absolute; + width: 13px; + height: 18px; + left: 5px; + top: 2px; + background: url('@/assets/images/chat/chatbubbles/bubble_36_extra.png'); + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_36_pointer.png'); + } + } + + &.bubble-37 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_37.png'); + + border-image-slice: 16 6 7 32 fill; + border-image-width: 16px 6px 7px 32px; + border-image-outset: 5px 0px 0px 3px; + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_23_37_pointer.png'); + } + } + + &.bubble-38 { + border-image-source: url('@/assets/images/chat/chatbubbles/bubble_38.png'); + + border-image-slice: 17 7 5 30 fill; + border-image-width: 17px 7px 5px 30px; + border-image-outset: 2px 0px 0px 0px; + + .user-container { + display: none; + } + + &::before { + content: ' '; + position: absolute; + width: 19px; + height: 19px; + left: 3px; + top: 2px; + background: url('@/assets/images/chat/chatbubbles/bubble_38_extra.png'); + } + + .pointer { + background: url('@/assets/images/chat/chatbubbles/bubble_38_pointer.png'); + } + } + + .user-container { + z-index: 3; + display: flex; + align-items: center; + justify-content: center; + height: 100%; + max-height: 24px; + overflow: hidden; + + .user-image { + position: absolute; + top: -15px; + left: -9.25px; + width: 45px; + height: 65px; + background-repeat: no-repeat; + background-position: center; + transform: scale(0.5); + overflow: hidden; + image-rendering: initial; + } + } + + .chat-content { + padding: 5px 6px 5px 4px; + margin-left: 27px; + line-height: 1; + color: #000; + min-height: 25px; + } + } +} + +.chat-bubble-icon { + background-repeat: no-repeat; + background-position: center; + + &.bubble-0 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_0.png'); + } + + &.bubble-1 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_1.png'); + height: 25px; + } + + &.bubble-2, + &.bubble-31 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_2.png'); + } + + &.bubble-3 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_3.png'); + } + + &.bubble-4 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_4.png'); + } + + &.bubble-5 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_5.png'); + } + + &.bubble-6 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_6.png'); + } + + &.bubble-7 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_7.png'); + } + + &.bubble-8 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_8.png'); + } + + &.bubble-9 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_9.png'); + } + + &.bubble-10 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_10.png'); + } + + &.bubble-11 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_11.png'); + } + + &.bubble-12 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_12.png'); + } + + &.bubble-13 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_13.png'); + } + + &.bubble-14 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_14.png'); + } + + &.bubble-15 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_15.png'); + } + + &.bubble-16 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_16.png'); + } + + &.bubble-17 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_17.png'); + } + + &.bubble-18 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_18.png'); + } + + &.bubble-19 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_19.png'); + } + + &.bubble-20 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_20.png'); + } + + &.bubble-21 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_21.png'); + } + + &.bubble-22 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_22.png'); + } + + &.bubble-23 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_23.png'); + } + + &.bubble-24 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_24.png'); + } + + &.bubble-25 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_25.png'); + } + + &.bubble-26 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_26.png'); + } + + &.bubble-27 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_27.png'); + } + + &.bubble-28 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_28.png'); + } + + &.bubble-29 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_29.png'); + } + + &.bubble-30 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_30.png'); + } + + &.bubble-32 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_32.png'); + } + + &.bubble-33 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_33_34.png'); + + &::before { + content: ' '; + position: absolute; + width: 19px; + height: 19px; + left: 11px; + top: 10px; + background: url('@/assets/images/chat/chatbubbles/bubble_33_extra.png'); + } + } + + &.bubble-34 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_33_34.png'); + + &::before { + content: ' '; + position: absolute; + width: 19px; + height: 19px; + left: 11px; + top: 10px; + background: url('@/assets/images/chat/chatbubbles/bubble_34_extra.png'); + } + } + + &.bubble-35 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_35.png'); + } + + &.bubble-36 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_36.png'); + + &::before { + content: ' '; + position: absolute; + width: 13px; + height: 18px; + left: 13px; + top: 10px; + background: url('@/assets/images/chat/chatbubbles/bubble_36_extra.png'); + } + } + + &.bubble-37 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_35.png'); + } + + &.bubble-38 { + background-image: url('@/assets/images/chat/chatbubbles/bubble_38.png'); + + &::before { + content: ' '; + position: absolute; + width: 19px; + height: 19px; + left: 11px; + top: 10px; + background: url('@/assets/images/chat/chatbubbles/bubble_38_extra.png'); + } + } +} \ No newline at end of file diff --git a/Coolui v3 test/src/css/common/Buttons.css b/Coolui v3 test/src/css/common/Buttons.css new file mode 100644 index 0000000000..106a3cc62c --- /dev/null +++ b/Coolui v3 test/src/css/common/Buttons.css @@ -0,0 +1,109 @@ +.btn-sm { + min-height: 28px; +} + +textarea { + resize: none; +} + +/* Chrome, Safari, Edge, Opera */ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* Firefox */ +input[type=number] { + -moz-appearance: textfield; +} + +.rounded { + border-radius: 0.5rem; +} + +.btn-primary { + color: #fff; + background-color: #3c6d82; + border: 2px solid #1a617f; + padding: 0.25rem 0.5rem; + font-size: .7875rem; + border-radius: 0.5rem; + box-shadow: none!important; +} + +.btn-primary:hover { + border: 2px solid #1a617f; + box-shadow: none!important; +} + +.btn-success{ + color: #fff; + background-color: #3c8243; + border: 2px solid #006d09; + padding: 0.25rem 0.5rem; + font-size: .7875rem; + border-radius: 0.5rem; + box-shadow: none!important; +} + +.btn-success:hover{ + box-shadow: none!important; +} + +.btn-danger{ + color: #fff; + background-color: #a81a12; + border: 2px solid #b9322a; + padding: 0.25rem 0.5rem; + font-size: .7875rem; + border-radius: 0.5rem; + box-shadow: none!important; +} + +.btn-danger:hover{ + box-shadow: none!important; +} + +.btn-warning{ + color: #222; + background-color: #ffc107; + border: 2px solid #f3c12a; + padding: 0.25rem 0.5rem; + font-size: .7875rem; + border-radius: 0.5rem; + box-shadow: none!important; +} + +.btn-warning:hover{ + box-shadow: none!important; +} + +.btn-dark { + color: #fff; + background-color: #212131; + border: 2px solid #1c1c2a; + box-shadow: none!important; + border-radius: 8px; + padding: 4px 11px 4px 11px; +} + +.btn-dark:hover{ + background-color: #212131; + border: 2px solid #1c1c2a; + box-shadow: none!important; + border-radius: 8px; + padding: 4px 11px 4px 11px; +} + +.btn-friendsgen{ + background-color: #424354; + border: 2px solid #63647a; + border-radius: 10px; +} + +.btn-friendsgensuccess{ + background-color: #b69b83; + border: 2px solid #e2c1a3; + border-radius: 10px; +} diff --git a/Coolui v3 test/src/css/common/MiniCamera.css b/Coolui v3 test/src/css/common/MiniCamera.css new file mode 100644 index 0000000000..fd4a145fb7 --- /dev/null +++ b/Coolui v3 test/src/css/common/MiniCamera.css @@ -0,0 +1,13 @@ +.nitro-room-thumbnail-camera { + width: 132px; + height: 192px; + background-image: url('@/assets/images/room-widgets/thumbnail-widget/thumbnail-camera-spritesheet.png'); + + .camera-frame { + position: absolute; + width: 110px; + height: 110px; + margin-top: 30px; + margin-left: 3px; + } +} \ No newline at end of file diff --git a/Coolui v3 test/src/css/floorplan/FloorplanEditorView.css b/Coolui v3 test/src/css/floorplan/FloorplanEditorView.css new file mode 100644 index 0000000000..219a197a0f --- /dev/null +++ b/Coolui v3 test/src/css/floorplan/FloorplanEditorView.css @@ -0,0 +1,9 @@ +.nitro-floorplan-editor { + width: 760px; + height: 500px; +} + +.floorplan-import-export { + width: 630px; + height: 475px; +} \ No newline at end of file diff --git a/Coolui v3 test/src/css/forms/form_select.css b/Coolui v3 test/src/css/forms/form_select.css new file mode 100644 index 0000000000..8336b6ffff --- /dev/null +++ b/Coolui v3 test/src/css/forms/form_select.css @@ -0,0 +1,24 @@ +/* Styling for text inputs (e.g., password fields) */ +.form-control-sm { + padding: 0.25rem 0.5rem; /* Reduced padding */ + font-size: 0.75rem; /* Small font size, adjust to match */ + line-height: 1.5; + border-radius: 0.2rem; + min-height: calc(1.5em + 0.5rem + 2px); /* Matches your inline style */ +} + +/* Optional: Styling for radio/checkbox inputs */ +.form-check-input { + /* No font-size here since it’s an input’s appearance, not text */ + margin-top: 0.25rem; /* Align with small text */ +} + +/* If you have + ); +}); + +NitroInput.displayName = 'NitroInput'; diff --git a/Coolui v3 test/src/layout/NitroItemCountBadge.tsx b/Coolui v3 test/src/layout/NitroItemCountBadge.tsx new file mode 100644 index 0000000000..f8b0782f2d --- /dev/null +++ b/Coolui v3 test/src/layout/NitroItemCountBadge.tsx @@ -0,0 +1,33 @@ +import { DetailedHTMLProps, forwardRef, HTMLAttributes, PropsWithChildren } from 'react'; +import { classNames } from './classNames'; + +const classes = { + base: 'text-[white] font-bold leading-none text-[9.5px] absolute right-0 top-0 py-0.5 px-[3px] z-[1] rounded border', + themes: { + 'primary': 'border-black bg-red-700' + } +}; + +export const NitroItemCountBadge = forwardRef & DetailedHTMLProps, HTMLDivElement>>((props, ref) => +{ + const { theme = 'primary', count = 0, className = null, children = null, ...rest } = props; + + return ( +
+ { count } + { children } +
+ ); +}); + +NitroItemCountBadge.displayName = 'NitroItemCountBadge'; diff --git a/Coolui v3 test/src/layout/classNames.ts b/Coolui v3 test/src/layout/classNames.ts new file mode 100644 index 0000000000..2127d85ef9 --- /dev/null +++ b/Coolui v3 test/src/layout/classNames.ts @@ -0,0 +1 @@ +export const classNames = (...classes: string[]) => classes.filter(Boolean).join(' '); diff --git a/Coolui v3 test/src/layout/index.ts b/Coolui v3 test/src/layout/index.ts new file mode 100644 index 0000000000..a7041de8ec --- /dev/null +++ b/Coolui v3 test/src/layout/index.ts @@ -0,0 +1,8 @@ +export * from './InfiniteGrid'; +export * from './NitroButton'; +export * from './NitroCard'; +export * from './NitroInput'; +export * from './NitroItemCountBadge'; +export * from './classNames'; +export * from './limited-edition'; +export * from './styleNames'; diff --git a/Coolui v3 test/src/layout/limited-edition/NitroLimitedEditionStyledNumberView.tsx b/Coolui v3 test/src/layout/limited-edition/NitroLimitedEditionStyledNumberView.tsx new file mode 100644 index 0000000000..0cd02506de --- /dev/null +++ b/Coolui v3 test/src/layout/limited-edition/NitroLimitedEditionStyledNumberView.tsx @@ -0,0 +1,18 @@ +import { FC } from 'react'; + +export const NitroLimitedEditionStyledNumberView: FC<{ + value: number; +}> = props => +{ + const { value = 0 } = props; + + return ( + <> + { value.toString().split('').map((number, index) => + + ) } + + ); +}; diff --git a/Coolui v3 test/src/layout/limited-edition/index.ts b/Coolui v3 test/src/layout/limited-edition/index.ts new file mode 100644 index 0000000000..079a6d4fc3 --- /dev/null +++ b/Coolui v3 test/src/layout/limited-edition/index.ts @@ -0,0 +1 @@ +export * from './NitroLimitedEditionStyledNumberView'; diff --git a/Coolui v3 test/src/layout/styleNames.ts b/Coolui v3 test/src/layout/styleNames.ts new file mode 100644 index 0000000000..ac58f7791c --- /dev/null +++ b/Coolui v3 test/src/layout/styleNames.ts @@ -0,0 +1,8 @@ +export const styleNames = (...styles: object[]) => +{ + let mergedStyle = {}; + + styles.filter(Boolean).forEach(style => mergedStyle = { ...mergedStyle, ...style }); + + return mergedStyle; +}; diff --git a/Coolui v3 test/src/workers/IntervalWebWorker.ts b/Coolui v3 test/src/workers/IntervalWebWorker.ts new file mode 100644 index 0000000000..add63f620a --- /dev/null +++ b/Coolui v3 test/src/workers/IntervalWebWorker.ts @@ -0,0 +1,26 @@ +export default () => +{ + let interval: ReturnType = null; + + + self.onmessage = (message: MessageEvent) => + { + if(!message) return; + + const data: { [index: string]: any } = message.data; + + switch(data.action) + { + case 'START': + interval = setInterval(() => postMessage(null), data.content); + break; + case 'STOP': + if(interval) + { + clearInterval(interval); + interval = null; + } + break; + } + }; +}; diff --git a/Coolui v3 test/src/workers/WorkerBuilder.ts b/Coolui v3 test/src/workers/WorkerBuilder.ts new file mode 100644 index 0000000000..b848893e25 --- /dev/null +++ b/Coolui v3 test/src/workers/WorkerBuilder.ts @@ -0,0 +1,10 @@ +export class WorkerBuilder extends Worker +{ + constructor(worker) + { + const code = worker.toString(); + const blob = new Blob([ `(${ code })()` ]); + + super(URL.createObjectURL(blob)); + } +}