Merge pull request #231 from duckietm/Dev

🆙 Added colored background to items in group furni & fix catalog price
This commit is contained in:
DuckieTM
2026-06-11 10:14:58 +02:00
committed by GitHub
8 changed files with 90 additions and 53 deletions
+2 -2
View File
@@ -24,10 +24,10 @@ export const LayoutGridItem: FC<LayoutGridItemProps> = props =>
const getClassNames = useMemo(() => const getClassNames = useMemo(() =>
{ {
const newClassNames: string[] = [ 'layout-grid-item', 'border', 'border-2', 'border-[#c4cabf]', 'rounded-[6px]' ]; const newClassNames: string[] = [ 'layout-grid-item' ];
if(itemActive) newClassNames.push('bg-[#e4e7df]! border-[#aeb7aa]!'); if(itemActive) newClassNames.push('is-grid-active', 'bg-[#e4e7df]!');
if(itemUniqueSoldout || (itemUniqueNumber > 0)) newClassNames.push('unique-item'); if(itemUniqueSoldout || (itemUniqueNumber > 0)) newClassNames.push('unique-item');
@@ -1,5 +1,5 @@
import { MouseEventType } from '@nitrots/nitro-renderer'; import { MouseEventType } from '@nitrots/nitro-renderer';
import { FC, MouseEvent, useMemo, useState } from 'react'; import { CSSProperties, FC, MouseEvent, useMemo, useState } from 'react';
import { FaHeart } from 'react-icons/fa'; import { FaHeart } from 'react-icons/fa';
import { CatalogType, GetConfigurationValue, IPurchasableOffer, Offer, ProductTypeEnum } from '../../../../../api'; import { CatalogType, GetConfigurationValue, IPurchasableOffer, Offer, ProductTypeEnum } from '../../../../../api';
import { LayoutAvatarImageView, LayoutGridItem, LayoutGridItemProps } from '../../../../../common'; import { LayoutAvatarImageView, LayoutGridItem, LayoutGridItemProps } from '../../../../../common';
@@ -9,11 +9,12 @@ interface CatalogGridOfferViewProps extends LayoutGridItemProps
{ {
offer: IPurchasableOffer; offer: IPurchasableOffer;
selectOffer: (offer: IPurchasableOffer) => void; selectOffer: (offer: IPurchasableOffer) => void;
tintColor?: string;
} }
export const CatalogGridOfferView: FC<CatalogGridOfferViewProps> = props => export const CatalogGridOfferView: FC<CatalogGridOfferViewProps> = props =>
{ {
const { offer = null, selectOffer = null, itemActive = false, ...rest } = props; const { offer = null, selectOffer = null, itemActive = false, tintColor = null, ...rest } = props;
const [ isMouseDown, setMouseDown ] = useState(false); const [ isMouseDown, setMouseDown ] = useState(false);
const { requestOfferToMover = null } = useCatalogActions(); const { requestOfferToMover = null } = useCatalogActions();
const { currentType = CatalogType.NORMAL } = useCatalogUiState(); const { currentType = CatalogType.NORMAL } = useCatalogUiState();
@@ -113,9 +114,10 @@ export const CatalogGridOfferView: FC<CatalogGridOfferViewProps> = props =>
return ( return (
<LayoutGridItem <LayoutGridItem
className={ `group/tile relative ${ itemActive ? 'is-active' : '' }` } className={ `group/tile relative ${ itemActive ? 'is-active' : '' } ${ tintColor ? 'has-guild-tint' : '' }` }
gap={ 1 } gap={ 1 }
itemActive={ itemActive } itemActive={ itemActive }
style={ tintColor ? ({ '--guild-tint': tintColor } as CSSProperties) : undefined }
itemCount={ ((offer.pricingModel === Offer.PRICING_MODEL_MULTI) ? product.productCount : 1) } itemCount={ ((offer.pricingModel === Offer.PRICING_MODEL_MULTI) ? product.productCount : 1) }
itemUniqueNumber={ product.uniqueLimitedItemSeriesSize } itemUniqueNumber={ product.uniqueLimitedItemSeriesSize }
itemUniqueSoldout={ (product.uniqueLimitedItemSeriesSize && !product.uniqueLimitedItemsLeft) } itemUniqueSoldout={ (product.uniqueLimitedItemSeriesSize && !product.uniqueLimitedItemsLeft) }
@@ -112,6 +112,7 @@ export const CatalogLayoutDefaultView: FC<CatalogLayoutProps> = props =>
<CatalogSpinnerWidgetView /> <CatalogSpinnerWidgetView />
</div> </div>
<div className="nitro-catalog-classic-total-price-slot"> <div className="nitro-catalog-classic-total-price-slot">
<span className="nitro-catalog-classic-total-price-label">{ LocalizeText('catalog.bundlewidget.price') }</span>
<CatalogTotalPriceWidget /> <CatalogTotalPriceWidget />
</div> </div>
</div> } </div> }
@@ -1,7 +1,8 @@
import { FC } from 'react'; import { StringDataType } from '@nitrots/nitro-renderer';
import { FC, useMemo } from 'react';
import { FaExchangeAlt, FaSyncAlt } from 'react-icons/fa'; import { FaExchangeAlt, FaSyncAlt } from 'react-icons/fa';
import { Column } from '../../../../../common'; import { Column } from '../../../../../common';
import { useCatalogData, useUserGroups } from '../../../../../hooks'; import { useCatalogData, useCatalogUiState, useUserGroups } from '../../../../../hooks';
import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView'; import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView';
import { CatalogGuildBadgeWidgetView } from '../widgets/CatalogGuildBadgeWidgetView'; import { CatalogGuildBadgeWidgetView } from '../widgets/CatalogGuildBadgeWidgetView';
import { CatalogGuildSelectorWidgetView } from '../widgets/CatalogGuildSelectorWidgetView'; import { CatalogGuildSelectorWidgetView } from '../widgets/CatalogGuildSelectorWidgetView';
@@ -14,9 +15,29 @@ import { CatalogLayoutProps } from './CatalogLayout.types';
export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = () => export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = () =>
{ {
const { currentOffer = null, roomPreviewer = null } = useCatalogData(); const { currentOffer = null, roomPreviewer = null } = useCatalogData();
const { purchaseOptions = null } = useCatalogUiState();
const { data: groups = null } = useUserGroups(); const { data: groups = null } = useUserGroups();
const hasGroups = !!(groups && groups.length); const hasGroups = !!(groups && groups.length);
const tintColor = useMemo(() =>
{
const previewStuffData = purchaseOptions?.previewStuffData ?? null;
if(!previewStuffData) return null;
const colorA = (previewStuffData as StringDataType).getValue(3);
const colorB = (previewStuffData as StringDataType).getValue(4);
if(!colorA || !colorA.length) return null;
if(colorB && colorB.length && (colorB !== colorA))
{
return `linear-gradient(90deg, #${ colorA } 0 50%, #${ colorB } 50% 100%)`;
}
return `#${ colorA }`;
}, [ purchaseOptions ]);
return ( return (
<> <>
<CatalogFirstProductSelectorWidgetView /> <CatalogFirstProductSelectorWidgetView />
@@ -38,7 +59,7 @@ export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = () =>
</div> </div>
</div> } </div> }
<div className="grow! min-h-0 overflow-auto"> <div className="grow! min-h-0 overflow-auto">
<CatalogItemGridWidgetView columnCount={ 5 } columnMinWidth={ 36 } /> <CatalogItemGridWidgetView className="nitro-catalog-classic-grid" columnCount={ 6 } columnMinHeight={ 80 } columnMinWidth={ 55 } tintColor={ tintColor } />
</div> </div>
{ !!currentOffer && { !!currentOffer &&
<div className="flex shrink-0 flex-col gap-1"> <div className="flex shrink-0 flex-col gap-1">
@@ -33,7 +33,9 @@ export const CatalogLayouGuildForumView: FC<CatalogLayoutProps> = props =>
</div> </div>
</Flex> </Flex>
{ hasGroups && { hasGroups &&
<CatalogPurchaseWidgetView noGiftOption={ true } /> } <div className="flex justify-center">
<CatalogPurchaseWidgetView noGiftOption={ true } />
</div> }
</div> } </div> }
</Column> </Column>
<Column alignItems="center" overflow="hidden" size={ 4 }> <Column alignItems="center" overflow="hidden" size={ 4 }>
@@ -7,12 +7,12 @@ import { CatalogGridOfferView } from '../common/CatalogGridOfferView';
interface CatalogItemGridWidgetViewProps extends AutoGridProps interface CatalogItemGridWidgetViewProps extends AutoGridProps
{ {
tintColor?: string;
} }
export const CatalogItemGridWidgetView: FC<CatalogItemGridWidgetViewProps> = props => export const CatalogItemGridWidgetView: FC<CatalogItemGridWidgetViewProps> = props =>
{ {
const { columnCount = 5, children = null, ...rest } = props; const { columnCount = 5, tintColor = null, children = null, ...rest } = props;
const { currentOffer = null, currentPage = null } = useCatalogData(); const { currentOffer = null, currentPage = null } = useCatalogData();
const { selectCatalogOffer = null } = useCatalogActions(); const { selectCatalogOffer = null } = useCatalogActions();
const catalogAdmin = useCatalogAdmin(); const catalogAdmin = useCatalogAdmin();
@@ -26,13 +26,6 @@ export const CatalogItemGridWidgetView: FC<CatalogItemGridWidgetViewProps> = pro
if(elementRef && elementRef.current) elementRef.current.scrollTop = 0; if(elementRef && elementRef.current) elementRef.current.scrollTop = 0;
}, [ currentPage ]); }, [ currentPage ]);
// Drag-and-drop handlers — hooks MUST run unconditionally so the
// hook order stays stable when currentPage flips from null to a
// real value (the `if(!currentPage) return null` below would
// otherwise hide these from the first render and React would flag
// "Rendered more hooks than during the previous render"). Bodies
// are safe to evaluate pre-load: currentPage? optional chaining
// already guards the only access inside handleDrop.
const handleDragStart = useCallback((index: number) => const handleDragStart = useCallback((index: number) =>
{ {
setDragIndex(index); setDragIndex(index);
@@ -96,6 +89,7 @@ export const CatalogItemGridWidgetView: FC<CatalogItemGridWidgetViewProps> = pro
itemActive={ (currentOffer && (currentOffer.offerId === offer.offerId)) } itemActive={ (currentOffer && (currentOffer.offerId === offer.offerId)) }
offer={ offer } offer={ offer }
selectOffer={ selectOffer } selectOffer={ selectOffer }
tintColor={ tintColor }
/> />
</div> </div>
); );
+46 -35
View File
@@ -827,40 +827,49 @@
overflow: visible !important; overflow: visible !important;
} }
.nitro-catalog-classic-window .layout-grid-item { @layer utilities {
width: 100% !important; .nitro-catalog-classic-window .layout-grid-item {
height: var(--nitro-grid-column-min-height, 70px) !important; width: 100% !important;
min-width: 0 !important; height: var(--nitro-grid-column-min-height, 70px) !important;
min-height: var(--nitro-grid-column-min-height, 70px) !important; min-width: 0 !important;
border: 0 !important; min-height: var(--nitro-grid-column-min-height, 70px) !important;
border-radius: 0 !important; border: 0 !important;
background-image: none !important; border-radius: 0 !important;
box-shadow: none !important; background-image: none !important;
overflow: visible !important; box-shadow: none !important;
} overflow: visible !important;
}
.nitro-catalog-classic-window .layout-grid-item:not(.has-highlight) { .nitro-catalog-classic-window .layout-grid-item:not(.has-highlight) {
background-color: transparent !important; background-color: #e4e7df !important;
} border: 2px solid transparent !important;
border-radius: 4px !important;
box-shadow: none !important;
}
.nitro-catalog-classic-window .nitro-catalog-classic-pet-breeds .layout-grid-item { .nitro-catalog-classic-window .nitro-catalog-classic-pet-breeds .layout-grid-item {
width: 84px !important; width: 84px !important;
min-width: 84px !important; min-width: 84px !important;
height: 74px !important; height: 74px !important;
min-height: 74px !important; min-height: 74px !important;
} }
.nitro-catalog-classic-window .layout-grid-item:hover { .nitro-catalog-classic-window .layout-grid-item:not(.has-highlight):not(.is-active):hover {
background-image: none !important; background-image: none !important;
box-shadow: inset 0 0 0 1px #a1a19b !important; border-color: transparent !important;
} box-shadow: none !important;
}
.nitro-catalog-classic-window .layout-grid-item.is-active { .nitro-catalog-classic-window .layout-grid-item.is-active {
background-image: none !important; background-color: #ffffff !important;
box-shadow: background-image: none !important;
inset 0 0 0 1px #63c5e9, border: 2px solid #62c4e8 !important;
inset 2px 2px 0 #ecece4, box-shadow: none !important;
inset -2px -2px 0 #ecece4 !important; }
.nitro-catalog-classic-window .layout-grid-item.has-guild-tint:not(.has-highlight):not(.is-active) {
background: var(--guild-tint) !important;
}
} }
.nitro-catalog-classic-window .layout-grid-item.has-highlight { .nitro-catalog-classic-window .layout-grid-item.has-highlight {
@@ -901,13 +910,15 @@
pointer-events: none; pointer-events: none;
} }
.nitro-catalog-classic-grid-price { .nitro-catalog-classic-grid-price {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: flex-end;
gap: 3px; gap: 3px;
width: 100%; width: 100%;
padding-right: 4px;
color: #000; color: #000;
font-size: 11px; font-size: 11px;
font-weight: 700; font-weight: 700;
@@ -963,7 +974,8 @@
.nitro-catalog-classic-grid-price.is-multi-price { .nitro-catalog-classic-grid-price.is-multi-price {
height: auto; height: auto;
min-height: 0; min-height: 0;
flex-wrap: wrap; flex-direction: column;
align-items: flex-end;
row-gap: 1px; row-gap: 1px;
} }
@@ -971,7 +983,7 @@
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 1px; gap: 3px;
height: 13px; height: 13px;
white-space: nowrap; white-space: nowrap;
} }
@@ -1022,8 +1034,7 @@
padding-right: 2px; padding-right: 2px;
} }
.nitro-catalog-classic-total-price-slot::before { .nitro-catalog-classic-total-price-label {
content: "Prezzo";
color: #666; color: #666;
font-size: 11px; font-size: 11px;
line-height: 17px; line-height: 17px;
+6
View File
@@ -714,6 +714,12 @@ body {
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-color: #cdd3d9; background-color: #cdd3d9;
border: 2px solid #c4cabf;
border-radius: 6px;
}
.layout-grid-item.is-grid-active {
border-color: #aeb7aa;
} }
.nitro-friends-spritesheet { .nitro-friends-spritesheet {