Merge branch 'MadeBaruna:main' into main
|
@ -0,0 +1 @@
|
|||
[{"category":"Wall","name":"Wall","type":"interior"},{"category":"Flooring","name":"Flooring","type":"interior"},{"category":"Ceiling","name":"Ceiling","type":"interior"},{"category":"Ceiling Lamp","name":"Ceiling Lamp","type":"interior"},{"category":"Room Door","name":"Room Door","type":"interior"},{"category":"Stairs","name":"Stairs","type":"interior"},{"category":"Cabinet","name":"Cabinet","type":"interior"},{"category":"Bookcase","name":"Bookcase","type":"interior"},{"category":"Table","name":"Table","type":"interior"},{"category":"Counter","name":"Counter","type":"interior"},{"category":"Bed","name":"Bed","type":"interior"},{"category":"Seating","name":"Seating","type":"interior"},{"category":"Ornament","name":"Ornament","type":"interior"},{"category":"Carpet","name":"Carpet","type":"interior"},{"category":"Lighting","name":"Lighting","type":"interior"},{"category":"Potted Plant","name":"Potted Plant","type":"interior"},{"category":"Utensil","name":"Utensil","type":"interior"},{"category":"Artwork","name":"Artwork","type":"interior"},{"category":"Hanging Ornament","name":"Hanging Ornament","type":"interior"},{"category":"Courtyard Wall","name":"Courtyard Wall","type":"exterior"},{"category":"Large Ornament","name":"Large Ornament","type":"exterior"},{"category":"Liyue","name":"Liyue","type":"exterior"},{"category":"Mondstadt","name":"Mondstadt","type":"exterior"},{"category":"Hilichurl Style","name":"Hilichurl Style","type":"exterior"},{"category":"Mercantile","name":"Mercantile","type":"exterior"},{"category":"Free Booth","name":"Free Booth","type":"exterior"},{"category":"Mountain","name":"Mountain","type":"exterior"},{"category":"Rock","name":"Rock","type":"exterior"},{"category":"Tree","name":"Tree","type":"exterior"},{"category":"Shrub","name":"Shrub","type":"exterior"},{"category":"Item","name":"Item","type":"exterior"},{"category":"Terrace","name":"Terrace","type":"exterior"},{"category":"Ornament","name":"Ornament","type":"exterior"},{"category":"Lighting","name":"Lighting","type":"exterior"},{"category":"Indoor Creature","name":"Indoor Creature","type":"interior"},{"category":"Outdoor Creature","name":"Outdoor Creature","type":"exterior"},{"category":"Mansion","name":"Mansion","type":"exterior"},{"category":"Fence","name":"Fence","type":"exterior"},{"category":"Seating","name":"Seating","type":"exterior"},{"category":"Table","name":"Table","type":"exterior"},{"category":"Cabinet","name":"Cabinet","type":"exterior"}]
|
|
@ -0,0 +1 @@
|
|||
[{"category":"Wall","name":"Murs","type":"interior"},{"category":"Flooring","name":"Sols","type":"interior"},{"category":"Ceiling","name":"Plafonds","type":"interior"},{"category":"Ceiling Lamp","name":"Lustres","type":"interior"},{"category":"Room Door","name":"Portes","type":"interior"},{"category":"Stairs","name":"Escaliers","type":"interior"},{"category":"Cabinet","name":"Rangements","type":"interior"},{"category":"Bookcase","name":"Bibliothèques","type":"interior"},{"category":"Table","name":"Tables","type":"interior"},{"category":"Counter","name":"Comptoirs","type":"interior"},{"category":"Bed","name":"Lits","type":"interior"},{"category":"Seating","name":"Chaises","type":"interior"},{"category":"Ornament","name":"Objets d'agrément","type":"interior"},{"category":"Carpet","name":"Tapis","type":"interior"},{"category":"Lighting","name":"Éclairages","type":"interior"},{"category":"Potted Plant","name":"Plantes en pot","type":"interior"},{"category":"Utensil","name":"Objets divers","type":"interior"},{"category":"Artwork","name":"Œuvres d'art","type":"interior"},{"category":"Hanging Ornament","name":"Éléments suspendus","type":"interior"},{"category":"Courtyard Wall","name":"Murs de cour","type":"exterior"},{"category":"Large Ornament","name":"Grands ornements","type":"exterior"},{"category":"Liyue","name":"Style liyuéen","type":"exterior"},{"category":"Mondstadt","name":"Style mondstadtois","type":"exterior"},{"category":"Hilichurl Style","name":"Style Brutocollinus","type":"exterior"},{"category":"Mercantile","name":"Étals de marchands","type":"exterior"},{"category":"Free Booth","name":"Étals libres","type":"exterior"},{"category":"Mountain","name":"Reliefs","type":"exterior"},{"category":"Rock","name":"Roches","type":"exterior"},{"category":"Tree","name":"Arbres","type":"exterior"},{"category":"Shrub","name":"Buissons","type":"exterior"},{"category":"Item","name":"Objets divers","type":"exterior"},{"category":"Terrace","name":"Végétation en pot","type":"exterior"},{"category":"Ornament","name":"Aménagements divers","type":"exterior"},{"category":"Lighting","name":"Éclairages","type":"exterior"},{"category":"Indoor Creature","name":"Animaux d'intérieur","type":"interior"},{"category":"Outdoor Creature","name":"Animaux d'extérieur","type":"exterior"},{"category":"Mansion","name":"Résidences","type":"exterior"},{"category":"Fence","name":"Clôtures","type":"exterior"},{"category":"Seating","name":"Chaises","type":"exterior"},{"category":"Table","name":"Tables","type":"exterior"},{"category":"Cabinet","name":"Rangements","type":"exterior"}]
|
|
@ -0,0 +1 @@
|
|||
[{"category":"Wall","name":"Dinding","type":"interior"},{"category":"Flooring","name":"Lantai","type":"interior"},{"category":"Ceiling","name":"Langit-Langit","type":"interior"},{"category":"Ceiling Lamp","name":"Lampu Gantung","type":"interior"},{"category":"Room Door","name":"Pintu","type":"interior"},{"category":"Stairs","name":"Tangga","type":"interior"},{"category":"Cabinet","name":"Kabinet","type":"interior"},{"category":"Bookcase","name":"Rak Buku","type":"interior"},{"category":"Table","name":"Meja","type":"interior"},{"category":"Counter","name":"Konter","type":"interior"},{"category":"Bed","name":"Ranjang","type":"interior"},{"category":"Seating","name":"Kursi","type":"interior"},{"category":"Ornament","name":"Ornamen","type":"interior"},{"category":"Carpet","name":"Karpet","type":"interior"},{"category":"Lighting","name":"Lampu","type":"interior"},{"category":"Potted Plant","name":"Tanaman Pot","type":"interior"},{"category":"Utensil","name":"Perkakas","type":"interior"},{"category":"Artwork","name":"Karya Seni","type":"interior"},{"category":"Hanging Ornament","name":"Hiasan Gantung","type":"interior"},{"category":"Courtyard Wall","name":"Dinding Halaman","type":"exterior"},{"category":"Large Ornament","name":"Ornamen Besar","type":"exterior"},{"category":"Liyue","name":"Model Liyue","type":"exterior"},{"category":"Mondstadt","name":"Model Mondstadt","type":"exterior"},{"category":"Hilichurl Style","name":"Gaya Hilichurl","type":"exterior"},{"category":"Mercantile","name":"Model Perdagangan","type":"exterior"},{"category":"Free Booth","name":"Stan Cuma-Cuma","type":"exterior"},{"category":"Mountain","name":"Gunung","type":"exterior"},{"category":"Rock","name":"Batu","type":"exterior"},{"category":"Tree","name":"Pohon","type":"exterior"},{"category":"Shrub","name":"Semak Belukar","type":"exterior"},{"category":"Item","name":"Benda","type":"exterior"},{"category":"Terrace","name":"Teras Berbunga","type":"exterior"},{"category":"Ornament","name":"Ornamen","type":"exterior"},{"category":"Lighting","name":"Lampu","type":"exterior"},{"category":"Indoor Creature","name":"Makhluk Dalam Ruangan","type":"interior"},{"category":"Outdoor Creature","name":"Makhluk Luar Ruangan","type":"exterior"},{"category":"Mansion","name":"Rumah Mewah","type":"exterior"},{"category":"Fence","name":"Pagar","type":"exterior"},{"category":"Seating","name":"Kursi","type":"exterior"},{"category":"Table","name":"Meja","type":"exterior"},{"category":"Cabinet","name":"Kabinet","type":"exterior"}]
|
|
@ -0,0 +1 @@
|
|||
[{"category":"Wall","name":"벽지","type":"interior"},{"category":"Flooring","name":"바닥","type":"interior"},{"category":"Ceiling","name":"천장","type":"interior"},{"category":"Ceiling Lamp","name":"조명","type":"interior"},{"category":"Room Door","name":"문","type":"interior"},{"category":"Stairs","name":"계단","type":"interior"},{"category":"Cabinet","name":"수납장","type":"interior"},{"category":"Bookcase","name":"책장","type":"interior"},{"category":"Table","name":"탁자","type":"interior"},{"category":"Counter","name":"카운터","type":"interior"},{"category":"Bed","name":"침대","type":"interior"},{"category":"Seating","name":"의자","type":"interior"},{"category":"Ornament","name":"장식","type":"interior"},{"category":"Carpet","name":"카펫","type":"interior"},{"category":"Lighting","name":"조명","type":"interior"},{"category":"Potted Plant","name":"분재","type":"interior"},{"category":"Utensil","name":"기물","type":"interior"},{"category":"Artwork","name":"그림","type":"interior"},{"category":"Hanging Ornament","name":"인테리어 모빌","type":"interior"},{"category":"Courtyard Wall","name":"담장","type":"exterior"},{"category":"Large Ornament","name":"대형 장식","type":"exterior"},{"category":"Liyue","name":"리월 테마","type":"exterior"},{"category":"Mondstadt","name":"몬드 테마","type":"exterior"},{"category":"Hilichurl Style","name":"츄츄 테마","type":"exterior"},{"category":"Mercantile","name":"상가 테마","type":"exterior"},{"category":"Free Booth","name":"자유 가판대","type":"exterior"},{"category":"Mountain","name":"산","type":"exterior"},{"category":"Rock","name":"암석","type":"exterior"},{"category":"Tree","name":"교목","type":"exterior"},{"category":"Shrub","name":"관목","type":"exterior"},{"category":"Item","name":"물품","type":"exterior"},{"category":"Terrace","name":"화단","type":"exterior"},{"category":"Ornament","name":"장식","type":"exterior"},{"category":"Lighting","name":"조명","type":"exterior"},{"category":"Indoor Creature","name":"실내 동물","type":"interior"},{"category":"Outdoor Creature","name":"실외 동물","type":"exterior"},{"category":"Mansion","name":"저택","type":"exterior"},{"category":"Fence","name":"울타리","type":"exterior"},{"category":"Seating","name":"의자","type":"exterior"},{"category":"Table","name":"탁자","type":"exterior"},{"category":"Cabinet","name":"수납장","type":"exterior"}]
|
|
@ -0,0 +1 @@
|
|||
[{"category":"Wall","name":"Parede","type":"interior"},{"category":"Flooring","name":"Assoalho","type":"interior"},{"category":"Ceiling","name":"Teto","type":"interior"},{"category":"Ceiling Lamp","name":"Luminária","type":"interior"},{"category":"Room Door","name":"Portas","type":"interior"},{"category":"Stairs","name":"Escadas","type":"interior"},{"category":"Cabinet","name":"Armário","type":"interior"},{"category":"Bookcase","name":"Estante","type":"interior"},{"category":"Table","name":"Mesa","type":"interior"},{"category":"Counter","name":"Balcão","type":"interior"},{"category":"Bed","name":"Cama","type":"interior"},{"category":"Seating","name":"Cadeira","type":"interior"},{"category":"Ornament","name":"Ornamentos","type":"interior"},{"category":"Carpet","name":"Carpete","type":"interior"},{"category":"Lighting","name":"Iluminação","type":"interior"},{"category":"Potted Plant","name":"Planta em Vaso","type":"interior"},{"category":"Utensil","name":"Utensílio","type":"interior"},{"category":"Artwork","name":"Obra de Arte","type":"interior"},{"category":"Hanging Ornament","name":"Ornamento Suspenso","type":"interior"},{"category":"Courtyard Wall","name":"Muro do Pátio","type":"exterior"},{"category":"Large Ornament","name":"Ornamento Largo","type":"exterior"},{"category":"Liyue","name":"Estilo de Liyue","type":"exterior"},{"category":"Mondstadt","name":"Estilo de Mondstadt","type":"exterior"},{"category":"Hilichurl Style","name":"Estilo de Hilichurls","type":"exterior"},{"category":"Mercantile","name":"Estilo de Comercial","type":"exterior"},{"category":"Free Booth","name":"Estande Livre","type":"exterior"},{"category":"Mountain","name":"Montanha","type":"exterior"},{"category":"Rock","name":"Selo de Pedra","type":"exterior"},{"category":"Tree","name":"Arborea","type":"exterior"},{"category":"Shrub","name":"Arbusto","type":"exterior"},{"category":"Item","name":"Item","type":"exterior"},{"category":"Terrace","name":"Terraço Florido","type":"exterior"},{"category":"Ornament","name":"Ornamentos","type":"exterior"},{"category":"Lighting","name":"Iluminação","type":"exterior"},{"category":"Indoor Creature","name":"Criaturas Domésticas","type":"interior"},{"category":"Outdoor Creature","name":"Criaturas Silvestres","type":"exterior"},{"category":"Mansion","name":"Residência","type":"exterior"},{"category":"Fence","name":"Cercas","type":"exterior"},{"category":"Seating","name":"Cadeira","type":"exterior"},{"category":"Table","name":"Mesa","type":"exterior"},{"category":"Cabinet","name":"Armário","type":"exterior"}]
|
|
@ -0,0 +1 @@
|
|||
[{"category":"Wall","name":"Стены","type":"interior"},{"category":"Flooring","name":"Полы","type":"interior"},{"category":"Ceiling","name":"Потолки","type":"interior"},{"category":"Ceiling Lamp","name":"Люстры","type":"interior"},{"category":"Room Door","name":"Двери","type":"interior"},{"category":"Stairs","name":"Лестницы","type":"interior"},{"category":"Cabinet","name":"Шкафы","type":"interior"},{"category":"Bookcase","name":"Книжные полки","type":"interior"},{"category":"Table","name":"Столы","type":"interior"},{"category":"Counter","name":"Стойки","type":"interior"},{"category":"Bed","name":"Кровати","type":"interior"},{"category":"Seating","name":"Стулья","type":"interior"},{"category":"Ornament","name":"Украшения","type":"interior"},{"category":"Carpet","name":"Ковры","type":"interior"},{"category":"Lighting","name":"Освещение","type":"interior"},{"category":"Potted Plant","name":"Цветки","type":"interior"},{"category":"Utensil","name":"Утварь","type":"interior"},{"category":"Artwork","name":"Картины","type":"interior"},{"category":"Hanging Ornament","name":"Подвесные украшения","type":"interior"},{"category":"Courtyard Wall","name":"Ограды","type":"exterior"},{"category":"Large Ornament","name":"Крупные украшения","type":"exterior"},{"category":"Liyue","name":"Стиль Ли Юэ","type":"exterior"},{"category":"Mondstadt","name":"Стиль Мондштадта","type":"exterior"},{"category":"Hilichurl Style","name":"Стиль хиличурлов","type":"exterior"},{"category":"Mercantile","name":"Купеческий стиль","type":"exterior"},{"category":"Free Booth","name":"Свободный ларёк","type":"exterior"},{"category":"Mountain","name":"Скалы","type":"exterior"},{"category":"Rock","name":"Камни","type":"exterior"},{"category":"Tree","name":"Деревья","type":"exterior"},{"category":"Shrub","name":"Кусты","type":"exterior"},{"category":"Item","name":"Предметы","type":"exterior"},{"category":"Terrace","name":"Клумбы","type":"exterior"},{"category":"Ornament","name":"Украшения","type":"exterior"},{"category":"Lighting","name":"Лампы","type":"exterior"},{"category":"Indoor Creature","name":"Домашние животные","type":"interior"},{"category":"Outdoor Creature","name":"Домашние животные","type":"exterior"},{"category":"Mansion","name":"Дом","type":"exterior"},{"category":"Fence","name":"Изгороди","type":"exterior"},{"category":"Seating","name":"Стулья","type":"exterior"},{"category":"Table","name":"Столы","type":"exterior"},{"category":"Cabinet","name":"Шкафы","type":"exterior"}]
|
|
@ -0,0 +1 @@
|
|||
[{"category":"Wall","name":"墙面","type":"interior"},{"category":"Flooring","name":"地板","type":"interior"},{"category":"Ceiling","name":"天花板","type":"interior"},{"category":"Ceiling Lamp","name":"吊灯","type":"interior"},{"category":"Room Door","name":"房门","type":"interior"},{"category":"Stairs","name":"楼梯","type":"interior"},{"category":"Cabinet","name":"柜子","type":"interior"},{"category":"Bookcase","name":"书柜","type":"interior"},{"category":"Table","name":"桌子","type":"interior"},{"category":"Counter","name":"柜台","type":"interior"},{"category":"Bed","name":"床","type":"interior"},{"category":"Seating","name":"椅子","type":"interior"},{"category":"Ornament","name":"饰品","type":"interior"},{"category":"Carpet","name":"地毯","type":"interior"},{"category":"Lighting","name":"灯具","type":"interior"},{"category":"Potted Plant","name":"盆景","type":"interior"},{"category":"Utensil","name":"器物","type":"interior"},{"category":"Artwork","name":"字画","type":"interior"},{"category":"Hanging Ornament","name":"挂饰","type":"interior"},{"category":"Courtyard Wall","name":"院墙","type":"exterior"},{"category":"Large Ornament","name":"大型饰品","type":"exterior"},{"category":"Liyue","name":"璃月风格","type":"exterior"},{"category":"Mondstadt","name":"蒙德风格","type":"exterior"},{"category":"Hilichurl Style","name":"丘丘风格","type":"exterior"},{"category":"Mercantile","name":"商户风格","type":"exterior"},{"category":"Free Booth","name":"自由摊位","type":"exterior"},{"category":"Mountain","name":"山体","type":"exterior"},{"category":"Rock","name":"岩石","type":"exterior"},{"category":"Tree","name":"乔木","type":"exterior"},{"category":"Shrub","name":"灌木","type":"exterior"},{"category":"Item","name":"物件","type":"exterior"},{"category":"Terrace","name":"花坛","type":"exterior"},{"category":"Ornament","name":"饰品","type":"exterior"},{"category":"Lighting","name":"灯具","type":"exterior"},{"category":"Indoor Creature","name":"室内动物","type":"interior"},{"category":"Outdoor Creature","name":"室外动物","type":"exterior"},{"category":"Mansion","name":"宅邸","type":"exterior"},{"category":"Fence","name":"围栏","type":"exterior"},{"category":"Seating","name":"椅子","type":"exterior"},{"category":"Table","name":"桌子","type":"exterior"},{"category":"Cabinet","name":"柜子","type":"exterior"}]
|
14
src/i18n.js
|
@ -25,6 +25,7 @@ $locale.subscribe((value) => {
|
|||
}
|
||||
});
|
||||
|
||||
const supportedLanguage = ['en', 'id', 'ru', 'ko', 'fr', 'zh', 'pt'];
|
||||
addMessages('en', en);
|
||||
addMessages('id', id);
|
||||
addMessages('ru', ru);
|
||||
|
@ -34,11 +35,22 @@ addMessages('zh', zh);
|
|||
addMessages('pt', pt);
|
||||
|
||||
export function startClient() {
|
||||
let used = 'en';
|
||||
const savedLocale = localStorage.getItem('locale');
|
||||
const detectedLocale = getLocaleFromNavigator().substring(0, 2);
|
||||
if (savedLocale !== null) {
|
||||
if (!supportedLanguage.includes(savedLocale)) {
|
||||
localStorage.setItem('locale', 'en');
|
||||
} else {
|
||||
used = savedLocale;
|
||||
}
|
||||
} else if (supportedLanguage.includes(detectedLocale)) {
|
||||
used = detectedLocale;
|
||||
}
|
||||
|
||||
init({
|
||||
...INIT_OPTIONS,
|
||||
initialLocale: savedLocale !== null ? savedLocale : getLocaleFromNavigator().substring(0, 2),
|
||||
initialLocale: used,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,10 @@
|
|||
"achievement": {
|
||||
"title": "🏆 View and track your achievement list here",
|
||||
"detail": "Achievement"
|
||||
},
|
||||
"furnishing": {
|
||||
"title": "Check what furnishing you need to make to complete a sets. And also you can view the load of each furnishing.",
|
||||
"detail": "Furnishing"
|
||||
}
|
||||
},
|
||||
"characters": {
|
||||
|
@ -604,7 +608,24 @@
|
|||
"hall": "Hall",
|
||||
"room": "Room {number}",
|
||||
"exteriorNum": "Area {number}",
|
||||
"corridor": "Corridor"
|
||||
"corridor": "Corridor",
|
||||
"inventoryButton": "Inventory",
|
||||
"listButton": "List",
|
||||
"inventory": {
|
||||
"title": "Furnishing Inventory",
|
||||
"subtitle": "Some special categories like wall are not shown",
|
||||
"all": "All",
|
||||
"openSets": "Open Sets"
|
||||
},
|
||||
"sets": {
|
||||
"title": "Furnishing Sets",
|
||||
"subtitle": "Click the furnishing icon for detail, and you can click the character icon to mark them! Open the Inventory menu above to fill your furnishing items count.",
|
||||
"setPlaced": "Set as placed",
|
||||
"setUnplaced": "Set as unplaced",
|
||||
"inInventory": "In inventory",
|
||||
"available": "Available",
|
||||
"used": "Used in other set"
|
||||
}
|
||||
},
|
||||
"weapon": {
|
||||
"title": "Weapon List",
|
||||
|
|
|
@ -60,6 +60,10 @@
|
|||
"twitter": {
|
||||
"title": "Follow my Twitter, akan post tentang apa yang lagi di develop dan update terbaru tentang paimon.moe!",
|
||||
"detail": "Follow Twitter"
|
||||
},
|
||||
"furnishing": {
|
||||
"title": "Cek furnitur apa saja yang kamu perlukan untuk menyelesaikan suatu set. Dan kamu juga bisa melihat beban masing-masing furnitur.",
|
||||
"detail": "Furnitur"
|
||||
}
|
||||
},
|
||||
"characters": {
|
||||
|
@ -568,6 +572,27 @@
|
|||
"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!)"
|
||||
]
|
||||
],
|
||||
"hall": "Aula Utama",
|
||||
"room": "Kamar {number}",
|
||||
"exteriorNum": "Area {number}",
|
||||
"corridor": "Koridor",
|
||||
"inventoryButton": "Inventory",
|
||||
"listButton": "List",
|
||||
"inventory": {
|
||||
"title": "Furnishing Inventory",
|
||||
"subtitle": "Beberapa kategori special seperti dinding tidak ditampilkan",
|
||||
"all": "Semua",
|
||||
"openSets": "Buka Set"
|
||||
},
|
||||
"sets": {
|
||||
"title": "Furnishing Set",
|
||||
"subtitle": "Klik icon furnitur untuk detail, dan kamu bisa klik icon karakter untuk menandai mereka! Buka menu inventory diatas untuk mengisi jumlah furnitur yang kamu punya.",
|
||||
"setPlaced": "Set ditempatkan",
|
||||
"setUnplaced": "Set belum ditempatkan",
|
||||
"inInventory": "Di inventory",
|
||||
"available": "Tersedia",
|
||||
"used": "Digunakan di set lain"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
"home": {
|
||||
"welcome": "Boas-vindas ao Paimon.moe! 👋",
|
||||
"message": "Seu melhor companheiro de Genshin Impact! Planeje seu farm com a calculadora de ascenção e acompanhe seu progresso com a lista de afazeres e o histórico de orações.",
|
||||
"message": "Seu melhor companheiro de Genshin Impact! Planeje seu farm com a calculadora de ascensão e acompanhe seu progresso com a lista de afazeres e o histórico de orações.",
|
||||
"banner": {
|
||||
"featured": [
|
||||
"Eula"
|
||||
|
@ -51,12 +51,12 @@
|
|||
"join": "Junte-se ao Discord"
|
||||
},
|
||||
"items": {
|
||||
"title": "Farmáveis Hoje",
|
||||
"title": "Farmaveis Hoje",
|
||||
"detail": "Itens",
|
||||
"sunday": "Todos os itens podem ser farmados aos domingos 😁"
|
||||
},
|
||||
"calculator": {
|
||||
"title": "🧮 Calcule materiais de ascenção de Personagens, Armas e elevação de talento! Todos os cálculos podem ser adicionados na Lista de Afazeres. Também mostra quantas resinas você irá precisar!",
|
||||
"title": "🧮 Calcule materiais de ascensão de Personagens, Armas e elevação de talento! Todos os cálculos podem ser adicionados na Lista de Afazeres. Também mostra quantas resinas você irá precisar!",
|
||||
"detail": "Calculadora"
|
||||
},
|
||||
"twitter": {
|
||||
|
@ -70,7 +70,7 @@
|
|||
},
|
||||
"characters": {
|
||||
"title": "Personagens",
|
||||
"subtitle": "Os números dos status são do Nível 80, Ascenção 6. Você pode clicar nos índices da tabela para ordenar!",
|
||||
"subtitle": "Os números dos status são do Nível 80, Ascensão 6. Você pode clicar nos índices da tabela para ordenar!",
|
||||
"name": "Nome",
|
||||
"element": "Elemento",
|
||||
"rarity": "Raridade",
|
||||
|
@ -115,7 +115,7 @@
|
|||
"welcomeStart2": "acima",
|
||||
"manual": "Se você quiser informar os dados manualmente, você pode fazer isso aqui:",
|
||||
"manualButton": "Habilitar Inserção Manual",
|
||||
"errorBanner": "Incompatibilidade no tempo do banner! Ajuste seu servidor na página de configurações. Ainda não está funcionando? Por favor, deixa uma mensagem no Discord 😅",
|
||||
"errorBanner": "Incompatibilidade no tempo do banner! Ajuste seu servidor na página de configurações. Ainda não está funcionando? Por favor, deixe uma mensagem no Discord 😅",
|
||||
"globalWishTally": "Contagem Global de Orações",
|
||||
"pityTooltip": [
|
||||
"Informa seu pity atual para {rarity}",
|
||||
|
@ -179,7 +179,7 @@
|
|||
"Se você não deseja compartilhar sua URL, você pode utilizar um pequeno script de importação para salvar seu histórico de orações em seu PC (opção para PC Local)"
|
||||
],
|
||||
"q6": "Eu fiz todos os procedimentos, mas tive um erro na API?",
|
||||
"a6": "Certifique-se de copiar todo o texto (segura e pressione Selecionar Tudo para dispositivos móveis); talvez você tenha esquecido alguns caracteres que não necessários para o funcionamento da importação.",
|
||||
"a6": "Certifique-se de copiar todo o texto (segure e pressione Selecionar Tudo para dispositivos móveis); talvez você tenha esquecido alguns caracteres que não necessários para o funcionamento da importação.",
|
||||
"q7": "Não leu todo meu histórico!?",
|
||||
"a7": "Histórico de orações mais antigos que 6 meses são deletados dos servidores da MiHoYo, então se você não possui um backup em algum lugar, infelizmente se foi"
|
||||
},
|
||||
|
@ -225,7 +225,7 @@
|
|||
"pclocal": [
|
||||
"Se você não se sente confortável em compartilhar sua URL de feedback, você pode usar esta opção para processar seu histórico de orações em seu PC localmente. Este script irá ler o log em seu PC para gerar a URL do histórico de orações.",
|
||||
"Abra o menu Iniciar, e então procure por Powershell",
|
||||
"Abra o Powershell do Widows, e então copie & cole o script abaixo no Powershell",
|
||||
"Abra o Powershell do Windows, e então copie & cole o script abaixo no Powershell",
|
||||
"iex ((New-Object System.Net.WebClient).DownloadString('https://gist.githubusercontent.com/MadeBaruna/9ff8b7a2af11f3002395af7963b5ed18/raw/cdfead30f830b897e8822a40f98fea5340dbd62e/importer.ps1'))",
|
||||
"Você pode revisar o script",
|
||||
"aqui",
|
||||
|
@ -244,7 +244,7 @@
|
|||
"export": "Exportar para Excel",
|
||||
"exporting": "Exportando...",
|
||||
"import": "Importar",
|
||||
"exportFinish": "Exportado com successo, aguarde até que o navegador realize o download do arquivo!",
|
||||
"exportFinish": "Exportado com sucesso, aguarde até que o navegador realize o download do arquivo!",
|
||||
"wishTallyTitle": "Enviar Contagem de Orações",
|
||||
"wishTally": "Estamos fazendo uma contagem global de orações! Você pode enviar sua contagem de orações para participar. Todas as informações do pity serão agregadas para saber qual a média de pity dos usuários do paimon.moe.",
|
||||
"wishTallyCollected": [
|
||||
|
@ -280,7 +280,7 @@
|
|||
"para editar os valores manualmente!"
|
||||
],
|
||||
"p6": [
|
||||
"Pressione a seta embaixo para visualizar os detalhes das orações. Um pop-up irá aparecer quando você conseguir um item",
|
||||
"Pressione a seta abaixo para visualizar os detalhes das orações. Um pop-up irá aparecer quando você conseguir um item",
|
||||
"ou",
|
||||
"Você também pode adicionar ou editar a tabela manualmente."
|
||||
]
|
||||
|
@ -342,7 +342,7 @@
|
|||
"howToCharacter": "Como usar a Calculadora de Personagens"
|
||||
},
|
||||
"weapon": {
|
||||
"calculateAscension": "Calcular Materiais de Ascenção?",
|
||||
"calculateAscension": "Calcular Materiais de Ascensão?",
|
||||
"selectRarity": "Selecione a raridade da arma",
|
||||
"selectWeapon": "Selecione a arma",
|
||||
"current": "Nível, EXP, & Ascenção Atual da Arma",
|
||||
|
@ -353,14 +353,14 @@
|
|||
"resource": "Recursos para Usar",
|
||||
"calculate": "Calcular",
|
||||
"unknownInformation": "Há alguma informação desconhecida",
|
||||
"ascensionLevel": "Nível de ascenção",
|
||||
"ascensionLevel": "Nível de ascensão",
|
||||
"mora": "Mora (aproximadamente ±40)",
|
||||
"expWasted": "EXP Desperdiçada",
|
||||
"addToTodo": "Adicionar na Lista de Afazeres",
|
||||
"addedToTodo": "Adicionado na Lista de Afazeres"
|
||||
},
|
||||
"character": {
|
||||
"calculateAscension": "Calcular Materiais de Ascenção?",
|
||||
"calculateAscension": "Calcular Materiais de Ascensão?",
|
||||
"selectCharacter": "Selecione o personagem",
|
||||
"current": "Nível, EXP, & Ascenção Atual do Personagem",
|
||||
"inputCurrentLevel": "Informe o nível atual do personagem...",
|
||||
|
@ -379,7 +379,7 @@
|
|||
"talentToLevel": "para o nível",
|
||||
"calculate": "Calcular",
|
||||
"unknownInformation": "Há alguma informação desconhecida",
|
||||
"ascensionLevel": "Nível de ascenção",
|
||||
"ascensionLevel": "Nível de ascensão",
|
||||
"mora": "Mora (aproximadamente ±40)",
|
||||
"expWasted": "EXP Desperdiçada",
|
||||
"addToTodo": "Adicionar na Lista de Afazeres",
|
||||
|
@ -440,12 +440,12 @@
|
|||
"summary": "Sumário",
|
||||
"empty": [
|
||||
"Nada para fazer ainda 😀",
|
||||
"Adicione algumas coisas a partir da Cálculadora ou da página de Itens!"
|
||||
"Adicione algumas coisas a partir da Calculadora ou da página de Itens!"
|
||||
],
|
||||
"farmableToday": "Farmáveis hoje",
|
||||
"resin": "Resinas necessárias",
|
||||
"based": "Baseado no AR:{ar} e WL:{wl}",
|
||||
"change": "(altera nas configurações)",
|
||||
"change": "(alterar nas configurações)",
|
||||
"approximation": "Aproximação calculada a partir da taxa de drops por",
|
||||
"delete": {
|
||||
"title": "Deletar esse afazer?",
|
||||
|
@ -549,7 +549,7 @@
|
|||
"donate": {
|
||||
"message": [
|
||||
"Muito obrigado! Espero que ache isso útil.",
|
||||
"Fiz este site para me divertir quando tenha um tempo livre. Obviamente irei adicionar mais recursos e atualizarei os dados a cada nova atualização, pois gosto de explorar o jogo e tentar maximizar minha experiência",
|
||||
"Fiz este site para me divertir quando tenho um tempo livre. Obviamente irei adicionar mais recursos e atualizarei os dados a cada nova atualização, pois gosto de explorar o jogo e tentar maximizar minha experiência",
|
||||
"Se você quiser doar, sua doação definitivamente irá ajudar a melhorar o site e me motivar a adicionar mais conteúdo para Paimon.moe! Muito obrigado e divirta-se, espero que goste!",
|
||||
"Se você gosta de codificar, você também pode contribuir para o projeto em"
|
||||
],
|
||||
|
|
|
@ -390,7 +390,7 @@
|
|||
"mora": "Мора (приблизительно ±40)",
|
||||
"expWasted": "EXP потеряно",
|
||||
"addToTodo": "Добавить в список дел",
|
||||
"addedToTodo": "Добавлено в список дел"
|
||||
"addedToTodo": "Добавлено в список дел",
|
||||
"talent": ["Обычн.Атака", "Элем.Навык", "Взрыв Стихии"]
|
||||
},
|
||||
"expTable": {
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<script>
|
||||
import { mdiChevronRight } from '@mdi/js';
|
||||
|
||||
import { t } from 'svelte-i18n';
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
</script>
|
||||
|
||||
<div class="bg-item rounded-xl p-4 flex flex-col">
|
||||
<p class="text-white">{$t('home.furnishing.title')}</p>
|
||||
<a
|
||||
href="/furnishing"
|
||||
class="flex justify-end items-center self-end lg:self-start text-white mt-4
|
||||
bg-background-secondary rounded-xl py-2 px-4 hover:bg-background transition-colors duration-100"
|
||||
>
|
||||
{$t('home.furnishing.detail')}
|
||||
<Icon path={mdiChevronRight} />
|
||||
</a>
|
||||
</div>
|
|
@ -1,161 +1,128 @@
|
|||
<script context="module">
|
||||
import setsData from '../../data/furnishing/sets/en.json';
|
||||
import data from '../../data/furnishing/en.json';
|
||||
export async function preload() {
|
||||
return { data };
|
||||
return { data, setsData };
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { locale, t } from 'svelte-i18n';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { mdiInformationOutline, mdiMinus, mdiPlus } from '@mdi/js';
|
||||
|
||||
import TableHeader from '../../components/Table/TableHeader.svelte';
|
||||
import Button from '../../components/Button.svelte';
|
||||
import CharacterSelect from '../../components/CharacterSelect.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
import { mdiCheckCircleOutline, mdiClose } from '@mdi/js';
|
||||
import { getAccountPrefix } from '../../stores/account';
|
||||
import { readSave, updateSave } from '../../stores/saveManager';
|
||||
|
||||
export let data;
|
||||
export let setsData;
|
||||
|
||||
let type = 'hall';
|
||||
let items = [];
|
||||
let max = 0;
|
||||
let loading = true;
|
||||
let furnishing = {};
|
||||
let sets = [];
|
||||
let saved = {};
|
||||
let _saved = {};
|
||||
let used = {};
|
||||
let placed = {};
|
||||
let character = {};
|
||||
let charFilter = null;
|
||||
|
||||
const minEnergy = {
|
||||
exterior: 0,
|
||||
exterior2: 0,
|
||||
exterior3: 0,
|
||||
exterior4: 0,
|
||||
hall: 150,
|
||||
room1: 150,
|
||||
room2: 150,
|
||||
room3: 150,
|
||||
corridor: 150,
|
||||
};
|
||||
const maxLoad = {
|
||||
exterior: 10000,
|
||||
exterior2: 10000,
|
||||
exterior3: 10000,
|
||||
exterior4: 10000,
|
||||
hall: 10000,
|
||||
room1: 4000,
|
||||
room2: 4000,
|
||||
room3: 4000,
|
||||
corridor: 4000,
|
||||
};
|
||||
let currentUsage = {
|
||||
exterior: {},
|
||||
exterior2: {},
|
||||
exterior3: {},
|
||||
exterior4: {},
|
||||
hall: {},
|
||||
room1: {},
|
||||
room2: {},
|
||||
room3: {},
|
||||
corridor: {},
|
||||
};
|
||||
$: currentLoad = Object.entries(currentUsage[type]).reduce(
|
||||
(prev, [id, val]) => {
|
||||
prev.load += data[id].load * val;
|
||||
prev.energy += data[id].energy * val;
|
||||
return prev;
|
||||
},
|
||||
{
|
||||
load: 0,
|
||||
energy: minEnergy[type],
|
||||
},
|
||||
);
|
||||
|
||||
let sortBy = 'ratio';
|
||||
let sortOrder = false;
|
||||
|
||||
async function parseFurnishing() {
|
||||
const currentType = type.startsWith('exterior') ? 'exterior' : 'interior';
|
||||
items = Object.values(data)
|
||||
.filter((e) => e.type === currentType || e.type === '')
|
||||
.sort((a, b) => {
|
||||
switch (sortBy) {
|
||||
case 'ratio':
|
||||
if (sortOrder) return a.ratio - b.ratio;
|
||||
else return b.ratio - a.ratio;
|
||||
case 'energy':
|
||||
if (sortOrder) return a.energy - b.energy;
|
||||
else return b.energy - a.energy;
|
||||
case 'load':
|
||||
if (sortOrder) return a.load - b.load;
|
||||
else return b.load - a.load;
|
||||
case 'using':
|
||||
if (sortOrder) return (currentUsage[type][a.id] || 0) - (currentUsage[type][b.id] || 0);
|
||||
else return (currentUsage[type][b.id] || 0) - (currentUsage[type][a.id] || 0);
|
||||
case 'name':
|
||||
if (sortOrder) return a.name.localeCompare(b.name);
|
||||
else return b.name.localeCompare(a.name);
|
||||
}
|
||||
});
|
||||
function parseSets() {
|
||||
const _sets = [];
|
||||
furnishing = data;
|
||||
used = {};
|
||||
saved = { ..._saved };
|
||||
for (const set of setsData) {
|
||||
for (const [item, amount] of Object.entries(set.items)) {
|
||||
if (placed[set.id] === true) {
|
||||
if (used[item] === undefined) {
|
||||
used[item] = 0;
|
||||
}
|
||||
|
||||
function sort(by) {
|
||||
if (sortBy === by) {
|
||||
sortOrder = !sortOrder;
|
||||
} else {
|
||||
sortBy = by;
|
||||
used[item] += amount;
|
||||
saved[item] -= amount;
|
||||
}
|
||||
}
|
||||
parseFurnishing();
|
||||
}
|
||||
|
||||
function changeType(_type) {
|
||||
type = _type;
|
||||
sortBy = 'ratio';
|
||||
sortOrder = false;
|
||||
parseFurnishing();
|
||||
max = items[0].ratio;
|
||||
for (const set of setsData.sort((a, b) => b.gift - a.gift)) {
|
||||
set.enough = {};
|
||||
set.canBePlaced = true;
|
||||
|
||||
for (const [item, amount] of Object.entries(set.items)) {
|
||||
let enough = true;
|
||||
if (placed[set.id] !== true) {
|
||||
enough = saved[item] >= amount;
|
||||
}
|
||||
|
||||
function changeUsage(id, val) {
|
||||
if (currentUsage[type][id] === undefined) currentUsage[type][id] = 0;
|
||||
currentUsage[type][id] = Math.max(0, currentUsage[type][id] + val);
|
||||
if (currentUsage[type][id] === 0) delete currentUsage[type][id];
|
||||
set.enough[item] = enough;
|
||||
if (!enough) set.canBePlaced = false;
|
||||
}
|
||||
|
||||
_sets.push(set);
|
||||
}
|
||||
|
||||
sets = _sets;
|
||||
console.log(sets);
|
||||
loading = false;
|
||||
}
|
||||
|
||||
function place(id) {
|
||||
placed[id] = !placed[id];
|
||||
saveData();
|
||||
parseSets();
|
||||
}
|
||||
|
||||
function checkCharacter(setId, id) {
|
||||
if (character[setId] === undefined) {
|
||||
character[setId] = {};
|
||||
}
|
||||
|
||||
character[setId][id] = !character[setId][id];
|
||||
saveData();
|
||||
}
|
||||
|
||||
async function readLocalData() {
|
||||
const prefix = getAccountPrefix();
|
||||
const savedIventory = await readSave(`${prefix}furnishing-inventory`);
|
||||
const savedSet = await readSave(`${prefix}furnishing-set-placed`);
|
||||
const savedSetCharacters = await readSave(`${prefix}furnishing-set-character`);
|
||||
if (savedIventory !== null) {
|
||||
_saved = { ...savedIventory };
|
||||
saved = { ...savedIventory };
|
||||
}
|
||||
if (savedSet !== null) {
|
||||
placed = savedSet;
|
||||
}
|
||||
if (savedSetCharacters !== null) {
|
||||
character = savedSetCharacters;
|
||||
}
|
||||
}
|
||||
|
||||
async function changeLocale(locale) {
|
||||
data = (await import(`../../data/furnishing/${locale}.json`)).default;
|
||||
parseFurnishing();
|
||||
}
|
||||
|
||||
function calculateColor(percentage) {
|
||||
const hue = (percentage / max) * 120;
|
||||
return `color: hsl(${hue}, 100%, 60%);`;
|
||||
}
|
||||
|
||||
function calculateColorLoad(percentage) {
|
||||
const hue = Math.max((1 - percentage) * 120, 0);
|
||||
return `color: hsl(${hue}, 100%, 60%);`;
|
||||
setsData = (await import(`../../data/furnishing/sets/${locale}.json`)).default;
|
||||
parseSets();
|
||||
}
|
||||
|
||||
const saveData = debounce(async () => {
|
||||
const data = currentUsage;
|
||||
|
||||
const prefix = getAccountPrefix();
|
||||
await updateSave(`${prefix}furnishing`, data);
|
||||
}, 2000);
|
||||
await updateSave(`${prefix}furnishing-set-placed`, placed);
|
||||
await updateSave(`${prefix}furnishing-set-character`, character);
|
||||
}, 1000);
|
||||
|
||||
async function readLocalData() {
|
||||
const prefix = getAccountPrefix();
|
||||
const furnishingData = await readSave(`${prefix}furnishing`);
|
||||
if (furnishingData !== null) {
|
||||
currentUsage = {
|
||||
...currentUsage,
|
||||
...furnishingData,
|
||||
};
|
||||
function onCharFilterChanged() {
|
||||
if (!loading) {
|
||||
parseSets();
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
parseFurnishing();
|
||||
max = items[0].ratio;
|
||||
await readLocalData();
|
||||
|
||||
locale.subscribe((val) => {
|
||||
|
@ -163,203 +130,127 @@
|
|||
});
|
||||
});
|
||||
|
||||
// $: charFilter, onCharFilterChanged();
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Furnishing - Paimon.moe</title>
|
||||
<title>Furnishing Sets - Paimon.moe</title>
|
||||
<meta name="description" content="Genshin Impact Furnishing list with the load and energy values" />
|
||||
<meta property="og:description" content="Genshin Impact Furnishing list with the load and energy values" />
|
||||
</svelte:head>
|
||||
<div class="lg:ml-64 pt-20 lg:px-8 lg:pt-8 max-w-screen-xl">
|
||||
<div class="px-4 flex md:space-x-2 items-start md:items-center flex-col md:flex-row">
|
||||
<h1 class="font-display font-black text-3xl md:text-4xl text-white">{$t('furnishing.title')}</h1>
|
||||
<div class="flex items-center space-x-2">
|
||||
<div
|
||||
class="rounded-2xl border-2 border-white border-opacity-25 text-white px-4 py-2 group relative"
|
||||
style={calculateColorLoad(currentLoad.load / maxLoad[type])}
|
||||
>
|
||||
<Icon size={0.7} path={mdiInformationOutline} />
|
||||
{$t('furnishing.load')}
|
||||
{currentLoad.load} / {maxLoad[type]}
|
||||
<div
|
||||
class="hidden group-hover:block absolute left-0 transform translate-y-full
|
||||
bg-white rounded-xl z-50 text-gray-900 px-4 py-2 w-screen max-w-xs md:max-w-sm"
|
||||
style="bottom: -10px;"
|
||||
>
|
||||
<p>{$t('furnishing.info.0')}</p>
|
||||
<p>{$t('furnishing.info.1')}</p>
|
||||
<div class="lg:ml-64 pt-20 px-4 lg:px-8 lg:pt-8 max-w-screen-xl">
|
||||
<div class="flex flex-col md:flex-row items-center md:space-x-2 space-y-2 md:space-y-0">
|
||||
<h1 class="font-display font-black text-3xl md:text-4xl text-white">{$t('furnishing.sets.title')}</h1>
|
||||
<div>
|
||||
<a href="/furnishing/inventory">
|
||||
<Button>{$t('furnishing.inventoryButton')}</Button>
|
||||
</a>
|
||||
<a href="/furnishing/list">
|
||||
<Button>{$t('furnishing.listButton')}</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-2xl border-2 border-white border-opacity-25 text-white px-4 py-2">
|
||||
{$t('furnishing.energy')}
|
||||
{currentLoad.energy}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-4 flex space-x-2 mt-2 mb-2">
|
||||
<button on:click={() => changeType('hall')} class="pill {type.startsWith('exterior') ? '' : 'active'}">
|
||||
{$t('furnishing.interior')}
|
||||
</button>
|
||||
<button on:click={() => changeType('exterior')} class="pill {type.startsWith('exterior') ? 'active' : ''}">
|
||||
{$t('furnishing.exterior')}
|
||||
</button>
|
||||
</div>
|
||||
{#if type.startsWith('exterior')}
|
||||
<div class="px-4 flex space-x-2 mt-2 mb-4 overflow-x-auto">
|
||||
<button on:click={() => changeType('exterior')} class="pill {type === 'exterior' ? 'active' : ''}">
|
||||
{$t('furnishing.exteriorNum', { values: { number: 1 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('exterior2')} class="pill {type === 'exterior2' ? 'active' : ''}">
|
||||
{$t('furnishing.exteriorNum', { values: { number: 2 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('exterior3')} class="pill {type === 'exterior3' ? 'active' : ''}">
|
||||
{$t('furnishing.exteriorNum', { values: { number: 3 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('exterior4')} class="pill {type === 'exterior4' ? 'active' : ''}">
|
||||
{$t('furnishing.exteriorNum', { values: { number: 4 } })}
|
||||
</button>
|
||||
</div>
|
||||
{#if loading}
|
||||
<p class="text-white">Loading...</p>
|
||||
{:else}
|
||||
<div class="px-4 flex space-x-2 mt-2 mb-4 overflow-x-auto">
|
||||
<button on:click={() => changeType('hall')} class="pill {type === 'hall' ? 'active' : ''}">
|
||||
{$t('furnishing.hall')}
|
||||
</button>
|
||||
<button on:click={() => changeType('room1')} class="pill {type === 'room1' ? 'active' : ''}">
|
||||
{$t('furnishing.room', { values: { number: 1 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('room2')} class="pill {type === 'room2' ? 'active' : ''}">
|
||||
{$t('furnishing.room', { values: { number: 2 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('room3')} class="pill {type === 'room3' ? 'active' : ''}">
|
||||
{$t('furnishing.room', { values: { number: 3 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('corridor')} class="pill {type === 'corridor' ? 'active' : ''}">
|
||||
{$t('furnishing.corridor')}
|
||||
</button>
|
||||
<p class="text-gray-400 font-medium pb-2">
|
||||
※ {$t('furnishing.sets.subtitle')}
|
||||
</p>
|
||||
<div class="w-full md:w-64">
|
||||
<CharacterSelect bind:selected={charFilter} />
|
||||
</div>
|
||||
<div
|
||||
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-4 gap-2 flex-1 mt-2"
|
||||
style="height: fit-content;"
|
||||
>
|
||||
{#each sets as set (set.id)}
|
||||
{#if charFilter === null || (charFilter !== null && set.characters && set.characters.includes(charFilter.id))}
|
||||
<div class="text-white p-2 rounded-xl flex flex-col bg-item">
|
||||
<div class="w-full flex items-center justify-center relative">
|
||||
<img
|
||||
src="/images/furnishing/sets/{set.id}.png"
|
||||
alt=""
|
||||
class="w-full image relative object-contain rounded-xl"
|
||||
/>
|
||||
{#if placed[set.id]}
|
||||
<div class="text-green-300 absolute bottom-0 right-0 p-2">
|
||||
<Icon path={mdiCheckCircleOutline} size={1.5} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="mt-1 flex flex-col h-full">
|
||||
<p class="text-white mb-1">{set.name}</p>
|
||||
{#if set.gift}
|
||||
<div class="flex -m-1 py-1">
|
||||
{#each set.characters as char}
|
||||
<div class="relative cursor-pointer" on:click={() => checkCharacter(set.id, char)}>
|
||||
<img src="/images/characters/{char}.png" class="w-10 h-10 rounded-full m-1" alt={char} />
|
||||
{#if character[set.id]?.[char]}
|
||||
<div class="text-green-300 absolute bottom-0 right-0">
|
||||
<Icon path={mdiCheckCircleOutline} size={1} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex mt-4 wrapper">
|
||||
<div class="block overflow-x-auto xl:overflow-x-visible whitespace-no-wrap">
|
||||
<div class="px-4 table">
|
||||
<table class="w-full block pl-4 pr-4 py-2 md:pl-8 md:py-4 bg-item rounded-xl">
|
||||
<tr>
|
||||
<th />
|
||||
<TableHeader
|
||||
className="sticky top-0 bg-item z-30"
|
||||
on:click={() => sort('name')}
|
||||
sort={sortBy === 'name'}
|
||||
order={sortOrder}
|
||||
align="left"
|
||||
>
|
||||
{$t('furnishing.name')}
|
||||
</TableHeader>
|
||||
<TableHeader
|
||||
className="sticky top-0 bg-item z-30"
|
||||
on:click={() => sort('energy')}
|
||||
sort={sortBy === 'energy'}
|
||||
order={sortOrder}
|
||||
align="center"
|
||||
>
|
||||
{$t('furnishing.energy')}
|
||||
</TableHeader>
|
||||
<TableHeader
|
||||
className="sticky top-0 bg-item z-30"
|
||||
on:click={() => sort('load')}
|
||||
sort={sortBy === 'load'}
|
||||
order={sortOrder}
|
||||
align="center"
|
||||
>
|
||||
{$t('furnishing.load')}
|
||||
</TableHeader>
|
||||
<TableHeader
|
||||
className="sticky top-0 bg-item z-30"
|
||||
on:click={() => sort('ratio')}
|
||||
sort={sortBy === 'ratio'}
|
||||
order={sortOrder}
|
||||
align="center"
|
||||
>
|
||||
{$t('furnishing.ratio')}
|
||||
</TableHeader>
|
||||
<TableHeader
|
||||
className="sticky top-0 bg-item z-30"
|
||||
on:click={() => sort('using')}
|
||||
sort={sortBy === 'using'}
|
||||
order={sortOrder}
|
||||
align="center"
|
||||
>
|
||||
{$t('furnishing.using')}
|
||||
</TableHeader>
|
||||
</tr>
|
||||
{#each items as item (item.id)}
|
||||
<tr>
|
||||
<td class="pr-4 h-12">
|
||||
<img
|
||||
src="/images/furnishing/{item.id}.png"
|
||||
alt=""
|
||||
class="h-12 w-12 image relative"
|
||||
style="min-width: 3rem;"
|
||||
/>
|
||||
</td>
|
||||
<td class="px-4 text-gray-200">{item.name}</td>
|
||||
<td class="px-4 text-gray-200 text-center">{item.energy}</td>
|
||||
<td class="px-4 text-gray-200 text-center">{item.load}</td>
|
||||
<td class="px-4 text-gray-200 text-center" style={calculateColor(item.ratio)}>{item.ratio.toFixed(2)}</td>
|
||||
<td class="px-4">
|
||||
<div
|
||||
class="flex justify-between items-center border-2 border-white border-opacity-25 rounded-xl text-gray-400"
|
||||
>
|
||||
<button class="hover:text-primary" on:click={() => changeUsage(item.id, 1)}>
|
||||
<Icon path={mdiPlus} />
|
||||
</button>
|
||||
<p
|
||||
class="h-full px-2 text-center {currentUsage[type][item.id] > 0
|
||||
? 'text-gray-200'
|
||||
: 'text-gray-700'}"
|
||||
style="min-width: 40px;"
|
||||
>
|
||||
{currentUsage[type][item.id] || 0}
|
||||
</p>
|
||||
<button class="hover:text-primary" on:click={() => changeUsage(item.id, -1)}>
|
||||
<Icon path={mdiMinus} />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex -m-1 flex-wrap pt-1">
|
||||
{#each Object.entries(set.items) as [item, amount]}
|
||||
<button
|
||||
class="rounded-xl {set.enough[item] === true
|
||||
? 'bg-background'
|
||||
: 'bg-red-900'} text-white px-2 furnishing-item focus:outline-none filter"
|
||||
style="margin: 2px;"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<img src="/images/furnishing/{item}.png" class="w-8 h-8" alt={item} />
|
||||
<Icon path={mdiClose} size={0.5} />
|
||||
<span class="inline-block w-2">{amount}</span>
|
||||
</div>
|
||||
<div class="popup text-left">
|
||||
<p class="text-left mb-1">{furnishing[item].name}</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>{$t('furnishing.sets.inInventory')}</td>
|
||||
<td class="pl-2 text-center">{_saved[item] || 0}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{$t('furnishing.sets.used')}</td>
|
||||
<td class="pl-2 text-center">{used[item] || 0}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{$t('furnishing.sets.available')}</td>
|
||||
<td class="pl-2 text-center">{saved[item] || 0}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="flex-1" />
|
||||
<Button className="mt-2" disabled={!set.canBePlaced} on:click={() => place(set.id)}>
|
||||
{placed[set.id] ? $t('furnishing.sets.setUnplaced') : $t('furnishing.sets.setPlaced')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</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;
|
||||
@apply whitespace-no-wrap;
|
||||
|
||||
&:hover {
|
||||
@apply border-primary;
|
||||
.popup {
|
||||
@apply text-sm pt-1 hidden p-2 rounded-xl;
|
||||
}
|
||||
|
||||
&.active {
|
||||
@apply bg-primary;
|
||||
@apply border-primary;
|
||||
@apply text-background;
|
||||
}
|
||||
}
|
||||
.furnishing-item:focus {
|
||||
@apply w-full;
|
||||
|
||||
.image[alt]:after {
|
||||
@apply block absolute top-0 left-0 w-full h-full bg-item;
|
||||
content: '';
|
||||
.popup {
|
||||
@apply block;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,266 @@
|
|||
<script context="module">
|
||||
import data from '../../data/furnishing/en.json';
|
||||
import categories from '../../data/furnishing/category/en.json';
|
||||
export async function preload() {
|
||||
return { data, categories };
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { locale, t } from 'svelte-i18n';
|
||||
import { onMount, tick } from 'svelte';
|
||||
import { mdiMinus, mdiPlus } from '@mdi/js';
|
||||
import debounce from 'lodash/debounce';
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
import { readSave, updateSave } from '../../stores/saveManager';
|
||||
import { getAccountPrefix } from '../../stores/account';
|
||||
import Button from '../../components/Button.svelte';
|
||||
|
||||
export let data;
|
||||
export let categories;
|
||||
|
||||
let loading = true;
|
||||
let active = {
|
||||
name: 'all',
|
||||
type: 'all',
|
||||
};
|
||||
let inventoryContainer;
|
||||
let categoryList = [];
|
||||
let categoryData = {
|
||||
'all-all': {
|
||||
items: [],
|
||||
count: {},
|
||||
},
|
||||
};
|
||||
let saved = {};
|
||||
|
||||
async function parseFurnishing() {
|
||||
categoryList = categories;
|
||||
|
||||
categoryData = {
|
||||
'all-all': {
|
||||
items: [],
|
||||
count: {},
|
||||
},
|
||||
};
|
||||
|
||||
for (const category of categories) {
|
||||
const categoryId = `${category.category}-${category.type}`;
|
||||
categoryData[categoryId] = {
|
||||
items: [],
|
||||
count: {},
|
||||
};
|
||||
}
|
||||
|
||||
for (const item of Object.values(data)) {
|
||||
if (item.category.category === 'Companion') continue;
|
||||
|
||||
if (item.category.type !== '') {
|
||||
const categoryId = `${item.category.category}-${item.category.type}`;
|
||||
categoryData[categoryId].items.push(item);
|
||||
categoryData['all-all'].items.push(item);
|
||||
if (saved[item.id] && saved[item.id] > 0) {
|
||||
categoryData[categoryId].count[item.id] = true;
|
||||
categoryData['all-all'].count[item.id] = true;
|
||||
}
|
||||
} else {
|
||||
const categoryIdEx = `${item.category.category}-exterior`;
|
||||
const categoryIdIn = `${item.category.category}-interior`;
|
||||
|
||||
categoryData[categoryIdEx]?.items.push(item);
|
||||
categoryData[categoryIdIn]?.items.push(item);
|
||||
categoryData['all-all'].items.push(item);
|
||||
if (saved[item.id] && saved[item.id] > 0) {
|
||||
if (categoryData[categoryIdEx]) categoryData[categoryIdEx].count[item.id] = true;
|
||||
if (categoryData[categoryIdIn]) categoryData[categoryIdIn].count[item.id] = true;
|
||||
categoryData['all-all'].count[item.id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
async function changeCategory(category) {
|
||||
active = category;
|
||||
await tick();
|
||||
inventoryContainer.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
|
||||
async function readLocalData() {
|
||||
const prefix = getAccountPrefix();
|
||||
const savedIventory = await readSave(`${prefix}furnishing-inventory`);
|
||||
if (savedIventory !== null) {
|
||||
saved = savedIventory;
|
||||
}
|
||||
}
|
||||
|
||||
const saveData = debounce(async () => {
|
||||
const prefix = getAccountPrefix();
|
||||
await updateSave(`${prefix}furnishing-inventory`, saved);
|
||||
}, 1000);
|
||||
|
||||
function changeItemValue(id, val) {
|
||||
saved[id] = Math.max(0, val);
|
||||
if (saved[id] === 0) {
|
||||
delete categoryData[`${active.name}-${active.type}`].count[id];
|
||||
categoryData = categoryData;
|
||||
} else {
|
||||
categoryData[`${active.name}-${active.type}`].count[id] = true;
|
||||
}
|
||||
saveData();
|
||||
}
|
||||
|
||||
async function changeLocale(locale) {
|
||||
categories = (await import(`../../data/furnishing/category/${locale}.json`)).default;
|
||||
data = (await import(`../../data/furnishing/${locale}.json`)).default;
|
||||
parseFurnishing();
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
await readLocalData();
|
||||
|
||||
locale.subscribe((val) => {
|
||||
changeLocale(val);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Furnishing Inventory - Paimon.moe</title>
|
||||
<meta name="description" content="Genshin Impact Furnishing list with the load and energy values" />
|
||||
<meta property="og:description" content="Genshin Impact Furnishing list with the load and energy values" />
|
||||
</svelte:head>
|
||||
<div class="lg:ml-64 pt-20 px-4 lg:px-8 lg:pt-8 max-w-screen-xl">
|
||||
<div class="flex flex-col md:flex-row items-center md:space-x-2 space-y-2 md:space-y-0">
|
||||
<h1 class="font-display font-black text-3xl md:text-4xl text-white">{$t('furnishing.inventory.title')}</h1>
|
||||
<a href="/furnishing">
|
||||
<Button>{$t('furnishing.inventory.openSets')}</Button>
|
||||
</a>
|
||||
</div>
|
||||
{#if loading}
|
||||
<p class="text-white">Loading...</p>
|
||||
{:else}
|
||||
<p class="text-gray-400 font-medium pb-2">
|
||||
※ {$t('furnishing.inventory.subtitle')}
|
||||
</p>
|
||||
|
||||
<div class="flex flex-col lg:flex-row space-y-3 lg:space-y-0 lg:space-x-3 mt-4 md:mt-0">
|
||||
<div class="flex flex-col space-y-2 lg:h-screen lg:overflow-auto lg:sticky lg:pr-1 pb-4 category">
|
||||
<div
|
||||
on:click={() => changeCategory({ name: 'all', type: 'all' })}
|
||||
class="rounded-xl p-2 cursor-pointer flex text-white {active.name === 'all' ? 'bg-primary' : 'bg-item'}"
|
||||
>
|
||||
<p class="flex-1">{$t('furnishing.inventory.all')}</p>
|
||||
<!-- <p class={Object.keys(categoryData['all-all'].count).length === 0 ? 'text-gray-600' : 'text-white'}>
|
||||
{Object.keys(categoryData['all-all'].count).length}
|
||||
</p> -->
|
||||
</div>
|
||||
{#each categoryList as category (`${category.category}-${category.type}`)}
|
||||
{#if categoryData[`${category.category}-${category.type}`].items.length > 0}
|
||||
<div
|
||||
on:click={() => changeCategory({ name: category.category, type: category.type })}
|
||||
class="rounded-xl p-2 cursor-pointer flex text-white {category.category === active.name &&
|
||||
category.type === active.type
|
||||
? 'bg-primary'
|
||||
: 'bg-item'}"
|
||||
>
|
||||
<p class="flex-1">{category.name}</p>
|
||||
<p
|
||||
class={Object.keys(categoryData[`${category.category}-${category.type}`].count).length === 0
|
||||
? 'text-gray-600'
|
||||
: 'text-white'}
|
||||
>
|
||||
{Object.keys(categoryData[`${category.category}-${category.type}`].count).length}
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<div
|
||||
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-4 gap-2 flex-1 pt-20 lg:pt-2"
|
||||
style="height: max-content;"
|
||||
bind:this={inventoryContainer}
|
||||
>
|
||||
{#each categoryData[`${active.name}-${active.type}`].items as item (item.id)}
|
||||
<div class="text-white p-2 rounded-xl flex bg-item">
|
||||
<div class="h-16 w-16 flex items-center justify-center">
|
||||
<img
|
||||
src="/images/furnishing/{item.id}.png"
|
||||
alt=""
|
||||
class="h-16 w-16 image relative"
|
||||
style="min-width: 4rem;"
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-2 flex flex-col">
|
||||
<p class="text-sm flex-1">
|
||||
{item.name}
|
||||
</p>
|
||||
<div class="flex items-center bg-black bg-opacity-25 rounded-md" style="width: max-content;">
|
||||
<button class="hover:text-primary" on:click={() => changeItemValue(item.id, (saved[item.id] || 0) + 1)}>
|
||||
<Icon path={mdiPlus} />
|
||||
</button>
|
||||
<input
|
||||
type="number"
|
||||
value={saved[item.id] || 0}
|
||||
on:change={(e) => changeItemValue(item.id, e.target.value)}
|
||||
class="bg-transparent w-12 text-center {(saved[item.id] || 0) > 0 ? 'text-white' : 'text-gray-600'}"
|
||||
/>
|
||||
<button class="hover:text-primary" on:click={() => changeItemValue(item.id, (saved[item.id] || 0) - 1)}>
|
||||
<Icon path={mdiMinus} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.category {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@screen lg {
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
@apply bg-transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
@apply rounded-xl;
|
||||
}
|
||||
|
||||
.category {
|
||||
min-width: 15rem;
|
||||
width: 15rem;
|
||||
top: 0px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.image[alt]:after {
|
||||
@apply block absolute top-0 left-0 w-full h-full bg-item;
|
||||
content: '';
|
||||
}
|
||||
|
||||
input[type='number'] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,381 @@
|
|||
<script context="module">
|
||||
import data from '../../data/furnishing/en.json';
|
||||
export async function preload() {
|
||||
return { data };
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { locale, t } from 'svelte-i18n';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { mdiInformationOutline, mdiMinus, mdiPlus } from '@mdi/js';
|
||||
|
||||
import TableHeader from '../../components/Table/TableHeader.svelte';
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
import Button from '../../components/Button.svelte';
|
||||
import { getAccountPrefix } from '../../stores/account';
|
||||
import { readSave, updateSave } from '../../stores/saveManager';
|
||||
|
||||
export let data;
|
||||
|
||||
let type = 'hall';
|
||||
let items = [];
|
||||
let max = 0;
|
||||
|
||||
const minEnergy = {
|
||||
exterior: 0,
|
||||
exterior2: 0,
|
||||
exterior3: 0,
|
||||
exterior4: 0,
|
||||
hall: 150,
|
||||
room1: 150,
|
||||
room2: 150,
|
||||
room3: 150,
|
||||
room4: 150,
|
||||
room5: 150,
|
||||
corridor: 150,
|
||||
};
|
||||
const maxLoad = {
|
||||
exterior: 10000,
|
||||
exterior2: 10000,
|
||||
exterior3: 10000,
|
||||
exterior4: 10000,
|
||||
hall: 10000,
|
||||
room1: 4000,
|
||||
room2: 4000,
|
||||
room3: 4000,
|
||||
room4: 4000,
|
||||
room5: 4000,
|
||||
corridor: 4000,
|
||||
};
|
||||
let currentUsage = {
|
||||
exterior: {},
|
||||
exterior2: {},
|
||||
exterior3: {},
|
||||
exterior4: {},
|
||||
hall: {},
|
||||
room1: {},
|
||||
room2: {},
|
||||
room3: {},
|
||||
room4: {},
|
||||
room5: {},
|
||||
corridor: {},
|
||||
};
|
||||
$: currentLoad = Object.entries(currentUsage[type]).reduce(
|
||||
(prev, [id, val]) => {
|
||||
prev.load += data[id].load * val;
|
||||
prev.energy += data[id].energy * val;
|
||||
return prev;
|
||||
},
|
||||
{
|
||||
load: 0,
|
||||
energy: minEnergy[type],
|
||||
},
|
||||
);
|
||||
|
||||
let sortBy = 'ratio';
|
||||
let sortOrder = false;
|
||||
|
||||
async function parseFurnishing() {
|
||||
const currentType = type.startsWith('exterior') ? 'exterior' : 'interior';
|
||||
items = Object.values(data)
|
||||
.filter((e) => e.type === currentType || e.type === '')
|
||||
.sort((a, b) => {
|
||||
switch (sortBy) {
|
||||
case 'ratio':
|
||||
if (sortOrder) return a.ratio - b.ratio;
|
||||
else return b.ratio - a.ratio;
|
||||
case 'energy':
|
||||
if (sortOrder) return a.energy - b.energy;
|
||||
else return b.energy - a.energy;
|
||||
case 'load':
|
||||
if (sortOrder) return a.load - b.load;
|
||||
else return b.load - a.load;
|
||||
case 'using':
|
||||
if (sortOrder) return (currentUsage[type][a.id] || 0) - (currentUsage[type][b.id] || 0);
|
||||
else return (currentUsage[type][b.id] || 0) - (currentUsage[type][a.id] || 0);
|
||||
case 'name':
|
||||
if (sortOrder) return a.name.localeCompare(b.name);
|
||||
else return b.name.localeCompare(a.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sort(by) {
|
||||
if (sortBy === by) {
|
||||
sortOrder = !sortOrder;
|
||||
} else {
|
||||
sortBy = by;
|
||||
}
|
||||
parseFurnishing();
|
||||
}
|
||||
|
||||
function changeType(_type) {
|
||||
type = _type;
|
||||
sortBy = 'ratio';
|
||||
sortOrder = false;
|
||||
parseFurnishing();
|
||||
max = items[0].ratio;
|
||||
}
|
||||
|
||||
function changeUsage(id, val) {
|
||||
if (currentUsage[type][id] === undefined) currentUsage[type][id] = 0;
|
||||
currentUsage[type][id] = Math.max(0, currentUsage[type][id] + val);
|
||||
if (currentUsage[type][id] === 0) delete currentUsage[type][id];
|
||||
saveData();
|
||||
}
|
||||
|
||||
async function changeLocale(locale) {
|
||||
data = (await import(`../../data/furnishing/${locale}.json`)).default;
|
||||
parseFurnishing();
|
||||
}
|
||||
|
||||
function calculateColor(percentage) {
|
||||
const hue = (percentage / max) * 120;
|
||||
return `color: hsl(${hue}, 100%, 60%);`;
|
||||
}
|
||||
|
||||
function calculateColorLoad(percentage) {
|
||||
const hue = Math.max((1 - percentage) * 120, 0);
|
||||
return `color: hsl(${hue}, 100%, 60%);`;
|
||||
}
|
||||
|
||||
const saveData = debounce(async () => {
|
||||
const data = currentUsage;
|
||||
|
||||
const prefix = getAccountPrefix();
|
||||
await updateSave(`${prefix}furnishing`, data);
|
||||
}, 2000);
|
||||
|
||||
async function readLocalData() {
|
||||
const prefix = getAccountPrefix();
|
||||
const furnishingData = await readSave(`${prefix}furnishing`);
|
||||
if (furnishingData !== null) {
|
||||
currentUsage = {
|
||||
...currentUsage,
|
||||
...furnishingData,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
parseFurnishing();
|
||||
max = items[0].ratio;
|
||||
await readLocalData();
|
||||
|
||||
locale.subscribe((val) => {
|
||||
changeLocale(val);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Furnishing - Paimon.moe</title>
|
||||
<meta name="description" content="Genshin Impact Furnishing list with the load and energy values" />
|
||||
<meta property="og:description" content="Genshin Impact Furnishing list with the load and energy values" />
|
||||
</svelte:head>
|
||||
<div class="lg:ml-64 pt-20 lg:px-8 lg:pt-8 max-w-screen-xl">
|
||||
<div class="px-4 flex md:space-x-2 items-start md:items-center flex-col md:flex-row">
|
||||
<h1 class="font-display font-black text-3xl md:text-4xl text-white">{$t('furnishing.title')}</h1>
|
||||
<div class="flex items-center space-x-2">
|
||||
<div
|
||||
class="rounded-2xl border-2 border-white border-opacity-25 text-white px-4 py-2 group relative"
|
||||
style={calculateColorLoad(currentLoad.load / maxLoad[type])}
|
||||
>
|
||||
<Icon size={0.7} path={mdiInformationOutline} />
|
||||
{$t('furnishing.load')}
|
||||
{currentLoad.load} / {maxLoad[type]}
|
||||
<div
|
||||
class="hidden group-hover:block absolute left-0 transform translate-y-full
|
||||
bg-white rounded-xl z-50 text-gray-900 px-4 py-2 w-screen max-w-xs md:max-w-sm"
|
||||
style="bottom: -10px;"
|
||||
>
|
||||
<p>{$t('furnishing.info.0')}</p>
|
||||
<p>{$t('furnishing.info.1')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-2xl border-2 border-white border-opacity-25 text-white px-4 py-2">
|
||||
{$t('furnishing.energy')}
|
||||
{currentLoad.energy}
|
||||
</div>
|
||||
<a href="/furnishing">
|
||||
<Button>{$t('furnishing.inventory.openSets')}</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-4 flex space-x-2 mt-2 mb-2">
|
||||
<button on:click={() => changeType('hall')} class="pill {type.startsWith('exterior') ? '' : 'active'}">
|
||||
{$t('furnishing.interior')}
|
||||
</button>
|
||||
<button on:click={() => changeType('exterior')} class="pill {type.startsWith('exterior') ? 'active' : ''}">
|
||||
{$t('furnishing.exterior')}
|
||||
</button>
|
||||
</div>
|
||||
{#if type.startsWith('exterior')}
|
||||
<div class="px-4 flex space-x-2 mt-2 mb-4 overflow-x-auto">
|
||||
<button on:click={() => changeType('exterior')} class="pill {type === 'exterior' ? 'active' : ''}">
|
||||
{$t('furnishing.exteriorNum', { values: { number: 1 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('exterior2')} class="pill {type === 'exterior2' ? 'active' : ''}">
|
||||
{$t('furnishing.exteriorNum', { values: { number: 2 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('exterior3')} class="pill {type === 'exterior3' ? 'active' : ''}">
|
||||
{$t('furnishing.exteriorNum', { values: { number: 3 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('exterior4')} class="pill {type === 'exterior4' ? 'active' : ''}">
|
||||
{$t('furnishing.exteriorNum', { values: { number: 4 } })}
|
||||
</button>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="px-4 flex space-x-2 mt-2 mb-4 overflow-x-auto">
|
||||
<button on:click={() => changeType('hall')} class="pill {type === 'hall' ? 'active' : ''}">
|
||||
{$t('furnishing.hall')}
|
||||
</button>
|
||||
<button on:click={() => changeType('room1')} class="pill {type === 'room1' ? 'active' : ''}">
|
||||
{$t('furnishing.room', { values: { number: 1 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('room2')} class="pill {type === 'room2' ? 'active' : ''}">
|
||||
{$t('furnishing.room', { values: { number: 2 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('room3')} class="pill {type === 'room3' ? 'active' : ''}">
|
||||
{$t('furnishing.room', { values: { number: 3 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('corridor')} class="pill {type === 'corridor' ? 'active' : ''}">
|
||||
{$t('furnishing.corridor')}
|
||||
</button>
|
||||
<button on:click={() => changeType('room4')} class="pill {type === 'room4' ? 'active' : ''}">
|
||||
{$t('furnishing.room', { values: { number: 4 } })}
|
||||
</button>
|
||||
<button on:click={() => changeType('room5')} class="pill {type === 'room5' ? 'active' : ''}">
|
||||
{$t('furnishing.room', { values: { number: 5 } })}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex mt-4 wrapper">
|
||||
<div class="block overflow-x-auto xl:overflow-x-visible whitespace-no-wrap">
|
||||
<div class="px-4 table">
|
||||
<table class="w-full block pl-4 pr-4 py-2 md:pl-8 md:py-4 bg-item rounded-xl">
|
||||
<tr>
|
||||
<th />
|
||||
<TableHeader
|
||||
className="sticky top-0 bg-item z-30"
|
||||
on:click={() => sort('name')}
|
||||
sort={sortBy === 'name'}
|
||||
order={sortOrder}
|
||||
align="left"
|
||||
>
|
||||
{$t('furnishing.name')}
|
||||
</TableHeader>
|
||||
<TableHeader
|
||||
className="sticky top-0 bg-item z-30"
|
||||
on:click={() => sort('energy')}
|
||||
sort={sortBy === 'energy'}
|
||||
order={sortOrder}
|
||||
align="center"
|
||||
>
|
||||
{$t('furnishing.energy')}
|
||||
</TableHeader>
|
||||
<TableHeader
|
||||
className="sticky top-0 bg-item z-30"
|
||||
on:click={() => sort('load')}
|
||||
sort={sortBy === 'load'}
|
||||
order={sortOrder}
|
||||
align="center"
|
||||
>
|
||||
{$t('furnishing.load')}
|
||||
</TableHeader>
|
||||
<TableHeader
|
||||
className="sticky top-0 bg-item z-30"
|
||||
on:click={() => sort('ratio')}
|
||||
sort={sortBy === 'ratio'}
|
||||
order={sortOrder}
|
||||
align="center"
|
||||
>
|
||||
{$t('furnishing.ratio')}
|
||||
</TableHeader>
|
||||
<TableHeader
|
||||
className="sticky top-0 bg-item z-30"
|
||||
on:click={() => sort('using')}
|
||||
sort={sortBy === 'using'}
|
||||
order={sortOrder}
|
||||
align="center"
|
||||
>
|
||||
{$t('furnishing.using')}
|
||||
</TableHeader>
|
||||
</tr>
|
||||
{#each items as item (item.id)}
|
||||
<tr>
|
||||
<td class="pr-4 h-12">
|
||||
<img
|
||||
src="/images/furnishing/{item.id}.png"
|
||||
alt=""
|
||||
class="h-12 w-12 image relative"
|
||||
style="min-width: 3rem;"
|
||||
/>
|
||||
</td>
|
||||
<td class="px-4 text-gray-200">{item.name}</td>
|
||||
<td class="px-4 text-gray-200 text-center">{item.energy}</td>
|
||||
<td class="px-4 text-gray-200 text-center">{item.load}</td>
|
||||
<td class="px-4 text-gray-200 text-center" style={calculateColor(item.ratio)}>{item.ratio.toFixed(2)}</td>
|
||||
<td class="px-4">
|
||||
<div
|
||||
class="flex justify-between items-center border-2 border-white border-opacity-25 rounded-xl text-gray-400"
|
||||
>
|
||||
<button class="hover:text-primary" on:click={() => changeUsage(item.id, 1)}>
|
||||
<Icon path={mdiPlus} />
|
||||
</button>
|
||||
<p
|
||||
class="h-full px-2 text-center {currentUsage[type][item.id] > 0
|
||||
? 'text-gray-200'
|
||||
: 'text-gray-700'}"
|
||||
style="min-width: 40px;"
|
||||
>
|
||||
{currentUsage[type][item.id] || 0}
|
||||
</p>
|
||||
<button class="hover:text-primary" on:click={() => changeUsage(item.id, -1)}>
|
||||
<Icon path={mdiMinus} />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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;
|
||||
@apply whitespace-no-wrap;
|
||||
|
||||
&:hover {
|
||||
@apply border-primary;
|
||||
}
|
||||
|
||||
&.active {
|
||||
@apply bg-primary;
|
||||
@apply border-primary;
|
||||
@apply text-background;
|
||||
}
|
||||
}
|
||||
|
||||
.image[alt]:after {
|
||||
@apply block absolute top-0 left-0 w-full h-full bg-item;
|
||||
content: '';
|
||||
}
|
||||
|
||||
</style>
|
|
@ -15,6 +15,7 @@
|
|||
import Discord from './_index/discord.svelte';
|
||||
import Twitter from './_index/twitter.svelte';
|
||||
import Achievement from './_index/achievement.svelte';
|
||||
import Furnishing from './_index/furnishing.svelte';
|
||||
|
||||
let refreshLayout;
|
||||
|
||||
|
@ -59,6 +60,7 @@
|
|||
<Calculator on:done={onDone} />
|
||||
<Achievement on:done={onDone} />
|
||||
<Twitter on:done={onDone} />
|
||||
<Furnishing on:done={onDone} />
|
||||
<!-- <div class="flex flex-col space-y-4">
|
||||
</div> -->
|
||||
</Masonry>
|
||||
|
|
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 281 KiB |
After Width: | Height: | Size: 360 KiB |
After Width: | Height: | Size: 343 KiB |
After Width: | Height: | Size: 342 KiB |
After Width: | Height: | Size: 424 KiB |
After Width: | Height: | Size: 319 KiB |
After Width: | Height: | Size: 323 KiB |
After Width: | Height: | Size: 347 KiB |
After Width: | Height: | Size: 355 KiB |
After Width: | Height: | Size: 389 KiB |
After Width: | Height: | Size: 377 KiB |
After Width: | Height: | Size: 357 KiB |
After Width: | Height: | Size: 423 KiB |
After Width: | Height: | Size: 359 KiB |
After Width: | Height: | Size: 329 KiB |
After Width: | Height: | Size: 371 KiB |
After Width: | Height: | Size: 358 KiB |
After Width: | Height: | Size: 332 KiB |
After Width: | Height: | Size: 399 KiB |
After Width: | Height: | Size: 284 KiB |
After Width: | Height: | Size: 405 KiB |
After Width: | Height: | Size: 419 KiB |
After Width: | Height: | Size: 627 KiB |
After Width: | Height: | Size: 416 KiB |
After Width: | Height: | Size: 374 KiB |
After Width: | Height: | Size: 395 KiB |
After Width: | Height: | Size: 428 KiB |
After Width: | Height: | Size: 304 KiB |
After Width: | Height: | Size: 641 KiB |
After Width: | Height: | Size: 368 KiB |
After Width: | Height: | Size: 415 KiB |
After Width: | Height: | Size: 379 KiB |
After Width: | Height: | Size: 328 KiB |
After Width: | Height: | Size: 392 KiB |
After Width: | Height: | Size: 295 KiB |
After Width: | Height: | Size: 375 KiB |
After Width: | Height: | Size: 350 KiB |
After Width: | Height: | Size: 364 KiB |
After Width: | Height: | Size: 308 KiB |
After Width: | Height: | Size: 383 KiB |
After Width: | Height: | Size: 343 KiB |
After Width: | Height: | Size: 389 KiB |
After Width: | Height: | Size: 398 KiB |
After Width: | Height: | Size: 307 KiB |
After Width: | Height: | Size: 330 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 5.6 KiB |