obsidian-plugin-config 1.3.9 → 1.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/obsidian-inject.js +1 -1
- package/docs/LLM-GUIDE.md +111 -0
- package/package.json +3 -3
- package/scripts/build-npm.ts +17 -5
- package/scripts/help.ts +37 -32
- package/scripts/inject-core.ts +28 -40
- package/src/main.ts +105 -108
- package/src/modals/GenericConfirmModal.ts +48 -47
- package/src/tools/index.ts +3 -3
- package/src/utils/NoticeHelper.ts +70 -87
- package/src/utils/SettingsHelper.ts +158 -168
- package/templates/.editorconfig +5 -1
- package/templates/package-sass.json +5 -0
- package/templates/package.json +43 -0
- package/templates/scripts/esbuild.config.ts +1 -1
- package/templates/scripts/help.ts +6 -7
- package/templates/tsconfig.json +29 -40
- package/versions.json +4 -1
- package/templates/help-plugin.ts +0 -51
|
@@ -1,66 +1,67 @@
|
|
|
1
|
-
import { App, Modal } from
|
|
1
|
+
import { App, Modal } from 'obsidian';
|
|
2
2
|
|
|
3
3
|
export interface ConfirmModalOptions {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
title: string;
|
|
5
|
+
message: string;
|
|
6
|
+
confirmText?: string;
|
|
7
|
+
cancelText?: string;
|
|
8
|
+
onConfirm: () => void;
|
|
9
|
+
onCancel?: () => void;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export class GenericConfirmModal extends Modal {
|
|
13
|
-
|
|
13
|
+
private options: ConfirmModalOptions;
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
constructor(app: App, options: ConfirmModalOptions) {
|
|
16
|
+
super(app);
|
|
17
|
+
this.options = options;
|
|
18
|
+
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
onOpen(): void {
|
|
21
|
+
const { contentEl } = this;
|
|
22
|
+
contentEl.empty();
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const title =
|
|
25
|
+
this.options.title.charAt(0).toUpperCase() + this.options.title.slice(1);
|
|
26
|
+
contentEl.createEl('h2', { text: title });
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
// Message
|
|
29
|
+
contentEl.createEl('p', { text: this.options.message });
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
// Buttons container
|
|
32
|
+
const buttonContainer = contentEl.createDiv('modal-button-container');
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
// Cancel button
|
|
35
|
+
const cancelBtn = buttonContainer.createEl('button', {
|
|
36
|
+
text: this.options.cancelText || 'Cancel',
|
|
37
|
+
cls: 'mod-cta'
|
|
38
|
+
});
|
|
39
|
+
cancelBtn.addEventListener('click', () => {
|
|
40
|
+
this.options.onCancel?.();
|
|
41
|
+
this.close();
|
|
42
|
+
});
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
// Confirm button
|
|
45
|
+
const confirmBtn = buttonContainer.createEl('button', {
|
|
46
|
+
text: this.options.confirmText || 'Confirm',
|
|
47
|
+
cls: 'mod-cta mod-warning'
|
|
48
|
+
});
|
|
49
|
+
confirmBtn.addEventListener('click', () => {
|
|
50
|
+
this.options.onConfirm();
|
|
51
|
+
this.close();
|
|
52
|
+
});
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
// Focus on confirm button
|
|
55
|
+
confirmBtn.focus();
|
|
56
|
+
}
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
onClose(): void {
|
|
59
|
+
const { contentEl } = this;
|
|
60
|
+
contentEl.empty();
|
|
61
|
+
}
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
// Utility function for quick usage
|
|
64
65
|
export function showConfirmModal(app: App, options: ConfirmModalOptions): void {
|
|
65
|
-
|
|
66
|
+
new GenericConfirmModal(app, options).open();
|
|
66
67
|
}
|
package/src/tools/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Simple tools for testing
|
|
2
2
|
export function showTestMessage(): string {
|
|
3
|
-
|
|
3
|
+
return '✅ CENTRALIZED TOOLS WORK! This comes from obsidian-plugin-config!';
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
export function getRandomEmoji(): string {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const emojis = ['🚀', '🎉', '✨', '🔥', '💯', '⚡', '🎯', '🌟'];
|
|
8
|
+
return emojis[Math.floor(Math.random() * emojis.length)];
|
|
9
9
|
}
|
|
@@ -1,102 +1,85 @@
|
|
|
1
|
-
import { Notice } from
|
|
1
|
+
import { Notice } from 'obsidian';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Enhanced Notice helper with different types and durations
|
|
5
5
|
*/
|
|
6
6
|
export class NoticeHelper {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
private static readonly DEFAULT_DURATION = 5000;
|
|
8
|
+
private static readonly SUCCESS_DURATION = 3000;
|
|
9
|
+
private static readonly ERROR_DURATION = 8000;
|
|
10
|
+
private static readonly WARNING_DURATION = 6000;
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
);
|
|
20
|
-
return notice;
|
|
21
|
-
}
|
|
12
|
+
/**
|
|
13
|
+
* Show a success notice with green styling
|
|
14
|
+
*/
|
|
15
|
+
static success(message: string, duration?: number): Notice {
|
|
16
|
+
const notice = new Notice(`✅ ${message}`, duration ?? this.SUCCESS_DURATION);
|
|
17
|
+
return notice;
|
|
18
|
+
}
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
);
|
|
31
|
-
return notice;
|
|
32
|
-
}
|
|
20
|
+
/**
|
|
21
|
+
* Show an error notice with red styling
|
|
22
|
+
*/
|
|
23
|
+
static error(message: string, duration?: number): Notice {
|
|
24
|
+
const notice = new Notice(`❌ ${message}`, duration ?? this.ERROR_DURATION);
|
|
25
|
+
return notice;
|
|
26
|
+
}
|
|
33
27
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
42
|
-
return notice;
|
|
43
|
-
}
|
|
28
|
+
/**
|
|
29
|
+
* Show a warning notice with yellow styling
|
|
30
|
+
*/
|
|
31
|
+
static warning(message: string, duration?: number): Notice {
|
|
32
|
+
const notice = new Notice(`⚠️ ${message}`, duration ?? this.WARNING_DURATION);
|
|
33
|
+
return notice;
|
|
34
|
+
}
|
|
44
35
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
);
|
|
53
|
-
return notice;
|
|
54
|
-
}
|
|
36
|
+
/**
|
|
37
|
+
* Show an info notice with blue styling
|
|
38
|
+
*/
|
|
39
|
+
static info(message: string, duration?: number): Notice {
|
|
40
|
+
const notice = new Notice(`ℹ️ ${message}`, duration ?? this.DEFAULT_DURATION);
|
|
41
|
+
return notice;
|
|
42
|
+
}
|
|
55
43
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Show a loading notice that can be updated
|
|
46
|
+
*/
|
|
47
|
+
static loading(message: string): Notice {
|
|
48
|
+
return new Notice(`⏳ ${message}`, 0); // 0 = permanent until manually hidden
|
|
49
|
+
}
|
|
62
50
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Update a loading notice to success and auto-hide
|
|
53
|
+
*/
|
|
54
|
+
static updateToSuccess(notice: Notice, message: string): void {
|
|
55
|
+
notice.setMessage(`✅ ${message}`);
|
|
56
|
+
setTimeout(() => notice.hide(), this.SUCCESS_DURATION);
|
|
57
|
+
}
|
|
70
58
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Update a loading notice to error and auto-hide
|
|
61
|
+
*/
|
|
62
|
+
static updateToError(notice: Notice, message: string): void {
|
|
63
|
+
notice.setMessage(`❌ ${message}`);
|
|
64
|
+
setTimeout(() => notice.hide(), this.ERROR_DURATION);
|
|
65
|
+
}
|
|
78
66
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
duration ?? this.DEFAULT_DURATION
|
|
86
|
-
);
|
|
87
|
-
}
|
|
67
|
+
/**
|
|
68
|
+
* Show a notice with custom emoji and duration
|
|
69
|
+
*/
|
|
70
|
+
static custom(emoji: string, message: string, duration?: number): Notice {
|
|
71
|
+
return new Notice(`${emoji} ${message}`, duration ?? this.DEFAULT_DURATION);
|
|
72
|
+
}
|
|
88
73
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
);
|
|
101
|
-
}
|
|
74
|
+
/**
|
|
75
|
+
* Show a progress notice for long operations
|
|
76
|
+
*/
|
|
77
|
+
static progress(message: string, current: number, total: number): Notice {
|
|
78
|
+
const percentage = Math.round((current / total) * 100);
|
|
79
|
+
const progressBar =
|
|
80
|
+
'█'.repeat(Math.floor(percentage / 5)) +
|
|
81
|
+
'░'.repeat(20 - Math.floor(percentage / 5));
|
|
82
|
+
|
|
83
|
+
return new Notice(`🔄 ${message}\n[${progressBar}] ${percentage}%`, 0);
|
|
84
|
+
}
|
|
102
85
|
}
|
|
@@ -1,180 +1,170 @@
|
|
|
1
|
-
import { Setting } from
|
|
1
|
+
import { Setting } from 'obsidian';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Helper for creating common setting types with consistent styling
|
|
5
5
|
*/
|
|
6
6
|
export class SettingsHelper {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Create a text input setting
|
|
9
|
+
*/
|
|
10
|
+
static createTextSetting(
|
|
11
|
+
containerEl: HTMLElement,
|
|
12
|
+
name: string,
|
|
13
|
+
desc: string,
|
|
14
|
+
value: string,
|
|
15
|
+
onChange: (value: string) => void,
|
|
16
|
+
placeholder?: string
|
|
17
|
+
): Setting {
|
|
18
|
+
return new Setting(containerEl)
|
|
19
|
+
.setName(name)
|
|
20
|
+
.setDesc(desc)
|
|
21
|
+
.addText((text) =>
|
|
22
|
+
text
|
|
23
|
+
.setPlaceholder(placeholder || '')
|
|
24
|
+
.setValue(value)
|
|
25
|
+
.onChange(onChange)
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
.onChange(onChange)
|
|
45
|
-
);
|
|
46
|
-
}
|
|
29
|
+
/**
|
|
30
|
+
* Create a toggle setting
|
|
31
|
+
*/
|
|
32
|
+
static createToggleSetting(
|
|
33
|
+
containerEl: HTMLElement,
|
|
34
|
+
name: string,
|
|
35
|
+
desc: string,
|
|
36
|
+
value: boolean,
|
|
37
|
+
onChange: (value: boolean) => void
|
|
38
|
+
): Setting {
|
|
39
|
+
return new Setting(containerEl)
|
|
40
|
+
.setName(name)
|
|
41
|
+
.setDesc(desc)
|
|
42
|
+
.addToggle((toggle) => toggle.setValue(value).onChange(onChange));
|
|
43
|
+
}
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
});
|
|
70
|
-
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a dropdown setting
|
|
47
|
+
*/
|
|
48
|
+
static createDropdownSetting(
|
|
49
|
+
containerEl: HTMLElement,
|
|
50
|
+
name: string,
|
|
51
|
+
desc: string,
|
|
52
|
+
options: Record<string, string>,
|
|
53
|
+
value: string,
|
|
54
|
+
onChange: (value: string) => void
|
|
55
|
+
): Setting {
|
|
56
|
+
return new Setting(containerEl)
|
|
57
|
+
.setName(name)
|
|
58
|
+
.setDesc(desc)
|
|
59
|
+
.addDropdown((dropdown) => {
|
|
60
|
+
Object.entries(options).forEach(([key, label]) => {
|
|
61
|
+
dropdown.addOption(key, label);
|
|
62
|
+
});
|
|
63
|
+
dropdown.setValue(value).onChange(onChange);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
71
66
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
text
|
|
95
|
-
.setValue(value.toString())
|
|
96
|
-
.onChange(val => {
|
|
97
|
-
const num = parseFloat(val);
|
|
98
|
-
if (!isNaN(num)) onChange(num);
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
}
|
|
67
|
+
/**
|
|
68
|
+
* Create a number input setting
|
|
69
|
+
*/
|
|
70
|
+
static createNumberSetting(
|
|
71
|
+
containerEl: HTMLElement,
|
|
72
|
+
name: string,
|
|
73
|
+
desc: string,
|
|
74
|
+
value: number,
|
|
75
|
+
onChange: (value: number) => void,
|
|
76
|
+
min?: number,
|
|
77
|
+
max?: number,
|
|
78
|
+
step?: number
|
|
79
|
+
): Setting {
|
|
80
|
+
return new Setting(containerEl)
|
|
81
|
+
.setName(name)
|
|
82
|
+
.setDesc(desc)
|
|
83
|
+
.addText((text) => {
|
|
84
|
+
text.inputEl.type = 'number';
|
|
85
|
+
if (min !== undefined) text.inputEl.min = min.toString();
|
|
86
|
+
if (max !== undefined) text.inputEl.max = max.toString();
|
|
87
|
+
if (step !== undefined) text.inputEl.step = step.toString();
|
|
102
88
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
desc: string,
|
|
110
|
-
buttonText: string,
|
|
111
|
-
onClick: () => void
|
|
112
|
-
): Setting {
|
|
113
|
-
return new Setting(containerEl)
|
|
114
|
-
.setName(name)
|
|
115
|
-
.setDesc(desc)
|
|
116
|
-
.addButton(button => button
|
|
117
|
-
.setButtonText(buttonText)
|
|
118
|
-
.onClick(onClick)
|
|
119
|
-
);
|
|
120
|
-
}
|
|
89
|
+
text.setValue(value.toString()).onChange((val) => {
|
|
90
|
+
const num = parseFloat(val);
|
|
91
|
+
if (!isNaN(num)) onChange(num);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
121
95
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const descEl = containerEl.createEl("p", { text: description });
|
|
138
|
-
descEl.style.marginTop = "0";
|
|
139
|
-
descEl.style.marginBottom = "15px";
|
|
140
|
-
descEl.style.color = "var(--text-muted)";
|
|
141
|
-
descEl.style.fontSize = "0.9em";
|
|
142
|
-
}
|
|
143
|
-
}
|
|
96
|
+
/**
|
|
97
|
+
* Create a button setting
|
|
98
|
+
*/
|
|
99
|
+
static createButtonSetting(
|
|
100
|
+
containerEl: HTMLElement,
|
|
101
|
+
name: string,
|
|
102
|
+
desc: string,
|
|
103
|
+
buttonText: string,
|
|
104
|
+
onClick: () => void
|
|
105
|
+
): Setting {
|
|
106
|
+
return new Setting(containerEl)
|
|
107
|
+
.setName(name)
|
|
108
|
+
.setDesc(desc)
|
|
109
|
+
.addButton((button) => button.setButtonText(buttonText).onClick(onClick));
|
|
110
|
+
}
|
|
144
111
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
112
|
+
/**
|
|
113
|
+
* Create a section header
|
|
114
|
+
*/
|
|
115
|
+
static createHeader(
|
|
116
|
+
containerEl: HTMLElement,
|
|
117
|
+
title: string,
|
|
118
|
+
description?: string
|
|
119
|
+
): void {
|
|
120
|
+
const headerEl = containerEl.createEl('h3', { text: title });
|
|
121
|
+
headerEl.style.marginTop = '20px';
|
|
122
|
+
headerEl.style.marginBottom = '10px';
|
|
123
|
+
headerEl.style.borderBottom = '1px solid var(--background-modifier-border)';
|
|
124
|
+
headerEl.style.paddingBottom = '5px';
|
|
125
|
+
|
|
126
|
+
if (description) {
|
|
127
|
+
const descEl = containerEl.createEl('p', { text: description });
|
|
128
|
+
descEl.style.marginTop = '0';
|
|
129
|
+
descEl.style.marginBottom = '15px';
|
|
130
|
+
descEl.style.color = 'var(--text-muted)';
|
|
131
|
+
descEl.style.fontSize = '0.9em';
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Create a collapsible section
|
|
137
|
+
*/
|
|
138
|
+
static createCollapsibleSection(
|
|
139
|
+
containerEl: HTMLElement,
|
|
140
|
+
title: string,
|
|
141
|
+
isOpen: boolean = false
|
|
142
|
+
): { container: HTMLElement; toggle: () => void } {
|
|
143
|
+
const sectionEl = containerEl.createDiv('setting-item');
|
|
144
|
+
const headerEl = sectionEl.createDiv('setting-item-info');
|
|
145
|
+
const nameEl = headerEl.createDiv('setting-item-name');
|
|
146
|
+
nameEl.setText(title);
|
|
147
|
+
nameEl.style.cursor = 'pointer';
|
|
148
|
+
nameEl.style.userSelect = 'none';
|
|
149
|
+
|
|
150
|
+
const contentEl = containerEl.createDiv('collapsible-content');
|
|
151
|
+
contentEl.style.display = isOpen ? 'block' : 'none';
|
|
152
|
+
contentEl.style.marginLeft = '20px';
|
|
153
|
+
contentEl.style.marginTop = '10px';
|
|
154
|
+
|
|
155
|
+
const arrow = nameEl.createSpan('collapse-icon');
|
|
156
|
+
arrow.setText(isOpen ? '▼' : '▶');
|
|
157
|
+
arrow.style.marginRight = '8px';
|
|
158
|
+
arrow.style.fontSize = '0.8em';
|
|
159
|
+
|
|
160
|
+
const toggle = (): void => {
|
|
161
|
+
const isCurrentlyOpen = contentEl.style.display !== 'none';
|
|
162
|
+
contentEl.style.display = isCurrentlyOpen ? 'none' : 'block';
|
|
163
|
+
arrow.setText(isCurrentlyOpen ? '▶' : '▼');
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
nameEl.addEventListener('click', toggle);
|
|
167
|
+
|
|
168
|
+
return { container: contentEl, toggle };
|
|
169
|
+
}
|
|
180
170
|
}
|
package/templates/.editorconfig
CHANGED