์‚ฌ์šฉ์ž๊ฐ€ ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ์ผ๋ถ€๋ฅผ ์ง์ ‘ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ ค๋ฉด ์„ค์ •(settings) ์œผ๋กœ ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ฐ€์ด๋“œ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์„ค์ • ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์›๋‹ˆ๋‹ค ๐Ÿ‘‡

ํ”Œ๋Ÿฌ๊ทธ์ธ์— ์„ค์ •์„ ์ถ”๊ฐ€ํ•˜๋Š” ์ฃผ๋œ ์ด์œ ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ Obsidian์„ ์ข…๋ฃŒํ•œ ํ›„์—๋„ ์œ ์ง€๋˜๋Š” ๊ตฌ์„ฑ์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์ œ๋Š” ๋””์Šคํฌ์—์„œ ์„ค์ •์„ ์ €์žฅํ•˜๊ณ  ๋กœ๋“œํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค:

import { Plugin } from 'obsidian';
import { ExampleSettingTab } from './settings';
 
interface ExamplePluginSettings {
  dateFormat: string;
}
 
const DEFAULT_SETTINGS: Partial<ExamplePluginSettings> = {
  dateFormat: 'YYYY-MM-DD',
};
 
export default class ExamplePlugin extends Plugin {
  settings: ExamplePluginSettings;
 
  async onload() {
    await this.loadSettings();
 
    this.addSettingTab(new ExampleSettingTab(this.app, this));
  }
 
  async loadSettings() {
    this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
  }
 
  async saveSettings() {
    await this.saveData(this.settings);
  }
}

์„ค์ •์˜ ์ค‘์ฒฉ๋œ ์†์„ฑ

Object.assign()์€ ์ค‘์ฒฉ๋œ ์†์„ฑ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค(์–•์€ ๋ณต์‚ฌ). ์„ค์ • ๊ฐ์ฒด์— ์ค‘์ฒฉ๋œ ์†์„ฑ์ด ํฌํ•จ๋œ ๊ฒฝ์šฐ, ๊ฐ ์ค‘์ฒฉ๋œ ์†์„ฑ์„ ์žฌ๊ท€์ ์œผ๋กœ ๋ณต์‚ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๊นŠ์€ ๋ณต์‚ฌ). ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ค‘์ฒฉ๋œ ์†์„ฑ์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด Object.assign()์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณต์‚ฌ๋œ ๋ชจ๋“  ๊ฐ์ฒด์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—๋Š” ๋งŽ์€ ๋‚ด์šฉ์ด ์žˆ์œผ๋‹ˆ ๐Ÿคฏ, ๊ฐ ๋ถ€๋ถ„์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์„ค์ • ์ •์˜ ์ƒ์„ฑํ•˜๊ธฐ

๋จผ์ €, ์‚ฌ์šฉ์ž๊ฐ€ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ ค๋Š” ์„ค์ •์— ๋Œ€ํ•œ ์ •์˜ ExamplePluginSettings๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋Š” ๋™์•ˆ settings ๋ฉค๋ฒ„ ๋ณ€์ˆ˜์—์„œ ์„ค์ •์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

interface ExamplePluginSettings {
  dateFormat: string;
}
 
export default class ExamplePlugin extends Plugin {
  settings: ExamplePluginSettings;
 
  // ...
}

์„ค์ • ๊ฐ์ฒด ์ €์žฅ ๋ฐ ๋กœ๋“œํ•˜๊ธฐ

loadData() ๋ฐ saveData()๋Š” ๋””์Šคํฌ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•˜๋Š” ์‰ฌ์šด ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ๋Š” ๋˜ํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„์—์„œ loadData() ๋ฐ saveData()๋ฅผ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ํ—ฌํผ ๋ฉ”์†Œ๋“œ๋ฅผ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.

export default class ExamplePlugin extends Plugin {
 
  // ...
 
  async loadSettings() {
    this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
  }
 
  async saveSettings() {
    await this.saveData(this.settings);
  }
}

๋งˆ์ง€๋ง‰์œผ๋กœ, ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ๋กœ๋“œ๋  ๋•Œ ์„ค์ •์„ ๋กœ๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

async onload() {
  await this.loadSettings();
 
  // ...
}

๊ธฐ๋ณธ๊ฐ’ ์ œ๊ณตํ•˜๊ธฐ

