Skip to content

Commit

Permalink
Add Svelecte traits and clean up code
Browse files Browse the repository at this point in the history
  • Loading branch information
In3luki committed Nov 26, 2024
1 parent 62289e8 commit 43546ff
Show file tree
Hide file tree
Showing 27 changed files with 358 additions and 184 deletions.
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
"nouislider": "^15.8.1",
"remeda": "^2.17.3",
"sortablejs": "^1.15.3",
"svelecte": "^5.0.0-next.16",
"svelte": "^5.2.2",
"uuid": "^11.0.3"
}
Expand Down
2 changes: 1 addition & 1 deletion src/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
CompendiumBrowser,
CompendiumBrowserSettings,
CompendiumBrowserSources,
} from "@module/apps/compendium-browser/browser.svelte.ts";
} from "@module/apps/compendium-browser/browser.ts";
import type { EffectsPanel } from "@module/apps/effects-panel.ts";
import type { HotbarPF2e } from "@module/apps/hotbar.ts";
import type { LicenseViewer } from "@module/apps/license-viewer/app.ts";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,18 @@ import * as browserTabs from "./tabs/index.ts";
const foundryApp = foundry.applications.api;

class CompendiumBrowser extends SvelteApplicationMixin(foundryApp.ApplicationV2) {
settings: CompendiumBrowserSettings;
dataTabsList = ["action", "bestiary", "campaignFeature", "equipment", "feat", "hazard", "spell"] as const;
tabs: BrowserTabs;
tabsArray: BrowserTab[];
packLoader = new PackLoader();
root = App;

/** The amount of rendered result items for initial loading and per load operation */
static RESULT_LIMIT = 100;

protected declare $state: CompendiumBrowserState;
root = App;

activeTab?: BrowserTab;
dataTabsList = ["action", "bestiary", "campaignFeature", "equipment", "feat", "hazard", "spell"] as const;
packLoader = new PackLoader();
settings: CompendiumBrowserSettings;
tabs: BrowserTabs;
tabsArray: BrowserTab[];

constructor(options: Partial<ApplicationConfiguration> = {}) {
super(options);
Expand Down Expand Up @@ -123,6 +124,19 @@ class CompendiumBrowser extends SvelteApplicationMixin(foundryApp.ApplicationV2)
return controls;
}

protected override async _prepareContext(_options: ApplicationRenderOptions): Promise<CompendiumBrowserContext> {
return {
state: {
activeTabName: "",
activeFilter: undefined,
filterKey: fu.randomID(),
results: [],
resultLimit: CompendiumBrowser.RESULT_LIMIT,
resultListKey: fu.randomID(),
},
};
}

#setVisibleTabs(visible?: ContentTabName[]): void {
const isGM = game.user.isGM;
const showCampaign = game.settings.get("pf2e", "campaignType") !== "none";
Expand All @@ -139,13 +153,12 @@ class CompendiumBrowser extends SvelteApplicationMixin(foundryApp.ApplicationV2)
}

#renderParts(parts: ("filter" | "resultList")[]): void {
const props = compendiumBrowserContext;
if (parts.includes("filter")) {
props.filterKey = fu.randomID();
this.$state.filterKey = fu.randomID();
}
if (parts.includes("resultList")) {
untrack(() => (props.results.length = 0));
props.resultListKey = fu.randomID();
untrack(() => (this.$state.results.length = 0));
this.$state.resultListKey = fu.randomID();
}
}

Expand All @@ -167,7 +180,6 @@ class CompendiumBrowser extends SvelteApplicationMixin(foundryApp.ApplicationV2)
if (!this.rendered) {
await this.render({ force: true });
}
const props = compendiumBrowserContext;

if (options?.hideNavigation) {
this.#setVisibleTabs([]);
Expand All @@ -184,13 +196,14 @@ class CompendiumBrowser extends SvelteApplicationMixin(foundryApp.ApplicationV2)
this.#setVisibleTabs();
}

