diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 71706e4..1ca7d6f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -96,6 +96,19 @@ body: validations: required: true + - type: dropdown + id: theme-mode + attributes: + label: Theme mode + description: Which Obsidian appearance mode does the bug occur in? If you haven't checked the other mode, please try to reproduce there as well — some issues are theme-specific. + options: + - Both light and dark mode + - Light mode only + - Dark mode only + - Not applicable / not visual + validations: + required: true + - type: textarea id: other-plugins attributes: diff --git a/.github/PULL_REQUEST_TEMPLATE/bugfix.md b/.github/PULL_REQUEST_TEMPLATE/bugfix.md index 51a9455..d7f1553 100644 --- a/.github/PULL_REQUEST_TEMPLATE/bugfix.md +++ b/.github/PULL_REQUEST_TEMPLATE/bugfix.md @@ -42,3 +42,4 @@ Fixes # - [ ] `npm run lint` passes. - [ ] `npm run build` passes with no TypeScript errors. - [ ] I have tested with existing contact notes to confirm no regression. +- [ ] I have verified the fix in both light and dark mode (if the bug is visual). diff --git a/.github/PULL_REQUEST_TEMPLATE/feature.md b/.github/PULL_REQUEST_TEMPLATE/feature.md index 62a2ab9..667113d 100644 --- a/.github/PULL_REQUEST_TEMPLATE/feature.md +++ b/.github/PULL_REQUEST_TEMPLATE/feature.md @@ -40,5 +40,6 @@ Closes # - [ ] `npm run build` passes with no TypeScript errors. - [ ] I have tested with both folder-based and tag-based contact identification (if relevant). - [ ] I have tested with existing contact notes to confirm no regression. +- [ ] I have verified the feature renders correctly in both light and dark mode (if it adds or modifies UI). - [ ] I have updated the README to document the new feature (if relevant). - [ ] Settings persist correctly across reloads (if settings were changed). diff --git a/.github/PULL_REQUEST_TEMPLATE/refactor.md b/.github/PULL_REQUEST_TEMPLATE/refactor.md index e315031..573a3a5 100644 --- a/.github/PULL_REQUEST_TEMPLATE/refactor.md +++ b/.github/PULL_REQUEST_TEMPLATE/refactor.md @@ -33,3 +33,4 @@ - [ ] `npm run lint` passes. - [ ] `npm run build` passes with no TypeScript errors. - [ ] I have tested the affected areas in a local vault to confirm no regression. +- [ ] I have verified the affected UI in both light and dark mode (if any styles or DOM structure were touched). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d85794b..14c7b76 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,6 +15,7 @@ Before opening a new bug report: - Search [existing issues](https://github.com/Jalad25/contact-note/issues) to see if it has already been reported. - Make sure you are running the latest version of the plugin and the minimum required version of Obsidian. - Try to reproduce the bug in a clean vault with other plugins disabled or removed. +- Try to reproduce the bug in **both light and dark mode**, since some issues are theme-specific. ## Suggesting Enhancements diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 12c3b84..e80391c 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -97,6 +97,7 @@ Currently, the project relies on manual testing within an Obsidian vault. When m - Settings persist across reloads. - The contact list view updates correctly when notes are added, modified, or deleted. - Both folder-based and tag-based contact identification work. +- The plugin renders correctly in **both light and dark mode**. All bugs, features, and UI changes should be verified against both themes before submission. ## Submitting Changes diff --git a/README.md b/README.md index 148d070..82cb370 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ An [Obsidian](https://obsidian.md/) plugin that renders visual contact cards fro - **Multiple Values for Certain Frontmatter Properties**: Supports multiple emails, phone numbers, and social media profiles per contact. - **Default Filters**: Create default list filters based on any frontmatter property! - **Contact Note Identification**: Contacts identified by folder or tag. +- **Light and Dark Mode Support**: All plugin UI is styled for both Obsidian themes. ## Installation diff --git a/src/SchemaMigration.ts b/src/SchemaMigration.ts new file mode 100644 index 0000000..97b321c --- /dev/null +++ b/src/SchemaMigration.ts @@ -0,0 +1,59 @@ +/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument -- This module reads untyped JSON of unknown shape from prior plugin versions. Strict typing here would only obscure the runtime guards that actually protect against malformed input. */ + +import { ContactNoteSettings } from "./main"; + +//#region Constants + +export const CURRENT_SCHEMA_VERSION = 0; + +const MIGRATIONS: Migration[] = []; + +//#endregion + +//#region Types/Objects/Interfaces + +type Migration = { + from: number; + to: number; + apply: (raw: any) => Partial & { schemaVersion: number }; +}; + +export type MigrationResult = { + values: Partial; + migrated: boolean; +}; + +//#endregion + +//#region Migration + +export function migrate(raw: unknown): MigrationResult { + if (!raw || typeof raw !== "object") { + return { values: { schemaVersion: CURRENT_SCHEMA_VERSION }, migrated: true }; + } + + let current: any = raw; + let version: number = typeof current.schemaVersion === "number" ? current.schemaVersion : 0; + + let migrated = false; + while (version < CURRENT_SCHEMA_VERSION) { + const step = MIGRATIONS.find((m) => m.from === version); + if (!step) break; + current = step.apply(current); + version = step.to; + migrated = true; + } + + return { + values: current as Partial, + migrated + }; +} + +//#endregion + +//#region Migration Step Functions + +/* This is a per-version migration steps. Append new functions below for each schema change and add it to MIGRATIONS. Never edit existing steps. */ + +//#endregion diff --git a/src/main.ts b/src/main.ts index d04b8a6..85038b3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -10,6 +10,7 @@ import { ContactListView } from "./ContactListView"; import { ContactNoteSettingTab } from "./ContactNoteSettingTab"; import { Contact } from "./Contact"; import { buildContactCard } from "./ContactCard"; +import { CURRENT_SCHEMA_VERSION, migrate } from "./SchemaMigration"; //#region Types/Objects/Interface @@ -20,6 +21,7 @@ export interface FrontmatterFilter { } export interface ContactNoteSettings { + schemaVersion: number; useFolder: boolean; folderPath: string; tag: string; @@ -34,6 +36,7 @@ export interface ContactNoteSettings { //#region Constants/Defaults export const DEFAULT_SETTINGS: ContactNoteSettings = { + schemaVersion: CURRENT_SCHEMA_VERSION, useFolder: true, folderPath: "Contacts", tag: "contact", @@ -140,7 +143,10 @@ export default class ContactNotePlugin extends Plugin { async loadSettings() { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Disabling eslint as this is an issue triggered by Obsidian's API. Triggers locally - this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + const raw = await this.loadData(); + const { values, migrated } = migrate(raw); + this.settings = Object.assign({}, DEFAULT_SETTINGS, values); + if (migrated) await this.saveSettings(); } async saveSettings() {