์‚ฌ์šฉ์ž๊ฐ€ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ฒ˜์Œ ํ™œ์„ฑํ™”ํ•˜๋ฉด ์„ค์ •์ด ์•„์ง ๊ตฌ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์•ž์˜ ์˜ˆ์ œ๋Š” ๋ˆ„๋ฝ๋œ ์„ค์ •์— ๋Œ€ํ•œ ๊ธฐ๋ณธ๊ฐ’์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

Object.assign({}, DEFAULT_SETTINGS, await this.loadData())

Object.assign()์€ ํ•œ ๊ฐ์ฒด์—์„œ ๋‹ค๋ฅธ ๊ฐ์ฒด๋กœ ๋ชจ๋“  ์†์„ฑ์„ ๋ณต์‚ฌํ•˜๋Š” JavaScript ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. loadData()์—์„œ ๋ฐ˜ํ™˜๋œ ๋ชจ๋“  ์†์„ฑ์€ DEFAULT_SETTINGS์˜ ์†์„ฑ์„ ๋ฎ์–ด์”๋‹ˆ๋‹ค.

const DEFAULT_SETTINGS: Partial<ExamplePluginSettings> = {
  dateFormat: 'YYYY-MM-DD',
};

Tip

Partial<Type>์€ Type์˜ ๋ชจ๋“  ์†์„ฑ์„ ์„ ํƒ์ ์œผ๋กœ ์„ค์ •ํ•œ ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๋Š” TypeScript ์œ ํ‹ธ๋ฆฌํ‹ฐ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์„ ์ œ๊ณตํ•˜๋ ค๋Š” ์†์„ฑ๋งŒ ์ •์˜ํ•˜๋ฉด์„œ ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„ค์ • ํƒญ ๋“ฑ๋กํ•˜๊ธฐ

์ด์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ตฌ์„ฑ์„ ์ €์žฅํ•˜๊ณ  ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์‚ฌ์šฉ์ž๋Š” ์•„์ง ์„ค์ •์„ ๋ณ€๊ฒฝํ•  ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค. ์„ค์ • ํƒญ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ค์ •์„ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋Š” ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

this.addSettingTab(new ExampleSettingTab(this.app, this));

์—ฌ๊ธฐ์„œ ExampleSettingTab์€ PluginSettingTab์„ ํ™•์žฅํ•˜๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค:

import ExamplePlugin from './main';
import { App, PluginSettingTab, Setting } from 'obsidian';
 
export class ExampleSettingTab extends PluginSettingTab {
  plugin: ExamplePlugin;
 
  constructor(app: App, plugin: ExamplePlugin) {
    super(app, plugin);
    this.plugin = plugin;
  }
 
  display(): void {
    let { containerEl } = this;
 
    containerEl.empty();
 
    new Setting(containerEl)
      .setName('Date format')
      .setDesc('Default date format')
      .addText((text) =>
        text
          .setPlaceholder('MMMM dd, yyyy')
          .setValue(this.plugin.settings.dateFormat)
          .onChange(async (value) => {
            this.plugin.settings.dateFormat = value;
            await this.plugin.saveSettings();
          })
      );
  }
}

display()๋Š” ์„ค์ • ํƒญ์˜ ๋‚ด์šฉ์„ ๋นŒ๋“œํ•˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ HTML elements๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

new Setting(containerEl)์€ ์ปจํ…Œ์ด๋„ˆ ์š”์†Œ์— ์„ค์ •์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ๋Š” addText()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…์ŠคํŠธ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ๋‹ค๋ฅธ ์—ฌ๋Ÿฌ ์„ค์ • ์œ ํ˜•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ…์ŠคํŠธ ํ•„๋“œ์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์„ค์ • ๊ฐ์ฒด๋ฅผ ์—…๋ฐ์ดํŠธํ•œ ๋‹ค์Œ ๋””์Šคํฌ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค:

.onChange(async (value) => {
  this.plugin.settings.dateFormat = value;
  await this.plugin.saveSettings();
})

์ž˜ํ–ˆ์Šต๋‹ˆ๋‹ค! ๐Ÿ’ช ์‚ฌ์šฉ์ž๋“ค์€ ํ”Œ๋Ÿฌ๊ทธ์ธ๊ณผ ์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉ์ž ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ด ์ค€ ๊ฒƒ์— ๋Œ€ํ•ด ๊ฐ์‚ฌํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ๊ฐ€์ด๋“œ๋กœ ๋„˜์–ด๊ฐ€๊ธฐ ์ „์—, ๋ฐฐ์šด ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ ๋‹ค๋ฅธ ์„ค์ •์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์‹คํ—˜ํ•ด๋ณด์„ธ์š”.