Skip to content

Commit b7723f6

Browse files
committed
4.1.0
- Added copy content button setting (closes #28)
1 parent 2ffb266 commit b7723f6

File tree

9 files changed

+162
-92
lines changed

9 files changed

+162
-92
lines changed

@types/types.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,21 @@ export interface INestedAdmonition {
1212
end: number;
1313
src: string;
1414
}
15+
16+
export interface ISettingsData {
17+
userAdmonitions: {
18+
[admonitionType: string]: Admonition;
19+
};
20+
syntaxHighlight: boolean;
21+
copyButton: boolean;
22+
version: string;
23+
}
1524
export declare class ObsidianAdmonitionPlugin extends Plugin_2 {
1625
removeAdmonition: (admonition: Admonition) => Promise<void>;
1726
admonitions: { [admonitionType: string]: Admonition };
18-
userAdmonitions: { [admonitionType: string]: Admonition };
19-
syntaxHighlight: boolean;
27+
/* userAdmonitions: { [admonitionType: string]: Admonition };
28+
syntaxHighlight: boolean; */
29+
data: ISettingsData;
2030
turnOnSyntaxHighlighting: (types?: string[]) => void;
2131
turnOffSyntaxHighlighting: (types?: string[]) => void;
2232
saveSettings: () => Promise<void>;

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,15 +275,31 @@ An icon without a title will have this CSS:
275275
}
276276
```
277277

278+
## Settings
279+
280+
### Syntax Highlighting
281+
282+
Turns on an experimental mode that uses Obsidian's markdown syntax highlighter inside admonition code blocks.
283+
284+
### Copy Button
285+
286+
Adds a "copy content" button to every admonition block.
287+
278288
## Todo
279289

280290
- [x] Add the ability to collapse the admonition
281291
- [x] Custom admonitions
282292
- [x] Settings tab to customize icon and color of all admonitions
283293
- [x] Ability to render markdown inside an admonition
294+
- [ ] Top-level Python Markdown-style admonitions
284295

285296
# Version History
286297

298+
## 4.1.0
299+
300+
- Added "Copy Button" setting
301+
- Turning this on adds a "copy content" button to each admonition, which copies the admonition content to the clipboard
302+
287303
## 4.0.0
288304

289305
- Nested admonitions are now possible

manifest.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
2-
"id": "obsidian-admonition",
3-
"name": "Admonition",
4-
"version": "4.0.1",
5-
"minAppVersion": "0.11.0",
6-
"description": "Admonition block-styled content for Obsidian.md",
7-
"author": "Jeremy Valentine",
8-
"authorUrl": "",
9-
"isDesktopOnly": false
10-
}
2+
"id": "obsidian-admonition",
3+
"name": "Admonition",
4+
"version": "4.1.0",
5+
"minAppVersion": "0.11.0",
6+
"description": "Admonition block-styled content for Obsidian.md",
7+
"author": "Jeremy Valentine",
8+
"authorUrl": "",
9+
"isDesktopOnly": false
10+
}

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "obsidian-admonition",
3-
"version": "4.0.1",
3+
"version": "4.1.0",
44
"description": "Admonition block-styled content for Obsidian.md",
55
"main": "main.js",
66
"scripts": {
@@ -13,6 +13,7 @@
1313
"devDependencies": {
1414
"@fortawesome/fontawesome-svg-core": "^1.2.35",
1515
"@fortawesome/free-solid-svg-icons": "^5.15.1",
16+
"@fortawesome/free-regular-svg-icons": "^5.15.3",
1617
"@rollup/plugin-commonjs": "^15.1.0",
1718
"@rollup/plugin-node-resolve": "^9.0.0",
1819
"@rollup/plugin-typescript": "^6.0.0",
@@ -24,5 +25,6 @@
2425
"rollup-plugin-css-only": "^3.1.0",
2526
"tslib": "^2.0.3",
2627
"typescript": "^4.0.3"
27-
}
28-
}
28+
},
29+
"dependencies": {}
30+
}

src/icons.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { fas } from "@fortawesome/free-solid-svg-icons";
2+
import { faCopy } from "@fortawesome/free-regular-svg-icons";
23
import {
34
findIconDefinition,
45
icon,
56
library
67
} from "@fortawesome/fontawesome-svg-core";
78

8-
library.add(fas);
9+
library.add(fas, faCopy);
910

1011
export { icon, findIconDefinition };

src/main.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@
5353

5454
.admonition-content {
5555
margin: 0 0.6rem;
56+
position: relative;
57+
}
58+
.admonition-content-copy {
59+
position: absolute;
60+
top: 0;
61+
right: 0;
62+
color: var(--text-faint);
63+
cursor: pointer;
64+
margin: -10px -2px;
65+
}
66+
.admonition-content-copy:hover {
67+
color: var(--text-normal);
5668
}
5769

5870
details.admonition:not([open]) {

src/main.ts

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import {
88
} from "obsidian";
99
import {
1010
Admonition,
11-
INestedAdmonition,
12-
ObsidianAdmonitionPlugin
11+
ObsidianAdmonitionPlugin,
12+
ISettingsData
1313
} from "../@types/types";
1414
import {
1515
getAdmonitionElement,
@@ -48,12 +48,16 @@ Object.fromEntries =
4848
return obj;
4949
};
5050

51-
/* const compareVersions = (a: string, b: string) => {
52-
return a.localeCompare(b, undefined, { numeric: true }) === 1;
53-
}; */
54-
5551
import "./main.css";
5652
import AdmonitionSetting from "./settings";
53+
import { findIconDefinition, icon } from "@fortawesome/fontawesome-svg-core";
54+
55+
const DEFAULT_APP_SETTINGS: ISettingsData = {
56+
userAdmonitions: {},
57+
syntaxHighlight: false,
58+
copyButton: false,
59+
version: ""
60+
};
5761

5862
const ADMONITION_MAP: {
5963
[admonitionType: string]: Admonition;
@@ -104,69 +108,63 @@ const ADMONITION_MAP: {
104108
};
105109
export default class ObsidianAdmonition
106110
extends Plugin
107-
implements ObsidianAdmonitionPlugin {
111+
implements ObsidianAdmonitionPlugin
112+
{
108113
admonitions: { [admonitionType: string]: Admonition } = {};
109-
userAdmonitions: { [admonitionType: string]: Admonition } = {};
110-
syntaxHighlight: boolean;
114+
/* userAdmonitions: { [admonitionType: string]: Admonition } = {};
115+
syntaxHighlight: boolean; */
116+
data: ISettingsData;
111117
get types() {
112118
return Object.keys(this.admonitions);
113119
}
114120
async saveSettings() {
115-
await this.saveData({
116-
syntaxHighlight: this.syntaxHighlight || false,
117-
userAdmonitions: this.userAdmonitions || {},
118-
version: this.manifest.version
119-
});
121+
await this.saveData(this.data);
120122
}
121-
async loadSettings() {
122-
let data = Object.assign({}, await this.loadData());
123123

124-
if (!Object.prototype.hasOwnProperty.call(data, "syntaxHighlight")) {
125-
data = {
126-
userAdmonitions: data,
127-
syntaxHighlight: false
128-
};
129-
}
124+
async loadSettings() {
125+
let data = Object.assign(
126+
{},
127+
DEFAULT_APP_SETTINGS,
128+
await this.loadData()
129+
);
130130

131-
let { userAdmonitions = {}, syntaxHighlight = false } = data || {};
132-
this.userAdmonitions = userAdmonitions;
133-
this.syntaxHighlight = syntaxHighlight;
131+
this.data = data;
134132

135133
this.admonitions = {
136134
...ADMONITION_MAP,
137-
...this.userAdmonitions
135+
...this.data.userAdmonitions
138136
};
139137
await this.saveSettings();
140138
}
141139
async addAdmonition(admonition: Admonition): Promise<void> {
142-
this.userAdmonitions = {
143-
...this.userAdmonitions,
140+
this.data.userAdmonitions = {
141+
...this.data.userAdmonitions,
144142
[admonition.type]: admonition
145143
};
146144
this.admonitions = {
147145
...ADMONITION_MAP,
148-
...this.userAdmonitions
146+
...this.data.userAdmonitions
149147
};
150148
this.registerMarkdownCodeBlockProcessor(
151149
`ad-${admonition.type}`,
152150
this.postprocessor.bind(this, admonition.type)
153151
);
154-
if (this.syntaxHighlight) {
152+
if (this.data.syntaxHighlight) {
155153
this.turnOnSyntaxHighlighting([admonition.type]);
156154
}
157155
await this.saveSettings();
158156
}
159157

160158
async removeAdmonition(admonition: Admonition) {
161-
if (this.userAdmonitions[admonition.type]) {
162-
delete this.userAdmonitions[admonition.type];
159+
if (this.data.userAdmonitions[admonition.type]) {
160+
delete this.data.userAdmonitions[admonition.type];
163161
}
164162
this.admonitions = {
165163
...ADMONITION_MAP,
166-
...this.userAdmonitions
164+
...this.data.userAdmonitions
167165
};
168166

169-
if (this.syntaxHighlight) {
167+
if (this.data.syntaxHighlight) {
170168
this.turnOffSyntaxHighlighting([admonition.type]);
171169
}
172170

@@ -185,7 +183,7 @@ export default class ObsidianAdmonition
185183
this.postprocessor.bind(this, type)
186184
);
187185
});
188-
if (this.syntaxHighlight) {
186+
if (this.data.syntaxHighlight) {
189187
this.turnOnSyntaxHighlighting();
190188
}
191189

@@ -196,9 +194,8 @@ export default class ObsidianAdmonition
196194
let view = this.app.workspace.getActiveViewOfType(MarkdownView);
197195
if (!view || !(view instanceof MarkdownView)) return;
198196

199-
let admonitions = view.contentEl.querySelectorAll(
200-
"details[open]"
201-
);
197+
let admonitions =
198+
view.contentEl.querySelectorAll("details[open]");
202199
for (let i = 0; i < admonitions.length; i++) {
203200
let admonition = admonitions[i];
204201
admonition.removeAttribute("open");
@@ -223,9 +220,9 @@ export default class ObsidianAdmonition
223220
});
224221
}
225222
turnOnSyntaxHighlighting(types: string[] = Object.keys(this.admonitions)) {
226-
if (!this.syntaxHighlight) return;
223+
if (!this.data.syntaxHighlight) return;
227224
types.forEach((type) => {
228-
if (this.syntaxHighlight) {
225+
if (this.data.syntaxHighlight) {
229226
/** Process from @deathau's syntax highlight plugin */
230227
CodeMirror.defineMode(`ad-${type}`, (config, options) => {
231228
return CodeMirror.getMode(config, "hypermd");
@@ -334,15 +331,32 @@ export default class ObsidianAdmonition
334331
markdownRenderChild
335332
);
336333

334+
if (this.data.copyButton) {
335+
let copy = admonitionContent
336+
.createDiv("admonition-content-copy")
337+
.appendChild(
338+
icon(
339+
findIconDefinition({
340+
iconName: "copy",
341+
prefix: "far"
342+
})
343+
).node[0]
344+
);
345+
copy.addEventListener("click", () => {
346+
navigator.clipboard.writeText(content).then(() => {
347+
new Notice("Admonition content copied to clipboard.");
348+
});
349+
});
350+
}
351+
337352
const taskLists = admonitionContent.querySelectorAll(
338353
".contains-task-list"
339354
);
340355
const splitContent = content.split("\n");
341356

342357
for (let i = 0; i < taskLists.length; i++) {
343-
let tasks: NodeListOf<HTMLLIElement> = taskLists[
344-
i
345-
].querySelectorAll(".task-list-item");
358+
let tasks: NodeListOf<HTMLLIElement> =
359+
taskLists[i].querySelectorAll(".task-list-item");
346360
if (!tasks.length) continue;
347361
for (let j = 0; j < tasks.length; j++) {
348362
let task = tasks[j];

0 commit comments

Comments
 (0)