Compare commits

...

6 commits

Author SHA1 Message Date
Ell 33bfe95ca5 cleanup 2023-08-13 17:25:53 +02:00
Ell 6c4b1022b0 added JSP commands 2023-08-13 17:23:21 +02:00
Ell a5f20a15f2 display notices when using JSP actions 2023-08-13 17:16:55 +02:00
Ell deae38984c moved plugin logic into functions 2023-08-13 16:02:00 +02:00
Ell 85cb03cda4 improved error styling and added index page 2023-08-13 15:52:05 +02:00
Ell fd6184ae10 improve code style media queries 2023-08-13 15:38:12 +02:00
6 changed files with 179 additions and 78 deletions

View file

@ -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=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/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-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="not (prefers-color-scheme: dark)">
<link rel="stylesheet" href="style.css">
<link rel="icon" href="favicon.ico">
</head>
@ -27,10 +27,16 @@
<div class="content">
<div id="main">
<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");
// TODO display nice message when there is no hash
$(window).on("hashchange", display);
display();
@ -40,20 +46,9 @@
hash = hash.substring(1);
$.ajax({
method: "get",
url: `share.php?id=${hash}`,
success: t => {
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;
}
}));
main.html(DOMPurify.sanitize(marked.parse(t)));
},
// TODO display this error more nicely
error: (r, s, e) => main.html(e)
url: hash ? `share.php?id=${hash}` : "index.md",
success: t => main.html(DOMPurify.sanitize(marked.parse(t))),
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>`)
});
}
</script>

3
server/public/index.md Normal file
View 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!

View file

@ -46,6 +46,14 @@ a:hover {
margin: 40px auto 80px;
}
.error {
position: absolute;
text-align: center;
left: 50%;
top: 40%;
transform: translate(-50%, -60%);
}
#footer {
position: absolute;
left: 0;

View file

@ -1,10 +1,11 @@
import {Plugin, requestUrl, TFile} from "obsidian";
import {Notice, Plugin, requestUrl, TFile} from "obsidian";
import {defaultSettings, JSPSettings, SharedItem} from "./settings";
import {JSPSettingsTab} from "./settings-tab";
import {basename, extname} from "path";
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 strip frontmatter before uploading? maybe optionally
settings: JSPSettings;
@ -15,82 +16,84 @@ export default class JustSharePleasePlugin extends Plugin {
this.registerEvent(this.app.workspace.on("file-menu", async (m, f) => {
if (f instanceof TFile) {
let shared = this.settings.shared.find(i => i.path == f.path);
let shared = this.getSharedItem(f);
if (!shared) {
// (newly) share a note
m.addItem(i => {
i.setTitle("Share to JSP");
i.setIcon("share");
i.onClick(async () => {
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();
}
});
i.onClick(async () => this.shareFile(f));
});
} else {
// copy note link
m.addItem(i => {
i.setTitle("Copy JSP link");
i.setIcon("link");
// TODO let people know this happened
i.onClick(() => navigator.clipboard.writeText(`${this.settings.url}#${shared.id}`));
i.onClick(() => this.copyShareLink(shared));
});
// update
m.addItem(i => {
i.setTitle("Update in JSP");
i.setIcon("share");
i.onClick(async () => {
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);
});
i.onClick(() => this.updateFile(shared, f));
});
// delete
m.addItem(i => {
i.setTitle("Delete from JSP");
i.setIcon("trash");
i.onClick(async () => {
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();
}
});
i.onClick(async () => this.deleteFile(shared));
});
}
}
}));
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> {
@ -100,4 +103,85 @@ export default class JustSharePleasePlugin extends Plugin {
async saveSettings(): Promise<void> {
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`);
}
}

View file

@ -1,4 +1,4 @@
{
"accentColor": "",
"theme": "moonstone"
"theme": "obsidian"
}

View file

@ -1,4 +1,15 @@
{
"url": "http://localhost:8080",
"shared": []
"shared": [
{
"id": "7dd626d1",
"password": "6253e1ab4b813dc08d52ee7c82b0990b",
"path": "Second note.md"
},
{
"id": "281d96f9",
"password": "2eb4979a9e853df98f5fcdc2cdc4b770",
"path": "Cool Test Note.md"
}
]
}