mirror of
https://github.com/YouHaveTrouble/DiscipleOfLand.git
synced 2026-05-12 06:26:56 +00:00
filter shenanigans
This commit is contained in:
+29
-1
@@ -4,13 +4,26 @@
|
|||||||
<div class="current-eorzea-time">
|
<div class="current-eorzea-time">
|
||||||
{{ eorzeaTime.getPrettyTime() }}
|
{{ eorzeaTime.getPrettyTime() }}
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
class="filters-button"
|
||||||
|
:class="{ active: filtersActive}"
|
||||||
|
@click="filtersActive = !filtersActive"
|
||||||
|
>
|
||||||
|
{{ filtersActive ? ' Close filters' : 'Open filters' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<main>
|
<main>
|
||||||
<SortedNodeList
|
<SortedNodeList
|
||||||
|
v-if="!filtersActive"
|
||||||
:nodes="nodes as Node[]"
|
:nodes="nodes as Node[]"
|
||||||
:zones="zones"
|
:zones="zones"
|
||||||
:eorzea-time="eorzeaTime"
|
:eorzea-time="eorzeaTime"
|
||||||
/>
|
/>
|
||||||
|
<FiltersMenu
|
||||||
|
v-if="filtersActive"
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -26,16 +39,20 @@ import {nodeTypeFromString} from "@/enums/NodeType";
|
|||||||
import SortedNodeList from "@/components/SortedNodeList.vue";
|
import SortedNodeList from "@/components/SortedNodeList.vue";
|
||||||
import TimeRange from "@/entities/TimeRange";
|
import TimeRange from "@/entities/TimeRange";
|
||||||
import Zone from "@/entities/Zone";
|
import Zone from "@/entities/Zone";
|
||||||
|
import FiltersMenu from "@/components/FiltersMenu.vue";
|
||||||
|
import Filters from "@/util/Filters";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {SortedNodeList},
|
components: {FiltersMenu, SortedNodeList},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
eorzeaTime: new EorzeaTime() as EorzeaTime,
|
eorzeaTime: new EorzeaTime() as EorzeaTime,
|
||||||
nodes: [] as Node[],
|
nodes: [] as Node[],
|
||||||
aetherytes: [] as Aetheryte[],
|
aetherytes: [] as Aetheryte[],
|
||||||
items: {} as { [key: string]: Item },
|
items: {} as { [key: string]: Item },
|
||||||
zones: {} as { [key: string]: Zone },
|
zones: {} as { [key: string]: Zone },
|
||||||
|
filtersActive: false,
|
||||||
|
filters: new Filters(),
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
findNearestAetheryte(zone: string, x: number, y: number): Aetheryte | null {
|
findNearestAetheryte(zone: string, x: number, y: number): Aetheryte | null {
|
||||||
@@ -172,5 +189,16 @@ nav {
|
|||||||
.current-eorzea-time {
|
.current-eorzea-time {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filters-button {
|
||||||
|
display: flex;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
&.active {
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
<template>
|
||||||
|
<section>
|
||||||
|
<details open>
|
||||||
|
<summary>Level of items</summary>
|
||||||
|
<section>
|
||||||
|
<label>
|
||||||
|
<span>Minimum level</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="1"
|
||||||
|
:min="1"
|
||||||
|
:max="filters.maxLevel"
|
||||||
|
v-model="filters.minLevel"
|
||||||
|
@focusout="(e: FocusEvent) => {
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
const numberValue = parseInt(target.value);
|
||||||
|
if (filters.maxLevel && numberValue > filters.maxLevel) {
|
||||||
|
filters.maxLevel = filters.minLevel;
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Maximum level</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="100"
|
||||||
|
:min="filters.minLevel"
|
||||||
|
:max="100"
|
||||||
|
v-model="filters.maxLevel"
|
||||||
|
@focusout="(e: FocusEvent) => {
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
const numberValue = parseInt(target.value);
|
||||||
|
if (filters.minLevel && numberValue < filters.minLevel) {
|
||||||
|
filters.minLevel = filters.maxLevel;
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
</section>
|
||||||
|
</details>
|
||||||
|
<details open>
|
||||||
|
<summary>Jobs</summary>
|
||||||
|
<section>
|
||||||
|
<label class="horizontal">
|
||||||
|
<span>Botanist</span>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="filters.jobs.includes(Job.BOTANIST)"
|
||||||
|
@change="(e: Event) => {
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
if (target.checked) {
|
||||||
|
filters.jobs.push(Job.BOTANIST);
|
||||||
|
} else {
|
||||||
|
filters.jobs = filters.jobs.filter((job) => job !== Job.BOTANIST);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<label class="horizontal">
|
||||||
|
<span>Miner</span>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="filters.jobs.includes(Job.MINER)"
|
||||||
|
@change="(e: Event) => {
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
if (target.checked) {
|
||||||
|
filters.jobs.push(Job.MINER);
|
||||||
|
} else {
|
||||||
|
filters.jobs = filters.jobs.filter((job) => job !== Job.MINER);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
</section>
|
||||||
|
</details>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {defineComponent} from "vue";
|
||||||
|
import Filters from "@/util/Filters";
|
||||||
|
import {Job} from "@/enums/Job";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "FiltersMenu",
|
||||||
|
computed: {
|
||||||
|
Job() {
|
||||||
|
return Job
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:filters'],
|
||||||
|
data: () => ({
|
||||||
|
filters: {
|
||||||
|
minLevel: undefined,
|
||||||
|
maxLevel: undefined,
|
||||||
|
jobs: [] as Job[],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
watch: {
|
||||||
|
filters: {
|
||||||
|
handler(newFilters) {
|
||||||
|
const filters = new Filters(newFilters);
|
||||||
|
window.localStorage.setItem("filters", JSON.stringify(filters));
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
|
minLevel(newValue: string) {
|
||||||
|
const numberValue = parseInt(newValue);
|
||||||
|
return isNaN(numberValue) ? 1 : numberValue;
|
||||||
|
},
|
||||||
|
maxLevel(newValue: string) {
|
||||||
|
const numberValue = parseInt(newValue);
|
||||||
|
return isNaN(numberValue) ? 100 : numberValue;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
const filters = window.localStorage.getItem("filters");
|
||||||
|
if (filters) {
|
||||||
|
this.filters = JSON.parse(filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
|
||||||
|
details {
|
||||||
|
background-color: #1f1f1f;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0.5rem;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
summary {
|
||||||
|
cursor: pointer;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 2rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&.horizontal {
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="number"] {
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
background-color: transparent;
|
||||||
|
color: white;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
width: 5rem;
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<article class="node" :class="{active: gatheringNode.isActive(eorzeaTime)}">
|
<article
|
||||||
|
class="node"
|
||||||
|
:class="{active: gatheringNode.isActive(eorzeaTime)}"
|
||||||
|
>
|
||||||
<div class="timer">
|
<div class="timer">
|
||||||
{{
|
{{
|
||||||
gatheringNode.isActive(eorzeaTime) ? 'Active' : prettyTimer(gatheringNode.getSecondsToNextActiveTime(eorzeaTime))
|
gatheringNode.isActive(eorzeaTime) ? 'Active' : prettyTimer(gatheringNode.getSecondsToNextActiveTime(eorzeaTime))
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import EorzeaTime from "../util/EorzeaTime";
|
|||||||
import Node from "@/entities/Node";
|
import Node from "@/entities/Node";
|
||||||
import GatheringNode from "@/components/GatheringNode.vue";
|
import GatheringNode from "@/components/GatheringNode.vue";
|
||||||
import Zone from "@/entities/Zone";
|
import Zone from "@/entities/Zone";
|
||||||
|
import Filters from "@/util/Filters";
|
||||||
|
|
||||||
export default defineComponent(
|
export default defineComponent(
|
||||||
{
|
{
|
||||||
@@ -37,10 +38,10 @@ export default defineComponent(
|
|||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
nodes: {
|
nodes: {
|
||||||
immediate: true,
|
handler(newNodes: Node[]) {
|
||||||
handler() {
|
this.filterNodes(newNodes);
|
||||||
this.displayNodes = this.nodes;
|
},
|
||||||
}
|
deep: true
|
||||||
},
|
},
|
||||||
displayNodes: {
|
displayNodes: {
|
||||||
handler() {
|
handler() {
|
||||||
@@ -48,7 +49,6 @@ export default defineComponent(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
eorzeaTime: {
|
eorzeaTime: {
|
||||||
immediate: true,
|
|
||||||
handler(newValue, oldValue) {
|
handler(newValue, oldValue) {
|
||||||
if (oldValue === undefined) return;
|
if (oldValue === undefined) return;
|
||||||
if (newValue?.getMinutes() === oldValue?.getMinutes()) return;
|
if (newValue?.getMinutes() === oldValue?.getMinutes()) return;
|
||||||
@@ -68,10 +68,37 @@ export default defineComponent(
|
|||||||
return aSeconds - bSeconds;
|
return aSeconds - bSeconds;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
filterNodes(nodes: Node[] = []) {
|
||||||
async mounted() {
|
let filters: Filters | null = null;
|
||||||
|
const filtersString = window.localStorage.getItem("filters");
|
||||||
|
if (filtersString === null) {
|
||||||
this.displayNodes = this.nodes;
|
this.displayNodes = this.nodes;
|
||||||
this.sortListByTime();
|
return;
|
||||||
|
}
|
||||||
|
const parsedFilters = JSON.parse(filtersString);
|
||||||
|
filters = new Filters(parsedFilters);
|
||||||
|
|
||||||
|
this.displayNodes = nodes.filter((node) => {
|
||||||
|
let shouldDisplay = false;
|
||||||
|
|
||||||
|
if (filters && !filters.jobs.includes(node.job)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of node.items) {
|
||||||
|
if (filters && item.level >= filters.minLevel && item.level <= filters.maxLevel) {
|
||||||
|
shouldDisplay = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shouldDisplay;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.filterNodes(this.nodes);
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import {Job, jobFromString} from "@/enums/Job";
|
||||||
|
|
||||||
|
export default class Filters {
|
||||||
|
|
||||||
|
minLevel: number;
|
||||||
|
maxLevel: number;
|
||||||
|
jobs: Job[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
data?: {
|
||||||
|
minLevel?: number,
|
||||||
|
maxLevel?: number,
|
||||||
|
jobs?: string[],
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
this.minLevel = data?.minLevel || 1;
|
||||||
|
this.maxLevel = data?.maxLevel || 100;
|
||||||
|
const jobData = data?.jobs || [];
|
||||||
|
|
||||||
|
for (const job of jobData) {
|
||||||
|
const parsedJob = jobFromString(job);
|
||||||
|
if (!parsedJob) continue;
|
||||||
|
this.jobs.push(parsedJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user