feat: catalog style toggle (classic/new) with admin mode & favorites

This commit is contained in:
Life
2026-03-22 16:54:40 +01:00
parent ccaec9185e
commit a5ea88010e
34 changed files with 2799 additions and 575 deletions
+41 -11
View File
@@ -1,30 +1,44 @@
import { AddLinkEventTracker, ILinkEventTracker, RemoveLinkEventTracker } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { AddLinkEventTracker, GetSessionDataManager, ILinkEventTracker, RemoveLinkEventTracker } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common';
import { useFurniEditor } from '../../hooks/furni-editor';
import { FurniEditorCreateView } from './views/FurniEditorCreateView';
import { FurniEditorEditView } from './views/FurniEditorEditView';
import { FurniEditorSearchView } from './views/FurniEditorSearchView';
const TAB_SEARCH = 0;
const TAB_EDIT = 1;
const TAB_CREATE = 2;
export const FurniEditorView: FC<{}> = () =>
{
const [ isVisible, setIsVisible ] = useState(false);
const [ activeTab, setActiveTab ] = useState(TAB_SEARCH);
const pendingEditRef = useRef(false);
const {
items, total, page, loading, error, clearError,
selectedItem, catalogItems, furniDataEntry,
interactions,
searchItems, loadDetail, loadBySpriteId, updateItem, deleteItem, loadInteractions
searchItems, loadDetail, loadBySpriteId, updateItem, createItem, deleteItem, loadInteractions
} = useFurniEditor();
useEffect(() =>
{
if(selectedItem && pendingEditRef.current)
{
pendingEditRef.current = false;
setActiveTab(TAB_EDIT);
}
}, [ selectedItem ]);
useEffect(() =>
{
const linkTracker: ILinkEventTracker = {
linkReceived: (url: string) =>
{
if(!GetSessionDataManager().isModerator) return;
const parts = url.split('/');
if(parts.length < 2) return;
@@ -57,13 +71,16 @@ export const FurniEditorView: FC<{}> = () =>
useEffect(() =>
{
const handler = async (e: CustomEvent<{ spriteId: number }>) =>
const handler = (e: CustomEvent<{ spriteId: number }>) =>
{
if(!GetSessionDataManager().isModerator) return;
const { spriteId } = e.detail;
const ok = await loadBySpriteId(spriteId);
if(!Number.isFinite(spriteId) || spriteId < 0) return;
if(ok) setActiveTab(TAB_EDIT);
pendingEditRef.current = true;
loadBySpriteId(spriteId);
};
window.addEventListener('furni-editor:open', handler as EventListener);
@@ -71,11 +88,10 @@ export const FurniEditorView: FC<{}> = () =>
return () => window.removeEventListener('furni-editor:open', handler as EventListener);
}, [ loadBySpriteId ]);
const handleSelect = useCallback(async (id: number) =>
const handleSelect = useCallback((id: number) =>
{
const ok = await loadDetail(id);
if(ok) setActiveTab(TAB_EDIT);
pendingEditRef.current = true;
loadDetail(id);
}, [ loadDetail ]);
const handleBack = useCallback(() =>
@@ -88,7 +104,9 @@ export const FurniEditorView: FC<{}> = () =>
setIsVisible(false);
}, []);
if(!isVisible) return null;
const isMod = useMemo(() => GetSessionDataManager().isModerator, []);
if(!isVisible || !isMod) return null;
return (
<NitroCardView uniqueKey="furni-editor" className="w-[620px] h-[520px]">
@@ -100,6 +118,9 @@ export const FurniEditorView: FC<{}> = () =>
<NitroCardTabsItemView isActive={ activeTab === TAB_EDIT } onClick={ () => selectedItem && setActiveTab(TAB_EDIT) }>
Edit
</NitroCardTabsItemView>
<NitroCardTabsItemView isActive={ activeTab === TAB_CREATE } onClick={ () => setActiveTab(TAB_CREATE) }>
Create
</NitroCardTabsItemView>
</NitroCardTabsView>
<NitroCardContentView>
{ error &&
@@ -134,6 +155,15 @@ export const FurniEditorView: FC<{}> = () =>
/>
}
{ activeTab === TAB_CREATE &&
<FurniEditorCreateView
interactions={ interactions }
loading={ loading }
onCreate={ createItem }
onBack={ handleBack }
/>
}
</NitroCardContentView>
</NitroCardView>
);