diff --git a/frontend/src/lib/components/TradeButton.svelte b/frontend/src/lib/components/TradeButton.svelte
new file mode 100644
index 0000000..bef2e67
--- /dev/null
+++ b/frontend/src/lib/components/TradeButton.svelte
@@ -0,0 +1,27 @@
+
+
+
diff --git a/frontend/src/lib/components/TradeLinks.svelte b/frontend/src/lib/components/TradeLinks.svelte
new file mode 100644
index 0000000..6ff8731
--- /dev/null
+++ b/frontend/src/lib/components/TradeLinks.svelte
@@ -0,0 +1,14 @@
+
+
+
+ {#each queries as query, index}
+
+ {/each}
+
diff --git a/frontend/src/lib/skill_tree.ts b/frontend/src/lib/skill_tree.ts
index cc222c7..5e258d8 100644
--- a/frontend/src/lib/skill_tree.ts
+++ b/frontend/src/lib/skill_tree.ts
@@ -1,5 +1,7 @@
import type { Translation, Node, SkillTreeData, Group, Sprite, TranslationFile } from './skill_tree_types';
import { data } from './types';
+import { type Filter, type Query, filterGroupsToQuery, filtersToFilterGroup } from './utils/trade_utils';
+import { chunkArray } from './utils/utils';
export let skillTree: SkillTreeData;
@@ -384,91 +386,58 @@ const tradeStatNames: { [key: number]: { [key: string]: string } } = {
}
};
-export const constructQuery = (jewel: number, conqueror: string, result: SearchWithSeed[]) => {
- const max_filter_length = 50;
- const max_filters = 4;
- const max_query_length = max_filter_length * max_filters;
- const final_query = [];
- const stat = {
- type: 'count',
- value: { min: 1 },
- filters: [],
- disabled: false
- };
+export const constructSingleResultQuery = (jewel: number, conqueror: string | null, result: SearchWithSeed): Query => {
+ const anyConqueror = conqueror === null;
- // single seed case
- if (result.length == 1) {
- for (const conq of Object.keys(tradeStatNames[jewel])) {
- stat.filters.push({
- id: tradeStatNames[jewel][conq],
- value: {
- min: result[0].seed,
- max: result[0].seed
- },
- disabled: conq != conqueror
- });
- }
+ const filters: Filter[] = Object.keys(tradeStatNames[jewel]).map((conq) => ({
+ id: tradeStatNames[jewel][conq],
+ value: {
+ min: result.seed,
+ max: result.seed
+ },
+ disabled: anyConqueror ? false : conq != conqueror
+ }));
- final_query.push(stat);
- // too many results case
- } else if (result.length > max_query_length) {
- for (let i = 0; i < max_filters; i++) {
- final_query.push({
- type: 'count',
- value: { min: 1 },
- filters: [],
- disabled: i == 0 ? false : true
- });
- }
+ const filterGroup = filtersToFilterGroup(filters, false);
+ const query: Query = filterGroupsToQuery([filterGroup]);
+ return query;
+};
- for (const [i, r] of result.slice(0, max_query_length).entries()) {
- const index = Math.floor(i / max_filter_length);
+const constructSearchFilter = (jewel: number, conqueror: string | null, result: SearchWithSeed): Filter[] => {
+ // null conqueror indicates to search for any conqueror
+ const anyConqueror = conqueror === null;
+ const conquerors = anyConqueror ? Object.keys(tradeStatNames[jewel]) : [conqueror];
- final_query[index].filters.push({
- id: tradeStatNames[jewel][conqueror],
- value: {
- min: r.seed,
- max: r.seed
- }
- });
+ return conquerors.map((conq) => ({
+ id: tradeStatNames[jewel][conq],
+ value: {
+ min: result.seed,
+ max: result.seed
}
- } else {
- for (const conq of Object.keys(tradeStatNames[jewel])) {
- stat.disabled = conq != conqueror;
-
- for (const r of result) {
- stat.filters.push({
- id: tradeStatNames[jewel][conq],
- value: {
- min: r.seed,
- max: r.seed
- }
- });
- }
+ }));
+};
- if (stat.filters.length > max_filter_length) {
- stat.filters = stat.filters.slice(0, max_filter_length);
- }
+export const constructQueries = (jewel: number, conqueror: string | null, results: SearchWithSeed[]) => {
+ const max_filter_length = 50;
+ const max_filters = 4;
+ const max_query_length = max_filter_length * max_filters;
- final_query.push(stat);
- }
- }
+ // convert all results into filters
+ const allFilters = results.flatMap((result) => constructSearchFilter(jewel, conqueror, result));
- return {
- query: {
- status: {
- option: 'online'
- },
- stats: final_query
- },
- sort: {
- price: 'asc'
- }
- };
-};
+ // group filters into groups of max_query_length, where each group is further grouped into chunks of max_filter_length
+ // this represents multiple trade links, where each trade link has multiple filter groups, and each filter group has multiple filters
+ const queryFilterGroups = chunkArray(allFilters, max_query_length).map((chunk) =>
+ chunkArray(chunk, max_filter_length)
+ );
+
+ // map filters groups to queries
+ const tradeQueries = queryFilterGroups.map((queryFilterGroup) => {
+ // for each query, map the chunks within it to filter groups
+ const tradeFilterGroups = queryFilterGroup.map((filters, index) => filtersToFilterGroup(filters, index !== 0));
+ const tradeQuery: Query = filterGroupsToQuery(tradeFilterGroups);
+ return tradeQuery;
+ });
-export const openTrade = (jewel: number, conqueror: string, results: SearchWithSeed[]) => {
- const url = new URL('https://www.pathofexile.com/trade/search/Necropolis');
- url.searchParams.set('q', JSON.stringify(constructQuery(jewel, conqueror, results)));
- window.open(url, '_blank');
+ return tradeQueries;
};
diff --git a/frontend/src/lib/utils/trade_utils.ts b/frontend/src/lib/utils/trade_utils.ts
new file mode 100644
index 0000000..229a1ee
--- /dev/null
+++ b/frontend/src/lib/utils/trade_utils.ts
@@ -0,0 +1,47 @@
+export type Filter = {
+ id: string;
+ value: { min: number; max: number };
+ disabled?: boolean;
+};
+export type FilterGroup = {
+ type: string;
+ value: { min: number };
+ filters: Filter[];
+ disabled: boolean;
+};
+export type Query = {
+ query: {
+ status: {
+ option: string;
+ };
+ stats: FilterGroup[];
+ };
+ sort: {
+ price: string;
+ };
+};
+
+export const filtersToFilterGroup = (filters: Filter[], disabled: boolean): FilterGroup => ({
+ type: 'count',
+ value: { min: 1 },
+ filters: filters,
+ disabled: disabled
+});
+
+export const filterGroupsToQuery = (FilterGroups: FilterGroup[]): Query => ({
+ query: {
+ status: {
+ option: 'online'
+ },
+ stats: FilterGroups
+ },
+ sort: {
+ price: 'asc'
+ }
+});
+
+export const openQueryTrade = (query: Query) => {
+ const url = new URL('https://www.pathofexile.com/trade/search/Necropolis');
+ url.searchParams.set('q', JSON.stringify(query));
+ window.open(url, '_blank');
+};
diff --git a/frontend/src/lib/utils/utils.ts b/frontend/src/lib/utils/utils.ts
new file mode 100644
index 0000000..01f16a6
--- /dev/null
+++ b/frontend/src/lib/utils/utils.ts
@@ -0,0 +1,19 @@
+/**
+ * Break an array into chunks of the given size
+ *
+ * e.g. for chunk size 2:
+ *
+ * [1, 2, 3, 4, 5] => [[1, 2], [3, 4], [5]]
+ */
+export const chunkArray =
(inputArray: Array, chunkSize: number): Array[] =>
+ inputArray.reduce((resultArray, item, index) => {
+ const chunkIndex = Math.floor(index / chunkSize);
+
+ if (!resultArray[chunkIndex]) {
+ resultArray[chunkIndex] = []; // start a new chunk
+ }
+
+ resultArray[chunkIndex].push(item);
+
+ return resultArray;
+ }, [] as Array[]);
diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte
index 9eb628c..870c1d0 100644
--- a/frontend/src/routes/+page.svelte
+++ b/frontend/src/routes/+page.svelte
@@ -117,8 +117,9 @@
{#if result.AlternatePassiveSkill}
Alternate Passive Skill
- {result.AlternatePassiveSkill.Name} ({result.AlternatePassiveSkill.ID}) ({result.AlternatePassiveSkill})
+
+ {result.AlternatePassiveSkill.Name} ({result.AlternatePassiveSkill.ID})
+
{#if result.StatRolls && Object.keys(result.StatRolls).length > 0}
diff --git a/frontend/src/routes/tree/+page.svelte b/frontend/src/routes/tree/+page.svelte
index 531b8f0..1d0ae35 100644
--- a/frontend/src/routes/tree/+page.svelte
+++ b/frontend/src/routes/tree/+page.svelte
@@ -4,13 +4,15 @@
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import type { Node } from '../../lib/skill_tree_types';
- import { getAffectedNodes, skillTree, translateStat, openTrade } from '../../lib/skill_tree';
+ import { getAffectedNodes, skillTree, translateStat, constructQueries } from '../../lib/skill_tree';
import { syncWrap } from '../../lib/worker';
import { proxy } from 'comlink';
- import type { ReverseSearchConfig, StatConfig } from '../../lib/skill_tree';
+ import type { Query, ReverseSearchConfig, StatConfig } from '../../lib/skill_tree';
import SearchResults from '../../lib/components/SearchResults.svelte';
import { statValues } from '../../lib/values';
import { data, calculator } from '../../lib/types';
+ import TradeButton from '$lib/components/TradeButton.svelte';
+ import TradeLinks from '$lib/components/TradeLinks.svelte';
const searchParams = $page.url.searchParams;
@@ -28,13 +30,19 @@
}))
: [];
- let selectedConqueror = searchParams.has('conqueror')
+ $: dropdownConqs = conquerors.concat([{ value: 'Any', label: 'Any' }]);
+
+ let dropdownConqueror = searchParams.has('conqueror')
? {
value: searchParams.get('conqueror'),
label: searchParams.get('conqueror')
}
: undefined;
+ $: anyConqueror = dropdownConqueror?.value === 'Any';
+
+ $: selectedConqueror = dropdownConqueror?.value === 'Any' ? conquerors[0] : dropdownConqueror;
+
let seed: number = searchParams.has('seed') ? parseInt(searchParams.get('seed')) : 0;
let circledNode: number | undefined = searchParams.has('location')
@@ -80,7 +88,7 @@
const updateUrl = () => {
const url = new URL(window.location.origin + window.location.pathname);
selectedJewel && url.searchParams.append('jewel', selectedJewel.value.toString());
- selectedConqueror && url.searchParams.append('conqueror', selectedConqueror.value);
+ dropdownConqueror && url.searchParams.append('conqueror', dropdownConqueror.value);
seed && url.searchParams.append('seed', seed.toString());
circledNode && url.searchParams.append('location', circledNode.toString());
mode && url.searchParams.append('mode', mode);
@@ -156,14 +164,14 @@
let currentSeed = 0;
let searchResults: SearchResults;
let searchJewel = 1;
- let searchConqueror = '';
+ let searchConqueror: string | null = null;
const search = () => {
if (!circledNode) {
return;
}
searchJewel = selectedJewel.value;
- searchConqueror = selectedConqueror.value;
+ searchConqueror = anyConqueror ? null : selectedConqueror.value;
searching = true;
searchResults = undefined;
@@ -421,6 +429,20 @@
};
let collapsed = false;
+
+ let showTradeLinks = false;
+
+ let queries: Query[];
+
+ // reconstruct queries if search results change
+ $: if (searchResults && results) {
+ queries = constructQueries(searchJewel, searchConqueror, searchResults.raw);
+
+ // reset showTradeLinks to hidden if new queries is only length of 1
+ if (queries.length === 1) {
+ showTradeLinks = false;
+ }
+ }
@@ -457,12 +479,7 @@
{#if searchResults}
{#if results}
-
+
{#if selectedConqueror && Object.keys(data.TimelessJewelConquerors[selectedJewel.value]).indexOf(selectedConqueror.value) >= 0}
@@ -661,6 +678,9 @@
{/if}
{#if searchResults && results}
+ {#if showTradeLinks}
+
+ {/if}
{/if}
@@ -698,7 +718,8 @@
}
.grouped {
- @apply bg-pink-500/40 disabled:bg-pink-900/40;
+ @apply bg-pink-500/40;
+ disabled: bg-pink-900/40;
}
.rainbow {
From f07b12e59be61cbbb705f481311e22b269876761 Mon Sep 17 00:00:00 2001
From: Hamba <129166482+ImHamba@users.noreply.github.com>
Date: Sun, 26 May 2024 22:26:01 +1000
Subject: [PATCH 2/2] Update release.yml
---
.github/workflows/release.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 976b3ed..3dcb80d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -2,8 +2,8 @@ name: release
on:
push:
- tags:
- - v*
+ branches:
+ - main
jobs:
release: