Compare commits

..

38 Commits
v9 ... v0.0.4

Author SHA1 Message Date
Zsolt Viczian
a711987163 v0.0.4 mvp 2021-04-20 20:41:07 +02:00
Zsolt Viczian
38ec3634c6 updated SVG 2021-04-20 14:52:42 +02:00
Zsolt Viczian
adc9c17d28 removed old view.ts file 2021-04-20 14:02:19 +02:00
Zsolt Viczian
12b64710a2 Merge branch 'master' of https://github.com/zsviczian/obsidian-excalidraw-plugin 2021-04-20 13:58:25 +02:00
Zsolt Viczian
f2012de41c MVP 2021-04-20 13:57:53 +02:00
zsviczian
f873ac3164 Update README.md 2021-04-20 13:56:02 +02:00
zsviczian
ab568abf5a Update README.md 2021-04-20 13:15:02 +02:00
zsviczian
274b1939f8 Update README.md 2021-04-20 12:03:46 +02:00
Zsolt Viczian
fea67c100b pre mvp alpha 0.0.2 2021-04-19 19:36:41 +02:00
Zsolt Viczian
68404144be Merge branch 'master' of https://github.com/zsviczian/obsidian-excalidraw-plugin 2021-04-19 17:35:54 +02:00
Zsolt Viczian
0ddac23f4c MVP alpha 0.1 - before rework to use TextFileView 2021-04-19 17:35:36 +02:00
zsviczian
b601b6b272 Update issue templates 2021-04-19 12:07:44 +02:00
Zsolt Viczian
9d6c80cbea plugin-replace preventAssignment: true 2021-04-19 09:15:51 +02:00
Zsolt Viczian
a58db4db6f fixed rollup to build with Excalidraw prod package 2021-04-19 09:12:40 +02:00
Zsolt Viczian
35698bb205 removed crypto 2021-04-19 07:51:50 +02:00
Zsolt Viczian
3bdac43599 playing with build config 2021-04-19 07:47:18 +02:00
Zsolt Viczian
9e7960d9d0 Merge branch 'master' of https://github.com/zsviczian/obsidian-excalidraw-take3 2021-04-18 23:28:20 +02:00
Zsolt Viczian
fd1e6f6163 alpha release 2021-04-18 23:28:02 +02:00
zsviczian
6bca013462 Update README.md 2021-04-18 23:26:56 +02:00
zsviczian
9843e8d5f8 Update README.md 2021-04-18 23:15:53 +02:00
Zsolt Viczian
4854ec314a ready to build alpha 0.0.1 2021-04-18 22:19:16 +02:00
Zsolt Viczian
387e4fb7d0 Merge branch 'master' of https://github.com/zsviczian/obsidian-excalidraw-take3 2021-04-17 22:29:56 +02:00
Zsolt Viczian
70e39d7e27 got it working! 2021-04-17 22:27:26 +02:00
zsviczian
d4f524fa37 Update README.md 2021-04-17 21:35:21 +02:00
dhruvik7
2658b5f351 durability 2021-02-25 09:51:41 -05:00
dhruvik7
12b94cf8ae versioning 2021-02-25 09:00:17 -05:00
dhruvik7
a4f747d65c Merge pull request #2 from dhruvik7/update/tracker
Update/tracker
2021-02-25 08:44:38 -05:00
dhruvik7
1cd5557787 Merge branch 'master' into update/tracker 2021-02-25 08:44:26 -05:00
dhruvik7
7cd552848f small edits 2021-02-25 08:43:50 -05:00
dhruvik7
3452c7b3a2 added coloring 2021-02-21 21:58:35 -05:00
dhruvik7
d8eee206c7 added icon 2021-02-21 17:10:04 -05:00
dhruvik7
2587ff5820 added tooltip 2021-02-21 16:31:55 -05:00
dhruvik7
4874cf4d4f working commit graph, needs tooltips 2021-02-21 14:50:22 -05:00
dhruvik7
09305323cb Progress with bad pkg 2021-02-21 13:08:28 -05:00
dhruvik7
caa732e423 inner content 2021-02-21 10:50:43 -05:00
dhruvik7
c3543942a3 Update README.md 2021-02-16 11:26:15 -05:00
dhruvik7
7d1dc84610 updating versions 2021-02-15 10:14:53 -05:00
dhruvik7
f94b207a77 Added debouncing 2021-02-14 21:16:24 -05:00
22 changed files with 12858 additions and 367 deletions

38
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,7 +1,20 @@
## Obsidian Daily Stats
## Obsidian-Excalidraw
![image](https://user-images.githubusercontent.com/14358394/115391516-d9df4880-a1df-11eb-95a9-cad850cdf9fc.png)
### Key features
- Use the Excalidraw command in the Command palette to open an existing drawing or to create a new one. You create a new one by typing its name and hitting enter.
- Set up a default folder for your drawings in Settings, however you can have excalidraw drawings in any folder within your vault.
- You can also set up a Template, by creating a drawing, customizing it the way you like it, and specifying the file as the template in settings.
- There is a known bug when inserting images from the library, in some cases these images will be placed out of view, and you'll need to select scroll to view at the bottom of the screen. The bug was reproduced by the Excalidraw dev team, so I expect in the next update of Excalidraw it will be fixed.
- Translusion of drawings into markdown documents
- Drawings are saved to your vault as a file with the extension .excalidraw
- You can also use the file explorer in your vault to open Excalidraw files
### Excalidraw in Obsidian
https://user-images.githubusercontent.com/14358394/115386872-3fc8d180-a1da-11eb-9366-16d0e064932a.mp4
### Support
If you want to support me and my work, you can donate me a little something by [buying me a coffee](https://ko-fi.com/zsolt)
This is a daily word count plugin for Obsidian (https://obsidian.md). You can see today's word count in the bottom right corner of your screen, and also see the historical logs.
This plugin was inspired by liamcain's [Calender](https://github.com/liamcain/obsidian-calendar-plugin) and lukeleppan's [Better Word Count](https://github.com/lukeleppan/better-word-count).
![Example](./images/example.png)

1
data-ZsoltServer.json Normal file
View File

@@ -0,0 +1 @@
{"openFile":"Blog/attachements/security through obscurity.excalidraw","settings":{"folder":"excalidraw","templateFilePath":"excalidraw/Template.excalidraw"}}

1
data.json Normal file
View File

@@ -0,0 +1 @@
{"folder":"excalidraw","templateFilePath":"excalidraw/Template.excalidra","width":"400","openFile":"excalidraw/new file.excalidraw","settings":{"folder":"excalidraw","templateFilePath":""}}

10
dist/manifest.json vendored Normal file
View File

@@ -0,0 +1,10 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "0.1.0",
"minAppVersion": "0.0.2",
"description": "An obsidian plugin to edit and view Excalidraw drawings",
"author": "Zsolt Viczian",
"authorUrl": "https://zsolt.blog",
"isDesktopOnly": false
}

18
dist/styles.css vendored Normal file
View File

@@ -0,0 +1,18 @@
.App {
font-family: sans-serif;
text-align: center;
}
.excalidraw-wrapper {
height: 100%;
margin: 0px;
background-color: white;
}
.context-menu-option__shortcut {
background-color: transparent !important;
}
.block-language-excalidraw {
text-align:center;
}

BIN
images/example-graph.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

118
main.ts
View File

@@ -1,118 +0,0 @@
import { TFile, Plugin, MarkdownView } from 'obsidian';
interface WordCount {
initial: number;
current: number;
}
interface DailyStatsSettings {
dayCounts: Record<string, number>;
todaysWordCount: Record<string, WordCount>;
}
const DEFAULT_SETTINGS: DailyStatsSettings = {
dayCounts: {},
todaysWordCount: {}
}
export default class DailyStats extends Plugin {
settings: DailyStatsSettings;
statusBarEl: HTMLElement;
currentWordCount: number;
today: string;
async onload() {
await this.loadSettings();
this.statusBarEl = this.addStatusBarItem();
this.updateDate();
if (this.settings.dayCounts.hasOwnProperty(this.today)) {
this.updateCounts();
} else {
this.currentWordCount = 0;
}
this.registerEvent(
this.app.workspace.on("quit", this.onunload.bind(this))
);
this.registerEvent(
this.app.workspace.on("quick-preview", this.onQuickPreview.bind(this))
);
this.registerInterval(
window.setInterval(() => {
this.statusBarEl.setText(this.currentWordCount + " words today ");
}, 200)
);
this.registerInterval(window.setInterval(() => {
this.updateDate();
this.saveSettings();
}, 1000));
}
async onunload() {
await this.saveSettings();
}
onQuickPreview(file: TFile, contents: string) {
if (this.app.workspace.getActiveViewOfType(MarkdownView)) {
this.updateWordCount(contents, file.path);
}
}
//Credit: better-word-count by Luke Leppan (https://github.com/lukeleppan/better-word-count)
getWordCount(text: string) {
let words: number = 0;
const matches = text.match(
/[a-zA-Z0-9_\u0392-\u03c9\u00c0-\u00ff\u0600-\u06ff]+|[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af]+/gm
);
if (matches) {
for (let i = 0; i < matches.length; i++) {
if (matches[i].charCodeAt(0) > 19968) {
words += matches[i].length;
} else {
words += 1;
}
}
}
return words;
}
updateWordCount(contents: string, filepath: string) {
const curr = this.getWordCount(contents);
if (this.settings.dayCounts.hasOwnProperty(this.today)) {
if (this.settings.todaysWordCount.hasOwnProperty(filepath)) {//updating existing file
this.settings.todaysWordCount[filepath].current = curr;
} else {//created new file during session
this.settings.todaysWordCount[filepath] = { initial: curr, current: curr };
}
} else {//new day, flush the cache
this.settings.todaysWordCount = {};
this.settings.todaysWordCount[filepath] = { initial: curr, current: curr };
}
this.updateCounts();
}
updateDate() {
const d = new Date();
this.today = d.getFullYear() + "/" + d.getMonth() + "/" + d.getDate();
}
updateCounts() {
this.currentWordCount = Object.values(this.settings.todaysWordCount).map((wordCount) => Math.max(0, wordCount.current - wordCount.initial)).reduce((a, b) => a + b, 0);
this.settings.dayCounts[this.today] = this.currentWordCount;
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
}

View File

@@ -1,10 +1,10 @@
{
"id": "obsidian-daily-stats",
"name": "Daily Stats",
"version": "1.0.0",
"minAppVersion": "0.9.10",
"description": "Track your daily word count across all notes in your vault.",
"author": "Dhruvik Parikh",
"authorUrl": "https://github.com/dhruvik7",
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "0.1.0",
"minAppVersion": "0.0.2",
"description": "An obsidian plugin to edit and view Excalidraw drawings",
"author": "Zsolt Viczian",
"authorUrl": "https://zsolt.blog",
"isDesktopOnly": false
}

View File

@@ -1,23 +1,35 @@
{
"name": "obsidian-daily-stats",
"version": "1.0.0",
"description": "This is an Obsidian.md plugin that lets you view your daily word count.",
"main": "main.js",
"scripts": {
"dev": "rollup --config rollup.config.js -w",
"build": "rollup --config rollup.config.js"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@rollup/plugin-commonjs": "^15.1.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-typescript": "^6.0.0",
"@types/node": "^14.14.2",
"obsidian": "https://github.com/obsidianmd/obsidian-api/tarball/master",
"rollup": "^2.32.1",
"tslib": "^2.0.3",
"typescript": "^4.0.3"
}
}
{
"name": "obsidian-excalidraw-plugin",
"version": "1.0.4",
"description": "This is an Obsidian.md plugin that lets you view and edit Excalidraw drawings",
"main": "main.js",
"scripts": {
"dev": "cross-env NODE_ENV=development rollup --config rollup.config.js -w",
"build": "cross-env NODE_ENV=production rollup --config rollup.config.js"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"@excalidraw/excalidraw": "0.6.0",
"react": "17.0.0",
"react-dom": "17.0.0",
"react-scripts": "4.0.1"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^15.1.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-typescript": "^6.0.0",
"@types/node": "^14.14.2",
"@types/react-dom": "^17.0.0",
"cross-env": "7.0.3",
"obsidian": "https://github.com/obsidianmd/obsidian-api/tarball/master",
"postcss": "^8.2.6",
"rollup": "2.45.2",
"rollup-plugin-copy": "3.4.0",
"rollup-plugin-minify": "1.0.3",
"rollup-plugin-postcss": "^4.0.0",
"tslib": "^2.0.3",
"typescript": "^4.0.3"
}
}

View File

@@ -1,19 +1,43 @@
import typescript from '@rollup/plugin-typescript';
import {nodeResolve} from '@rollup/plugin-node-resolve';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import copy from 'rollup-plugin-copy';
//import uglify from 'rollup-plugin-uglify';
//import minify from "rollup-plugin-minify"
import { env } from "process";
import replace from "@rollup/plugin-replace";
const isProd = (process.env.NODE_ENV === "production");
console.log(process.env.NODE_ENV);
console.log("Is production", isProd);
export default {
input: 'main.ts',
input: 'src/main.ts',
output: {
dir: '.',
dir: isProd ? './dist' : '.',
sourcemap: 'inline',
format: 'cjs',
exports: 'default'
},
external: ['obsidian'],
plugins: [
typescript(),
nodeResolve({browser: true}),
typescript({inlineSources: !isProd}),
nodeResolve({ browser: true, preferBuiltins: true }),
replace({
preventAssignment: true,
"process.env.NODE_ENV": JSON.stringify(env.NODE_ENV),
}),
commonjs(),
postcss({
plugins: []
}),
copy({
targets: [
{ src: ['manifest.json', 'styles.css'], dest: './dist' }
], flatten: true
}),
//process.env.NODE_ENV === 'production' && minify(),
]
};

164
src/ExcalidrawView.ts Normal file
View File

@@ -0,0 +1,164 @@
import { TextFileView, WorkspaceLeaf } from "obsidian";
import * as React from "react";
import * as ReactDOM from "react-dom";
import Excalidraw, {exportToSvg} from "@excalidraw/excalidraw";
import { ExcalidrawElement } from "@excalidraw/excalidraw/types/element/types";
import { AppState } from "@excalidraw/excalidraw/types/types";
export default class ExcalidrawView extends TextFileView {
private getScene: any;
constructor(leaf: WorkspaceLeaf) {
super(leaf);
this.getScene = null;
}
async onClose() {
this.requestSave();
}
// clear the view content
clear() {
ReactDOM.unmountComponentAtNode(this.contentEl);
this.getScene = null;
}
// get the new file content
getViewData () {
if(this.getScene) return this.getScene();
else return '';
}
setViewData (data: string, clear: boolean) {
if (this.app.workspace.layoutReady) {
this.loadDrawing(data,clear);
} else {
this.registerEvent(this.app.workspace.on('layout-ready', async () => this.loadDrawing(data,clear)));
}
}
private loadDrawing (data:string, clear:boolean) :void {
if(clear) this.clear();
const excalidrawData = JSON.parse(data);
this.instantiateExcalidraw({
elements: excalidrawData.elements,
appState: excalidrawData.appState,
scrollToContent: true,
});
}
// gets the title of the document
getDisplayText() {
if(this.file) return this.file.basename;
else return "excalidraw (no file)";
}
// confirms this view can accept csv extension
canAcceptExtension(extension: string) {
return extension == 'excalidraw';
}
// the view type name
getViewType() {
return "excalidraw";
}
// icon for the view
getIcon() {
return "excalidraw-icon";
}
private instantiateExcalidraw(initdata: any) {
ReactDOM.render(React.createElement(() => {
let previousSceneVersion = 0;
const excalidrawRef = React.useRef(null);
const excalidrawWrapperRef = React.useRef(null);
const [dimensions, setDimensions] = React.useState({
width: undefined,
height: undefined
});
React.useEffect(() => {
setDimensions({
width: this.contentEl.clientWidth,
height: this.contentEl.clientHeight,
});
const onResize = () => {
try {
setDimensions({
width: this.contentEl.clientWidth,
height: this.contentEl.clientHeight,
});
} catch(err) {console.log ("onResize ",err)}
};
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize);
}, [excalidrawWrapperRef]);
this.getScene = function() {
const el: ExcalidrawElement[] = excalidrawRef.current.getSceneElements();
const st: AppState = excalidrawRef.current.getAppState();
return JSON.stringify({
"type": "excalidraw",
"version": 2,
"source": "https://excalidraw.com",
"elements": el.filter(e => !e.isDeleted),
"appState": {
"theme": st.theme,
"viewBackgroundColor": st.viewBackgroundColor,
"gridSize": st.gridSize,
"zenModeEnabled": st.zenModeEnabled
}
});
};
return React.createElement(
React.Fragment,
null,
React.createElement(
"div",
{
className: "excalidraw-wrapper",
ref: excalidrawWrapperRef
},
React.createElement(Excalidraw.default, {
ref: excalidrawRef,
width: dimensions.width,
height: dimensions.height,
UIOptions: {
canvasActions: {
loadScene: false,
saveScene: false,
saveAsScene: false
},
},
initialData: initdata
})
)
);
}),(this as any).contentEl);
}
public static getSVG(data:string):SVGSVGElement {
try {
const excalidrawData = JSON.parse(data);
return exportToSvg({
elements: excalidrawData.elements,
appState: {
exportBackground: true,
exportWithDarkMode: excalidrawData.appState?.theme=="light" ? false : true,
... excalidrawData.appState,},
exportPadding:10,
metadata: "Generated by Excalidraw-Obsidian plugin",
});
} catch (error) {
return null;
}
}
}

6
src/constants.ts Normal file
View File

@@ -0,0 +1,6 @@
export const VIEW_TYPE_EXCALIDRAW = "excalidraw";
export const MAX_COLORS = 5;
export const COLOR_FREQ = 6;
export const BLANK_DRAWING = '{"type":"excalidraw","version":2,"source":"https://excalidraw.com","elements":[],"appState":{"gridSize":null,"viewBackgroundColor":"#ffffff"}}';
export const EMPTY_MESSAGE = "Hit enter to create a new drawing";
export const EXCALIDRAW_ICON = `<g transform="translate(30,0)"><path fill="currentColor" stroke="currentColor" d="M14.45 1.715c-2.723 2.148-6.915 5.797-10.223 8.93l-2.61 2.445.477 3.207c.258 1.75.738 5.176 1.031 7.582.332 2.406.66 4.668.773 4.996.145.438 0 .656-.406.656-.699 0-.734-.183 1.176 5.832.7 2.297 1.363 4.414 1.434 4.633.074.254.367.363.699.254.332-.145.515-.438.406-.691-.113-.293.074-.586.367-.696.403-.144.367-.437-.258-1.492-.992-1.64-3.53-15.64-3.675-20.164-.11-3.207-.11-3.242 1.25-5.066 1.324-1.786 4.375-4.485 9.078-7.91 1.324-.985 2.648-2.079 3.015-2.446.551-.656.809-.472 5.442 4.414 2.683 2.805 5.664 5.688 6.617 6.414l1.766 1.313-1.36 2.844c-.734 1.53-3.715 7.437-6.656 13.054-6.137 11.813-4.887 10.68-12.02 10.79l-4.632.038-1.547 1.75c-1.617 1.86-1.836 2.551-1.063 3.72.293.398.512 1.054.512 1.456 0 .656.258.766 1.73.84.918.035 1.762.145 1.875.254.11.11.258 2.371.368 5.031l.144 4.813-2.46 5.25C1.616 72.516 0 76.527 0 77.84c0 .691.148 1.273.293 1.273.367 0 .367-.035 15.332-30.988 6.95-14.363 13.531-27.89 14.633-30.113 1.101-2.227 2.094-4.266 2.168-4.559.074-.328-2.461-2.844-6.508-6.379C22.281 3.864 19.082.95 18.785.621c-.844-1.023-2.094-.695-4.336 1.094zM15.7 43.64c-1.692 3.246-1.766 3.28-6.4 3.5-4.081.218-4.152.183-4.152-.582 0-.438-.148-1.024-.332-1.313-.222-.328-.074-.914.442-1.715l.808-1.238h3.676c2.024-.04 4.34-.184 5.149-.328.808-.149 1.507-.219 1.578-.184.074.035-.293.875-.77 1.86zm-3.09 5.832c-.294.765-1.067 2.37-1.692 3.574-1.027 2.043-1.137 2.113-1.395 1.277-.148-.511-.257-2.008-.296-3.355-.036-2.66-.11-2.625 2.98-2.809l.992-.035zm0 0"/><path fill="currentColor" stroke="currentColor" d="M15.55 10.39c-.66.473-.843.95-.843 2.153 0 1.422.11 1.64 1.102 2.039.992.402 1.25.367 2.39-.398 1.508-1.024 1.543-1.278.442-2.918-.957-1.422-1.914-1.676-3.09-.875zm2.098 1.313c.586 1.02.22 1.785-.882 1.785-.993 0-1.434-.984-.883-1.968.441-.801 1.285-.727 1.765.183zm0 0M38.602 18.594c0 .183-.22.363-.477.363-.219 0-.844 1.023-1.324 2.262-1.469 3.793-16.176 32.629-16.211 31.718 0-.472-.223-.8-.59-.8-.516 0-.59.289-.367 1.71.219 1.641.074 2.008-5.149 12.071-2.941 5.723-6.101 11.703-7.02 13.305-.956 1.68-1.69 3.5-1.765 4.265-.11 1.313.035 1.496 3.235 4.23 1.84 1.606 4.191 3.61 5.222 4.52 4.63 4.196 6.801 5.871 7.387 5.762.883-.145 14.523-14.328 14.559-15.129 0-.367-.66-5.906-1.47-12.324-1.398-10.938-2.722-23.734-2.573-24.973.109-.765-.442-4.633-.844-6.308-.332-1.313-.184-1.86 2.46-7.84 1.544-3.535 3.567-7.875 4.45-9.625.844-1.75 1.582-3.281 1.582-3.39 0-.11-.258-.18-.55-.18-.298 0-.555.144-.555.363zm-8.454 27.234c.403 2.55 1.211 8.676 1.801 13.598 1.14 9.043 2.461 19.07 2.832 21.62.219 1.278.07 1.532-2.316 4.157-4.156 4.629-8.567 9.188-10.074 10.356l-1.399 1.093-7.168-6.636c-6.617-6.051-7.168-6.672-6.765-7.403.222-.398 2.097-3.789 4.156-7.508 2.058-3.718 4.777-8.68 6.027-11.011 1.29-2.371 2.465-4.41 2.684-4.52.258-.148.332 3.535.258 11.375-.149 11.703-.11 11.739 1.066 11.485.148 0 .258-5.907.258-13.09V56.293l3.86-7.656c2.132-4.23 3.898-7.621 3.972-7.586.07.039.441 2.187.808 4.777zm0 0"/></g>`;

179
src/main.ts Normal file
View File

@@ -0,0 +1,179 @@
import {
TFile,
Plugin,
WorkspaceLeaf,
addIcon,
App,
PluginManifest,
MarkdownView,
} from 'obsidian';
import { BLANK_DRAWING, VIEW_TYPE_EXCALIDRAW, EXCALIDRAW_ICON } from './constants';
import ExcalidrawView from './ExcalidrawView';
import {
ExcalidrawSettings,
DEFAULT_SETTINGS,
ExcalidrawSettingTab
} from './settings';
import {openDialogAction, OpenFileDialog} from './openDrawing';
import {getDateString} from './utils'
export default class ExcalidrawPlugin extends Plugin {
public settings: ExcalidrawSettings;
public view: ExcalidrawView;
private openDialog: OpenFileDialog;
private activeDrawing: TFile;
private activeDrawingFilename: string;
constructor(app: App, manifest: PluginManifest) {
super(app, manifest);
this.activeDrawing = null;
this.activeDrawingFilename = '';
}
async onload() {
addIcon("excalidraw-icon", EXCALIDRAW_ICON);
this.registerView(
VIEW_TYPE_EXCALIDRAW,
(leaf: WorkspaceLeaf) => (this.view = new ExcalidrawView(leaf))
);
this.registerExtensions(["excalidraw"],"excalidraw");
this.registerMarkdownCodeBlockProcessor('excalidraw', (source,el,ctx) => {
const parseError = (message: string) => {
el.createDiv("excalidraw-error",(el)=> {
el.createEl("p","Please provide a link to an excalidraw file: [[file.excalidraw]]");
el.createEl("p",message);
el.createEl("p",source);
})
}
const filename = source.match(/\[{2}(.*)\]{2}/m);
const filenameWH = source.match(/\[{2}(.*)\|(\d*)x(\d*)\]{2}/m);
const filenameW = source.match(/\[{2}(.*)\|(\d*)\]{2}/m);
let fname:string = '';
let fwidth:string = this.settings.width;
let fheight:string = null;
if (filenameWH) {
fname = filenameWH[1];
fwidth = filenameWH[2];
fheight = filenameWH[3];
} else if (filenameW) {
fname = filenameW[1];
fwidth = filenameW[2];
} else if (filename) {
fname = filename[1];
}
if(fname!='') {
const file:TFile = (this.app.vault.getAbstractFileByPath(fname) as TFile);
if(file) {
if(file.extension == "excalidraw") {
this.app.vault.read(file).then(async (content: string) => {
const svg = ExcalidrawView.getSVG(content);
if(svg) {
el.createDiv("excalidraw-svg",(el)=> {
svg.removeAttribute('width');
svg.removeAttribute('height');
svg.style.setProperty('width',fwidth);
if(fheight) svg.style.setProperty('height',fheight);
el.appendChild(svg);
})
} else parseError("Parse error. Not a valid Excalidraw file.");
});
} else parseError("Not an excalidraw file. Must have extension .excalidraw");
} else parseError("File does not exist");
} else parseError("No link to file found in codeblock.");
});
await this.loadSettings();
this.addSettingTab(new ExcalidrawSettingTab(this.app, this));
this.openDialog = new OpenFileDialog(this.app, this);
this.addRibbonIcon('excalidraw-icon', 'Excalidraw', async () => {
this.openDialog.start(openDialogAction.openFile);
});
this.addCommand({
id: "excalidraw-open",
name: "Open existing drawing or create new one",
callback: () => {
this.openDialog.start(openDialogAction.openFile);
},
});
this.addCommand({
id: "excalidraw-insert-transclusion",
name: "Insert link to .excalidraw file into markdown document",
callback: () => {
this.openDialog.start(openDialogAction.insertLink);
},
});
this.addCommand({
id: "excalidraw-autocreate",
name: "Create a new drawing",
callback: () => {
this.createDrawing(this.getNextDefaultFilename());
},
});
}
public insertCodeblock(data:string) {
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
if(activeView) {
const editor = activeView.editor;
let doc = editor.getDoc();
doc.replaceSelection(
String.fromCharCode(96,96,96) +
"excalidraw\n[["+data+"]]\n" +
String.fromCharCode(96,96,96));
editor.focus();
}
}
private async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
public async openDrawing(drawingFile: TFile) {
this.activeDrawing = drawingFile;
this.saveSettings();
const leaf = this.view ? this.view.leaf : this.app.workspace.activeLeaf;
leaf.setViewState({
type: VIEW_TYPE_EXCALIDRAW,
state: {file: drawingFile.path}}
);
}
private getNextDefaultFilename():string {
return this.settings.folder+'/Drawing ' + getDateString('yyyy-MM-dd HH.mm.ss')+'.excalidraw';
}
public async createDrawing(filename: string) {
if(!(this.app.vault.getAbstractFileByPath(this.settings.folder) as TFile)) {
this.app.vault.createFolder(this.settings.folder);
}
const file = (this.app.vault.getAbstractFileByPath(this.settings.templateFilePath) as TFile);
if(file) {
this.app.vault.read(file).then(async (content: string) => {
this.openDrawing(await this.app.vault.create(filename,content==''?BLANK_DRAWING:content))
});
} else {
this.openDrawing(await this.app.vault.create(filename,BLANK_DRAWING));
}
}
}

79
src/openDrawing.ts Normal file
View File

@@ -0,0 +1,79 @@
import { App, FuzzySuggestModal, TFile, TFolder, normalizePath, Vault, TAbstractFile, Instruction } from "obsidian";
import ExcalidrawPlugin from './main';
import {EMPTY_MESSAGE} from './constants';
export enum openDialogAction {
openFile,
insertLink,
}
export class OpenFileDialog extends FuzzySuggestModal<TFile> {
public app: App;
private plugin: ExcalidrawPlugin;
private action: openDialogAction;
constructor(app: App, plugin: ExcalidrawPlugin) {
super(app);
this.app = app;
this.action = openDialogAction.openFile;
this.plugin = plugin;
this.setInstructions([{
command: "Type name of drawing to select.",
purpose: "",
}]);
this.inputEl.onkeyup = (e) => {
if(e.key=="Enter" && this.action == openDialogAction.openFile) {
if (this.containerEl.innerText.includes(EMPTY_MESSAGE)) {
this.plugin.createDrawing(this.plugin.settings.folder+'/'+this.inputEl.value+'.excalidraw');
this.close();
}
}
};
}
getItems(): TFile[] {
let excalidrawFiles: TFile[] = [];
excalidrawFiles = this.app.vault.getFiles();
return excalidrawFiles.filter((f:TFile) => (f.extension=='excalidraw'));
}
getItemText(item: TFile): string {
return item.basename;
}
onChooseItem(item: TFile, _evt: MouseEvent | KeyboardEvent): void {
switch(this.action) {
case(openDialogAction.openFile):
this.plugin.openDrawing(item);
break;
case(openDialogAction.insertLink):
this.plugin.insertCodeblock(item.path);
break;
}
}
start(action:openDialogAction): void {
this.action = action;
switch(action) {
case (openDialogAction.openFile):
this.emptyStateText = EMPTY_MESSAGE;
this.setPlaceholder("Select existing drawing or type name of new and hit enter.");
break;
case (openDialogAction.insertLink):
this.emptyStateText = "No file matches your query.";
this.setPlaceholder("Select existing drawing to insert into document.");
break;
}
try {
let files = this.getItems();
this.open();
}
catch(error) {
console.log(error);
}
}
}

66
src/settings.ts Normal file
View File

@@ -0,0 +1,66 @@
import {App, PluginSettingTab, Setting} from 'obsidian';
import type ExcalidrawPlugin from "./main";
export interface ExcalidrawSettings {
folder: string,
templateFilePath: string,
width: string,
}
export const DEFAULT_SETTINGS: ExcalidrawSettings = {
folder: 'excalidraw',
templateFilePath: '',
width: '400',
}
export class ExcalidrawSettingTab extends PluginSettingTab {
plugin: ExcalidrawPlugin;
constructor(app: App, plugin: ExcalidrawPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
let {containerEl} = this;
this.containerEl.empty();
new Setting(containerEl)
.setName('Excalidraw folder')
.setDesc('Default location for Excalidraw drawings. Leaving this empty means drawings will be saved to the Vault root.')
.addText(text => text
.setPlaceholder('excalidraw')
.setValue(this.plugin.settings.folder)
.onChange(async (value) => {
this.plugin.settings.folder = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Excalidraw template file')
.setDesc('Full path to file containing the file you want to use as the template for new Excalidraw drawings. '+
'Note that Excalidraw files will have an extension of ".excalidraw" ' +
'Assuming your template is in the default excalidraw folder, the setting would be: excalidraw/Template.excalidraw')
.addText(text => text
.setPlaceholder('excalidraw')
.setValue(this.plugin.settings.templateFilePath)
.onChange(async (value) => {
this.plugin.settings.templateFilePath = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Default width of embedded image')
.setDesc('The default width of an embedded drawing. You can specify a different ' +
'width when embedding an image using the [[drawing.excalidraw|100]] or ' +
'[[drawing.excalidraw|100x100]] format.')
.addText(text => text
.setPlaceholder('400')
.setValue(this.plugin.settings.width)
.onChange(async (value) => {
this.plugin.settings.width = value;
await this.plugin.saveSettings();
}));
}
}

28
src/utils.ts Normal file
View File

@@ -0,0 +1,28 @@
export function getDateString(format:string):string {
const pad2 = (n:number) => {
return n>9? n.toString():'0'+n;
}
const now = new Date();
const M=now.getMonth()+1,H=now.getHours(),m=now.getMinutes(),d=now.getDate(),s=now.getSeconds(),yyyy=now.getFullYear();
const n = {
yyyy: yyyy.toString(),
MM : pad2(M),
dd : pad2(d),
HH : pad2(H),
mm : pad2(m),
ss : pad2(s)
};
return format.replace(/([a-zA-Z]+)/g,function (s:string, $1:string):string {
switch($1) {
case 'yyyy' : return n.yyyy;
case 'MM' : return n.MM;
case 'dd' : return n.dd;
case 'HH' : return n.HH;
case 'mm' : return n.mm;
case 'ss' : return n.ss;
}
return '';
});
}

View File

@@ -0,0 +1,18 @@
.App {
font-family: sans-serif;
text-align: center;
}
.excalidraw-wrapper {
height: 100%;
margin: 0px;
background-color: white;
}
.context-menu-option__shortcut {
background-color: transparent !important;
}
.block-language-excalidraw {
text-align:center;
}

View File

@@ -13,10 +13,13 @@
"dom",
"es5",
"scripthost",
"es2015"
]
"es2015",
"DOM.Iterable"
],
"jsx": "react",
},
"include": [
"**/*.ts"
"**/*.ts",
"**/*.tsx", "src/openDrawing.ts",
]
}
}

View File

@@ -1,3 +1,3 @@
{
"1.0.0": "0.9.10"
".0.1": "0.11.13"
}

12339
yarn.lock

File diff suppressed because it is too large Load Diff