T

TyphonJS

typhonjs-runtime

Join Server

Sidebar Tab Application

FFaey2/28/2023
I have, after diving deep into the Foundry Code, figured out how to actually add new Sidebar tabs.

it's a two step process of sorts.

You need to add the actual button to reveal the Sidebar Tab, as well as actually provide the SidebarTab Application.

Only ways to add the Button is either wrap the getData() method on Sidebar, if you already use libWrapper this is the cleaner method. Alternatively you can just sort of inject the HTML for the button with jQuery.
The Tab itself is actually the easier part. Because the canonical way is already just
ui.sidebar.tabs[this.tabName] = this;
at the end of the SidebarTab constructor.
And then the Sidebar takes care of rendering and stuff.

However, the SidebarTab has a very specific api that the Sidebar Application expects to exist. As such, the Application templates in TRL are currently insufficient to just make new SidebarTabs on their own
FFaey2/28/2023
As long as you add your SidebarTab class to CONFIG.ui at literally any point before the setup hook is called, it will get treated like any other SidebarTab, except for the missing button
MMLeahy2/28/2023
There isn't too much logic in SidebarTab, so you can implement what is necessary as a child class to SvelteApplication.

There is no ETA currently when I might provide a ready-made solution. Perhaps any effort on your side could turn into said ready-made solution. 😄
MMLeahy2/28/2023
There is a mechanism to switch the element root in SvelteApplication. This would come in handy when implementing the docked vs popout modes. You can use ApplicationShell when in popout mode and a docked component otherwise.

An example of this is in my unreleased "Better Macro Directory" demo module. It switches between ApplicationShell / TJSApplicationShell for testing this mechanism though I haven't finished the ApplicationShell / light mode styles. This is done for a dark mode / native app look and feel test.

https://github.com/typhonjs-fvtt/better-macros-directory/blob/main/src/view/BMDAppShell.svelte#L20

https://github.com/typhonjs-fvtt/better-macros-directory/blob/main/src/view/BMDAppShell.svelte#L30-L34

https://github.com/typhonjs-fvtt/better-macros-directory/blob/main/src/view/BMDAppShell.svelte#L53-L55

Quite likely though you don't need the above and just have to launch another SvelteApplication w/ ApplicationShell wrapping your sidebar content component when the sidebar tab is right clicked. Store the reference to the popped out app in the sidebar instance and if tab right clicked again call bringToTop instead of creating a new pop out.
FFaey3/1/2023
Oh yeah, i just have to figure out which of these methods actually matter and reimplement them.
FFaey3/1/2023
I can't just copy the foundry code because that would violate the license
MMLeahy3/1/2023
Not sure if that is the case if your code is only being run on Foundry. I believe there is some leniency for small utility aspects, but a lot of it can be rewritten. You can always ask / contact them directly or in the developer channels on the mothership.
FFaey3/3/2023
@TyphonJS (Michael) [UTC-7] Okay so I've finally had some time to sit down and do this. Wierdly, I can't get the application to render docked. It always appears popped out
MMLeahy3/3/2023
You need to use your own component beside ApplicationShell for the docked sidebar. Essentially duplicating similar layout to one of the classes that extends the SidebarTab class w/ a template like (SidebarDirectory): templates/sidebar/document-directory.html.
MMLeahy3/3/2023
The JS implementation of your SidebarTab class should be able to hold an instance of the SvelteApplication that uses ApplicationShell to wrap whatever content is in the tab.
FFaey3/3/2023
is there a way to make use of getData with SvelteApplication?
MMLeahy3/3/2023
For what purpose? In the App v1 API that is used to gather data to hand to the HBS template.
FFaey3/3/2023
I'm trying to write the base class as a SvelteApplication version of SidebarTab
FFaey3/3/2023
As such I want to keep the variability
FFaey3/3/2023
SidebarTab has 4 variables that are passed to the template
FFaey3/3/2023
cssId, cssClass and tabName are the ones that immediately matter
FFaey3/3/2023
it also passes game.user
FFaey3/3/2023
but that matters less with svelte
MMLeahy3/3/2023
Yeah... You have access to the external application that the css ID / classes assigned in defaultOptions with
const { application } = getContext('#external');

You could store an additional parameter for tabName in the options.

You can actually access game directly in Svelte templates as there is a special store to do so:

import { gameState } from '@typhonjs-fvtt/runtime/store';

Then in the template use $gameState.user.

That last bit probably wouldn't be obvious, but just a handy utility store to access game in a template. You can always access game in the <script> section.

