diff --git a/README.md b/README.md index d61e296..b168f28 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,7 @@ Go to Settings > Food Tracker to configure: - `YYYY-MM-DD-[journal]` → `2025-11-12-journal` - `dddd YYYY-MM-DD` → `Wednesday 2025-11-12` - **Goals file**: Specify the path to your nutrition goals file (e.g., "nutrition-goals.md"). The field includes type-ahead file suggestions. -- **Metadata field names**: Customize the frontmatter property names used for storing nutrition totals in daily notes. By default, the plugin uses `ft-` prefixed names (e.g., `ft-calories`, `ft-protein`). You can customize these to match your existing setup or personal preferences (e.g., just `calories` instead of `ft-calories`). +- **Metadata field names**: Choose which nutrition totals to display in daily note properties and customize their field names. Each macro (calories, fats, protein, etc.) has a toggle to enable/disable its display in properties, plus a text field to customize the property name. By default, the plugin uses `ft-` prefixed names (e.g., `ft-calories`, `ft-protein`). You can customize these to match your existing setup or preferences. If you only track certain macros (e.g., just calories and fat), you can disable the others to avoid clutter in your daily notes. > **Note**: When you change the food or workout tag settings, the plugin will only recognize the new tags. Existing entries will need to be updated if you want them included in calculations. diff --git a/src/FoodTrackerSettingTab.ts b/src/FoodTrackerSettingTab.ts index 83b4d20..18c5d3a 100644 --- a/src/FoodTrackerSettingTab.ts +++ b/src/FoodTrackerSettingTab.ts @@ -2,7 +2,11 @@ import { App, PluginSettingTab, Setting, moment, normalizePath } from "obsidian" import type FoodTrackerPlugin from "./FoodTrackerPlugin"; import FolderSuggest from "./FolderSuggest"; import FileSuggest from "./FileSuggest"; -import { DEFAULT_FRONTMATTER_FIELD_NAMES, type FrontmatterFieldNames } from "./SettingsService"; +import { + DEFAULT_FRONTMATTER_FIELD_NAMES, + type EnabledFrontmatterFields, + type FrontmatterFieldNames, +} from "./SettingsService"; const obsidianMoment = moment as unknown as typeof import("moment"); /** @@ -157,30 +161,42 @@ export default class FoodTrackerSettingTab extends PluginSettingTab { const descEl = detailsEl.createEl("p", { cls: "food-tracker-settings-collapsible-desc setting-item-description", - text: "Customize the frontmatter field names used to store nutrition totals in daily notes.", + text: "Choose which nutrition totals to display in daily note properties and customize their field names.", }); descEl.style.marginTop = "0.5em"; descEl.style.marginBottom = "1em"; const fieldConfigs: Array<{ - key: keyof FrontmatterFieldNames; + key: keyof FrontmatterFieldNames & keyof EnabledFrontmatterFields; name: string; desc: string; }> = [ - { key: "calories", name: "Calories field", desc: "Field name for total calories" }, - { key: "fats", name: "Fats field", desc: "Field name for total fats (g)" }, - { key: "saturated_fats", name: "Saturated fats field", desc: "Field name for saturated fats (g)" }, - { key: "protein", name: "Protein field", desc: "Field name for total protein (g)" }, - { key: "carbs", name: "Carbs field", desc: "Field name for total carbohydrates (g)" }, - { key: "fiber", name: "Fiber field", desc: "Field name for total fiber (g)" }, - { key: "sugar", name: "Sugar field", desc: "Field name for total sugar (g)" }, - { key: "sodium", name: "Sodium field", desc: "Field name for total sodium (mg)" }, + { key: "calories", name: "Calories", desc: "Total calories" }, + { key: "fats", name: "Fats", desc: "Total fats (g)" }, + { key: "saturated_fats", name: "Saturated fats", desc: "Saturated fats (g)" }, + { key: "protein", name: "Protein", desc: "Total protein (g)" }, + { key: "carbs", name: "Carbs", desc: "Total carbohydrates (g)" }, + { key: "fiber", name: "Fiber", desc: "Total fiber (g)" }, + { key: "sugar", name: "Sugar", desc: "Total sugar (g)" }, + { key: "sodium", name: "Sodium", desc: "Total sodium (mg)" }, ]; for (const config of fieldConfigs) { new Setting(detailsEl) .setName(config.name) .setDesc(config.desc) + .addToggle(toggle => + toggle.setValue(this.plugin.settings.enabledFrontmatterFields[config.key]).onChange(async value => { + const enabledFields = this.plugin.settings.enabledFrontmatterFields; + enabledFields[config.key] = value; + this.plugin.settingsService.updateEnabledFrontmatterFields(enabledFields); + this.plugin.settings = { + ...this.plugin.settings, + enabledFrontmatterFields: this.plugin.settingsService.currentEnabledFrontmatterFields, + }; + await this.plugin.saveSettings(); + }) + ) .addText(text => text .setPlaceholder(DEFAULT_FRONTMATTER_FIELD_NAMES[config.key]) diff --git a/src/FrontmatterTotalsService.ts b/src/FrontmatterTotalsService.ts index abc3072..49be95c 100644 --- a/src/FrontmatterTotalsService.ts +++ b/src/FrontmatterTotalsService.ts @@ -1,7 +1,13 @@ import { App, TFile } from "obsidian"; import { NutrientData, calculateNutritionTotals } from "./NutritionCalculator"; import NutrientCache from "./NutrientCache"; -import { DEFAULT_FRONTMATTER_FIELD_NAMES, FrontmatterFieldNames, SettingsService } from "./SettingsService"; +import { + DEFAULT_ENABLED_FRONTMATTER_FIELDS, + DEFAULT_FRONTMATTER_FIELD_NAMES, + EnabledFrontmatterFields, + FrontmatterFieldNames, + SettingsService, +} from "./SettingsService"; import GoalsService from "./GoalsService"; import DailyNoteLocator from "./DailyNoteLocator"; @@ -69,12 +75,14 @@ export function nutrientDataToFrontmatterTotals(data: NutrientData): Frontmatter export function applyNutrientTotalsToFrontmatter( frontmatter: Record, totals: NutrientData | null, - fieldNames: FrontmatterFieldNames = DEFAULT_FRONTMATTER_FIELD_NAMES + fieldNames: FrontmatterFieldNames = DEFAULT_FRONTMATTER_FIELD_NAMES, + enabledFields: EnabledFrontmatterFields = DEFAULT_ENABLED_FRONTMATTER_FIELDS ): void { const keys = Object.keys(fieldNames) as FrontmatterKey[]; if (!totals || Object.keys(totals).length === 0) { for (const key of keys) { + if (!enabledFields[key]) continue; const frontmatterKey = fieldNames[key]; if (frontmatterKey in frontmatter) { frontmatter[frontmatterKey] = 0; @@ -86,6 +94,7 @@ export function applyNutrientTotalsToFrontmatter( const formattedTotals = nutrientDataToFrontmatterTotals(totals); for (const key of keys) { + if (!enabledFields[key]) continue; const frontmatterKey = fieldNames[key]; const value = formattedTotals[key]; if (value !== undefined) { @@ -174,7 +183,12 @@ export default class FrontmatterTotalsService { } private updateFrontmatterValues(frontmatter: Record, totals: NutrientData | null): void { - applyNutrientTotalsToFrontmatter(frontmatter, totals, this.settingsService.currentFrontmatterFieldNames); + applyNutrientTotalsToFrontmatter( + frontmatter, + totals, + this.settingsService.currentFrontmatterFieldNames, + this.settingsService.currentEnabledFrontmatterFields + ); } cancelPendingUpdates(): void { diff --git a/src/SettingsService.ts b/src/SettingsService.ts index 4e1e9e5..bad2cfb 100644 --- a/src/SettingsService.ts +++ b/src/SettingsService.ts @@ -13,6 +13,28 @@ export interface FrontmatterFieldNames { sodium: string; } +export interface EnabledFrontmatterFields { + calories: boolean; + fats: boolean; + saturated_fats: boolean; + protein: boolean; + carbs: boolean; + fiber: boolean; + sugar: boolean; + sodium: boolean; +} + +export const DEFAULT_ENABLED_FRONTMATTER_FIELDS: EnabledFrontmatterFields = Object.freeze({ + calories: true, + fats: true, + saturated_fats: true, + protein: true, + carbs: true, + fiber: true, + sugar: true, + sodium: true, +}); + const FRONTMATTER_KEYS_ORDER: Array = [ "calories", "fats", @@ -39,6 +61,10 @@ export function cloneFrontmatterFieldNames(names: FrontmatterFieldNames): Frontm return { ...names }; } +export function cloneEnabledFrontmatterFields(fields: EnabledFrontmatterFields): EnabledFrontmatterFields { + return { ...fields }; +} + function sanitizeFrontmatterFieldNames( fieldNames: Partial, base: FrontmatterFieldNames = DEFAULT_FRONTMATTER_FIELD_NAMES @@ -72,6 +98,8 @@ export function sanitizeSettings(settings: FoodTrackerPluginSettings): FoodTrack return { ...settings, frontmatterFieldNames: sanitizeFrontmatterFieldNames(settings.frontmatterFieldNames), + enabledFrontmatterFields: + settings.enabledFrontmatterFields ?? cloneEnabledFrontmatterFields(DEFAULT_ENABLED_FRONTMATTER_FIELDS), }; } @@ -84,6 +112,7 @@ export interface FoodTrackerPluginSettings { showCalorieHints: boolean; dailyNoteFormat: string; frontmatterFieldNames: FrontmatterFieldNames; + enabledFrontmatterFields: EnabledFrontmatterFields; linkType: "wikilink" | "markdown"; } @@ -96,6 +125,7 @@ export const DEFAULT_SETTINGS: FoodTrackerPluginSettings = { showCalorieHints: true, dailyNoteFormat: "YYYY-MM-DD", frontmatterFieldNames: cloneFrontmatterFieldNames(DEFAULT_FRONTMATTER_FIELD_NAMES), + enabledFrontmatterFields: cloneEnabledFrontmatterFields(DEFAULT_ENABLED_FRONTMATTER_FIELDS), linkType: "wikilink", }; @@ -183,6 +213,13 @@ export class SettingsService { return this.settings$.pipe(map(settings => settings.frontmatterFieldNames)); } + /** + * Observable stream of the enabled frontmatter fields + */ + get enabledFrontmatterFields$(): Observable { + return this.settings$.pipe(map(settings => settings.enabledFrontmatterFields)); + } + /** * Get the current settings value synchronously */ @@ -260,6 +297,13 @@ export class SettingsService { return cloneFrontmatterFieldNames(this.currentSettings.frontmatterFieldNames); } + /** + * Get the current enabled frontmatter fields synchronously + */ + get currentEnabledFrontmatterFields(): EnabledFrontmatterFields { + return cloneEnabledFrontmatterFields(this.currentSettings.enabledFrontmatterFields); + } + /** * Get the current link type value synchronously */ @@ -343,6 +387,17 @@ export class SettingsService { this.updateSetting("frontmatterFieldNames", sanitized); } + /** + * Updates enabled frontmatter fields (partial update supported) + */ + updateEnabledFrontmatterFields(fields: Partial): void { + const merged = { + ...this.currentEnabledFrontmatterFields, + ...fields, + }; + this.updateSetting("enabledFrontmatterFields", merged); + } + /** * Initialize the service with settings */