add card.admin, rse.admin
This commit is contained in:
@@ -1,4 +1,15 @@
|
||||
// RSE display component for ai.syui.rse.user collection
|
||||
import { renderCard, type UserCard, type CardAdminEntry, type CardAdminData } from './card'
|
||||
|
||||
export interface RseAdminItem {
|
||||
id: number
|
||||
name: string
|
||||
text: { ja: string; en: string }
|
||||
}
|
||||
|
||||
export interface RseAdminData {
|
||||
item: RseAdminItem[]
|
||||
}
|
||||
|
||||
export interface RseItem {
|
||||
id: number
|
||||
@@ -14,31 +25,135 @@ export interface RseCollection {
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
// Get current language
|
||||
function getLang(): string {
|
||||
return localStorage.getItem('preferredLang') || 'ja'
|
||||
}
|
||||
|
||||
// Get localized text
|
||||
function getLocalizedText(obj: { ja: string; en: string } | undefined): string {
|
||||
if (!obj) return ''
|
||||
const lang = getLang()
|
||||
return obj[lang as 'ja' | 'en'] || obj.ja || obj.en || ''
|
||||
}
|
||||
|
||||
// Get rarity class from unique flag
|
||||
function getRarityClass(item: RseItem): string {
|
||||
if (item.unique) return 'unique'
|
||||
return ''
|
||||
}
|
||||
|
||||
// Render single item/character
|
||||
function renderRseItem(item: RseItem, type: 'item' | 'character'): string {
|
||||
// Get cards for a character (character 0 = cards 0-99, character 1 = cards 100-199, etc.)
|
||||
function getCardsForCharacter(
|
||||
characterId: number,
|
||||
userCards: UserCard[],
|
||||
adminData: CardAdminData | null
|
||||
): { card: UserCard; adminEntry?: CardAdminEntry }[] {
|
||||
const minId = characterId * 100
|
||||
const maxId = minId + 99
|
||||
|
||||
// Build admin lookup map
|
||||
const adminMap = new Map<number, CardAdminEntry>()
|
||||
if (adminData?.card) {
|
||||
for (const entry of adminData.card) {
|
||||
adminMap.set(entry.id, entry)
|
||||
}
|
||||
}
|
||||
|
||||
// Filter and dedupe cards for this character
|
||||
const cardGroups = new Map<number, UserCard>()
|
||||
for (const card of userCards) {
|
||||
if (card.id >= minId && card.id <= maxId) {
|
||||
const existing = cardGroups.get(card.id)
|
||||
if (!existing || card.cp > existing.cp || card.unique) {
|
||||
cardGroups.set(card.id, card)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by ID and add admin entries
|
||||
return Array.from(cardGroups.values())
|
||||
.sort((a, b) => a.id - b.id)
|
||||
.map(card => ({
|
||||
card,
|
||||
adminEntry: adminMap.get(card.id)
|
||||
}))
|
||||
}
|
||||
|
||||
// Render character section with its cards below
|
||||
function renderCharacterSection(
|
||||
item: RseItem,
|
||||
userCards: UserCard[],
|
||||
adminData: CardAdminData | null
|
||||
): string {
|
||||
const rarityClass = getRarityClass(item)
|
||||
const effectsHtml = rarityClass ? `
|
||||
<div class="card-status pattern-${rarityClass}"></div>
|
||||
<div class="card-status color-${rarityClass}"></div>
|
||||
` : ''
|
||||
|
||||
// Get cards for this character
|
||||
const characterCards = getCardsForCharacter(item.id, userCards, adminData)
|
||||
const cardsHtml = characterCards.map(({ card, adminEntry }) =>
|
||||
renderCard(card, '/card', undefined, adminEntry)
|
||||
).join('')
|
||||
|
||||
return `
|
||||
<div class="rse-character-section">
|
||||
<div class="rse-character-main">
|
||||
<div class="card-item">
|
||||
<div class="card-wrapper">
|
||||
<div class="card-reflection">
|
||||
<img src="/rse/character/${item.id}.webp" alt="character ${item.id}" loading="lazy" />
|
||||
</div>
|
||||
${effectsHtml}
|
||||
</div>
|
||||
<div class="card-detail">
|
||||
<span class="card-cp">${item.cp}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
${characterCards.length > 0 ? `
|
||||
<div class="rse-card-grid">${cardsHtml}</div>
|
||||
` : ''}
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
// Render single item
|
||||
function renderRseItem(item: RseItem, rseAdminData: RseAdminData | null): string {
|
||||
const rarityClass = getRarityClass(item)
|
||||
const effectsHtml = rarityClass ? `
|
||||
<div class="card-status pattern-${rarityClass}"></div>
|
||||
<div class="card-status color-${rarityClass}"></div>
|
||||
` : ''
|
||||
|
||||
// Get admin entry for this item
|
||||
const adminEntry = rseAdminData?.item?.find(i => i.id === item.id)
|
||||
const name = adminEntry?.name || ''
|
||||
const text = adminEntry ? getLocalizedText(adminEntry.text) : ''
|
||||
|
||||
const infoHtml = (name || text) ? `
|
||||
<div class="card-info">
|
||||
<div class="card-info-header">
|
||||
<span class="card-info-name">${name}</span>
|
||||
</div>
|
||||
${text ? `<div class="card-info-text">${text}</div>` : ''}
|
||||
</div>
|
||||
` : ''
|
||||
|
||||
return `
|
||||
<div class="card-item">
|
||||
<div class="card-wrapper">
|
||||
<div class="card-reflection">
|
||||
<img src="/rse/${type}/${item.id}.webp" alt="${type} ${item.id}" loading="lazy" />
|
||||
<img src="/rse/item/${item.id}.webp" alt="item ${item.id}" loading="lazy" />
|
||||
</div>
|
||||
${effectsHtml}
|
||||
</div>
|
||||
<div class="card-detail">
|
||||
<span class="card-cp">${item.cp}</span>
|
||||
</div>
|
||||
${infoHtml}
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -46,7 +161,10 @@ function renderRseItem(item: RseItem, type: 'item' | 'character'): string {
|
||||
// Render RSE page
|
||||
export function renderRsePage(
|
||||
collection: RseCollection | null,
|
||||
handle: string
|
||||
handle: string,
|
||||
userCards: UserCard[] = [],
|
||||
adminData: CardAdminData | null = null,
|
||||
rseAdminData: RseAdminData | null = null
|
||||
): string {
|
||||
const jsonUrl = `/@${handle}/at/collection/ai.syui.rse.user/self`
|
||||
|
||||
@@ -70,19 +188,14 @@ export function renderRsePage(
|
||||
const totalItems = items.length
|
||||
const uniqueChars = characters.filter(c => c.unique).length
|
||||
|
||||
// Sort by unique > id
|
||||
const sortedChars = [...characters].sort((a, b) => {
|
||||
if (a.unique !== b.unique) return a.unique ? -1 : 1
|
||||
return a.id - b.id
|
||||
})
|
||||
// Sort by id
|
||||
const sortedChars = [...characters].sort((a, b) => a.id - b.id)
|
||||
const sortedItems = [...items].sort((a, b) => a.id - b.id)
|
||||
|
||||
const sortedItems = [...items].sort((a, b) => {
|
||||
if (a.unique !== b.unique) return a.unique ? -1 : 1
|
||||
return a.id - b.id
|
||||
})
|
||||
|
||||
const charsHtml = sortedChars.map(c => renderRseItem(c, 'character')).join('')
|
||||
const itemsHtml = sortedItems.map(i => renderRseItem(i, 'item')).join('')
|
||||
const charsHtml = sortedChars.map(c =>
|
||||
renderCharacterSection(c, userCards, adminData)
|
||||
).join('')
|
||||
const itemsHtml = sortedItems.map(i => renderRseItem(i, rseAdminData)).join('')
|
||||
|
||||
return `
|
||||
<div class="card-page">
|
||||
@@ -107,7 +220,7 @@ export function renderRsePage(
|
||||
</div>
|
||||
${charsHtml ? `
|
||||
<h3 class="rse-section-title">Characters</h3>
|
||||
<div class="card-grid">${charsHtml}</div>
|
||||
<div class="rse-characters">${charsHtml}</div>
|
||||
` : ''}
|
||||
${itemsHtml ? `
|
||||
<h3 class="rse-section-title">Items</h3>
|
||||
|
||||
Reference in New Issue
Block a user