Compare commits
No commits in common. "main" and "task-menu" have entirely different histories.
35 changed files with 33136 additions and 1001 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -6,17 +6,11 @@
|
|||
node_modules
|
||||
package-lock.json
|
||||
|
||||
# yarn
|
||||
yarn.lock
|
||||
|
||||
|
||||
*.js.map
|
||||
|
||||
# obsidian
|
||||
data.json
|
||||
|
||||
#build_files
|
||||
main.js
|
||||
|
||||
#vscode
|
||||
.vscode
|
||||
.vscode
|
||||
|
|
|
|||
21
LICENSE
21
LICENSE
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Zain Siddavatam and John Mavrick Reyes
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
46
README.md
46
README.md
|
|
@ -1,46 +1,20 @@
|
|||
# Habitica Sync in Obsidian
|
||||
This plugin for Obsidian incorporates a view to display and interact with the task management app Habitica.
|
||||
|
||||
Please open issues for any bugs/functionality requests :)
|
||||
|
||||
## Usage
|
||||
The plugin's view is enabled by clicking on the "Open Habitica Pane" option in the side ribbon (default hotkey is `Ctrl+Shift+H`).
|
||||
|
||||
To sync your Habitica account, go to the settings page of the plugin and enter your user ID and API token credentials.
|
||||
The plugin's view is enabled by clicking on the "Open Habitica Pane" option in the side ribbon. To sync your account, go to the settings page of the plugin and enter your user ID and API token credentials.
|
||||
## Features
|
||||
### Pane View
|
||||
#### View stats (HP, XP, coins)
|
||||
#### Views
|
||||
Task Information:
|
||||
- Title, description, subtasks
|
||||
- Markdown and emoji support
|
||||
|
||||
Tabs:
|
||||
- To Do's
|
||||
- Active/Completed
|
||||
- Dailies
|
||||
- Due/Not Due/Completed
|
||||
- [](https://gyazo.com/1966b17f954dcffa954922570e860a06)
|
||||
- Habits
|
||||
- [](https://gyazo.com/280494e620fc91548838d5b29a62652b)
|
||||
- Rewards
|
||||
#### Interactivity
|
||||
- Check off tasks/dailies in the view
|
||||
- Can uncheck completed habits/todos
|
||||
- [](https://gyazo.com/efb858cd9d54f9d9df936da1bd5858ed)
|
||||
- modify habit counters (+/-)
|
||||
|
||||
### Settings
|
||||
|
||||
The following two inputs help fetch your user data to be displayed in the Obsidian view:
|
||||
- View current HP and XP
|
||||
- View todos, Check off tasks in the view, which sync to habitica website.
|
||||
## Settings
|
||||
- **Habitica User ID:** You can find this by clicking on the "User" icon in the top right of the Habitica webapp, "Settings", then "API"
|
||||
- **Habitica Token API:** You can find this by clicking on the "User" icon in the top right of the Habitica webapp, "Settings", then "API"
|
||||
- **Show Task Descriptions:** Toggles whether description/notes for tasks will be shown or not
|
||||
- **Show Subtasks:** Toggles whether subtasks for to do's/dailies will be shown or not
|
||||
|
||||
The following two inputs help fetch your user data to be displayed in the Obsidian view.
|
||||
|
||||
## Roadmap
|
||||
We will be implementing additional features including:
|
||||
|
||||
*Feel free to support us and donate!*
|
||||
|
||||
<a href='https://ko-fi.com/leonardandran' target='_blank'><img height='35' style='border:0px;height:46px;' src='https://az743702.vo.msecnd.net/cdn/kofi3.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' />
|
||||
|
||||
- Panes to view active/completed dailies and habits
|
||||
- Add/delete/customize tasks and habits
|
||||
- View/claim rewards
|
||||
|
|
|
|||
32522
main.js
Normal file
32522
main.js
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "obsidian-habitica-integration",
|
||||
"name": "Habitica Sync",
|
||||
"version": "1.0.2",
|
||||
"version": "0.9.1",
|
||||
"minAppVersion": "0.9.12",
|
||||
"description": "This plugin helps integrate Habitica user tasks and stats into Obsidian",
|
||||
"author": "Leoh and Ran",
|
||||
|
|
|
|||
59
package.json
59
package.json
|
|
@ -1,51 +1,36 @@
|
|||
{
|
||||
"name": "obsidian-habitica-integration",
|
||||
"version": "1.0.0",
|
||||
"version": "0.12.0",
|
||||
"description": "This plugin allows for Habitica integration into Obsidian",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "rollup --config rollup.config.mjs -w",
|
||||
"build": "rollup --config rollup.config.mjs --environment BUILD:production",
|
||||
"dev2": "obsidian-plugin dev src/main.ts"
|
||||
"dev": "rollup --config rollup.config.js -w",
|
||||
"build": "rollup --config rollup.config.js --environment BUILD:production"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Leonard and Ran",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/markdown-it": "^13.0.7",
|
||||
"@types/markdown-it-emoji": "^2.0.4",
|
||||
"@types/node": "^20.11.0",
|
||||
"@types/node-emoji": "^1.8.2",
|
||||
"@types/react": "^18.2.47",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@types/react-tabs": "^5.0.4",
|
||||
"@types/twemoji": "^13.1.1",
|
||||
"css-loader": "^6.9.0",
|
||||
"mini-css-extract-plugin": "^2.7.7",
|
||||
"obsidian": "^1.4.11",
|
||||
"obsidian-plugin-cli": "^0.0.5",
|
||||
"rollup": "^4.9.4",
|
||||
"style-loader": "^3.3.4",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.3.3",
|
||||
"webpack": "^5.89.0"
|
||||
"@rollup/plugin-commonjs": "^18.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"@rollup/plugin-typescript": "^8.2.1",
|
||||
"@types/node": "^14.14.37",
|
||||
"@types/react": "^17.0.27",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@types/react-tabs": "^2.3.3",
|
||||
"css-loader": "^6.4.0",
|
||||
"extract-text-webpack-plugin": "^2.1.2",
|
||||
"obsidian": "^0.12.0",
|
||||
"rollup": "^2.32.1",
|
||||
"style-loader": "^3.3.0",
|
||||
"tslib": "^2.2.0",
|
||||
"typescript": "^4.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"markdown-it": "^14.0.0",
|
||||
"markdown-it-emoji": "^2.0.2",
|
||||
"moment": "^2.30.1",
|
||||
"node": "^21.2.0",
|
||||
"node-emoji": "^2.1.3",
|
||||
"node-fetch": "^3.3.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-emoji-render": "^2.0.1",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-tabs": "^6.0.2",
|
||||
"twemoji": "^14.0.2"
|
||||
"node": "^16.10.0",
|
||||
"node-fetch": "^3.0.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-tabs": "^3.2.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,30 @@
|
|||
import typescript from '@rollup/plugin-typescript';
|
||||
import {nodeResolve} from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import json from '@rollup/plugin-json';
|
||||
|
||||
const isProd = (process.env.BUILD === 'production');
|
||||
|
||||
const banner =
|
||||
`/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
|
||||
if you want to view the source visit the plugins github repository
|
||||
*/
|
||||
`;
|
||||
|
||||
export default {
|
||||
input: 'src/main.ts',
|
||||
output: {
|
||||
dir: '.',
|
||||
sourcemap: 'inline',
|
||||
sourcemapExcludeSources: isProd,
|
||||
format: 'cjs',
|
||||
exports: 'default',
|
||||
banner,
|
||||
},
|
||||
external: ['obsidian'],
|
||||
plugins: [
|
||||
typescript(),
|
||||
nodeResolve({browser: true}),
|
||||
commonjs(),
|
||||
json(),
|
||||
]
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
import {nodeResolve} from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
|
||||
const isProd = (process.env.BUILD === 'production');
|
||||
|
||||
const banner =
|
||||
`/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
|
||||
if you want to view the source visit the plugins github repository
|
||||
*/
|
||||
`;
|
||||
|
||||
export default {
|
||||
input: 'src/main.ts',
|
||||
output: {
|
||||
dir: '.',
|
||||
sourcemap: 'inline',
|
||||
sourcemapExcludeSources: isProd,
|
||||
format: 'cjs',
|
||||
exports: 'default',
|
||||
banner,
|
||||
},
|
||||
external: ['obsidian'],
|
||||
plugins: [
|
||||
typescript(),
|
||||
nodeResolve({browser: true}),
|
||||
commonjs(),
|
||||
]
|
||||
};
|
||||
26
src/main.ts
26
src/main.ts
|
|
@ -1,34 +1,30 @@
|
|||
import { Plugin } from "obsidian";
|
||||
import { Notice, Plugin } from "obsidian";
|
||||
import { HabiticaSyncSettingsTab } from "./settings";
|
||||
import { HabiticaSyncView, VIEW_TYPE} from "./view"
|
||||
|
||||
interface HabiticaSyncSettings {
|
||||
userID: string
|
||||
apiToken: string
|
||||
showTaskDescription: boolean
|
||||
showSubTasks: boolean
|
||||
dueDateFormat: string
|
||||
}
|
||||
const DEFAULT_SETTINGS: Partial<HabiticaSyncSettings> = {
|
||||
userID: "",
|
||||
apiToken: "",
|
||||
showTaskDescription: true,
|
||||
showSubTasks: true,
|
||||
dueDateFormat: "DD-MM-YYYY"
|
||||
apiToken: ""
|
||||
}
|
||||
export default class HabiticaSync extends Plugin {
|
||||
settings: HabiticaSyncSettings;
|
||||
view: HabiticaSyncView;
|
||||
|
||||
displayNotice(message: string){
|
||||
new Notice(message)
|
||||
}
|
||||
async onload() {
|
||||
console.log("load plugin: habitica-sync")
|
||||
await this.loadSettings();
|
||||
this.addSettingTab(new HabiticaSyncSettingsTab(this.app, this));
|
||||
this.registerView(
|
||||
VIEW_TYPE,
|
||||
(leaf) => (new HabiticaSyncView(leaf, this))
|
||||
(leaf) => (this.view = new HabiticaSyncView(leaf, this))
|
||||
);
|
||||
this.addRibbonIcon("popup-open", "Open Habitica Pane", () => {
|
||||
this.addRibbonIcon("popup-open", "Open Habitica Pane", () => { //activate view
|
||||
this.activateView();
|
||||
});
|
||||
this.addCommand({
|
||||
|
|
@ -39,7 +35,6 @@ export default class HabiticaSync extends Plugin {
|
|||
this.activateView();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign(DEFAULT_SETTINGS, await this.loadData())
|
||||
|
|
@ -47,7 +42,6 @@ export default class HabiticaSync extends Plugin {
|
|||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
async onunload() {
|
||||
await this.view.onClose();
|
||||
|
||||
|
|
@ -57,15 +51,15 @@ export default class HabiticaSync extends Plugin {
|
|||
}
|
||||
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]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import HabiticaSync from "./main";
|
||||
import { App, PluginSettingTab, Setting } from "obsidian";
|
||||
import moment from "moment";
|
||||
|
||||
export class HabiticaSyncSettingsTab extends PluginSettingTab {
|
||||
plugin: HabiticaSync;
|
||||
|
|
@ -39,42 +38,5 @@ export class HabiticaSyncSettingsTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Show Task Descriptions")
|
||||
.setDesc("Updates require pane re-opening")
|
||||
.addToggle(cb => {
|
||||
cb
|
||||
.setValue(this.plugin.settings.showTaskDescription)
|
||||
.onChange(async (isEnable) => {
|
||||
this.plugin.settings.showTaskDescription = isEnable;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Show Sub-Tasks")
|
||||
.setDesc("Updates require pane re-opening")
|
||||
.addToggle(cb => {
|
||||
cb
|
||||
.setValue(this.plugin.settings.showSubTasks)
|
||||
.onChange(async (isEnable) => {
|
||||
this.plugin.settings.showSubTasks = isEnable;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
});
|
||||
new Setting(containerEl)
|
||||
.setName("Due Date Format")
|
||||
.setDesc("Update requires pane re-opening, check moment.js docs for formatting. Current Format: " + moment().format(this.plugin.settings.dueDateFormat))
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("DD-MM-YYYY")
|
||||
.setValue(this.plugin.settings.dueDateFormat)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.dueDateFormat = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,8 @@ export class HabiticaSyncView extends ItemView {
|
|||
this.containerEl.children[1]
|
||||
)
|
||||
}
|
||||
async onClose(){
|
||||
|
||||
async onClose(){
|
||||
ReactDOM.unmountComponentAtNode(this.containerEl.children[1]);
|
||||
}
|
||||
}
|
||||
329
src/view/App.tsx
329
src/view/App.tsx
|
|
@ -1,31 +1,17 @@
|
|||
import * as React from "react";
|
||||
import { Notice } from "obsidian";
|
||||
import { getStats, scoreTask, makeCronReq, costReward, scoreChecklistItem } from "./habiticaAPI"
|
||||
import { getStats, scoreTask } from "./habiticaAPI"
|
||||
import Statsview from "./Components/Statsview"
|
||||
import Taskview from "./Components/Taskview"
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
class App extends React.Component<any, any> {
|
||||
private _username = "";
|
||||
public get username() {
|
||||
return this._username;
|
||||
}
|
||||
public set username(value) {
|
||||
this._username = value;
|
||||
}
|
||||
private _credentials = "";
|
||||
public get credentials() {
|
||||
return this._credentials;
|
||||
}
|
||||
public set credentials(value) {
|
||||
this._credentials = value;
|
||||
}
|
||||
let username = ""
|
||||
let credentials = ""
|
||||
|
||||
class App extends React.Component<any,any> {
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.username = this.props.plugin.settings.userID
|
||||
this.credentials = this.props.plugin.settings.apiToken
|
||||
username = this.props.plugin.settings.userID
|
||||
credentials = this.props.plugin.settings.apiToken
|
||||
this.state = {
|
||||
needCron: false,
|
||||
isLoaded: false,
|
||||
user_data: {
|
||||
profile: {
|
||||
|
|
@ -34,192 +20,201 @@ class App extends React.Component<any, any> {
|
|||
stats: {
|
||||
hp: 0,
|
||||
lvl: 0,
|
||||
gold: 0,
|
||||
},
|
||||
lastCron: "",
|
||||
}
|
||||
},
|
||||
todos: [],
|
||||
dailys: [],
|
||||
habits: [],
|
||||
}
|
||||
this.handleChangeTodos = this.handleChangeTodos.bind(this);
|
||||
this.handleChangeDailys = this.handleChangeDailys.bind(this);
|
||||
this.handleChangeHabits = this.handleChangeHabits.bind(this);
|
||||
this.handleChangeRewards = this.handleChangeRewards.bind(this);
|
||||
this.handleChangeChecklistItem = this.handleChangeChecklistItem.bind(this);
|
||||
this.runCron = this.runCron.bind(this);
|
||||
this.handleChangeTodos = this.handleChangeTodos.bind(this)
|
||||
this.handleChangeDailys = this.handleChangeDailys.bind(this)
|
||||
this.handleChangeHabits = this.handleChangeHabits.bind(this)
|
||||
|
||||
|
||||
}
|
||||
CheckCron(lastCron: string) {
|
||||
let cronDate = new Date(lastCron);
|
||||
let now = new Date();
|
||||
if (cronDate.getDate() != now.getDate() || (cronDate.getMonth() != now.getMonth() || cronDate.getFullYear() != now.getFullYear())) {
|
||||
return (
|
||||
<div className="cron">
|
||||
<div id="cronMessage"> Welcome back! Please check your tasks for the last day and hit continue to get your daily rewards.</div>
|
||||
<button id="cronButton" onClick={this.runCron}>Continue</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
else {
|
||||
return null
|
||||
};
|
||||
sendNotice(message: string){
|
||||
this.props.plugin.displayNotice(message)
|
||||
}
|
||||
async runCron() {
|
||||
console.log("running cron");
|
||||
try {
|
||||
let response = await makeCronReq(this.username, this.credentials);
|
||||
this.setState({
|
||||
needCron: false,
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
new Notice("There was an error running the cron. Please try again later.");
|
||||
}
|
||||
this.reloadData();
|
||||
}
|
||||
async reloadData() {
|
||||
try {
|
||||
let response = await getStats(this.username, this.credentials);
|
||||
let result = await response.json();
|
||||
if (result.success === false) {
|
||||
new Notice('Login Failed, Please check credentials and try again!');
|
||||
reloadData() {
|
||||
getStats(username, credentials)
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
result => {
|
||||
if(result.success === false){
|
||||
this.sendNotice("Login Failed, Please check credentials and try again!")
|
||||
} else {
|
||||
this.setState({
|
||||
isLoaded: true,
|
||||
user_data: result,
|
||||
tasks: result.tasks,
|
||||
})
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
this.setState({
|
||||
isLoaded: true,
|
||||
error
|
||||
})
|
||||
}
|
||||
else {
|
||||
this.setState({
|
||||
isLoaded: true,
|
||||
user_data: result,
|
||||
tasks: result.tasks,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
new Notice("API Error: Please check credentials")
|
||||
}
|
||||
)
|
||||
}
|
||||
componentDidMount() {
|
||||
this.reloadData()
|
||||
}
|
||||
|
||||
async sendScore(id: string, score: string, message: string) {
|
||||
try {
|
||||
let response = await scoreTask(this.username, this.credentials, id, score);
|
||||
let result = await response.json();
|
||||
if (result.success === true) {
|
||||
new Notice(message);
|
||||
this.reloadData();
|
||||
} else {
|
||||
new Notice("Resyncing, please try again");
|
||||
this.reloadData();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
new Notice("API Error: Please check credentials")
|
||||
}
|
||||
}
|
||||
|
||||
async sendReward(id: string, score: string, message: string) {
|
||||
try {
|
||||
let response = await costReward(this.username, this.credentials, id, score);
|
||||
let result = await response.json();
|
||||
if (result.success === true) {
|
||||
new Notice(message);
|
||||
this.reloadData();
|
||||
} else {
|
||||
new Notice("Resyncing, please try again");
|
||||
this.reloadData();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
new Notice("API Error: Please check credentials")
|
||||
}
|
||||
}
|
||||
|
||||
handleChangeTodos(event: any) {
|
||||
handleChangeTodos(event: any){
|
||||
this.state.tasks.todos.forEach((element: any) => {
|
||||
if (element.id == event.target.id) {
|
||||
if (!element.completed) {
|
||||
this.sendScore(event.target.id, "up", "Checked!")
|
||||
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 {
|
||||
this.sendScore(event.target.id, "down", "Un-Checked!")
|
||||
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)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
handleChangeDailys(event: any) {
|
||||
handleChangeDailys(event: any){
|
||||
this.state.tasks.dailys.forEach((element: any) => {
|
||||
if (element.id == event.target.id) {
|
||||
if (element.id == event.target.id) {
|
||||
if (!element.completed) {
|
||||
this.sendScore(event.target.id, "up", "Checked!")
|
||||
} else {
|
||||
this.sendScore(event.target.id, "down", "Un-Checked!")
|
||||
}
|
||||
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)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
handleChangeHabits(event: any) {
|
||||
handleChangeHabits(event: any){
|
||||
const target_id = event.target.id.slice(4)
|
||||
if (event.target.id.slice(0, 4) == "plus") {
|
||||
console.log(target_id)
|
||||
if(event.target.id.slice(0,4) == "plus"){
|
||||
this.state.tasks.habits.forEach((element: any) => {
|
||||
if (element.id == target_id) {
|
||||
this.sendScore(target_id, "up", "Plus!")
|
||||
if(element.id == target_id){
|
||||
scoreTask(username, credentials, target_id, "up")
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
result => {
|
||||
if(result.success) {
|
||||
this.sendNotice("Plus!")
|
||||
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 {
|
||||
this.state.tasks.habits.forEach((element: any) => {
|
||||
if (element.id == target_id) {
|
||||
this.sendScore(target_id, "down", "Minus :(")
|
||||
if(element.id == target_id){
|
||||
scoreTask(username, credentials, target_id, "down")
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
result => {
|
||||
if(result.success) {
|
||||
this.sendNotice("Minus :(")
|
||||
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)
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
handleChangeRewards(event: any) {
|
||||
const target_id = event.target.id
|
||||
this.state.tasks.rewards.forEach((element: any) => {
|
||||
if (element.id == event.target.id) {
|
||||
if (element.id == target_id) {
|
||||
this.sendReward(target_id, "down", "Redeemed!")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
async handleChangeChecklistItem(event: any){
|
||||
let parentID = event.target.parentNode.parentNode.parentNode.getAttribute("id")
|
||||
let targetID = event.target.id
|
||||
console.log(parentID+ " , " + targetID)
|
||||
try{
|
||||
let response = await scoreChecklistItem(this.username, this.credentials, targetID, parentID);
|
||||
let result = await response.json();
|
||||
if (result.success === true) {
|
||||
new Notice("Checked!");
|
||||
this.reloadData();
|
||||
} else {
|
||||
new Notice("Resyncing, please try again");
|
||||
this.reloadData();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
new Notice("API Error: Please check credentials")
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let content = this.CheckCron(this.state.user_data.lastCron);
|
||||
if (this.state.error)
|
||||
return (<div className="loading">Loading....</div>)
|
||||
else if (!this.state.isLoaded)
|
||||
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">
|
||||
{content}
|
||||
<Statsview className ="stats-view" user_data={this.state.user_data} />
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
||||
<Taskview data={this.state.tasks} handleChangeTodos={this.handleChangeTodos} settings = {this.props.plugin.settings} handleChangeDailys={this.handleChangeDailys} handleChangeHabits={this.handleChangeHabits} handleChangeRewards={this.handleChangeRewards} handleChangeChecklistItem={this.handleChangeChecklistItem}/>
|
||||
|
||||
</div>
|
||||
<Statsview user_data={this.state.user_data} />
|
||||
<Taskview data={this.state.tasks} handleChangeTodos={this.handleChangeTodos} handleChangeDailys={this.handleChangeDailys} handleChangeHabits={this.handleChangeHabits}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,9 @@ 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">HP: {numberWithCommas((props.user_data.stats.hp).toFixed(0))}</div>
|
||||
<div className = "substats" id="lvl">LEVEL: {props.user_data.stats.lvl}</div>
|
||||
<div className = "substats" id="gold">GOLD: {numberWithCommas(props.user_data.stats.gp.toFixed(2))}</div>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
function numberWithCommas(x: any) {
|
||||
return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
|
@ -1,20 +1,10 @@
|
|||
import * as React from "react";
|
||||
import DailySubTasks from "./DailySubTasks";
|
||||
import renderMarkdown from "../markdownRender";
|
||||
import * as React from "react";
|
||||
|
||||
function DailyItem(props: any) {
|
||||
var text_html = renderMarkdown(props.daily_text);
|
||||
var note_html = renderMarkdown(props.daily_notes);
|
||||
return (
|
||||
<div className="todo-item" id={props.id}>
|
||||
<input type="checkbox" className="checkbox" id={props.id} onChange={props.onChange} checked={props.completed} />
|
||||
<div>
|
||||
<p><span dangerouslySetInnerHTML={{__html: text_html}}></span></p>
|
||||
<div className="description" dangerouslySetInnerHTML={{__html: note_html}}></div>
|
||||
{/* {console.log(props.checklist)} */}
|
||||
<DailySubTasks key={props.daily_subtasks.id} subtasks={props.daily_subtasks} onChangeChecklistItem={props.onChangeChecklistItem}></DailySubTasks>
|
||||
</div>
|
||||
|
||||
<input type="checkbox" className="checkbox" id={props.id} onChange={props.onChange} checked={props.completed}/>
|
||||
<p>{props.daily_text}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
import * as React from "react";
|
||||
import renderMarkdown from "../markdownRender";
|
||||
|
||||
function DailySubTasks(props: any) {
|
||||
|
||||
if (props.subtasks) {
|
||||
const subtasks = props.subtasks.map((subtask: any) => {
|
||||
let subtask_text = renderMarkdown(subtask.text);
|
||||
return (
|
||||
<div className="subtask" id={subtask.id} key={subtask.id} >
|
||||
<input id={subtask.id} type="checkbox" className="checkbox-checklist" onChange={props.onChangeChecklistItem} checked={subtask.completed} />
|
||||
<p id={subtask.id}><span dangerouslySetInnerHTML={{__html: subtask_text}}></span></p>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
return subtasks
|
||||
}
|
||||
else {
|
||||
return <div></div>
|
||||
}
|
||||
}
|
||||
export default DailySubTasks
|
||||
|
|
@ -3,89 +3,23 @@ import DailyItem from "./DailyItem"
|
|||
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
|
||||
|
||||
export default function Index(props: any){
|
||||
|
||||
if(props.dailys == undefined) {
|
||||
return <div id="classDisplay">No Dailies Present</div>
|
||||
}
|
||||
else {
|
||||
|
||||
const notDueDailies = props.dailys.map((daily: any) => {
|
||||
|
||||
if (!daily.isDue) {
|
||||
let daily_notes = '';
|
||||
let daily_subtasks = '';
|
||||
if (props.settings.showTaskDescription) {
|
||||
daily_notes = daily.notes;
|
||||
}
|
||||
|
||||
if (props.settings.showSubTasks) {
|
||||
daily_subtasks = daily.checklist;
|
||||
}
|
||||
return <DailyItem key={daily.id} id={daily.id} daily_text={daily.text}
|
||||
daily_notes={daily_notes} daily_subtasks={daily_subtasks}
|
||||
onChange={props.onChange} completed={daily.completed} onChangeChecklistItem={props.onChangeChecklistItem}/>
|
||||
}
|
||||
})
|
||||
|
||||
const incompleteDailies = props.dailys.map((daily: any) => {
|
||||
if (!daily.completed&&daily.isDue) {
|
||||
let daily_notes = '';
|
||||
let daily_subtasks = '';
|
||||
if (props.settings.showTaskDescription) {
|
||||
daily_notes = daily.notes;
|
||||
}
|
||||
|
||||
if (props.settings.showSubTasks) {
|
||||
daily_subtasks = daily.checklist;
|
||||
}
|
||||
return <DailyItem key={daily.id} id={daily.id} daily_text={daily.text}
|
||||
daily_notes={daily_notes} daily_subtasks={daily_subtasks}
|
||||
onChange={props.onChange} completed={daily.completed} onChangeChecklistItem={props.onChangeChecklistItem}/>
|
||||
}
|
||||
})
|
||||
if(!daily.completed)
|
||||
return <DailyItem key={daily.id} id={daily.id}daily_text={daily.text} onChange={props.onChange} completed={daily.completed}/>
|
||||
})
|
||||
const completedDailies = props.dailys.map((daily: any) => {
|
||||
// if(daily.completed)
|
||||
// return <DailyItem key={daily.id} id={daily.id} daily_text={daily.text} daily_notes={daily.notes} onChange={props.onChange} completed={daily.completed}/>
|
||||
if (daily.completed) {
|
||||
let daily_notes = '';
|
||||
let daily_subtasks = '';
|
||||
if (props.settings.showTaskDescription) {
|
||||
daily_notes = daily.notes;
|
||||
}
|
||||
|
||||
if (props.settings.showSubTasks) {
|
||||
daily_subtasks = daily.checklist;
|
||||
}
|
||||
return <DailyItem key={daily.id} id={daily.id} daily_text={daily.text}
|
||||
daily_notes={daily_notes} daily_subtasks={daily_subtasks}
|
||||
onChange={props.onChange} completed={daily.completed} onChangeChecklistItem={props.onChangeChecklistItem}/>
|
||||
}
|
||||
if(daily.completed)
|
||||
return <DailyItem key={daily.id} id={daily.id}daily_text={daily.text} onChange={props.onChange} completed={daily.completed}/>
|
||||
})
|
||||
|
||||
const allDailies = props.dailys.map((daily: any) => {
|
||||
// if(daily.completed)
|
||||
// return <DailyItem key={daily.id} id={daily.id} daily_text={daily.text} daily_notes={daily.notes} onChange={props.onChange} completed={daily.completed}/>
|
||||
let daily_notes = '';
|
||||
let daily_subtasks = '';
|
||||
if (props.settings.showTaskDescription) {
|
||||
daily_notes = daily.notes;
|
||||
}
|
||||
|
||||
if (props.settings.showSubTasks) {
|
||||
daily_subtasks = daily.checklist;
|
||||
}
|
||||
return <DailyItem key={daily.id} id={daily.id} daily_text={daily.text}
|
||||
daily_notes={daily_notes} daily_subtasks={daily_subtasks}
|
||||
onChange={props.onChange} completed={daily.completed} onChangeChecklistItem={props.onChangeChecklistItem}/>
|
||||
})
|
||||
|
||||
const display = <div id="classDisplay">
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab>Active</Tab>
|
||||
<Tab>Completed</Tab>
|
||||
<Tab>Not Due</Tab>
|
||||
<Tab>All</Tab>
|
||||
</TabList>
|
||||
<TabPanel>
|
||||
<ul>{incompleteDailies}</ul>
|
||||
|
|
@ -93,15 +27,10 @@ export default function Index(props: any){
|
|||
<TabPanel>
|
||||
<ul>{completedDailies}</ul>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<ul>{notDueDailies}</ul>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<ul>{allDailies}</ul>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</div>
|
||||
return(display);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
56
src/view/Components/Taskview/Dailiesview/react-tabs.css
Normal file
56
src/view/Components/Taskview/Dailiesview/react-tabs.css
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
.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
src/view/Components/Taskview/Dailiesview/tabs.ts
Normal file
1
src/view/Components/Taskview/Dailiesview/tabs.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
import * as React from "react"
|
||||
|
|
@ -1,23 +1,15 @@
|
|||
import * as React from "react";
|
||||
import renderMarkdown from "../markdownRender";
|
||||
import * as React from "react";
|
||||
|
||||
function HabitItem(props: any) {
|
||||
let habit_text = renderMarkdown(props.habit_text);
|
||||
let habit_notes = renderMarkdown(props.habit_notes);
|
||||
return (
|
||||
<div className="habit-item" id={props.id}>
|
||||
<div className="habit-button-grp">
|
||||
<button className="habit-button" id={"plus" + props.id} onClick={props.onChange}>
|
||||
+{props.upCount}
|
||||
</button>
|
||||
<button className="habit-button" id={"mins" + props.id} onClick={props.onChange}>
|
||||
-{props.downCount}
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="habit-text"><span dangerouslySetInnerHTML={{__html: habit_text}}></span></p>
|
||||
<div className="description" dangerouslySetInnerHTML={{__html: habit_notes}}></div>
|
||||
</div>
|
||||
<button className="habit-plus" id={"plus"+props.id} onClick={props.onChange}>
|
||||
+{props.upCount}
|
||||
</button>
|
||||
<p className="habit-text">{props.habit_text}</p>
|
||||
<button className="habit-minus" id={"mins"+props.id} onClick={props.onChange}>
|
||||
-{props.downCount}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,9 @@ export default function Index(props: any){
|
|||
</div>)
|
||||
}
|
||||
else {
|
||||
console.log("habits = " + props.habits);
|
||||
const allHabits = props.habits.map((habit: any) => {
|
||||
if (props.settings.showTaskDescription) {
|
||||
return <HabitItem key={habit.id} id={habit.id} habit_text={habit.text} habit_notes={habit.notes} upCount={habit.counterUp} downCount={habit.counterDown} onChange={props.onChange}/>
|
||||
} else {
|
||||
return <HabitItem key={habit.id} id={habit.id} habit_text={habit.text} upCount={habit.counterUp} downCount={habit.counterDown} onChange={props.onChange}/>
|
||||
}
|
||||
return <HabitItem key={habit.id} id={habit.id} habit_text={habit.text} upCount={habit.counterUp} downCount={habit.counterDown} onChange={props.onChange}/>
|
||||
})
|
||||
const display = <div id="classDisplay">
|
||||
<ul>{allHabits}</ul>
|
||||
|
|
|
|||
56
src/view/Components/Taskview/Habitsview/react-tabs.css
Normal file
56
src/view/Components/Taskview/Habitsview/react-tabs.css
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
.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
src/view/Components/Taskview/Habitsview/tabs.ts
Normal file
1
src/view/Components/Taskview/Habitsview/tabs.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
import * as React from "react"
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import * as React from "react";
|
||||
import renderMarkdown from "../markdownRender";
|
||||
|
||||
function RewardItem(props: any) {
|
||||
let reward_text = renderMarkdown(props.reward_text);
|
||||
let reward_notes = renderMarkdown(props.reward_notes);
|
||||
return (
|
||||
<div className="habit-item" id={props.id}>
|
||||
<div className="habit-button-grp">
|
||||
<button className="habit-button" id={props.id} onClick={props.onChange}>-{props.reward_value}</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="habit-text"><span dangerouslySetInnerHTML={{__html: reward_text}}></span></p>
|
||||
<div className="description" dangerouslySetInnerHTML={{__html: reward_notes}}></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RewardItem
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
import * as React from "react";
|
||||
import RewardItem from "./RewardItem"
|
||||
|
||||
export default function Index(props: any){
|
||||
if(props.rewards == undefined) {
|
||||
return (<div id="classDisplay">
|
||||
No Rewards present.
|
||||
</div>)
|
||||
}
|
||||
else {
|
||||
const allRewards = props.rewards.map((reward: any) => {
|
||||
if (props.settings.showTaskDescription) {
|
||||
return <RewardItem key={reward.id} id={reward.id} reward_text={reward.text} reward_notes={reward.notes} reward_value={reward.value} onChange={props.onChange}/>
|
||||
} else {
|
||||
return <RewardItem key={reward.id} id={reward.id} reward_text={reward.text} reward_value={reward.value} onChange={props.onChange}/>
|
||||
}
|
||||
})
|
||||
const display = <div id="classDisplay">
|
||||
<ul>{allRewards}</ul>
|
||||
</div>
|
||||
|
||||
return(display);
|
||||
}
|
||||
}
|
||||
|
||||
12
src/view/Components/Taskview/TodoItem.tsx
Normal file
12
src/view/Components/Taskview/TodoItem.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
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,21 +1,10 @@
|
|||
import * as React from "react";
|
||||
import TodoSubTasks from "./TodoSubTasks";
|
||||
import renderMarkdown from "../markdownRender"
|
||||
import moment from "moment";
|
||||
import * as React from "react";
|
||||
|
||||
function TodoItem(props: any) {
|
||||
var dueDate = (props.dueDate==null)?"":("Due Date:"+(moment(props.dueDate).format(props.dueDateFormat)));
|
||||
var text_html = renderMarkdown(props.todo_text);
|
||||
var note_html = renderMarkdown(props.todo_notes);
|
||||
return (
|
||||
<div className="todo-item" id={props.id}>
|
||||
<input type="checkbox" className="checkbox" id={props.id} onChange={props.onChange} checked={props.completed}/>
|
||||
<div>
|
||||
<p><span dangerouslySetInnerHTML={{__html: text_html}}></span></p>
|
||||
<div className="description" dangerouslySetInnerHTML={{__html: note_html}}></div>
|
||||
<TodoSubTasks todoID={props.id} subtasks={props.todo_subtasks} onChange={props.onChangeChecklistItem}></TodoSubTasks>
|
||||
<div className="due-date">{dueDate}</div>
|
||||
</div>
|
||||
<p>{props.todo_text}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
import * as React from "react";
|
||||
import renderMarkdown from "../markdownRender";
|
||||
|
||||
function TodoSubTasks(props: any) {
|
||||
if (props.subtasks) {
|
||||
const subtasks = props.subtasks.map((subtask: any) => {
|
||||
let subtask_text = renderMarkdown(subtask.text);
|
||||
return (
|
||||
<div className="subtask" id={subtask.id} key={subtask.id}>
|
||||
<input type="checkbox" className="checkbox" onChange={props.onChange} checked={subtask.completed} id={subtask.id}/>
|
||||
<p id={subtask.id}><span dangerouslySetInnerHTML={{__html: subtask_text}}></span></p>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
return subtasks
|
||||
}
|
||||
else {
|
||||
return <div></div>
|
||||
}
|
||||
}
|
||||
export default TodoSubTasks
|
||||
|
|
@ -8,26 +8,12 @@ export default function Index(props: any){
|
|||
}
|
||||
else {
|
||||
const incompleteTodos = props.todos.map((todo: any) => {
|
||||
|
||||
if(!todo.completed) {
|
||||
let todo_notes = '';
|
||||
let todo_subtasks = '';
|
||||
if (props.settings.showTaskDescription) {
|
||||
todo_notes = todo.notes;
|
||||
}
|
||||
|
||||
if (props.settings.showSubTasks) {
|
||||
todo_subtasks = todo.checklist;
|
||||
}
|
||||
return <TodoItem key={todo.id} id={todo.id} todo_text={todo.text}
|
||||
todo_notes={todo_notes} todo_subtasks={todo_subtasks}
|
||||
onChange={props.onChange} onChangeChecklistItem={props.onChangeChecklistItem} completed={todo.completed} dueDate={todo.date} dueDateFormat={props.settings.dueDateFormat}/>
|
||||
}
|
||||
|
||||
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} todo_notes={todo.notes} onChange={props.onChange} completed={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>
|
||||
|
|
@ -36,10 +22,10 @@ export default function Index(props: any){
|
|||
<Tab>Completed</Tab>
|
||||
</TabList>
|
||||
<TabPanel>
|
||||
<ul className="todolist-indent">{incompleteTodos}</ul>
|
||||
<ul>{incompleteTodos}</ul>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<ul className="todolist-indent">{completedTodos}</ul>
|
||||
<ul>{completedTodos}</ul>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
|
|
|||
58
src/view/Components/Taskview/Todoview/react-tabs.css
Normal file
58
src/view/Components/Taskview/Todoview/react-tabs.css
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
.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;
|
||||
}
|
||||
|
||||
.re
|
||||
|
||||
.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
src/view/Components/Taskview/Todoview/tabs.ts
Normal file
1
src/view/Components/Taskview/Todoview/tabs.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
import * as React from "react"
|
||||
|
|
@ -2,41 +2,33 @@ import * as React from "react";
|
|||
import Dailiesview from "./Dailiesview"
|
||||
import Habitsview from "./Habitsview"
|
||||
import Todoview from "./Todoview"
|
||||
import Rewardview from "./Rewardview"
|
||||
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
|
||||
|
||||
export default function Index(props: any){
|
||||
const display = <div className="task-view">
|
||||
<Tabs>
|
||||
<TabList>
|
||||
|
||||
<Tab >
|
||||
<span className="material-icons md-24">task_alt</span>
|
||||
</Tab>
|
||||
<Tab>
|
||||
<span className="material-icons md-24">today</span>
|
||||
</Tab>
|
||||
<Tab >
|
||||
<span className="material-icons md-24">add_chart</span>
|
||||
</Tab>
|
||||
<Tab>
|
||||
<span className="material-icons md-24">assignment_turned_in</span>
|
||||
</Tab>
|
||||
<Tab>
|
||||
<span className="material-icons md-24">account_balance</span>
|
||||
<span className="material-icons md-24">add_circle_outline</span>
|
||||
</Tab>
|
||||
</TabList>
|
||||
<TabPanel>
|
||||
<Dailiesview dailys={props.data.dailys} settings = {props.settings} onChange={props.handleChangeDailys} onChangeChecklistItem={props.handleChangeChecklistItem}/>
|
||||
<Habitsview habits={props.data.habits} onChange={props.handleChangeHabits}/>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<Habitsview habits={props.data.habits} settings = {props.settings} onChange={props.handleChangeHabits}/>
|
||||
<Dailiesview dailys={props.data.dailys} onChange={props.handleChangeDailys} />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<Todoview todos={props.data.todos} settings = {props.settings} onChange={props.handleChangeTodos} onChangeChecklistItem={props.handleChangeChecklistItem}/>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<Rewardview rewards={props.data.rewards} settings = {props.settings} onChange={props.handleChangeRewards} />
|
||||
<Todoview todos={props.data.todos} onChange={props.handleChangeTodos} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</div>
|
||||
return(display);
|
||||
}
|
||||
} //yes
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
import MarkdownIt from "markdown-it";
|
||||
import markdownitEmoji from "markdown-it-emoji"
|
||||
import twemoji from "twemoji";
|
||||
|
||||
export default function renderMarkdown(markdown: string) {
|
||||
//check if markdown is empty or not a string
|
||||
if (markdown === "" || markdown === undefined) {
|
||||
return "";
|
||||
}
|
||||
const md = new MarkdownIt({
|
||||
html: true,
|
||||
breaks: true,
|
||||
linkify: true,
|
||||
typographer: true
|
||||
});
|
||||
md.use(markdownitEmoji);
|
||||
md.renderer.rules.emoji = function(token, idx) {
|
||||
return twemoji.parse(token[idx].content);
|
||||
};
|
||||
return md.render(markdown);
|
||||
}
|
||||
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
export async function getStats(username: string, credentials: string){
|
||||
const url = "https://habitica.com/export/userdata.json"
|
||||
const response = await fetch(url, {
|
||||
const response = fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client": "278e719e-5f9c-43b1-9dba-8b73343dc062-HabiticaSync",
|
||||
"x-client": username.concat("-testAPI"),
|
||||
"x-api-user": username,
|
||||
"x-api-key": credentials,
|
||||
},
|
||||
})
|
||||
return (await response)
|
||||
return (response)
|
||||
}
|
||||
|
||||
export async function scoreTask(username: string, credentials: string, taskID: string, direction: string) {
|
||||
|
|
@ -20,48 +20,7 @@ export async function scoreTask(username: string, credentials: string, taskID: s
|
|||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client": "278e719e-5f9c-43b1-9dba-8b73343dc062-HabiticaSync",
|
||||
"x-api-user": username,
|
||||
"x-api-key": credentials,
|
||||
}
|
||||
})
|
||||
return(response)
|
||||
}
|
||||
export async function makeCronReq(username: string, credentials: string){
|
||||
const url = "https://habitica.com/api/v3/cron";
|
||||
const response = fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client": "278e719e-5f9c-43b1-9dba-8b73343dc062-HabiticaSync",
|
||||
"x-api-user": username,
|
||||
"x-api-key": credentials,
|
||||
}
|
||||
})
|
||||
return(response)
|
||||
}
|
||||
|
||||
export async function costReward(username: string, credentials: string, taskID: string, direction: string) {
|
||||
const url = "https://habitica.com/api/v4/tasks/".concat(taskID).concat("/score/").concat(direction)
|
||||
const response = fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client": "278e719e-5f9c-43b1-9dba-8b73343dc062-HabiticaSync",
|
||||
"x-api-user": username,
|
||||
"x-api-key": credentials,
|
||||
}
|
||||
})
|
||||
return(response)
|
||||
}
|
||||
|
||||
export async function scoreChecklistItem(username: string, credentials: string, checklistItemID: string, taskID: string) {
|
||||
const url = "https://habitica.com/api/v3/tasks/".concat(taskID).concat("/checklist/").concat(checklistItemID).concat("/score")
|
||||
const response = fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client": "278e719e-5f9c-43b1-9dba-8b73343dc062-HabiticaSync",
|
||||
"x-client": username.concat("-testAPI"),
|
||||
"x-api-user": username,
|
||||
"x-api-key": credentials,
|
||||
}
|
||||
|
|
|
|||
474
styles.css
474
styles.css
|
|
@ -1,323 +1,151 @@
|
|||
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@1,300&display=swap');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Open Sans:ital,wght@0,400;1,100&family=Roboto&display=swap');
|
||||
|
||||
.add-task-input {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#profile-name {
|
||||
font-size: x-large;
|
||||
font-weight: bold;
|
||||
padding-bottom: 3%;
|
||||
}
|
||||
.stats {
|
||||
width: 95%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-weight: bold;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.stats-view {
|
||||
border-bottom: 1px;
|
||||
}
|
||||
.modify-todo {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.delete-todo {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.todo-item {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 30fr 1fr 1fr;
|
||||
justify-content: left;
|
||||
align-items: flex-start;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #cecece;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-family: Open Sans, sans-serif;
|
||||
font-weight: 100;
|
||||
}
|
||||
.description > ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.habit-text {
|
||||
text-align: left !important;
|
||||
font-weight: bold;
|
||||
padding-top: 5px;
|
||||
width: 80%;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.habit-button {
|
||||
background-color: var(--interactive-accent);
|
||||
border: none;
|
||||
/* color: black; */
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
display: block;
|
||||
width: 100%;
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
/* habit-button on hover css selector */
|
||||
.habit-button:hover {
|
||||
color: var(--text-on-accent);
|
||||
background-color: var(--interactive-accent-hover);
|
||||
}
|
||||
|
||||
.habit-item {
|
||||
display: flex;
|
||||
grid-template-columns: 60px 1fr;
|
||||
width: 100%;
|
||||
gap: 5px;
|
||||
border-bottom: 1px solid #cecece;
|
||||
font-family: Open Sans, sans-serif;
|
||||
font-weight: 100%;
|
||||
font-size: 16px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.habit-button-grp {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-content: stretch;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
margin-right: 10px;
|
||||
margin-top: 5px;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.todo-content {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
/* padding: 5px 5px; */
|
||||
font-size: 15px;
|
||||
border: 1px solid #aaa;
|
||||
/* white-space: nowrap; */
|
||||
/* margin: 10px; */
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type=checkbox]:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
display: none; /* Chrome Safari */
|
||||
}
|
||||
|
||||
.plugin-root {
|
||||
min-width: 260px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
#classDisplay {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.view-content {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.substats {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* react-tabs internal file :wink: */
|
||||
.material-icons {
|
||||
font-size: 12px !important;
|
||||
padding-top: 1px;
|
||||
padding-right: 2px;
|
||||
|
||||
}
|
||||
|
||||
.material-icons.md-18 { font-size: 18px !important; }
|
||||
.material-icons.md-24 { font-size: 24px !important; }
|
||||
.material-icons.md-32 { font-size: 32px !important; }
|
||||
.material-icons.md-48 { font-size: 48px !important; }
|
||||
|
||||
|
||||
.react-tabs {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.react-tabs__tab-list {
|
||||
border-bottom: 1px solid #aaa;
|
||||
margin: 0 0 5px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.react-tabs__tab {
|
||||
display: inline-block;
|
||||
border: 1px solid transparent;
|
||||
border-bottom: none;
|
||||
bottom: -1px;
|
||||
position: relative;
|
||||
list-style: none;
|
||||
padding: 1% 2%;
|
||||
cursor: pointer;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.react-tabs__tab--selected {
|
||||
background: var(--interactive-accent);
|
||||
color: white;
|
||||
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;
|
||||
left: 0px;
|
||||
height: 88%;
|
||||
/* overflow: scroll; */
|
||||
}
|
||||
|
||||
.task-panel {
|
||||
overflow: scroll;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.react-tabs__tab-panel--selected {
|
||||
display: block;
|
||||
}
|
||||
ul li:not(.task-list-item)::before {
|
||||
content: "•";
|
||||
color: transparent;
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
margin-left: -1em;
|
||||
padding: 0;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 0 0.5em transparent;
|
||||
}
|
||||
|
||||
.task-operation {
|
||||
align-self: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.edit-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.edit-button {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.task-submit {
|
||||
display: grid;
|
||||
grid-template-columns: 10fr 5fr;
|
||||
}
|
||||
|
||||
.add-task-input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.task-input-box {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: auto;
|
||||
margin-bottom: 5px;
|
||||
white-space: nowrap;
|
||||
padding: 5px 5px;
|
||||
margin-right: 0;
|
||||
}
|
||||
.cron {
|
||||
display: inline-grid;
|
||||
justify-content: center;
|
||||
text-align: center;;
|
||||
margin-top: 5px;
|
||||
margin-left: 10%;
|
||||
margin-right: 10%;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
#cronMessage {
|
||||
margin: 20px;
|
||||
margin-bottom: 10px;
|
||||
color: var(--text-normal)
|
||||
}
|
||||
#cronButton {
|
||||
margin: auto;
|
||||
margin-bottom: 5px;
|
||||
white-space: nowrap;
|
||||
padding: 5px 5px;
|
||||
background-color: var(--interactive-accent);
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.subtask {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-weight: normal;
|
||||
font-family: Roboto, sans-serif;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.emoji {
|
||||
height: 1em;
|
||||
}
|
||||
.description>ul {
|
||||
list-style-type: disc;
|
||||
margin-left: 10% !important;
|
||||
}
|
||||
|
||||
#profile-name {
|
||||
font-size: x-large;
|
||||
font-weight: bold;
|
||||
padding-bottom: 3%;
|
||||
}
|
||||
.stats {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.todo-item {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 0px 0px 0;
|
||||
width: 80%;
|
||||
border-bottom: 1px solid #cecece;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.habit-text {
|
||||
text-align: center !important;
|
||||
padding: 0px;
|
||||
width: 80px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.habit-plus {
|
||||
/* background-color: #fff; */
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 7px 10px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.habit-minus {
|
||||
/* background-color: #fff; */
|
||||
/* border-radius: 50%; */
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 7px 10px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.habit-item {
|
||||
display: flex;
|
||||
/* justify-content: center; */
|
||||
align-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0px 0px 0;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #cecece;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: 50%;
|
||||
font-size: 16px;
|
||||
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
input[type=checkbox]:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.plugin-root {
|
||||
min-width: 260px;
|
||||
}
|
||||
|
||||
.substats {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
/* react-tabs internal file :wink: */
|
||||
.material-icons {
|
||||
font-size: 12px !important;
|
||||
padding-top: 1px;
|
||||
padding-right: 2px;
|
||||
|
||||
}
|
||||
|
||||
.material-icons.md-18 { font-size: 18px !important; }
|
||||
.material-icons.md-24 { font-size: 24px !important; }
|
||||
.material-icons.md-32 { font-size: 32px !important; }
|
||||
.material-icons.md-48 { font-size: 48px !important; }
|
||||
|
||||
|
||||
.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: 1% 2%;
|
||||
cursor: pointer;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.react-tabs__tab--selected {
|
||||
background: var(--interactive-accent);
|
||||
color: white;
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@
|
|||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"es5",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue