diff --git a/.gitignore b/.gitignore index e09a007..e2cf968 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # vscode -.vscode +.vscode # Intellij *.iml @@ -20,3 +20,4 @@ data.json # Exclude macOS Finder (System Explorer) View States .DS_Store +dist diff --git a/README.md b/README.md index 578e9f8..4854c76 100644 --- a/README.md +++ b/README.md @@ -1,101 +1,37 @@ -# Obsidian Sample Plugin (Yomaru) +# Obsidian Publish Url -- ✅ husky -- ✅ bun -- ✅ bun github release workflow -- ✅ extended obsidian typescript api +This plugin helps you to copy and open your publish url quickly. -This is a sample plugin for Obsidian (https://obsidian.md). +Demo: -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. +## Features -**Note:** The Obsidian API is still in early alpha and is subject to change at any time! +1. simple set up, just require your domain name +2. respect the permalink +3. copy/open the publish url of current view +4. copy theog.io link -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. +## How to install? -## First time developing plugins? +### Through obsidian community plugin -Quick starting guide for new plugin devs: +waiting for approval: -- 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. +### Through BRAT -## Releasing new releases +1. install the BRAT plugin +2. go to the plugin option, add beta plugin, copy and paste the link of this repo. +3. the plugin will automatically appear in the list of installed community plugins, enabled this plugin -- 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. +### Manual installation -> 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` +1. cd to .obsidian/plugins +2. git clone this repo +3. cd obsidian-3d-graph && bun install && bun run build +4. there you go 🎉 -## Adding your plugin to the community plugin list +## Say thank you -- 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. +If you are enjoying this plugin then please support my work and enthusiasm by sponsoring me on Github or buying me a coffee on . -## 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 +Buy Me A Coffee [![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/hananoshikayomaru) diff --git a/manifest.json b/manifest.json index b462b5a..86c4348 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "publish-url", "name": "Publish url", - "version": "1.0.1", + "version": "1.0.2", "minAppVersion": "0.15.0", "description": "Obsidian Publish url to the clipboard", "author": "Hananoshika Yomaru", diff --git a/package.json b/package.json index 34dfe8d..cd4fc61 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-publish-url", - "version": "1.0.1", + "version": "1.0.2", "description": "Get the publish url", "main": "main.js", "scripts": { diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 1bfa186..f46f6eb 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -1,3 +1,5 @@ +import { NoticeManager } from "@/NoticeManager"; +import type { Notice, Plugin as _Plugin } from "obsidian"; export interface ISettingManager { /** * save settings @@ -23,3 +25,12 @@ export interface ISettingManager { */ loadSettings(): Promise; } + +export interface Plugin extends _Plugin { + settingManager: ISettingManager; + noticeManager: NoticeManager; + createNotice: ( + message: string | DocumentFragment, + duration?: number | undefined + ) => Notice; +} diff --git a/src/NoticeManager.ts b/src/NoticeManager.ts new file mode 100644 index 0000000..b4979fc --- /dev/null +++ b/src/NoticeManager.ts @@ -0,0 +1,19 @@ +import { Notice, Plugin } from "obsidian"; + +export class NoticeManager { + plugin: Plugin; + constructor(plugin: Plugin) { + this.plugin = plugin; + } + + createNotice = ( + message: string | DocumentFragment, + duration?: number | undefined + ): Notice => { + const notice = new Notice( + `${this.plugin.manifest.name}: ${message}`, + duration + ); + return notice; + }; +} diff --git a/src/SettingManager.ts b/src/SettingManager.ts index fdf2386..fa2d2aa 100644 --- a/src/SettingManager.ts +++ b/src/SettingManager.ts @@ -1,9 +1,8 @@ import { ISettingManager } from "@/Interfaces"; import { AsyncQueue } from "@/util/AsyncQueue"; import { SettingSchema } from "@/SettingsSchemas"; -import { createNotice } from "@/util/createNotice"; import { State } from "@/util/State"; -import { Plugin } from "obsidian"; +import { Plugin } from "@/Interfaces"; import { z } from "zod"; // the setting of slider @@ -14,38 +13,8 @@ export const nodeSize = { default: 3, }; -// export type BaseFilterSettings = Prettify< -// z.TypeOf -// >; - -// export type LocalFilterSetting = Prettify< -// z.TypeOf -// >; - -// export type GroupSettings = Prettify>; - -// export type BaseDisplaySettings = Prettify< -// z.TypeOf -// >; - -// export type LocalDisplaySettings = Prettify< -// z.TypeOf -// >; - -// export type GlobalGraphSettings = Prettify< -// z.TypeOf -// >; - -// export type LocalGraphSettings = Prettify< -// z.TypeOf -// >; - -// export type SavedSetting = Prettify>; - export type Setting = Prettify>; -// export type GraphSetting = Exclude; - const corruptedMessage = "The setting is corrupted. You will not be able to save the setting. Please backup your data.json, remove it and reload the plugin. Then migrate your old setting back."; @@ -108,7 +77,7 @@ export class MySettingManager implements ISettingManager { const result = SettingSchema.safeParse(loadedData); // the data schema is wrong or the data is corrupted, then we need to initialize the data if (!result.success) { - createNotice(corruptedMessage); + this.plugin.createNotice(corruptedMessage); console.warn("parsed loaded data failed", result.error.flatten()); this.isLoaded = false; this.setting.value = DEFAULT_SETTING; @@ -130,7 +99,7 @@ export class MySettingManager implements ISettingManager { const result = SettingSchema.safeParse(this.setting.value); if (!result.success) { - createNotice(corruptedMessage); + this.plugin.createNotice(corruptedMessage); console.warn( "parsed loaded data failed", result.error.flatten() @@ -146,5 +115,6 @@ export class MySettingManager implements ISettingManager { } export const DEFAULT_SETTING: Setting = { - test: "test", + publishDomain: "", + theogTemplate: 3, }; diff --git a/src/SettingsSchemas.ts b/src/SettingsSchemas.ts index 09637ae..828c55d 100644 --- a/src/SettingsSchemas.ts +++ b/src/SettingsSchemas.ts @@ -1,5 +1,6 @@ import { z } from "zod"; export const SettingSchema = z.object({ - test: z.string().default("test"), + publishDomain: z.string().default(""), + theogTemplate: z.number().default(3), }); diff --git a/src/dist/SettingManager.js b/src/dist/SettingManager.js deleted file mode 100644 index ca28818..0000000 --- a/src/dist/SettingManager.js +++ /dev/null @@ -1,152 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -exports.__esModule = true; -exports.DEFAULT_SETTING = exports.MySettingManager = exports.nodeSize = void 0; -var AsyncQueue_1 = require("@/util/AsyncQueue"); -var SettingsSchemas_1 = require("@/SettingsSchemas"); -var createNotice_1 = require("@/util/createNotice"); -var State_1 = require("@/util/State"); -// the setting of slider -exports.nodeSize = { - min: 1, - max: 10, - step: 0.1, - "default": 3 -}; -// export type GraphSetting = Exclude; -var corruptedMessage = "The setting is corrupted. You will not be able to save the setting. Please backup your data.json, remove it and reload the plugin. Then migrate your old setting back."; -/** - * @remarks the setting will not keep the temporary setting. It will only keep the saved settings. - */ -var MySettingManager = /** @class */ (function () { - /** - * @remarks don't forget to call `loadSettings` after creating this class - */ - function MySettingManager(plugin) { - this.setting = new State_1.State(exports.DEFAULT_SETTING); - this.asyncQueue = new AsyncQueue_1.AsyncQueue(); - /** - * whether the setting is loaded successfully - */ - this.isLoaded = false; - this.plugin = plugin; - } - /** - * this function will update the setting and save it to the json file. But it is still a sync function. - * You should always use this function to update setting - */ - MySettingManager.prototype.updateSettings = function (updateFunc) { - // update the setting first - updateFunc(this.setting); - // save the setting to json - this.asyncQueue.push(this.saveSettings.bind(this)); - // return the updated setting - return this.setting.value; - }; - MySettingManager.prototype.getSettings = function () { - return this.setting.value; - }; - /** - * load the settings from the json file - */ - MySettingManager.prototype.loadSettings = function () { - return __awaiter(this, void 0, void 0, function () { - var loadedData, result; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.plugin.loadData()]; - case 1: - loadedData = (_a.sent()); - console.log("loaded: ", loadedData); - if (!!loadedData) return [3 /*break*/, 3]; - this.setting.value = exports.DEFAULT_SETTING; - this.isLoaded = true; - return [4 /*yield*/, this.saveSettings()]; - case 2: - _a.sent(); - return [2 /*return*/, this.setting.value]; - case 3: - result = SettingsSchemas_1.SettingSchema.safeParse(loadedData); - // the data schema is wrong or the data is corrupted, then we need to initialize the data - if (!result.success) { - createNotice_1.createNotice(corruptedMessage); - console.warn("parsed loaded data failed", result.error.flatten()); - this.isLoaded = false; - this.setting.value = exports.DEFAULT_SETTING; - return [2 /*return*/, this.setting.value]; - } - console.log("parsed loaded data successfully"); - this.setting.value = result.data; - return [2 /*return*/, this.setting.value]; - } - }); - }); - }; - /** - * save the settings to the json file - */ - MySettingManager.prototype.saveSettings = function () { - return __awaiter(this, void 0, void 0, function () { - var result; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (!this.isLoaded) { - result = SettingsSchemas_1.SettingSchema.safeParse(this.setting.value); - if (!result.success) { - createNotice_1.createNotice(corruptedMessage); - console.warn("parsed loaded data failed", result.error.flatten()); - return [2 /*return*/]; - } - this.isLoaded = true; - console.log("parsed loaded data successfully"); - } - return [4 /*yield*/, this.plugin.saveData(this.setting.value)]; - case 1: - _a.sent(); - return [2 /*return*/]; - } - }); - }); - }; - return MySettingManager; -}()); -exports.MySettingManager = MySettingManager; -exports.DEFAULT_SETTING = { - test: "test" -}; diff --git a/src/main.ts b/src/main.ts index f279401..2ef761d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,107 +1,136 @@ import { App, - Editor, EventRef, - MarkdownView, - Modal, Notice, Plugin, PluginSettingTab, Setting, + TFile, } from "obsidian"; import "@total-typescript/ts-reset"; import "@total-typescript/ts-reset/dom"; -import { MySettingManager } from "@/SettingManager"; - -// Remember to rename these classes and interfaces! +import { DEFAULT_SETTING, MySettingManager } from "@/SettingManager"; + +import { NoticeManager } from "@/NoticeManager"; + +const getPublishUrl = ( + path: string, + publishDomain: string, + permalink?: string +) => { + if (permalink) return `https://${publishDomain}/${permalink}`; + // Remove the .md extension from the path + const pathWithoutExtension = path.replace(/\.md$/, ""); + + // Encode the path using encodeURIComponent to escape special characters, + // then replace encoded spaces with a plus sign + const encodedPath = encodeURIComponent(pathWithoutExtension).replace( + /%20/g, + "+" + ); + + return `https://${publishDomain}/${encodedPath}`; +}; -interface MyPluginSettings { - mySetting: string; +export function isMarkdownFile(file: TFile) { + return file && file.extension === "md"; } -const DEFAULT_SETTINGS: MyPluginSettings = { - mySetting: "default", -}; - -export default class MyPlugin extends Plugin { +export default class PublishUrlSetting extends Plugin { settingManager: MySettingManager; + noticeManager: NoticeManager; private eventRefs: EventRef[] = []; async onload() { + const that = this; // initialize the setting manager this.settingManager = new MySettingManager(this); + this.noticeManager = new NoticeManager(this); // load the setting using setting manager await this.settingManager.loadSettings(); - // This creates an icon in the left ribbon. - const ribbonIconEl = this.addRibbonIcon( - "dice", - "Sample Plugin", - (evt: MouseEvent) => { - // Called when the user clicks the icon. - new Notice("This is a notice!"); - } - ); - // Perform additional things with the ribbon - ribbonIconEl.addClass("my-plugin-ribbon-class"); - - // This adds a status bar item to the bottom of the app. Does not work on mobile apps. - const statusBarItemEl = this.addStatusBarItem(); - statusBarItemEl.setText("Status Bar Text"); - - // This adds a simple command that can be triggered anywhere + // This adds a complex command that can check whether the current state of the app allows execution of the command this.addCommand({ - id: "open-sample-modal-simple", - name: "Open sample modal (simple)", - callback: () => { - new SampleModal(this.app).open(); + id: "copy-publish-url", + name: "Copy publish url", + editorCheckCallback(checking, editor, ctx) { + if (!ctx.file) return; + if (checking) { + return isMarkdownFile(ctx.file); + } + const publishUrl = that.copyPublishUrl(ctx.file); + // copy this to clipboard + navigator.clipboard.writeText(publishUrl); + that.createNotice("Copied publish url to clipboard"); }, }); - // This adds an editor command that can perform some operation on the current editor instance + this.addCommand({ - id: "sample-editor-command", - name: "Sample editor command", - editorCallback: (editor: Editor, view: MarkdownView) => { - console.log(editor.getSelection()); - editor.replaceSelection("Sample Editor Command"); + id: "copy-theog-url", + name: "Copy theog url", + editorCheckCallback(checking, editor, ctx) { + if (!ctx.file) return; + if (checking) { + return isMarkdownFile(ctx.file); + } + // get the publish url + const publishUrl = that.copyPublishUrl(ctx.file); + const theogUrl = that.copyTheogUrl( + publishUrl, + that.settingManager.getSettings().theogTemplate + ); + // copy this to clipboard + navigator.clipboard.writeText(theogUrl); + that.createNotice("Copied theog url to clipboard"); }, }); - // This adds a complex command that can check whether the current state of the app allows execution of the command + this.addCommand({ - id: "open-sample-modal-complex", - name: "Open sample modal (complex)", - checkCallback: (checking: boolean) => { - // Conditions to check - const markdownView = - this.app.workspace.getActiveViewOfType(MarkdownView); - if (markdownView) { - // If checking is true, we're simply "checking" if the command can be run. - // If checking is false, then we want to actually perform the operation. - if (!checking) { - new SampleModal(this.app).open(); - } - - // This command will only show up in Command Palette when the check function returns true - return true; + id: "open-in-publish", + name: "Open in publish", + editorCheckCallback(checking, editor, ctx) { + if (!ctx.file) return; + if (checking) { + return isMarkdownFile(ctx.file); } + // get the publish url + const publishUrl = that.copyPublishUrl(ctx.file); + // open in default browser + window.open(publishUrl, "_blank"); }, }); // This adds a settings tab so the user can configure various aspects of the plugin - this.addSettingTab(new SampleSettingTab(this.app, this)); + this.addSettingTab(new SettingTab(this.app, this)); + } - // If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin) - // Using this function will automatically remove the event listener when this plugin is disabled. - this.registerDomEvent(document, "click", (evt: MouseEvent) => { - console.log("click", evt); + copyPublishUrl = (file: TFile) => { + const path = file.path; + // get the frontmatter of the current file + const frontmatter = + this.app.metadataCache.getFileCache(file)?.frontmatter; + const publishDomain = this.settingManager.getSettings().publishDomain; + const permalink = frontmatter?.permalink; + const publishUrl = getPublishUrl(path, publishDomain, permalink); + return publishUrl; + }; + + copyTheogUrl = (url: string, template: number) => { + // Construct the new URL with query parameters + const theogBaseUrl = "https://theog.io/goto"; + const queryParams = new URLSearchParams({ + url: url, + template: template.toString(), }); - // When registering intervals, this function will automatically clear the interval when the plugin is disabled. - this.registerInterval( - window.setInterval(() => console.log("setInterval"), 5 * 60 * 1000) - ); - } + return `${theogBaseUrl}?${queryParams.toString()}`; + }; + + createNotice = ( + message: string | DocumentFragment, + duration?: number | undefined + ): Notice => this.noticeManager.createNotice(message, duration); onunload() { super.onunload(); @@ -112,26 +141,10 @@ export default class MyPlugin extends Plugin { } } -class SampleModal extends Modal { - constructor(app: App) { - super(app); - } +class SettingTab extends PluginSettingTab { + plugin: PublishUrlSetting; - onOpen() { - const { contentEl } = this; - contentEl.setText("Woah!"); - } - - onClose() { - const { contentEl } = this; - contentEl.empty(); - } -} - -class SampleSettingTab extends PluginSettingTab { - plugin: MyPlugin; - - constructor(app: App, plugin: MyPlugin) { + constructor(app: App, plugin: PublishUrlSetting) { super(app, plugin); this.plugin = plugin; } @@ -141,18 +154,31 @@ class SampleSettingTab extends PluginSettingTab { containerEl.empty(); - new Setting(containerEl) - .setName("Setting #1") - .setDesc("It's a secret") - .addText((text) => - text - .setPlaceholder("Enter your secret") - .setValue(this.plugin.settingManager.getSettings().test) - .onChange(async (value) => { - this.plugin.settingManager.updateSettings((setting) => { - setting.value.test = value; - }); - }) - ); + new Setting(containerEl).setName("Publish domain").addText((text) => + text + .setPlaceholder("Your publish domain") + .setValue( + this.plugin.settingManager.getSettings().publishDomain + ) + .onChange(async (value) => { + this.plugin.settingManager.updateSettings((setting) => { + setting.value.publishDomain = value; + }); + }) + ); + + new Setting(containerEl).setName("Template Number").addText((text) => { + text.setPlaceholder(String(DEFAULT_SETTING.theogTemplate)) + .setValue( + String( + this.plugin.settingManager.getSettings().theogTemplate + ) + ) + .onChange(async (value) => { + this.plugin.settingManager.updateSettings((setting) => { + setting.value.theogTemplate = Number(value); + }); + }); + }); } } diff --git a/src/util/createNotice.ts b/src/util/createNotice.ts deleted file mode 100644 index ee97fe1..0000000 --- a/src/util/createNotice.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Notice } from "obsidian"; - -export const createNotice = ( - message: string | DocumentFragment, - duration?: number | undefined -): Notice => new Notice(`3D graph: ${message}`, duration); diff --git a/versions.json b/versions.json index a6d5a03..03d60fe 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,5 @@ { "1.0.0": "0.15.0", - "1.0.1": "0.15.0" + "1.0.1": "0.15.0", + "1.0.2": "0.15.0" } \ No newline at end of file