Add fishing spot timer

pull/1/head
Made Baruna 2021-10-15 17:26:24 +07:00
parent 3b7767085c
commit 2c25647c0c
No known key found for this signature in database
GPG Key ID: 5AA5DA16AA5DCEAD
59 changed files with 318 additions and 102 deletions

View File

@ -8,20 +8,24 @@
let px = 'px-4';
let py = 'py-2';
let textColor = 'white';
let borderColor = 'white';
let borderColorHover = 'white';
let borderColorFocus = 'white';
$: switch (color) {
case 'blue':
textColor = 'text-white';
borderColor = 'border-primary';
borderColorHover = 'hover:border-primary';
borderColorFocus = 'focus:border-primary';
break;
case 'red':
textColor = 'text-red-400';
borderColor = 'border-red-400';
borderColorHover = 'hover:border-red-400';
borderColorFocus = 'focus:border-red-400';
break;
case 'green':
textColor = 'text-green-400';
borderColor = 'border-green-400';
borderColorHover = 'hover:border-green-400';
borderColorFocus = 'focus:border-green-400';
break;
}
@ -42,7 +46,7 @@
class="{textColor} border-2 border-white border-opacity-25 {rounded
? 'rounded-xl'
: 'rounded-none'} {px} {py} transition duration-100
hover:{borderColor} focus:outline-none focus:{borderColor} disabled:opacity-50 disabled:border-gray-600 {className}"
{borderColorHover} {borderColorFocus} focus:outline-none disabled:opacity-50 disabled:border-gray-600 {className}"
on:click
>
<slot />

View File

@ -196,7 +196,6 @@
const data = await getData();
remoteSave = data;
console.log(JSON.stringify(remoteSave));
const remoteSize = new Blob([JSON.stringify(remoteSave)]).size / 1000;
const localSave = await getLocalSaveJson();

View File

