mirror of
https://github.com/Ellpeck/ObsidianJustSharePlease.git
synced 2024-06-02 15:33:38 +02:00
Compare commits
6 commits
15c9cdbd16
...
33bfe95ca5
Author | SHA1 | Date | |
---|---|---|---|
Ell | 33bfe95ca5 | ||
Ell | 6c4b1022b0 | ||
Ell | a5f20a15f2 | ||
Ell | deae38984c | ||
Ell | 85cb03cda4 | ||
Ell | fd6184ae10 |
|
@ -17,8 +17,8 @@
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter&display=swap">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=JetBrains+Mono&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=JetBrains+Mono&display=swap">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.8.0/build/styles/github-dark.min.css" media="(prefers-color-scheme:dark)">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.8.0/build/styles/github-dark.min.css" media="(prefers-color-scheme: dark)">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.8.0/build/styles/github.min.css" media="(prefers-color-scheme:light),(prefers-color-scheme:no-preference)">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.8.0/build/styles/github.min.css" media="not (prefers-color-scheme: dark)">
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<link rel="icon" href="favicon.ico">
|
<link rel="icon" href="favicon.ico">
|
||||||
</head>
|
</head>
|
||||||
|
@ -27,10 +27,16 @@
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div id="main">
|
<div id="main">
|
||||||
<script>
|
<script>
|
||||||
|
marked.use(markedKatex());
|
||||||
|
marked.use(markedHighlight.markedHighlight({
|
||||||
|
langPrefix: "hljs language-",
|
||||||
|
highlight: (c, l) => {
|
||||||
|
const language = hljs.getLanguage(l) ? l : "plaintext";
|
||||||
|
return hljs.highlight(c, {language}).value;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
let main = $("#main");
|
let main = $("#main");
|
||||||
|
|
||||||
// TODO display nice message when there is no hash
|
|
||||||
|
|
||||||
$(window).on("hashchange", display);
|
$(window).on("hashchange", display);
|
||||||
display();
|
display();
|
||||||
|
|
||||||
|
@ -40,20 +46,9 @@
|
||||||
hash = hash.substring(1);
|
hash = hash.substring(1);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
method: "get",
|
method: "get",
|
||||||
url: `share.php?id=${hash}`,
|
url: hash ? `share.php?id=${hash}` : "index.md",
|
||||||
success: t => {
|
success: t => main.html(DOMPurify.sanitize(marked.parse(t))),
|
||||||
marked.use(markedKatex());
|
error: (r, s, e) => main.html(`<div class="error"><p>Error loading shared note with id <code>${hash}</code>: ${e}</p><p><a href="#">Home</a></p></div>`)
|
||||||
marked.use(markedHighlight.markedHighlight({
|
|
||||||
langPrefix: "hljs language-",
|
|
||||||
highlight: (c, l) => {
|
|
||||||
const language = hljs.getLanguage(l) ? l : "plaintext";
|
|
||||||
return hljs.highlight(c, {language}).value;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
main.html(DOMPurify.sanitize(marked.parse(t)));
|
|
||||||
},
|
|
||||||
// TODO display this error more nicely
|
|
||||||
error: (r, s, e) => main.html(e)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
3
server/public/index.md
Normal file
3
server/public/index.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Just Share Please
|
||||||
|
|
||||||
|
Just Share Please is an [Obsidian](https://obsidian.md) plugin that allows quickly and easily sharing individual notes online using an anonymized link. It's pretty cool!
|
|
@ -46,6 +46,14 @@ a:hover {
|
||||||
margin: 40px auto 80px;
|
margin: 40px auto 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
left: 50%;
|
||||||
|
top: 40%;
|
||||||
|
transform: translate(-50%, -60%);
|
||||||
|
}
|
||||||
|
|
||||||
#footer {
|
#footer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
198
src/main.ts
198
src/main.ts
|
@ -1,10 +1,11 @@
|
||||||
import {Plugin, requestUrl, TFile} from "obsidian";
|
import {Notice, Plugin, requestUrl, TFile} from "obsidian";
|
||||||
import {defaultSettings, JSPSettings, SharedItem} from "./settings";
|
import {defaultSettings, JSPSettings, SharedItem} from "./settings";
|
||||||
import {JSPSettingsTab} from "./settings-tab";
|
import {JSPSettingsTab} from "./settings-tab";
|
||||||
|
import {basename, extname} from "path";
|
||||||
|
|
||||||
export default class JustSharePleasePlugin extends Plugin {
|
export default class JustSharePleasePlugin extends Plugin {
|
||||||
|
|
||||||
// TODO allow deleting uploads whose local files have been deleted (through command?)
|
// TODO panel that displays all shares, including ones for removed files, and allows unsharing or updating them
|
||||||
// TODO add a setting for auto-refreshing uploads when saving
|
// TODO add a setting for auto-refreshing uploads when saving
|
||||||
// TODO strip frontmatter before uploading? maybe optionally
|
// TODO strip frontmatter before uploading? maybe optionally
|
||||||
settings: JSPSettings;
|
settings: JSPSettings;
|
||||||
|
@ -15,82 +16,84 @@ export default class JustSharePleasePlugin extends Plugin {
|
||||||
|
|
||||||
this.registerEvent(this.app.workspace.on("file-menu", async (m, f) => {
|
this.registerEvent(this.app.workspace.on("file-menu", async (m, f) => {
|
||||||
if (f instanceof TFile) {
|
if (f instanceof TFile) {
|
||||||
let shared = this.settings.shared.find(i => i.path == f.path);
|
let shared = this.getSharedItem(f);
|
||||||
if (!shared) {
|
if (!shared) {
|
||||||
// (newly) share a note
|
|
||||||
m.addItem(i => {
|
m.addItem(i => {
|
||||||
i.setTitle("Share to JSP");
|
i.setTitle("Share to JSP");
|
||||||
i.setIcon("share");
|
i.setIcon("share");
|
||||||
i.onClick(async () => {
|
i.onClick(async () => this.shareFile(f));
|
||||||
let response = await requestUrl({
|
|
||||||
url: `${this.settings.url}/share.php`,
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({content: await this.app.vault.cachedRead(f)}),
|
|
||||||
throw: false
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO display message about status success/fail and copy URL to clipboard
|
|
||||||
console.log(response.status + " " + response.text);
|
|
||||||
|
|
||||||
if (response.status == 200) {
|
|
||||||
shared = response.json;
|
|
||||||
shared.path = f.path;
|
|
||||||
this.settings.shared.push(shared);
|
|
||||||
await this.saveSettings();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// copy note link
|
|
||||||
m.addItem(i => {
|
m.addItem(i => {
|
||||||
i.setTitle("Copy JSP link");
|
i.setTitle("Copy JSP link");
|
||||||
i.setIcon("link");
|
i.setIcon("link");
|
||||||
// TODO let people know this happened
|
i.onClick(() => this.copyShareLink(shared));
|
||||||
i.onClick(() => navigator.clipboard.writeText(`${this.settings.url}#${shared.id}`));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// update
|
|
||||||
m.addItem(i => {
|
m.addItem(i => {
|
||||||
i.setTitle("Update in JSP");
|
i.setTitle("Update in JSP");
|
||||||
i.setIcon("share");
|
i.setIcon("share");
|
||||||
i.onClick(async () => {
|
i.onClick(() => this.updateFile(shared, f));
|
||||||
let response = await requestUrl({
|
|
||||||
url: `${this.settings.url}/share.php?id=${shared.id}`,
|
|
||||||
method: "PATCH",
|
|
||||||
headers: {"Password": shared.password},
|
|
||||||
body: JSON.stringify({content: await this.app.vault.cachedRead(f)}),
|
|
||||||
throw: false
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO display message about status success/fail after updating
|
|
||||||
console.log(response.status + " " + response.text);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// delete
|
|
||||||
m.addItem(i => {
|
m.addItem(i => {
|
||||||
i.setTitle("Delete from JSP");
|
i.setTitle("Delete from JSP");
|
||||||
i.setIcon("trash");
|
i.setIcon("trash");
|
||||||
i.onClick(async () => {
|
i.onClick(async () => this.deleteFile(shared));
|
||||||
let response = await requestUrl({
|
|
||||||
url: `${this.settings.url}/share.php?id=${shared.id}`,
|
|
||||||
method: "DELETE",
|
|
||||||
headers: {"Password": shared.password},
|
|
||||||
throw: false
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO display message about status success/fail when deleting
|
|
||||||
console.log(response.status);
|
|
||||||
|
|
||||||
if (response.status == 200) {
|
|
||||||
this.settings.shared.remove(shared);
|
|
||||||
await this.saveSettings();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this.addCommand({
|
||||||
|
id: "share",
|
||||||
|
name: "Share current file to JSP",
|
||||||
|
editorCheckCallback: (checking, _, ctx) => {
|
||||||
|
if (!this.getSharedItem(ctx.file)) {
|
||||||
|
if (!checking)
|
||||||
|
this.shareFile(ctx.file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.addCommand({
|
||||||
|
id: "copy",
|
||||||
|
name: "Copy current file's JSP link",
|
||||||
|
editorCheckCallback: (checking, _, ctx) => {
|
||||||
|
let shared = this.getSharedItem(ctx.file);
|
||||||
|
if (shared) {
|
||||||
|
if (!checking)
|
||||||
|
this.copyShareLink(shared);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.addCommand({
|
||||||
|
id: "update",
|
||||||
|
name: "Update current file in JSP",
|
||||||
|
editorCheckCallback: (checking, _, ctx) => {
|
||||||
|
let shared = this.getSharedItem(ctx.file);
|
||||||
|
if (shared) {
|
||||||
|
if (!checking)
|
||||||
|
this.updateFile(shared, ctx.file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.addCommand({
|
||||||
|
id: "delete",
|
||||||
|
name: "Delete current file from JSP",
|
||||||
|
editorCheckCallback: (checking, _, ctx) => {
|
||||||
|
let shared = this.getSharedItem(ctx.file);
|
||||||
|
if (shared) {
|
||||||
|
if (!checking)
|
||||||
|
this.deleteFile(shared);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadSettings(): Promise<void> {
|
async loadSettings(): Promise<void> {
|
||||||
|
@ -100,4 +103,85 @@ export default class JustSharePleasePlugin extends Plugin {
|
||||||
async saveSettings(): Promise<void> {
|
async saveSettings(): Promise<void> {
|
||||||
await this.saveData(this.settings);
|
await this.saveData(this.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSharedItem(file: TFile): SharedItem {
|
||||||
|
return this.settings.shared.find(f => f.path == file.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
async shareFile(file: TFile): Promise<SharedItem> {
|
||||||
|
try {
|
||||||
|
let response = await requestUrl({
|
||||||
|
url: `${this.settings.url}/share.php`,
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({content: await this.app.vault.cachedRead(file)})
|
||||||
|
});
|
||||||
|
let shared = response.json as SharedItem;
|
||||||
|
shared.path = file.path;
|
||||||
|
|
||||||
|
await this.copyShareLink(shared, false);
|
||||||
|
new Notice(`Successfully shared ${file.basename} and copied link to clipboard`);
|
||||||
|
|
||||||
|
this.settings.shared.push(shared);
|
||||||
|
await this.saveSettings();
|
||||||
|
|
||||||
|
return shared;
|
||||||
|
} catch (e) {
|
||||||
|
new Notice(createFragment(f => {
|
||||||
|
f.createSpan({text: `There was an error sharing ${file.basename}: `});
|
||||||
|
f.createEl("code", {text: e});
|
||||||
|
}), 10000);
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateFile(item: SharedItem, file: TFile, notice = true): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
await requestUrl({
|
||||||
|
url: `${this.settings.url}/share.php?id=${item.id}`,
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {"Password": item.password},
|
||||||
|
body: JSON.stringify({content: await this.app.vault.cachedRead(file)})
|
||||||
|
});
|
||||||
|
new Notice(`Successfully updated ${file.basename} on JSP`);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
if (notice) {
|
||||||
|
new Notice(createFragment(f => {
|
||||||
|
f.createSpan({text: `There was an error updating ${file.basename}: `});
|
||||||
|
f.createEl("code", {text: e});
|
||||||
|
}), 10000);
|
||||||
|
}
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteFile(item: SharedItem): Promise<boolean> {
|
||||||
|
let name = basename(item.path, extname(item.path));
|
||||||
|
try {
|
||||||
|
await requestUrl({
|
||||||
|
url: `${this.settings.url}/share.php?id=${item.id}`,
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {"Password": item.password}
|
||||||
|
});
|
||||||
|
new Notice(`Successfully deleted ${name} from JSP`);
|
||||||
|
|
||||||
|
this.settings.shared.remove(item);
|
||||||
|
await this.saveSettings();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
new Notice(createFragment(f => {
|
||||||
|
f.createSpan({text: `There was an error deleting ${name}: `});
|
||||||
|
f.createEl("code", {text: e});
|
||||||
|
}), 10000);
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async copyShareLink(item: SharedItem, notice = true): Promise<void> {
|
||||||
|
await navigator.clipboard.writeText(`${this.settings.url}#${item.id}`);
|
||||||
|
if (notice)
|
||||||
|
new Notice(`Copied link to ${basename(item.path, extname(item.path))} to clipboard`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
2
test-vault/.obsidian/appearance.json
vendored
2
test-vault/.obsidian/appearance.json
vendored
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"accentColor": "",
|
"accentColor": "",
|
||||||
"theme": "moonstone"
|
"theme": "obsidian"
|
||||||
}
|
}
|
|
@ -1,4 +1,15 @@
|
||||||
{
|
{
|
||||||
"url": "http://localhost:8080",
|
"url": "http://localhost:8080",
|
||||||
"shared": []
|
"shared": [
|
||||||
|
{
|
||||||
|
"id": "7dd626d1",
|
||||||
|
"password": "6253e1ab4b813dc08d52ee7c82b0990b",
|
||||||
|
"path": "Second note.md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "281d96f9",
|
||||||
|
"password": "2eb4979a9e853df98f5fcdc2cdc4b770",
|
||||||
|
"path": "Cool Test Note.md"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
Loading…
Reference in a new issue