Compare commits

...

136 commits

Author SHA1 Message Date
Ell 0cf9067abf added discord to readme 2024-05-08 17:31:38 +02:00
Ell 3526aaf70c 2.4.7 2024-02-21 13:10:24 +01:00
Ell b0a325a04f fixed settings tab missing custom js 2024-02-21 13:08:46 +01:00
Afdzal Yunus df1ddd5c17
Improve preset styling for Google Keeps frame (#99)
* Improve preset styling for Google Keeps

* Remove pointer cursor from app logo

* Remove pointer cursor from app logo

---------

Co-authored-by: Ell <me@ellpeck.de>
2024-02-21 13:07:20 +01:00
WmeLuna 0ec307eab6
feat: Add Custom JS (#104)
* Add Custom JS

* Resolve requested changes
2023-10-11 22:01:03 +02:00
Ell bd10df45ee update known issues & roadmap 2023-08-25 14:00:18 +02:00
Ell 0fc0e9e18d ignore vault files 2023-08-11 19:28:02 +02:00
Fruffel 0cd6422f74
Update frame.ts - 'allow-downloads' added to sanbox attribute (#84) 2023-07-11 11:04:39 +02:00
Ell ab10797f39 cleanup 2023-05-22 19:37:17 +02:00
Ell 51b03d7bfc also remove google calendar logo padding 2023-05-10 19:14:22 +02:00
Ell c1f085d26e Improved default GCal css 2023-05-10 18:56:00 +02:00
Ell d96c8baf8c 2.4.6 2023-05-07 17:55:24 +02:00
Ell 3ffe20f441 fixed centered views having weird behavior with tabs
closes #67
2023-05-07 17:33:39 +02:00
Ell 21a8230e70 2.4.5 2023-01-30 12:17:38 +01:00
Ell 256f00e727 cleaned up google tasks preset 2023-01-30 12:12:56 +01:00
Lin, Yong Xiang 880d4c975c
Add google tasks preset (#63) 2023-01-30 12:12:14 +01:00
Ell 3ec5caf330 fixed custom frames in new windows
closes #43 closes #46
2023-01-30 12:11:19 +01:00
Ell 2363a5e338 fixed more options not displaying in sidebar tabs
Closes #66
2023-01-30 11:55:45 +01:00
Ell 72c14f63d7 2.4.4 2022-09-17 18:30:45 +02:00
Ell 4340d08e29 focus a frame's content when it gets opened 2022-09-17 18:28:06 +02:00
Ell 33f3407afe don't detach existing nodes when opening from the sidebar
Closes #58
2022-09-17 17:42:34 +02:00
Ell 2e5cbe42f5 don't sync new workspace for test vault 2022-09-17 17:38:24 +02:00
Ell 92db9fe55d improved google calendar settings
Closes #39
2022-09-17 17:37:23 +02:00
Ell 01ad91c8d4 fixed google calendar preset forcing day view 2022-09-17 17:34:41 +02:00
Ell 8db94a85f9 2.4.3 2022-08-21 18:22:15 +02:00
Ell f2c73ef189 added a security disclaimer
Closes #54
2022-08-21 18:13:38 +02:00
Ell 0a70f83d46 untrack main.js 2022-08-21 18:01:02 +02:00
Ell a91735dc44 added a unique class to each custom frame
Closes #53
2022-08-21 17:59:12 +02:00
firinael b425e9671f
add Detexify frame (#56) 2022-08-21 17:52:04 +02:00
Ell 14b01b67e5 fixed untracked files 2022-08-21 17:50:27 +02:00
Ell 8b7c80d218 some cleanup 2022-08-21 17:49:57 +02:00
Ell b805078fb1 fixed test vault data being ignored 2022-08-21 17:41:40 +02:00
Ell e826e93d27 added a test vault 2022-08-21 17:37:20 +02:00
Ell 5022385ee1 updated to new obsidian API 2022-06-19 23:42:29 +02:00
Ell c37dff03fd 2.4.2 2022-06-01 15:24:57 +02:00
Ell dd8f3054ee Added "open in browser" button
Closes #32
2022-06-01 15:22:33 +02:00
Ell cd0285c2dd Allow adding a URL suffix to Markdown mode, closes #37 2022-06-01 15:15:43 +02:00
Ell 52c1005440 allow holding control to open a center frame in a new split
Closes #33
2022-06-01 15:04:53 +02:00
Ell 5a0597d930 Merge branch 'master' of https://github.com/Ellpeck/ObsidianCustomFrames 2022-05-21 16:27:30 +02:00
Ell 0b397da89e improve the readme a bit 2022-05-21 16:27:29 +02:00
Ell fcdda42106 removed some outdated known issues 2022-05-05 13:28:53 +02:00
Ell c557ce548f 2.4.1 2022-04-26 13:11:13 +02:00
Ell 126000617f added a setting to force iframe usage
Closes #25
2022-04-26 13:05:22 +02:00
Ell cecae7de83 2.4.0 2022-04-15 13:36:23 +02:00
Ell 75d6d9f91a added the ability to display the frame in the center 2022-04-15 13:34:24 +02:00
Ell 5d3254e7bb added the option to add a ribbon icon 2022-04-15 13:22:09 +02:00
Ell c0aaf17d17 another roadmap idea 2022-04-15 11:56:51 +02:00
Ell 8199d7f67b also hide markdown frames on mobile if the setting is enabled 2022-04-13 22:34:16 +02:00
Ell bd6c7b5901 anchor consistency?? 2022-04-13 22:11:15 +02:00
Ell 5c78fcf180 2.3.0 2022-04-13 22:09:57 +02:00
Ell c32d83dc6e allow displaying custom frames in files 2022-04-13 21:59:39 +02:00
Ell 4131f0a51c Merge branch 'master' of https://github.com/Ellpeck/ObsidianCustomFrames 2022-04-13 21:21:49 +02:00
Ell 055e3f2042 moved frame impl to a different class 2022-04-13 21:21:48 +02:00
Ell bebba65abd 2.2.2 2022-04-08 14:26:30 +02:00
Ell 83bf0fbf96 allow collapsing settings sections
Closes #17
2022-04-08 14:23:05 +02:00
Ell 5616d76bb5 improved keep css to stop it from hiding other stuff 2022-04-08 14:09:01 +02:00
Ell 0ab4c18082 added a warning to the padding description 2022-04-08 14:03:32 +02:00
Ell ce2bd9af3a
Create CONTRIBUTING.md 2022-04-08 13:55:39 +02:00
Ell 92ad15a168 added a "known issues" section to the README 2022-04-08 13:49:45 +02:00
Ell 1c54de4688 2.2.1 2022-04-02 15:38:12 +02:00
Ell 02ba5611d3 updated plugin description 2022-04-02 15:36:05 +02:00
Ell 4ca103fc83 changed the google keep preset to use paths instead of class names 2022-04-02 15:29:05 +02:00
Ell a7cf61b9d0 adapt todoist to new settings 2022-04-02 15:19:27 +02:00
EdHout 5bd5a75061
Added todoist preset (#15)
* Added todoist preset

* Fixed literal indenting

* Added todoist
2022-04-02 15:18:38 +02:00
Ell eedac8f048 added a way to change a site's zoom level
Closes #13
2022-04-02 15:16:01 +02:00
Ell 97f122c33b removed wonky minimum width setting 2022-04-02 14:50:55 +02:00
Ell 6558acea1e added another suggestion to the README 2022-03-29 21:57:18 +02:00
Emile van Krieken 9108b86a6f
Feat: Add google calendar preset (#9)
* Feat: Add Google Calendar preset

* Update README.md
2022-03-29 17:00:16 +02:00
Ell 2980c2cb5f mmm consistency 2022-03-29 16:04:55 +02:00
Ell 85e9c5a0a4 added copy link action 2022-03-29 15:53:18 +02:00
Ell 7bef7cdd0a added an option to open developer tools 2022-03-29 15:15:34 +02:00
Ell d48e8d888b added a twitter preset 2022-03-29 14:07:25 +02:00
Ell 9c401f0bea clarify mobile usage restrictions in readme 2022-03-29 14:04:59 +02:00
Ell 972feb2fa8 fixed preset link in readme 2022-03-29 13:21:17 +02:00
Ell 1172aa121f formatting 2022-03-29 13:19:33 +02:00
Ell 683e245197 split up the code into multiple files 2022-03-29 13:18:25 +02:00
Ell ec922e8031 added navigation buttons to frames
Closes #8
2022-03-29 13:03:19 +02:00
Ell 3d13938588 2.2.0 2022-03-28 18:35:56 +02:00
Ell 8284a9b9e2 another idea 2022-03-27 15:35:08 +02:00
Ell 88aee30476 made obsidian forum the topmost preset 2022-03-26 16:11:30 +01:00
Ell e2ce193353 added a way to refresh and return to the original page 2022-03-26 15:57:09 +01:00
Ell 2ceb4bc48e added notion and obsidian forum presets 2022-03-26 15:35:09 +01:00
Ell fc6bea2f50 added an option to disable frames on mobile 2022-03-26 15:23:51 +01:00
Ell f7c6d93b90 experiment with webviews 2022-03-26 11:23:11 +01:00
Ell 76ad8e0f20 please read this 2022-03-25 16:26:32 +01:00
Ell 4b4f27291a allow top navigation by user activation 2022-03-25 15:35:23 +01:00
Ell d019b1d381 make extra sure to avoid variable reuse 2022-03-25 15:26:22 +01:00
Ell 6cf6eb04f2 Avoid polluting the global namespace
Closes #6
2022-03-25 15:25:25 +01:00
Ell 2f6bff67f7 2.1.0 2022-03-24 13:44:05 +01:00
Ell 377a210063 added support section 2022-03-23 18:06:12 +01:00
Ell dfbf454c3e use proper quotation marks 2022-03-23 16:13:11 +01:00
Ell 059b91d37d remove the word "preset" from the preset dropdown 2022-03-23 16:09:31 +01:00
Ell a7815a157f allow adding custom icons to frames, and cleaned up settings menu 2022-03-23 15:26:30 +01:00
Ell 7664d04f15 2.0.1 2022-03-23 13:14:34 +01:00
Ell 52392cfb63 change the version requirement to be a disclaimer instead 2022-03-23 12:58:33 +01:00
Ell 51d911f9be specify the obsidian version requirement 2022-03-23 12:55:47 +01:00
Ell e701632c3e added some attributes to the frame to make it more permissible 2022-03-23 12:52:45 +01:00
Ell 88a38de4a2 force the iframe's background to white
Closes #2
2022-03-23 11:56:49 +01:00
Ell c7d6ee8702 use Platform.isDesktop for minimum width 2022-03-23 11:45:08 +01:00
Ell 5a6bf176e7 allow using the plugin on mobile (with limitations) 2022-03-23 11:42:05 +01:00
Ell 822672ed2b fixed readme screenshots link 2022-03-22 17:07:02 +01:00
Ell 000e568387 such a sellout 2022-03-22 17:02:39 +01:00
Ell d6259d4e23 forcing me to change the description, unbelievable 2022-03-22 16:11:03 +01:00
Ell 3f5b883588 add code blocks to the roadmap 2022-03-22 14:09:08 +01:00
Ell 4bf6a3855a added acknowledgements 2022-03-22 14:06:42 +01:00
Ell bfb6ad2209 improve readme 2022-03-22 14:01:49 +01:00
Ell 4805efb216 hide old versions since this is the definitive first version 2022-03-22 13:51:29 +01:00
Ell e91cfc16ae bump version number 2022-03-22 13:36:51 +01:00
Ell 5bc2504a64 clarify that you have to reload (for now) 2022-03-22 13:33:35 +01:00
Ell 24103b14c9 turns out the bring web version is unusable lmao 2022-03-22 13:30:07 +01:00
Ell 562ce1eb9c added some nice promo screenshots 2022-03-22 13:27:52 +01:00
Ell bbf1cd22fb also reveal the leaf when using the open command 2022-03-22 13:22:58 +01:00
Ell 51e09944db calm down a bit with the css field's size 2022-03-22 13:18:53 +01:00
Ell cdbd29448a finished system! 2022-03-22 13:17:10 +01:00
Ell 672288135e initial rename 2022-03-22 12:03:48 +01:00
Ell 8758299d99 set a better minimum width and remove some unnecessary css 2022-03-22 01:16:51 +01:00
Ell 98e9496691 only hide the "Keep" text by default, not the icon 2022-03-22 01:06:16 +01:00
Ell e83dbedd44 added desktop notice 2022-03-22 00:55:20 +01:00
Ell 66ab5b44d9 update readme and remove zip 2022-03-22 00:54:12 +01:00
Ell 2ab3df63d3 switch to using iframes (with lishid's help) 2022-03-22 00:51:28 +01:00
Ell 2ecd6662c9 actually allow setting settings to 0 2022-03-21 19:39:03 +01:00
Ell 2ea3617af3 fully ensure the browser view gets removed 2022-03-21 15:03:37 +01:00
Ell c90f4ac55d added some fanciness to the README 2022-03-21 14:52:55 +01:00
Ell 0251931cbd
Create LICENSE (#1) 2022-03-21 14:43:57 +01:00
Ell 4b62cad481 minimum width that works on left and right sides 2022-03-21 00:13:22 +01:00
Ell c1c4d00ea8 improve some defaults 2022-03-21 00:10:06 +01:00
Ell 1002198580 reset settings to default when no value is entered 2022-03-21 00:09:03 +01:00
Ell c272d1fa57 1.1.1 2022-03-20 19:34:47 +01:00
Ell 578c7fd73b added automatic width calculation 2022-03-20 19:32:21 +01:00
Ell 57e0cb6a33 added installation instructions 2022-03-20 14:18:58 +01:00
Ell 10404caf63 1.1.0 2022-03-20 13:59:36 +01:00
Ell 6d100212b7 save settings that are edited 2022-03-20 13:57:02 +01:00
Ell 5edfc5c0de added settings and added custom css 2022-03-20 13:55:19 +01:00
Ell 89f9030643 also hide keep for notice toasts 2022-03-20 11:57:54 +01:00
Ell 5208f9a298 removed debug zoom level 2022-03-20 00:44:25 +01:00
Ell 62aebe87e1 increased interval timeout 2022-03-20 00:44:01 +01:00
35 changed files with 2774 additions and 2536 deletions

View file

@ -1,9 +1,9 @@
# top-most EditorConfig file
root = true
[*]
charset = utf-8
insert_final_newline = true
indent_style = tab
indent_size = 4
tab_width = 4
# top-most EditorConfig file
root = true
[*]
charset = utf-8
insert_final_newline = true
indent_style = space
indent_size = 4
tab_width = 4

3
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,3 @@
github: Ellpeck
ko_fi: Ellpeck
patreon: Ellpeck

45
.gitignore vendored
View file

@ -1,22 +1,23 @@
# vscode
.vscode
# Intellij
*.iml
.idea
# npm
node_modules
# Don't include the compiled main.js file in the repo.
# They should be uploaded to GitHub releases instead.
main.js
# Exclude sourcemaps
*.map
# obsidian
data.json
# Exclude macOS Finder (System Explorer) View States
.DS_Store
# vscode
.vscode
# Intellij
*.iml
.idea
# npm
node_modules
# Don't include the compiled main.js file in the repo.
# They should be uploaded to GitHub releases instead.
/main.js
# Exclude sourcemaps
*.map
# obsidian
workspace
workspace.json
# Exclude macOS Finder (System Explorer) View States
.DS_Store

1
.npmrc
View file

@ -1 +0,0 @@
tag-version-prefix=""

5
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,5 @@
Hi, thanks for contributing to Custom Frames!
Before reporting an issue or suggesting a new feature, please check the [README](README.md)'s [Roadmap](README.md#%EF%B8%8F-roadmap) and [Known Issues](https://github.com/Ellpeck/ObsidianCustomFrames/blob/master/README.md#%EF%B8%8F-known-issues) sections. If your issue or suggestion is already listed there, you don't need to report it here.
Thanks! ❤️

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Ellpeck
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.

View file

@ -1,6 +1,75 @@
# ObsidianKeep
An Obsidian plugin that displays Google Keep in the app.
Since Google Keep doesn't allow the use of iframes, this plugin gets creative by adding a [BrowserView](https://www.electronjs.org/docs/latest/api/browser-view) for the Google Keep view. However, since they render on top of everything else, the view has to be hidden whenever a modal or menu is open. It's a compromise.
When the official [Google Keep API](https://developers.google.com/keep) is farther along and has an official JavaScript API, this plugin will start using that instead, probably.
# Obsidian Custom Frames
An Obsidian plugin that turns web apps into panes using iframes with custom styling. Also comes with presets for Google Keep, Todoist and more.
![A screenshot of the plugin in action, where you can see Google Keep attached as a narrow side pane on the right](https://raw.githubusercontent.com/Ellpeck/ObsidianCustomFrames/master/screenshot.png)
![A screenshot of the plugin in action, where you can see Google Calendar opened in the center, and the mouse hovering over the corresponding ribbon button](https://raw.githubusercontent.com/Ellpeck/ObsidianCustomFrames/master/screenshot-big.png)
![A screenshot of the plugin's settings](https://raw.githubusercontent.com/Ellpeck/ObsidianCustomFrames/master/settings.png)
## 🤔 Usage
To use this plugin, simply go into its settings and add a new frame, either from a preset shipped with the plugin, or a custom one that you can edit yourself.
### 🪟 Pane Mode
To open a Custom Frame as a pane, you can use the "Custom Frames: Open" command.
There are also plenty of settings to customize your frame further, including adding custom CSS to the site, adding a ribbon icon, displaying the frame in the center of the editor, and more.
### 🗒️ Markdown Mode
You can also display your custom frames in your Markdown documents. Custom Frames adds a special code block syntax that transforms the code block into a custom frame in Live Preview and Reading mode. Your code block should look like this:
~~~
```custom-frames
frame: YOUR FRAME'S NAME
```
~~~
Optionally, you can also pass custom style settings to the embed, which allows you to change things like the embed's height, as well as an additional suffix that will be appended to the frame's regular URL, which can be useful for things like displaying a specific note in Google Keep.
Here's an example using the [Google Keep preset](#-presets):
~~~
```custom-frames
frame: Google Keep
style: height: 1000px;
urlSuffix: #reminders
```
~~~
### 📱 On Obsidian Mobile
Unfortunately, Obsidian Mobile does not run on [Electron](https://www.electronjs.org/), which is what allows iframes and [webviews](https://www.electronjs.org/docs/latest/api/webview-tag) to be displayed with very few restrictions related to cookies, cross-origin resource sharing, and so on. This means that a lot of sites won't work there, especially ones that you have to log in to. However, when you create a frame, you can toggle the "Disable on Mobile" option to hide a Desktop-only frame in Obsidian mobile.
Need help using the plugin? Feel free to join the Discord server!
[![Join the Discord server](https://ellpeck.de/res/discord-wide.png)](https://link.ellpeck.de/discordweb)
## 📦 Presets
By default, Custom Frames comes with a few presets that allow you to get new panes for popular sites up and running quickly.
- [Obsidian Forum](https://forum.obsidian.md/)
- [Google Keep](https://keep.google.com), optimized for a narrow pane on the side
- [Google Calendar](https://calendar.google.com/calendar/u/0/r/day), optimized by removing some buttons. Close side panel with top-left button.
- [Todoist](https://todoist.com), optimized for a narrow (half-height) side panel by removing some buttons and slimming margins.
- [Notion](https://www.notion.so/) (it's recommended to close Notion's sidebar if used as a side pane)
- [Twitter](https://twitter.com)
If you create a frame that you think other people would like, don't hesitate to create a pull request with [a new preset](https://github.com/Ellpeck/ObsidianCustomFrames/blob/master/src/settings.ts#L5).
## 🛣️ Roadmap
- ~~Allow setting a custom icon for each pane~~
- ~~Allow displaying custom frames in Markdown code blocks~~
- ~~Add the ability to add a ribbon button for a frame that opens it in the main view~~
- Allow creating links outside of Obsidian that open in a custom frame
- Possibly allow executing custom JavaScript in iframes (though security implications still need to be explored)
- Add a global setting that causes popups to be opened in a new Obsidian window rather than the default browser
- Add more options to Markdown mode, like allowing for back and forward buttons
- Possibly allow extracting selected text into a note similar to how the Note composer plugin works, and potentially allow using a note template that includes the link to the site extracted from
## ⚠️ Known Issues
There are a few known issues with Custom Frames. If you encounter any of these, please **don't** report it on the issue tracker.
- Popups and new tabs are currently opened in the default browser rather than the custom frame. You can find more info, including workarounds for logging in to certain sites, in [this issue](https://github.com/Ellpeck/ObsidianCustomFrames/issues/40).
- Some links refuse to open from within custom frames, especially before Obsidian 1.3.7. You can find more info in [this issue](https://github.com/Ellpeck/ObsidianCustomFrames/issues/76).
## 🙏 Acknowledgements
Thanks to [lishid](https://github.com/lishid) for their help with making iframes work in Obsidian for a purpose like this. Also thanks to them for *motivating* me to turn Obsidian Keep into a more versatile plugin, which is how Custom Frames was born.
If you like this plugin and want to support its development, you can do so through my website by clicking this fancy image!
[![Support me (if you want), via Patreon, Ko-fi or GitHub Sponsors](https://ellpeck.de/res/generalsupport-wide.png)](https://ellpeck.de/support)

View file

@ -1,52 +1,60 @@
import esbuild from "esbuild";
import process from "process";
import builtins from 'builtin-modules'
import builtins from 'builtin-modules';
import {copy} from 'esbuild-plugin-copy';
const banner =
`/*
const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
`;
*/`;
const prod = (process.argv[2] === 'production');
esbuild.build({
banner: {
js: banner,
},
entryPoints: ['main.ts'],
bundle: true,
external: [
'obsidian',
'electron',
'@codemirror/autocomplete',
'@codemirror/closebrackets',
'@codemirror/collab',
'@codemirror/commands',
'@codemirror/comment',
'@codemirror/fold',
'@codemirror/gutter',
'@codemirror/highlight',
'@codemirror/history',
'@codemirror/language',
'@codemirror/lint',
'@codemirror/matchbrackets',
'@codemirror/panel',
'@codemirror/rangeset',
'@codemirror/rectangular-selection',
'@codemirror/search',
'@codemirror/state',
'@codemirror/stream-parser',
'@codemirror/text',
'@codemirror/tooltip',
'@codemirror/view',
...builtins],
format: 'cjs',
watch: !prod,
target: 'es2016',
logLevel: "info",
sourcemap: prod ? false : 'inline',
treeShaking: true,
outfile: 'main.js',
banner: {
js: banner,
},
entryPoints: ['src/main.ts'],
bundle: true,
external: [
'obsidian',
'electron',
'@codemirror/autocomplete',
'@codemirror/closebrackets',
'@codemirror/collab',
'@codemirror/commands',
'@codemirror/comment',
'@codemirror/fold',
'@codemirror/gutter',
'@codemirror/highlight',
'@codemirror/history',
'@codemirror/language',
'@codemirror/lint',
'@codemirror/matchbrackets',
'@codemirror/panel',
'@codemirror/rangeset',
'@codemirror/rectangular-selection',
'@codemirror/search',
'@codemirror/state',
'@codemirror/stream-parser',
'@codemirror/text',
'@codemirror/tooltip',
'@codemirror/view',
...builtins
],
plugins: [
copy({
assets: [{
from: ["./manifest.json", "./main.js", "./styles.css"],
to: ["./test-vault/.obsidian/plugins/obsidian-custom-frames/."]
}]
}),
],
format: 'cjs',
watch: !prod,
target: 'es2016',
logLevel: "info",
sourcemap: prod ? false : 'inline',
treeShaking: true,
outfile: 'main.js',
}).catch(() => process.exit(1));

125
main.ts
View file

@ -1,125 +0,0 @@
import { ItemView, Plugin } from 'obsidian';
import { BrowserView, remote } from 'electron';
const viewName: string = "keep";
const padding: number = 5;
export default class MyPlugin extends Plugin {
async onload(): Promise<void> {
console.log('Loading obsidian-keep');
this.registerView(viewName, l => new KeepView(l));
this.addCommand({
id: "open-keep",
name: "Open Keep",
checkCallback: (checking: boolean) => {
if (checking)
return !this.app.workspace.getLeavesOfType(viewName).length;
this.openKeep();
},
});
this.app.workspace.onLayoutReady(() => this.openKeep());
}
private openKeep(): void {
if (!this.app.workspace.getLeavesOfType(viewName).length)
this.app.workspace.getRightLeaf(false).setViewState({ type: viewName });
}
}
export class KeepView extends ItemView {
private keep: BrowserView;
private visible: boolean;
private open: boolean;
private size: DOMRect;
async onload(): Promise<void> {
this.keep = new remote.BrowserView();
await this.keep.webContents.loadURL('https://keep.google.com');
this.registerInterval(window.setInterval(() => this.update(), 16.67));
}
onunload(): void {
this.hide();
}
onResize(): void {
this.resizeIfNecessary();
}
getViewType(): string {
return viewName;
}
getDisplayText(): string {
return "Google Keep";
}
getIcon(): string {
return "documents";
}
update() {
if (this.open) {
let covered = this.coveredByElement();
if (this.visible && covered) {
this.hide();
} else if (!this.visible && !covered) {
this.show();
}
if (this.visible)
this.resizeIfNecessary();
}
}
hide() {
if (this.visible) {
remote.BrowserWindow.getFocusedWindow().removeBrowserView(this.keep);
this.visible = false;
}
}
show() {
if (!this.visible) {
remote.BrowserWindow.getFocusedWindow().addBrowserView(this.keep);
this.visible = true;
}
}
protected async onOpen(): Promise<void> {
this.show();
this.resizeIfNecessary();
this.open = true;
}
protected async onClose(): Promise<void> {
this.hide();
this.open = false;
}
private resizeIfNecessary(): void {
let rect = this.contentEl.getBoundingClientRect();
if (this.size && rect.x == this.size.x && rect.y == this.size.y && rect.width == this.size.width && rect.height == this.size.height)
return;
this.size = rect;
this.keep.setBounds({
x: Math.floor(rect.x) + padding,
y: Math.floor(rect.top) + padding,
width: Math.floor(rect.width) - 2 * padding,
height: Math.floor(rect.height) - 2 * padding
});
}
private coveredByElement(): boolean {
let nodes = document.body.querySelectorAll(".modal-bg, .menu");
for (let i = 0; i < nodes.length; i++) {
let rect = nodes[i].getBoundingClientRect();
if (rect.left < this.size.right && this.size.left < rect.right && rect.top < this.size.bottom && this.size.top < rect.bottom)
return true;
}
return false;
}
}

View file

@ -1,10 +1,10 @@
{
"id": "obsidian-keep",
"name": "Obsidian Keep",
"version": "1.0.1",
"minAppVersion": "0.13.33",
"description": "An Obsidian plugin that displays Google Keep in the app",
"author": "Ellpeck",
"authorUrl": "https://ellpeck.de",
"isDesktopOnly": true
}
{
"id": "obsidian-custom-frames",
"name": "Custom Frames",
"version": "2.4.7",
"minAppVersion": "1.2.0",
"description": "A plugin that turns web apps into panes using iframes with custom styling. Also comes with presets for Google Keep, Todoist and more.",
"author": "Ellpeck",
"authorUrl": "https://ellpeck.de",
"isDesktopOnly": false
}

3906
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,23 +1,24 @@
{
"name": "obsidian-keep",
"version": "1.0.1",
"description": "An Obsidian plugin that displays Google Keep in the app",
"main": "main.js",
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"version": "node version-bump.mjs && git add manifest.json versions.json"
},
"keywords": [],
"author": "Ellpeck",
"license": "MIT",
"devDependencies": {
"@types/node": "^16.11.6",
"builtin-modules": "^3.2.0",
"electron": "^13.6.2",
"esbuild": "0.13.12",
"obsidian": "latest",
"tslib": "2.3.1",
"typescript": "4.4.4"
}
"name": "obsidian-custom-frames",
"version": "2.4.7",
"description": "An Obsidian plugin that turns web apps into panes using iframes with custom styling. Also comes with presets for Google Keep, Todoist and more.",
"main": "main.js",
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"version": "node version-bump.mjs && git add manifest.json versions.json"
},
"keywords": [],
"author": "Ellpeck",
"license": "MIT",
"devDependencies": {
"@types/node": "^16.11.6",
"builtin-modules": "^3.2.0",
"electron": "^20.3.9",
"esbuild": "0.14.0",
"esbuild-plugin-copy": "^1.3.0",
"obsidian": "latest",
"tslib": "2.3.1",
"typescript": "4.4.4"
}
}

BIN
screenshot-big.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

109
src/frame.ts Normal file
View file

@ -0,0 +1,109 @@
import { Platform } from "obsidian";
import { CustomFrameSettings, CustomFramesSettings, getId } from "./settings";
export class CustomFrame {
private readonly settings: CustomFramesSettings;
private readonly data: CustomFrameSettings;
private frame: HTMLIFrameElement | any;
constructor(settings: CustomFramesSettings, data: CustomFrameSettings) {
this.settings = settings;
this.data = data;
}
create(parent: HTMLElement, additionalStyle: string = undefined, urlSuffix: string = undefined): void {
let style = `padding: ${this.settings.padding}px;`;
if (additionalStyle)
style += additionalStyle;
if (Platform.isDesktopApp && !this.data.forceIframe) {
let frameDoc = parent.doc;
this.frame = frameDoc.createElement("webview");
parent.appendChild(this.frame);
this.frame.setAttribute("allowpopups", "");
this.frame.addEventListener("dom-ready", () => {
this.frame.setZoomFactor(this.data.zoomLevel);
this.frame.insertCSS(this.data.customCss);
this.frame.executeJavaScript(this.data.customJs)
});
this.frame.addEventListener("destroyed", () => {
// recreate the webview if it was moved to a new window
if (frameDoc != parent.doc) {
this.frame.detach();
this.create(parent, additionalStyle, urlSuffix);
}
});
} else {
this.frame = parent.doc.createElement("iframe");
parent.appendChild(this.frame);
this.frame.setAttribute("sandbox", "allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation allow-downloads");
this.frame.setAttribute("allow", "encrypted-media; fullscreen; oversized-images; picture-in-picture; sync-xhr; geolocation;");
style += `transform: scale(${this.data.zoomLevel}); transform-origin: 0 0;`;
}
this.frame.addClass("custom-frames-frame");
this.frame.addClass(`custom-frames-${getId(this.data)}`);
this.frame.setAttribute("style", style);
let src = this.data.url;
if (urlSuffix) {
if (!urlSuffix.startsWith("/"))
src += "/";
src += urlSuffix;
}
this.frame.setAttribute("src", src);
}
refresh(): void {
if (this.frame instanceof HTMLIFrameElement) {
this.frame.contentWindow.location.reload();
} else {
this.frame.reload();
}
}
return(): void {
if (this.frame instanceof HTMLIFrameElement) {
this.frame.contentWindow.open(this.data.url);
} else {
this.frame.loadURL(this.data.url);
}
}
goBack(): void {
if (this.frame instanceof HTMLIFrameElement) {
this.frame.contentWindow.history.back();
} else {
this.frame.goBack();
}
}
goForward(): void {
if (this.frame instanceof HTMLIFrameElement) {
this.frame.contentWindow.history.forward();
} else {
this.frame.goForward();
}
}
toggleDevTools(): void {
if (!(this.frame instanceof HTMLIFrameElement)) {
if (!this.frame.isDevToolsOpened()) {
this.frame.openDevTools();
} else {
this.frame.closeDevTools();
}
}
}
getCurrentUrl(): string {
return this.frame instanceof HTMLIFrameElement ? this.frame.contentWindow.location.href : this.frame.getURL();
}
focus(): void {
if (this.frame instanceof HTMLIFrameElement) {
this.frame.contentWindow.focus();
} else {
this.frame.focus();
}
}
}

97
src/main.ts Normal file
View file

@ -0,0 +1,97 @@
import { Plugin, Platform, WorkspaceLeaf } from "obsidian";
import { CustomFrame } from "./frame";
import { CustomFramesSettings, defaultSettings, getIcon, getId } from "./settings";
import { CustomFramesSettingTab } from "./settings-tab";
import { CustomFrameView } from "./view";
export default class CustomFramesPlugin extends Plugin {
settings: CustomFramesSettings;
async onload(): Promise<void> {
await this.loadSettings();
for (let frame of this.settings.frames) {
if (!frame.url || !frame.displayName)
continue;
let name = `custom-frames-${getId(frame)}`;
if (Platform.isMobileApp && frame.hideOnMobile) {
console.log(`Skipping frame ${name} which is hidden on mobile`);
continue;
}
try {
console.log(`Registering frame ${name} for URL ${frame.url}`);
this.registerView(name, l => new CustomFrameView(l, this.settings, frame, name));
this.addCommand({
id: `open-${name}`,
name: `Open ${frame.displayName}`,
callback: () => this.openLeaf(name, frame.openInCenter, false),
});
if (frame.addRibbonIcon)
this.addRibbonIcon(getIcon(frame), `Open ${frame.displayName}`,
e => this.openLeaf(name, frame.openInCenter, Platform.isMacOS ? e.metaKey : e.ctrlKey));
} catch {
console.error(`Couldn't register frame ${name}, is there already one with the same name?`);
}
}
this.addSettingTab(new CustomFramesSettingTab(this.app, this));
this.registerMarkdownCodeBlockProcessor("custom-frames", (s, e) => {
e.empty();
e.addClass("custom-frames-view-file");
let frameMatch = /frame:([^\n]+)/gi.exec(s);
let frameName = frameMatch && frameMatch[1].trim();
if (!frameName) {
e.createSpan({ text: "Couldn't parse frame name" });
return;
}
let data = this.settings.frames.find(f => f.displayName == frameName);
if (!data) {
e.createSpan({ text: `Couldn't find a frame with name ${frameName}` });
return;
}
if (Platform.isMobileApp && data.hideOnMobile) {
e.createSpan({ text: `${frameName} is hidden on mobile` });
return;
}
let styleMatch = /style:([^\n]+)/gi.exec(s);
let style = styleMatch && styleMatch[1].trim();
style ||= "height: 600px;";
let urlSuffixMatch = /urlsuffix:([^\n]+)/gi.exec(s);
let urlSuffix = urlSuffixMatch && urlSuffixMatch[1].trim();
urlSuffix ||= "";
let frame = new CustomFrame(this.settings, data);
frame.create(e, style, urlSuffix);
});
}
async loadSettings() {
this.settings = Object.assign({}, defaultSettings, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
private async openLeaf(name: string, center: boolean, split: boolean): Promise<void> {
let leaf: WorkspaceLeaf;
if (center) {
leaf = this.app.workspace.getLeaf(split);
await leaf.setViewState({ type: name, active: true });
} else {
if (!this.app.workspace.getLeavesOfType(name).length)
await this.app.workspace.getRightLeaf(false).setViewState({ type: name, active: true });
leaf = this.app.workspace.getLeavesOfType(name)[0];
this.app.workspace.revealLeaf(leaf);
}
if (leaf.view instanceof CustomFrameView)
leaf.view.focus();
}
}

226
src/settings-tab.ts Normal file
View file

@ -0,0 +1,226 @@
import { App, ButtonComponent, DropdownComponent, PluginSettingTab, Setting } from "obsidian";
import { defaultSettings, presets } from "./settings";
import CustomFramesPlugin from "./main";
export class CustomFramesSettingTab extends PluginSettingTab {
plugin: CustomFramesPlugin;
constructor(app: App, plugin: CustomFramesPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
this.containerEl.empty();
this.containerEl.createEl("h2", { text: "Custom Frames Settings" });
this.containerEl.createEl("p", {
text: "Please note that Obsidian has to be restarted or reloaded for most of these settings to take effect.",
cls: "mod-warning"
});
new Setting(this.containerEl)
.setName("Frame Padding")
.setDesc("The padding that should be left around the inside of custom frame panes, in pixels.")
.addText(t => {
t.inputEl.type = "number";
t.setValue(String(this.plugin.settings.padding));
t.onChange(async v => {
this.plugin.settings.padding = v.length ? Number(v) : defaultSettings.padding;
await this.plugin.saveSettings();
});
});
for (let frame of this.plugin.settings.frames) {
let heading = this.containerEl.createEl("h3", { text: frame.displayName || "Unnamed Frame" });
let toggle = new ButtonComponent(this.containerEl)
.setButtonText("Show Settings")
.setClass("custom-frames-show")
.onClick(async () => {
content.hidden = !content.hidden;
toggle.setButtonText(content.hidden ? "Show Settings" : "Hide Settings");
});
let content = this.containerEl.createDiv();
content.hidden = true;
new Setting(content)
.setName("Display Name")
.setDesc("The display name that this frame should have.")
.addText(t => {
t.setValue(frame.displayName);
t.onChange(async v => {
frame.displayName = v;
heading.setText(frame.displayName || "Unnamed Frame");
await this.plugin.saveSettings();
});
});
new Setting(content)
.setName("Icon")
.setDesc(createFragment(f => {
f.createSpan({ text: "The icon that this frame's pane should have. The names of any " });
f.createEl("a", { text: "Lucide icons", href: "https://lucide.dev/" });
f.createSpan({ text: " can be used." });
}))
.addText(t => {
t.setValue(frame.icon);
t.onChange(async v => {
frame.icon = v;
await this.plugin.saveSettings();
});
});
new Setting(content)
.setName("URL")
.setDesc("The URL that should be opened in this frame.")
.addText(t => {
t.setValue(frame.url);
t.onChange(async v => {
frame.url = v;
await this.plugin.saveSettings();
});
});
new Setting(content)
.setName("Disable on Mobile")
.setDesc("Custom Frames is a lot more restricted on mobile devices and doesn't allow for the same types of content to be displayed. If a frame doesn't work as expected on mobile, it can be disabled.")
.addToggle(t => {
t.setValue(frame.hideOnMobile);
t.onChange(async v => {
frame.hideOnMobile = v;
await this.plugin.saveSettings();
});
});
new Setting(content)
.setName("Add Ribbon Icon")
.setDesc("Whether a button to open this frame should be added to the ribbon.")
.addToggle(t => {
t.setValue(frame.addRibbonIcon);
t.onChange(async v => {
frame.addRibbonIcon = v;
await this.plugin.saveSettings();
});
});
new Setting(content)
.setName("Open in Center")
.setDesc("Whether this frame should be opened in the unpinned center editor rather than one of the panes on the side. This is useful for sites that don't work well in a narrow view, or sites that don't require a note to be open when viewed.")
.addToggle(t => {
t.setValue(frame.openInCenter);
t.onChange(async v => {
frame.openInCenter = v;
await this.plugin.saveSettings();
});
});
new Setting(content)
.setName("Force iframe")
.setDesc(createFragment(f => {
f.createSpan({ text: "Whether this frame should use iframes on desktop as opposed to Electron webviews." });
f.createEl("br");
f.createEl("em", { text: "Only enable this setting if the frame is causing issues or frequent crashes. This setting causes all Desktop-only settings to be ignored." });
}))
.addToggle(t => {
t.setValue(frame.forceIframe);
t.onChange(async v => {
frame.forceIframe = v;
await this.plugin.saveSettings();
});
});
new Setting(content)
.setName("Page Zoom")
.setDesc("The zoom that this frame's page should be displayed with, as a percentage.")
.addText(t => {
t.inputEl.type = "number";
t.setValue(String(frame.zoomLevel * 100));
t.onChange(async v => {
frame.zoomLevel = v.length ? Number(v) / 100 : 1;
await this.plugin.saveSettings();
});
});
new Setting(content)
.setName("Additional CSS")
.setDesc(createFragment(f => {
f.createSpan({ text: "A snippet of additional CSS that should be applied to this frame." });
f.createEl("br");
f.createEl("em", { text: "Note that this is only applied on Desktop." });
}))
.addTextArea(t => {
t.inputEl.rows = 5;
t.inputEl.cols = 50;
t.setValue(frame.customCss);
t.onChange(async v => {
frame.customCss = v;
await this.plugin.saveSettings();
});
});
new Setting(content)
.setName("Additional JavaScript")
.setDesc(createFragment(f => {
f.createSpan({ text: "A snippet of additional JavaScript that should be applied to this frame." });
f.createEl("br");
f.createEl("em", { text: "Note that this is only applied on Desktop." });
}))
.addTextArea(t => {
t.inputEl.rows = 5;
t.inputEl.cols = 50;
t.setValue(frame.customJs);
t.onChange(async v => {
frame.customJs = v;
await this.plugin.saveSettings();
});
});
new ButtonComponent(content)
.setButtonText("Remove Frame")
.onClick(async () => {
this.plugin.settings.frames.remove(frame);
await this.plugin.saveSettings();
this.display();
});
}
this.containerEl.createEl("hr");
this.containerEl.createEl("p", { text: "Create a new frame, either from a preset shipped with the plugin, or a custom one that you can edit yourself. Each frame's pane can be opened using the \"Custom Frames: Open\" command." });
let addDiv = this.containerEl.createDiv();
let dropdown = new DropdownComponent(addDiv);
dropdown.addOption("new", "Custom");
for (let key of Object.keys(presets))
dropdown.addOption(key, presets[key].displayName);
new ButtonComponent(addDiv)
.setButtonText("Add Frame")
.setClass("custom-frames-add")
.onClick(async () => {
let option = dropdown.getValue();
if (option == "new") {
this.plugin.settings.frames.push({
url: "",
displayName: "New Frame",
icon: "",
hideOnMobile: true,
addRibbonIcon: false,
openInCenter: false,
zoomLevel: 1,
forceIframe: false,
customCss: "",
customJs: ""
});
} else {
this.plugin.settings.frames.push(presets[option]);
}
await this.plugin.saveSettings();
this.display();
});
let disclaimer = this.containerEl.createEl("p", { cls: "mod-warning" });
disclaimer.createSpan({ text: "Please be advised that, when adding a site as a custom frame, you potentially expose personal information you enter to other plugins you have installed. For more information, see " });
disclaimer.createEl("a", {
text: "this discussion",
href: "https://github.com/Ellpeck/ObsidianCustomFrames/issues/54#issuecomment-1210879685",
cls: "mod-warning"
});
disclaimer.createSpan({ text: "." });
this.containerEl.createEl("hr");
this.containerEl.createEl("p", { text: "If you like this plugin and want to support its development, you can do so through my website by clicking this fancy image!" });
this.containerEl.createEl("a", { href: "https://ellpeck.de/support" }).createEl("img", {
attr: { src: "https://ellpeck.de/res/generalsupport.png" },
cls: "custom-frames-support"
});
}
}

164
src/settings.ts Normal file
View file

@ -0,0 +1,164 @@
export const defaultSettings: CustomFramesSettings = {
frames: [],
padding: 5
};
export const presets: Record<string, CustomFrameSettings> = {
"obsidian": {
url: "https://forum.obsidian.md/",
displayName: "Obsidian Forum",
icon: "edit",
hideOnMobile: true,
addRibbonIcon: true,
openInCenter: true,
zoomLevel: 1,
forceIframe: false,
customCss: "",
customJs: ""
},
"detexify": {
url: "https://detexify.kirelabs.org/classify.html",
displayName: "Detexify",
icon: "type",
hideOnMobile: true,
addRibbonIcon: true,
openInCenter: false,
zoomLevel: .95,
forceIframe: false,
customCss: `/* hide info clutter and ad banner */
#classify--info-area,
.adsbygoogle {
display: none !important
}`,
customJs: ""
},
"calendar": {
url: "https://calendar.google.com/calendar",
displayName: "Google Calendar",
icon: "calendar",
hideOnMobile: true,
addRibbonIcon: true,
openInCenter: true,
zoomLevel: 1,
forceIframe: false,
customCss: `/* hide the menu bar "Calendar" text and remove minimum width */
div[style*="min-width: 238px"] {
min-width: 0 !important;
padding-right: 0 !important;
}
div[style*="min-width: 238px"] span[role*="heading"] {
display: none !important;
}`,
customJs: ""
},
"keep": {
url: "https://keep.google.com",
displayName: "Google Keep",
icon: "files",
hideOnMobile: true,
addRibbonIcon: false,
openInCenter: false,
zoomLevel: 1,
forceIframe: false,
customCss: `/* hide the menu bar, the "Keep" text and the Google Apps button */
html > body > div:nth-child(2) > div:nth-child(2) > div:first-child,
html > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child > span,
html > body > div:first-child > header:first-child > div:nth-child(2) > div:first-child > div:first-child,
html > body > div:first-child > header:first-child > div:nth-child(2) > div:nth-child(3) > div:first-child > div:first-child > div:first-child {
display: none !important;
}
html > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child {
cursor: default;
}`,
customJs: ""
},
"todoist": {
url: "https://todoist.com",
displayName: "Todoist",
icon: "list-checks",
hideOnMobile: true,
addRibbonIcon: false,
openInCenter: false,
zoomLevel: 1,
forceIframe: false,
customCss: `/* hide the help, home, search, and productivity overview buttons, create extra space, and prevent toast pop-up from acting weird */
[aria-label="Go to Home view"], #quick_find, [aria-label="Productivity"], [aria-label="Help & Feedback"] {
display: none !important;
}
.view_content {
padding-left: 15px;
}
.view_header {
padding-left: 15px;
padding-top: 10px;
}
.undo_toast {
width: 95%;
}`,
customJs: ""
},
"notion": {
url: "https://www.notion.so/",
displayName: "Notion",
icon: "box",
hideOnMobile: true,
addRibbonIcon: true,
openInCenter: true,
zoomLevel: 1,
forceIframe: false,
customCss: "",
customJs: ""
},
"twitter": {
url: "https://twitter.com",
displayName: "Twitter",
icon: "twitter",
hideOnMobile: true,
addRibbonIcon: false,
openInCenter: false,
zoomLevel: 1,
forceIframe: false,
customCss: "",
customJs: ""
},
"tasks": {
url: "https://tasks.google.com/embed/?origin=https://calendar.google.com&fullWidth=1",
displayName: "Google Tasks",
icon: "list-checks",
hideOnMobile: true,
addRibbonIcon: false,
openInCenter: false,
zoomLevel: 1,
forceIframe: false,
customCss: "",
customJs: ""
}
};
export interface CustomFramesSettings {
frames: CustomFrameSettings[];
padding: number;
}
export interface CustomFrameSettings {
url: string;
displayName: string;
icon: string;
hideOnMobile: boolean;
addRibbonIcon: boolean;
openInCenter: boolean;
zoomLevel: number;
forceIframe: boolean;
customCss: string;
customJs: string;
}
export function getIcon(settings: CustomFrameSettings) {
return settings.icon ? `lucide-${settings.icon}` : "documents";
}
export function getId(settings: CustomFrameSettings) {
return settings.displayName.toLowerCase().replace(/\s/g, "-");
}

92
src/view.ts Normal file
View file

@ -0,0 +1,92 @@
import { ItemView, WorkspaceLeaf, Menu } from "obsidian";
import { CustomFrame } from "./frame";
import { CustomFrameSettings, CustomFramesSettings, getIcon } from "./settings";
export class CustomFrameView extends ItemView {
private static readonly actions: Action[] = [
{
name: "Return to original page",
icon: "home",
action: v => v.frame.return()
}, {
name: "Open dev tools",
icon: "binary",
action: v => v.frame.toggleDevTools()
}, {
name: "Copy link",
icon: "link",
action: v => navigator.clipboard.writeText(v.frame.getCurrentUrl())
}, {
name: "Open in browser",
icon: "globe",
action: v => open(v.frame.getCurrentUrl())
}, {
name: "Refresh",
icon: "refresh-cw",
action: v => v.frame.refresh()
}, {
name: "Go back",
icon: "arrow-left",
action: v => v.frame.goBack()
}, {
name: "Go forward",
icon: "arrow-right",
action: v => v.frame.goForward()
}
];
private readonly data: CustomFrameSettings;
private readonly name: string;
private frame: CustomFrame;
constructor(leaf: WorkspaceLeaf, settings: CustomFramesSettings, data: CustomFrameSettings, name: string) {
super(leaf);
this.data = data;
this.name = name;
this.frame = new CustomFrame(settings, data);
this.navigation = data.openInCenter;
for (let action of CustomFrameView.actions)
this.addAction(action.icon, action.name, () => action.action(this));
}
onload(): void {
this.contentEl.empty();
this.contentEl.addClass("custom-frames-view");
this.frame.create(this.contentEl);
}
onPaneMenu(menu: Menu, source: string): void {
super.onPaneMenu(menu, source);
for (let action of CustomFrameView.actions) {
menu.addItem(i => {
i.setTitle(action.name);
i.setIcon(action.icon);
i.onClick(() => action.action(this));
});
}
}
getViewType(): string {
return this.name;
}
getDisplayText(): string {
return this.data.displayName;
}
getIcon(): string {
return getIcon(this.data);
}
focus(): void {
this.frame.focus();
}
}
interface Action {
name: string;
icon: string;
action: (view: CustomFrameView) => any;
}

31
styles.css Normal file
View file

@ -0,0 +1,31 @@
.custom-frames-view {
padding: 0 !important;
overflow: hidden !important;
}
.custom-frames-view-file {
padding: 0;
overflow: auto;
}
.custom-frames-frame {
width: 100%;
height: 100%;
border: none;
background-color: white;
background-clip: content-box;
}
.custom-frames-add {
margin-left: 10px;
}
.custom-frames-show {
margin-bottom: 18px;
}
.custom-frames-support {
max-width: 50%;
width: 400px;
height: auto;
}

3
test-vault/.obsidian/app.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"promptDelete": false
}

3
test-vault/.obsidian/appearance.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"accentColor": ""
}

View file

@ -0,0 +1,3 @@
[
"obsidian-custom-frames"
]

View file

@ -0,0 +1,30 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"outgoing-link": true,
"tag-pane": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"starred": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": false,
"canvas": true,
"bookmarks": true
}

20
test-vault/.obsidian/core-plugins.json vendored Normal file
View file

@ -0,0 +1,20 @@
[
"file-explorer",
"global-search",
"switcher",
"graph",
"backlink",
"canvas",
"outgoing-link",
"tag-pane",
"page-preview",
"daily-notes",
"templates",
"note-composer",
"command-palette",
"editor-status",
"bookmarks",
"outline",
"word-count",
"file-recovery"
]

22
test-vault/.obsidian/graph.json vendored Normal file
View file

@ -0,0 +1,22 @@
{
"collapse-filter": true,
"search": "",
"showTags": false,
"showAttachments": false,
"hideUnresolved": false,
"showOrphans": true,
"collapse-color-groups": true,
"colorGroups": [],
"collapse-display": true,
"showArrow": false,
"textFadeMultiplier": 0,
"nodeSizeMultiplier": 1,
"lineSizeMultiplier": 1,
"collapse-forces": true,
"centerStrength": 0.518713248970312,
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
"scale": 1,
"close": false
}

11
test-vault/.obsidian/hotkeys.json vendored Normal file
View file

@ -0,0 +1,11 @@
{
"app:reload": [
{
"modifiers": [
"Mod",
"Shift"
],
"key": "R"
}
]
}

View file

@ -0,0 +1,3 @@
*
!.gitignore
!data.json

View file

@ -0,0 +1,49 @@
{
"frames": [
{
"url": "https://forum.obsidian.md/",
"displayName": "Obsidian Forum",
"icon": "edit",
"hideOnMobile": true,
"addRibbonIcon": true,
"openInCenter": true,
"zoomLevel": 1,
"forceIframe": false,
"customCss": ""
},
{
"url": "https://keep.google.com",
"displayName": "Google Keep",
"icon": "files",
"hideOnMobile": true,
"addRibbonIcon": false,
"openInCenter": false,
"zoomLevel": 1,
"forceIframe": false,
"customCss": "/* hide the menu bar, the \"Keep\" text and the Google Apps button */\nhtml > body > div:nth-child(2) > div:nth-child(2) > div:first-child, \nhtml > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child > span, \nhtml > body > div:first-child > header:first-child > div:nth-child(2) > div:first-child > div:first-child, \nhtml > body > div:first-child > header:first-child > div:nth-child(2) > div:nth-child(3) > div:first-child > div:first-child > div:first-child { \n\tdisplay: none !important; \n}\nhtml > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child {\n\tcursor: default; \n}"
},
{
"url": "https://calendar.google.com/calendar",
"displayName": "Google Calendar",
"icon": "calendar",
"hideOnMobile": true,
"addRibbonIcon": true,
"openInCenter": true,
"zoomLevel": 1,
"forceIframe": false,
"customCss": "/* hide the menu bar, \"Keep\" text, and logo */\nhtml > body > div:nth-child(2) > div:nth-child(2) > div:first-child[class*=\" \"],\nhtml > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child,\nhtml > body > div:nth-child(2) > div:nth-child(2) > div:first-child > div:first-child {\ndisplay: none !important;\n}"
},
{
"url": "https://scholar.google.com",
"displayName": "Scholar",
"icon": "book",
"hideOnMobile": false,
"addRibbonIcon": true,
"openInCenter": false,
"zoomLevel": 1,
"forceIframe": false,
"customCss": ""
}
],
"padding": 5
}

View file

@ -0,0 +1,6 @@
{
"nodes":[
{"id":"98d23d47aafe2b68","x":-480,"y":-360,"width":795,"height":535,"type":"link","url":"https://calendar.google.com"}
],
"edges":[]
}

0
test-vault/note.md Normal file
View file

View file

@ -1,23 +1,23 @@
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"lib": [
"DOM",
"ES5",
"ES6",
"ES7"
]
},
"include": [
"**/*.ts"
]
}
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"lib": [
"DOM",
"ES5",
"ES6",
"ES7"
]
},
"include": [
"**/*.ts"
]
}

View file

@ -1,14 +0,0 @@
import { readFileSync, writeFileSync } from "fs";
const targetVersion = process.env.npm_package_version;
// read minAppVersion from manifest.json and bump version to target version
let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
const { minAppVersion } = manifest;
manifest.version = targetVersion;
writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
// update versions.json with target version and minAppVersion from manifest.json
let versions = JSON.parse(readFileSync("versions.json", "utf8"));
versions[targetVersion] = minAppVersion;
writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));

View file

@ -1,4 +1,17 @@
{
"1.0.0": "0.13.33",
"1.0.1": "0.13.33"
}
{
"2.0.0": "0.13.33",
"2.0.1": "0.13.33",
"2.1.0": "0.13.33",
"2.2.0": "0.14.3",
"2.2.1": "0.14.3",
"2.2.2": "0.14.3",
"2.3.0": "0.14.5",
"2.4.0": "0.14.5",
"2.4.1": "0.14.5",
"2.4.2": "0.14.5",
"2.4.3": "0.15.5",
"2.4.4": "0.16.0",
"2.4.5": "1.1.0",
"2.4.6": "1.2.0",
"2.4.7": "1.2.0"
}