@ -1,16 +1,15 @@
{
"cider_lake": {
"name": "Cider Lake",
"17668": {
"name": "Windrise",
"fish": [
"medaka",
"aizen_medaka",
"crystalfish",
"venomspine_fish",
"rusty_koi",
"tea-colored_shirakodai"
],
"location": "mondstadt"
},
"stormbearer_mountains": {
"17669": {
"name": "Stormbearer Mountains",
"fish": [
"medaka",
@ -23,7 +22,17 @@
],
"location": "mondstadt"
},
"stormterrors_lair": {
"17670": {
"name": "Stormterror's Lair",
"fish": [
"medaka",
"aizen_medaka",
"dawncatcher",
"tea-colored_shirakodai"
],
"location": "mondstadt"
},
"17671": {
"name": "Stormterror's Lair",
"fish": [
"medaka",
@ -33,17 +42,31 @@
],
"location": "mondstadt"
},
"windrise": {
"name": "Windrise",
"17672": {
"name": "Cider Lake",
"fish": [
"medaka",
"aizen_medaka",
"venomspine_fish",
"akai_maou",
"tea-colored_shirakodai",
"pufferfish",
"bitter_pufferfish"
],
"location": "mondstadt"
},
"17673": {
"name": "Cider Lake",
"fish": [
"aizen_medaka",
"crystalfish",
"venomspine_fish",
"rusty_koi",
"tea-colored_shirakodai"
],
"location": "mondstadt"
},
"near_dawn_winery": {
"17674": {
"name": "Near Dawn Winery",
"fish": [
"aizen_medaka",
@ -56,7 +79,7 @@
],
"location": "mondstadt"
},
"dragonspine": {
"17676": {
"name": "Dragonspine",
"fish": [
"medaka",
@ -66,7 +89,7 @@
],
"location": "mondstadt"
},
"qingce_village": {
"17675": {
"name": "Qingce Village",
"fish": [
"sweet-flower_medaka",
@ -78,7 +101,7 @@
],
"location": "liyue"
},
"dihua_marsh": {
"17677": {
"name": "Dihua Marsh",
"fish": [
"medaka",
@ -88,31 +111,16 @@
],
"location": "liyue"
},
"beside_wangshu_inn": {
"name": "Beside Wangshu Inn",
"17678": {
"name": "Bishui Plain",
"fish": [
"sweet-flower_medaka",
"medaka",
"betta",
"akai_maou",
"golden_koi",
"rusty_koi",
"brown_shirakodai"
],
"location": "liyue"
},
"beside_guili_plains": {
"name": "Beside Guili Plains",
"fish": [
"sweet-flower_medaka",
"betta",
"akai_maou",
"golden_koi",
"rusty_koi",
"brown_shirakodai"
],
"location": "liyue"
},
"bishui_plain": {
"17679": {
"name": "Bishui Plain",
"fish": [
"medaka",
@ -122,7 +130,18 @@
],
"location": "liyue"
},
"mt._hulao": {
"17680": {
"name": "Mt. Aocang",
"fish": [
"medaka",
"sweet-flower_medaka",
"dawncatcher",
"crystalfish",
"abiding_angelfish"
],
"location": "liyue"
},
"17681": {
"name": "Mt. Hulao",
"fish": [
"medaka",
@ -134,7 +153,28 @@
],
"location": "liyue"
},
"luhua_pool": {
"17682": {
"name": "Beside Wangshu Inn",
"fish": [
"sweet-flower_medaka",
"betta",
"akai_maou",
"golden_koi",
"rusty_koi",
"brown_shirakodai"
],
"location": "liyue"
},
"17683": {
"name": "Tianqiu Valley",
"fish": [
"medaka",
"crystalfish",
"betta"
],
"location": "liyue"
},
"17684": {
"name": "Luhua Pool",
"fish": [
"sweet-flower_medaka",
@ -146,16 +186,19 @@
],
"location": "liyue"
},
"tianqiu_valley": {
"name": "Tianqiu Valley",
"17685": {
"name": "Beside Guili Plains",
"fish": [
"medaka",
"crystalfish",
"betta"
"sweet-flower_medaka",
"betta",
"akai_maou",
"golden_koi",
"rusty_koi",
"brown_shirakodai"
],
"location": "liyue"
},
"liyue_harbor": {
"17686": {
"name": "Liyue Harbor",
"fish": [
"sweet-flower_medaka",
@ -166,48 +209,7 @@
],
"location": "liyue"
},
"mt._aocang": {
"name": "Mt. Aocang",
"fish": [
"medaka",
"sweet-flower_medaka",
"dawncatcher",
"crystalfish",
"abiding_angelfish"
],
"location": "liyue"
},
"ritou": {
"name": "Ritou",
"fish": [
"glaze_medaka",
"lunged_stickleback",
"akai_maou",
"pufferfish",
"bitter_pufferfish"
],
"location": "inazuma"
},
"near_amakane_island": {
"name": "Near Amakane Island",
"fish": [
"glaze_medaka",
"lunged_stickleback",
"purple_shirakodai"
],
"location": "inazuma"
},
"nazuchi_beach": {
"name": "Nazuchi Beach",
"fish": [
"medaka",
"lunged_stickleback",
"purple_shirakodai",
"bitter_pufferfish"
],
"location": "inazuma"
},
"sangonomiya_shrine": {
"17687": {
"name": "Sangonomiya Shrine",
"fish": [
"medaka",
@ -219,7 +221,7 @@
],
"location": "inazuma"
},
"suigetsu_pool": {
"17688": {
"name": "Suigetsu Pool",
"fish": [
"medaka",
@ -231,7 +233,35 @@
],
"location": "inazuma"
},
"koseki_village": {
"17689": {
"name": "Nazuchi Beach",
"fish": [
"medaka",
"lunged_stickleback",
"purple_shirakodai",
"bitter_pufferfish"
],
"location": "inazuma"
},
"17690": {
"name": "Tatarasuna",
"fish": [
"raimei_angelfish"
],
"location": "inazuma"
},
"17691": {
"name": "Near Koseki Village",
"fish": [
"medaka",
"dawncatcher",
"crystalfish",
"purple_shirakodai",
"pufferfish"
],
"location": "inazuma"
},
"17694": {
"name": "Koseki Village",
"fish": [
"glaze_medaka",
@ -243,21 +273,33 @@
],
"location": "inazuma"
},
"near_koseki_village": {
"name": "Near Koseki Village",
"17692": {
"name": "Ritou",
"fish": [
"medaka",
"dawncatcher",
"crystalfish",
"purple_shirakodai",
"pufferfish"
"glaze_medaka",
"lunged_stickleback",
"akai_maou",
"pufferfish",
"bitter_pufferfish"
],
"location": "inazuma"
},
"tatarasuna": {
"name": "Tatarasuna",
"17693": {
"name": "Near Amakane Island",
"fish": [
"raimei_angelfish"
"glaze_medaka",
"lunged_stickleback",
"purple_shirakodai"
],
"location": "inazuma"
},
"18686": {
"name": "Chirai Shrine",
"fish": [
"medaka",
"glaze_medaka",
"dawncatcher",
"crystalfish"
],
"location": "inazuma"
}

View File

@ -761,8 +761,14 @@
},
"fishing": {
"title": "Fishing Book",
"subtitle": "Mark the fishing spot as empty when you already fish out all the fish to start the respawn timer",
"mondstadt": "Mondstadt",
"liyue": "Liyue",
"inazuma": "Inazuma"
"inazuma": "Inazuma",
"setEmpty": "Set as empty",
"emptyTime": "Time when the spot is empty:",
"clear": "Clear",
"save": "Save",
"cancel": "Cancel"
}
}

View File

@ -9,6 +9,9 @@
<h1 class="font-display px-4 md:px-8 font-black text-5xl text-white">{$t('settings.changelog')}</h1>
<pre
class="text-white px-4 md:px-8">
2021/10/15
- Add fishing spot timer
2021/10/13
- Update weapons
- Update achievements

View File

@ -0,0 +1,29 @@
<script>
import dayjs from 'dayjs';
import { t } from 'svelte-i18n';
import Button from '../../components/Button.svelte';
import Input from '../../components/Input.svelte';
export let time;
export let close;
export let clear;
export let edit;
function save() {
const updatedTime = dayjs(time);
edit(updatedTime);
}
</script>
<div>
<p class="text-white mb-4">{$t('fishing.emptyTime')}</p>
<Input type="datetime-local" pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}" bind:value={time} />
<div class="flex space-x-2 mt-4">
<Button on:click={clear} color="red">{$t('fishing.clear')}</Button>
<div class="flex-1" />
<Button on:click={save} color="green">{$t('fishing.save')}</Button>
<Button on:click={close}>{$t('fishing.cancel')}</Button>
</div>
</div>

View File

@ -18,22 +18,137 @@
<script>
import { locale, t } from 'svelte-i18n';
import { onMount } from 'svelte';
import { getContext, onMount } from 'svelte';
import { mdiCheck, mdiPencil } from '@mdi/js';
import dayjs from 'dayjs';
import duration from 'dayjs/plugin/duration';
dayjs.extend(duration);
import Button from '../../components/Button.svelte';
import Icon from '../../components/Icon.svelte';
import { readSave, updateSave } from '../../stores/saveManager';
import { getAccountPrefix } from '../../stores/account';
import EditModal from './_editModal.svelte';
const { open: openModal, close: closeModal } = getContext('simple-modal');
export let data;
export let spots;
let fishList = data;
let timer = {};
let now = dayjs();
async function setAsEmpty(id) {
timer[id] = {
time: dayjs(),
text: '3d',
};
await save();
}
async function setEditing(id) {
openModal(
EditModal,
{
time: timer[id].time.format('YYYY-MM-DDTHH:mm'),
close: closeModal,
edit: (time) => edit(id, time),
clear: () => clear(id),
},
{
closeButton: false,
styleWindow: { background: '#25294A', width: '500px' },
},
);
}
async function clear(id) {
delete timer[id];
closeModal();
await save();
}
async function edit(id, time) {
timer[id] = {
time,
text: '...',
};
closeModal();
await save();
}
async function changeLocale(locale) {
const _data = await import(`../../data/fishing/${locale}.json`);
fishList = _data.default;
}
function getDuration(time) {
const diff = time.add(3, 'days').diff(now);
const duration = dayjs.duration(diff);
let format = 'D[d] HH:mm:ss';
if (duration.days() === 0) {
format = 'HH:mm:ss';
}
return duration.format(format);
}
async function load() {
const prefix = getAccountPrefix();
const data = await readSave(`${prefix}fishing`);
const timerData = {};
if (data !== null) {
for (const [id, item] of Object.entries(data)) {
timerData[id] = {
...item,
text: '...',
time: dayjs(item.time),
};
}
}
timer = timerData;
}
async function save() {
const prefix = getAccountPrefix();
const formattedTimer = {};
for (const [id, item] of Object.entries(timer)) {
formattedTimer[id] = {
...item,
time: item.time.toISOString(),
};
}
await updateSave(`${prefix}fishing`, formattedTimer);
}
onMount(async () => {
await load();
locale.subscribe((val) => {
changeLocale(val);
});
const interval = setInterval(() => {
now = dayjs();
for (const [id, item] of Object.entries(timer)) {
if (item.time.add(3, 'days').isBefore(now)) {
delete timer[id];
save();
} else {
item.text = getDuration(item.time);
}
}
timer = timer;
}, 1000);
return () => {
clearInterval(interval);
};
});
</script>
@ -44,12 +159,15 @@
</svelte:head>
<div class="lg:ml-64 pt-20 lg:pt-8 max-w-screen-xl">
<h1 class="font-display px-4 md:px-8 font-black text-5xl text-white">{$t('fishing.title')}</h1>
<p class="text-gray-400 px-4 md:px-8 font-medium pb-4" style="margin-top: -1rem;">
{$t('fishing.subtitle')}
</p>
{#each Object.entries(spots) as [id, location]}
<h3 class="font-display px-4 md:px-8 font-black text-2xl text-white mt-4 mb-2">{$t(`fishing.${id}`)}</h3>
<div class="px-4 md:px-8 w-full">
{#each location as spot}
<div class="flex flex-col items-center md:items-start md:flex-row w-full bg-item rounded-xl p-4 mb-2">
<div class="mr-4">
<div class="mr-4 flex flex-col">
<img
class="w-48 h-48 rounded-md"
style="min-width: 192px;"
@ -57,6 +175,21 @@
alt={spot.name}
title={spot.name}
/>
{#if timer[spot.id]}
<div class="flex mt-2 items-center">
<p class="text-white text-center mr-1 flex-1">
{timer[spot.id].text}
</p>
<Button on:click={() => setEditing(spot.id)} size="sm">
<Icon path={mdiPencil} color="white" />
</Button>
</div>
{:else}
<Button on:click={() => setAsEmpty(spot.id)} size="sm" className="mt-2 flex-1">
{$t('fishing.setEmpty')}
<Icon path={mdiCheck} color="white" />
</Button>
{/if}
</div>
<div
class="flex flex-wrap pt-6 md:pt-0 justify-center md:justify-start"

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB