🆙 Init V3

This commit is contained in:
DuckieTM
2026-01-31 09:10:52 +01:00
commit 7feb10ab15
1733 changed files with 53405 additions and 0 deletions
@@ -0,0 +1,19 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { AchievementUtilities } from '../../api';
import { BaseProps, LayoutBadgeImageView } from '../../common';
interface AchievementBadgeViewProps extends BaseProps<HTMLDivElement>
{
achievement: AchievementData;
scale?: number;
}
export const AchievementBadgeView: FC<AchievementBadgeViewProps> = props =>
{
const { achievement = null, scale = 1, ...rest } = props;
if(!achievement) return null;
return <LayoutBadgeImageView badgeCode={ AchievementUtilities.getAchievementBadgeCode(achievement) } isGrayscale={ !AchievementUtilities.getAchievementHasStarted(achievement) } scale={ scale } { ...rest } />;
};
@@ -0,0 +1,42 @@
import { FC, useEffect } from 'react';
import { AchievementCategory } from '../../api';
import { Column } from '../../common';
import { useAchievements } from '../../hooks';
import { AchievementDetailsView } from './AchievementDetailsView';
import { AchievementListView } from './achievement-list';
interface AchievementCategoryViewProps {
category: AchievementCategory;
}
export const AchievementCategoryView: FC<AchievementCategoryViewProps> = (
props,
) =>
{
const { category = null } = props;
const { selectedAchievement = null, setSelectedAchievementId = null } =
useAchievements();
useEffect(() =>
{
if(!category) return;
if(!selectedAchievement)
{
setSelectedAchievementId(
category?.achievements?.[0]?.achievementId,
);
}
}, [category, selectedAchievement, setSelectedAchievementId]);
if(!category) return null;
return (
<Column fullHeight justifyContent="between">
<AchievementListView achievements={category.achievements} />
{!!selectedAchievement && (
<AchievementDetailsView achievement={selectedAchievement} />
)}
</Column>
);
};
@@ -0,0 +1,53 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { AchievementUtilities, LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../api';
import { Column, Flex, LayoutCurrencyIcon, LayoutProgressBar, Text } from '../../common';
import { AchievementBadgeView } from './AchievementBadgeView';
interface AchievementDetailsViewProps
{
achievement: AchievementData;
}
export const AchievementDetailsView: FC<AchievementDetailsViewProps> = props =>
{
const { achievement = null } = props;
if(!achievement) return null;
return (
<Flex shrink className="bg-muted rounded p-2 text-black" gap={ 2 } overflow="hidden">
<Column center gap={ 1 }>
<AchievementBadgeView achievement={ achievement } className="nitro-achievements-relative w-[40px] h-[40px] bg-no-repeat bg-center" scale={ 2 } />
<Text fontWeight="bold">
{ LocalizeText('achievements.details.level', [ 'level', 'limit' ], [ AchievementUtilities.getAchievementLevel(achievement).toString(), achievement.levelCount.toString() ]) }
</Text>
</Column>
<Column fullWidth justifyContent="center" overflow="hidden">
<div className="flex flex-col gap-1">
<Text truncate fontWeight="bold">
{ LocalizeBadgeName(AchievementUtilities.getAchievementBadgeCode(achievement)) }
</Text>
<Text textBreak>
{ LocalizeBadgeDescription(AchievementUtilities.getAchievementBadgeCode(achievement)) }
</Text>
</div>
{ ((achievement.levelRewardPoints > 0) || (achievement.scoreLimit > 0)) &&
<div className="flex flex-col gap-1">
{ (achievement.levelRewardPoints > 0) &&
<div className="flex items-center gap-1">
<Text truncate className="small">
{ LocalizeText('achievements.details.reward') }
</Text>
<Flex center className="font-bold small" gap={ 1 }>
{ achievement.levelRewardPoints }
<LayoutCurrencyIcon type={ achievement.levelRewardPointType } />
</Flex>
</div> }
{ (achievement.scoreLimit > 0) &&
<LayoutProgressBar maxProgress={ (achievement.scoreLimit + achievement.scoreAtStartOfLevel) } progress={ (achievement.currentPoints + achievement.scoreAtStartOfLevel) } text={ LocalizeText('achievements.details.progress', [ 'progress', 'limit' ], [ (achievement.currentPoints + achievement.scoreAtStartOfLevel).toString(), (achievement.scoreLimit + achievement.scoreAtStartOfLevel).toString() ]) } /> }
</div> }
</Column>
</Flex>
);
};
@@ -0,0 +1,143 @@
import
{
AddLinkEventTracker,
ILinkEventTracker,
RemoveLinkEventTracker,
} from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { AchievementUtilities, LocalizeText } from '../../api';
import { Column, LayoutImage, LayoutProgressBar, Text } from '../../common';
import { useAchievements } from '../../hooks';
import { NitroCard } from '../../layout';
import { AchievementCategoryView } from './AchievementCategoryView';
import { AchievementsCategoryListView } from './category-list';
export const AchievementsView: FC<{}> = (props) =>
{
const [isVisible, setIsVisible] = useState(false);
const {
achievementCategories = [],
selectedCategoryCode = null,
setSelectedCategoryCode = null,
achievementScore = 0,
getProgress = 0,
getMaxProgress = 0,
selectedCategory = null,
} = useAchievements();
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: 'achievements/',
};
AddLinkEventTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker);
}, []);
if(!isVisible) return null;
return (
<NitroCard className="w-[375px] h-[405px]" uniqueKey="achievements">
<NitroCard.Header
headerText={LocalizeText('inventory.achievements')}
onCloseClick={(event) => setIsVisible(false)}
/>
{selectedCategory && (
<div className="relative flex items-center justify-center gap-3 p-1 cursor-pointer container-fluid bg-muted">
<div
className="bg-[url('@/assets/images/achievements/back-arrow.png')] bg-center no-repeat w-[33px] h-[34px]"
onClick={(event) => setSelectedCategoryCode(null)}
/>
<Column className="!flex-grow" gap={0}>
<Text
className="text-small"
fontSize={4}
fontWeight="bold"
>
{LocalizeText(
`quests.${selectedCategory.code}.name`
)}
</Text>
<Text>
{LocalizeText(
'achievements.details.categoryprogress',
['progress', 'limit'],
[
selectedCategory.getProgress().toString(),
selectedCategory
.getMaxProgress()
.toString(),
]
)}
</Text>
</Column>
<LayoutImage
imageUrl={AchievementUtilities.getAchievementCategoryImageUrl(
selectedCategory,
null,
true
)}
/>
</div>
)}
<NitroCard.Content>
{!selectedCategory && (
<>
<AchievementsCategoryListView
categories={achievementCategories}
selectedCategoryCode={selectedCategoryCode}
setSelectedCategoryCode={setSelectedCategoryCode}
/>
<div
className="flex flex-col justify-end flex-grow gap-1"
>
<Text center small>
{LocalizeText(
'achievements.categories.score',
['score'],
[achievementScore.toString()]
)}
</Text>
<LayoutProgressBar
maxProgress={getMaxProgress}
progress={getProgress}
text={LocalizeText(
'achievements.categories.totalprogress',
['progress', 'limit'],
[
getProgress.toString(),
getMaxProgress.toString(),
]
)}
/>
</div>
</>
)}
{selectedCategory && (
<AchievementCategoryView category={selectedCategory} />
)}
</NitroCard.Content>
</NitroCard>
);
};
@@ -0,0 +1,24 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { LayoutGridItem } from '../../../common';
import { useAchievements } from '../../../hooks';
import { AchievementBadgeView } from '../AchievementBadgeView';
interface AchievementListItemViewProps
{
achievement: AchievementData;
}
export const AchievementListItemView: FC<AchievementListItemViewProps> = props =>
{
const { achievement = null } = props;
const { selectedAchievement = null, setSelectedAchievementId = null } = useAchievements();
if(!achievement) return null;
return (
<LayoutGridItem itemActive={ (selectedAchievement === achievement) } itemUnseen={ (achievement.unseen > 0) } onClick={ event => setSelectedAchievementId(achievement.achievementId) }>
<AchievementBadgeView achievement={ achievement } />
</LayoutGridItem>
);
};
@@ -0,0 +1,20 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { AutoGrid } from '../../../common';
import { AchievementListItemView } from './AchievementListItemView';
interface AchievementListViewProps
{
achievements: AchievementData[];
}
export const AchievementListView: FC<AchievementListViewProps> = props =>
{
const { achievements = null } = props;
return (
<AutoGrid columnCount={ 6 } columnMinHeight={ 50 } columnMinWidth={ 50 }>
{ achievements && (achievements.length > 0) && achievements.map((achievement, index) => <AchievementListItemView key={ index } achievement={ achievement } />) }
</AutoGrid>
);
};
@@ -0,0 +1,2 @@
export * from './AchievementListItemView';
export * from './AchievementListView';
@@ -0,0 +1,31 @@
import { Dispatch, FC, SetStateAction } from 'react';
import { AchievementUtilities, IAchievementCategory, LocalizeText } from '../../../api';
import { LayoutBackgroundImage, LayoutGridItem, Text } from '../../../common';
interface AchievementCategoryListItemViewProps
{
category: IAchievementCategory;
selectedCategoryCode: string;
setSelectedCategoryCode: Dispatch<SetStateAction<string>>;
}
export const AchievementsCategoryListItemView: FC<AchievementCategoryListItemViewProps> = props =>
{
const { category = null, selectedCategoryCode = null, setSelectedCategoryCode = null } = props;
if(!category) return null;
const progress = AchievementUtilities.getAchievementCategoryProgress(category);
const maxProgress = AchievementUtilities.getAchievementCategoryMaxProgress(category);
const getCategoryImage = AchievementUtilities.getAchievementCategoryImageUrl(category, progress);
const getTotalUnseen = AchievementUtilities.getAchievementCategoryTotalUnseen(category);
return (
<LayoutGridItem gap={ 1 } itemActive={ (selectedCategoryCode === category.code) } itemCount={ getTotalUnseen } itemCountMinimum={ 0 } onClick={ event => setSelectedCategoryCode(category.code) }>
<Text center fullWidth small className="pt-1">{ LocalizeText(`quests.${ category.code }.name`) }</Text>
<LayoutBackgroundImage imageUrl={ getCategoryImage } position="relative">
<Text center fullWidth position="absolute" style={ { fontSize: 12, bottom: 9 } } variant="white">{ progress } / { maxProgress }</Text>
</LayoutBackgroundImage>
</LayoutGridItem>
);
};
@@ -0,0 +1,22 @@
import { Dispatch, FC, SetStateAction } from 'react';
import { IAchievementCategory } from '../../../api';
import { AutoGrid } from '../../../common';
import { AchievementsCategoryListItemView } from './AchievementsCategoryListItemView';
interface AchievementsCategoryListViewProps
{
categories: IAchievementCategory[];
selectedCategoryCode: string;
setSelectedCategoryCode: Dispatch<SetStateAction<string>>;
}
export const AchievementsCategoryListView: FC<AchievementsCategoryListViewProps> = props =>
{
const { categories = null, selectedCategoryCode = null, setSelectedCategoryCode = null } = props;
return (
<AutoGrid columnCount={ 3 } columnMinHeight={ 100 } columnMinWidth={ 90 }>
{ categories && (categories.length > 0) && categories.map((category, index) => <AchievementsCategoryListItemView key={ index } category={ category } selectedCategoryCode={ selectedCategoryCode } setSelectedCategoryCode={ setSelectedCategoryCode } />) }
</AutoGrid>
);
};
@@ -0,0 +1,2 @@
export * from './AchievementsCategoryListItemView';
export * from './AchievementsCategoryListView';
+6
View File
@@ -0,0 +1,6 @@
export * from './AchievementBadgeView';
export * from './AchievementCategoryView';
export * from './AchievementDetailsView';
export * from './AchievementsView';
export * from './achievement-list';
export * from './category-list';