props.activeFilter = options?.filter ?? this.activeTab.filterData;
if (props.activeTabName === tabName && this.rendered) {
props.resultLimit = CompendiumBrowser.RESULT_LIMIT;
untrack(() => (props.results = []));
const state = this.$state;
state.activeFilter = options?.filter ?? this.activeTab.filterData;
if (state.activeTabName === tabName && this.rendered) {
state.resultLimit = CompendiumBrowser.RESULT_LIMIT;
untrack(() => (state.results = []));
this.#renderParts(["filter", "resultList"]);
} else {
props.activeTabName = tabName;
state.activeTabName = tabName;
}

this.bringToFront();
Expand Down Expand Up @@ -357,11 +370,15 @@ class CompendiumBrowser extends SvelteApplicationMixin(foundryApp.ApplicationV2)
await tab.init(true);
}
}
compendiumBrowserContext.activeTabName = "";
this.$state.activeTabName = "";
}
}

interface CompendiumBrowserContext {
state: CompendiumBrowserState;
}

interface CompendiumBrowserState {
/** Changing this will trigger a tab rerender. An empty string will show the landing page. */
activeTabName: ContentTabName | "";
/** The currently rendered filter */
Expand All @@ -375,17 +392,8 @@ interface CompendiumBrowserContext {
/** Changing this wil trigger a result list rerender. */
resultListKey: string;
}
// This is imported as needed by svelte components for easy access to these values
const compendiumBrowserContext: CompendiumBrowserContext = $state({
activeTabName: "",
activeFilter: undefined,
filterKey: fu.randomID(),
results: [],
resultLimit: CompendiumBrowser.RESULT_LIMIT,
resultListKey: fu.randomID(),
});

type CompendiumBrowserSettings = Omit<TabData<Record<string, PackInfo | undefined>>, "settings">;

type CompendiumBrowserSettings = TabData<Record<string, PackInfo | undefined>>;

type CompendiumBrowserSourcesList = Record<string, SourceInfo | undefined>;
interface CompendiumBrowserSources {
Expand All @@ -404,10 +412,11 @@ interface CompendiumBrowserOpenTabOptions {
showTabs?: ContentTabName[];
}

export { CompendiumBrowser, compendiumBrowserContext };
export { CompendiumBrowser };
export type {
CompendiumBrowserContext,
CompendiumBrowserOpenTabOptions,
CompendiumBrowserSettings,
CompendiumBrowserSources,
CompendiumBrowserState,
};
34 changes: 27 additions & 7 deletions src/module/apps/compendium-browser/components/app.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<script lang="ts">
import { tupleHasValue } from "@util";
import BrowserTab from "./browser-tab.svelte";
import { compendiumBrowserContext as context } from "../browser.svelte.ts";
import type { CompendiumBrowserContext } from "../browser.ts";
const browser = game.pf2e.compendiumBrowser;
const tabs = $derived(browser.tabsArray.filter((t) => t.visible));
const props: CompendiumBrowserContext = $props();
const state = props.state;
async function onClickNav(event: MouseEvent & { currentTarget: EventTarget }): Promise<void> {
if (!(event.target instanceof HTMLElement)) return;
const clickedTab = event.target.dataset.tabName;
if (tupleHasValue(browser.dataTabsList, clickedTab)) {
browser.activeTab = browser.tabs[clickedTab];
await browser.activeTab.init();
context.activeFilter = browser.activeTab.filterData;
context.activeTabName = clickedTab;
state.activeFilter = browser.activeTab.filterData;
state.activeTabName = clickedTab;
}
}
</script>
Expand All @@ -24,25 +26,43 @@
<button
type="button"
onclick={onClickNav}
class:active={context.activeTabName === tab.tabName}
class:active={state.activeTabName === tab.tabName}
data-tab-name={tab.tabName}
>
{tab.label}
</button>
{/each}
</nav>
{/if}
{#if !context.activeTabName}
{#if !state.activeTabName}
<div class="browser-tab" data-tooltip-class="pf2e">
<div class="landing-page">{game.i18n.localize("PF2E.CompendiumBrowser.Hint")}</div>
</div>
{:else}
{#key context.activeTabName}
<BrowserTab activeTabName={context.activeTabName} />
{#key state.activeTabName}
<BrowserTab {state} />
{/key}
{/if}

<style lang="scss">
:global {
.compendium-browser {
--color-result-list-odd: rgba(0, 0, 0, 0.12);
--input-text-color: var(--color-dark-2);
.window-content {
padding: 0.5em;
}
}
.theme-dark .compendium-browser {
--secondary: var(--color-cool-5);
--color-result-list-odd: var(--color-dark-2);
--color-select-option-bg: var(--color-cool-5);
--input-text-color: var(--color-light-3);
}
}
nav {
flex: 0;
width: 100%;
Expand Down
39 changes: 20 additions & 19 deletions src/module/apps/compendium-browser/components/browser-tab.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<script lang="ts">
import { untrack } from "svelte";
import type { CompendiumBrowserContext } from "../browser.svelte.ts";
import Filters from "./filters.svelte";
import ResultList from "./result-list.svelte";
import { compendiumBrowserContext as context, CompendiumBrowser } from "../browser.svelte.ts";
import { type CompendiumBrowserState, CompendiumBrowser } from "../browser.ts";
import { ErrorPF2e } from "@util";
type BrowserTabProps = Pick<CompendiumBrowserContext, "activeTabName">;
type BrowserTabProps = { state: CompendiumBrowserState };
let { activeTabName }: BrowserTabProps = $props();
const props: BrowserTabProps = $props();
const state = props.state;
const activeTabName = state.activeTabName;
if (!activeTabName) {
throw ErrorPF2e(`Invalid tab name: "${activeTabName}"!`);
}
Expand All @@ -19,35 +20,35 @@
}
function rerenderList(): void {
untrack(() => (context.results.length = 0));
context.resultListKey = fu.randomID();
untrack(() => (state.results.length = 0));
state.resultListKey = fu.randomID();
}
function resetFilters(): void {
context.activeFilter = fu.deepClone(tab.defaultFilterData);
state.activeFilter = fu.deepClone(tab.defaultFilterData);
rerenderList();
}
function loadMore(): void {
if (!context.activeFilter) return;
tab.filterData = context.activeFilter;
if (context.resultLimit === CompendiumBrowser.RESULT_LIMIT) {
context.results = tab.getIndexData(0, CompendiumBrowser.RESULT_LIMIT);
context.resultLimit = 2 * CompendiumBrowser.RESULT_LIMIT;
if (!state.activeFilter) return;
tab.filterData = state.activeFilter;
if (state.resultLimit === CompendiumBrowser.RESULT_LIMIT) {
state.results = tab.getIndexData(0, CompendiumBrowser.RESULT_LIMIT);
state.resultLimit = 2 * CompendiumBrowser.RESULT_LIMIT;
return;
}
const next = tab.currentIndex.slice(context.resultLimit, context.resultLimit + CompendiumBrowser.RESULT_LIMIT);
context.resultLimit += CompendiumBrowser.RESULT_LIMIT;
context.results.push(...next);
const next = tab.currentIndex.slice(state.resultLimit, state.resultLimit + CompendiumBrowser.RESULT_LIMIT);
state.resultLimit += CompendiumBrowser.RESULT_LIMIT;
state.results.push(...next);
}
</script>

<div class="browser-tab" data-tab-name={activeTabName} data-tooltip-class="pf2e">
{#key context.filterKey}
<Filters bind:filter={context.activeFilter!} {rerenderList} {resetFilters} />
{#key state.filterKey}
<Filters bind:filter={state.activeFilter!} {rerenderList} {resetFilters} />
{/key}
{#key context.resultListKey}
<ResultList {loadMore} />
{#key state.resultListKey}
<ResultList {state} {loadMore} />
{/key}
</div>

Expand Down
Loading

0 comments on commit 43546ff

Please sign in to comment.