/** * Settings Schema - Single source of truth for searchable settings. * * This schema defines all searchable fields with their metadata for the iOS-like * settings search functionality. The search index is auto-populated from this * schema, ensuring it stays in sync with available settings. * * To add a new searchable field: * 1. Add an entry to the appropriate section in SETTINGS_SCHEMA * 2. The search will automatically include it */ import { baseTabs } from "./baseTabs"; import type { TabId } from "./types"; /** * Configuration for fields that require a parent toggle to be enabled. * When the toggle is off and user searches for this field, they'll be * redirected to the toggle instead (iOS Settings-like behavior). */ export interface RequiresToggle { /** The settings key that controls visibility (e.g., 'enable_tooltips') */ settingKey: string; /** How to compare current value to enabledValue (default: 'equals') */ operator?: "equals" | "notEquals" | "greaterThan"; /** The value that means "enabled" (default: true) */ enabledValue?: unknown; /** The ID of the toggle field to redirect to */ toggleFieldId: string; /** Message to show when redirecting (optional) */ message?: string; } /** * Reusable toggle configurations for common parent toggles. * Use these to avoid repeating the same requiresToggle config for multiple fields. */ export const TOGGLE_CONFIGS = { /** Tooltips toggle - all tooltip sub-settings depend on this */ tooltips: { settingKey: "enable_tooltips", enabledValue: true, toggleFieldId: "tooltips-enable", message: 'Enable "Tooltips" to access this setting', } satisfies RequiresToggle, } as const; /** * A searchable field definition with all metadata needed for search and navigation. */ export interface SettingsFieldSchema { /** Unique identifier matching the DOM element id */ id: string; /** Display label shown in search results */ label: string; /** Optional description/help text for the field */ description?: string; /** Tab ID where this field is located */ tabId: TabId; /** Optional section within the tab */ section?: string; /** Optional sub-tab within the main tab (e.g., 'layout' | 'size' | 'options' for General) */ subTab?: string; /** Additional keywords for search discovery (synonyms, related terms) */ keywords?: string[]; /** * If this field requires a parent toggle to be enabled, specify the toggle info here. * When the toggle is off, searching for this field will redirect to the toggle. */ requiresToggle?: RequiresToggle; } /** * Get the label for a tab ID from the tabs constant. */ function getTabLabel(tabId: string): string { const tab = baseTabs.find((t) => t.id === tabId); return tab?.label ?? tabId; } /** * Complete settings schema organized by tab. * Each entry defines a searchable field with all necessary metadata. */ export const SETTINGS_SCHEMA: SettingsFieldSchema[] = [ // ============================================================================= // GENERAL TAB - Layout & Display // ============================================================================= { id: "general-layout", label: "Layout", description: "Choose how swatches are arranged on your product pages. The default layout is Wrap.", tabId: "general", section: "Layout & Display", subTab: "layout", keywords: ["wrap", "arrangement", "display", "layout"], }, { id: "general-shape", label: "Shape", description: "Choose the shape style for your swatches. The default shape is Square.", tabId: "general", section: "Layout & Display", subTab: "layout", keywords: ["square", "shape", "corners"], }, { id: "general-selector-style", label: "Selector Style", description: "Choose how the selected swatch is visually indicated. The default style is Underline.", tabId: "general", section: "Layout & Display", subTab: "layout", keywords: ["underline", "selection", "indicator", "highlight", "active"], }, // ============================================================================= // GENERAL TAB - Size & Dimensions // ============================================================================= { id: "general-swatch-size", label: "Color Swatch Size", description: "Control the width and height of color swatches in pixels (used as the default for other types).", tabId: "general", section: "Size & Dimensions", subTab: "size", keywords: [ "color", "width", "height", "dimensions", "pixels", "px", "scale", ], }, { id: "general-internal-padding", label: "Internal Layout Padding", description: "Padding inside the swatch layout container. Adjust top, right, bottom, and left padding independently.", tabId: "general", section: "Size & Dimensions", subTab: "size", keywords: ["padding", "internal", "inside", "container", "spacing"], }, { id: "general-external-padding", label: "External Layout Padding", description: "Padding outside the swatch layout container. Controls spacing from other elements on the page.", tabId: "general", section: "Size & Dimensions", subTab: "size", keywords: ["padding", "external", "outside", "margin", "spacing", "page"], }, // ============================================================================= // GENERAL TAB - Labels & Options // ============================================================================= { id: "general-show-labels-colors", label: "Show Labels on Color Swatches", description: "Display text labels alongside color swatches.", tabId: "general", section: "Labels & Options", subTab: "options", keywords: ["labels", "text", "names", "color", "display", "show", "hide"], }, { id: "general-auto-convert-dropdowns", label: "Replace WooCommerce Dropdowns with Swatches", description: "Replaces the default WooCommerce variation dropdowns (selects) with the B3 swatches UI on product pages.", tabId: "general", section: "Labels & Options", subTab: "options", keywords: [ "dropdown", "select", "convert", "replace", "woocommerce", "default", ], }, // ============================================================================= // VARIATION CHIPS TAB // ============================================================================= { id: "chips-selected-color", label: "Selected Chip Color", description: "Sets the highlight color used for selected/active chips.", tabId: "chips", section: "Appearance", keywords: ["chip", "button", "selected", "active", "color", "highlight"], }, // ============================================================================= // TYPOGRAPHY TAB // ============================================================================= { id: "typography-heading", label: "Heading Typography", description: "Styles WooCommerce variation attribute headings such as Color and Size.", tabId: "typography", section: "Heading", keywords: ["heading", "title", "font", "typography", "attribute"], }, { id: "typography-heading-color", label: "Heading Color", description: "Sets the text color for variation attribute headings.", tabId: "typography", section: "Heading", keywords: ["heading", "color", "text", "attribute", "label"], }, { id: "typography-heading-size", label: "Heading Font Size", description: "Controls the font size used for variation attribute headings.", tabId: "typography", section: "Heading", keywords: ["heading", "font size", "size", "text", "px", "attribute"], }, { id: "typography-label", label: "Label Typography", description: "Styles text shown inside variation chips and swatches.", tabId: "typography", section: "Labels", keywords: ["label", "text", "font", "typography", "chip", "swatch"], }, { id: "typography-label-color", label: "Label Text Color", description: "Sets a fixed text color for variation chips and swatches, or leave it empty to use automatic contrast.", tabId: "typography", section: "Labels", keywords: [ "label", "text color", "color", "chip", "swatch", "font", "auto", "contrast", "override", ], }, { id: "typography-label-size", label: "Label Font Size", description: "Controls the font size used inside variation chips/swatches.", tabId: "typography", section: "Labels", keywords: ["label", "font size", "size", "text", "chip", "swatch", "px"], }, // ============================================================================= // TOOLTIPS TAB // ============================================================================= { id: "tooltips-enable", label: "Enable Tooltips", description: "Show tooltip popups when hovering over swatches.", tabId: "tooltips", section: "General", keywords: [ "tooltip", "popup", "hover", "enable", "disable", "show", "hide", ], }, // ============================================================================= // ADVANCED TAB // ============================================================================= { id: "advanced-uninstall-cleanup", label: "Uninstall Cleanup", description: "Remove plugin data (settings, per-product overrides, term meta) when uninstalling the plugin.", tabId: "advanced", section: "Cleanup", keywords: ["uninstall", "cleanup", "remove data", "reset"], }, ]; /** * Apply requiresToggle configs to fields that need them. * This auto-applies toggle dependencies so we don't have to repeat the config on each field. */ function applyToggleConfigs( fields: SettingsFieldSchema[], ): SettingsFieldSchema[] { return fields.map((field) => { // If field already has a requiresToggle, keep it if (field.requiresToggle) return field; // Auto-apply Tooltips toggle to all tooltip sub-settings (except the main toggle itself) if (field.tabId === "tooltips" && field.id !== "tooltips-enable") { return { ...field, requiresToggle: TOGGLE_CONFIGS.tooltips }; } return field; }); } /** * Get all searchable fields with toggle configs applied. * Fields with requiresToggle will redirect to their parent toggle when the setting is disabled. */ export function getSearchableFields(): SettingsFieldSchema[] { return applyToggleConfigs(SETTINGS_SCHEMA); } /** * Searchable field data with requiresToggle info for the search handler. */ export interface SearchableFieldWithToggle { id: string; label: string; description?: string; tabId: string; tabLabel: string; section?: string; subTab?: string; keywords?: string[]; requiresToggle?: RequiresToggle; } /** * Convert schema fields to SearchableFieldData format for the search index. * Includes requiresToggle info so the search handler can redirect to parent toggles. */ export function schemaToSearchableFields(): SearchableFieldWithToggle[] { return getSearchableFields().map((field) => ({ ...field, id: field.id, label: field.label, description: field.description, tabId: field.tabId, tabLabel: getTabLabel(field.tabId), section: field.section, subTab: field.subTab, keywords: field.keywords, requiresToggle: field.requiresToggle, })); }