mirror of
https://github.com/4source/favorites-obsidian-plugin.git
synced 2026-07-22 16:40:28 +00:00
Compare commits
12 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a09294e56 | ||
|
|
e0c6469396 | ||
|
|
663db4c648 | ||
|
|
8c53184308 | ||
|
|
fcc243b4ee | ||
|
|
b7d7227a7c | ||
|
|
a4182bf48a | ||
|
|
8f706c9372 | ||
|
|
81a01388fa | ||
|
|
40c4930ba1 | ||
|
|
7303174298 | ||
|
|
7293d464c2 |
47 changed files with 1898 additions and 362 deletions
|
|
@ -9,7 +9,6 @@
|
|||
"allow": [
|
||||
"warn",
|
||||
"error",
|
||||
"debug"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
|
|||
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
|
|
@ -26,6 +26,8 @@ If not related issue exists, open a new one using the appropriate <a href="../..
|
|||
#### 1. Fork the repository.
|
||||
#### 2. Create a new vault
|
||||
Just for testing the plugin so you **can't** exedentially destroy your real vault
|
||||
> [!NOTE]
|
||||
> When you working with ``npm run dev`` the plugin will use another key to identify the favorite lists. This **should** ensure you are not overwriting your real favorite lists. When you are working with ``npm run build`` the plugin will use the real key.
|
||||
#### 3. Clone repository to your local machine.
|
||||
```shell
|
||||
cd path/to/vault
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -17,6 +17,7 @@ main.js
|
|||
|
||||
# obsidian
|
||||
data.json
|
||||
backup
|
||||
|
||||
# Exclude macOS Finder (System Explorer) View States
|
||||
.DS_Store
|
||||
|
|
|
|||
112
README.md
112
README.md
|
|
@ -3,15 +3,16 @@
|
|||
Stop re-searching the same plugins or themes in every vault. With one central list, your essential tools and styles are always easy to find.
|
||||
|
||||
# Features
|
||||
- **Global Favorites for Plugins & Themes** - Mark your go to plugins and themes once and use them in all vaults
|
||||
- **Ease of Use** - Favorite/unfavorite directly from the Obsidian's plugin and theme details browser
|
||||
- **Global Favorites list for Plugins & Themes** - Mark your go-to plugins and themes once and access them across all vaults.
|
||||
- **Global In Use list for Plugins & Themes** - Automatically maintained list of plugins and themes that are currently enabled in at least one vault.
|
||||
- **Global Known list for Plugins & Themes** - Automatically maintained history of plugins and themes that have been installed at least once in any vault.
|
||||
- **Ease of Use** - Favorite/unfavorite directly inside the Obsidian's
|
||||
- Plugin browser
|
||||
- Community plugins tab
|
||||
- Theme browser
|
||||
- via [Commands](#commands)
|
||||
- **Vault Independence** - Favorites are stored globally on your device, not tied to a single vault
|
||||
|
||||
# Screenshots
|
||||
<img width="1104" height="1004" alt="image" src="https://github.com/user-attachments/assets/61b41e7b-4569-4509-95f3-d5e8a667d653" />
|
||||
|
||||
<img width="1104" height="1004" alt="image" src="https://github.com/user-attachments/assets/960eac0d-fea2-48e1-8faf-e54a7504149e" />
|
||||
|
||||
# How It Works
|
||||
1. Install and enable ***Favorites***.
|
||||
2. Open Obsidian's plugin or theme browser.
|
||||
|
|
@ -19,6 +20,103 @@ Stop re-searching the same plugins or themes in every vault. With one central li
|
|||
4. Use the Favorite button.
|
||||
5. Your favorites are saved globally and appear in every vault.
|
||||
|
||||
For plugins you can also favorite already installed plugins directly from the Community plugins tab.
|
||||
|
||||
# Screenshots
|
||||

|
||||
|
||||

|
||||
|
||||
<img width="1100" height="1000" alt="image" src="https://github.com/user-attachments/assets/5c8537dd-f5dc-4393-8cf7-6b506806631c" />
|
||||
|
||||
<img width="1100" height="1000" alt="image" src="https://github.com/user-attachments/assets/a6aebde5-a93c-4a93-ba0e-ccb9ad1c6560" />
|
||||
|
||||
<img width="1100" height="1000" alt="image" src="https://github.com/user-attachments/assets/e34ec7f4-57f2-4dc1-a150-45e9ab152295" />
|
||||
|
||||
<img width="1100" height="1000" alt="image" src="https://github.com/user-attachments/assets/ec9dfdf9-d607-4ff5-8679-fc286cb5e43c" />
|
||||
|
||||
<img width="1100" height="1000" alt="image" src="https://github.com/user-attachments/assets/a0b35f98-b194-433f-bd9e-66eecb5dd111" />
|
||||
|
||||
# Commands
|
||||
If you prefer managing your favorites list with commands here are the available commands
|
||||
- [Search and add plugin to favorite list](#search-and-add-plugin-to-favorite-list)
|
||||
- [Search and add theme to favorite list](#search-and-add-theme-to-favorite-list)
|
||||
- [Search and remove plugin from favorite list](#search-and-remove-plugin-from-favorite-list)
|
||||
- [Search and remove theme from favorite list](#search-and-remove-theme-from-favorite-list)
|
||||
- [Clear the plugin favorites list](#clear-the-plugin-favorites-list)
|
||||
- [Clear the plugin in use list](#clear-the-plugin-in-use-list)
|
||||
- [Clear the plugin known list](#clear-the-plugin-known-list)
|
||||
- [Clear the theme favorites list](#clear-the-theme-favorites-list)
|
||||
- [Clear the theme in use list](#clear-the-theme-in-use-list)
|
||||
- [Clear the theme known list](#clear-the-theme-known-list)
|
||||
- [Manually load the lists](#manually-load-the-lists)
|
||||
- [Manually save the lists](#manually-save-the-lists)
|
||||
- [Export lists to file](#export-lists-to-file)
|
||||
- [Import lists from file](#import-lists-from-file)
|
||||
|
||||
## Search and add plugin to favorite list
|
||||
Search and select a community plugin to add it to your favorites list. The list is fetched from the community plugin registry.
|
||||
|
||||
## Search and add theme to favorite list
|
||||
Search and select a community theme to add it to your favorites list. The list is fetched from the community theme registry.
|
||||
|
||||
## Search and remove plugin from favorite list
|
||||
Search and select from your current favorite plugins to remove it from your favorites list.
|
||||
|
||||
## Search and remove theme from favorite list
|
||||
Search and select from your current favorite themes to remove it from your favorites list.
|
||||
|
||||
## Clear the plugin favorites list
|
||||
Permanently removes ***all*** plugins from your favorites list after confirmation.
|
||||
> [!WARNING]
|
||||
> This action cannot be undone.
|
||||
|
||||
## Clear the plugin in use list
|
||||
Permanently removes ***all*** plugins from your in use list after confirmation.
|
||||
> [!WARNING]
|
||||
> This action cannot be undone.
|
||||
|
||||
## Clear the plugin known list
|
||||
Permanently removes ***all*** plugins from your known list after confirmation.
|
||||
> [!WARNING]
|
||||
> This action cannot be undone.
|
||||
|
||||
## Clear the theme favorites list
|
||||
Permanently removes ***all*** themes from your favorites list after confirmation.
|
||||
> [!WARNING]
|
||||
> This action cannot be undone.
|
||||
|
||||
## Clear the theme in use list
|
||||
Permanently removes ***all*** themes from your in use list after confirmation.
|
||||
> [!WARNING]
|
||||
> This action cannot be undone.
|
||||
|
||||
## Clear the theme known list
|
||||
Permanently removes ***all*** themes from your known list after confirmation.
|
||||
> [!WARNING]
|
||||
> This action cannot be undone.
|
||||
|
||||
## Manually load the lists
|
||||
Reloads the saved lists for plugins and themes. Use this to restore your lists if they were changed externally or need to be refreshed.
|
||||
> [!NOTE]
|
||||
> This is normally not necessary because the plugin handles this internally.
|
||||
|
||||
## Manually save the lists
|
||||
Forces the plugin to immediately save your current lists for plugins and themes. Use this if you want to ensure your lists are persistent.
|
||||
> [!WARNING]
|
||||
> This could overwrite changes from another running Obsidian instance if the changes from there are not loaded beforehand.
|
||||
|
||||
> [!NOTE]
|
||||
> This is normally not necessary because the plugin handles this internally.
|
||||
|
||||
## Export lists to file
|
||||
Creates a backup file containing your current lists for plugins and themes. The backup is saved as a timestamped JSON file inside the plugins backup folder within your vault configuration directory.
|
||||
|
||||
## Import lists from file
|
||||
Restores lists for plugins and themes from a previously created backup file. You will be prompted to select a backup file from the plugins backup folder. After confirmation imported lists will replaces your current lists with the content of the selected backup.
|
||||
> [!WARNING]
|
||||
> This will overwrite current lists and can't be undone.
|
||||
|
||||
# Contribution
|
||||
Feel free to contribute.
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,11 @@ const context = await esbuild.context({
|
|||
outfile: "main.js",
|
||||
define: {
|
||||
'process.env.FAVORITE_PLUGINS_KEY': JSON.stringify(prod ? 'favorite-plugins' : 'dev-favorite-plugins'),
|
||||
'process.env.FAVORITE_THEMES_KEY': JSON.stringify(prod ? 'favorite-themes' : 'dev-favorite-themes')
|
||||
'process.env.FAVORITE_THEMES_KEY': JSON.stringify(prod ? 'favorite-themes' : 'dev-favorite-themes'),
|
||||
'process.env.INUSE_PLUGINS_KEY': JSON.stringify(prod ? 'in-use-plugins' : 'dev-in-use-plugins'),
|
||||
'process.env.INUSE_THEMES_KEY': JSON.stringify(prod ? 'in-use-themes' : 'dev-in-use-themes'),
|
||||
'process.env.KNOWN_PLUGINS_KEY': JSON.stringify(prod ? 'known-plugins' : 'dev-known-plugins'),
|
||||
'process.env.KNOWN_THEMES_KEY': JSON.stringify(prod ? 'known-themes' : 'dev-known-themes'),
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@
|
|||
"authorUrl": "https://github.com/4Source",
|
||||
"isDesktopOnly": false,
|
||||
"fundingUrl": "https://www.buymeacoffee.com/4Source",
|
||||
"version": "1.1.1"
|
||||
"version": "1.4.0"
|
||||
}
|
||||
92
package-lock.json
generated
92
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "favorites",
|
||||
"version": "1.1.0",
|
||||
"version": "1.4.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "favorites",
|
||||
"version": "1.1.0",
|
||||
"version": "1.4.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@stylistic/eslint-plugin": "^3.1.0",
|
||||
|
|
@ -1059,10 +1059,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
|
|
@ -1105,10 +1106,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
|
|
@ -1175,10 +1177,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
||||
"version": "3.14.2",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
|
|
@ -2207,10 +2210,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
|
||||
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
|
|
@ -3226,10 +3230,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
|
|
@ -3443,10 +3448,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/filelist/node_modules/minimatch": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"version": "5.1.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
|
||||
"integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
|
|
@ -3497,10 +3503,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
|
||||
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
|
||||
"dev": true
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
|
||||
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.4",
|
||||
|
|
@ -3667,10 +3674,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/glob/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
|
|
@ -4118,10 +4126,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/jake/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
|
|
@ -4730,10 +4739,11 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
|
|
@ -5026,12 +5036,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
"brace-expansion": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
|
|
@ -5864,10 +5875,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/test-exclude/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -33,5 +33,5 @@
|
|||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
"version": "1.1.1"
|
||||
"version": "1.4.0"
|
||||
}
|
||||
21
src/commands/ClearPluginFavoritesList.ts
Normal file
21
src/commands/ClearPluginFavoritesList.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { DialogModal } from 'src/modals/DialogModal';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'clear-plugin-favorites-list',
|
||||
name: 'Clear the plugin favorites list',
|
||||
callback: () => {
|
||||
plugin.loadFavoritePlugins();
|
||||
const numberClear = plugin.favoritePlugins.length;
|
||||
new DialogModal(plugin.app, `Clear ${numberClear} plugin(s) permanently from favorite list?`, '', () => {
|
||||
plugin.favoritePlugins = [];
|
||||
plugin.saveFavoritePlugins();
|
||||
new Notice(`Cleared ${numberClear} plugins from favorite list`);
|
||||
}, () => {
|
||||
new Notice('Canceled clear plugins from favorite list');
|
||||
}, 'Clear', true, 'Cancel', false).open();
|
||||
},
|
||||
};
|
||||
}
|
||||
21
src/commands/ClearPluginInUseList.ts
Normal file
21
src/commands/ClearPluginInUseList.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { DialogModal } from 'src/modals/DialogModal';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'clear-plugin-in-use-list',
|
||||
name: 'Clear the plugin in use list',
|
||||
callback: () => {
|
||||
plugin.loadInUsePlugins();
|
||||
const numberClear = Object.keys(plugin.inUsePlugins).length;
|
||||
new DialogModal(plugin.app, `Clear ${numberClear} plugin(s) permanently from in use list?`, '', () => {
|
||||
plugin.inUsePlugins = {};
|
||||
plugin.saveInUsePlugins();
|
||||
new Notice(`Cleared ${numberClear} plugins from in use list`);
|
||||
}, () => {
|
||||
new Notice('Canceled clear plugins from in use list');
|
||||
}, 'Clear', true, 'Cancel', false).open();
|
||||
},
|
||||
};
|
||||
}
|
||||
21
src/commands/ClearPluginKnownList.ts
Normal file
21
src/commands/ClearPluginKnownList.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { DialogModal } from 'src/modals/DialogModal';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'clear-plugin-known-list',
|
||||
name: 'Clear the plugin known list',
|
||||
callback: () => {
|
||||
plugin.loadKnownPlugins();
|
||||
const numberClear = plugin.knownPlugins.length;
|
||||
new DialogModal(plugin.app, `Clear ${numberClear} plugin(s) permanently from known list?`, '', () => {
|
||||
plugin.knownPlugins = [];
|
||||
plugin.saveKnownPlugins();
|
||||
new Notice(`Cleared ${numberClear} plugins from known list`);
|
||||
}, () => {
|
||||
new Notice('Canceled clear plugins from known list');
|
||||
}, 'Clear', true, 'Cancel', false).open();
|
||||
},
|
||||
};
|
||||
}
|
||||
21
src/commands/ClearThemeFavoritesList.ts
Normal file
21
src/commands/ClearThemeFavoritesList.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { DialogModal } from 'src/modals/DialogModal';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'clear-theme-favorites-list',
|
||||
name: 'Clear the theme favorites list',
|
||||
callback: () => {
|
||||
plugin.loadFavoriteThemes();
|
||||
const numberClear = plugin.favoriteThemes.length;
|
||||
new DialogModal(plugin.app, `Clear ${numberClear} theme(s) permanently from favorite list?`, '', () => {
|
||||
plugin.favoriteThemes = [];
|
||||
plugin.saveFavoriteThemes();
|
||||
new Notice(`Cleared ${numberClear} themes from favorite list`);
|
||||
}, () => {
|
||||
new Notice('Canceled clear themes from favorite list');
|
||||
}, 'Clear', true, 'Cancel', false).open();
|
||||
},
|
||||
};
|
||||
}
|
||||
21
src/commands/ClearThemeInUseList.ts
Normal file
21
src/commands/ClearThemeInUseList.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { DialogModal } from 'src/modals/DialogModal';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'clear-theme-in-use-list',
|
||||
name: 'Clear the theme in use list',
|
||||
callback: () => {
|
||||
plugin.loadInUseThemes();
|
||||
const numberClear = Object.keys(plugin.inUseThemes).length;
|
||||
new DialogModal(plugin.app, `Clear ${numberClear} theme(s) permanently from in use list?`, '', () => {
|
||||
plugin.inUseThemes = {};
|
||||
plugin.saveInUseThemes();
|
||||
new Notice(`Cleared ${numberClear} themes from in use list`);
|
||||
}, () => {
|
||||
new Notice('Canceled clear themes from in use list');
|
||||
}, 'Clear', true, 'Cancel', false).open();
|
||||
},
|
||||
};
|
||||
}
|
||||
21
src/commands/ClearThemeKnownList.ts
Normal file
21
src/commands/ClearThemeKnownList.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { DialogModal } from 'src/modals/DialogModal';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'clear-theme-known-list',
|
||||
name: 'Clear the theme known list',
|
||||
callback: () => {
|
||||
plugin.loadKnownThemes();
|
||||
const numberClear = plugin.knownThemes.length;
|
||||
new DialogModal(plugin.app, `Clear ${numberClear} theme(s) permanently from known list?`, '', () => {
|
||||
plugin.knownThemes = [];
|
||||
plugin.saveKnownThemes();
|
||||
new Notice(`Cleared ${numberClear} themes from known list`);
|
||||
}, () => {
|
||||
new Notice('Canceled clear themes from known list');
|
||||
}, 'Clear', true, 'Cancel', false).open();
|
||||
},
|
||||
};
|
||||
}
|
||||
37
src/commands/ExportLists.ts
Normal file
37
src/commands/ExportLists.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { Command, normalizePath, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { PLUGIN_BACKUP_BASE_PATH } from 'src/constants';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'export-lists',
|
||||
name: 'Export lists to file',
|
||||
callback: async () => {
|
||||
if (plugin.favoritePlugins.length <= 0 && plugin.favoriteThemes.length <= 0 && Object.keys(plugin.inUsePlugins).length <= 0 && Object.keys(plugin.inUseThemes).length <= 0 && plugin.knownPlugins.length <= 0 && plugin.knownThemes.length <= 0) {
|
||||
new Notice('No lists to backup');
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure backup path does exist
|
||||
const backupPath = normalizePath(`${plugin.app.vault.configDir}${PLUGIN_BACKUP_BASE_PATH}`);
|
||||
await plugin.app.vault.adapter.mkdir(backupPath);
|
||||
|
||||
// Create the file name
|
||||
const pad = (n: number) => n.toString().padStart(2, '0');
|
||||
const date = new Date();
|
||||
const dateString = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}-${pad(date.getHours())}-${pad(date.getMinutes())}`;
|
||||
const backupFilePath = normalizePath(`${backupPath}/favorite-${dateString}.json`);
|
||||
|
||||
// Write backup file for lists
|
||||
await plugin.app.vault.adapter.write(backupFilePath, JSON.stringify({
|
||||
favoritePlugins: plugin.favoritePlugins,
|
||||
favoriteThemes: plugin.favoriteThemes,
|
||||
inUsePlugins: plugin.inUsePlugins,
|
||||
inUseThemes: plugin.inUseThemes,
|
||||
knownPlugins: plugin.knownPlugins,
|
||||
knownThemes: plugin.knownThemes,
|
||||
}));
|
||||
new Notice(`Lists backup successful written to: ${backupFilePath}`);
|
||||
},
|
||||
};
|
||||
}
|
||||
51
src/commands/ImportLists.ts
Normal file
51
src/commands/ImportLists.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { Command, normalizePath, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { PLUGIN_BACKUP_BASE_PATH } from 'src/constants';
|
||||
import { StringSuggestModal } from 'src/modals/StringSuggestModal';
|
||||
import { DialogModal } from 'src/modals/DialogModal';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'import-lists',
|
||||
name: 'Import lists from file',
|
||||
callback: async () => {
|
||||
const backupPath = normalizePath(`${plugin.app.vault.configDir}${PLUGIN_BACKUP_BASE_PATH}`);
|
||||
if (!(await plugin.app.vault.adapter.exists(backupPath))) {
|
||||
// Backup path does not exist
|
||||
new Notice(`Backup path does not exist: ${backupPath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const backupFiles = (await plugin.app.vault.adapter.list(backupPath)).files;
|
||||
if (backupFiles.length <= 0) {
|
||||
// Backup path is empty
|
||||
new Notice('Backup path is empty');
|
||||
return;
|
||||
}
|
||||
|
||||
new StringSuggestModal(plugin.app, 'Select backup file to load from', backupFiles, async (result) => {
|
||||
const content = await plugin.app.vault.adapter.read(result);
|
||||
const json = JSON.parse(content);
|
||||
const loadedFavoritePlugins = json.favoritePlugins || [];
|
||||
const loadedFavoriteThemes = json.favoriteThemes || [];
|
||||
const loadedInUsePlugins = json.inUsePlugins || [];
|
||||
const loadedInUseThemes = json.inUseThemes || [];
|
||||
const loadedKnownPlugins = json.knownPlugins || [];
|
||||
const loadedKnownThemes = json.knownThemes || [];
|
||||
new DialogModal(plugin.app, 'Are you sure you want to overwrite current lists?', `The following lists will be overwritten: favorite plugins will change from ${plugin.favoritePlugins.length} items to ${loadedFavoritePlugins.length} items, favorite themes will change from ${plugin.favoriteThemes.length} items to ${loadedFavoriteThemes.length} items, in use plugins will change from ${plugin.inUsePlugins.length} items to ${loadedInUsePlugins.length} items, in use themes will change from ${plugin.inUseThemes.length} items to ${loadedInUseThemes.length} items, known plugins will change from ${plugin.knownPlugins.length} items to ${loadedKnownPlugins.length} items, and known themes will change from ${plugin.knownThemes.length} items to ${loadedKnownThemes.length} items.`, () => {
|
||||
plugin.favoritePlugins = loadedFavoritePlugins;
|
||||
plugin.favoriteThemes = loadedFavoriteThemes;
|
||||
plugin.inUsePlugins = loadedInUsePlugins;
|
||||
plugin.inUseThemes = loadedInUseThemes;
|
||||
plugin.knownPlugins = loadedKnownPlugins;
|
||||
plugin.knownThemes = loadedKnownThemes;
|
||||
plugin.saveLists();
|
||||
|
||||
new Notice('Loaded backup successfully');
|
||||
}, () => {
|
||||
new Notice('Canceled loading backup by user');
|
||||
}, 'Overwrite', true, 'Cancel', false).open();
|
||||
}).open();
|
||||
},
|
||||
};
|
||||
}
|
||||
13
src/commands/LoadLists.ts
Normal file
13
src/commands/LoadLists.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'load-lists',
|
||||
name: 'Manually load the lists',
|
||||
callback: () => {
|
||||
plugin.loadLists();
|
||||
new Notice('Loaded lists');
|
||||
},
|
||||
};
|
||||
}
|
||||
13
src/commands/SaveLists.ts
Normal file
13
src/commands/SaveLists.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'save-lists',
|
||||
name: 'Manually save the lists',
|
||||
callback: () => {
|
||||
plugin.saveLists();
|
||||
new Notice('Saved lists');
|
||||
},
|
||||
};
|
||||
}
|
||||
33
src/commands/SearchAndAddPluginToFavoriteList.ts
Normal file
33
src/commands/SearchAndAddPluginToFavoriteList.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { CommunitySuggestModal } from 'src/modals/CommunitySuggestModal';
|
||||
import { CommunityPlugin, fetchCommunityPluginList } from 'src/util/GitHub';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'search-and-add-plugin-to-favorite-list',
|
||||
name: 'Search and add plugin to favorite list',
|
||||
callback: async () => {
|
||||
let items = await fetchCommunityPluginList();
|
||||
if (!items) {
|
||||
new Notice('Failed to fetch community plugins. See console for more information.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter out favorites
|
||||
plugin.loadFavoritePlugins();
|
||||
items = items.filter(value => !plugin.favoritePlugins.contains(value.id));
|
||||
|
||||
if (items.length <= 0) {
|
||||
new Notice('No plugin left which is could be added to favorite list');
|
||||
return;
|
||||
}
|
||||
|
||||
new CommunitySuggestModal<CommunityPlugin>(plugin.app, 'Select plugin which should be added to favorites list...', items, (result) => {
|
||||
plugin.favoritePlugins.push(result.id);
|
||||
plugin.saveFavoritePlugins();
|
||||
new Notice(`Added ${result.name} to favorite list`);
|
||||
}).open();
|
||||
},
|
||||
};
|
||||
}
|
||||
33
src/commands/SearchAndAddThemeToFavoriteList.ts
Normal file
33
src/commands/SearchAndAddThemeToFavoriteList.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { CommunitySuggestModal } from 'src/modals/CommunitySuggestModal';
|
||||
import { CommunityTheme, fetchCommunityThemeList } from 'src/util/GitHub';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'search-and-add-theme-to-favorite-list',
|
||||
name: 'Search and add theme to favorite list',
|
||||
callback: async () => {
|
||||
let items = await fetchCommunityThemeList();
|
||||
if (!items) {
|
||||
new Notice('Failed to fetch community themes. See console for more information.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter out favorites
|
||||
plugin.loadFavoriteThemes();
|
||||
items = items.filter(value => !plugin.favoriteThemes.contains(value.name));
|
||||
|
||||
if (items.length <= 0) {
|
||||
new Notice('No theme left which is could be added to favorite list');
|
||||
return;
|
||||
}
|
||||
|
||||
new CommunitySuggestModal<CommunityTheme>(plugin.app, 'Select theme which should be added to favorites list...', items, (result) => {
|
||||
plugin.favoriteThemes.push(result.name);
|
||||
plugin.saveFavoriteThemes();
|
||||
new Notice(`Added ${result.name} to favorite list`);
|
||||
}).open();
|
||||
},
|
||||
};
|
||||
}
|
||||
29
src/commands/SearchAndRemovePluginFromFavoriteList.ts
Normal file
29
src/commands/SearchAndRemovePluginFromFavoriteList.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { CommunityPlugin, fetchCommunityPluginList } from 'src/util/GitHub';
|
||||
import { CommunitySuggestModal } from 'src/modals/CommunitySuggestModal';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'search-and-remove-plugin-from-favorite-list',
|
||||
name: 'Search and remove plugin from favorite list',
|
||||
callback: async () => {
|
||||
plugin.loadFavoritePlugins();
|
||||
if (plugin.favoritePlugins.length <= 0) {
|
||||
new Notice('Plugin favorite list is empty');
|
||||
return;
|
||||
}
|
||||
const communityItems = await fetchCommunityPluginList();
|
||||
const installedItems = Object.values(plugin.app.plugins.manifests);
|
||||
const items = plugin.favoritePlugins.map((value) => {
|
||||
return communityItems?.find((communityValue) => value === communityValue.id) || installedItems.find(installedValue => value === installedValue.id) as unknown as CommunityPlugin || { id: value, name: value, author: 'unknown' } as CommunityPlugin;
|
||||
});
|
||||
|
||||
new CommunitySuggestModal<CommunityPlugin>(plugin.app, 'Select plugin which should be removed from the favorites list...', items, (result) => {
|
||||
plugin.favoritePlugins.remove(result.id);
|
||||
plugin.saveFavoritePlugins();
|
||||
new Notice(`Removed ${result.name} from favorite list`);
|
||||
}).open();
|
||||
},
|
||||
};
|
||||
}
|
||||
29
src/commands/SearchAndRemoveThemeFromFavoriteList.ts
Normal file
29
src/commands/SearchAndRemoveThemeFromFavoriteList.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { Command, Notice } from 'obsidian';
|
||||
import CurrentPlugin from '../main';
|
||||
import { CommunityTheme, fetchCommunityThemeList } from 'src/util/GitHub';
|
||||
import { CommunitySuggestModal } from 'src/modals/CommunitySuggestModal';
|
||||
|
||||
export default function (plugin: CurrentPlugin): Command {
|
||||
return {
|
||||
id: 'search-and-remove-theme-from-favorite-list',
|
||||
name: 'Search and remove theme from favorite list',
|
||||
callback: async () => {
|
||||
plugin.loadFavoriteThemes();
|
||||
if (plugin.favoriteThemes.length <= 0) {
|
||||
new Notice('Theme favorite list is empty');
|
||||
return;
|
||||
}
|
||||
const communityItems = await fetchCommunityThemeList();
|
||||
const installedItems = Object.values(plugin.app.customCss.themes);
|
||||
const items = plugin.favoriteThemes.map((value) => {
|
||||
return communityItems?.find((communityValue) => value === communityValue.name) || installedItems.find(installedValue => value === installedValue.name) as unknown as CommunityTheme || { name: value, author: 'unknown' } as CommunityTheme;
|
||||
});
|
||||
|
||||
new CommunitySuggestModal<CommunityTheme>(plugin.app, 'Select theme which should be removed from the favorites list...', items, (result) => {
|
||||
plugin.favoriteThemes.remove(result.name);
|
||||
plugin.saveFavoriteThemes();
|
||||
new Notice(`Removed ${result.name} from favorite list`);
|
||||
}).open();
|
||||
},
|
||||
};
|
||||
}
|
||||
34
src/commands/index.ts
Normal file
34
src/commands/index.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import CurrentPlugin from '../main';
|
||||
import ClearPluginFavoritesList from './ClearPluginFavoritesList';
|
||||
import ClearPluginInUseList from './ClearPluginInUseList';
|
||||
import ClearPluginKnownList from './ClearPluginKnownList';
|
||||
import ClearThemeFavoritesList from './ClearThemeFavoritesList';
|
||||
import ClearThemeInUseList from './ClearThemeInUseList';
|
||||
import ClearThemeKnownList from './ClearThemeKnownList';
|
||||
import ExportLists from './ExportLists';
|
||||
import ImportLists from './ImportLists';
|
||||
import LoadLists from './LoadLists';
|
||||
import SaveLists from './SaveLists';
|
||||
import SearchAndAddPluginToFavoriteList from './SearchAndAddPluginToFavoriteList';
|
||||
import SearchAndAddThemeToFavoriteList from './SearchAndAddThemeToFavoriteList';
|
||||
import SearchAndRemovePluginFromFavoriteList from './SearchAndRemovePluginFromFavoriteList';
|
||||
import SearchAndRemoveThemeFromFavoriteList from './SearchAndRemoveThemeFromFavoriteList';
|
||||
|
||||
export async function addAllCommands(plugin: CurrentPlugin) {
|
||||
// TODO: Dynamically import all files in the commands folder during bundling time
|
||||
|
||||
plugin.addCommand(ClearPluginFavoritesList(plugin));
|
||||
plugin.addCommand(ClearPluginInUseList(plugin));
|
||||
plugin.addCommand(ClearPluginKnownList(plugin));
|
||||
plugin.addCommand(ClearThemeFavoritesList(plugin));
|
||||
plugin.addCommand(ClearThemeInUseList(plugin));
|
||||
plugin.addCommand(ClearThemeKnownList(plugin));
|
||||
plugin.addCommand(ExportLists(plugin));
|
||||
plugin.addCommand(ImportLists(plugin));
|
||||
plugin.addCommand(LoadLists(plugin));
|
||||
plugin.addCommand(SaveLists(plugin));
|
||||
plugin.addCommand(SearchAndAddPluginToFavoriteList(plugin));
|
||||
plugin.addCommand(SearchAndAddThemeToFavoriteList(plugin));
|
||||
plugin.addCommand(SearchAndRemovePluginFromFavoriteList(plugin));
|
||||
plugin.addCommand(SearchAndRemoveThemeFromFavoriteList(plugin));
|
||||
}
|
||||
|
|
@ -1,6 +1,2 @@
|
|||
export const PLUGIN_ID = 'favorite';
|
||||
export const MONKEY_KEY_MODAL_OPEN = `${PLUGIN_ID}-Modal-open`;
|
||||
export const MONKEY_KEY_PLUGIN_BROWSER_MODAL_UPDATE_ITEMS = `${PLUGIN_ID}-CommunityPluginModal-updateItems`;
|
||||
export const MONKEY_KEY_PLUGIN_BROWSER_MODAL_SHOW_ITEMS = `${PLUGIN_ID}-CommunityPluginModal-showItems`;
|
||||
export const MONKEY_KEY_THEME_BROWSER_MODAL_UPDATE_ITEMS = `${PLUGIN_ID}-ThemePluginModal-updateItems`;
|
||||
export const MONKEY_KEY_THEME_BROWSER_MODAL_SHOW_ITEMS = `${PLUGIN_ID}-ThemePluginModal-showItems`;
|
||||
export const PLUGIN_ID = 'favorites';
|
||||
export const PLUGIN_BACKUP_BASE_PATH = `/plugins/${PLUGIN_ID}/backup`;
|
||||
|
|
|
|||
663
src/main.ts
663
src/main.ts
|
|
@ -1,312 +1,429 @@
|
|||
import { CommunityItem, CommunityModal, Modal, Plugin } from 'obsidian';
|
||||
import { dedupe, around } from 'monkey-around';
|
||||
import { MONKEY_KEY_PLUGIN_BROWSER_MODAL_UPDATE_ITEMS, MONKEY_KEY_MODAL_OPEN, MONKEY_KEY_THEME_BROWSER_MODAL_UPDATE_ITEMS, MONKEY_KEY_THEME_BROWSER_MODAL_SHOW_ITEMS, MONKEY_KEY_PLUGIN_BROWSER_MODAL_SHOW_ITEMS } from './constants';
|
||||
import { Plugin } from 'obsidian';
|
||||
import { addAllCommands } from './commands';
|
||||
import patchSettingsModal from './patches/patch.SettingsModal';
|
||||
import patchModal from './patches/patch.Modal';
|
||||
import patchPluginManager from './patches/patch.PluginManager';
|
||||
import patchStyleManager from './patches/patch.StyleManager';
|
||||
|
||||
export default class FavoritesPlugin extends Plugin {
|
||||
pluginsKey: string;
|
||||
themesKey: string;
|
||||
favoritePlugins?: string[];
|
||||
favoriteThemes?: string[];
|
||||
communityPluginModalPrototype?: CommunityModal;
|
||||
communityThemesModalPrototype?: CommunityModal;
|
||||
uninstallModalOpen?: () => void;
|
||||
uninstallPluginBrowserModalUpdateItems?: () => void;
|
||||
uninstallPluginBrowserModalShowItem?: () => void;
|
||||
uninstallThemeBrowserModalUpdateItems?: () => void;
|
||||
uninstallThemeBrowserModalShowItem?: () => void;
|
||||
pluginFavoritesKey: string;
|
||||
favoritePlugins: string[];
|
||||
themeFavoritesKey: string;
|
||||
favoriteThemes: string[];
|
||||
pluginInUseKey: string;
|
||||
inUsePlugins: Record<string, string[]>;
|
||||
themeInUseKey: string;
|
||||
inUseThemes: Record<string, string[]>;
|
||||
pluginKnownKey: string;
|
||||
knownPlugins: string[];
|
||||
themeKnownKey: string;
|
||||
knownThemes: string[];
|
||||
uninstallCommunityPluginModalPatch?: () => void;
|
||||
uninstallCommunityPluginsSettingTabPatch?: () => void;
|
||||
uninstallCommunityThemeModalPatch?: () => void;
|
||||
uninstallModalPatch?: () => void;
|
||||
uninstallPluginManagerPatch?: () => void;
|
||||
uninstallSettingsModalPatch?: () => void;
|
||||
uninstallStyleManagerPatch?: () => void;
|
||||
|
||||
async onload() {
|
||||
this.pluginsKey = process.env.FAVORITE_PLUGINS_KEY || '';
|
||||
this.themesKey = process.env.FAVORITE_THEMES_KEY || '';
|
||||
console.debug(`Plugins key: ${this.pluginsKey} Themes key: ${this.themesKey}`);
|
||||
this.loadStorageKeys();
|
||||
this.loadLists();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias -- Is required because the this context wil change inside the 'monkey-around' functions but the plugin is required to be accessible
|
||||
const plugin = this;
|
||||
|
||||
if (!this.uninstallModalOpen) {
|
||||
console.debug('Patch Modal.open');
|
||||
this.uninstallModalOpen = around(Modal.prototype, {
|
||||
open(oldMethod) {
|
||||
return dedupe(MONKEY_KEY_MODAL_OPEN, oldMethod, function (...args) {
|
||||
console.debug('Call Modal.open');
|
||||
const result = oldMethod && oldMethod.apply(this, args);
|
||||
|
||||
// Check the opened Modal is the Community plugin browse modal
|
||||
if (this.containerEl?.querySelector('.mod-community-plugin')) {
|
||||
// Patch updateItems method
|
||||
if (!plugin.uninstallPluginBrowserModalUpdateItems) {
|
||||
console.debug('Patch PluginBrowserModal.updateItems');
|
||||
plugin.uninstallPluginBrowserModalUpdateItems = around(this.constructor.prototype, {
|
||||
updateItems(oldMethod) {
|
||||
return dedupe(MONKEY_KEY_PLUGIN_BROWSER_MODAL_UPDATE_ITEMS, oldMethod, function () {
|
||||
console.debug('Call PluginBrowserModal.updateItems');
|
||||
|
||||
// Load the favorite plugins
|
||||
plugin.loadFavoritePlugins;
|
||||
|
||||
const result = oldMethod && oldMethod.apply(this);
|
||||
|
||||
// Add to the favorite plugins a tag to visualize it for the user
|
||||
if (plugin.favoritePlugins) {
|
||||
plugin.favoritePlugins.forEach(id => {
|
||||
if (this.items && this.items[id]?.nameEl) {
|
||||
this.items[id].nameEl.createSpan({
|
||||
cls: 'flair',
|
||||
text: 'favorite',
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.warn('PluginBrowserModal.updateItems already patched!');
|
||||
}
|
||||
|
||||
// Patch showItem method
|
||||
if (!plugin.uninstallPluginBrowserModalShowItem) {
|
||||
console.debug('Patch PluginBrowserModal.showItem');
|
||||
plugin.uninstallPluginBrowserModalShowItem = around(this.constructor.prototype, {
|
||||
showItem(oldMethod) {
|
||||
return dedupe(MONKEY_KEY_PLUGIN_BROWSER_MODAL_SHOW_ITEMS, oldMethod, function (...args: CommunityItem[]) {
|
||||
console.debug('Call PluginBrowserModal.showItem');
|
||||
|
||||
return oldMethod && oldMethod.apply(this, args)
|
||||
.then(async (r: void) => {
|
||||
const infoEl = await this.detailsEl.getElementsByClassName('community-modal-info')[0];
|
||||
const infoNameEl = await infoEl?.getElementsByClassName('community-modal-info-name')[0];
|
||||
const buttonContainerEl = await infoEl?.getElementsByClassName('community-modal-button-container')[0];
|
||||
|
||||
// Load the favorite plugins
|
||||
plugin.loadFavoritePlugins();
|
||||
const isFavorite = plugin.favoritePlugins?.contains(this.selectedItemId);
|
||||
|
||||
// Add to the favorite plugins a tag to visualize it for the user
|
||||
if (isFavorite) {
|
||||
if (infoNameEl) {
|
||||
infoNameEl.createSpan({
|
||||
cls: 'flair',
|
||||
text: 'favorite',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
plugin.registerEvent(buttonContainerEl?.createEl('button', { text: isFavorite ? 'Unfavorite' : 'Favorite' }).addEventListener('click', () => {
|
||||
if (isFavorite) {
|
||||
plugin.favoritePlugins?.remove(this.selectedItemId);
|
||||
}
|
||||
else {
|
||||
plugin.favoritePlugins?.push(this.selectedItemId);
|
||||
}
|
||||
|
||||
plugin.saveFavorites();
|
||||
|
||||
// Redraw
|
||||
infoEl.detach();
|
||||
this.showItem(this.items[this.selectedItemId]);
|
||||
this.update();
|
||||
}));
|
||||
|
||||
return r;
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.warn('PluginBrowserModal.showItem already patched!');
|
||||
}
|
||||
}
|
||||
|
||||
// Check the opened Modal is the Community themes browse modal
|
||||
if (this.containerEl?.querySelector('.mod-community-theme')) {
|
||||
// Patch updateItems method
|
||||
if (!plugin.uninstallThemeBrowserModalUpdateItems) {
|
||||
console.debug('Patch ThemeBrowserModal.updateItems');
|
||||
plugin.uninstallThemeBrowserModalUpdateItems = around(this.constructor.prototype, {
|
||||
updateItems(oldMethod) {
|
||||
return dedupe(MONKEY_KEY_THEME_BROWSER_MODAL_UPDATE_ITEMS, oldMethod, function () {
|
||||
console.debug('Call ThemeBrowserModal.updateItems');
|
||||
|
||||
// Load the favorite themes
|
||||
plugin.loadFavoriteThemes();
|
||||
|
||||
const result = oldMethod && oldMethod.apply(this);
|
||||
|
||||
// Ignore the default theme
|
||||
if (this.selectedItemId === '') {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Add to the favorite themes a tag to visualize it for the user
|
||||
if (plugin.favoriteThemes) {
|
||||
plugin.favoriteThemes.forEach(id => {
|
||||
if (this.items && this.items[id]?.nameEl) {
|
||||
this.items[id].nameEl.createSpan({
|
||||
cls: 'flair',
|
||||
text: 'favorite',
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.warn('ThemeBrowserModal.updateItems already patched!');
|
||||
}
|
||||
|
||||
// Patch showItems method
|
||||
if (!plugin.uninstallThemeBrowserModalShowItem) {
|
||||
console.debug('Patch ThemeBrowserModal.showItem');
|
||||
plugin.uninstallThemeBrowserModalShowItem = around(this.constructor.prototype, {
|
||||
showItem(oldMethod) {
|
||||
return dedupe(MONKEY_KEY_THEME_BROWSER_MODAL_SHOW_ITEMS, oldMethod, function (...args: CommunityItem[]) {
|
||||
console.debug('Call ThemeBrowserModal.showItem');
|
||||
|
||||
return oldMethod && oldMethod.apply(this, args)
|
||||
.then(async (r: void) => {
|
||||
// Ignore the default theme
|
||||
if (this.selectedItemId === '') {
|
||||
return r;
|
||||
}
|
||||
|
||||
const infoEl = await this.detailsEl.getElementsByClassName('community-modal-info')[0];
|
||||
const infoNameEl = await infoEl?.getElementsByClassName('community-modal-info-name')[0];
|
||||
const buttonContainerEl = await infoEl?.getElementsByClassName('community-modal-button-container')[0];
|
||||
|
||||
// Load the favorite themes
|
||||
plugin.loadFavoriteThemes();
|
||||
const isFavorite = plugin.favoriteThemes?.contains(this.selectedItemId);
|
||||
|
||||
// Add to the favorite themes a tag to visualize it for the user
|
||||
if (isFavorite) {
|
||||
if (infoNameEl) {
|
||||
infoNameEl.createSpan({
|
||||
cls: 'flair',
|
||||
text: 'favorite',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
plugin.registerEvent(buttonContainerEl?.createEl('button', { text: isFavorite ? 'Unfavorite' : 'Favorite' }).addEventListener('click', () => {
|
||||
if (isFavorite) {
|
||||
plugin.favoriteThemes?.remove(this.selectedItemId);
|
||||
}
|
||||
else {
|
||||
plugin.favoriteThemes?.push(this.selectedItemId);
|
||||
}
|
||||
|
||||
plugin.saveFavorites();
|
||||
|
||||
// Redraw
|
||||
infoEl.detach();
|
||||
this.showItem(this.items[this.selectedItemId]);
|
||||
this.update();
|
||||
}));
|
||||
|
||||
return r;
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.warn('ThemeBrowserModal.showItem already patched!');
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin.uninstallModalOpen && plugin.uninstallPluginBrowserModalUpdateItems && plugin.uninstallPluginBrowserModalShowItem && plugin.uninstallThemeBrowserModalUpdateItems && plugin.uninstallThemeBrowserModalShowItem) {
|
||||
console.debug('Uninstall Modal.open');
|
||||
plugin.uninstallModalOpen();
|
||||
plugin.uninstallModalOpen = undefined;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.warn('Modal.open already patched!');
|
||||
// Patch SettingsModal
|
||||
if (!this.uninstallSettingsModalPatch) {
|
||||
// console.debug('Patch SettingsModal');
|
||||
this.uninstallSettingsModalPatch = patchSettingsModal(this);
|
||||
}
|
||||
|
||||
// TODO: Redraw modals if local storage 'favorite-plugins' or 'favorite-themes' changed
|
||||
// Patch Modal
|
||||
if (!this.uninstallModalPatch) {
|
||||
// console.debug('Patch Modal');
|
||||
this.uninstallModalPatch = patchModal(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Add command to save and reload the favorites list
|
||||
* TODO: Add command to remove all favorites from list
|
||||
* TODO: Add command to search for plugin to add to favorites list
|
||||
*/
|
||||
// Patch PluginManager
|
||||
if (!this.uninstallPluginManagerPatch) {
|
||||
// console.debug('Patch PluginManager');
|
||||
this.uninstallPluginManagerPatch = patchPluginManager(this);
|
||||
}
|
||||
|
||||
// Patch StyleManager
|
||||
if (!this.uninstallStyleManagerPatch) {
|
||||
// console.debug('Patch StyleManager');
|
||||
this.uninstallStyleManagerPatch = patchStyleManager(this);
|
||||
}
|
||||
|
||||
// Check the state of the vault and update lists
|
||||
this.updateListsForVault();
|
||||
|
||||
// Add all commands registered
|
||||
addAllCommands(this);
|
||||
}
|
||||
|
||||
onunload() {
|
||||
async onunload() {
|
||||
try {
|
||||
// Restore the original functions
|
||||
if (this.uninstallModalOpen) {
|
||||
console.debug('Uninstall Modal.open');
|
||||
this.uninstallModalOpen();
|
||||
this.uninstallModalOpen = undefined;
|
||||
if (this.uninstallCommunityPluginModalPatch) {
|
||||
// console.debug('Uninstall CommunityPluginModal patch');
|
||||
this.uninstallCommunityPluginModalPatch();
|
||||
this.uninstallCommunityPluginModalPatch = undefined;
|
||||
}
|
||||
if (this.uninstallPluginBrowserModalUpdateItems) {
|
||||
console.debug('Uninstall PluginBrowserModal.updateItem');
|
||||
this.uninstallPluginBrowserModalUpdateItems();
|
||||
this.uninstallPluginBrowserModalUpdateItems = undefined;
|
||||
|
||||
if (this.uninstallCommunityPluginsSettingTabPatch) {
|
||||
// console.debug('Uninstall CommunityPluginsSettingTab patch');
|
||||
this.uninstallCommunityPluginsSettingTabPatch();
|
||||
this.uninstallCommunityPluginsSettingTabPatch = undefined;
|
||||
}
|
||||
if (this.uninstallPluginBrowserModalShowItem) {
|
||||
console.debug('Uninstall PluginBrowserModal.showItem');
|
||||
this.uninstallPluginBrowserModalShowItem();
|
||||
this.uninstallPluginBrowserModalShowItem = undefined;
|
||||
|
||||
if (this.uninstallCommunityThemeModalPatch) {
|
||||
// console.debug('Uninstall CommunityThemeModal patch');
|
||||
this.uninstallCommunityThemeModalPatch();
|
||||
this.uninstallCommunityThemeModalPatch = undefined;
|
||||
}
|
||||
if (this.uninstallThemeBrowserModalUpdateItems) {
|
||||
console.debug('Uninstall ThemeBrowserModal.updateItem');
|
||||
this.uninstallThemeBrowserModalUpdateItems();
|
||||
this.uninstallThemeBrowserModalUpdateItems = undefined;
|
||||
|
||||
if (this.uninstallModalPatch) {
|
||||
// console.debug('Uninstall Modal patch');
|
||||
this.uninstallModalPatch();
|
||||
this.uninstallModalPatch = undefined;
|
||||
}
|
||||
if (this.uninstallThemeBrowserModalShowItem) {
|
||||
console.debug('Uninstall ThemeBrowserModal.showItem');
|
||||
this.uninstallThemeBrowserModalShowItem();
|
||||
this.uninstallThemeBrowserModalShowItem = undefined;
|
||||
|
||||
if (this.uninstallPluginManagerPatch) {
|
||||
// console.debug('Uninstall PluginManager patch');
|
||||
this.uninstallPluginManagerPatch();
|
||||
this.uninstallPluginManagerPatch = undefined;
|
||||
}
|
||||
|
||||
if (this.uninstallSettingsModalPatch) {
|
||||
// console.debug('Uninstall SettingsModal patch');
|
||||
this.uninstallSettingsModalPatch();
|
||||
this.uninstallSettingsModalPatch = undefined;
|
||||
}
|
||||
|
||||
if (this.uninstallStyleManagerPatch) {
|
||||
// console.debug('Uninstall StyleManager patch');
|
||||
this.uninstallStyleManagerPatch();
|
||||
this.uninstallStyleManagerPatch = undefined;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
console.error('Failed uninstalling patch functions!');
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
loadStorageKeys() {
|
||||
// favorite keys
|
||||
if (process.env.FAVORITE_PLUGINS_KEY) {
|
||||
this.pluginFavoritesKey = process.env.FAVORITE_PLUGINS_KEY;
|
||||
}
|
||||
else {
|
||||
throw Error('Missing environment variable \'FAVORITE_PLUGINS_KEY\'');
|
||||
}
|
||||
if (process.env.FAVORITE_THEMES_KEY) {
|
||||
this.themeFavoritesKey = process.env.FAVORITE_THEMES_KEY;
|
||||
}
|
||||
else {
|
||||
throw Error('Missing environment variable \'FAVORITE_THEMES_KEY\'');
|
||||
}
|
||||
|
||||
// console.debug(`Plugins favorite key: ${this.pluginFavoritesKey} Themes favorite key: ${this.themeFavoritesKey}`);
|
||||
|
||||
// In use keys
|
||||
if (process.env.INUSE_PLUGINS_KEY) {
|
||||
this.pluginInUseKey = process.env.INUSE_PLUGINS_KEY;
|
||||
}
|
||||
else {
|
||||
throw Error('Missing environment variable \'INUSE_PLUGINS_KEY\'');
|
||||
}
|
||||
if (process.env.INUSE_THEMES_KEY) {
|
||||
this.themeInUseKey = process.env.INUSE_THEMES_KEY;
|
||||
}
|
||||
else {
|
||||
throw Error('Missing environment variable \'INUSE_THEMES_KEY\'');
|
||||
}
|
||||
|
||||
// console.debug(`Plugins in use key: ${this.pluginInUseKey} Themes in use key: ${this.themeInUseKey}`);
|
||||
|
||||
// Known keys
|
||||
if (process.env.KNOWN_PLUGINS_KEY) {
|
||||
this.pluginKnownKey = process.env.KNOWN_PLUGINS_KEY;
|
||||
}
|
||||
else {
|
||||
throw Error('Missing environment variable \'KNOWN_PLUGINS_KEY\'');
|
||||
}
|
||||
if (process.env.KNOWN_THEMES_KEY) {
|
||||
this.themeKnownKey = process.env.KNOWN_THEMES_KEY;
|
||||
}
|
||||
else {
|
||||
throw Error('Missing environment variable \'KNOWN_THEMES_KEY\'');
|
||||
}
|
||||
|
||||
// console.debug(`Plugins known key: ${this.pluginKnownKey} Themes known key: ${this.themeKnownKey}`);
|
||||
|
||||
// Register for storage key changes
|
||||
this.registerDomEvent(window, 'storage', (event) => {
|
||||
if (event.key === this.pluginFavoritesKey) {
|
||||
// console.debug('Plugins favorites key content changed', event);
|
||||
this.onFavoritePluginsChanged(event.newValue);
|
||||
}
|
||||
if (event.key === this.themeFavoritesKey) {
|
||||
// console.debug('Themes favorites key content changed', event);
|
||||
this.onFavoriteThemesChanged(event.newValue);
|
||||
}
|
||||
if (event.key === this.pluginInUseKey) {
|
||||
// console.debug('Plugins in use key content changed', event);
|
||||
this.onInUsePluginsChanged(event.newValue);
|
||||
}
|
||||
if (event.key === this.themeInUseKey) {
|
||||
// console.debug('Themes in use key content changed', event);
|
||||
this.onInUseThemesChanged(event.newValue);
|
||||
}
|
||||
if (event.key === this.pluginKnownKey) {
|
||||
// console.debug('Plugins known key content changed', event);
|
||||
this.onKnownPluginsChanged(event.newValue);
|
||||
}
|
||||
if (event.key === this.themeKnownKey) {
|
||||
// console.debug('Themes known key content changed', event);
|
||||
this.onKnownThemesChanged(event.newValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onFavoritePluginsChanged(newValue: string | null) {
|
||||
// console.debug(`onFavoritePluginsChanged: ${newValue}`);
|
||||
if (newValue) {
|
||||
this.favoritePlugins = JSON.parse(newValue);
|
||||
}
|
||||
else {
|
||||
this.favoritePlugins = [];
|
||||
}
|
||||
}
|
||||
|
||||
onFavoriteThemesChanged(newValue: string | null) {
|
||||
// console.debug(`onFavoriteThemesChanged: ${newValue}`);
|
||||
if (newValue) {
|
||||
this.favoriteThemes = JSON.parse(newValue);
|
||||
}
|
||||
else {
|
||||
this.favoriteThemes = [];
|
||||
}
|
||||
}
|
||||
|
||||
onInUsePluginsChanged(newValue: string | null) {
|
||||
// console.debug(`onInUsePluginsChanged: ${newValue}`);
|
||||
if (newValue) {
|
||||
this.inUsePlugins = JSON.parse(newValue);
|
||||
}
|
||||
else {
|
||||
this.inUsePlugins = {};
|
||||
}
|
||||
}
|
||||
|
||||
onInUseThemesChanged(newValue: string | null) {
|
||||
// console.debug(`onInUseThemesChanged: ${newValue}`);
|
||||
if (newValue) {
|
||||
this.inUseThemes = JSON.parse(newValue);
|
||||
}
|
||||
else {
|
||||
this.inUseThemes = {};
|
||||
}
|
||||
}
|
||||
|
||||
onKnownPluginsChanged(newValue: string | null) {
|
||||
// console.debug(`onKnownPluginsChanged: ${newValue}`);
|
||||
if (newValue) {
|
||||
this.knownPlugins = JSON.parse(newValue);
|
||||
}
|
||||
else {
|
||||
this.knownPlugins = [];
|
||||
}
|
||||
}
|
||||
|
||||
onKnownThemesChanged(newValue: string | null) {
|
||||
// console.debug(`onKnownThemesChanged: ${newValue}`);
|
||||
if (newValue) {
|
||||
this.knownThemes = JSON.parse(newValue);
|
||||
}
|
||||
else {
|
||||
this.knownThemes = [];
|
||||
}
|
||||
}
|
||||
|
||||
loadFavoritePlugins() {
|
||||
// Load the favorite plugins
|
||||
this.favoritePlugins = JSON.parse(localStorage.getItem(this.pluginsKey) || '[]');
|
||||
this.favoritePlugins = JSON.parse(localStorage.getItem(this.pluginFavoritesKey) || '[]');
|
||||
}
|
||||
|
||||
loadFavoriteThemes() {
|
||||
// Load the favorite plugins
|
||||
this.favoritePlugins = JSON.parse(localStorage.getItem(this.themesKey) || '[]');
|
||||
this.favoriteThemes = JSON.parse(localStorage.getItem(this.themeFavoritesKey) || '[]');
|
||||
}
|
||||
|
||||
saveFavorites() {
|
||||
if (this.favoritePlugins) {
|
||||
if (this.favoritePlugins.length > 0) {
|
||||
localStorage.setItem(this.pluginsKey, JSON.stringify(this.favoritePlugins));
|
||||
}
|
||||
else {
|
||||
localStorage.removeItem(this.pluginsKey);
|
||||
loadInUsePlugins() {
|
||||
// Load the in use plugins
|
||||
this.inUsePlugins = JSON.parse(localStorage.getItem(this.pluginInUseKey) || '{}');
|
||||
}
|
||||
|
||||
loadInUseThemes() {
|
||||
// Load the in use plugins
|
||||
this.inUseThemes = JSON.parse(localStorage.getItem(this.themeInUseKey) || '{}');
|
||||
}
|
||||
|
||||
loadKnownPlugins() {
|
||||
// Load the known plugins
|
||||
this.knownPlugins = JSON.parse(localStorage.getItem(this.pluginKnownKey) || '[]');
|
||||
}
|
||||
|
||||
loadKnownThemes() {
|
||||
// Load the known plugins
|
||||
this.knownThemes = JSON.parse(localStorage.getItem(this.themeKnownKey) || '[]');
|
||||
}
|
||||
|
||||
loadLists() {
|
||||
this.loadFavoritePlugins();
|
||||
this.loadFavoriteThemes();
|
||||
this.loadInUsePlugins();
|
||||
this.loadInUseThemes();
|
||||
this.loadKnownPlugins();
|
||||
this.loadKnownThemes();
|
||||
}
|
||||
|
||||
saveFavoritePlugins() {
|
||||
if (this.favoritePlugins.length > 0) {
|
||||
localStorage.setItem(this.pluginFavoritesKey, JSON.stringify(this.favoritePlugins));
|
||||
}
|
||||
else {
|
||||
localStorage.removeItem(this.pluginFavoritesKey);
|
||||
}
|
||||
}
|
||||
|
||||
saveFavoriteThemes() {
|
||||
if (this.favoriteThemes.length > 0) {
|
||||
localStorage.setItem(this.themeFavoritesKey, JSON.stringify(this.favoriteThemes));
|
||||
}
|
||||
else {
|
||||
localStorage.removeItem(this.themeFavoritesKey);
|
||||
}
|
||||
}
|
||||
|
||||
saveInUsePlugins() {
|
||||
if (Object.keys(this.inUsePlugins).length > 0) {
|
||||
localStorage.setItem(this.pluginInUseKey, JSON.stringify(this.inUsePlugins));
|
||||
}
|
||||
else {
|
||||
localStorage.removeItem(this.pluginInUseKey);
|
||||
}
|
||||
}
|
||||
|
||||
saveInUseThemes() {
|
||||
if (Object.keys(this.inUseThemes).length > 0) {
|
||||
localStorage.setItem(this.themeInUseKey, JSON.stringify(this.inUseThemes));
|
||||
}
|
||||
else {
|
||||
localStorage.removeItem(this.themeInUseKey);
|
||||
}
|
||||
}
|
||||
|
||||
saveKnownPlugins() {
|
||||
if (this.knownPlugins.length > 0) {
|
||||
localStorage.setItem(this.pluginKnownKey, JSON.stringify(this.knownPlugins));
|
||||
}
|
||||
else {
|
||||
localStorage.removeItem(this.pluginKnownKey);
|
||||
}
|
||||
}
|
||||
|
||||
saveKnownThemes() {
|
||||
if (this.knownThemes.length > 0) {
|
||||
localStorage.setItem(this.themeKnownKey, JSON.stringify(this.knownThemes));
|
||||
}
|
||||
else {
|
||||
localStorage.removeItem(this.themeKnownKey);
|
||||
}
|
||||
}
|
||||
|
||||
saveLists() {
|
||||
this.saveFavoritePlugins();
|
||||
this.saveFavoriteThemes();
|
||||
this.saveInUsePlugins();
|
||||
this.saveInUseThemes();
|
||||
this.saveKnownPlugins();
|
||||
this.saveKnownThemes();
|
||||
}
|
||||
|
||||
updateListsForVault() {
|
||||
const currentVault = this.app.appId;
|
||||
|
||||
// Check the installed plugins and update known plugins list
|
||||
for (const id of Object.keys(this.app.plugins.manifests)) {
|
||||
// Add Plugin to known list if not already
|
||||
if (!this.knownPlugins.contains(id)) {
|
||||
this.knownPlugins.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.favoriteThemes) {
|
||||
if (this.favoriteThemes.length > 0) {
|
||||
localStorage.setItem(this.themesKey, JSON.stringify(this.favoriteThemes));
|
||||
// Check the enabled plugins and update in use plugins list
|
||||
for (const id of this.app.plugins.enabledPlugins) {
|
||||
// Add the plugin to the in use list with this vault as user
|
||||
if (!this.inUsePlugins[id] || !Array.isArray(this.inUsePlugins[id])) {
|
||||
this.inUsePlugins[id] = [];
|
||||
}
|
||||
else {
|
||||
localStorage.removeItem(this.themesKey);
|
||||
if (!this.inUsePlugins[id].contains(currentVault)) {
|
||||
this.inUsePlugins[id].push(currentVault);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the in use plugins list does not contain old entries of this vault
|
||||
for (const id of Object.keys(this.inUsePlugins)) {
|
||||
if (Array.isArray(this.inUsePlugins[id]) && this.inUsePlugins[id].contains(currentVault)) {
|
||||
if (!this.app.plugins.enabledPlugins.has(id)) {
|
||||
this.inUsePlugins[id].remove(currentVault);
|
||||
|
||||
// Cleanup in use if last vault stops using it
|
||||
if (this.inUsePlugins[id].length <= 0) {
|
||||
delete this.inUsePlugins[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the installed themes and update known themes list
|
||||
for (const name of Object.keys(this.app.customCss.themes)) {
|
||||
// Add theme to known list if not already
|
||||
if (!this.knownThemes.contains(name)) {
|
||||
this.knownThemes.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the enabled theme and update in use themes list
|
||||
const name = this.app.customCss.theme;
|
||||
|
||||
// Ignore the default theme
|
||||
if (name !== '') {
|
||||
// Add the theme to the in use list with this vault as user
|
||||
if (!this.inUseThemes[name] || !Array.isArray(this.inUseThemes[name])) {
|
||||
this.inUseThemes[name] = [];
|
||||
}
|
||||
if (!this.inUseThemes[name].contains(currentVault)) {
|
||||
this.inUseThemes[name].push(currentVault);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the in use themes list does not contain old entries of this vault
|
||||
for (const name of Object.keys(this.inUseThemes)) {
|
||||
if (Array.isArray(this.inUseThemes[name]) && this.inUseThemes[name].contains(currentVault)) {
|
||||
if (this.app.customCss.theme !== name) {
|
||||
this.inUseThemes[name].remove(currentVault);
|
||||
|
||||
// Cleanup in use if last vault stops using it
|
||||
if (this.inUseThemes[name].length <= 0) {
|
||||
delete this.inUseThemes[name];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.saveLists();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
35
src/modals/CommunitySuggestModal.ts
Normal file
35
src/modals/CommunitySuggestModal.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { App, FuzzyMatch, FuzzySuggestModal, renderResults } from 'obsidian';
|
||||
|
||||
export class CommunitySuggestModal<T extends { name: string, author: string }> extends FuzzySuggestModal<T> {
|
||||
private items: T[] = [];
|
||||
private onSubmit: (result: T) => void = () => { };
|
||||
|
||||
constructor(app: App, title: string, items: T[], onSubmit: (result: T) => void) {
|
||||
super(app);
|
||||
this.setPlaceholder(title);
|
||||
this.items = items;
|
||||
this.onSubmit = onSubmit;
|
||||
}
|
||||
|
||||
getItemText(item: T): string {
|
||||
return `${item.name} ${item.author}`;
|
||||
}
|
||||
|
||||
getItems(): T[] {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
onChooseItem(item: T): void {
|
||||
this.onSubmit(item);
|
||||
}
|
||||
|
||||
renderSuggestion(match: FuzzyMatch<T>, el: HTMLElement) {
|
||||
const titleEl = el.createDiv();
|
||||
renderResults(titleEl, match.item.name, match.match);
|
||||
|
||||
// Only render the matches in the author name.
|
||||
const authorEl = el.createEl('small');
|
||||
const offset = -(match.item.name.length + 1);
|
||||
renderResults(authorEl, match.item.author, match.match, offset);
|
||||
}
|
||||
}
|
||||
77
src/modals/DialogModal.ts
Normal file
77
src/modals/DialogModal.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import { App, Modal, Setting } from 'obsidian';
|
||||
|
||||
export class DialogModal extends Modal {
|
||||
message: string;
|
||||
submit: string;
|
||||
submitWarning: boolean;
|
||||
deny: string;
|
||||
denyWarning: boolean;
|
||||
onSubmit: () => void;
|
||||
onDeny: () => void;
|
||||
|
||||
constructor(app: App, title: string, message: string, onSubmit: () => void, onDeny: () => void, submit = 'Agree', submitWarning = false, deny = 'Cancel', denyWarning = true) {
|
||||
super(app);
|
||||
|
||||
this.titleEl.setText(title);
|
||||
|
||||
this.message = message;
|
||||
this.onSubmit = onSubmit;
|
||||
this.onDeny = onDeny;
|
||||
this.submit = submit;
|
||||
this.submitWarning = submitWarning;
|
||||
this.deny = deny;
|
||||
this.denyWarning = denyWarning;
|
||||
}
|
||||
|
||||
onOpen(): void {
|
||||
const { contentEl } = this;
|
||||
|
||||
if (this.message && this.message !== '') {
|
||||
contentEl.createEl('span', { text: this.message });
|
||||
}
|
||||
|
||||
const setting = new Setting(contentEl);
|
||||
if (this.submitWarning) {
|
||||
setting.addButton(button => button
|
||||
.setButtonText(this.submit)
|
||||
.setWarning()
|
||||
.onClick(() => {
|
||||
this.close();
|
||||
this.onSubmit();
|
||||
}));
|
||||
}
|
||||
else {
|
||||
setting.addButton(button => button
|
||||
.setButtonText(this.submit)
|
||||
.onClick(() => {
|
||||
this.close();
|
||||
this.onSubmit();
|
||||
}));
|
||||
}
|
||||
|
||||
if (this.denyWarning) {
|
||||
setting.addButton(button => button
|
||||
.setButtonText(this.deny)
|
||||
.setWarning()
|
||||
.onClick(() => {
|
||||
this.close();
|
||||
this.onDeny();
|
||||
}));
|
||||
}
|
||||
else {
|
||||
setting.addButton(button => button
|
||||
.setButtonText(this.deny)
|
||||
.onClick(() => {
|
||||
this.close();
|
||||
this.onDeny();
|
||||
}));
|
||||
}
|
||||
|
||||
setting.setClass('modal-buttons');
|
||||
}
|
||||
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
}
|
||||
23
src/modals/StringSuggestModal.ts
Normal file
23
src/modals/StringSuggestModal.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { App, FuzzySuggestModal } from 'obsidian';
|
||||
|
||||
export class StringSuggestModal extends FuzzySuggestModal<string> {
|
||||
private items: string[] = [];
|
||||
onSubmit: (result: string) => void = () => { };
|
||||
|
||||
constructor(app: App, title: string, items: string[], onSubmit: (result: string) => void) {
|
||||
super(app);
|
||||
this.setPlaceholder(title);
|
||||
this.items = items;
|
||||
this.onSubmit = onSubmit;
|
||||
}
|
||||
|
||||
getItems(): string[] {
|
||||
return this.items;
|
||||
}
|
||||
getItemText(item: string): string {
|
||||
return item;
|
||||
}
|
||||
onChooseItem(item: string): void {
|
||||
this.onSubmit(item);
|
||||
}
|
||||
}
|
||||
100
src/patches/patch.CommunityPluginModal.ts
Normal file
100
src/patches/patch.CommunityPluginModal.ts
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import { around, dedupe } from 'monkey-around';
|
||||
import MyPlugin from '../main';
|
||||
import { PLUGIN_ID } from 'src/constants';
|
||||
import { CommunityItem, CommunityPluginModal } from 'obsidian';
|
||||
import FavoriteFlair from 'src/ui-components/FavoriteFlair';
|
||||
import InUseFlair from 'src/ui-components/InUseFlair';
|
||||
import KnownFlair from 'src/ui-components/KnownFlair';
|
||||
import InstalledFlair from 'src/ui-components/InstalledFlair';
|
||||
|
||||
const MONKEY_KEY = `${PLUGIN_ID}-CommunityPluginModal-`;
|
||||
|
||||
export default (context: CommunityPluginModal, plugin: MyPlugin) => around(context.constructor.prototype, {
|
||||
showItem(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}showItem`, oldMethod, async function (item: CommunityItem) {
|
||||
// console.debug('Call CommunityPluginModal.showItem');
|
||||
|
||||
const result = oldMethod && await oldMethod.apply(this, [item]);
|
||||
|
||||
const infoEl = await this.detailsEl.getElementsByClassName('community-modal-info')[0];
|
||||
const infoNameEl = await infoEl?.getElementsByClassName('community-modal-info-name')[0];
|
||||
const buttonContainerEl = await infoEl?.getElementsByClassName('community-modal-button-container')[0];
|
||||
|
||||
// Load the plugin lists
|
||||
plugin.loadFavoritePlugins();
|
||||
plugin.loadInUsePlugins();
|
||||
plugin.loadKnownPlugins();
|
||||
|
||||
// Add aria label to installed flair
|
||||
new InstalledFlair(infoNameEl);
|
||||
|
||||
// Add to the favorite plugins a flair to visualize it for the user
|
||||
const isFavorite = plugin.favoritePlugins.contains(this.selectedItemId);
|
||||
if (isFavorite) {
|
||||
new FavoriteFlair(infoNameEl);
|
||||
}
|
||||
|
||||
// Add to the in use plugins a flair to visualize it for the user
|
||||
if (Object.keys(plugin.inUsePlugins).contains(this.selectedItemId)) {
|
||||
new InUseFlair(infoNameEl);
|
||||
}
|
||||
|
||||
// Add to the known plugins a flair to visualize it for the user
|
||||
if (plugin.knownPlugins.contains(this.selectedItemId)) {
|
||||
new KnownFlair(infoNameEl);
|
||||
}
|
||||
|
||||
plugin.registerDomEvent(buttonContainerEl?.createEl('button', { text: isFavorite ? 'Unfavorite' : 'Favorite' }), 'click', async () => {
|
||||
if (isFavorite) {
|
||||
plugin.favoritePlugins.remove(this.selectedItemId);
|
||||
}
|
||||
else {
|
||||
plugin.favoritePlugins.push(this.selectedItemId);
|
||||
}
|
||||
|
||||
plugin.saveFavoritePlugins();
|
||||
|
||||
// Redraw
|
||||
infoEl.detach();
|
||||
await this.showItem(this.items[this.selectedItemId]);
|
||||
this.update();
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
updateItems(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}updateItems`, oldMethod, function () {
|
||||
// console.debug('Call PluginBrowserModal.updateItems');
|
||||
|
||||
// Load the plugin lists
|
||||
plugin.loadFavoritePlugins();
|
||||
plugin.loadInUsePlugins();
|
||||
plugin.loadKnownPlugins();
|
||||
|
||||
const result = oldMethod && oldMethod.apply(this);
|
||||
|
||||
// Add aria label to installed flair
|
||||
Object.keys(plugin.app.plugins.manifests).forEach(id => {
|
||||
new InstalledFlair(this.items[id]?.nameEl);
|
||||
});
|
||||
|
||||
// Add to the favorite plugins a flair to visualize it for the user
|
||||
plugin.favoritePlugins.forEach(id => {
|
||||
new FavoriteFlair(this.items[id]?.nameEl);
|
||||
});
|
||||
|
||||
// Add to the in use plugins a flair to visualize it for the user
|
||||
Object.keys(plugin.inUsePlugins).forEach(id => {
|
||||
new InUseFlair(this.items[id]?.nameEl);
|
||||
});
|
||||
|
||||
// Add to the known plugins a flair to visualize it for the user
|
||||
plugin.knownPlugins.forEach(id => {
|
||||
new KnownFlair(this.items[id]?.nameEl);
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
});
|
||||
50
src/patches/patch.CommunityPluginsSettingTab.ts
Normal file
50
src/patches/patch.CommunityPluginsSettingTab.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { CommunityItem, CommunityPluginsSettingTab, setIcon, setTooltip } from 'obsidian';
|
||||
import MyPlugin from '../main';
|
||||
import { around, dedupe } from 'monkey-around';
|
||||
import { PLUGIN_ID } from 'src/constants';
|
||||
|
||||
const MONKEY_KEY = `${PLUGIN_ID}-CommunityPluginsSettingTab-`;
|
||||
|
||||
export default (context: CommunityPluginsSettingTab, plugin: MyPlugin) => around(context, {
|
||||
renderInstalledPlugin(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}renderInstalledPlugin`, oldMethod, function (item: CommunityItem, containerEl: HTMLElement, n: unknown, i: unknown, r: unknown) {
|
||||
// console.debug('Call CommunityPluginsSettingTab.renderInstalledPlugin');
|
||||
oldMethod && oldMethod.apply(this, [item, containerEl, n, i, r]);
|
||||
|
||||
// Load the favorite plugins
|
||||
plugin.loadFavoritePlugins();
|
||||
|
||||
const selectedPluginID = item.id;
|
||||
const isFavorite = plugin.favoritePlugins.contains(selectedPluginID);
|
||||
|
||||
const favEl = createDiv('clickable-icon extra-setting-button');
|
||||
|
||||
plugin.registerDomEvent(favEl, 'click', () => {
|
||||
if (isFavorite) {
|
||||
plugin.favoritePlugins.remove(selectedPluginID);
|
||||
}
|
||||
else {
|
||||
plugin.favoritePlugins.push(selectedPluginID);
|
||||
}
|
||||
|
||||
plugin.saveFavoritePlugins();
|
||||
|
||||
// Redraw
|
||||
this.render(false);
|
||||
});
|
||||
|
||||
if (isFavorite) {
|
||||
setIcon(favEl, 'star-off');
|
||||
setTooltip(favEl, 'Unfavorite');
|
||||
}
|
||||
else {
|
||||
setIcon(favEl, 'star');
|
||||
setTooltip(favEl, 'Favorite');
|
||||
}
|
||||
|
||||
// Add Favorite Icon to plugin control
|
||||
const controlEl: HTMLElement = this.installedPlugins.listEl.lastChild?.getElementsByClassName('setting-item-control')[0];
|
||||
controlEl.insertBefore(favEl, controlEl.children[0]);
|
||||
});
|
||||
},
|
||||
});
|
||||
114
src/patches/patch.CommunityThemeModal.ts
Normal file
114
src/patches/patch.CommunityThemeModal.ts
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
import { CommunityItem, CommunityThemeModal } from 'obsidian';
|
||||
import MyPlugin from '../main';
|
||||
import { around, dedupe } from 'monkey-around';
|
||||
import { PLUGIN_ID } from 'src/constants';
|
||||
import InstalledFlair from 'src/ui-components/InstalledFlair';
|
||||
import FavoriteFlair from 'src/ui-components/FavoriteFlair';
|
||||
import InUseFlair from 'src/ui-components/InUseFlair';
|
||||
import KnownFlair from 'src/ui-components/KnownFlair';
|
||||
import ActiveFlair from 'src/ui-components/ActiveFlair';
|
||||
|
||||
const MONKEY_KEY = `${PLUGIN_ID}-ThemePluginModal-`;
|
||||
|
||||
export default (context: CommunityThemeModal, plugin: MyPlugin) => around(context.constructor.prototype, {
|
||||
showItem(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}showItem`, oldMethod, async function (item: CommunityItem) {
|
||||
// console.debug('Call CommunityThemeModal.showItem');
|
||||
|
||||
const result = oldMethod && await oldMethod.apply(this, [item]);
|
||||
|
||||
const infoEl = await this.detailsEl.getElementsByClassName('community-modal-info')[0];
|
||||
const infoNameEl = await infoEl?.getElementsByClassName('community-modal-info-name')[0];
|
||||
|
||||
// Add aria label to installed flair
|
||||
new InstalledFlair(infoNameEl);
|
||||
|
||||
// Ignore the default theme
|
||||
if (this.selectedItemId === '') {
|
||||
return result;
|
||||
}
|
||||
const buttonContainerEl = await infoEl?.getElementsByClassName('community-modal-button-container')[0];
|
||||
|
||||
// Load the theme lists
|
||||
plugin.loadFavoriteThemes();
|
||||
plugin.loadInUseThemes();
|
||||
plugin.loadKnownThemes();
|
||||
|
||||
// Add to the favorite themes a flair to visualize it for the user
|
||||
const isFavorite = plugin.favoriteThemes.contains(this.selectedItemId);
|
||||
if (isFavorite) {
|
||||
new FavoriteFlair(infoNameEl);
|
||||
}
|
||||
|
||||
// Add to the in use themes a flair to visualize it for the user
|
||||
if (Object.keys(plugin.inUseThemes).contains(this.selectedItemId)) {
|
||||
new InUseFlair(infoNameEl);
|
||||
}
|
||||
|
||||
// Add to the known themes a flair to visualize it for the user
|
||||
if (plugin.knownThemes.contains(this.selectedItemId)) {
|
||||
new KnownFlair(infoNameEl);
|
||||
}
|
||||
|
||||
plugin.registerDomEvent(buttonContainerEl?.createEl('button', { text: isFavorite ? 'Unfavorite' : 'Favorite' }), 'click', async () => {
|
||||
if (isFavorite) {
|
||||
plugin.favoriteThemes.remove(this.selectedItemId);
|
||||
}
|
||||
else {
|
||||
plugin.favoriteThemes.push(this.selectedItemId);
|
||||
}
|
||||
|
||||
plugin.saveFavoriteThemes();
|
||||
|
||||
// Redraw
|
||||
infoEl.detach();
|
||||
await this.showItem(this.items[this.selectedItemId]);
|
||||
this.update();
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
updateItems(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}updateItems`, oldMethod, function () {
|
||||
// console.debug('Call CommunityThemeModal.updateItems');
|
||||
|
||||
// Load the theme lists
|
||||
plugin.loadFavoriteThemes();
|
||||
plugin.loadInUseThemes();
|
||||
plugin.loadKnownThemes();
|
||||
|
||||
const result = oldMethod && oldMethod.apply(this);
|
||||
|
||||
// Add aria label to installed flair
|
||||
Object.keys(plugin.app.customCss.themes).forEach(id => {
|
||||
new InstalledFlair(this.items[id]?.nameEl);
|
||||
});
|
||||
|
||||
// Add aria label to active flair
|
||||
new ActiveFlair(this.items[plugin.app.customCss.theme]?.nameEl);
|
||||
|
||||
// Ignore the default theme
|
||||
if (this.selectedItemId === '') {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Add to the favorite themes a flair to visualize it for the user
|
||||
plugin.favoriteThemes.forEach(id => {
|
||||
new FavoriteFlair(this.items[id]?.nameEl);
|
||||
});
|
||||
|
||||
// Add to the in use themes a flair to visualize it for the user
|
||||
Object.keys(plugin.inUseThemes).forEach(id => {
|
||||
new InUseFlair(this.items[id]?.nameEl);
|
||||
});
|
||||
|
||||
// Add to the known themes a flair to visualize it for the user
|
||||
plugin.knownThemes.forEach(id => {
|
||||
new KnownFlair(this.items[id]?.nameEl);
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
});
|
||||
43
src/patches/patch.Modal.ts
Normal file
43
src/patches/patch.Modal.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { Modal } from 'obsidian';
|
||||
import MyPlugin from '../main';
|
||||
import { around, dedupe } from 'monkey-around';
|
||||
import { PLUGIN_ID } from 'src/constants';
|
||||
import patchCommunityPluginModal from './patch.CommunityPluginModal';
|
||||
import patchCommunityThemeModal from './patch.CommunityThemeModal';
|
||||
|
||||
const MONKEY_KEY = `${PLUGIN_ID}-Modal-`;
|
||||
|
||||
export default (plugin: MyPlugin) => around(Modal.prototype, {
|
||||
open(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}open`, oldMethod, function () {
|
||||
// console.debug('Call Modal.open');
|
||||
const result = oldMethod && oldMethod.apply(this);
|
||||
|
||||
// Check the opened Modal is the Community plugin browse modal
|
||||
if (this.containerEl?.querySelector('.mod-community-plugin')) {
|
||||
// Patch CommunityPluginModal
|
||||
if (!plugin.uninstallCommunityPluginModalPatch) {
|
||||
// console.debug('Patch CommunityPluginModal');
|
||||
plugin.uninstallCommunityPluginModalPatch = patchCommunityPluginModal(this, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the opened Modal is the Community themes browse modal
|
||||
if (this.containerEl?.querySelector('.mod-community-theme')) {
|
||||
// Patch CommunityThemeModal
|
||||
if (!plugin.uninstallCommunityThemeModalPatch) {
|
||||
// console.debug('Patch CommunityThemeModal');
|
||||
plugin.uninstallCommunityThemeModalPatch = patchCommunityThemeModal(this, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin.uninstallModalPatch && plugin.uninstallCommunityPluginModalPatch && plugin.uninstallCommunityThemeModalPatch) {
|
||||
// console.debug('Uninstall Modal patch');
|
||||
plugin.uninstallModalPatch();
|
||||
plugin.uninstallModalPatch = undefined;
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
});
|
||||
74
src/patches/patch.PluginManager.ts
Normal file
74
src/patches/patch.PluginManager.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import MyPlugin from '../main';
|
||||
import { around, dedupe } from 'monkey-around';
|
||||
import { PluginManifest } from 'obsidian';
|
||||
import { PLUGIN_ID } from 'src/constants';
|
||||
|
||||
const MONKEY_KEY = `${PLUGIN_ID}-PluginManager-`;
|
||||
|
||||
export default (plugin: MyPlugin) => around(plugin.app.plugins, {
|
||||
installPlugin(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}installPlugin`, oldMethod, async function (repo: string, version: string, manifest: PluginManifest) {
|
||||
// console.debug('Call PluginManager.installPlugin');
|
||||
|
||||
const result = oldMethod && await oldMethod.apply(this, [repo, version, manifest]);
|
||||
|
||||
// Load the plugin lists
|
||||
plugin.loadKnownPlugins();
|
||||
|
||||
// Add Plugin to known list if not already
|
||||
if (!plugin.knownPlugins.contains(manifest.id)) {
|
||||
plugin.knownPlugins.push(manifest.id);
|
||||
}
|
||||
|
||||
plugin.saveKnownPlugins();
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
loadPlugin(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}loadPlugin`, oldMethod, async function (id: string) {
|
||||
// console.debug('Call PluginManager.loadPlugin');
|
||||
|
||||
const currentVault = plugin.app.appId;
|
||||
|
||||
// Load the plugin lists
|
||||
plugin.loadInUsePlugins();
|
||||
|
||||
// Add the plugin to the in use list with this vault as user
|
||||
if (!plugin.inUsePlugins[id] || !Array.isArray(plugin.inUsePlugins[id])) {
|
||||
plugin.inUsePlugins[id] = [];
|
||||
}
|
||||
if (!plugin.inUsePlugins[id].contains(currentVault)) {
|
||||
plugin.inUsePlugins[id].push(currentVault);
|
||||
}
|
||||
|
||||
plugin.saveInUsePlugins();
|
||||
|
||||
return oldMethod && oldMethod.apply(this, [id]);
|
||||
});
|
||||
},
|
||||
unloadPlugin(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}unloadPlugin`, oldMethod, async function (id: string) {
|
||||
// console.debug('Call PluginManager.unloadPlugin');
|
||||
|
||||
const currentVault = plugin.app.appId;
|
||||
|
||||
// Load the plugin lists
|
||||
plugin.loadInUsePlugins();
|
||||
|
||||
// Remove current vault from unloaded plugin
|
||||
if (plugin.inUsePlugins[id] && Array.isArray(plugin.inUsePlugins[id]) && plugin.inUsePlugins[id].contains(currentVault)) {
|
||||
plugin.inUsePlugins[id].remove(currentVault);
|
||||
|
||||
// Cleanup in use if last vault stops using it
|
||||
if (plugin.inUsePlugins[id].length <= 0) {
|
||||
delete plugin.inUsePlugins[id];
|
||||
}
|
||||
}
|
||||
|
||||
plugin.saveInUsePlugins();
|
||||
|
||||
return oldMethod && oldMethod.apply(this, [id]);
|
||||
});
|
||||
},
|
||||
});
|
||||
30
src/patches/patch.SettingsModal.ts
Normal file
30
src/patches/patch.SettingsModal.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { CommunityPluginsSettingTab, SettingsModal, SettingTab } from 'obsidian';
|
||||
import MyPlugin from '../main';
|
||||
import { around, dedupe } from 'monkey-around';
|
||||
import { PLUGIN_ID } from 'src/constants';
|
||||
import patchCommunityPluginsSettingTab from './patch.CommunityPluginsSettingTab';
|
||||
|
||||
const MONKEY_KEY = `${PLUGIN_ID}-SettingsModal-`;
|
||||
|
||||
export default (plugin: MyPlugin) => around(plugin.app.setting as SettingsModal, {
|
||||
openTab(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}openTab`, oldMethod, function (tab: SettingTab) {
|
||||
// console.debug('Call SettingsModal.openTab');
|
||||
|
||||
if (tab.id === 'community-plugins') {
|
||||
if (!plugin.uninstallCommunityPluginsSettingTabPatch) {
|
||||
// console.debug('Patch CommunityPluginsSettingTab');
|
||||
plugin.uninstallCommunityPluginsSettingTabPatch = patchCommunityPluginsSettingTab(tab as CommunityPluginsSettingTab, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin.uninstallSettingsModalPatch && plugin.uninstallCommunityPluginsSettingTabPatch) {
|
||||
// console.debug('Uninstall SettingsModal patch');
|
||||
plugin.uninstallSettingsModalPatch();
|
||||
plugin.uninstallSettingsModalPatch = undefined;
|
||||
}
|
||||
|
||||
return oldMethod && oldMethod.apply(this, [tab]);
|
||||
});
|
||||
},
|
||||
});
|
||||
69
src/patches/patch.StyleManager.ts
Normal file
69
src/patches/patch.StyleManager.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import MyPlugin from '../main';
|
||||
import { around, dedupe } from 'monkey-around';
|
||||
import { ThemeManifest } from 'obsidian';
|
||||
import { PLUGIN_ID } from 'src/constants';
|
||||
|
||||
const MONKEY_KEY = `${PLUGIN_ID}-StyleManager-installTheme`;
|
||||
|
||||
export default (plugin: MyPlugin) => around(plugin.app.customCss, {
|
||||
installTheme(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}installTheme`, oldMethod, async function (manifest: ThemeManifest, version: string) {
|
||||
// console.debug('Call StyleManager.installTheme');
|
||||
|
||||
const result = oldMethod && await oldMethod.apply(this, [manifest, version]);
|
||||
|
||||
// Load the theme lists
|
||||
plugin.loadKnownThemes();
|
||||
|
||||
// Add Theme to known list if not already
|
||||
if (!plugin.knownThemes.contains(manifest.name)) {
|
||||
plugin.knownThemes.push(manifest.name);
|
||||
}
|
||||
|
||||
plugin.saveKnownThemes();
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
setTheme(oldMethod) {
|
||||
return dedupe(`${MONKEY_KEY}setTheme`, oldMethod, function (name: string) {
|
||||
// console.debug('Call StyleManager.setTheme', this);
|
||||
|
||||
const currentVault = plugin.app.appId;
|
||||
|
||||
// Load the theme lists
|
||||
plugin.loadInUseThemes();
|
||||
|
||||
// Remove current vault from replaced theme
|
||||
const oldTheme = this.theme;
|
||||
if (plugin.inUseThemes[oldTheme] && Array.isArray(plugin.inUseThemes[oldTheme]) && plugin.inUseThemes[oldTheme].contains(currentVault)) {
|
||||
plugin.inUseThemes[oldTheme].remove(currentVault);
|
||||
|
||||
// Cleanup in use if last vault stops using it
|
||||
if (plugin.inUseThemes[oldTheme].length <= 0) {
|
||||
delete plugin.inUseThemes[oldTheme];
|
||||
}
|
||||
}
|
||||
|
||||
const result = oldMethod && oldMethod.apply(this, [name]);
|
||||
|
||||
// Ignore the default theme
|
||||
if (name === '') {
|
||||
plugin.saveInUseThemes();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Add the theme to the in use list with this vault as user
|
||||
if (!plugin.inUseThemes[name] || !Array.isArray(plugin.inUseThemes[name])) {
|
||||
plugin.inUseThemes[name] = [];
|
||||
}
|
||||
if (!plugin.inUseThemes[name].contains(currentVault)) {
|
||||
plugin.inUseThemes[name].push(currentVault);
|
||||
}
|
||||
|
||||
plugin.saveInUseThemes();
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
});
|
||||
205
src/types.d.ts
vendored
205
src/types.d.ts
vendored
|
|
@ -1,37 +1,200 @@
|
|||
import { } from 'obsidian';
|
||||
|
||||
declare module 'obsidian' {
|
||||
interface App {
|
||||
appId: string;
|
||||
setting: SettingsModal;
|
||||
plugins: PluginManager;
|
||||
customCss: StyleManager;
|
||||
}
|
||||
|
||||
interface ThemeManifest {
|
||||
author: string;
|
||||
authorUrl: string;
|
||||
dir: string;
|
||||
minAppVersion: string;
|
||||
name: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
interface CommunityItem {
|
||||
id: string;
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
interface CommunityModal {
|
||||
interface CommunityModal extends Modal {
|
||||
sortOrder: string;
|
||||
items: unknown;
|
||||
itemsVisible: unknown;
|
||||
selectedItemId: string | null;
|
||||
dimBackground: unknown;
|
||||
onCloseCallback: () => void;
|
||||
update(): void;
|
||||
returnToGridView(): void;
|
||||
selectItem(id: string | null): unknown;
|
||||
showSortMenu(event: unknown): void;
|
||||
sortItems(items: unknown): unknown;
|
||||
scrollIntoView(): unknown;
|
||||
addCustomControls(): unknown;
|
||||
updateItems(): CommunityItem[];
|
||||
showItem(item: CommunityItem): void;
|
||||
|
||||
// ...
|
||||
|
||||
// Additional from this plugin
|
||||
/**
|
||||
* This is the backup of the original ``updateItems()`` function. Do not use otherwise than restoring!
|
||||
*/
|
||||
originalUpdateItems?(): CommunityItem[];
|
||||
|
||||
/**
|
||||
* This is the backup of the original ``showItem()`` function. Do not use otherwise than restoring!
|
||||
*/
|
||||
originalShowItem?(item: CommunityItem): void;
|
||||
showItem(item: CommunityItem): Promise<void>;
|
||||
}
|
||||
|
||||
interface Modal {
|
||||
interface CommunityThemeModal extends CommunityModal {
|
||||
|
||||
}
|
||||
|
||||
interface CommunityPluginModal extends CommunityModal {
|
||||
setAutoOpen(id: string): CommunityPluginModal;
|
||||
loadItems(): unknown;
|
||||
}
|
||||
|
||||
interface SettingsModal extends Modal {
|
||||
openTab(settingTab: SettingTab): void;
|
||||
}
|
||||
|
||||
interface SettingTab {
|
||||
|
||||
// Additional form this plugin
|
||||
/**
|
||||
* This is the backup of the original ``open()`` function. Do not use otherwise than restoring!
|
||||
* Used to identify the tab
|
||||
*
|
||||
* @private reverse engineered
|
||||
*/
|
||||
originalOpen?(): void;
|
||||
id: string;
|
||||
setting: unknown;
|
||||
navEl: HTMLElement;
|
||||
}
|
||||
|
||||
interface CommunityPluginsSettingTab extends SettingTab {
|
||||
id: 'community-plugins';
|
||||
installedPlugins: {
|
||||
listEl: HTMLElement
|
||||
};
|
||||
|
||||
render(e: boolean): void;
|
||||
renderInstalledPlugin(plugin: CommunityItem, containerEl: HTMLElement, n: unknown, i: unknown, r: unknown): void;
|
||||
updateSearch(e: unknown): void
|
||||
}
|
||||
|
||||
interface HotkeysSettingTab extends SettingTab {
|
||||
name: string;
|
||||
id: 'hotkeys';
|
||||
setHotkeyScope: unknown;
|
||||
commandBeingCustomized: unknown;
|
||||
filterHotkeyScope: unknown;
|
||||
filterHotkeyEl: unknown;
|
||||
filterHotkeyActiveEl: unknown;
|
||||
hotkeyListContainerEl: unknown;
|
||||
hotkeyFilter: unknown;
|
||||
}
|
||||
|
||||
interface StyleManager extends Component {
|
||||
app: App;
|
||||
styleEl: HTMLStyleElement;
|
||||
extraStyleEls: HTMLStyleElement[];
|
||||
boundRaw: () => unknown;
|
||||
oldThemes: unknown[];
|
||||
|
||||
/**
|
||||
* Holds the manifest of the installed themes in this vault
|
||||
*
|
||||
* @private reverse engineered
|
||||
*/
|
||||
themes: Record<string, ThemeManifest>;
|
||||
updates: Record<string, { themeInfo: unknown, version: string }>;
|
||||
snippets: string[];
|
||||
enabledSnippets: Set<string>;
|
||||
csscache: Map<number, unknown>;
|
||||
|
||||
/**
|
||||
* Holds the id of the enabled theme
|
||||
*
|
||||
* @private reverse engineered
|
||||
*/
|
||||
theme: string;
|
||||
requestLoadTheme: () => unknown;
|
||||
requestLoadSnippets: () => unknown;
|
||||
requestReadThemes: () => unknown;
|
||||
queue: unknown;
|
||||
|
||||
onload(): Promise<unknown>;
|
||||
loadData(): void;
|
||||
readThemes(e: unknown): unknown;
|
||||
readSnippets(e: unknown): unknown;
|
||||
onRaw(e: unknown): void;
|
||||
loadTheme(e: undefined): unknown;
|
||||
loadSnippets(): unknown;
|
||||
loadCss(path: string): Promise<unknown>;
|
||||
setCssEnabledStatus(e: unknown, t: unknown): void;
|
||||
setTheme(name: string): void;
|
||||
setTranslucency(e: unknown): void;
|
||||
enableTranslucency(): void;
|
||||
disableTranslucency(): void;
|
||||
getThemeFolder(): string;
|
||||
getSnippetsFolder(): string;
|
||||
getThemePath(e: unknown): string;
|
||||
getSnippetPath(e: unknown): string;
|
||||
removeTheme(e: unknown): Promise<unknown>;
|
||||
downloadLegacyTheme(e: unknown): Promise<unknown>;
|
||||
isThemeInstalled(e: unknown): unknown;
|
||||
hasUpdates(): unknown;
|
||||
checkForUpdate(e: unknown): Promise<unknown>;
|
||||
checkForUpdates(): Promise<unknown>;
|
||||
installLegacyTheme(e: unknown): Promise<unknown>;
|
||||
installTheme(manifest: ThemeManifest, version: string): Promise<unknown>;
|
||||
getManifest(e: unknown): Promise<unknown>;
|
||||
}
|
||||
|
||||
interface PluginManager {
|
||||
|
||||
/**
|
||||
* Holds the manifest of the installed plugins in this vault
|
||||
*
|
||||
* @private reverse engineered
|
||||
*/
|
||||
manifests: Record<string, PluginManifest>;
|
||||
|
||||
/**
|
||||
* Holds references to the loaded plugins identified by there id
|
||||
*
|
||||
* @private reverse engineered
|
||||
*/
|
||||
plugins: Record<string, Plugin>;
|
||||
|
||||
/**
|
||||
* Holds a the ids of the enabled plugins in this vault
|
||||
*
|
||||
* @private reverse engineered
|
||||
*/
|
||||
enabledPlugins: Set<string>;
|
||||
|
||||
/**
|
||||
* Holds the available updates identified by there id with information about the update
|
||||
*
|
||||
* @private reverse engineered
|
||||
*/
|
||||
updates: Record<string, { repo: string, version: string, manifest: PluginManifest }>;
|
||||
requestSaveConfig: () => unknown;
|
||||
app: App;
|
||||
|
||||
onRaw(e: unknown): void;
|
||||
loadManifests(): Promise<unknown>;
|
||||
loadManifest(path: string): Promise<unknown>;
|
||||
loadPlugin(id: string): Promise<unknown>;
|
||||
unloadPlugin(id: string): Promise<unknown>;
|
||||
initialize(): Promise<unknown>;
|
||||
getPluginFolder(): string;
|
||||
enablePlugin(id: string): Promise<unknown>;
|
||||
disablePlugin(id: string): Promise<unknown>;
|
||||
enablePluginAndSave(id: string): Promise<unknown>;
|
||||
disablePluginAndSave(id: string): Promise<unknown>;
|
||||
uninstallPlugin(id: string): Promise<unknown>;
|
||||
getPlugin(id: string): unknown | null;
|
||||
saveConfig(): Promise<unknown>;
|
||||
isEnabled(): boolean;
|
||||
setEnable(e: unknown): Promise<unknown>;
|
||||
checkForDeprecations(): Promise<unknown>;
|
||||
isDeprecated(e: unknown): unknown;
|
||||
installPlugin(repo: string, version: string, manifest: PluginManifest): Promise<unknown>;
|
||||
checkForUpdates(): Promise<unknown>;
|
||||
}
|
||||
}
|
||||
11
src/ui-components/ActiveFlair.ts
Normal file
11
src/ui-components/ActiveFlair.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export default class ActiveFlair {
|
||||
constructor(parentEl: HTMLElement) {
|
||||
if (parentEl) {
|
||||
const flair = Array.from(parentEl.getElementsByClassName('flair')).find(el => el.textContent?.trim().toLowerCase() === 'active');
|
||||
|
||||
if (flair) {
|
||||
flair.setAttribute('aria-label', 'Active theme in this vault');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/ui-components/FavoriteFlair.ts
Normal file
7
src/ui-components/FavoriteFlair.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import Flair from './Flair';
|
||||
|
||||
export default class FavoriteFlair extends Flair {
|
||||
constructor(parentEl: HTMLElement) {
|
||||
super(parentEl, 'Favorite', 'Marked as favorite');
|
||||
}
|
||||
}
|
||||
13
src/ui-components/Flair.ts
Normal file
13
src/ui-components/Flair.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export default class Flair {
|
||||
constructor(parentEl: HTMLElement, text: string, ariaLabel: string | null = null) {
|
||||
if (parentEl) {
|
||||
const flair = parentEl.createSpan({
|
||||
cls: 'flair',
|
||||
text: text,
|
||||
});
|
||||
if (ariaLabel) {
|
||||
flair.setAttribute('aria-label', ariaLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/ui-components/InUseFlair.ts
Normal file
7
src/ui-components/InUseFlair.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import Flair from './Flair';
|
||||
|
||||
export default class InUseFlair extends Flair {
|
||||
constructor(parentEl: HTMLElement) {
|
||||
super(parentEl, 'In Use', 'Enabled in at least one vault');
|
||||
}
|
||||
}
|
||||
11
src/ui-components/InstalledFlair.ts
Normal file
11
src/ui-components/InstalledFlair.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export default class InstalledFlair {
|
||||
constructor(parentEl: HTMLElement) {
|
||||
if (parentEl) {
|
||||
const flair = Array.from(parentEl.getElementsByClassName('flair')).find(el => el.textContent?.trim().toLowerCase() === 'installed');
|
||||
|
||||
if (flair) {
|
||||
flair.setAttribute('aria-label', 'Installed in this vault');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/ui-components/KnownFlair.ts
Normal file
7
src/ui-components/KnownFlair.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import Flair from './Flair';
|
||||
|
||||
export default class KnownFlair extends Flair {
|
||||
constructor(parentEl: HTMLElement) {
|
||||
super(parentEl, 'Known', 'Installed at least once in a vault');
|
||||
}
|
||||
}
|
||||
60
src/util/GitHub.ts
Normal file
60
src/util/GitHub.ts
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* Credits: https://github.com/TfTHacker/obsidian42-brat
|
||||
*/
|
||||
|
||||
import { request } from 'obsidian';
|
||||
|
||||
export interface CommunityEntry {
|
||||
name: string;
|
||||
author: string;
|
||||
repo: string;
|
||||
}
|
||||
|
||||
export interface CommunityPlugin extends CommunityEntry {
|
||||
id: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface CommunityTheme extends CommunityEntry {
|
||||
screenshot: string;
|
||||
modes: string[];
|
||||
legacy?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all community plugin entries.
|
||||
* @returns A list of community plugins
|
||||
*/
|
||||
export async function fetchCommunityPluginList(): Promise<CommunityPlugin[] | undefined> {
|
||||
const URL = 'https://raw.githubusercontent.com/obsidianmd/obsidian-releases/HEAD/community-plugins.json';
|
||||
try {
|
||||
// Do a request to the url
|
||||
const response = await request({ url: URL });
|
||||
|
||||
// Process the response
|
||||
return (await JSON.parse(response)) as CommunityPlugin[];
|
||||
}
|
||||
catch (e) {
|
||||
(e as Error).message = 'Failed to fetch community plugin list! ' + (e as Error).message;
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all community theme entries.
|
||||
* @returns A list of community themes
|
||||
*/
|
||||
export async function fetchCommunityThemeList(): Promise<CommunityTheme[] | undefined> {
|
||||
const URL = 'https://raw.githubusercontent.com/obsidianmd/obsidian-releases/refs/heads/master/community-css-themes.json';
|
||||
try {
|
||||
// Do a request to the url
|
||||
const response = await request({ url: URL });
|
||||
|
||||
// Process the response
|
||||
return (await JSON.parse(response)) as CommunityTheme[];
|
||||
}
|
||||
catch (e) {
|
||||
(e as Error).message = 'Failed to fetch community plugin list! ' + (e as Error).message;
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
5
styles.css
Normal file
5
styles.css
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.community-item-name {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
import { version as manifestVersion, minAppVersion as manifestMinAppVersion } from '../manifest.json';
|
||||
import { version as packageVersion } from '../package.json';
|
||||
import { version as packageLockVersion } from '../package.json';
|
||||
import versions from '../versions.json';
|
||||
|
||||
test('Versions matching', () => {
|
||||
expect(manifestVersion).toBe(packageVersion);
|
||||
expect(manifestVersion).toBe(packageLockVersion);
|
||||
expect(Object.keys(versions).find(value => value === manifestVersion)).toBe(manifestVersion);
|
||||
expect(Object.entries(versions).find(value => value[0] === manifestVersion)?.[1]).toBe(manifestMinAppVersion);
|
||||
});
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { valid } from "semver";
|
||||
import { execSync } from 'child_process';
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import { valid } from 'semver';
|
||||
|
||||
const newVersion = process.argv.find(value => value.startsWith('--new_version'));
|
||||
if (!newVersion) {
|
||||
|
|
@ -14,23 +15,30 @@ if (!valid(targetVersion)) {
|
|||
}
|
||||
|
||||
// read minAppVersion from manifest.json
|
||||
let manifestFile = JSON.parse(readFileSync("manifest.json", "utf8"));
|
||||
let manifestFile = JSON.parse(readFileSync('manifest.json', 'utf8'));
|
||||
const { minAppVersion } = manifestFile;
|
||||
if (!minAppVersion || minAppVersion === "") {
|
||||
throw Error('Missing minAppVersion in "manifest.json"');
|
||||
if (!minAppVersion || minAppVersion === '') {
|
||||
throw Error(`Missing minAppVersion in 'manifest.json'`);
|
||||
}
|
||||
|
||||
// update version to target version
|
||||
manifestFile.version = targetVersion;
|
||||
writeFileSync("manifest.json", JSON.stringify(manifestFile, null, "\t"));
|
||||
writeFileSync('manifest.json', JSON.stringify(manifestFile, null, '\t'));
|
||||
|
||||
// update version in package
|
||||
let packageFile = JSON.parse(readFileSync("package.json", "utf8"));
|
||||
let packageFile = JSON.parse(readFileSync('package.json', 'utf8'));
|
||||
packageFile.version = targetVersion;
|
||||
writeFileSync("package.json", JSON.stringify(packageFile, null, "\t"));
|
||||
writeFileSync('package.json', JSON.stringify(packageFile, null, '\t'));
|
||||
|
||||
// update version in package-lock
|
||||
try {
|
||||
execSync('npm install', { stdio: 'inherit' });
|
||||
} catch (error) {
|
||||
throw Error('npm installed failed: ' + error);
|
||||
}
|
||||
|
||||
// read versions file
|
||||
let versionsFile = JSON.parse(readFileSync("versions.json", "utf8"));
|
||||
let versionsFile = JSON.parse(readFileSync('versions.json', 'utf8'));
|
||||
let keys = Object.keys(versionsFile);
|
||||
|
||||
// remove existing versions with same minAppVersion
|
||||
|
|
@ -42,4 +50,4 @@ keys.forEach(key => {
|
|||
|
||||
// update versions.json with target version and minAppVersion from manifest.json
|
||||
versionsFile[targetVersion] = minAppVersion;
|
||||
writeFileSync("versions.json", JSON.stringify(versionsFile, null, "\t"));
|
||||
writeFileSync('versions.json', JSON.stringify(versionsFile, null, '\t'));
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"1.1.1": "1.8.10"
|
||||
"1.4.0": "1.8.10"
|
||||
}
|
||||
Loading…
Reference in a new issue