Check out how ApplicationShell uses the options from the external app options to set CSS ID / classes:
https://github.com/typhonjs-fvtt-lib/svelte/blob/main/src/component/core/application/ApplicationShell.svelte#L374-L375
FFaey3/3/2023
I'm still having the issue of actually getting the svelte component to render at the correct position
FFaey3/3/2023
It just renders to document root
MMLeahy3/3/2023
Creating a standardized SidebarTab implementation is something useful to come up w/ an official wrapped / basic implementation that can be reused in the future. Kind of like providing a standardized TRL / Svelte ActorSheet.
FFaey3/3/2023
Not the document-fragment created in the tab
FFaey3/3/2023
it should show up up there, but it just kind of gets appended
FFaey3/3/2023
If I give it the same ID as my chat tab, it just refuses to render in the first place
MMLeahy3/3/2023
You need to change the target parameter to #sidebar instead of document.body or provide the specific element.

----

I can actually look into things this weekend as setting up the sidebar Svelte wrapper doesn't require more work per se like the actor sheet will. It does look like you'll need to override the Foundry Sidebar class to provide additional info on the new tabs to add in getData.
FFaey3/3/2023
I also honestly have NO idea how those templates get filled, I#ve been trying to analyse it, but its just, boom, different
FFaey3/3/2023
You shouldn't override it
FFaey3/3/2023
It's a better idea to monkeypatch the function specifically
FFaey3/3/2023
libWrapper is excellent for that exact purpose
FFaey3/3/2023
Also, you've got to get the app rendered too, the best way to do so is to stick it into CONFIG.ui
FFaey3/3/2023
Then Sidebar will just call _render during its own _render call
MMLeahy3/3/2023
libWrapper should be avoided if at all possible. Just need to replace the getData aspect returning a more complete list of tabs. I'll look into things this weekend though, so I'm just kind of spitballing right now.
FFaey3/3/2023
It's much more unsafe and prone for conflict to tear out the entire sidebar and replace the class than it is to use libWrapper to patch the function call
MMLeahy3/3/2023
There can be no dependency in TRL / svelte-standard on libWrapper.
FFaey3/3/2023
That said, you can also forgo this entire workaround and just plug the tab in yourself
MMLeahy3/3/2023
I'll see if I can come up with a solution. The Sidebar class only renders once so that most likely is possible.
FFaey3/3/2023
as long as the <nav> element contains the button and the parent sidebar div contains the section with the corresponding data-tab property, it will work
FFaey3/3/2023
So you could feasibly just write two svelte components that render a button and a section with the required contents and just target the corresponding elements on the page
FFaey3/3/2023
The only downside is that you loose all the SidebarTab specific API
MMLeahy3/3/2023
I'm mostly concerned about providing a simple API to do so for module / system developers that handles what is necessary to inject the data into the Sidebar class and Foundry rendered template.
The SidebarTab specific API needs to be duplicated. As mentioned I'll take a look this weekend.
FFaey3/3/2023
Yea yea, no worries, I'm just sharing what I have found about how the sidebar works to hopefully give you a headstart
MMLeahy3/3/2023
It shouldn't be too bad and will likely work out only because Sidebar is only rendered once.
FFaey3/3/2023
Yeah
FFaey3/3/2023
I wouldn't replace the Sidebar application itself though, as that might cause issues with modules that do use libWrapper to modify it
MMLeahy3/3/2023
Yep, not mentioning replacing the Sidebar application.
FFaey3/3/2023
Okay then I misunderstood
MMLeahy3/3/2023
Just some initial spitballing.
FFaey3/3/2023
I should mention, the only reason I am using libWrapper is to get the tab button rendered
FFaey3/3/2023
because the buttons are hardcoded, the applications themselves interestingly aren't
FFaey3/3/2023
The way those get added to the sidebar is actually in the constructor of the SidebarTab class
FFaey3/3/2023
Literally like this: ui.sidebar.tabs[this.tabName] = this
FFaey3/3/2023
So if you were to just mount the button and rendered tab manually, you can avoid modifying getData() altogether
MMLeahy3/3/2023
Yep.. It will involve manipulating ui.sidebar.tabs. No modifying of getData.
FFaey3/3/2023
The assignment of ui.sidebar.tabs also has to happen by the time the renderSidebar hook is called. I simply decided to stick my application class into CONFIG.ui in the init hook, which will automatically call the constructor before rendering the sidebar
MMLeahy3/3/2023
Well I'll definitely keep you informed on what I come up with.
FFaey3/3/2023
I'm looking forward to it. For now, I'll simply develop the popout version of my component and take care of the sidebar once you've had time to figure it out
FFaey3/3/2023
That said, this foray into TRL has taught me a lot though and the library has grown on me, I might migrate my other module over to TRL when I have the time
MMLeahy3/3/2023
Modules for sure are open game for TRL presently w/ no limitations really. Getting the system specific helper APIs worked out is the stuff that will develop over a bit more time. Heh heh.. Glad to know that things are growing on you / making sense.
MMLeahy3/4/2023
Making good progress... Initial engineering test / analysis efforts indicate that I should get this finished over the weekend.
FFaey3/4/2023
Awesome!