mirror of
https://github.com/ericaxu/gemmy.git
synced 2026-07-22 07:30:31 +00:00
Compare commits
12 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6916db84b | ||
|
|
195e4df1b6 | ||
|
|
831826d071 | ||
|
|
c1d71da4f9 | ||
|
|
6e2384a001 | ||
|
|
75d05be5c8 | ||
|
|
1e80fe564f | ||
|
|
0f9a59d97e | ||
|
|
37123587c6 | ||
|
|
6303889f2e | ||
|
|
f4f5958f11 | ||
|
|
a50e64b8bf |
5 changed files with 86 additions and 113 deletions
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Erica Xu
|
||||||
|
|
||||||
|
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.
|
||||||
97
README.md
97
README.md
|
|
@ -1,96 +1,45 @@
|
||||||
# Obsidian Sample Plugin
|
# Gemmy - Obsidian Unhelper
|
||||||
|
|
||||||
This is a sample plugin for Obsidian (https://obsidian.md).
|
<img src="https://user-images.githubusercontent.com/1171143/229297707-5efa8761-ef55-4d01-a105-88a347bc6cf0.png" width="300">
|
||||||
|
|
||||||
This project uses Typescript to provide type checking and documentation.
|
Not sure if an AI assistant is going to be helpful in your workflow?
|
||||||
The repo depends on the latest plugin API (obsidian.d.ts) in Typescript Definition format, which contains TSDoc comments describing what it does.
|
|
||||||
|
|
||||||
**Note:** The Obsidian API is still in early alpha and is subject to change at any time!
|
Don't worry, we've eliminated the guesswork for you because Gemmy is 100% going to be unhelpful.
|
||||||
|
|
||||||
This sample plugin demonstrates some of the basic functionality the plugin API can do.
|
Introducing Obsidian's first assistant — Gemmy, the Obsidian Unhelper. It has two major features:
|
||||||
- Changes the default font color to red using `styles.css`.
|
|
||||||
- Adds a ribbon icon, which shows a Notice when clicked.
|
|
||||||
- Adds a command "Open Sample Modal" which opens a Modal.
|
|
||||||
- Adds a plugin setting tab to the settings page.
|
|
||||||
- Registers a global click event and output 'click' to the console.
|
|
||||||
- Registers a global interval which logs 'setInterval' to the console.
|
|
||||||
|
|
||||||
## First time developing plugins?
|
## Randomly saying things
|
||||||
|
|
||||||
Quick starting guide for new plugin devs:
|
Gemmy seeks validation by randomly saying things every now and then.
|
||||||
|
|
||||||
- Check if [someone already developed a plugin for what you want](https://obsidian.md/plugins)! There might be an existing plugin similar enough that you can partner up with.
|
You can customize how often this happens. Or just don't summon Gemmy.
|
||||||
- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it).
|
|
||||||
- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder.
|
|
||||||
- Install NodeJS, then run `npm i` in the command line under your repo folder.
|
|
||||||
- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`.
|
|
||||||
- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`.
|
|
||||||
- Reload Obsidian to load the new version of your plugin.
|
|
||||||
- Enable plugin in settings window.
|
|
||||||
- For updates to the Obsidian API run `npm update` in the command line under your repo folder.
|
|
||||||
|
|
||||||
## Releasing new releases
|
## Writing mode
|
||||||
|
|
||||||
- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release.
|
Gemmy pops out to [motivate you](https://user-images.githubusercontent.com/1171143/229297494-8a0cae3f-4c8e-47a9-801b-dd1c52dfc917.png) when you have stopped typing for long enough. Again, you can customize how long that should be.
|
||||||
- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible.
|
|
||||||
- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases
|
|
||||||
- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments. Note: The manifest.json file must be in two places, first the root path of your repository and also in the release.
|
|
||||||
- Publish the release.
|
|
||||||
|
|
||||||
> You can simplify the version bump process by running `npm version patch`, `npm version minor` or `npm version major` after updating `minAppVersion` manually in `manifest.json`.
|
Risk: Gemmy might actually be helpful with writing if you use this mode. We're not responsible for any extra productivity Gemmy might bring.
|
||||||
> The command will bump version in `manifest.json` and `package.json`, and add the entry for the new version to `versions.json`
|
|
||||||
|
|
||||||
## Adding your plugin to the community plugin list
|
|
||||||
|
|
||||||
- Check https://github.com/obsidianmd/obsidian-releases/blob/master/plugin-review.md
|
|
||||||
- Publish an initial version.
|
|
||||||
- Make sure you have a `README.md` file in the root of your repo.
|
|
||||||
- Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin.
|
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
- Clone this repo.
|
Install Gemmy. There are four commands in the command palette when you type "Gemmy". You can figure out the rest on your own.
|
||||||
- `npm i` or `yarn` to install dependencies
|
|
||||||
- `npm run dev` to start compilation in watch mode.
|
|
||||||
|
|
||||||
## Manually installing the plugin
|
---
|
||||||
|
|
||||||
- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`.
|
Special thanks: [Rigmarole](https://rigmarolestudio.com/) for creating and animating Gemmy
|
||||||
|
|
||||||
## Improve code quality with eslint (optional)
|
Credit: the talented Obsidian mods team, including argentum, CawlinTeffid, cotmax, Eleanor Konik, koala, Leah, rigmarole, ryanjamurphy & WhiteNoise
|
||||||
- [ESLint](https://eslint.org/) is a tool that analyzes your code to quickly find problems. You can run ESLint against your plugin to find common bugs and ways to improve your code.
|
|
||||||
- To use eslint with this project, make sure to install eslint from terminal:
|
|
||||||
- `npm install -g eslint`
|
|
||||||
- To use eslint to analyze this project use this command:
|
|
||||||
- `eslint main.ts`
|
|
||||||
- eslint will then create a report with suggestions for code improvement by file and line number.
|
|
||||||
- If your source code is in a folder, such as `src`, you can use eslint with this command to analyze all files in that folder:
|
|
||||||
- `eslint .\src\`
|
|
||||||
|
|
||||||
## Funding URL
|
The code is under MIT license, whereas the Gemmy character is under CC BY 3.0 license.
|
||||||
|
|
||||||
You can include funding URLs where people who use your plugin can financially support it.
|
Obsidian logo is adapted from:
|
||||||
|
|
||||||
The simple way is to set the `fundingUrl` field to your link in your `manifest.json` file:
|
[Crystal shard icon](https://icon-icons.com/icon/Crystal-Shard/88819)
|
||||||
|
By [Chanut is Industries](https://icon-icons.com/users/W52nHhY3W1VlvwyJTwS4d/icon-sets/)
|
||||||
|
License: Attribution 3.0 Unported (CC BY 3.0)
|
||||||
|
|
||||||
```json
|
---
|
||||||
{
|
|
||||||
"fundingUrl": "https://buymeacoffee.com"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If you have multiple URLs, you can also do:
|
## Happy April Fools'
|
||||||
|
|
||||||
```json
|
Gemmy was proudly released on April 1, 2023.
|
||||||
{
|
|
||||||
"fundingUrl": {
|
|
||||||
"Buy Me a Coffee": "https://buymeacoffee.com",
|
|
||||||
"GitHub Sponsor": "https://github.com/sponsors",
|
|
||||||
"Patreon": "https://www.patreon.com/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## API Documentation
|
|
||||||
|
|
||||||
See https://github.com/obsidianmd/obsidian-api
|
|
||||||
|
|
|
||||||
68
main.ts
68
main.ts
|
|
@ -7,18 +7,16 @@ import LOOK_MOTION from './animations/gemmy_lookAround.gif'
|
||||||
import IDLE_MOTION from './animations/gemmy_idle.gif'
|
import IDLE_MOTION from './animations/gemmy_idle.gif'
|
||||||
import DISAPPOINT_IMG from './animations/gemmy_disappoint.gif'
|
import DISAPPOINT_IMG from './animations/gemmy_disappoint.gif'
|
||||||
|
|
||||||
// Remember to rename these classes and interfaces!
|
|
||||||
|
|
||||||
interface GemmySettings {
|
interface GemmySettings {
|
||||||
// how often does Gemmy talk in idle mode, in minutes
|
// how often does Gemmy talk in idle mode, in minutes
|
||||||
idleTalkFrequency: number;
|
idleTalkFrequency: number;
|
||||||
// the number of minutes you must write before Gemmy appears to mock you
|
// the number of minutes you must write before Gemmy appears to mock you
|
||||||
writingModeDeadline: number;
|
writingModeGracePeriod: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_SETTINGS: GemmySettings = {
|
const DEFAULT_SETTINGS: GemmySettings = {
|
||||||
idleTalkFrequency: 5,
|
idleTalkFrequency: 5,
|
||||||
writingModeDeadline: 5
|
writingModeGracePeriod: 5
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -28,27 +26,29 @@ const GEMMY_IDLE_QUOTES = [
|
||||||
"You have plugins that you can update!",
|
"You have plugins that you can update!",
|
||||||
"Hi I'm Gemmy! Like Clippy but shinier!",
|
"Hi I'm Gemmy! Like Clippy but shinier!",
|
||||||
"Everything is connected. Everything.",
|
"Everything is connected. Everything.",
|
||||||
`It looks like you’re writing a note.,
|
"Can’t decide which note to work on? Try the Random Note core plugin!",
|
||||||
|
"Are you sure you don’t want to upload all your notes just so we can chat?",
|
||||||
Would you like help?
|
"How tall would all your notes be if you stacked them up?",
|
||||||
- Get help with writing the note
|
"Wanna teach me to say things? Find me on GitHub and open a pull request!",
|
||||||
- Just type the note without help
|
"Have you considered using Comic Sans?",
|
||||||
- [ ] Don’t show me this tip again`,
|
"A blank page is just a masterpiece in waiting"
|
||||||
'Can’t decide which note to work on? Try the Random Note core plugin!',
|
|
||||||
'Are you sure you don’t want to upload all your notes just so we can chat?',
|
|
||||||
'How tall would all your notes be if you stacked them up?',
|
|
||||||
'Wanna teach me to say things? Find me on GitHub and open a pull request!',
|
|
||||||
'Have you considered using Comic Sans?'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const WRITING_MODE_QUOTES = [
|
const WRITING_MODE_QUOTES = [
|
||||||
`Is that the best you can do? Keep writing!`,
|
"Is that the best you can do? Keep writing!",
|
||||||
`Write first, editor later.`,
|
"Write first, edit later.",
|
||||||
`I love hearing your keyboard. Don't stop.`,
|
"I love hearing your keyboard. Don't stop.",
|
||||||
`How about we review some old notes today?`,
|
"How about we review some old notes today?",
|
||||||
`Stuck? Try journaling what happened today and see if that gives you inspiration.`,
|
"Stuck? Try journaling what happened today and see if that gives you inspiration.",
|
||||||
`Maybe it's time to go get some water or coffee.`,
|
"Maybe it's time to go get some water or coffee.",
|
||||||
`Anything is better than a blank page, even me. Write something!`
|
"Anything is better than a blank page, even me. Write something!",
|
||||||
|
"Oh, taking a break? Don’t let the ideas get cold!",
|
||||||
|
"What’s this? Writer’s block already?",
|
||||||
|
"You’ve got this! Every keystroke is a step closer to brilliance.",
|
||||||
|
"You’re doing amazing! Keep the momentum going.",
|
||||||
|
"Bold choice to open Obsidian and then do absolutely nothing.",
|
||||||
|
"Is this a journal or a staring contest with the cursor?",
|
||||||
|
"Hmm, I didn’t realize staring at the screen was a new note-taking strategy."
|
||||||
];
|
];
|
||||||
|
|
||||||
const BUBBLE_DURATION = 5000;
|
const BUBBLE_DURATION = 5000;
|
||||||
|
|
@ -70,7 +70,7 @@ export default class Gemmy extends Plugin {
|
||||||
gemmyEl.setAttribute('aria-label-delay', '0');
|
gemmyEl.setAttribute('aria-label-delay', '0');
|
||||||
gemmyEl.setAttribute('aria-label-classes', 'gemmy-tooltip');
|
gemmyEl.setAttribute('aria-label-classes', 'gemmy-tooltip');
|
||||||
|
|
||||||
let gemmyImageEl = this.imageEl = gemmyEl.createEl('img', {});
|
this.imageEl = gemmyEl.createEl('img', {});
|
||||||
|
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: 'show',
|
id: 'show',
|
||||||
|
|
@ -136,6 +136,8 @@ export default class Gemmy extends Plugin {
|
||||||
this.disappear();
|
this.disappear();
|
||||||
this.setWritingModeTimeout();
|
this.setWritingModeTimeout();
|
||||||
}, 500)));
|
}, 500)));
|
||||||
|
|
||||||
|
app.workspace.onLayoutReady(this.appear.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
appear() {
|
appear() {
|
||||||
|
|
@ -143,18 +145,14 @@ export default class Gemmy extends Plugin {
|
||||||
|
|
||||||
imageEl.setAttribute('src', EMERGE_MOTION);
|
imageEl.setAttribute('src', EMERGE_MOTION);
|
||||||
|
|
||||||
// Quick if we're in writing mode
|
// Quicker if we're in writing mode
|
||||||
if (this.inWritingMode) {
|
if (this.inWritingMode) {
|
||||||
imageEl.setAttribute('src', POP_MOTION);
|
imageEl.setAttribute('src', POP_MOTION);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// imageEl.setAttribute('src', DISAPPOINT_IMG);
|
|
||||||
// setTimeout(() => {
|
|
||||||
// imageEl.setAttribute('src', DISAPPOINT_IMG);
|
|
||||||
this.appeared = true;
|
this.appeared = true;
|
||||||
|
|
||||||
this.saySomething(WRITING_MODE_QUOTES, true);
|
this.saySomething(WRITING_MODE_QUOTES, true);
|
||||||
// }, 1000);
|
|
||||||
}, 1800);
|
}, 1800);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -185,7 +183,6 @@ export default class Gemmy extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
enterWritingMode() {
|
enterWritingMode() {
|
||||||
let { gemmyEl } = this;
|
|
||||||
this.inWritingMode = true;
|
this.inWritingMode = true;
|
||||||
|
|
||||||
this.disappear();
|
this.disappear();
|
||||||
|
|
@ -211,7 +208,7 @@ export default class Gemmy extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.appear();
|
this.appear();
|
||||||
}, this.settings.writingModeDeadline * 60000);
|
}, this.settings.writingModeGracePeriod * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
startNextIdleTimeout() {
|
startNextIdleTimeout() {
|
||||||
|
|
@ -264,7 +261,7 @@ export default class Gemmy extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
onunload() {
|
onunload() {
|
||||||
|
this.disappear();
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadSettings() {
|
async loadSettings() {
|
||||||
|
|
@ -276,7 +273,6 @@ export default class Gemmy extends Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: proper setting tab
|
|
||||||
class GemmySettingTab extends PluginSettingTab {
|
class GemmySettingTab extends PluginSettingTab {
|
||||||
plugin: Gemmy;
|
plugin: Gemmy;
|
||||||
|
|
||||||
|
|
@ -304,13 +300,13 @@ class GemmySettingTab extends PluginSettingTab {
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Writing mode grace period')
|
.setName('Writing mode grace period')
|
||||||
.setDesc('How soon Gemmy starts to get disappointed after you stop tying in writing mode, in minutes.')
|
.setDesc('How soon Gemmy starts to get disappointed after you stop tying in writing mode, in seconds.')
|
||||||
.addSlider(slider => slider
|
.addSlider(slider => slider
|
||||||
.setLimits(5, 60, 5)
|
.setLimits(5, 180, 5)
|
||||||
.setDynamicTooltip()
|
.setDynamicTooltip()
|
||||||
.setValue(this.plugin.settings.writingModeDeadline)
|
.setValue(this.plugin.settings.writingModeGracePeriod)
|
||||||
.onChange(async (value) => {
|
.onChange(async (value) => {
|
||||||
this.plugin.settings.writingModeDeadline = value;
|
this.plugin.settings.writingModeGracePeriod = value;
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "gemmy",
|
"id": "gemmy",
|
||||||
"name": "Gemmy",
|
"name": "Gemmy",
|
||||||
"version": "0.0.2",
|
"version": "1.0.1",
|
||||||
"minAppVersion": "0.15.0",
|
"minAppVersion": "0.15.0",
|
||||||
"description": "2023 April Fool's plugin brought to you by Obsidian",
|
"description": "2023 April Fool's plugin brought to you by Obsidian",
|
||||||
"author": "Obsidian",
|
"author": "Obsidian",
|
||||||
|
|
|
||||||
11
styles.css
11
styles.css
|
|
@ -15,6 +15,9 @@ If your plugin does not need CSS, delete this file.
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 30px;
|
bottom: 30px;
|
||||||
right: 30px;
|
right: 30px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gemmy-container img {
|
.gemmy-container img {
|
||||||
|
|
@ -23,10 +26,14 @@ If your plugin does not need CSS, delete this file.
|
||||||
border-radius: var(--gemmy-size);
|
border-radius: var(--gemmy-size);
|
||||||
}
|
}
|
||||||
|
|
||||||
.gemmy-tooltip {
|
.gemmy-container[aria-label]::before {
|
||||||
--background-modifier-message: #FFFFCB;
|
--background-modifier-message: #FFFFCB;
|
||||||
|
content: attr(aria-label);
|
||||||
color: #202020;
|
color: #202020;
|
||||||
font-size: var(--font-ui-medium);
|
font-size: var(--font-ui-medium);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
padding: var(--size-4-3) var(--size-4-6);
|
padding: var(--size-4-3) var(--size-4-6);
|
||||||
}
|
width: 150px;
|
||||||
|
background: var(--background-modifier-message);
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in a new issue