Add character builds

pull/1/head
Made Baruna 2021-08-08 22:33:14 +07:00
parent 635b8a13fb
commit ddc9a22fc8
No known key found for this signature in database
GPG Key ID: 5AA5DA16AA5DCEAD
7 changed files with 3754 additions and 32 deletions

3209
src/data/build.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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"
}
}

View File

@ -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"
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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">

View File

@ -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>