Biome reported 229 diagnostics after aligning the config with
bsi-ni.brain.riken.jp. Fix them all so `biome check` passes clean
without per-rule overrides.
- replace `any` in LokiJS queries with an `ItemFilter` interface and
a single `asLokiQuery()` cast, matching bsi-ni
- type the XOOPS redirect maps as
`Record<string, { key: string; isNumber: boolean }>`
- use `ItemSubTypes<string>` instead of `any` for sub item types
- join author lists with `.join(', ')` instead of index-keyed nodes
- give list elements stable keys derived from their own data
- return `React.ReactNode` from `ListBase.renderBody()`
- drop the temporary `noArrayIndexKey` override from biome.json
135 lines
5.4 KiB
TypeScript
135 lines
5.4 KiB
TypeScript
import { Fragment } from 'react';
|
|
import { Link } from 'react-router';
|
|
import type { MultiLang } from '../../config';
|
|
import Functions from '../../functions';
|
|
import { siteData } from '../../siteData';
|
|
import imageStar from '../assets/images/star.gif';
|
|
import ItemUtil, { type ItemCore } from '../lib/ItemUtil';
|
|
import styles from './Rankings.module.css';
|
|
|
|
interface Props {
|
|
lang: MultiLang;
|
|
}
|
|
|
|
const orderLabel = (order: number, lang: string) => {
|
|
return String(order) + (lang === 'en' ? Functions.ordinal(order) : '位');
|
|
};
|
|
|
|
const Rankings = (props: Props) => {
|
|
const items = [
|
|
{
|
|
title: Functions.mlang('[en]Frequently accessed items[/en][ja]頻繁に閲覧されるアイテム[/ja]', props.lang),
|
|
list: siteData().rankings.accessed.map((item, idx) => {
|
|
const url = ItemUtil.getUrl(item as ItemCore);
|
|
const title = Functions.mlang(item.title, props.lang);
|
|
const order = orderLabel(idx + 1, props.lang);
|
|
return (
|
|
<div key={url} className={styles.item}>
|
|
<div className={styles.order}>{order}</div>
|
|
<div className={styles.title}>
|
|
<Link to={url} title={title}>
|
|
{title}
|
|
</Link>
|
|
</div>
|
|
{idx === 0 && (
|
|
<div className={styles.star}>
|
|
<img src={imageStar} alt={order} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}),
|
|
},
|
|
{
|
|
title: Functions.mlang(
|
|
'[en]Frequently downloaded items[/en][ja]頻繁にダウンロードされるアイテム[/ja]',
|
|
props.lang
|
|
),
|
|
list: siteData().rankings.downloaded.map((item, idx) => {
|
|
const url = ItemUtil.getUrl(item as ItemCore);
|
|
const title = Functions.mlang(item.title, props.lang);
|
|
const order = orderLabel(idx + 1, props.lang);
|
|
return (
|
|
<div key={url} className={styles.item}>
|
|
<div className={styles.order}>{order}</div>
|
|
<div className={styles.title}>
|
|
<Link to={url} title={title}>
|
|
{title}
|
|
</Link>
|
|
</div>
|
|
{idx === 0 && (
|
|
<div className={styles.star}>
|
|
<img src={imageStar} alt={order} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}),
|
|
},
|
|
{
|
|
title: Functions.mlang(
|
|
'[en]Most active contributers[/en][ja]最も多くアイテムを公開したユーザ[/ja]',
|
|
props.lang
|
|
),
|
|
list: siteData().rankings.contributed.map((item, idx) => {
|
|
const name = item.name !== '' ? `${item.name} (${item.uname})` : item.uname;
|
|
const title = Functions.mlang(name, props.lang);
|
|
const order = orderLabel(idx + 1, props.lang);
|
|
return (
|
|
<div key={item.uname} className={styles.item}>
|
|
<div className={styles.order}>{order}</div>
|
|
<div className={styles.uname}>{title}</div>
|
|
<div className={styles.count}>({item.count})</div>
|
|
{idx === 0 && (
|
|
<div className={styles.star}>
|
|
<img src={imageStar} alt={order} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}),
|
|
},
|
|
{
|
|
title: Functions.mlang(
|
|
'[en]Frequently searched keywords[/en][ja]頻繁に検索されるキーワード[/ja]',
|
|
props.lang
|
|
),
|
|
list: siteData().rankings.searched.map((item, idx) => {
|
|
const url = ItemUtil.getSearchByKeywordUrl('all', item.keyword);
|
|
const title = `Search by: ${item.keyword}`;
|
|
const order = orderLabel(idx + 1, props.lang);
|
|
return (
|
|
<div key={url} className={styles.item}>
|
|
<div className={styles.order}>{order}</div>
|
|
<div className={styles.title}>
|
|
<Link to={url} title={title}>
|
|
{item.keyword}
|
|
</Link>
|
|
</div>
|
|
{idx === 0 && (
|
|
<div className={styles.star}>
|
|
<img src={imageStar} alt={order} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}),
|
|
},
|
|
];
|
|
return (
|
|
<div>
|
|
{items.map((item, idx) => {
|
|
return (
|
|
<Fragment key={item.title}>
|
|
{idx !== 0 && <hr />}
|
|
<h3 className={styles.heading}>{item.title}</h3>
|
|
<div>{item.list}</div>
|
|
</Fragment>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Rankings;
|