Initial upload

This commit is contained in:
Otavio Cordeiro 2022-09-21 15:41:36 +02:00
parent 2f542a691b
commit 5b23027983
19 changed files with 3522 additions and 0 deletions

10
.editorconfig Normal file
View File

@ -0,0 +1,10 @@
# top-most EditorConfig file
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = spaces
indent_size = 4
tab_width = 4

2
.eslintignore Normal file
View File

@ -0,0 +1,2 @@
npm node_modules
build

23
.eslintrc Normal file
View File

@ -0,0 +1,23 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"env": { "node": true },
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"parserOptions": {
"sourceType": "module"
},
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
"@typescript-eslint/ban-ts-comment": "off",
"no-prototype-builtins": "off",
"@typescript-eslint/no-empty-function": "off"
}
}

22
.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
# vscode
.vscode
# Intellij
*.iml
.idea
# npm
node_modules
# Don't include the compiled main.js file in the repo.
# They should be uploaded to GitHub releases instead.
main.js
# Exclude sourcemaps
*.map
# obsidian
data.json
# Exclude macOS Finder (System Explorer) View States
.DS_Store

1
.npmrc Normal file
View File

@ -0,0 +1 @@
tag-version-prefix=""

42
esbuild.config.mjs Normal file
View File

@ -0,0 +1,42 @@
import esbuild from "esbuild";
import process from "process";
import builtins from 'builtin-modules'
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
*/
`;
const prod = (process.argv[2] === 'production');
esbuild.build({
banner: {
js: banner,
},
entryPoints: ['source/MicroPlugin.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',
watch: !prod,
target: 'es2018',
logLevel: "info",
sourcemap: prod ? false : 'inline',
treeShaking: true,
outfile: 'main.js',
}).catch(() => process.exit(1));

10
manifest.json Normal file
View File

@ -0,0 +1,10 @@
{
"id": "microblog-publish-plugin",
"name": "Micro.blog Publish",
"version": "1.0.0",
"minAppVersion": "0.15.0",
"description": "Publish Note to Micro.blog",
"author": "Otavio Cordeiro",
"authorUrl": "https://otavio.cc",
"isDesktopOnly": false
}

3145
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

24
package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "microblog-publish-plugin",
"version": "1.0.0",
"description": "Publish Note to Micro.blog",
"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.14.47",
"obsidian": "latest",
"tslib": "2.4.0",
"typescript": "4.7.4"
}
}

View File

@ -0,0 +1,21 @@
import { App, Modal } from 'obsidian'
export class ConfirmationModal extends Modal {
constructor(app: App) {
super(app)
}
onOpen() {
const {contentEl} = this
contentEl.createEl('h2', {text: 'Published!'})
contentEl.createEl('a', {text: 'Go to Posts', href: 'https://micro.blog/account/posts/'})
}
onClose() {
const {contentEl} = this
contentEl.empty()
}
}

42
source/MicroPlugin.ts Normal file
View File

@ -0,0 +1,42 @@
import { Editor, MarkdownView, Plugin } from 'obsidian'
import { ConfirmationModal } from 'source/ConfirmationModal'
import { NetworkClient } from 'source/NetworkClient'
import { makePublishRequest, PublishResponse } from 'source/NetworkRequest.Publish'
import { StoredSettings, defaultSettings } from 'source/StoredSettings'
import { MicroPluginSettingsTab } from 'source/MicroPluginSettingsTab'
export default class MicroPlugin extends Plugin {
settings: StoredSettings
networkClient: NetworkClient
async onload() {
await this.loadSettings()
await this.loadNetworkClient()
this.addCommand({
id: 'microblog-publish-command',
name: 'Post to Micro.blog',
editorCallback: (editor: Editor, view: MarkdownView) => {
const request = makePublishRequest(editor.getValue(), this.settings.postVisibility)
this.networkClient.run<PublishResponse>(request)
new ConfirmationModal(this.app).open();
}
})
this.addSettingTab(new MicroPluginSettingsTab(this.app, this))
}
onunload() {}
async loadSettings() {
this.settings = Object.assign({}, defaultSettings, await this.loadData())
}
async loadNetworkClient() {
this.networkClient = new NetworkClient(this.settings)
}
async saveSettings() {
await this.saveData(this.settings)
}
}

View File

@ -0,0 +1,56 @@
import { App, PluginSettingTab, Setting } from 'obsidian'
import MicroPlugin from 'source/MicroPlugin'
export class MicroPluginSettingsTab extends PluginSettingTab {
plugin: MicroPlugin
constructor(app: App, plugin: MicroPlugin) {
super(app, plugin)
this.plugin = plugin
}
display(): void {
const {containerEl} = this
containerEl.empty()
containerEl.createEl('h2', {text: 'Micro.blog Publish'})
new Setting(containerEl)
.setName('App Token')
.setDesc('Visit Micro.blog\'s Account page to generate one')
.addText(text => text
.setPlaceholder('Enter app token')
.setValue(this.plugin.settings.appToken)
.onChange(async (value) => {
console.log('App Token: ' + value)
this.plugin.settings.appToken = value
await this.plugin.saveSettings()
}))
new Setting(containerEl)
.setName('Tags')
.setDesc('Default list of tags for new posts')
.addText(text => text
.setPlaceholder('tag1, tag2, tag3')
.setValue(this.plugin.settings.defaultTags)
.onChange(async (value) => {
console.log('Tags: ' + value)
this.plugin.settings.defaultTags = value
await this.plugin.saveSettings()
}))
new Setting(containerEl)
.setName('Post visibility')
.setDesc('Default visibility for new posts')
.addDropdown(dropDown => dropDown
.addOption('draft', 'Draft')
.addOption('published', 'Public')
.setValue(this.plugin.settings.postVisibility)
.onChange(async (value) => {
console.log('Post Visibility: '+ value)
this.plugin.settings.postVisibility = value
await this.plugin.saveSettings()
}))
}
}

43
source/NetworkClient.ts Normal file
View File

@ -0,0 +1,43 @@
import { StoredSettings } from 'source/StoredSettings'
import { NetworkRequest } from 'source/NetworkRequest'
export class NetworkClient {
settings: StoredSettings
constructor(settings: StoredSettings) {
this.settings = settings
}
async run<T>(request: NetworkRequest): Promise<string | T> {
try {
const encodedParameters = new URLSearchParams(request.parameters)
const url = `https://micro.blog${request.path}?${encodedParameters}`
const response = await fetch(url, {
method: request.method,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${this.settings.appToken}`
}
})
if (!response.ok) {
throw new Error(`Error! status: ${response.status}`)
}
const result = (await response.json()) as T
console.log('result is: ', JSON.stringify(result, null, 4))
return result
} catch (error) {
if (error instanceof Error) {
console.log('error message: ', error.message)
return error.message
} else {
console.log('unexpected error: ', error)
return 'An unexpected error occurred'
}
}
}
}

View File

@ -0,0 +1,18 @@
import { NetworkRequest } from 'source/NetworkRequest'
export function makePublishRequest(content: string, visiblity: string): NetworkRequest {
return new NetworkRequest(
"/micropub",
{
"h": "entry",
"content": content,
"post-status": visiblity
},
"POST"
)
}
export type PublishResponse = {
url: string
preview: string
}

13
source/NetworkRequest.ts Normal file
View File

@ -0,0 +1,13 @@
export class NetworkRequest {
path: string
parameters: Record<string, string>
method: string
body?: string
constructor(path: string, parameters: Record<string, string>, method: string, body?: string) {
this.path = path
this.parameters = parameters
this.body = body
this.method = method
}
}

11
source/StoredSettings.ts Normal file
View File

@ -0,0 +1,11 @@
export interface StoredSettings {
appToken: string
defaultTags: string
postVisibility: string
}
export const defaultSettings: StoredSettings = {
appToken: '',
defaultTags: '',
postVisibility: 'draft'
}

24
tsconfig.json Normal file
View File

@ -0,0 +1,24 @@
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"strictNullChecks": true,
"lib": [
"DOM",
"ES5",
"ES6",
"ES7"
]
},
"include": [
"**/*.ts"
]
}

12
version-bump.mjs Normal file
View File

@ -0,0 +1,12 @@
import { readFileSync, writeFileSync } from "fs";
const targetVersion = process.env.npm_package_version;
let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
const { minAppVersion } = manifest;
manifest.version = targetVersion;
writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
let versions = JSON.parse(readFileSync("versions.json", "utf8"));
versions[targetVersion] = minAppVersion;
writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));

3
versions.json Normal file
View File

@ -0,0 +1,3 @@
{
"1.0.0": "0.15.0"
}