mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 23:16:21 +00:00
🆙 100% Guild Furni Catalog Page
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { MouseEventType } from '@nitrots/nitro-renderer';
|
||||
import { CSSProperties, FC, MouseEvent, useMemo, useState } from 'react';
|
||||
import { FC, MouseEvent, useMemo, useState } from 'react';
|
||||
import { FaHeart } from 'react-icons/fa';
|
||||
import { CatalogType, GetConfigurationValue, IPurchasableOffer, Offer, ProductTypeEnum } from '../../../../../api';
|
||||
import { LayoutAvatarImageView, LayoutGridItem, LayoutGridItemProps } from '../../../../../common';
|
||||
@@ -114,10 +114,9 @@ export const CatalogGridOfferView: FC<CatalogGridOfferViewProps> = props =>
|
||||
|
||||
return (
|
||||
<LayoutGridItem
|
||||
className={ `group/tile relative ${ itemActive ? 'is-active' : '' } ${ tintColor ? 'has-guild-tint' : '' }` }
|
||||
className={ `group/tile relative ${ itemActive ? 'is-active' : '' }` }
|
||||
gap={ 1 }
|
||||
itemActive={ itemActive }
|
||||
style={ tintColor ? ({ '--guild-tint': tintColor } as CSSProperties) : undefined }
|
||||
itemCount={ ((offer.pricingModel === Offer.PRICING_MODEL_MULTI) ? product.productCount : 1) }
|
||||
itemUniqueNumber={ product.uniqueLimitedItemSeriesSize }
|
||||
itemUniqueSoldout={ (product.uniqueLimitedItemSeriesSize && !product.uniqueLimitedItemsLeft) }
|
||||
@@ -132,6 +131,7 @@ export const CatalogGridOfferView: FC<CatalogGridOfferViewProps> = props =>
|
||||
className="nitro-catalog-classic-grid-offer-icon"
|
||||
src={ iconUrl }
|
||||
draggable={ false }
|
||||
style={ tintColor ? { filter: 'url(#guild-furni-recolor)', transform: 'translateZ(0)' } : undefined }
|
||||
onError={ event =>
|
||||
{
|
||||
const fallbackIconUrl = product.getIconUrl(offer);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { StringDataType } from '@nitrots/nitro-renderer';
|
||||
import { FC, useMemo } from 'react';
|
||||
import { FC, useEffect, useMemo, useState } from 'react';
|
||||
import { FaExchangeAlt, FaSyncAlt } from 'react-icons/fa';
|
||||
import { Column } from '../../../../../common';
|
||||
import { useCatalogData, useCatalogUiState, useUserGroups } from '../../../../../hooks';
|
||||
import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView';
|
||||
import { CatalogGuildBadgeWidgetView } from '../widgets/CatalogGuildBadgeWidgetView';
|
||||
import { CatalogGuildFurniRecolorFilter } from '../widgets/CatalogGuildFurniRecolorFilter';
|
||||
import { CatalogGuildSelectorWidgetView } from '../widgets/CatalogGuildSelectorWidgetView';
|
||||
import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView';
|
||||
import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView';
|
||||
@@ -18,28 +19,40 @@ export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = () =>
|
||||
const { purchaseOptions = null } = useCatalogUiState();
|
||||
const { data: groups = null } = useUserGroups();
|
||||
const hasGroups = !!(groups && groups.length);
|
||||
const [ groupColors, setGroupColors ] = useState<{ colorA: string; colorB: string } | null>(null);
|
||||
|
||||
const tintColor = useMemo(() =>
|
||||
useEffect(() =>
|
||||
{
|
||||
const previewStuffData = purchaseOptions?.previewStuffData ?? null;
|
||||
|
||||
if(!previewStuffData) return null;
|
||||
if(!previewStuffData) return;
|
||||
|
||||
const colorA = (previewStuffData as StringDataType).getValue(3);
|
||||
const colorB = (previewStuffData as StringDataType).getValue(4);
|
||||
|
||||
if(!colorA || !colorA.length) return null;
|
||||
if(!colorA || !colorA.length) return;
|
||||
|
||||
if(colorB && colorB.length && (colorB !== colorA))
|
||||
{
|
||||
return `linear-gradient(90deg, #${ colorA } 0 50%, #${ colorB } 50% 100%)`;
|
||||
}
|
||||
const next = { colorA, colorB: (colorB && colorB.length) ? colorB : colorA };
|
||||
|
||||
setGroupColors(prev => (prev && (prev.colorA === next.colorA) && (prev.colorB === next.colorB)) ? prev : next);
|
||||
}, [ purchaseOptions ]);
|
||||
|
||||
|
||||
const tintColor = useMemo(() =>
|
||||
{
|
||||
if(!groupColors) return null;
|
||||
|
||||
const { colorA, colorB } = groupColors;
|
||||
|
||||
if(colorB && (colorB !== colorA)) return `linear-gradient(90deg, #${ colorA } 0 50%, #${ colorB } 50% 100%)`;
|
||||
|
||||
return `#${ colorA }`;
|
||||
}, [ purchaseOptions ]);
|
||||
}, [ groupColors ]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{ !!groupColors &&
|
||||
<CatalogGuildFurniRecolorFilter colorA={ groupColors.colorA } colorB={ groupColors.colorB } /> }
|
||||
<CatalogFirstProductSelectorWidgetView />
|
||||
<Column fullHeight gap={ 1 } overflow="hidden">
|
||||
{ !!currentOffer &&
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { memo, useMemo } from 'react';
|
||||
|
||||
interface CatalogGuildFurniRecolorFilterProps
|
||||
{
|
||||
colorA?: string;
|
||||
colorB?: string;
|
||||
}
|
||||
|
||||
export const GUILD_FURNI_RECOLOR_FILTER_ID = 'guild-furni-recolor';
|
||||
const OUTLINE_LEVEL = 0.08;
|
||||
|
||||
const toUnit = (hex: string, offset: number): number =>
|
||||
{
|
||||
const value = parseInt(hex.substr(offset, 2), 16);
|
||||
|
||||
return (isNaN(value) ? 0 : value) / 255;
|
||||
};
|
||||
|
||||
export const CatalogGuildFurniRecolorFilter = memo((props: CatalogGuildFurniRecolorFilterProps) =>
|
||||
{
|
||||
const { colorA = null, colorB = null } = props;
|
||||
|
||||
const tables = useMemo(() =>
|
||||
{
|
||||
if(!colorA || (colorA.length < 6) || !colorB || (colorB.length < 6)) return null;
|
||||
|
||||
const aR = toUnit(colorA, 0), aG = toUnit(colorA, 2), aB = toUnit(colorA, 4);
|
||||
const bR = toUnit(colorB, 0), bG = toUnit(colorB, 2), bB = toUnit(colorB, 4);
|
||||
|
||||
return {
|
||||
r: `${ OUTLINE_LEVEL } ${ bR } ${ bR } ${ aR } ${ aR } ${ aR }`,
|
||||
g: `${ OUTLINE_LEVEL } ${ bG } ${ bG } ${ aG } ${ aG } ${ aG }`,
|
||||
b: `${ OUTLINE_LEVEL } ${ bB } ${ bB } ${ aB } ${ aB } ${ aB }`
|
||||
};
|
||||
}, [ colorA, colorB ]);
|
||||
|
||||
if(!tables) return null;
|
||||
|
||||
return (
|
||||
<svg aria-hidden="true" focusable="false" width="0" height="0" style={ { position: 'absolute', width: 0, height: 0 } }>
|
||||
<filter id={ GUILD_FURNI_RECOLOR_FILTER_ID } colorInterpolationFilters="sRGB">
|
||||
<feComponentTransfer>
|
||||
<feFuncR type="table" tableValues={ tables.r } />
|
||||
<feFuncG type="table" tableValues={ tables.g } />
|
||||
<feFuncB type="table" tableValues={ tables.b } />
|
||||
</feComponentTransfer>
|
||||
</filter>
|
||||
</svg>
|
||||
);
|
||||
});
|
||||
|
||||
CatalogGuildFurniRecolorFilter.displayName = 'CatalogGuildFurniRecolorFilter';
|
||||
Reference in New Issue
Block a user