Organized all files. Code goes in src/ Added icon
This commit is contained in:
parent
6b715682f9
commit
32f0e6bc98
16 changed files with 117 additions and 482 deletions
|
|
@ -1,8 +0,0 @@
|
|||
import * as React from "react";
|
||||
import App from "./view/App";
|
||||
|
||||
export default function ReactView(props: any){
|
||||
return(
|
||||
<App username={props.userID} apiToken={props.tokenAPI} plugin={props.plugin}/>
|
||||
)
|
||||
}
|
||||
174
main.js
174
main.js
File diff suppressed because one or more lines are too long
65
main.ts
65
main.ts
|
|
@ -1,65 +0,0 @@
|
|||
import { Notice, Plugin } from "obsidian";
|
||||
import { HabiticaSyncSettingsTab } from "./settings";
|
||||
import { HabiticaSyncView, VIEW_TYPE} from "./view"
|
||||
|
||||
interface HabiticaSyncSettings {
|
||||
userID: string
|
||||
apiToken: string
|
||||
}
|
||||
const DEFAULT_SETTINGS: Partial<HabiticaSyncSettings> = {
|
||||
userID: "",
|
||||
apiToken: ""
|
||||
}
|
||||
export default class HabiticaSync extends Plugin {
|
||||
settings: HabiticaSyncSettings;
|
||||
view: HabiticaSyncView;
|
||||
|
||||
displayNotice(message: string){
|
||||
new Notice(message)
|
||||
}
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
this.addSettingTab(new HabiticaSyncSettingsTab(this.app, this));
|
||||
this.registerView(
|
||||
VIEW_TYPE,
|
||||
(leaf) => (this.view = new HabiticaSyncView(leaf, this))
|
||||
);
|
||||
this.addRibbonIcon("popup-open", "Open Habitica Pane", () => { //activate view
|
||||
this.activateView();
|
||||
});
|
||||
this.addCommand({
|
||||
id: "habitica-view-open",
|
||||
name: "Habitica: Open Pane",
|
||||
hotkeys: [{ modifiers: ["Mod", "Shift"], key: "h"}],
|
||||
callback: () => {
|
||||
this.activateView();
|
||||
}
|
||||
});
|
||||
}
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign(DEFAULT_SETTINGS, await this.loadData())
|
||||
}
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
async onunload() {
|
||||
await this.view.onClose();
|
||||
|
||||
this.app.workspace
|
||||
.getLeavesOfType(VIEW_TYPE)
|
||||
.forEach((leaf) => leaf.detach());
|
||||
}
|
||||
async activateView() {
|
||||
this.app.workspace.detachLeavesOfType(VIEW_TYPE);
|
||||
|
||||
await this.app.workspace.getRightLeaf(false).setViewState({
|
||||
type: VIEW_TYPE,
|
||||
active: true,
|
||||
});
|
||||
|
||||
this.app.workspace.revealLeaf(
|
||||
this.app.workspace.getLeavesOfType(VIEW_TYPE)[0]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -6,5 +6,6 @@
|
|||
"description": "This plugin helps integrate Habitica user tasks and stats into Obsidian",
|
||||
"author": "Leoh and Ran",
|
||||
"authorUrl": "",
|
||||
"isDesktopOnly": false
|
||||
"isDesktopOnly": false,
|
||||
"js": "main.js"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ if you want to view the source visit the plugins github repository
|
|||
`;
|
||||
|
||||
export default {
|
||||
input: 'main.ts',
|
||||
input: 'src/main.ts',
|
||||
output: {
|
||||
dir: '.',
|
||||
sourcemap: 'inline',
|
||||
|
|
|
|||
42
settings.ts
42
settings.ts
|
|
@ -1,42 +0,0 @@
|
|||
import HabiticaSync from "main";
|
||||
import { App, PluginSettingTab, Setting } from "obsidian";
|
||||
|
||||
export class HabiticaSyncSettingsTab extends PluginSettingTab {
|
||||
plugin: HabiticaSync;
|
||||
|
||||
constructor(app: App, plugin: HabiticaSync) {
|
||||
super(app, plugin)
|
||||
this.plugin = plugin
|
||||
}
|
||||
|
||||
display(): void {
|
||||
let { containerEl } = this;
|
||||
containerEl.empty();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Habitica User ID")
|
||||
.setDesc("Can be found in Settings > API")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("User ID")
|
||||
.setValue(this.plugin.settings.userID)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.userID = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Habitica API Token")
|
||||
.setDesc("Can be found in Settings > API")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("API Token")
|
||||
.setValue(this.plugin.settings.apiToken)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.apiToken = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,10 +3,9 @@
|
|||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "esnext",
|
||||
"module": "ESNext",
|
||||
"target": "es6",
|
||||
"jsx": "react",
|
||||
"target": "es2017",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
|
|
@ -19,5 +18,5 @@
|
|||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
, "view/TodoItem.tsx" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
35
view.tsx
35
view.tsx
|
|
@ -1,35 +0,0 @@
|
|||
import { ItemView,WorkspaceLeaf } from "obsidian";
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import ReactView from "./ReactView";
|
||||
import HabiticaSync from "main";
|
||||
|
||||
|
||||
export const VIEW_TYPE = "example-view"
|
||||
|
||||
export class HabiticaSyncView extends ItemView {
|
||||
plugin: HabiticaSync;
|
||||
constructor(leaf: WorkspaceLeaf, plugin: HabiticaSync) {
|
||||
super(leaf)
|
||||
this.plugin = plugin
|
||||
}
|
||||
|
||||
getViewType() {
|
||||
return VIEW_TYPE
|
||||
}
|
||||
|
||||
getDisplayText() {
|
||||
return "Habitica Pane"
|
||||
}
|
||||
|
||||
async onOpen() {
|
||||
ReactDOM.render(
|
||||
<ReactView userID = {this.plugin.settings.userID} tokenAPI = {this.plugin.settings.apiToken} plugin={this.plugin}/>,
|
||||
this.containerEl.children[1]
|
||||
)
|
||||
}
|
||||
|
||||
async onClose(){
|
||||
ReactDOM.unmountComponentAtNode(this.containerEl.children[1]);
|
||||
}
|
||||
}
|
||||
122
view/App.tsx
122
view/App.tsx
|
|
@ -1,122 +0,0 @@
|
|||
import * as React from "react";
|
||||
import { getStats, scoreTask } from "./habiticaAPI"
|
||||
import Statsview from "./Components/Statsview"
|
||||
import Taskview from "./Components/Taskview"
|
||||
|
||||
let username = ""
|
||||
let credentials = ""
|
||||
|
||||
class App extends React.Component<any,any> {
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
username = this.props.username
|
||||
credentials = this.props.apiToken
|
||||
this.state = {
|
||||
isLoaded: false,
|
||||
user_data: {
|
||||
profile: {
|
||||
name: "",
|
||||
},
|
||||
stats: {
|
||||
hp: 0,
|
||||
lvl: 0,
|
||||
}
|
||||
},
|
||||
todos: []
|
||||
}
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
}
|
||||
sendNotice(message: string){
|
||||
this.props.plugin.displayNotice(message)
|
||||
}
|
||||
reloadData() {
|
||||
getStats(username, credentials)
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
result => {
|
||||
if(result.success === false){
|
||||
this.sendNotice("Login Failed, Please check credentials and try again!")
|
||||
console.log(result)
|
||||
} else {
|
||||
console.log(result)
|
||||
console.log("data reloaded")
|
||||
this.setState({
|
||||
isLoaded: true,
|
||||
user_data: result,
|
||||
todos: result.tasks.todos
|
||||
})
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
this.setState({
|
||||
isLoaded: true,
|
||||
error
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
componentDidMount() {
|
||||
this.reloadData()
|
||||
}
|
||||
handleChange(event: any){
|
||||
this.state.todos.forEach((element: any) => {
|
||||
if(element.id == event.target.id){
|
||||
if(!element.completed){
|
||||
scoreTask(username, credentials, event.target.id, "up")
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
result => {
|
||||
if(result.success) {
|
||||
this.sendNotice("Checked!")
|
||||
console.log(result)
|
||||
this.reloadData()
|
||||
} else {
|
||||
this.sendNotice("Resyncing, please try again")
|
||||
this.reloadData()
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
this.sendNotice("API Error: Please Check crendentials and try again")
|
||||
console.log(error)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
scoreTask(username, credentials, event.target.id, "down")
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
result => {
|
||||
if(result.success){
|
||||
this.sendNotice("Un-checked!")
|
||||
console.log(result)
|
||||
this.reloadData()
|
||||
} else {
|
||||
this.sendNotice("Resyncing, please try again")
|
||||
this.reloadData()
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
this.sendNotice("API Error: Please Check crendentials and try again")
|
||||
console.log(error)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
if(this.state.error)
|
||||
return(<div className="loading">Loading....</div>)
|
||||
else if(!this.state.isLoaded)
|
||||
return <div className="loading">Loading....</div>
|
||||
else {
|
||||
return (<div className="plugin-root">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
||||
<Statsview user_data={this.state.user_data} />
|
||||
<Taskview todos={this.state.todos} onChange={this.handleChange} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
export default App
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import * as React from 'react';
|
||||
|
||||
export default function Index(props: any) {
|
||||
return(
|
||||
<div className="stats">
|
||||
<div id="profile-name">{props.user_data.profile.name}</div>
|
||||
<div className = "substats" id="hp"><i className="material-icons">favorite</i>HP: {(props.user_data.stats.hp).toPrecision(3)}</div>
|
||||
<div className = "substats" id="lvl"><i className="material-icons">star</i>LVL: {props.user_data.stats.lvl}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import * as React from "react";
|
||||
|
||||
function TodoItem(props: any) {
|
||||
return (
|
||||
<div className="todo-item" id={props.id}>
|
||||
<input type="checkbox" className="checkbox" id={props.id} onChange={props.onChange} checked={props.completed}/>
|
||||
<p>{props.todo_text}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TodoItem
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
import * as React from "react";
|
||||
import TodoItem from "./TodoItem"
|
||||
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
|
||||
|
||||
export default function Index(props: any){
|
||||
const incompleteTodos = props.todos.map((todo: any) => {
|
||||
if(!todo.completed)
|
||||
return <TodoItem key={todo.id} id={todo.id} todo_text={todo.text} onChange={props.onChange} completed={todo.completed}/>
|
||||
})
|
||||
const completedTodos = props.todos.map((todo: any) => {
|
||||
if(todo.completed)
|
||||
return <TodoItem key={todo.id} id={todo.id} todo_text={todo.text} onChange={props.onChange} completed={todo.completed}/>
|
||||
})
|
||||
const display = <div id="classDisplay">
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab>Active Todos</Tab>
|
||||
<Tab>Completed Todos</Tab>
|
||||
</TabList>
|
||||
<TabPanel>
|
||||
<ul>{incompleteTodos}</ul>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<ul>{completedTodos}</ul>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
return(display);
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
.react-tabs {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.react-tabs__tab-list {
|
||||
border-bottom: 1px solid #aaa;
|
||||
margin: 0 0 10px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.react-tabs__tab {
|
||||
display: inline-block;
|
||||
border: 1px solid transparent;
|
||||
border-bottom: none;
|
||||
bottom: -1px;
|
||||
position: relative;
|
||||
list-style: none;
|
||||
padding: 6px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.react-tabs__tab--selected {
|
||||
background: #fff;
|
||||
border-color: #aaa;
|
||||
color: black;
|
||||
border-radius: 5px 5px 0 0;
|
||||
}
|
||||
|
||||
.react-tabs__tab--disabled {
|
||||
color: GrayText;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.react-tabs__tab:focus {
|
||||
box-shadow: 0 0 5px hsl(208, 99%, 50%);
|
||||
border-color: hsl(208, 99%, 50%);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.react-tabs__tab:focus:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
height: 5px;
|
||||
left: -4px;
|
||||
right: -4px;
|
||||
bottom: -5px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.react-tabs__tab-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.react-tabs__tab-panel--selected {
|
||||
display: block;
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
import * as React from "react"
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
// import fetch from "node-fetch";
|
||||
|
||||
export async function getStats(username: string, credentials: string){
|
||||
const url = "https://habitica.com/export/userdata.json"
|
||||
const response = fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client": username.concat("-testAPI"),
|
||||
"x-api-user": username,
|
||||
"x-api-key": credentials,
|
||||
},
|
||||
})
|
||||
return (response)
|
||||
}
|
||||
|
||||
export async function scoreTask(username: string, credentials: string, taskID: string, direction: string) {
|
||||
const url = "https://habitica.com/api/v3/tasks/".concat(taskID).concat("/score/").concat(direction)
|
||||
const response = fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client": username.concat("-testAPI"),
|
||||
"x-api-user": username,
|
||||
"x-api-key": credentials,
|
||||
}
|
||||
})
|
||||
return(response)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue