mirror of
https://github.com/MadeBaruna/paimon-moe.git
synced 2025-03-13 11:18:28 +01:00
Add character builds
This commit is contained in:
parent
635b8a13fb
commit
ddc9a22fc8
7 changed files with 3754 additions and 32 deletions
3209
src/data/build.js
Normal file
3209
src/data/build.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -110,7 +110,8 @@
|
|||
"sortBy": "Sort by...",
|
||||
"talentBook": "Talent Book",
|
||||
"ascensionMaterial": "Ascension Materials",
|
||||
"talentStats": "Talent Stats"
|
||||
"talentStats": "Talent Stats",
|
||||
"build": "Build"
|
||||
},
|
||||
"wish": {
|
||||
"title": "Wish Counter",
|
||||
|
@ -715,7 +716,8 @@
|
|||
"ascensionMaterial": "Ascension Materials",
|
||||
"asc": "ASC",
|
||||
"lvl": "LVL",
|
||||
"baseAtk": "Base ATK"
|
||||
"baseAtk": "Base ATK",
|
||||
"recommendedCharacter": "Recommended Characters"
|
||||
},
|
||||
"artifact": {
|
||||
"title": "Artifact List",
|
||||
|
@ -725,6 +727,7 @@
|
|||
"bonus4": "4 Set Bonus",
|
||||
"domain": "Domain",
|
||||
"artifact": "Artifact",
|
||||
"setPiece": "{piece} Set Bonus"
|
||||
"setPiece": "{piece} Set Bonus",
|
||||
"recommendedCharacter": "Recommended Characters {piece} Set"
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
"timeline": "Timeline",
|
||||
"furnishing": "Furnitur",
|
||||
"weapons": "Senjata",
|
||||
"artifacts": "Artifak",
|
||||
"settings": "Pengaturan",
|
||||
"donate": "Donasi"
|
||||
},
|
||||
|
@ -20,6 +21,9 @@
|
|||
"message": "Your best Genshin Impact companion! Membantu kamu merencanakan apa yang harus di farm dengan kalkulator ascension, juga catat progress mu dengan todo dan wish counter.",
|
||||
"visitor": "{count} pengunjung dalam 7 hari terakhir",
|
||||
"banner": {
|
||||
"featured": [
|
||||
"Eula"
|
||||
],
|
||||
"summoned": "Pulang",
|
||||
"percentage": "dari semua {rarity}",
|
||||
"avg": "Pity rata-rata",
|
||||
|
@ -51,7 +55,7 @@
|
|||
},
|
||||
"items": {
|
||||
"title": "Bisa di Farm Hari Ini",
|
||||
"detail": "Items",
|
||||
"detail": "Item",
|
||||
"sunday": "Minggu bisa farm semua item 😁"
|
||||
},
|
||||
"calculator": {
|
||||
|
@ -62,6 +66,10 @@
|
|||
"title": "Follow my Twitter, akan post tentang apa yang lagi di develop dan update terbaru tentang paimon.moe!",
|
||||
"detail": "Follow Twitter"
|
||||
},
|
||||
"achievement": {
|
||||
"title": "🏆 Lihat dan tandai daftar achievement yang sudah kamu dapat disini",
|
||||
"detail": "Achievement"
|
||||
},
|
||||
"furnishing": {
|
||||
"title": "Cek furnitur apa saja yang kamu perlukan untuk menyelesaikan suatu set. Dan kamu juga bisa melihat beban masing-masing furnitur.",
|
||||
"detail": "Furnitur"
|
||||
|
@ -74,9 +82,36 @@
|
|||
"element": "Element",
|
||||
"rarity": "Rarity",
|
||||
"weapon": "Senjata",
|
||||
"talents": "Talent",
|
||||
"passiveTalents": "Talent Pasif",
|
||||
"constellations": "Konstelasi",
|
||||
"const": "Const",
|
||||
"asc": "ASC",
|
||||
"lvl": "LVL",
|
||||
"hp": "HP",
|
||||
"atk": "ATK",
|
||||
"def": "DEF"
|
||||
"def": "DEF",
|
||||
"hpPercent": "HP%",
|
||||
"atkPercent": "ATK%",
|
||||
"defPercent": "DEF%",
|
||||
"critRate": "CRiT Rate",
|
||||
"critDamage": "CRIT DMG",
|
||||
"em": "Elemental Mastery",
|
||||
"er": "Energy Recharge",
|
||||
"healingBonus": "Healing Bonus",
|
||||
"pyroDamageBonus": "Pyro DMG Bonus",
|
||||
"hydroDamageBonus": "Hydro DMG Bonus",
|
||||
"dendroDamageBonus": "Dendro DMG Bonus",
|
||||
"electroDamageBonus": "Electro DMG Bonus",
|
||||
"cryoDamageBonus": "Cryo DMG Bonus",
|
||||
"anemoDamageBonus": "Anemo DMG Bonus",
|
||||
"physicalDamageBonus": "Physical DMG Bonus",
|
||||
"geoDamageBonus": "Geo DMG Bonus",
|
||||
"sortBy": "Urutkan...",
|
||||
"talentBook": "Buku Talent",
|
||||
"ascensionMaterial": "Material Ascension",
|
||||
"talentStats": "Stat Talent",
|
||||
"build": "Build"
|
||||
},
|
||||
"wish": {
|
||||
"title": "Wish Counter",
|
||||
|
@ -116,10 +151,10 @@
|
|||
"parsing": "Membaca...",
|
||||
"save": "Simpan",
|
||||
"cancel": "Batal",
|
||||
"canceling": "Membatalkan...",
|
||||
"cancelling": "Membatalkan...",
|
||||
"importNewWishOnly": "Import wish baru saja",
|
||||
"importNewWishUncheck": "Hapus centang hanya jika kamu ingin mengimport ulang semua riwayat history mu",
|
||||
"import": "Import",
|
||||
"import": "Impor",
|
||||
"close": "Tutup",
|
||||
"invalidLink": "Link invalid, silahkan dicek kembali",
|
||||
"errorApi": "Error code dikembalikan dari API MiHoYo, coba lagi nanti!",
|
||||
|
@ -154,7 +189,7 @@
|
|||
"q5": "Apakah kamu menyimpan key sementara ku atau riwayat history ku?",
|
||||
"a5": [
|
||||
"Paimon.moe tidak menyimpan key mu, dan menggunakan HTTPS untuk mengirim link mu ke proxy cors sehingga bisa digunakan. Paimon.moe akan menyimpan pity 4*, pity 5*, dan informasi wish 5* jika kamu mensubmit wish mu ke perhitungan pity global paimon.moe (tidak ada data pribadi yang disimpan! harap cek",
|
||||
"Privacy Policy",
|
||||
"Kebijakan Privasi",
|
||||
"untuk info lebih lanjut). Kamu bisa tidak mencentang submit pity untuk tidak mengirim data wish. Kemudian semua data riwayat wish mu disimpan pada device masing-masing (atau google drive mu jika kamu menyalakan sync di setting).",
|
||||
"Jika kamu tidak ingin link feedback mu kemana-mana, kamu bisa menggunakan script importer yang akan memproses riwayat history secara lokal di pc mu (opsi PC Local) "
|
||||
],
|
||||
|
@ -312,7 +347,8 @@
|
|||
"totalThisBanner": "Total pull di banner ini",
|
||||
"worth": "Setara dengan",
|
||||
"loading": "Loading... (Kalau tidak selesai-selesai, ganti server di halaman settings)",
|
||||
"guaranteed": "5★ selanjutnya pasti karakter atau senjata promotional"
|
||||
"guaranteed": "5★ selanjutnya pasti karakter atau senjata promotional",
|
||||
"unknown_3_star": "Unknown"
|
||||
},
|
||||
"tally": {
|
||||
"title": "Perhitungan Pity Wish",
|
||||
|
@ -333,13 +369,16 @@
|
|||
"error": "Data belum tersedia 😞",
|
||||
"pity": "Pity",
|
||||
"median": "5★ Median",
|
||||
"user": "Total User"
|
||||
"user": "Total User",
|
||||
"detail": "Detail"
|
||||
}
|
||||
},
|
||||
"calculator": {
|
||||
"titleWeapon": "Kalkulator Senjata",
|
||||
"titleCharacter": "Kalkulator Karakter",
|
||||
"titleResin": "Kalkulator Resin",
|
||||
"titleFriendship": "Kalkulator Exp Friendship",
|
||||
"titleFate": "Kalkulator Harga Fate",
|
||||
"goto": "Ke {where}",
|
||||
"howToUse": "Cara Penggunaan",
|
||||
"guide": {
|
||||
|
@ -389,7 +428,12 @@
|
|||
"mora": "Mora (kurang lebih ±40)",
|
||||
"expWasted": "EXP Terbuang",
|
||||
"addToTodo": "Tambah ke Todo List",
|
||||
"addedToTodo": "Sudah ditambahkan ke Todo List"
|
||||
"addedToTodo": "Sudah ditambahkan ke Todo List",
|
||||
"talent": [
|
||||
"Attack",
|
||||
"Skill",
|
||||
"Burst"
|
||||
]
|
||||
},
|
||||
"expTable": {
|
||||
"level": "Level",
|
||||
|
@ -433,7 +477,7 @@
|
|||
"genesis": "Genesis",
|
||||
"first": "Bonus2x",
|
||||
"total": "Total",
|
||||
"price": "Price",
|
||||
"price": "Harga",
|
||||
"totalGenesis": "Total Genesis",
|
||||
"totalPrice": "Total Harga",
|
||||
"calculate": "Hitung berapa banyak Genesis Crystal yang bisa didapatkan dengan {currency}{value}",
|
||||
|
@ -467,7 +511,7 @@
|
|||
},
|
||||
"todo": {
|
||||
"title": "Todo List",
|
||||
"summary": "Summary",
|
||||
"summary": "Rangkuman",
|
||||
"empty": [
|
||||
"Belum ada yang ditambahkan 😀",
|
||||
"Tambahkan todo dari halaman Items atau dari Kalkulator!"
|
||||
|
@ -512,7 +556,7 @@
|
|||
"lastSync": "Sync Terakhir:",
|
||||
"feedback": "Jika kamu menemukan bug, data yang salah, atau ada feedback, kamu bisa chat di",
|
||||
"or": "atau",
|
||||
"thanks": "Thanks😁!",
|
||||
"thanks": "Terima Kasih!",
|
||||
"modal": {
|
||||
"notice": "Semua todo dan riwayat wish akan dihapus",
|
||||
"backup": "Kamu bisa backup dulu riwayat history dengan mengexport nya ke file excel!",
|
||||
|
@ -522,7 +566,7 @@
|
|||
}
|
||||
},
|
||||
"privacypolicy": {
|
||||
"title": "Privacy Policy",
|
||||
"title": "Kebijakan Privasi",
|
||||
"subtitle": "Apa yang paimon.moe kumpulkan dan kegunaannya",
|
||||
"collect": [
|
||||
{
|
||||
|
@ -592,6 +636,7 @@
|
|||
"blocked": "Notifikasi di blokir, notifikasi tidak akan bisa terkirim! Silahkan nyalakan notifikasi di browser mu.",
|
||||
"desktop": "Browser dekstop tidak bisa menerima notifikasi jika browser tidak berjalan!",
|
||||
"early": "Notifikasi mungkin akan muncul lebih awal (sekitar 1-10 menit) karena limitasi dalam pengiriman notifikasi.",
|
||||
"allowNotification": "Harap izinkan permintaan notifikasi yang muncul!",
|
||||
"transformer": "Reminder Parametric Transformer",
|
||||
"last": "Masukkan kapan kamu terakhir menggunakan Parametric Transformer",
|
||||
"lastHoyolab": "Masukkan jam berapa kamu ingin diingatkan untuk daily check-in nya",
|
||||
|
@ -620,7 +665,7 @@
|
|||
"ratio": "Rasio",
|
||||
"using": "Jumlah",
|
||||
"interior": "Interior",
|
||||
"exterior": "Exterior",
|
||||
"exterior": "Eksterior",
|
||||
"info": [
|
||||
"Ini menunjukkan berapa beban yang bisa ditampung dalam pulau. Masing-masing furnitur mempunyai nilai beban yang tersembunyi yang bisa dilihat di bawah.",
|
||||
"(Beban maximum belum dikonfirmasi!)"
|
||||
|
@ -630,9 +675,9 @@
|
|||
"exteriorNum": "Area {number}",
|
||||
"corridor": "Koridor",
|
||||
"inventoryButton": "Inventory",
|
||||
"listButton": "List",
|
||||
"listButton": "Daftar",
|
||||
"inventory": {
|
||||
"title": "Furnishing Inventory",
|
||||
"title": "Inventory Furnitur",
|
||||
"subtitle": "Beberapa kategori special seperti dinding tidak ditampilkan",
|
||||
"all": "Semua",
|
||||
"openSets": "Buka Set"
|
||||
|
@ -646,5 +691,43 @@
|
|||
"available": "Tersedia",
|
||||
"used": "Digunakan di set lain"
|
||||
}
|
||||
},
|
||||
"weapon": {
|
||||
"title": "Daftar Senjata",
|
||||
"subtitle": "Stat adalah pada level maksimum",
|
||||
"name": "Nama",
|
||||
"type": "Tipe",
|
||||
"rarity": "Rarity",
|
||||
"atk": "ATK",
|
||||
"secondary": "Secondary",
|
||||
"critRate": "CRIT Rate",
|
||||
"critDamage": "CRIT DMG",
|
||||
"em": "Elemental Mastery",
|
||||
"er": "Energy Recharge",
|
||||
"atkPercent": "ATK",
|
||||
"hpPercent": "HP",
|
||||
"defPercent": "DEF",
|
||||
"physicalDamage": "Physical DMG Bonus",
|
||||
"bow": "Bow",
|
||||
"polearm": "Polearm",
|
||||
"sword": "Sword",
|
||||
"catalyst": "Catalyst",
|
||||
"claymore": "Claymore",
|
||||
"ascensionMaterial": "Material Ascension",
|
||||
"asc": "ASC",
|
||||
"lvl": "LVL",
|
||||
"baseAtk": "Base ATK",
|
||||
"recommendedCharacter": "Karakter Rekomendasi"
|
||||
},
|
||||
"artifact": {
|
||||
"title": "Daftar Artifak",
|
||||
"name": "Nama",
|
||||
"maxRarity": "Max★",
|
||||
"bonus2": "Bonus 2 Set",
|
||||
"bonus4": "Bonus 4 Set",
|
||||
"domain": "Domain",
|
||||
"artifact": "Artifak",
|
||||
"setPiece": "Bonus {piece} Set",
|
||||
"recommendedCharacter": "Rekomendasi Karakter {piece} Set"
|
||||
}
|
||||
}
|
|
@ -1,10 +1,69 @@
|
|||
<script context="module">
|
||||
import data from '../../data/artifacts/en.json';
|
||||
import { builds } from '../../data/build';
|
||||
|
||||
function getCharacter(artifactId) {
|
||||
const collection2 = {};
|
||||
const collection4 = {};
|
||||
const chars = Object.entries(builds);
|
||||
for (const [charId, char] of chars) {
|
||||
const roles = Object.entries(char.roles);
|
||||
for (const [roleName, role] of roles) {
|
||||
if (!role.recommended) continue;
|
||||
|
||||
let found2 = false;
|
||||
let found4 = false;
|
||||
for (const artifact of role.artifacts) {
|
||||
if (
|
||||
artifact.find((e) => {
|
||||
if (e === '+18%_atk_set') {
|
||||
return ['gladiators_finale', 'shimenawas_reminiscence'].includes(artifactId);
|
||||
}
|
||||
|
||||
return e === artifactId;
|
||||
})
|
||||
) {
|
||||
if (artifact.length === 1) found4 = true;
|
||||
else found2 = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (found2) {
|
||||
if (collection2[charId] === undefined) {
|
||||
collection2[charId] = {
|
||||
id: charId,
|
||||
roles: [],
|
||||
};
|
||||
}
|
||||
|
||||
collection2[charId].roles.push(roleName);
|
||||
}
|
||||
|
||||
if (found4) {
|
||||
if (collection4[charId] === undefined) {
|
||||
collection4[charId] = {
|
||||
id: charId,
|
||||
roles: [],
|
||||
};
|
||||
}
|
||||
|
||||
collection4[charId].roles.push(roleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
two: Object.values(collection2).sort((a, b) => a.id.localeCompare(b.id)),
|
||||
four: Object.values(collection4).sort((a, b) => a.id.localeCompare(b.id)),
|
||||
};
|
||||
}
|
||||
|
||||
export async function preload(page) {
|
||||
const { id } = page.params;
|
||||
const artifact = data[id];
|
||||
const recommendedCharacter = getCharacter(id);
|
||||
|
||||
return { id, artifact };
|
||||
return { id, artifact, recommendedCharacter };
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -14,7 +73,7 @@
|
|||
import { locale, t } from 'svelte-i18n';
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
import { domains } from '../../data/domain.js';
|
||||
import Button from '../../components/Button.svelte';
|
||||
import { characters } from '../../data/characters';
|
||||
|
||||
const rarityList = {
|
||||
1: 'text-white',
|
||||
|
@ -26,6 +85,8 @@
|
|||
|
||||
export let id;
|
||||
export let artifact;
|
||||
export let recommendedCharacter;
|
||||
console.log(recommendedCharacter);
|
||||
let images = [];
|
||||
|
||||
async function changeLocale(locale) {
|
||||
|
@ -87,5 +148,57 @@
|
|||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
{#if recommendedCharacter.two.length > 0}
|
||||
<div class="mt-6 max-w-screen-lg">
|
||||
<h3 class="font-display font-bold text-2xl text-white px-4">
|
||||
{$t('artifact.recommendedCharacter', { values: { piece: 2 } })}
|
||||
</h3>
|
||||
<div class="flex flex-wrap px-4 -mx-1 -mb-2">
|
||||
{#each recommendedCharacter.two as char}
|
||||
<a
|
||||
class="flex items-center bg-background hover:bg-item rounded-xl px-2 py-1 mb-2 mx-1"
|
||||
href="/characters/{char.id}"
|
||||
>
|
||||
<img
|
||||
src="/images/characters/{char.id}.png"
|
||||
alt={characters[char.id].name}
|
||||
class="w-12 h-12 mr-2 rounded-full"
|
||||
/>
|
||||
<div class="-mx-1">
|
||||
{#each char.roles as role}
|
||||
<p class="text-white mx-1">{role}</p>
|
||||
{/each}
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if recommendedCharacter.four.length > 0}
|
||||
<div class="mt-4 max-w-screen-lg">
|
||||
<h3 class="font-display font-bold text-2xl text-white px-4">
|
||||
{$t('artifact.recommendedCharacter', { values: { piece: 4 } })}
|
||||
</h3>
|
||||
<div class="flex flex-wrap px-4 -mx-1 -mb-2">
|
||||
{#each recommendedCharacter.four as char}
|
||||
<a
|
||||
class="flex items-center bg-background hover:bg-item rounded-xl px-2 py-1 mb-2 mx-1"
|
||||
href="/characters/{char.id}"
|
||||
>
|
||||
<img
|
||||
src="/images/characters/{char.id}.png"
|
||||
alt={characters[char.id].name}
|
||||
class="w-12 h-12 mr-2 rounded-full"
|
||||
/>
|
||||
<div class="-mx-1">
|
||||
{#each char.roles as role}
|
||||
<p class="text-white mx-1">{role}</p>
|
||||
{/each}
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
<script context="module">
|
||||
import { builds as buildsJson } from '../../data/build';
|
||||
|
||||
export async function preload(page) {
|
||||
const { id } = page.params;
|
||||
const data = await import(`../../data/characterData/${id}.json`);
|
||||
const buildData = buildsJson[id];
|
||||
|
||||
return { id, data };
|
||||
return { id, data, buildData };
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export let id;
|
||||
export let data;
|
||||
export let buildData;
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { mdiCircle, mdiContentSave, mdiMinus, mdiPencil, mdiPlus, mdiStar } from '@mdi/js';
|
||||
import { mdiChevronRight, mdiCircle, mdiClose, mdiContentSave, mdiMinus, mdiPencil, mdiPlus, mdiStar } from '@mdi/js';
|
||||
import { goto } from '@sapper/app';
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
import Button from '../../components/Button.svelte';
|
||||
import { getAccountPrefix } from '../../stores/account';
|
||||
|
@ -23,8 +28,23 @@
|
|||
|
||||
import SkillCard from './_skillCard.svelte';
|
||||
import PassiveSkillCard from './_passiveSkillCard.svelte';
|
||||
import { weaponList } from '../../data/weaponList';
|
||||
import artifacts from '../../data/artifacts/en.json';
|
||||
|
||||
const rarityColor = {
|
||||
1: 'text-white',
|
||||
2: 'text-green-400',
|
||||
3: 'text-primary',
|
||||
4: 'text-rare-from',
|
||||
5: 'text-legendary-from',
|
||||
};
|
||||
|
||||
let constellationDiv;
|
||||
let talentDiv;
|
||||
const builds = Object.entries(buildData.roles)
|
||||
.sort((a, b) => b[1].recommended - a[1].recommended)
|
||||
.map((e) => ({ name: e[0], build: e[1] }));
|
||||
let currentBuild = 0;
|
||||
|
||||
const defaultChars = {
|
||||
amber: {
|
||||
|
@ -131,11 +151,25 @@
|
|||
view.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
|
||||
function selectBuild(index) {
|
||||
currentBuild = index;
|
||||
window.location.hash = builds[index].name.replace(/[ /]/g, '_').toLowerCase();
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
const buildHash = window.location.hash.substring(1);
|
||||
console.log(buildHash);
|
||||
const foundBuild = builds.findIndex((e) => e.name.replace(/[ /]/g, '_').toLowerCase() === buildHash);
|
||||
if (foundBuild > -1) {
|
||||
currentBuild = foundBuild;
|
||||
}
|
||||
|
||||
await getConstellationCount();
|
||||
});
|
||||
|
||||
$: constellationCountTotal = constellationCount + manualCount;
|
||||
$: buildName = builds[currentBuild].name;
|
||||
$: build = builds[currentBuild].build;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -312,13 +346,184 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button className="mt-4 mx-4 md:mx-8" on:click={() => scrollToView(constellationDiv)}>
|
||||
{$t('characters.constellations')}
|
||||
</Button>
|
||||
<div class="flex mt-4 mx-4 md:mx-8">
|
||||
<Button className="mr-4" on:click={() => scrollToView(talentDiv)}>
|
||||
{$t('characters.talents')}
|
||||
</Button>
|
||||
<Button on:click={() => scrollToView(constellationDiv)}>
|
||||
{$t('characters.constellations')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col mt-4 text-white px-4 md:px-8">
|
||||
<p class="font-black font-display text-2xl mt-4">{$t('characters.talents')}</p>
|
||||
{#if builds.length > 1}
|
||||
<div class="flex mt-4 items-center">
|
||||
{#each builds as item, i}
|
||||
<button class="pill mr-2 {currentBuild === i ? 'active' : ''}" on:click={() => selectBuild(i)}>
|
||||
{item.name}
|
||||
{item.build.recommended ? '👍' : ''}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="p-4 mt-2 rounded-xl bg-item flex flex-col">
|
||||
<h3 class="font-black font-display text-xl">
|
||||
{buildName}
|
||||
{$t('characters.build')}
|
||||
{build.recommended ? '👍' : ''}
|
||||
</h3>
|
||||
<p class="whitespace-pre-wrap text-gray-200">{build.note}</p>
|
||||
<div class="flex mt-2 -mx-4 flex-wrap">
|
||||
<div class="mx-4 mt-4">
|
||||
<h4 class="font-black font-display text-lg">MAIN STATS</h4>
|
||||
<div class="flex items-center">
|
||||
<div class="px-2 py-1 mr-3 bg-background rounded-md w-32">
|
||||
<img class="w-8 h-8 inline mr-1" src="/images/artifacts/adventurer_sands.png" alt="SANDS" />
|
||||
<span class="font-semibold">SANDS</span>
|
||||
</div>
|
||||
<p>{build.mainStats.sands}</p>
|
||||
</div>
|
||||
<div class="flex items-center mt-1">
|
||||
<div class="px-2 py-1 mr-3 bg-background rounded-md w-32">
|
||||
<img class="w-8 h-8 inline mr-1" src="/images/artifacts/adventurer_goblet.png" alt="GOBLET" />
|
||||
<span class="font-semibold">GOBLET</span>
|
||||
</div>
|
||||
<p>{build.mainStats.goblet}</p>
|
||||
</div>
|
||||
<div class="flex items-center mt-1">
|
||||
<div class="px-2 py-1 mr-3 bg-background rounded-md w-32">
|
||||
<img class="w-8 h-8 inline mr-1" src="/images/artifacts/adventurer_circlet.png" alt="CIRCLET" />
|
||||
<span class="font-semibold">CIRCLET</span>
|
||||
</div>
|
||||
<p>{build.mainStats.circlet}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 mx-4">
|
||||
<h4 class="font-black font-display text-lg">SUB STATS</h4>
|
||||
<div class="decimal-list">
|
||||
{#each build.subStats as stat, i}
|
||||
<p><span class="font-semibold w-4 inline-block">{i + 1}.</span> {stat}</p>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 mx-4">
|
||||
<h4 class="font-black font-display text-lg">TALENT PRIORITY</h4>
|
||||
<div class="flex items-center">
|
||||
{#each build.talent as talent, i}
|
||||
<p class="mr-1">{talent}</p>
|
||||
{#if i !== build.talent.length - 1}
|
||||
<Icon className="mr-1" path={mdiChevronRight} />
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex -mx-4 flex-wrap">
|
||||
<div class="mt-4 mx-4 -mb-1">
|
||||
<h4 class="font-black font-display text-lg">WEAPONS</h4>
|
||||
{#each build.weapons as weapon, i}
|
||||
<a class="flex mb-1" href="/weapons/{weapon.id}">
|
||||
<div class="flex items-center justify-center bg-background rounded-md p-1 mr-1">
|
||||
<p class=" w-6 text-center">{i + 1}</p>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center justify-center bg-background rounded-md p-1 mr-1 {rarityColor[
|
||||
weaponList[weapon.id].rarity
|
||||
]}"
|
||||
>
|
||||
<Icon path={mdiStar} size={0.8} />
|
||||
</div>
|
||||
<p class="bg-background rounded-md py-1 pl-1 pr-2 flex items-center">
|
||||
<img class="h-8 mr-2" src="/images/weapons/{weapon.id}.png" alt={weaponList[weapon.id].name} />
|
||||
<span>{weaponList[weapon.id].name}</span>
|
||||
{#if weapon.refine}
|
||||
<span class="ml-2 bg-blue-300 rounded-md px-1 text-sm text-gray-900">R{weapon.refine.join('-')}</span>
|
||||
{/if}
|
||||
{#if weapon.stack}
|
||||
<span class="ml-2 bg-orange-300 rounded-md px-1 text-sm text-gray-900">S{weapon.stack}</span>
|
||||
{/if}
|
||||
</p>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="mt-4 mx-4 -mb-1 md:max-w-screen-sm">
|
||||
<h4 class="font-black font-display text-lg">ARTIFACTS</h4>
|
||||
{#each build.artifacts as item, i}
|
||||
<div class="flex mb-1">
|
||||
<div class="flex items-center justify-center bg-background rounded-md p-1 mr-1">
|
||||
<p class=" w-6 text-center">{i + 1}</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap -mb-1">
|
||||
{#each item as artifact, i}
|
||||
{#if item.length > 2 && i === 0}
|
||||
<div class="flex items-center justify-center bg-background rounded-md px-2 py-1 mb-1 mr-1">
|
||||
<p class="text-center whitespace-no-wrap text-primary">Choose 2</p>
|
||||
</div>
|
||||
{/if}
|
||||
<a
|
||||
class="popup bg-background rounded-md py-1 pl-1 pr-2 mr-1 mb-1 flex items-center"
|
||||
href={artifact === '+18%_atk_set' ? undefined : `/artifacts/${artifact}`}
|
||||
>
|
||||
<div class="popup-container">
|
||||
<div class="bg-gray-300 text-gray-900 p-2 rounded-md mb-1 shadow-2xl">
|
||||
{#if artifact !== '+18%_atk_set'}
|
||||
{#each artifacts[artifact].bonuses as bonus, i}
|
||||
<div class={i === 1 ? 'mt-2' : ''}>
|
||||
<p class="font-bold text-primary text-sm">
|
||||
{$t('artifact.setPiece', { values: { piece: (i + 1) * 2 } })}
|
||||
</p>
|
||||
<p class="text-gray-900 text-sm">{bonus}</p>
|
||||
</div>
|
||||
{/each}
|
||||
{:else}
|
||||
<a
|
||||
class="flex items-center text-primary hover:text-blue-400 pb-1 border-b border-gray-400"
|
||||
href="/artifacts/gladiators_finale"
|
||||
>
|
||||
<img
|
||||
class="h-8 ml-1 mr-2"
|
||||
src="/images/artifacts/gladiators_finale_flower.png"
|
||||
alt="Gladiator's Finale"
|
||||
/>
|
||||
<span class="font-semibold">Gladiator's Finale</span>
|
||||
</a>
|
||||
<a
|
||||
class="flex items-center text-primary hover:text-blue-400 pt-1"
|
||||
href="/artifacts/shimenawas_reminiscence"
|
||||
>
|
||||
<img
|
||||
class="h-8 ml-1 mr-2"
|
||||
src="/images/artifacts/shimenawas_reminiscence_flower.png"
|
||||
alt="Shimenawa's Reminiscence"
|
||||
/>
|
||||
<span class="font-semibold">Shimenawa's Reminiscence</span>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
class="h-8 mr-2"
|
||||
src="/images/artifacts/{artifact === '+18%_atk_set' ? 'gladiators_finale' : artifact}_flower.png"
|
||||
alt={artifact === '+18%_atk_set' ? '+18% ATK set' : artifacts[artifact].name}
|
||||
/>
|
||||
<span>{artifact === '+18%_atk_set' ? '+18% ATK Set' : artifacts[artifact].name}</span>
|
||||
<span class="ml-2 bg-gray-400 rounded-md px-1 text-sm text-gray-900">
|
||||
{item.length === 1 ? '4' : '2'}
|
||||
</span>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col mt-4 text-white px-4 md:px-8" bind:this={talentDiv}>
|
||||
<a href="/characters/{id}/#talents" class="font-black font-display text-2xl mt-4">
|
||||
{$t('characters.talents')}
|
||||
</a>
|
||||
<SkillCard {id} image="talent_1" data={data.attack} withQuote={false} />
|
||||
<SkillCard {id} image="talent_2" data={data.elementalSkill} withQuote={true} />
|
||||
<SkillCard {id} image="talent_3" data={data.burst} withQuote={true} />
|
||||
|
@ -345,6 +550,29 @@
|
|||
</div>
|
||||
|
||||
<style>
|
||||
.pill {
|
||||
@apply rounded-2xl;
|
||||
@apply border-2;
|
||||
@apply border-white;
|
||||
@apply border-opacity-25;
|
||||
@apply text-white;
|
||||
@apply px-4;
|
||||
@apply py-1;
|
||||
@apply outline-none;
|
||||
@apply transition;
|
||||
@apply duration-100;
|
||||
|
||||
&:hover {
|
||||
@apply border-primary;
|
||||
}
|
||||
|
||||
&.active {
|
||||
@apply bg-primary;
|
||||
@apply border-primary;
|
||||
@apply text-background;
|
||||
}
|
||||
}
|
||||
|
||||
.character-image {
|
||||
height: calc(100vh - 4rem);
|
||||
max-height: 700px;
|
||||
|
@ -369,4 +597,26 @@
|
|||
td:not(:last-child) {
|
||||
@apply border-r;
|
||||
}
|
||||
|
||||
.popup {
|
||||
@apply relative;
|
||||
|
||||
.popup-container {
|
||||
@apply hidden absolute top-0 left-0;
|
||||
transform: translateY(-100%);
|
||||
width: calc(100vw - 100px);
|
||||
}
|
||||
|
||||
@screen md {
|
||||
.popup-container {
|
||||
width: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.popup-container {
|
||||
@apply block;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -61,10 +61,13 @@
|
|||
</div>
|
||||
<div class="px-4 mt-4 grid md:grid-cols-2 gap-2 max-w-2xl w-full">
|
||||
{#each currentArtifacts as artifact (artifact.id)}
|
||||
<div class="bg-background rounded-xl p-2 text-white flex items-center">
|
||||
<a
|
||||
class="bg-background hover:bg-item rounded-xl p-2 text-white flex items-center"
|
||||
href="/artifacts/{artifact.id}"
|
||||
>
|
||||
<img src="/images/artifacts/{artifact.id}_flower.png" alt={id} class="w-12 h-12 mr-2" />
|
||||
<p>{artifact.name}</p>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="px-4 mt-4 flex flex-col space-y-2 max-w-2xl w-full">
|
||||
|
|
|
@ -1,14 +1,48 @@
|
|||
<script context="module">
|
||||
import data from '../../data/weapons/en.json';
|
||||
import { weaponList } from '../../data/weaponList.js';
|
||||
import { builds } from '../../data/build';
|
||||
|
||||
function getCharacter(weaponId) {
|
||||
const collection = {};
|
||||
const chars = Object.entries(builds);
|
||||
for (const [charId, char] of chars) {
|
||||
const roles = Object.entries(char.roles);
|
||||
for (const [roleName, role] of roles) {
|
||||
if (!role.recommended) continue;
|
||||
|
||||
let found = false;
|
||||
for (const weapon of role.weapons) {
|
||||
if (weapon.id === weaponId) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
if (collection[charId] === undefined) {
|
||||
collection[charId] = {
|
||||
id: charId,
|
||||
roles: [],
|
||||
};
|
||||
}
|
||||
|
||||
collection[charId].roles.push(roleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Object.values(collection).sort((a, b) => a.id.localeCompare(b.id));
|
||||
}
|
||||
|
||||
export async function preload(page) {
|
||||
const { id } = page.params;
|
||||
const weapon = data[id];
|
||||
const materials = weaponList[id].ascension[0].items;
|
||||
const recommendedCharacter = getCharacter(id);
|
||||
|
||||
return { id, weapon, materials };
|
||||
return { id, weapon, materials, recommendedCharacter };
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
@ -16,6 +50,7 @@
|
|||
import { locale, t } from 'svelte-i18n';
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { characters } from '../../data/characters';
|
||||
|
||||
const rarity = {
|
||||
1: 'text-white',
|
||||
|
@ -33,6 +68,7 @@
|
|||
|
||||
export let id;
|
||||
export let weapon;
|
||||
export let recommendedCharacter;
|
||||
// export let materials;
|
||||
|
||||
async function changeLocale(locale) {
|
||||
|
@ -48,7 +84,6 @@
|
|||
|
||||
$: multiplier = weapon.secondary.name === 'em' ? 1 : 100;
|
||||
$: suffix = weapon.secondary.name === 'em' ? '' : '%';
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -72,6 +107,33 @@
|
|||
<p class="skill-description text-white">{@html weapon.skill.description}</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if recommendedCharacter.length > 0}
|
||||
<div class="mt-4 max-w-screen-lg">
|
||||
<h3 class="font-display font-bold text-2xl text-white">
|
||||
{$t('weapon.recommendedCharacter')}
|
||||
</h3>
|
||||
<div class="flex flex-wrap -mx-1 -mb-2">
|
||||
{#each recommendedCharacter as char}
|
||||
<a
|
||||
class="flex items-center bg-background hover:bg-item rounded-xl px-2 py-1 mb-2 mx-1"
|
||||
href="/characters/{char.id}"
|
||||
>
|
||||
<img
|
||||
src="/images/characters/{char.id}.png"
|
||||
alt={characters[char.id].name}
|
||||
class="w-12 h-12 mr-2 rounded-full"
|
||||
/>
|
||||
<div class="-mx-1">
|
||||
{#each char.roles as role}
|
||||
<p class="text-white mx-1">{role}</p>
|
||||
{/each}
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="mt-4 block overflow-x-auto whitespace-no-wrap md:w-auto">
|
||||
<div style="width: min-content;">
|
||||
<div class="table max-w-full rounded-xl border border-gray-200 border-opacity-25">
|
||||
|
@ -119,5 +181,4 @@
|
|||
td:not(:last-child) {
|
||||
@apply border-r;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
Loading…
Add table
Reference in a new issue