Add file-view configuration controls
Use getConfigurationItems to add compact, view-specific controls to the Explorer’s view configuration menu. Return Phoundry UI MenuItem values rather than rendering a separate popover.
Good configuration rows change how the current view is presented: card density, label placement, grouping, previews, or a small set of display modes. Plugin-wide credentials, accounts, and behavior belong in plugin settings.
Return Phoundry UI menu items
The provider receives the pane and a ViewAPI each time Phials builds the configuration menu:
import type { MenuItem } from "phoundry-ui";
import { PhiIcons } from "phoundry-ui/icons";
import ReviewCardsView from "./ReviewCardsView.svelte";
const configurationItems: FileBrowserViewProvider["getConfigurationItems"] =
(pane, api) => {
const compact = api.settings.get<boolean>("compactRows") ?? false;
const labelPosition =
api.settings.get<"below" | "beside">("labelPosition") ?? "below";
return [
{
type: "boolean",
id: "acme.review-cards.compact",
label: "Compact cards",
value: compact,
preventClose: true,
onchange: (next: boolean) => {
void api.settings.set("compactRows", next);
},
},
{
type: "submenu",
id: "acme.review-cards.label-position",
label: "Label position",
items: [
{
type: "action",
id: "acme.review-cards.label-below",
label: "Below preview",
selected: labelPosition === "below",
preventClose: true,
action: () => {
void api.settings.set("labelPosition", "below");
},
},
{
type: "action",
id: "acme.review-cards.label-beside",
label: "Beside preview",
selected: labelPosition === "beside",
preventClose: true,
action: () => {
void api.settings.set("labelPosition", "beside");
},
},
],
},
];
};
export const reviewCardsView: FileBrowserViewProvider = {
type: "view",
id: "acme.review-cards",
name: "Review cards",
priority: 100,
icon: PhiIcons.document,
component: ReviewCardsView,
getConfigurationItems: configurationItems,
};The IDs identify menu rows, not stored setting keys. Keep both stable and namespace the row IDs to the provider.
Use the standard Phoundry UI menu item types:
booleanfor an independent toggle or one selected choicesubmenufor a short set of related choicesgroupto organize several related rows- the standard command or action row for an immediate operation
Set preventClose: true when users are likely to compare the result while adjusting several options. Leave the menu free to close for choices that finish a short decision.
Read effective options in the component
The component reads view options through its pane context:
<script lang="ts">
let { pane }: FileBrowserViewProps = $props();
const compact = $derived(
pane.view.options.get<boolean>("compactRows") ?? false,
);
const labelPosition = $derived(
pane.view.options.get<"below" | "beside">("labelPosition") ?? "below",
);
</script>pane.view.options resolves the value for this pane. If the pane has an active saved view, a saved-view override wins. Otherwise, the plugin setting is used. This keeps two panes free to use different saved-view presentations while preserving a sensible plugin-wide default.
The api.settings supplied to getConfigurationItems has the same effective scope. Writing through it updates the active saved-view override when one is active and the plugin default otherwise. The component reacts through pane.view.options.
Do not capture the ViewAPI or pane in long-lived global state. Treat the factory as a current snapshot and let Phials rebuild it when the pane, active saved view, or settings change.
Keep controls focused
A configuration menu has limited space. Prefer:
- a small number of frequently adjusted choices
- labels that describe the visible result
- immediate application with no extra confirmation
- values that can be understood without documentation
Avoid:
- duplicating the global Settings window
- adding a control for every internal implementation detail
- destructive actions mixed into display choices
- custom HTML rows when a standard Phoundry UI menu item communicates the same control
- settings that silently change file contents
For example, “Preview: None / Image / Metadata” is a useful view choice. “Enable provider cache revalidation” is an implementation detail.
Use the pane when availability depends on context
The factory can tailor choices to the current pane:
getConfigurationItems: (pane, api) => {
const items: MenuItem[] = [
createDensityItem(api),
];
if (pane.workspaceFolder.active) {
items.push(createGroupPropertyItem(pane, api));
}
return items;
}Only omit a row when the capability truly does not apply. If an option is temporarily unavailable but still explains the view, a disabled row with a concise reason is usually clearer.
Choose defaults deliberately
Every setting read by the menu or component needs a deterministic fallback:
const showLabels =
api.settings.get<boolean>("showLabels") ?? true;Use the same fallback in the component. Better still, centralize keys and defaults:
export const reviewViewOptions = {
compactRows: {
key: "compactRows",
defaultValue: false,
},
labelPosition: {
key: "labelPosition",
defaultValue: "below" as const,
},
};This prevents the menu and renderer from disagreeing before a setting has been written.