feat: add header component with integrated settings and data management modal controls
Gitea Auto Deploy / Deploy-Container (push) Successful in 40s
Gitea Auto Deploy / Deploy-Container (push) Successful in 40s
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { EyeOff, Eye, Hammer, RefreshCw, ShieldBan, User, Swords, SkipForward, BowArrow, Info, RouteIcon, Search, CupSoda, UsersIcon } from "lucide-react"
|
import { EyeOff, Eye, Hammer, RefreshCw, ShieldBan, User, Swords, SkipForward, BowArrow, Info, RouteIcon, Search, CupSoda, UsersIcon, X, Check, Code, Plus } 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"
|
||||||
@@ -39,19 +39,19 @@ export default function ExtraSettingBar() {
|
|||||||
)
|
)
|
||||||
const [showSearchStage, setShowSearchStage] = useState(false)
|
const [showSearchStage, setShowSearchStage] = useState(false)
|
||||||
const [showSearchLineup, setShowSearchLineup] = useState(false)
|
const [showSearchLineup, setShowSearchLineup] = useState(false)
|
||||||
const [isChildClick, setIsChildClick] = useState(false)
|
|
||||||
const [stageSearchTerm, setStageSearchTerm] = useState("")
|
const [stageSearchTerm, setStageSearchTerm] = useState("")
|
||||||
|
const [lineupSearchTerm, setLineupSearchTerm] = useState("")
|
||||||
const [stagePage, setStagePage] = useState(1)
|
const [stagePage, setStagePage] = useState(1)
|
||||||
|
|
||||||
const pageSize = 30
|
const pageSize = 30
|
||||||
const stageList = useMemo(() => Object.values(stage), [stage])
|
const stageList = useMemo(() => Object.values(stage), [stage])
|
||||||
|
|
||||||
const term = stageSearchTerm.toLowerCase()
|
const stageTerm = stageSearchTerm.toLowerCase()
|
||||||
|
|
||||||
const filteredStages = useMemo(() => stageList.filter((s) =>
|
const filteredStages = useMemo(() => stageList.filter((s) =>
|
||||||
getLocaleName(locale, s.Name).toLowerCase().includes(term) ||
|
getLocaleName(locale, s.Name).toLowerCase().includes(stageTerm) ||
|
||||||
String(s.ID).toLowerCase().includes(term)
|
String(s.ID).toLowerCase().includes(stageTerm)
|
||||||
), [stageList, term, locale])
|
), [stageList, stageTerm, locale])
|
||||||
|
|
||||||
const paginatedStages = useMemo(() => filteredStages.slice(
|
const paginatedStages = useMemo(() => filteredStages.slice(
|
||||||
(stagePage - 1) * pageSize,
|
(stagePage - 1) * pageSize,
|
||||||
@@ -60,35 +60,58 @@ export default function ExtraSettingBar() {
|
|||||||
|
|
||||||
const hasMorePages = useMemo(() => stagePage * pageSize < filteredStages.length, [stagePage, filteredStages])
|
const hasMorePages = useMemo(() => stagePage * pageSize < filteredStages.length, [stagePage, filteredStages])
|
||||||
|
|
||||||
const onChangeSearch = (v: string) => {
|
const onChangeStageSearch = (v: string) => {
|
||||||
setStageSearchTerm(v)
|
setStageSearchTerm(v)
|
||||||
setStagePage(1)
|
setStagePage(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter avatars for lineup selector
|
||||||
|
const avatarList = useMemo(() => Object.values(mapAvatar), [mapAvatar])
|
||||||
|
const filteredAvatars = useMemo(() => {
|
||||||
|
if (!lineupSearchTerm.trim()) return avatarList
|
||||||
|
const term = lineupSearchTerm.toLowerCase()
|
||||||
|
return avatarList.filter(a => {
|
||||||
|
const charName = getNameChar(locale, transI18n, a).toLowerCase()
|
||||||
|
return charName.includes(term) || a.ID.toString().includes(term)
|
||||||
|
})
|
||||||
|
}, [avatarList, lineupSearchTerm, locale, transI18n])
|
||||||
|
|
||||||
|
const currentLineup = extraData?.theory_craft?.custom_lineup || []
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="max-w-4xl mx-auto space-y-4 pb-2">
|
||||||
{/* THEORY CRAFT */}
|
{/* THEORY CRAFT */}
|
||||||
{extraData?.theory_craft && (
|
{extraData?.theory_craft && (
|
||||||
<div className="p-4 sm:p-5 rounded-2xl bg-base-200/60 border border-white/10 shadow-lg space-y-4">
|
<section className="relative z-30 rounded-2xl bg-base-200/40 border border-white/10 shadow-xs backdrop-blur-sm transition-all duration-200">
|
||||||
<div className="flex items-center justify-between pb-2 border-b border-base-content/10">
|
{/* Section Header */}
|
||||||
<h3 className="text-sm font-bold uppercase tracking-wider text-primary flex items-center gap-2">
|
<div className="flex items-center justify-between p-4 sm:p-5">
|
||||||
<span className="w-1.5 h-3.5 bg-primary rounded-full"></span>
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-xl bg-primary/10 border border-primary/20 text-primary flex items-center justify-center shrink-0 shadow-inner">
|
||||||
|
<Hammer className="w-5 h-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<h3 className="text-sm font-bold tracking-tight text-base-content">
|
||||||
{transI18n("theoryCraft")}
|
{transI18n("theoryCraft")}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="tooltip tooltip-left tooltip-info" data-tip={transI18n("detailTheoryCraft")}>
|
<div className="tooltip tooltip-bottom tooltip-info" data-tip={transI18n("detailTheoryCraft")}>
|
||||||
<Info className="text-primary w-4 h-4 cursor-pointer" />
|
<Info className="text-primary/70 hover:text-primary w-3.5 h-3.5 cursor-pointer transition-colors" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-base-content/60 line-clamp-1 mt-0.5">
|
||||||
|
{transI18n("detailTheoryCraft")}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-3.5 rounded-xl bg-base-100/60 border border-white/5 flex items-center justify-between">
|
<div className="flex items-center gap-2.5">
|
||||||
<label className="flex items-center gap-3 cursor-pointer">
|
<span className={`text-xs font-semibold uppercase tracking-wider hidden sm:inline ${extraData?.theory_craft?.mode ? 'text-primary' : 'text-base-content/40'}`}>
|
||||||
<Hammer className="text-primary w-4 h-4" />
|
{extraData?.theory_craft?.mode ? 'Active' : 'Off'}
|
||||||
<span className="text-xs sm:text-sm font-semibold">{transI18n("theoryCraftMode")}</span>
|
</span>
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="toggle toggle-primary"
|
className="toggle toggle-primary"
|
||||||
checked={extraData?.theory_craft?.mode}
|
checked={extraData?.theory_craft?.mode || false}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setExtraData({
|
setExtraData({
|
||||||
...extraData,
|
...extraData,
|
||||||
@@ -96,25 +119,31 @@ export default function ExtraSettingBar() {
|
|||||||
hp: extraData?.theory_craft?.hp || {},
|
hp: extraData?.theory_craft?.hp || {},
|
||||||
cycle_count: extraData?.theory_craft?.cycle_count || 1,
|
cycle_count: extraData?.theory_craft?.cycle_count || 1,
|
||||||
mode: e.target.checked,
|
mode: e.target.checked,
|
||||||
stage_id: extraData?.theory_craft?.stage_id || 0
|
stage_id: extraData?.theory_craft?.stage_id || 0,
|
||||||
|
custom_lineup: extraData?.theory_craft?.custom_lineup || []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{extraData?.theory_craft?.mode && (
|
|
||||||
<div className="space-y-3 pt-1">
|
|
||||||
{/* Cycle Count */}
|
|
||||||
<div className="p-3.5 rounded-xl bg-base-100/60 border border-white/5 flex items-center justify-between gap-3">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<RefreshCw className="text-info w-4 h-4" />
|
|
||||||
<span className="text-xs sm:text-sm font-semibold">{transI18n("cycleCount")}</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Theorycraft Expanded Content */}
|
||||||
|
{extraData?.theory_craft?.mode && (
|
||||||
|
<div className="border-t border-white/5 bg-base-300/20 p-4 sm:p-5 space-y-4">
|
||||||
|
{/* Simulation Settings Grid */}
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
|
{/* Cycle Count */}
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<label className="flex items-center gap-2 text-xs font-semibold text-base-content/80">
|
||||||
|
<RefreshCw className="text-info w-3.5 h-3.5" />
|
||||||
|
<span>{transI18n("cycleCount")}</span>
|
||||||
|
</label>
|
||||||
|
<div className="relative">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
className="input input-sm input-bordered w-24 rounded-xl text-center font-mono font-bold"
|
className="input input-sm input-bordered w-full rounded-xl bg-base-100 text-base-content border-white/15 focus:border-primary text-xs sm:text-sm font-mono font-bold"
|
||||||
value={extraData?.theory_craft?.cycle_count}
|
value={extraData?.theory_craft?.cycle_count || 1}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setExtraData({
|
setExtraData({
|
||||||
...extraData,
|
...extraData,
|
||||||
@@ -122,63 +151,75 @@ export default function ExtraSettingBar() {
|
|||||||
hp: extraData?.theory_craft?.hp || {},
|
hp: extraData?.theory_craft?.hp || {},
|
||||||
cycle_count: Number(e.target.value) || 1,
|
cycle_count: Number(e.target.value) || 1,
|
||||||
mode: extraData?.theory_craft?.mode || false,
|
mode: extraData?.theory_craft?.mode || false,
|
||||||
stage_id: extraData?.theory_craft?.stage_id || 0
|
stage_id: extraData?.theory_craft?.stage_id || 0,
|
||||||
|
custom_lineup: extraData?.theory_craft?.custom_lineup || []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
min="1"
|
min="1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Stage Selection */}
|
{/* Stage Selection */}
|
||||||
<div className="p-3.5 rounded-xl bg-base-100/60 border border-white/5 space-y-2">
|
<div className="space-y-1.5 relative">
|
||||||
<div className="flex items-center gap-2">
|
<label className="flex items-center gap-2 text-xs font-semibold text-base-content/80">
|
||||||
<RouteIcon className="text-info w-4 h-4" />
|
<RouteIcon className="text-info w-3.5 h-3.5" />
|
||||||
<span className="text-xs sm:text-sm font-semibold">{transI18n("stage")}</span>
|
<span>{transI18n("stage")}</span>
|
||||||
</div>
|
</label>
|
||||||
<div className="relative">
|
|
||||||
<button
|
<button
|
||||||
className="btn btn-sm btn-outline w-full rounded-xl flex items-center justify-between text-xs sm:text-sm"
|
type="button"
|
||||||
onClick={(e) => {
|
className="btn btn-sm btn-outline w-full rounded-xl bg-base-100 text-base-content border-white/15 hover:border-primary flex items-center justify-between text-xs font-normal transition-all"
|
||||||
e.stopPropagation()
|
onClick={() => setShowSearchStage(pre => !pre)}
|
||||||
if (!isChildClick) {
|
|
||||||
setShowSearchStage(pre => !pre)
|
|
||||||
}
|
|
||||||
setIsChildClick(false)
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<span className="truncate">
|
<span className="truncate">
|
||||||
{getLocaleName(locale, stageList.find((s) => s.ID.toString() === extraData?.theory_craft?.stage_id?.toString())?.Name) || transI18n("selectStage")}
|
{getLocaleName(locale, stageList.find((s) => s.ID.toString() === extraData?.theory_craft?.stage_id?.toString())?.Name) || transI18n("selectStage")}
|
||||||
</span>
|
</span>
|
||||||
<Search className="w-3.5 h-3.5 shrink-0 ml-2" />
|
<Search className="w-3.5 h-3.5 shrink-0 text-base-content/50 ml-2" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{/* Stage Search Popover */}
|
||||||
{showSearchStage && (
|
{showSearchStage && (
|
||||||
<div onClick={(e) => e.stopPropagation()} className="absolute top-full mt-2 w-full z-50 bg-base-100 border border-base-content/15 rounded-2xl p-3.5 shadow-2xl space-y-3">
|
<div
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
className="absolute top-full mt-2 left-0 right-0 z-50 bg-base-100 border border-white/15 rounded-2xl p-3 shadow-2xl space-y-2.5"
|
||||||
|
>
|
||||||
|
<div className="relative">
|
||||||
<input
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
className="input input-sm input-bordered w-full rounded-xl text-xs"
|
className="input input-sm input-bordered w-full rounded-xl bg-base-200/50 border-white/10 text-xs pr-7 focus:border-primary"
|
||||||
placeholder={transI18n("searchStage")}
|
placeholder={transI18n("searchStage")}
|
||||||
value={stageSearchTerm}
|
value={stageSearchTerm}
|
||||||
onChange={(e) => onChangeSearch(e.target.value)}
|
onChange={(e) => onChangeStageSearch(e.target.value)}
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
|
{stageSearchTerm && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="absolute right-2 top-1/2 -translate-y-1/2 text-base-content/40 hover:text-base-content"
|
||||||
|
onClick={() => onChangeStageSearch("")}
|
||||||
|
>
|
||||||
|
<X className="w-3 h-3" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="max-h-56 overflow-y-auto space-y-1 pr-1 text-xs">
|
<div className="max-h-52 overflow-y-auto space-y-0.5 pr-1 text-xs divide-y divide-white/5">
|
||||||
{paginatedStages.length > 0 ? (
|
{paginatedStages.length > 0 ? (
|
||||||
paginatedStages.map((stage) => (
|
paginatedStages.map((stg) => {
|
||||||
|
const isSelected = extraData?.theory_craft?.stage_id === Number(stg.ID)
|
||||||
|
return (
|
||||||
<div
|
<div
|
||||||
key={stage.ID}
|
key={stg.ID}
|
||||||
className="p-2 hover:bg-primary/20 rounded-xl cursor-pointer transition-colors"
|
className={`p-2 rounded-lg cursor-pointer flex items-center justify-between transition-colors ${
|
||||||
onClick={(e) => {
|
isSelected ? "bg-primary/20 text-primary font-bold" : "hover:bg-base-200/80 text-base-content/80 hover:text-base-content"
|
||||||
e.stopPropagation()
|
}`}
|
||||||
setIsChildClick(true)
|
onClick={() => {
|
||||||
|
if (extraData?.theory_craft?.stage_id !== Number(stg.ID)) {
|
||||||
if (extraData?.theory_craft?.stage_id !== Number(stage.ID)) {
|
|
||||||
setExtraData({
|
setExtraData({
|
||||||
...extraData,
|
...extraData,
|
||||||
theory_craft: {
|
theory_craft: {
|
||||||
stage_id: Number(stage.ID),
|
stage_id: Number(stg.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 ?? {},
|
||||||
@@ -186,38 +227,34 @@ export default function ExtraSettingBar() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
setShowSearchStage(pre => !pre)
|
setShowSearchStage(false)
|
||||||
onChangeSearch("")
|
onChangeStageSearch("")
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{getLocaleName(locale, stage.Name)}
|
<span className="truncate">{getLocaleName(locale, stg.Name)}</span>
|
||||||
|
{isSelected && <Check className="w-3.5 h-3.5 text-primary shrink-0 ml-1.5" />}
|
||||||
</div>
|
</div>
|
||||||
))
|
)
|
||||||
|
})
|
||||||
) : (
|
) : (
|
||||||
<div className="text-xs text-center py-4 text-base-content/40">{transI18n("noStageFound")}</div>
|
<div className="text-xs text-center py-4 text-base-content/40">{transI18n("noStageFound")}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{paginatedStages.length > 0 && (
|
{paginatedStages.length > 0 && (
|
||||||
<div className="flex items-center justify-between gap-2 pt-2 border-t border-white/5">
|
<div className="flex items-center justify-between gap-2 pt-2 border-t border-white/5 text-[11px]">
|
||||||
<button
|
<button
|
||||||
disabled={stagePage === 1}
|
disabled={stagePage === 1}
|
||||||
className="btn btn-xs btn-outline rounded-lg"
|
className="btn btn-xs btn-outline rounded-lg"
|
||||||
onClick={(e) => {
|
onClick={() => setStagePage(stagePage - 1)}
|
||||||
e.stopPropagation()
|
|
||||||
setStagePage(stagePage - 1)
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{transI18n("previous")}
|
{transI18n("previous")}
|
||||||
</button>
|
</button>
|
||||||
<span className="text-[11px] font-mono text-base-content/50">Page {stagePage}</span>
|
<span className="font-mono text-base-content/50">Page {stagePage}</span>
|
||||||
<button
|
<button
|
||||||
disabled={!hasMorePages}
|
disabled={!hasMorePages}
|
||||||
className="btn btn-xs btn-outline rounded-lg"
|
className="btn btn-xs btn-outline rounded-lg"
|
||||||
onClick={(e) => {
|
onClick={() => setStagePage(stagePage + 1)}
|
||||||
e.stopPropagation()
|
|
||||||
setStagePage(stagePage + 1)
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{transI18n("next")}
|
{transI18n("next")}
|
||||||
</button>
|
</button>
|
||||||
@@ -229,23 +266,47 @@ export default function ExtraSettingBar() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Custom Lineup */}
|
{/* Custom Lineup */}
|
||||||
<div className="p-3.5 rounded-xl bg-base-100/60 border border-white/5 space-y-2.5">
|
<div className="space-y-3 pt-2 border-t border-white/5">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center justify-between">
|
||||||
<UsersIcon className="text-info w-4 h-4" />
|
<label className="flex items-center gap-2 text-xs font-semibold text-base-content/80">
|
||||||
<span className="text-xs sm:text-sm font-semibold">{transI18n("customLineup")}</span>
|
<UsersIcon className="text-info w-3.5 h-3.5" />
|
||||||
|
<span>{transI18n("customLineup")}</span>
|
||||||
|
<span className="text-[10px] px-1.5 py-0.5 rounded-full bg-primary/10 text-primary border border-primary/20 font-bold">
|
||||||
|
{currentLineup.length}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-xs btn-ghost text-primary hover:bg-primary/10 gap-1 rounded-lg"
|
||||||
|
onClick={() => setShowSearchLineup(pre => !pre)}
|
||||||
|
>
|
||||||
|
{showSearchLineup ? (
|
||||||
|
<>
|
||||||
|
<X className="w-3 h-3" />
|
||||||
|
<span>Close List</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Plus className="w-3 h-3" />
|
||||||
|
<span>Select Characters</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-2 min-h-16 p-2 bg-base-200/50 rounded-xl border border-white/5">
|
{/* Selected Avatars Strip */}
|
||||||
{(extraData?.theory_craft?.custom_lineup || []).map((avatarId) => {
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
const avatarData = mapAvatar[avatarId];
|
{currentLineup.map((avatarId) => {
|
||||||
if (!avatarData) return null;
|
const avatarData = mapAvatar[avatarId]
|
||||||
|
if (!avatarData) return null
|
||||||
return (
|
return (
|
||||||
<SimpleAvatarCard
|
<SimpleAvatarCard
|
||||||
key={`selected-${avatarId}`}
|
key={`selected-${avatarId}`}
|
||||||
data={avatarData}
|
data={avatarData}
|
||||||
showRemoveHover={true}
|
showRemoveHover={true}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const newLineup = (extraData?.theory_craft?.custom_lineup || []).filter(id => id !== avatarId);
|
const newLineup = currentLineup.filter(id => id !== avatarId)
|
||||||
setExtraData({
|
setExtraData({
|
||||||
...extraData,
|
...extraData,
|
||||||
theory_craft: {
|
theory_craft: {
|
||||||
@@ -255,51 +316,56 @@ export default function ExtraSettingBar() {
|
|||||||
hp: extraData?.theory_craft?.hp ?? {},
|
hp: extraData?.theory_craft?.hp ?? {},
|
||||||
custom_lineup: newLineup
|
custom_lineup: newLineup
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
|
|
||||||
|
{!showSearchLineup && (
|
||||||
<button
|
<button
|
||||||
className="btn btn-outline btn-square border-dashed w-14 h-14 sm:w-16 sm:h-16 rounded-xl"
|
type="button"
|
||||||
onClick={(e) => {
|
className="btn btn-outline btn-square border-dashed border-white/20 hover:border-primary/50 hover:bg-primary/10 w-16 h-16 sm:w-20 sm:h-20 rounded-xl flex flex-col items-center justify-center gap-1 text-base-content/50 hover:text-primary transition-all"
|
||||||
e.stopPropagation();
|
onClick={() => setShowSearchLineup(true)}
|
||||||
setShowSearchLineup(pre => !pre);
|
title="Add Character"
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
+
|
<Plus className="w-5 h-5" />
|
||||||
|
<span className="text-[9px] uppercase font-bold tracking-wider">Add</span>
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Inline Character Selection Pool */}
|
||||||
{showSearchLineup && (
|
{showSearchLineup && (
|
||||||
<div
|
<div className="space-y-2.5 pt-2">
|
||||||
onClick={(e) => e.stopPropagation()}
|
<div className="relative">
|
||||||
className="mt-2 w-full z-50 bg-base-100 border border-base-content/15 rounded-2xl p-4 shadow-2xl space-y-3"
|
<Search className="w-3.5 h-3.5 absolute left-3 top-1/2 -translate-y-1/2 text-base-content/40" />
|
||||||
>
|
<input
|
||||||
<div className="flex justify-between items-center pb-2 border-b border-base-content/10">
|
type="search"
|
||||||
<span className="font-bold text-xs">{transI18n("selectedCharacters")}</span>
|
className="input input-sm input-bordered w-full rounded-xl bg-base-100 text-base-content border-white/10 pl-8 text-xs focus:border-primary"
|
||||||
<button className="btn btn-xs btn-circle btn-ghost" onClick={() => setShowSearchLineup(false)}>✕</button>
|
placeholder="Search character..."
|
||||||
|
value={lineupSearchTerm}
|
||||||
|
onChange={(e) => setLineupSearchTerm(e.target.value)}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap gap-2 max-h-60 overflow-y-auto p-1">
|
<div className="flex flex-wrap gap-2 max-h-56 overflow-y-auto pr-1">
|
||||||
{Object.values(mapAvatar).map((avatar) => {
|
{filteredAvatars.map((avatar) => {
|
||||||
const currentLineup = extraData?.theory_craft?.custom_lineup || [];
|
const isSelected = currentLineup.includes(avatar.ID.toString())
|
||||||
const isSelected = currentLineup.includes(avatar.ID.toString());
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SimpleAvatarCard
|
<SimpleAvatarCard
|
||||||
key={avatar.ID}
|
key={avatar.ID}
|
||||||
data={avatar}
|
data={avatar}
|
||||||
isSelected={isSelected}
|
isSelected={isSelected}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const idStr = avatar.ID.toString();
|
const idStr = avatar.ID.toString()
|
||||||
let newLineup = [...currentLineup];
|
let newLineup = [...currentLineup]
|
||||||
|
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
newLineup = newLineup.filter(id => id !== idStr);
|
newLineup = newLineup.filter(id => id !== idStr)
|
||||||
} else {
|
} else {
|
||||||
newLineup.push(idStr);
|
newLineup.push(idStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
setExtraData({
|
setExtraData({
|
||||||
@@ -311,10 +377,10 @@ export default function ExtraSettingBar() {
|
|||||||
hp: extraData?.theory_craft?.hp ?? {},
|
hp: extraData?.theory_craft?.hp ?? {},
|
||||||
custom_lineup: newLineup
|
custom_lineup: newLineup
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -322,35 +388,53 @@ export default function ExtraSettingBar() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</section>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* MULTIPATH CHAR */}
|
{/* MULTIPATH CHARACTER */}
|
||||||
<div className="p-4 sm:p-5 rounded-2xl bg-base-200/60 border border-white/10 shadow-lg space-y-4">
|
<section className="relative z-20 rounded-2xl bg-base-200/40 border border-white/10 shadow-xs backdrop-blur-sm transition-all duration-200">
|
||||||
<div className="flex items-center justify-between pb-2 border-b border-base-content/10">
|
<div className="flex items-center justify-between p-4 sm:p-5">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-xl bg-secondary/10 border border-secondary/20 text-secondary flex items-center justify-center shrink-0 shadow-inner">
|
||||||
|
<RouteIcon className="w-5 h-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<h3 className="text-sm font-bold uppercase tracking-wider text-primary">
|
<h3 className="text-sm font-bold tracking-tight text-base-content">
|
||||||
{transI18n("multipathCharacter")}
|
{transI18n("multipathCharacter")}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="tooltip tooltip-bottom tooltip-info" data-tip={transI18n("detailMultipathCharacter")}>
|
<div className="tooltip tooltip-bottom tooltip-info" data-tip={transI18n("detailMultipathCharacter")}>
|
||||||
<Info className="text-primary w-4 h-4 cursor-pointer" />
|
<Info className="text-primary/70 hover:text-primary w-3.5 h-3.5 cursor-pointer transition-colors" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-xs text-base-content/60 line-clamp-1 mt-0.5">
|
||||||
|
{transI18n("detailMultipathCharacter")}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2.5">
|
||||||
|
<span className={`text-xs font-semibold uppercase tracking-wider hidden sm:inline ${isEnableChangePath ? 'text-secondary' : 'text-base-content/40'}`}>
|
||||||
|
{isEnableChangePath ? 'Active' : 'Off'}
|
||||||
|
</span>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="toggle toggle-primary"
|
className="toggle toggle-secondary"
|
||||||
checked={isEnableChangePath}
|
checked={isEnableChangePath}
|
||||||
onChange={(e) => setIsEnableChangePath(e.target.checked)}
|
onChange={(e) => setIsEnableChangePath(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{isEnableChangePath && (
|
{isEnableChangePath && (
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 pt-1">
|
<div className="border-t border-white/5 bg-base-300/20 p-4 sm:p-5">
|
||||||
<div className="p-3.5 rounded-xl bg-base-100/60 border border-white/5 space-y-2">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<div className="flex items-center gap-2">
|
{/* Main Character Path */}
|
||||||
<User className="text-warning w-4 h-4" />
|
<div className="space-y-1.5">
|
||||||
<span className="text-xs font-semibold">{transI18n("mainPath")}</span>
|
<label className="flex items-center gap-2 text-xs font-semibold text-base-content/80">
|
||||||
</div>
|
<User className="text-warning w-3.5 h-3.5" />
|
||||||
|
<span>{transI18n("mainPath")}</span>
|
||||||
|
</label>
|
||||||
<SelectCustomImage
|
<SelectCustomImage
|
||||||
customSet={Object.values(mapAvatar).filter((it) => extraData?.multi_path?.multi_path_main?.includes(Number(it.ID))).map((it) => ({
|
customSet={Object.values(mapAvatar).filter((it) => extraData?.multi_path?.multi_path_main?.includes(Number(it.ID))).map((it) => ({
|
||||||
value: it.ID.toString(),
|
value: it.ID.toString(),
|
||||||
@@ -376,11 +460,12 @@ export default function ExtraSettingBar() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-3.5 rounded-xl bg-base-100/60 border border-white/5 space-y-2">
|
{/* March 7th Path */}
|
||||||
<div className="flex items-center gap-2">
|
<div className="space-y-1.5">
|
||||||
<BowArrow className="text-info w-4 h-4" />
|
<label className="flex items-center gap-2 text-xs font-semibold text-base-content/80">
|
||||||
<span className="text-xs font-semibold">{transI18n("march7Path")}</span>
|
<BowArrow className="text-info w-3.5 h-3.5" />
|
||||||
</div>
|
<span>{transI18n("march7Path")}</span>
|
||||||
|
</label>
|
||||||
<SelectCustomImage
|
<SelectCustomImage
|
||||||
customSet={Object.values(mapAvatar).filter((it) => extraData?.multi_path?.multi_path_march_7?.includes(Number(it.ID))).map((it) => ({
|
customSet={Object.values(mapAvatar).filter((it) => extraData?.multi_path?.multi_path_march_7?.includes(Number(it.ID))).map((it) => ({
|
||||||
value: it.ID.toString(),
|
value: it.ID.toString(),
|
||||||
@@ -406,31 +491,42 @@ export default function ExtraSettingBar() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
|
||||||
{/* CHALLENGE */}
|
{/* CHALLENGE SETTINGS */}
|
||||||
<div className="p-4 sm:p-5 rounded-2xl bg-base-200/60 border border-white/10 shadow-lg space-y-4">
|
<section className="relative z-10 rounded-2xl bg-base-200/40 border border-white/10 shadow-xs backdrop-blur-sm">
|
||||||
<div className="pb-2 border-b border-base-content/10">
|
<div className="p-4 sm:p-5 border-b border-white/5 flex items-center gap-3">
|
||||||
<h3 className="text-sm font-bold uppercase tracking-wider text-primary">
|
<div className="w-10 h-10 rounded-xl bg-error/10 border border-error/20 text-error flex items-center justify-center shrink-0 shadow-inner">
|
||||||
|
<Swords className="w-5 h-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-sm font-bold tracking-tight text-base-content">
|
||||||
{transI18n("challenge")}
|
{transI18n("challenge")}
|
||||||
</h3>
|
</h3>
|
||||||
|
<p className="text-xs text-base-content/60 line-clamp-1 mt-0.5">
|
||||||
|
Configure anomaly peak mode and node skip settings
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
<div className="p-4 sm:p-5">
|
||||||
<div className="p-3.5 rounded-xl bg-base-100/60 border border-white/5 space-y-2">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
|
{/* Anomaly Arbitration */}
|
||||||
|
<div className="space-y-1.5">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-2">
|
<label className="flex items-center gap-2 text-xs font-semibold text-base-content/80">
|
||||||
<Swords className="text-error w-4 h-4" />
|
<Swords className="text-error w-3.5 h-3.5" />
|
||||||
<span className="text-xs font-semibold">{transI18n("anomalyArbitration")}</span>
|
<span>{transI18n("anomalyArbitration")}</span>
|
||||||
</div>
|
</label>
|
||||||
<div className="tooltip tooltip-bottom tooltip-info" data-tip={transI18n("detailChallengePeak")}>
|
<div className="tooltip tooltip-bottom tooltip-info" data-tip={transI18n("detailChallengePeak")}>
|
||||||
<Info className="text-primary w-3.5 h-3.5 cursor-pointer" />
|
<Info className="text-primary/70 hover:text-primary w-3.5 h-3.5 cursor-pointer transition-colors" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<select
|
<select
|
||||||
value={extraData?.challenge?.challenge_peak_group_id || ""}
|
value={extraData?.challenge?.challenge_peak_group_id || ""}
|
||||||
className="select select-sm select-bordered w-full rounded-xl text-xs"
|
className="select select-sm select-bordered w-full rounded-xl bg-base-100 text-base-content border-white/15 focus:border-primary text-xs font-medium"
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setExtraData({
|
setExtraData({
|
||||||
...extraData,
|
...extraData,
|
||||||
@@ -444,26 +540,27 @@ export default function ExtraSettingBar() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
{Object.values(mapPeak).filter(event => extraData?.challenge?.challenge_peak_group_id_list?.includes(Number(event.ID))).map(event => (
|
{Object.values(mapPeak).filter(event => extraData?.challenge?.challenge_peak_group_id_list?.includes(Number(event.ID))).map(event => (
|
||||||
<option key={event.ID} value={event.ID}>
|
<option key={event.ID} value={event.ID} className="bg-base-100 text-base-content py-2">
|
||||||
{getLocaleName(locale, event.Name)} ({event.ID})
|
{getLocaleName(locale, event.Name)} ({event.ID})
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-3.5 rounded-xl bg-base-100/60 border border-white/5 space-y-2">
|
{/* Skip Node */}
|
||||||
|
<div className="space-y-1.5">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-2">
|
<label className="flex items-center gap-2 text-xs font-semibold text-base-content/80">
|
||||||
<SkipForward className="text-warning w-4 h-4" />
|
<SkipForward className="text-warning w-3.5 h-3.5" />
|
||||||
<span className="text-xs font-semibold">{transI18n("skipNode")}</span>
|
<span>{transI18n("skipNode")}</span>
|
||||||
</div>
|
</label>
|
||||||
<div className="tooltip tooltip-bottom tooltip-info" data-tip={transI18n("detailSkipNode")}>
|
<div className="tooltip tooltip-bottom tooltip-info" data-tip={transI18n("detailSkipNode")}>
|
||||||
<Info className="text-primary w-3.5 h-3.5 cursor-pointer" />
|
<Info className="text-primary/70 hover:text-primary w-3.5 h-3.5 cursor-pointer transition-colors" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<select
|
<select
|
||||||
value={extraData?.challenge?.skip_node || "0"}
|
value={extraData?.challenge?.skip_node || "0"}
|
||||||
className="select select-sm select-bordered w-full rounded-xl text-xs"
|
className="select select-sm select-bordered w-full rounded-xl bg-base-100 text-base-content border-white/15 focus:border-primary text-xs font-medium"
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setExtraData({
|
setExtraData({
|
||||||
...extraData,
|
...extraData,
|
||||||
@@ -476,33 +573,52 @@ export default function ExtraSettingBar() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<option value="0">{transI18n("disableSkip")}</option>
|
<option value="0" className="bg-base-100 text-base-content py-2">{transI18n("disableSkip")}</option>
|
||||||
<option value="1">{transI18n("skipNode1")}</option>
|
<option value="1" className="bg-base-100 text-base-content py-2">{transI18n("skipNode1")}</option>
|
||||||
<option value="2">{transI18n("skipNode2")}</option>
|
<option value="2" className="bg-base-100 text-base-content py-2">{transI18n("skipNode2")}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
{/* EXTRA FEATURES */}
|
{/* EXTRA FEATURES */}
|
||||||
<div className="p-4 sm:p-5 rounded-2xl bg-base-200/60 border border-white/10 shadow-lg space-y-4">
|
<section className="relative z-0 rounded-2xl bg-base-200/40 border border-white/10 shadow-xs backdrop-blur-sm">
|
||||||
<div className="pb-2 border-b border-base-content/10">
|
<div className="p-4 sm:p-5 border-b border-white/5 flex items-center gap-3">
|
||||||
<h3 className="text-sm font-bold uppercase tracking-wider text-primary">
|
<div className="w-10 h-10 rounded-xl bg-accent/10 border border-accent/20 text-accent flex items-center justify-center shrink-0 shadow-inner">
|
||||||
|
<Eye className="w-5 h-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-sm font-bold tracking-tight text-base-content">
|
||||||
{transI18n("extraFeatures")}
|
{transI18n("extraFeatures")}
|
||||||
</h3>
|
</h3>
|
||||||
|
<p className="text-xs text-base-content/60 line-clamp-1 mt-0.5">
|
||||||
|
UI display overrides and visual preferences
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
<div className="p-2 sm:p-3 divide-y divide-white/5">
|
||||||
|
{/* Hide UI Row */}
|
||||||
{extraData?.setting?.hide_ui !== undefined && (
|
{extraData?.setting?.hide_ui !== undefined && (
|
||||||
<div className="p-3.5 rounded-xl bg-base-100/60 border border-white/5 flex items-center justify-between">
|
<div className="flex items-center justify-between p-3 rounded-xl hover:bg-white/[0.03] transition-colors">
|
||||||
<div className="flex items-center gap-2.5">
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-8 h-8 rounded-lg bg-base-100/80 border border-white/10 flex items-center justify-center">
|
||||||
{extraData?.setting?.hide_ui
|
{extraData?.setting?.hide_ui
|
||||||
? <EyeOff className="text-warning w-4 h-4" />
|
? <EyeOff className="text-warning w-4 h-4" />
|
||||||
: <Eye className="text-success w-4 h-4" />
|
: <Eye className="text-success w-4 h-4" />
|
||||||
}
|
}
|
||||||
<span className="text-xs font-semibold">{transI18n("hideUI")}</span>
|
</div>
|
||||||
<div className="tooltip tooltip-bottom tooltip-info" data-tip={transI18n("detailHiddenUi")}>
|
<div>
|
||||||
<Info className="text-primary w-3.5 h-3.5 cursor-pointer" />
|
<div className="flex items-center gap-1.5">
|
||||||
|
<span className="text-xs sm:text-sm font-semibold text-base-content">{transI18n("hideUI")}</span>
|
||||||
|
<div className="tooltip tooltip-right tooltip-info" data-tip={transI18n("detailHiddenUi")}>
|
||||||
|
<Info className="text-primary/70 hover:text-primary w-3 h-3 cursor-pointer" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="text-[11px] text-base-content/50 hidden sm:block">
|
||||||
|
{transI18n("detailHiddenUi")}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -525,13 +641,23 @@ export default function ExtraSettingBar() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Disable Censorship Row */}
|
||||||
{extraData?.setting?.censorship !== undefined && (
|
{extraData?.setting?.censorship !== undefined && (
|
||||||
<div className="p-3.5 rounded-xl bg-base-100/60 border border-white/5 flex items-center justify-between">
|
<div className="flex items-center justify-between p-3 rounded-xl hover:bg-white/[0.03] transition-colors">
|
||||||
<div className="flex items-center gap-2.5">
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-8 h-8 rounded-lg bg-base-100/80 border border-white/10 flex items-center justify-center">
|
||||||
<ShieldBan className="text-error w-4 h-4" />
|
<ShieldBan className="text-error w-4 h-4" />
|
||||||
<span className="text-xs font-semibold">{transI18n("disableCensorship")}</span>
|
</div>
|
||||||
<div className="tooltip tooltip-bottom tooltip-info" data-tip={transI18n("detailDisableCensorship")}>
|
<div>
|
||||||
<Info className="text-primary w-3.5 h-3.5 cursor-pointer" />
|
<div className="flex items-center gap-1.5">
|
||||||
|
<span className="text-xs sm:text-sm font-semibold text-base-content">{transI18n("disableCensorship")}</span>
|
||||||
|
<div className="tooltip tooltip-right tooltip-info" data-tip={transI18n("detailDisableCensorship")}>
|
||||||
|
<Info className="text-primary/70 hover:text-primary w-3 h-3 cursor-pointer" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="text-[11px] text-base-content/50 hidden sm:block">
|
||||||
|
{transI18n("detailDisableCensorship")}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -554,25 +680,60 @@ export default function ExtraSettingBar() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* LUA SCRIPTING */}
|
||||||
|
<section className="relative rounded-2xl bg-base-200/40 border border-white/10 shadow-xs backdrop-blur-sm transition-all duration-200">
|
||||||
|
<div className="flex items-center justify-between p-4 sm:p-5">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-xl bg-amber-400/10 border border-amber-400/20 text-amber-400 flex items-center justify-center shrink-0 shadow-inner">
|
||||||
|
<CupSoda className="w-5 h-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-sm font-bold tracking-tight text-base-content">
|
||||||
|
Lua Scripting
|
||||||
|
</h3>
|
||||||
|
<p className="text-xs text-base-content/60 line-clamp-1 mt-0.5">
|
||||||
|
Inject custom Lua runtime scripts and behaviors
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* LUA EDITOR */}
|
<div className="flex items-center gap-2.5">
|
||||||
<div className="p-4 sm:p-5 rounded-2xl bg-base-200/60 border border-white/10 shadow-lg space-y-4">
|
<span className={`text-xs font-semibold uppercase tracking-wider hidden sm:inline ${isEnableLua ? 'text-amber-400' : 'text-base-content/40'}`}>
|
||||||
<div className="flex items-center justify-between pb-2 border-b border-base-content/10">
|
{isEnableLua ? 'Active' : 'Off'}
|
||||||
<div className="flex items-center gap-2">
|
</span>
|
||||||
<CupSoda className="text-primary w-4 h-4" />
|
|
||||||
<h3 className="text-sm font-bold uppercase tracking-wider text-primary">Lua Scripting</h3>
|
|
||||||
</div>
|
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="toggle toggle-primary"
|
className="toggle toggle-warning"
|
||||||
checked={isEnableLua}
|
checked={isEnableLua}
|
||||||
onChange={(e) => setIsEnableLua(e.target.checked)}
|
onChange={(e) => setIsEnableLua(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{isEnableLua && (
|
{isEnableLua && (
|
||||||
<div className="rounded-2xl overflow-hidden border border-white/10 shadow-inner">
|
<div className="border-t border-white/5 bg-[#0d0e15] overflow-hidden">
|
||||||
|
{/* Terminal Window Header Bar */}
|
||||||
|
<div className="flex items-center justify-between px-4 py-2.5 bg-[#141622] border-b border-white/5">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<div className="w-2.5 h-2.5 rounded-full bg-rose-500/70"></div>
|
||||||
|
<div className="w-2.5 h-2.5 rounded-full bg-amber-500/70"></div>
|
||||||
|
<div className="w-2.5 h-2.5 rounded-full bg-emerald-500/70"></div>
|
||||||
|
</div>
|
||||||
|
<div className="h-3.5 w-px bg-white/10 mx-1.5"></div>
|
||||||
|
<div className="flex items-center gap-1.5 text-xs text-base-content/70 font-mono">
|
||||||
|
<Code className="w-3.5 h-3.5 text-amber-400" />
|
||||||
|
<span>script.lua</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span className="text-[10px] uppercase font-mono px-2 py-0.5 rounded-md bg-white/5 text-base-content/50 border border-white/5">
|
||||||
|
LUA 5.4
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Code Editor */}
|
||||||
<Editor
|
<Editor
|
||||||
value={extraData?.lua || ""}
|
value={extraData?.lua || ""}
|
||||||
onValueChange={(code) =>
|
onValueChange={(code) =>
|
||||||
@@ -584,15 +745,15 @@ export default function ExtraSettingBar() {
|
|||||||
highlight={(code) => Prism.highlight(code, Prism.languages.lua, "lua")}
|
highlight={(code) => Prism.highlight(code, Prism.languages.lua, "lua")}
|
||||||
padding={16}
|
padding={16}
|
||||||
textareaClassName="outline-none font-mono"
|
textareaClassName="outline-none font-mono"
|
||||||
className="text-xs font-mono min-h-60 bg-[#161822] text-white"
|
className="text-xs font-mono min-h-60 text-slate-100 bg-[#0d0e15]"
|
||||||
style={{
|
style={{
|
||||||
background: "#161822",
|
background: "#0d0e15",
|
||||||
color: "#e2e8f0",
|
color: "#e2e8f0",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -636,7 +636,15 @@ export default function Header() {
|
|||||||
{/* Modals */}
|
{/* Modals */}
|
||||||
{modalConfigs?.map(({ id, title, onClose, content }) => (
|
{modalConfigs?.map(({ id, title, onClose, content }) => (
|
||||||
<dialog key={id} id={id} className="modal">
|
<dialog key={id} id={id} className="modal">
|
||||||
<div className={`modal-box w-11/12 max-w-[92vw] sm:max-w-[88vw] ${id === 'monster_modal' ? 'h-[85vh]' : 'max-h-[90vh]'} max-h-[90vh] flex flex-col bg-base-100 text-base-content border border-base-content/10 shadow-2xl rounded-2xl p-0 overflow-hidden`}>
|
<div className={`modal-box w-11/12 ${
|
||||||
|
id === 'monster_modal'
|
||||||
|
? 'max-w-[92vw] sm:max-w-[88vw] h-[85vh]'
|
||||||
|
: id === 'extra_modal'
|
||||||
|
? 'max-w-3xl lg:max-w-4xl max-h-[88vh]'
|
||||||
|
: id === 'connect_modal'
|
||||||
|
? 'max-w-lg max-h-[85vh]'
|
||||||
|
: 'max-w-2xl max-h-[90vh]'
|
||||||
|
} max-h-[90vh] flex flex-col bg-base-100 text-base-content border border-base-content/10 shadow-2xl rounded-2xl p-0 overflow-hidden`}>
|
||||||
{/* Modal Header */}
|
{/* Modal Header */}
|
||||||
<div className="sticky top-0 z-20 flex items-center justify-between px-6 py-4 border-b border-base-content/10 bg-base-100 shrink-0">
|
<div className="sticky top-0 z-20 flex items-center justify-between px-6 py-4 border-b border-base-content/10 bg-base-100 shrink-0">
|
||||||
<h3 className="font-bold text-xl tracking-tight bg-clip-text text-transparent bg-linear-to-r from-primary via-accent to-secondary">
|
<h3 className="font-bold text-xl tracking-tight bg-clip-text text-transparent bg-linear-to-r from-primary via-accent to-secondary">
|
||||||
|
|||||||
Reference in New Issue
Block a user