mirror of
https://github.com/alberti42/obsidian-plugins-annotations.git
synced 2026-07-22 05:11:57 +00:00
First import
This commit is contained in:
commit
8f6d101db5
12 changed files with 2819 additions and 0 deletions
96
README.md
Normal file
96
README.md
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# Obsidian Sample Plugin
|
||||
|
||||
This is a sample plugin for Obsidian (https://obsidian.md).
|
||||
|
||||
This project uses Typescript to provide type checking and documentation.
|
||||
The repo depends on the latest plugin API (obsidian.d.ts) in Typescript Definition format, which contains TSDoc comments describing what it does.
|
||||
|
||||
**Note:** The Obsidian API is still in early alpha and is subject to change at any time!
|
||||
|
||||
This sample plugin demonstrates some of the basic functionality the plugin API can do.
|
||||
- Adds a ribbon icon, which shows a Notice when clicked.
|
||||
- Adds a command "Open Sample Modal" which opens a Modal.
|
||||
- Adds a plugin setting tab to the settings page.
|
||||
- Registers a global click event and output 'click' to the console.
|
||||
- Registers a global interval which logs 'setInterval' to the console.
|
||||
|
||||
## First time developing plugins?
|
||||
|
||||
Quick starting guide for new plugin devs:
|
||||
|
||||
- Check if [someone already developed a plugin for what you want](https://obsidian.md/plugins)! There might be an existing plugin similar enough that you can partner up with.
|
||||
- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it).
|
||||
- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder.
|
||||
- Install NodeJS, then run `npm i` in the command line under your repo folder.
|
||||
- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`.
|
||||
- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`.
|
||||
- Reload Obsidian to load the new version of your plugin.
|
||||
- Enable plugin in settings window.
|
||||
- For updates to the Obsidian API run `npm update` in the command line under your repo folder.
|
||||
|
||||
## Releasing new releases
|
||||
|
||||
- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release.
|
||||
- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible.
|
||||
- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases
|
||||
- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments. Note: The manifest.json file must be in two places, first the root path of your repository and also in the release.
|
||||
- Publish the release.
|
||||
|
||||
> You can simplify the version bump process by running `npm version patch`, `npm version minor` or `npm version major` after updating `minAppVersion` manually in `manifest.json`.
|
||||
> The command will bump version in `manifest.json` and `package.json`, and add the entry for the new version to `versions.json`
|
||||
|
||||
## Adding your plugin to the community plugin list
|
||||
|
||||
- Check https://github.com/obsidianmd/obsidian-releases/blob/master/plugin-review.md
|
||||
- Publish an initial version.
|
||||
- Make sure you have a `README.md` file in the root of your repo.
|
||||
- Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin.
|
||||
|
||||
## How to use
|
||||
|
||||
- Clone this repo.
|
||||
- Make sure your NodeJS is at least v16 (`node --version`).
|
||||
- `npm i` or `yarn` to install dependencies.
|
||||
- `npm run dev` to start compilation in watch mode.
|
||||
|
||||
## Manually installing the plugin
|
||||
|
||||
- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`.
|
||||
|
||||
## Improve code quality with eslint (optional)
|
||||
- [ESLint](https://eslint.org/) is a tool that analyzes your code to quickly find problems. You can run ESLint against your plugin to find common bugs and ways to improve your code.
|
||||
- To use eslint with this project, make sure to install eslint from terminal:
|
||||
- `npm install -g eslint`
|
||||
- To use eslint to analyze this project use this command:
|
||||
- `eslint main.ts`
|
||||
- eslint will then create a report with suggestions for code improvement by file and line number.
|
||||
- If your source code is in a folder, such as `src`, you can use eslint with this command to analyze all files in that folder:
|
||||
- `eslint .\src\`
|
||||
|
||||
## Funding URL
|
||||
|
||||
You can include funding URLs where people who use your plugin can financially support it.
|
||||
|
||||
The simple way is to set the `fundingUrl` field to your link in your `manifest.json` file:
|
||||
|
||||
```json
|
||||
{
|
||||
"fundingUrl": "https://buymeacoffee.com"
|
||||
}
|
||||
```
|
||||
|
||||
If you have multiple URLs, you can also do:
|
||||
|
||||
```json
|
||||
{
|
||||
"fundingUrl": {
|
||||
"Buy Me a Coffee": "https://buymeacoffee.com",
|
||||
"GitHub Sponsor": "https://github.com/sponsors",
|
||||
"Patreon": "https://www.patreon.com/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Documentation
|
||||
|
||||
See https://github.com/obsidianmd/obsidian-api
|
||||
69
esbuild.config.mjs
Normal file
69
esbuild.config.mjs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import esbuild from "esbuild";
|
||||
import process from "process";
|
||||
import builtins from "builtin-modules";
|
||||
import copy from 'esbuild-plugin-copy';
|
||||
|
||||
// Banner message for the generated/bundled files
|
||||
const banner = `
|
||||
/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
`;
|
||||
|
||||
// Determine whether to build for production or development
|
||||
const prod = (process.argv[2] === "production");
|
||||
|
||||
// Get the output directory
|
||||
const outdir = 'dist';
|
||||
|
||||
const context = await esbuild.context({
|
||||
banner: {
|
||||
js: banner,
|
||||
},
|
||||
entryPoints: ["src/main.ts"],
|
||||
bundle: true,
|
||||
external: [
|
||||
"obsidian",
|
||||
"electron",
|
||||
"@codemirror/autocomplete",
|
||||
"@codemirror/collab",
|
||||
"@codemirror/commands",
|
||||
"@codemirror/language",
|
||||
"@codemirror/lint",
|
||||
"@codemirror/search",
|
||||
"@codemirror/state",
|
||||
"@codemirror/view",
|
||||
"@lezer/common",
|
||||
"@lezer/highlight",
|
||||
"@lezer/lr",
|
||||
...builtins
|
||||
],
|
||||
format: "cjs",
|
||||
target: "es2018",
|
||||
logLevel: "info",
|
||||
sourcemap: prod ? false : "inline",
|
||||
treeShaking: true,
|
||||
outdir,
|
||||
plugins: [
|
||||
copy({
|
||||
assets: {
|
||||
from: ['./manifest.json'],
|
||||
to: ['./manifest.json']
|
||||
}
|
||||
}),
|
||||
copy({
|
||||
assets: {
|
||||
from: ['./styles/styles.css'],
|
||||
to: ['./styles.css']
|
||||
}
|
||||
})
|
||||
],
|
||||
});
|
||||
|
||||
if (prod) {
|
||||
await context.rebuild();
|
||||
process.exit(0);
|
||||
} else {
|
||||
await context.watch();
|
||||
}
|
||||
11
manifest.json
Normal file
11
manifest.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"id": "plugins-comment",
|
||||
"name": "Plugin Comment",
|
||||
"version": "1.0.0",
|
||||
"minAppVersion": "1.5.0",
|
||||
"description": "Allows adding personal comments to each installed plugin.",
|
||||
"author": "Obsidian",
|
||||
"authorUrl": "https://www.linkedin.com/in/dr-andrea-alberti/",
|
||||
"fundingUrl": "https://buymeacoffee.com/alberti",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
2378
package-lock.json
generated
Normal file
2378
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
28
package.json
Normal file
28
package.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "obsidian-sample-plugin",
|
||||
"version": "1.0.0",
|
||||
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"esbuild": "0.17.3",
|
||||
"esbuild-plugin-copy": "^2.1.1",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"monkey-around": "^3.0.0"
|
||||
}
|
||||
}
|
||||
28
src/db.ts
Normal file
28
src/db.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// db.ts
|
||||
|
||||
import { Vault } from 'obsidian';
|
||||
|
||||
const DB_FILE = 'plugin-annotations.json';
|
||||
|
||||
interface PluginAnnotation {
|
||||
[pluginId: string]: string;
|
||||
}
|
||||
|
||||
export async function loadAnnotations(vault: Vault): Promise<PluginAnnotation> {
|
||||
try {
|
||||
const file = await vault.adapter.read(DB_FILE);
|
||||
return JSON.parse(file);
|
||||
} catch (error) {
|
||||
console.error('Failed to load annotations:', error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveAnnotations(vault: Vault, annotations: PluginAnnotation): Promise<void> {
|
||||
try {
|
||||
const data = JSON.stringify(annotations, null, 2);
|
||||
await vault.adapter.write(DB_FILE, data);
|
||||
} catch (error) {
|
||||
console.error('Failed to save annotations:', error);
|
||||
}
|
||||
}
|
||||
103
src/main.ts
Normal file
103
src/main.ts
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import { Plugin, SettingTab, PluginSettingTab, App, Setting } from 'obsidian';
|
||||
import { around } from 'monkey-around';
|
||||
|
||||
export default class PluginComment extends Plugin {
|
||||
async onload() {
|
||||
console.log('Loading Plugin Comment');
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
this.patchSettings();
|
||||
});
|
||||
}
|
||||
|
||||
patchSettings() {
|
||||
const self = this;
|
||||
|
||||
// Patch openTab to detect when a tab is opened
|
||||
this.register(
|
||||
around(this.app.setting, {
|
||||
openTab: (next: (tab: SettingTab) => void) => {
|
||||
return function(this: Setting, tab: SettingTab) {
|
||||
const result = next.call(this, tab);
|
||||
if (tab && tab.id === 'community-plugins') {
|
||||
self.observeTab(tab);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
observeTab(tab: SettingTab) {
|
||||
const observer = new MutationObserver(() => {
|
||||
this.addComments(tab);
|
||||
});
|
||||
|
||||
observer.observe(tab.containerEl, { childList: true, subtree: true });
|
||||
|
||||
// Initial call to add comments to already present plugins
|
||||
this.addComments(tab);
|
||||
|
||||
// Clean up observer on unload
|
||||
this.register(() => observer.disconnect());
|
||||
}
|
||||
|
||||
addComments(tab: SettingTab) {
|
||||
const pluginsContainer = tab.containerEl.querySelector('.installed-plugins-container');
|
||||
if (!pluginsContainer) return;
|
||||
|
||||
const plugins = pluginsContainer.querySelectorAll('.setting-item');
|
||||
plugins.forEach(plugin => {
|
||||
const settingItemInfo = plugin.querySelector('.setting-item-info');
|
||||
if (settingItemInfo) {
|
||||
const pluginNameDiv = plugin.querySelector('.setting-item-name');
|
||||
const pluginName = pluginNameDiv ? pluginNameDiv.textContent : 'Unknown Plugin';
|
||||
|
||||
const descriptionDiv = settingItemInfo.querySelector('.setting-item-description');
|
||||
if (descriptionDiv) {
|
||||
const commentDiv = descriptionDiv.querySelector('.plugin-comment');
|
||||
if (!commentDiv) {
|
||||
const label = document.createElement('div');
|
||||
label.innerText = `Personal annotation:`;
|
||||
label.className = 'plugin-comment-label'
|
||||
descriptionDiv.appendChild(label);
|
||||
|
||||
const comment = document.createElement('div');
|
||||
comment.className = 'plugin-comment';
|
||||
comment.contentEditable = 'true';
|
||||
comment.innerText = `Add your comment about ${pluginName} here...`;
|
||||
|
||||
// Prevent click event propagation to parent
|
||||
comment.addEventListener('click', (event) => {
|
||||
console.log("Triggede");
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
descriptionDiv.appendChild(comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
onunload() {
|
||||
console.log('Unloading Plugin Comment');
|
||||
}
|
||||
}
|
||||
|
||||
class CommentSettingTab extends PluginSettingTab {
|
||||
constructor(app: App, plugin: Plugin) {
|
||||
super(app, plugin);
|
||||
}
|
||||
|
||||
display() {
|
||||
const { containerEl } = this;
|
||||
|
||||
containerEl.empty();
|
||||
containerEl.createEl('h2', { text: 'Plugin Comment Settings' });
|
||||
|
||||
// Add any settings here if necessary
|
||||
}
|
||||
}
|
||||
53
src/types/obsidian-augment.d.ts
vendored
Normal file
53
src/types/obsidian-augment.d.ts
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// obsidian-augment.d.ts
|
||||
|
||||
import 'obsidian';
|
||||
|
||||
declare module "obsidian" {
|
||||
interface App {
|
||||
internalPlugins: InternalPlugins;
|
||||
plugins: Plugins;
|
||||
setting: Setting;
|
||||
}
|
||||
interface Plugin {
|
||||
_loaded: boolean;
|
||||
}
|
||||
interface PluginSettingTab {
|
||||
name: string;
|
||||
}
|
||||
interface SettingTab {
|
||||
id: string;
|
||||
name: string;
|
||||
navEl: HTMLElement;
|
||||
}
|
||||
interface Workspace {
|
||||
on(name: "settings-search-loaded", callback: (...args: any[]) => any): EventRef;
|
||||
}
|
||||
interface Setting {
|
||||
onOpen(): void;
|
||||
onClose(): void;
|
||||
|
||||
openTabById(id: string): void;
|
||||
openTab(tab: SettingTab): void;
|
||||
|
||||
isPluginSettingTab(tab: SettingTab): boolean;
|
||||
addSettingTab(tab: SettingTab): void;
|
||||
removeSettingTab(tab: SettingTab): void;
|
||||
|
||||
activeTab: SettingTab;
|
||||
lastTabId: string;
|
||||
|
||||
pluginTabs: PluginSettingTab[];
|
||||
settingTabs: SettingTab[];
|
||||
|
||||
tabContentContainer: HTMLDivElement;
|
||||
tabHeadersEl: HTMLDivElement;
|
||||
}
|
||||
interface Plugins {
|
||||
manifests: Record<string, PluginManifest>;
|
||||
plugins: Record<string, Plugin>;
|
||||
getPlugin(id: string): Plugin;
|
||||
}
|
||||
interface InternalPlugins {
|
||||
plugins: Record<string,{ _loaded: boolean; instance: { name: string; id: string } }>;
|
||||
}
|
||||
}
|
||||
9
styles/styles.css
Normal file
9
styles/styles.css
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* styles.css */
|
||||
.plugin-comment-label {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.plugin-comment-annotation {
|
||||
padding-top: 5px;
|
||||
font-style: italic;
|
||||
}
|
||||
27
tsconfig.json
Normal file
27
tsconfig.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "src",
|
||||
"outDir": "dist",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext", // or "CommonJS" if you are targeting Node.js
|
||||
"target": "ES2020", // Modern target for better browser support
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"strictNullChecks": true,
|
||||
"strict": true, // Enforces strict type checking options
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES2020"
|
||||
],
|
||||
//"jsx": "react-jsx", // Required by React
|
||||
},
|
||||
|
||||
"typeRoots": ["./src/types","./node_modules/@types"],
|
||||
"include": [
|
||||
"./src/**/*.ts"
|
||||
]
|
||||
}
|
||||
14
version-bump.mjs
Normal file
14
version-bump.mjs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { readFileSync, writeFileSync } from "fs";
|
||||
|
||||
const targetVersion = process.env.npm_package_version;
|
||||
|
||||
// read minAppVersion from manifest.json and bump version to target version
|
||||
let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
|
||||
const { minAppVersion } = manifest;
|
||||
manifest.version = targetVersion;
|
||||
writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
|
||||
|
||||
// update versions.json with target version and minAppVersion from manifest.json
|
||||
let versions = JSON.parse(readFileSync("versions.json", "utf8"));
|
||||
versions[targetVersion] = minAppVersion;
|
||||
writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));
|
||||
3
versions.json
Normal file
3
versions.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"1.0.0": "0.15.0"
|
||||
}
|
||||
Loading…
Reference in a new issue