UPDATE: Support custom lineup
All checks were successful
Gitea Auto Deploy / Deploy-Container (push) Successful in 53s
All checks were successful
Gitea Auto Deploy / Deploy-Container (push) Successful in 53s
This commit is contained in:
@@ -278,6 +278,7 @@
|
|||||||
"detailMultipathCharacter": "Allows changing the Path of certain characters.",
|
"detailMultipathCharacter": "Allows changing the Path of certain characters.",
|
||||||
"trailblazer": "Trailblazer",
|
"trailblazer": "Trailblazer",
|
||||||
"listExtraEffect": "List Extra Effect",
|
"listExtraEffect": "List Extra Effect",
|
||||||
"extra": "Extra"
|
"extra": "Extra",
|
||||||
|
"customLineup": "Custom Lineup"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,6 +277,7 @@
|
|||||||
"detailMultipathCharacter": "一部キャラクターの運命を変更できます。",
|
"detailMultipathCharacter": "一部キャラクターの運命を変更できます。",
|
||||||
"trailblazer": "開拓者",
|
"trailblazer": "開拓者",
|
||||||
"listExtraEffect": "追加効果一覧",
|
"listExtraEffect": "追加効果一覧",
|
||||||
"extra": "追加"
|
"extra": "追加",
|
||||||
|
"customLineup": "カスタム編成"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,6 +277,7 @@
|
|||||||
"detailMultipathCharacter": "일부 캐릭터의 운명을 변경할 수 있습니다.",
|
"detailMultipathCharacter": "일부 캐릭터의 운명을 변경할 수 있습니다.",
|
||||||
"trailblazer": "개척자",
|
"trailblazer": "개척자",
|
||||||
"listExtraEffect": "추가 효과 목록",
|
"listExtraEffect": "추가 효과 목록",
|
||||||
"extra": "추가"
|
"extra": "추가",
|
||||||
|
"customLineup": "커스텀 편성"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,6 +277,7 @@
|
|||||||
"detailMultipathCharacter": "Cho phép thay đổi Vận Mệnh của một vài nhân vật.",
|
"detailMultipathCharacter": "Cho phép thay đổi Vận Mệnh của một vài nhân vật.",
|
||||||
"trailblazer": "Nhà khai phá",
|
"trailblazer": "Nhà khai phá",
|
||||||
"listExtraEffect": "Danh sách hiệu ứng bổ sung",
|
"listExtraEffect": "Danh sách hiệu ứng bổ sung",
|
||||||
"extra": "Bổ sung"
|
"extra": "Bổ sung",
|
||||||
|
"customLineup": "Đội hình tùy chỉnh"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,6 +277,7 @@
|
|||||||
"detailMultipathCharacter": "允许更改部分角色的命途。",
|
"detailMultipathCharacter": "允许更改部分角色的命途。",
|
||||||
"trailblazer": "开拓者",
|
"trailblazer": "开拓者",
|
||||||
"listExtraEffect": "额外效果列表",
|
"listExtraEffect": "额外效果列表",
|
||||||
"extra": "额外"
|
"extra": "额外",
|
||||||
|
"customLineup": "自定义阵容"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { getNameChar } from '@/helper';
|
import { getNameChar } from '@/helper';
|
||||||
import useLocaleStore from '@/stores/localeStore';
|
import useLocaleStore from '@/stores/localeStore';
|
||||||
import { AvatarDetail } from '@/types';
|
import { AvatarDetail } from '@/types';
|
||||||
|
|||||||
69
src/components/card/simpleCharacterCard.tsx
Normal file
69
src/components/card/simpleCharacterCard.tsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
"use client";
|
||||||
|
import Image from 'next/image';
|
||||||
|
import { AvatarDetail } from '@/types';
|
||||||
|
import useDetailDataStore from '@/stores/detailDataStore';
|
||||||
|
|
||||||
|
|
||||||
|
interface SimpleAvatarCardProps {
|
||||||
|
data: AvatarDetail;
|
||||||
|
isSelected?: boolean;
|
||||||
|
onClick?: () => void;
|
||||||
|
showRemoveHover?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SimpleAvatarCard = ({ data, isSelected, onClick, showRemoveHover }: SimpleAvatarCardProps) => {
|
||||||
|
const { baseType, damageType } = useDetailDataStore()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={onClick}
|
||||||
|
className={`relative w-16 h-16 sm:w-20 sm:h-20 rounded-md cursor-pointer transition-transform duration-200 ease-in-out hover:scale-105 shadow-md shrink-0
|
||||||
|
${isSelected ? 'ring-2 ring-success opacity-60' : ''}
|
||||||
|
bg-linear-to-br ${data.Rarity === "CombatPowerAvatarRarityType5"
|
||||||
|
? "from-yellow-400 via-yellow-600/70 to-yellow-800/50"
|
||||||
|
: "from-purple-400 via-purple-600/70 to-purple-800/50"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
width={80}
|
||||||
|
height={80}
|
||||||
|
unoptimized
|
||||||
|
crossOrigin="anonymous"
|
||||||
|
src={`${process.env.CDN_URL}/${data.Image.ActionAvatarHeadIconPath}`}
|
||||||
|
priority={true}
|
||||||
|
className="w-full h-full object-contain"
|
||||||
|
alt="Avatar"
|
||||||
|
/>
|
||||||
|
<div className="absolute top-0 left-0 w-5 h-5 bg-black/40 rounded-full flex items-center justify-center p-0.5">
|
||||||
|
<Image
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
unoptimized
|
||||||
|
crossOrigin="anonymous"
|
||||||
|
src={`${process.env.CDN_URL}/${damageType?.[data.DamageType]?.Icon}`}
|
||||||
|
className="w-full h-full object-contain"
|
||||||
|
alt="Element"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="absolute top-0 right-0 w-5 h-5 bg-black/40 rounded-full flex items-center justify-center p-0.5">
|
||||||
|
<Image
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
unoptimized
|
||||||
|
crossOrigin="anonymous"
|
||||||
|
src={`${process.env.CDN_URL}/${baseType?.[data.BaseType]?.Icon}`}
|
||||||
|
className="w-full h-full object-contain"
|
||||||
|
alt="Path"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showRemoveHover && (
|
||||||
|
<div className="absolute inset-0 bg-error/80 rounded-md flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { motion } from "framer-motion"
|
import { motion } from "framer-motion"
|
||||||
import { EyeOff, Eye, Hammer, RefreshCw, ShieldBan, User, Swords, SkipForward, BowArrow, Info, RouteIcon, Search, CupSoda } from "lucide-react"
|
import { EyeOff, Eye, Hammer, RefreshCw, ShieldBan, User, Swords, SkipForward, BowArrow, Info, RouteIcon, Search, CupSoda, UsersIcon } from "lucide-react"
|
||||||
import useGlobalStore from '@/stores/globalStore'
|
import useGlobalStore from '@/stores/globalStore'
|
||||||
import { useTranslations } from "next-intl"
|
import { useTranslations } from "next-intl"
|
||||||
import { getLocaleName, getNameChar } from "@/helper"
|
import { getLocaleName, getNameChar } from "@/helper"
|
||||||
@@ -12,6 +12,7 @@ import Editor from "react-simple-code-editor"
|
|||||||
import Prism from "prismjs"
|
import Prism from "prismjs"
|
||||||
import "prismjs/components/prism-lua"
|
import "prismjs/components/prism-lua"
|
||||||
import "prismjs/themes/prism-tomorrow.css"
|
import "prismjs/themes/prism-tomorrow.css"
|
||||||
|
import { SimpleAvatarCard } from "../card/simpleCharacterCard"
|
||||||
|
|
||||||
export default function ExtraSettingBar() {
|
export default function ExtraSettingBar() {
|
||||||
const { extraData, setExtraData, isEnableChangePath, setIsEnableChangePath, isEnableLua, setIsEnableLua } = useGlobalStore()
|
const { extraData, setExtraData, isEnableChangePath, setIsEnableChangePath, isEnableLua, setIsEnableLua } = useGlobalStore()
|
||||||
@@ -19,6 +20,7 @@ export default function ExtraSettingBar() {
|
|||||||
const { mapAvatar, mapPeak, stage, baseType } = useDetailDataStore()
|
const { mapAvatar, mapPeak, stage, baseType } = useDetailDataStore()
|
||||||
const { locale } = useLocaleStore()
|
const { locale } = useLocaleStore()
|
||||||
const [showSearchStage, setShowSearchStage] = useState(false)
|
const [showSearchStage, setShowSearchStage] = useState(false)
|
||||||
|
const [showSearchLineup, setShowSearchLineup] = useState(false)
|
||||||
const [isChildClick, setIsChildClick] = useState(false)
|
const [isChildClick, setIsChildClick] = useState(false)
|
||||||
const [stageSearchTerm, setStageSearchTerm] = useState("")
|
const [stageSearchTerm, setStageSearchTerm] = useState("")
|
||||||
const [stagePage, setStagePage] = useState(1)
|
const [stagePage, setStagePage] = useState(1)
|
||||||
@@ -106,6 +108,7 @@ export default function ExtraSettingBar() {
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
<motion.div className="form-control bg-base-200 p-4 rounded-xl shadow">
|
<motion.div className="form-control bg-base-200 p-4 rounded-xl shadow">
|
||||||
<label className="flex flex-wrap items-center justify-start gap-3">
|
<label className="flex flex-wrap items-center justify-start gap-3">
|
||||||
<RouteIcon className="text-info" size={20} />
|
<RouteIcon className="text-info" size={20} />
|
||||||
@@ -170,9 +173,10 @@ export default function ExtraSettingBar() {
|
|||||||
...extraData,
|
...extraData,
|
||||||
theory_craft: {
|
theory_craft: {
|
||||||
stage_id: Number(stage.ID),
|
stage_id: Number(stage.ID),
|
||||||
cycle_count: extraData?.theory_craft?.cycle_count || 1,
|
cycle_count: extraData?.theory_craft?.cycle_count ?? 1,
|
||||||
mode: extraData?.theory_craft?.mode || false,
|
mode: extraData?.theory_craft?.mode ?? false,
|
||||||
hp: extraData?.theory_craft?.hp || {}
|
hp: extraData?.theory_craft?.hp ?? {},
|
||||||
|
custom_lineup: extraData?.theory_craft?.custom_lineup ?? []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -220,6 +224,100 @@ export default function ExtraSettingBar() {
|
|||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
<motion.div className="form-control bg-base-200 p-4 rounded-xl shadow relative">
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
<label className="flex flex-wrap items-center justify-start gap-3">
|
||||||
|
<UsersIcon className="text-info" size={20} />
|
||||||
|
<span className="label-text font-semibold">{transI18n("customLineup")}</span>
|
||||||
|
</label>
|
||||||
|
<div className="flex flex-wrap items-center gap-2 min-h-20 p-2 bg-base-300 rounded-lg border border-base-content/10">
|
||||||
|
{(extraData?.theory_craft?.custom_lineup || []).length > 0 && (
|
||||||
|
(extraData?.theory_craft?.custom_lineup || []).map((avatarId) => {
|
||||||
|
const avatarData = mapAvatar[avatarId];
|
||||||
|
if (!avatarData) return null;
|
||||||
|
return (
|
||||||
|
<SimpleAvatarCard
|
||||||
|
key={`selected-${avatarId}`}
|
||||||
|
data={avatarData}
|
||||||
|
showRemoveHover={true}
|
||||||
|
onClick={() => {
|
||||||
|
const newLineup = (extraData?.theory_craft?.custom_lineup || []).filter(id => id !== avatarId);
|
||||||
|
setExtraData({
|
||||||
|
...extraData,
|
||||||
|
theory_craft: {
|
||||||
|
stage_id: extraData?.theory_craft?.stage_id ?? 30118121,
|
||||||
|
cycle_count: extraData?.theory_craft?.cycle_count ?? 1,
|
||||||
|
mode: extraData?.theory_craft?.mode ?? false,
|
||||||
|
hp: extraData?.theory_craft?.hp ?? {},
|
||||||
|
custom_lineup: newLineup
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="btn btn-outline btn-square border-dashed w-16 h-16 sm:w-20 sm:h-20"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setShowSearchLineup(pre => !pre);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 4v16m8-8H4" /></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showSearchLineup && (
|
||||||
|
<div
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
className="absolute top-full left-0 mt-2 w-full z-50 border bg-base-200 border-slate-600 rounded-lg p-4 shadow-2xl"
|
||||||
|
>
|
||||||
|
<div className="flex justify-between items-center mb-3">
|
||||||
|
<span className="font-semibold text-sm">{transI18n("selectedCharacters")}</span>
|
||||||
|
<button className="btn btn-sm btn-error" onClick={() => setShowSearchLineup(false)}>Đóng</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap gap-2 max-h-72 overflow-y-auto p-1">
|
||||||
|
{Object.values(mapAvatar).map((avatar) => {
|
||||||
|
const currentLineup = extraData?.theory_craft?.custom_lineup || [];
|
||||||
|
const isSelected = currentLineup.includes(avatar.ID.toString());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SimpleAvatarCard
|
||||||
|
key={avatar.ID}
|
||||||
|
data={avatar}
|
||||||
|
isSelected={isSelected}
|
||||||
|
onClick={() => {
|
||||||
|
const idStr = avatar.ID.toString();
|
||||||
|
let newLineup = [...currentLineup];
|
||||||
|
|
||||||
|
if (isSelected) {
|
||||||
|
newLineup = newLineup.filter(id => id !== idStr);
|
||||||
|
} else {
|
||||||
|
newLineup.push(idStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
setExtraData({
|
||||||
|
...extraData,
|
||||||
|
theory_craft: {
|
||||||
|
stage_id: extraData?.theory_craft?.stage_id ?? 30118121,
|
||||||
|
cycle_count: extraData?.theory_craft?.cycle_count ?? 1,
|
||||||
|
mode: extraData?.theory_craft?.mode ?? false,
|
||||||
|
hp: extraData?.theory_craft?.hp ?? {},
|
||||||
|
custom_lineup: newLineup
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ interface EnkaState {
|
|||||||
setUidInput: (newUidInput: string) => void;
|
setUidInput: (newUidInput: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useEnkaStore = create<EnkaState>((set, get) => ({
|
const useEnkaStore = create<EnkaState>((set) => ({
|
||||||
selectedCharacters: [],
|
selectedCharacters: [],
|
||||||
enkaData: null,
|
enkaData: null,
|
||||||
uidInput: "",
|
uidInput: "",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export interface ExtraData {
|
|||||||
cycle_count: number
|
cycle_count: number
|
||||||
mode: boolean
|
mode: boolean
|
||||||
stage_id: number
|
stage_id: number
|
||||||
|
custom_lineup?: string[]
|
||||||
}
|
}
|
||||||
setting?: {
|
setting?: {
|
||||||
censorship: boolean
|
censorship: boolean
|
||||||
@@ -22,5 +23,5 @@ export interface ExtraData {
|
|||||||
multi_path_main: number[]
|
multi_path_main: number[]
|
||||||
multi_path_march_7: number[]
|
multi_path_march_7: number[]
|
||||||
},
|
},
|
||||||
lua: string | null
|
lua?: string | null
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user