├── .editorconfig ├── .github └── workflows │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── Justfile ├── LICENCE ├── README.md ├── docs ├── .obsidian │ ├── app.json │ ├── appearance.json │ ├── community-plugins.json │ ├── core-plugins-migration.json │ ├── core-plugins.json │ ├── graph.json │ ├── hotkeys.json │ ├── plugins │ │ └── obsidian-metatable │ │ │ ├── data.json │ │ │ ├── manifest.json │ │ │ ├── styles.css │ │ │ └── versions.json │ └── snippets │ │ ├── anatomy.css │ │ ├── custom_properties.css │ │ └── parts.css ├── changelog.md ├── decision_log │ ├── 2021-04-19_web_component.md │ ├── 2021-04-20_details_usage.md │ ├── 2021-04-28_css_grid.md │ ├── 2021-05-10_customise_tags.md │ ├── 2022-08-29_sidebar_view.md │ └── 2022-08-29_solidjs.md ├── examples │ ├── aliases.md │ ├── all_in_one.md │ ├── anatomy.md │ ├── basic.md │ ├── custom_properties.md │ ├── filtered_keys.md │ ├── links.md │ ├── null_values.md │ ├── parts.md │ └── skip_key.md ├── index.md ├── screenshots │ ├── anatomy.png │ ├── basic.png │ └── null_settings.png ├── sections │ ├── anatomy.md │ ├── autolinks.md │ ├── configuration.md │ ├── customising_colours_and_symbols.md │ ├── customising_parts.md │ ├── decision_log.md │ ├── getting_started.md │ ├── inline_metatable.md │ ├── installation.md │ ├── sidebar_metatable.md │ └── tags.md └── tests │ ├── broken-tags.md │ ├── broken.md │ ├── chinese-tags.md │ ├── emoji-tags.md │ ├── extreme.md │ ├── long-keys.md │ ├── none.md │ ├── normalise-tags.md │ ├── pdf_export.md │ ├── tags.md │ └── title with spaces.md ├── esbuild.config.mjs ├── jest.config.js ├── manifest.json ├── package-lock.json ├── package.json ├── screenshot.png ├── src ├── components │ ├── ExternalLink.tsx │ ├── Inline.tsx │ ├── InternalLink.tsx │ ├── Leaf.tsx │ ├── List.tsx │ ├── Member.tsx │ ├── Metatable.tsx │ ├── ParseError.tsx │ ├── Set.tsx │ ├── Sidebar.tsx │ ├── Tag.tsx │ └── Value.tsx ├── core.ts ├── frontmatter.ts ├── inliner.tsx ├── main.ts ├── metatable.css ├── mixture.tsx ├── plugin.ts ├── settings.ts ├── sidebarView.tsx ├── state.ts └── value.ts ├── styles.css ├── support └── version-bump.mjs ├── tsconfig.json └── versions.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_size = 2 8 | indent_style = space 9 | trim_trailing_whitespace = true 10 | max_line_length = 79 11 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Obsidian Plugin 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | env: 9 | PLUGIN_NAME: obsidian-metatable 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Setup node 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: "18.x" 21 | - name: Build 22 | id: build 23 | run: | 24 | npm install 25 | npm run dist 26 | mkdir ${{ env.PLUGIN_NAME }} 27 | cp dist/* ${{ env.PLUGIN_NAME }} 28 | zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }} 29 | ls 30 | echo "::set-output name=tag_name::$(git tag --sort version:refname | tail -n 1)" 31 | - name: Cut Release 32 | id: create_release 33 | uses: actions/create-release@v1 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | VERSION: ${{ github.ref }} 37 | with: 38 | tag_name: ${{ github.ref }} 39 | release_name: ${{ github.ref }} 40 | draft: false 41 | prerelease: false 42 | - name: Upload zip 43 | id: upload-zip 44 | uses: actions/upload-release-asset@v1 45 | env: 46 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 47 | with: 48 | upload_url: ${{ steps.create_release.outputs.upload_url }} 49 | asset_path: ./${{ env.PLUGIN_NAME }}.zip 50 | asset_name: ${{ env.PLUGIN_NAME }}-${{ steps.build.outputs.tag_name }}.zip 51 | asset_content_type: application/zip 52 | - name: Upload main.js 53 | id: upload-main 54 | uses: actions/upload-release-asset@v1 55 | env: 56 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | with: 58 | upload_url: ${{ steps.create_release.outputs.upload_url }} 59 | asset_path: ./dist/main.js 60 | asset_name: main.js 61 | asset_content_type: text/javascript 62 | - name: Upload manifest.json 63 | id: upload-manifest 64 | uses: actions/upload-release-asset@v1 65 | env: 66 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 67 | with: 68 | upload_url: ${{ steps.create_release.outputs.upload_url }} 69 | asset_path: ./dist/manifest.json 70 | asset_name: manifest.json 71 | asset_content_type: application/json 72 | - name: Upload styles.css 73 | id: upload-css 74 | uses: actions/upload-release-asset@v1 75 | env: 76 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 77 | with: 78 | upload_url: ${{ steps.create_release.outputs.upload_url }} 79 | asset_path: ./dist/styles.css 80 | asset_name: styles.css 81 | asset_content_type: text/css 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # npm 2 | node_modules 3 | 4 | # build 5 | main.js 6 | *.js.map 7 | 8 | # dist 9 | dist 10 | 11 | ## docs 12 | docs/.obsidian/themes 13 | docs/.obsidian/workspace 14 | docs/.obsidian/workspace.json 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | ## 0.14.7 5 | 6 | - Warn users of this plugin that Obsidian 1.4 broke it. 7 | 8 | ## 0.14.6 9 | 10 | - Fix mobile rendering (#45). This was due a webkit bug that forced the removal of customisations for the root `summary`. 11 | - Fix relative links (#47). 12 | 13 | ## 0.14.5 14 | 15 | - Handle aliases as a special case (#49). 16 | 17 | ## 0.14.4 18 | 19 | - Upgrade to Obsidian 1.1 20 | - Upgrade dependencies due to CVE-2022-46175 21 | 22 | ## 0.14.3 23 | 24 | - Fix (#37) local URLs should not be encoded as URIs. 25 | - Fix tag parts should not be encoded as URIs. 26 | 27 | ## 0.14.2 28 | 29 | - Fix (#38) tag URLs should not be encoded as URIs. 30 | 31 | ## 0.14.1 32 | 33 | - Fix (#36) tag normalisation when tags are separated by spaces. 34 | 35 | ## 0.14.0 36 | 37 | - (**breaking**) Restructure markup and use [Solid.js](https://www.solidjs.com/) instead of plain DOM. 38 | - (**breaking**) Normalise custom properties. See [customising colours and symbols](./docs/customising_colours_and_symbols) for the full list. 39 | - Add parts for leaf types (number, boolean, null, ISO date). 40 | - Add new [documentation](./docs). **It works as an Obsidian vault**. 41 | - Add sidebar view. 42 | - Add experimental "tight" boundary to change styles when the container is smaller than 260px. If and when Obsidian has a web renderer with support for [CSS Container Queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries) this will be reverted. 43 | - Add Markdown autolinks. 44 | 45 | 46 | ## 0.13.1 47 | 48 | - Fix custom text for frontmatter links. 49 | 50 | ## 0.13.0 51 | 52 | - Add `--metatable-member-gap`. 53 | - Add parts for `summary`, `member`, `set` and `marker`. 54 | - Fix preserving filter keys with the same starting substring. 55 | - Fix processing tags when the YAML key is capitalised. 56 | - Add custom text for wikilinks. 57 | 58 | ## 0.12.0 59 | 60 | - Add warning when the frontmatter is not valid YAML. 61 | - Fix preserving the folded frontmatter when in edit mode. 62 | 63 | ## 0.11.0 64 | 65 | - Improve filter key settings UX. 66 | - Add zotero links. Thanks @MaroLIACS 67 | - Add `naked` experimental setting. 68 | - Add `root-collapsed` expansion level. 69 | 70 | ## 0.10.4 71 | 72 | - Fix metatable duplication in embedded notes [bug #12](https://github.com/arnau/obsidian-metatable/issues/12) 73 | 74 | ## 0.10.3 75 | 76 | - Add parts for `link`, `external-link` and `internal-link`. 77 | - Fix parts `key` and `value`. 78 | - Fix vertical alignment for keys. 79 | 80 | ## 0.10.2 81 | 82 | - Add parts for `key` and `value`. 83 | 84 | ## 0.10.1 85 | 86 | - Fix scrolls always showing in Windows. 87 | 88 | ## 0.10.0 89 | 90 | - Add filter mode to either ignore or keep the listed keys. 91 | 92 | ## 0.9.1 93 | 94 | - Fix complex structures in small-screens. 95 | 96 | ## 0.9.0 97 | 98 | - Fix internal links. Now they use the Obsidian default behaviour. 99 | - Remove `--metatable-key-min-width`. 100 | - Add small-screen layout. 101 | 102 | ## 0.8.4 103 | 104 | - Ignore empty arrays when null values are to be ignored. 105 | 106 | ## 0.8.3 107 | 108 | - Ignore ignored keys when checking top-level keys. 109 | 110 | ## 0.8.2 111 | 112 | - Avoid rendering anything if all top-level keys are null and nulls are to be ignored. 113 | 114 | ## 0.8.1 115 | 116 | - Fix tags with spaces. 117 | 118 | ## 0.8.0 119 | 120 | - Add `::part` to enable full tag customisation. 121 | 122 | ## 0.7.2 123 | 124 | - Fix internal link styles (`--metatable-internal-link-icon`, `--metatable-internal-link-color`, `--metatable-internal-link-color-hover`). 125 | 126 | ## 0.7.1 127 | 128 | - Fix numeric values. 129 | - Add evernote autolinking. 130 | - Add custom property `--metatable-tag-symbol`. 131 | 132 | ## 0.7.0 133 | 134 | - Add autolinking (under a feature flag). 135 | 136 | ## 0.6.1 137 | 138 | - Fix opening external links. 139 | 140 | ## 0.6.0 141 | 142 | - Make tags non-foldable. 143 | - Add toggle to ignore members with null values. 144 | 145 | ## 0.5.3 146 | 147 | - Add skip key to avoid displaying the metatable for a document. 148 | - Add ignored key list to not display any of these keys in the metatable. 149 | 150 | ## 0.5.2 151 | 152 | - Handle null values. 153 | - Add null value setting. 154 | - Autolink external links (http, https). 155 | 156 | ## 0.5.1 157 | 158 | - Link comma-separated tags. 159 | -------------------------------------------------------------------------------- /Justfile: -------------------------------------------------------------------------------- 1 | icloud_basepath := "$HOME/Library/Mobile Documents/iCloud~md~obsidian/Documents" 2 | icloud_path := icloud_basepath / "docs/.obsidian/plugins/obsidian-metatable/" 3 | 4 | icloud-sync: 5 | npm run docs 6 | cp -R dist/* "{{icloud_path}}" 7 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Arnau Siches 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Obsidian Metatable 2 | 3 | *** 4 | **DEPRECATION NOTICE**: This Obsidan plugin is no longer actively maintained. 5 | New developments in Obsidian itself have made clear I'm no longer interested in 6 | the tool nor maintaining a plugin for it. 7 | *** 8 | 9 | A plugin for [Obsidian] to display the full frontmatter block instead of just the list of tags. 10 | 11 | 12 | ![screenshot](screenshot.png) 13 | 14 | ## Changelog 15 | 16 | - 0.14.7 17 | - Warn users of this plugin that Obsidian 1.4 broke it. 18 | - 0.14.6 19 | - Fix mobile rendering (#45). This was due a webkit bug that forced the removal of customisations for the root `summary`. 20 | - Fix relative links (#47). 21 | - 0.14.5 22 | - Handle aliases as a special case (#49). 23 | - 0.14.4 24 | - Upgrade to Obsidian 1.1 25 | - Upgrade dependencies due to CVE-2022-46175 26 | - 0.14.3 27 | - Fix (#37) local URLs should not be encoded as URIs. 28 | - Fix tag parts should not be encoded as URIs. 29 | - 0.14.2 30 | - Fix (#38) tag URLs should not be encoded as URIs. 31 | - 0.14.1 32 | - Fix (#36) tag normalisation when tags are separated by spaces. 33 | - 0.14.0 34 | - (**breaking**) Restructure markup and use [Solid.js](https://www.solidjs.com/) instead of plain DOM. 35 | - (**breaking**) Normalise custom properties. See [customising colours and symbols](https://github.com/arnau/obsidian-metatable/blob/main/docs/sections/customising_colours_and_symbols.md) for the full list. 36 | - Add parts for leaf types (number, boolean, null, ISO date). 37 | - Add new [documentation](./docs). **It works as an Obsidian vault**. 38 | - Add sidebar view. 39 | - Add experimental "tight" boundary to change styles when the container is smaller than 260px. If and when Obsidian has a web renderer with support for [CSS Container Queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries) this will be reverted. 40 | - Add Markdown autolinks. 41 | 42 | 43 | 44 | See the [changelog](./CHANGELOG.md) for the full list of version. Or check the 45 | [decision log](./docs/decision_log/) for the main design choices. 46 | 47 | 48 | ## Configuration 49 | 50 | By enabling the plugin in the “Community plugins” section you'll be all set. 51 | To see the effects you'll need to open a new document or restart the vault. 52 | 53 | Check the [documentation](./docs/index.md) for a getting started, customisation 54 | strategies, examples and more. 55 | 56 | 57 | ## Installation 58 | 59 | From Obsidian: 60 | 61 | - Ensure Community Plugins are enabled. 62 | - Browse community plugins searching for **metatable**. 63 | - Click install. 64 | - Enable plugin in the “Community Plugins” Settings section. 65 | - Open a file (notice that previously opened files won't get the effects of the plugin until reopened or changed). 66 | 67 | From release: 68 | 69 | - Download the `obsidian-metatable-{version}.zip` file from the chosen release, for example the [latest release]. 70 | - Ensure “Community Plugins” are enabled in Settings. 71 | - Ensure the `.obsidian/plugins/` directory exists in your vault directory. 72 | - Expand the zip file into the `.obsidian/plugins/` directory such that an `obsidian-metatable` directory is a direct child of `plugins`. 73 | - Enable plugin in the “Community Plugins” Settings section. 74 | - Open a file (notice that previously opened files won't get the effects of the plugin until reopened or changed). 75 | 76 | From source: 77 | 78 | - Clone the [source repository]. 79 | - Run `npm install`. 80 | - Run `npm run build`. 81 | - Create an `obsidian-metatable` directory under your vault's `.obsidian/plugins/` directory. 82 | - Copy over `main.js`, `versions.json` and `manifest.json`. 83 | - Enable plugin in the “Community Plugins” Settings section. 84 | - Open a file (notice that previously opened files won't get the effects of the plugin until reopened or changed). 85 | 86 | 87 | ## Licence 88 | 89 | Arnau Siches under the [MIT License](./LICENCE) 90 | 91 | 92 | [Obsidian]: https://www.obsidian.md/ 93 | [latest release]: https://github.com/arnau/obsidian-metatable/releases/latest 94 | [source repository]: https://github.com/arnau/obsidian-metatable 95 | -------------------------------------------------------------------------------- /docs/.obsidian/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "useTab": false, 3 | "alwaysUpdateLinks": true, 4 | "legacyEditor": false, 5 | "livePreview": true, 6 | "promptDelete": false, 7 | "rightToLeft": false, 8 | "showFrontmatter": true, 9 | "pdfExportSettings": { 10 | "pageSize": "Letter", 11 | "landscape": false, 12 | "margin": "0", 13 | "downscalePercent": 100 14 | } 15 | } -------------------------------------------------------------------------------- /docs/.obsidian/appearance.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "moonstone", 3 | "enabledCssSnippets": [ 4 | "metatable_colours" 5 | ], 6 | "baseFontSize": 16, 7 | "cssTheme": "", 8 | "accentColor": "" 9 | } -------------------------------------------------------------------------------- /docs/.obsidian/community-plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | "obsidian-metatable" 3 | ] -------------------------------------------------------------------------------- /docs/.obsidian/core-plugins-migration.json: -------------------------------------------------------------------------------- 1 | { 2 | "file-explorer": true, 3 | "global-search": true, 4 | "switcher": true, 5 | "graph": true, 6 | "backlink": true, 7 | "outgoing-link": true, 8 | "tag-pane": true, 9 | "page-preview": true, 10 | "daily-notes": true, 11 | "templates": true, 12 | "note-composer": true, 13 | "command-palette": true, 14 | "slash-command": true, 15 | "editor-status": false, 16 | "starred": true, 17 | "markdown-importer": true, 18 | "zk-prefixer": true, 19 | "random-note": true, 20 | "outline": true, 21 | "word-count": true, 22 | "slides": true, 23 | "audio-recorder": true, 24 | "workspaces": true, 25 | "file-recovery": true, 26 | "publish": false, 27 | "sync": false, 28 | "canvas": true, 29 | "bookmarks": true 30 | } -------------------------------------------------------------------------------- /docs/.obsidian/core-plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | "file-explorer", 3 | "global-search", 4 | "switcher", 5 | "graph", 6 | "backlink", 7 | "canvas", 8 | "outgoing-link", 9 | "tag-pane", 10 | "page-preview", 11 | "daily-notes", 12 | "templates", 13 | "note-composer", 14 | "command-palette", 15 | "slash-command", 16 | "bookmarks", 17 | "markdown-importer", 18 | "zk-prefixer", 19 | "random-note", 20 | "outline", 21 | "word-count", 22 | "slides", 23 | "audio-recorder", 24 | "workspaces", 25 | "file-recovery" 26 | ] -------------------------------------------------------------------------------- /docs/.obsidian/graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "collapse-filter": true, 3 | "search": "", 4 | "showTags": false, 5 | "showAttachments": false, 6 | "hideUnresolved": false, 7 | "showOrphans": true, 8 | "collapse-color-groups": true, 9 | "colorGroups": [], 10 | "collapse-display": true, 11 | "showArrow": false, 12 | "textFadeMultiplier": 0, 13 | "nodeSizeMultiplier": 1, 14 | "lineSizeMultiplier": 1, 15 | "collapse-forces": true, 16 | "centerStrength": 0.518713248970312, 17 | "repelStrength": 10, 18 | "linkStrength": 1, 19 | "linkDistance": 250, 20 | "scale": 1, 21 | "close": false 22 | } -------------------------------------------------------------------------------- /docs/.obsidian/hotkeys.json: -------------------------------------------------------------------------------- 1 | { 2 | "obsidian-metatable:toggle-metatable-sidebar": [ 3 | { 4 | "modifiers": [ 5 | "Ctrl" 6 | ], 7 | "key": "M" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /docs/.obsidian/plugins/obsidian-metatable/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "expansionMode": "expanded", 3 | "ignoreNulls": false, 4 | "nullValue": "NA", 5 | "skipKey": "metatable", 6 | "filterKeys": [ 7 | "metatable", 8 | "frontmatter", 9 | "ignored-key", 10 | "" 11 | ], 12 | "filterMode": "ignore", 13 | "autolinks": true, 14 | "naked": false, 15 | "theme": "light", 16 | "ignoredKeys": [], 17 | "vault": null 18 | } -------------------------------------------------------------------------------- /docs/.obsidian/plugins/obsidian-metatable/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "obsidian-metatable", 3 | "name": "Metatable", 4 | "version": "0.14.7", 5 | "minAppVersion": "0.15.9", 6 | "description": "Displays the full frontmatter as a table.", 7 | "author": "Arnau Siches", 8 | "authorUrl": "https://www.seachess.net/", 9 | "isDesktopOnly": false 10 | } -------------------------------------------------------------------------------- /docs/.obsidian/plugins/obsidian-metatable/styles.css: -------------------------------------------------------------------------------- 1 | /* Obsidian metatable default styles */ 2 | 3 | /* 4 | * Styles are wrapped inside a shadow DOM. If you want to see them go to https://github.com/arnau/obsidian-metatable/blob/main/src/metatable.css 5 | * 6 | * You might also find useful the documentation found at https://github.com/arnau/obsidian-metatable/blob/main/docs/ which is an Obsidian vault ready to use. 7 | */ 8 | -------------------------------------------------------------------------------- /docs/.obsidian/plugins/obsidian-metatable/versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "0.2.0": "0.11.13", 3 | "0.3.0": "0.11.13", 4 | "0.4.0": "0.11.13", 5 | "0.4.1": "0.11.13", 6 | "0.5.0": "0.11.13", 7 | "0.5.1": "0.11.13", 8 | "0.5.2": "0.11.13", 9 | "0.5.3": "0.11.13", 10 | "0.6.0": "0.11.13", 11 | "0.6.1": "0.11.13", 12 | "0.7.0": "0.11.13", 13 | "0.7.1": "0.11.13", 14 | "0.7.2": "0.11.13", 15 | "0.8.0": "0.11.13", 16 | "0.8.1": "0.11.13", 17 | "0.8.2": "0.11.13", 18 | "0.8.3": "0.11.13", 19 | "0.8.4": "0.11.13", 20 | "0.9.0": "0.12.3", 21 | "0.9.1": "0.12.3", 22 | "0.10.0": "0.12.3", 23 | "0.10.1": "0.12.3", 24 | "0.10.2": "0.12.3", 25 | "0.10.3": "0.12.3", 26 | "0.10.4": "0.12.19", 27 | "0.11.0": "0.12.19", 28 | "0.12.0": "0.15.9", 29 | "0.13.0": "0.15.9", 30 | "0.13.1": "0.15.9", 31 | "0.14.0": "0.15.9", 32 | "0.14.1": "0.15.9", 33 | "0.14.2": "0.15.9", 34 | "0.14.3": "0.15.9", 35 | "0.14.4": "0.15.9", 36 | "0.14.5": "0.15.9", 37 | "0.14.6": "0.15.9", 38 | "0.14.7": "0.15.9" 39 | } -------------------------------------------------------------------------------- /docs/.obsidian/snippets/anatomy.css: -------------------------------------------------------------------------------- 1 | .obsidian-metatable-sidebar::part(root) { 2 | position: relative; 3 | background-color: gold; 4 | margin: 20px; 5 | padding: 20px; 6 | } 7 | 8 | .obsidian-metatable-sidebar::part(root)::before { 9 | content: "root"; 10 | 11 | line-height: 1rem; 12 | display: inline-block; 13 | position: absolute; 14 | top: 8px; 15 | right: -20px; 16 | transform: rotate(90deg); 17 | background-color: gold; 18 | color: brown; 19 | padding: 0px 4px; 20 | } 21 | 22 | 23 | .obsidian-metatable-sidebar::part(member) { 24 | grid-gap: 20px; 25 | grid-template-columns: minmax(0, 2fr) minmax(0, 4fr); 26 | 27 | position: relative; 28 | background-color: brown; 29 | margin: 0 20px 20px 10px; 30 | padding: 20px 10px; 31 | } 32 | 33 | .obsidian-metatable-sidebar::part(member)::before { 34 | content: "member"; 35 | 36 | line-height: 1rem; 37 | display: inline-block; 38 | position: absolute; 39 | top: 20px; 40 | right: -30px; 41 | transform: rotate(90deg); 42 | background-color: brown; 43 | color: gold; 44 | padding: 0 4px; 45 | } 46 | 47 | 48 | .obsidian-metatable-sidebar::part(key) { 49 | position: relative; 50 | background-color: deepskyblue; 51 | padding: 10px; 52 | overflow: visible; 53 | } 54 | 55 | .obsidian-metatable-sidebar::part(key)::before { 56 | content: "key"; 57 | 58 | line-height: 1rem; 59 | display: inline-block; 60 | position: absolute; 61 | top: 7px; 62 | right: -20px; 63 | transform: rotate(90deg); 64 | background-color: deepskyblue; 65 | color: black; 66 | padding: 0px 4px; 67 | } 68 | 69 | /* .obsidian-metatable-sidebar::part(key):hover::before { */ 70 | /* content: "key"; */ 71 | /**/ 72 | /* line-height: 1rem; */ 73 | /* display: inline-block; */ 74 | /* position: absolute; */ 75 | /* top: 7px; */ 76 | /* right: -20px; */ 77 | /* transform: rotate(90deg); */ 78 | /* background-color: deepskyblue; */ 79 | /* color: black; */ 80 | /* padding: 0px 4px; */ 81 | /* } */ 82 | 83 | .obsidian-metatable-sidebar::part(value) { 84 | position: relative; 85 | background-color: lightblue; 86 | color: black; 87 | padding: 10px; 88 | margin-right: 20px; 89 | overflow: visible; 90 | } 91 | 92 | .obsidian-metatable-sidebar::part(value)::before { 93 | content: "value"; 94 | 95 | line-height: 1rem; 96 | display: inline-block; 97 | position: absolute; 98 | top: 12px; 99 | right: -25px; 100 | transform: rotate(90deg); 101 | background-color: lightblue; 102 | color: black; 103 | padding: 0px 4px; 104 | } 105 | 106 | .obsidian-metatable-sidebar::part(list) { 107 | position: relative; 108 | background-color: lightpink; 109 | color: black; 110 | padding: 10px; 111 | margin-right: 20px; 112 | } 113 | 114 | .obsidian-metatable-sidebar::part(list)::before { 115 | content: "list"; 116 | 117 | line-height: 1rem; 118 | display: inline-block; 119 | position: absolute; 120 | top: 5px; 121 | right: -20px; 122 | transform: rotate(90deg); 123 | background-color: lightpink; 124 | color: black; 125 | padding: 0px 4px; 126 | } 127 | 128 | .obsidian-metatable-sidebar::part(list-item) { 129 | position: relative; 130 | background-color: deeppink; 131 | color: lightpink; 132 | padding: 18px; 133 | margin: 20px 20px 0 0; 134 | } 135 | 136 | .obsidian-metatable-sidebar::part(list-item)::before { 137 | content: "list-item"; 138 | 139 | line-height: 1rem; 140 | display: inline-block; 141 | position: absolute; 142 | top: 18px; 143 | right: -33px; 144 | transform: rotate(90deg); 145 | background-color: deeppink; 146 | color: lightpink; 147 | padding: 0px 4px; 148 | } 149 | 150 | 151 | .obsidian-metatable-sidebar::part(set) { 152 | position: relative; 153 | background-color: lightpink; 154 | color: black; 155 | padding: 10px; 156 | margin-right: 20px; 157 | } 158 | 159 | .obsidian-metatable-sidebar::part(set)::before { 160 | content: "set"; 161 | 162 | line-height: 1rem; 163 | display: inline-block; 164 | position: absolute; 165 | top: 5px; 166 | right: -20px; 167 | transform: rotate(90deg); 168 | background-color: lightpink; 169 | color: black; 170 | padding: 0px 4px; 171 | } 172 | 173 | .obsidian-metatable-sidebar::part(boolean), 174 | .obsidian-metatable-sidebar::part(isodate), 175 | .obsidian-metatable-sidebar::part(number) 176 | { 177 | color: black; 178 | } 179 | -------------------------------------------------------------------------------- /docs/.obsidian/snippets/custom_properties.css: -------------------------------------------------------------------------------- 1 | .theme-light .obsidian-metatable, 2 | .theme-light .obsidian-metatable-sidebar 3 | { 4 | --metatable-text-primary: cornflowerblue; 5 | 6 | --metatable-tag-color: deeppink; 7 | --metatable-tag-symbol: "⁍ "; 8 | 9 | --metatable-collapsed-symbol: "😶"; 10 | --metatable-expanded-symbol: "😎"; 11 | 12 | --metatable-leaf-nil-color: gainsboro; 13 | 14 | --metatable-text-link: black; 15 | } 16 | -------------------------------------------------------------------------------- /docs/.obsidian/snippets/parts.css: -------------------------------------------------------------------------------- 1 | .obsidian-metatable-sidebar::part(root) { 2 | margin-left: 20px; 3 | } 4 | 5 | .obsidian-metatable-sidebar::part(member) { 6 | all: unset; 7 | display: block; 8 | } 9 | 10 | .obsidian-metatable-sidebar::part(key) { 11 | all: unset; 12 | display: block; 13 | font-weight: bold; 14 | } 15 | 16 | .obsidian-metatable-sidebar::part(key toggle) { 17 | all: unset; 18 | display: grid; 19 | grid-template-columns: 10px auto; 20 | grid-gap: 4px; 21 | font-weight: bold; 22 | } 23 | 24 | 25 | .obsidian-metatable-sidebar::part(value) { 26 | all: unset; 27 | display: block; 28 | padding-left: 20px; 29 | } 30 | 31 | 32 | .obsidian-metatable-sidebar::part(list-item-tags) { 33 | margin: 0; 34 | } 35 | 36 | .obsidian-metatable-sidebar::part(tag) { 37 | background-color: pink; 38 | } 39 | 40 | .obsidian-metatable-sidebar::part(tag):hover { 41 | filter: none; 42 | background-color: gold; 43 | color: black; 44 | } 45 | 46 | .obsidian-metatable-sidebar::part(tag important) { 47 | color: white; 48 | background-color: tomato; 49 | } 50 | 51 | .obsidian-metatable-sidebar::part(tag example) { 52 | color: black; 53 | background-color: deepskyblue; 54 | } 55 | 56 | .obsidian-metatable-sidebar::part(tag avocado) { 57 | --metatable-tag-symbol: "🥑 "; 58 | 59 | color: black; 60 | background-color: #83af2e; 61 | } 62 | -------------------------------------------------------------------------------- /docs/changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | ## 0.14.7 5 | 6 | - Warn users of this plugin that Obsidian 1.4 broke it. 7 | 8 | ## 0.14.6 9 | 10 | - Fix mobile rendering (#45). This was due a webkit bug that forced the removal of customisations for the root `summary`. 11 | - Fix relative links (#47). 12 | 13 | ## 0.14.5 14 | 15 | - Handle aliases as a special case (#49). 16 | 17 | ## 0.14.4 18 | 19 | - Upgrade to Obsidian 1.1 20 | - Upgrade dependencies due to CVE-2022-46175 21 | 22 | ## 0.14.3 23 | 24 | - Fix (#37) local URLs should not be encoded as URIs. 25 | - Fix tag parts should not be encoded as URIs. 26 | 27 | ## 0.14.2 28 | 29 | - Fix (#38) tag URLs should not be encoded as URIs. 30 | 31 | ## 0.14.1 32 | 33 | - Fix (#36) tag normalisation when tags are separated by spaces. 34 | 35 | ## 0.14.0 36 | 37 | - (**breaking**) Restructure markup and use [Solid.js](https://www.solidjs.com/) instead of plain DOM. 38 | - (**breaking**) Normalise custom properties. See [customising colours and symbols](./docs/customising_colours_and_symbols) for the full list. 39 | - Add parts for leaf types (number, boolean, null, ISO date). 40 | - Add new [documentation](./docs). **It works as an Obsidian vault**. 41 | - Add sidebar view. 42 | - Add experimental "tight" boundary to change styles when the container is smaller than 260px. If and when Obsidian has a web renderer with support for [CSS Container Queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries) this will be reverted. 43 | - Add Markdown autolinks. 44 | 45 | 46 | ## 0.13.1 47 | 48 | - Fix custom text for frontmatter links. 49 | 50 | ## 0.13.0 51 | 52 | - Add `--metatable-member-gap`. 53 | - Add parts for `summary`, `member`, `set` and `marker`. 54 | - Fix preserving filter keys with the same starting substring. 55 | - Fix processing tags when the YAML key is capitalised. 56 | - Add custom text for wikilinks. 57 | 58 | ## 0.12.0 59 | 60 | - Add warning when the frontmatter is not valid YAML. 61 | - Fix preserving the folded frontmatter when in edit mode. 62 | 63 | ## 0.11.0 64 | 65 | - Improve filter key settings UX. 66 | - Add zotero links. Thanks @MaroLIACS 67 | - Add `naked` experimental setting. 68 | - Add `root-collapsed` expansion level. 69 | 70 | ## 0.10.4 71 | 72 | - Fix metatable duplication in embedded notes [bug #12](https://github.com/arnau/obsidian-metatable/issues/12) 73 | 74 | ## 0.10.3 75 | 76 | - Add parts for `link`, `external-link` and `internal-link`. 77 | - Fix parts `key` and `value`. 78 | - Fix vertical alignment for keys. 79 | 80 | ## 0.10.2 81 | 82 | - Add parts for `key` and `value`. 83 | 84 | ## 0.10.1 85 | 86 | - Fix scrolls always showing in Windows. 87 | 88 | ## 0.10.0 89 | 90 | - Add filter mode to either ignore or keep the listed keys. 91 | 92 | ## 0.9.1 93 | 94 | - Fix complex structures in small-screens. 95 | 96 | ## 0.9.0 97 | 98 | - Fix internal links. Now they use the Obsidian default behaviour. 99 | - Remove `--metatable-key-min-width`. 100 | - Add small-screen layout. 101 | 102 | ## 0.8.4 103 | 104 | - Ignore empty arrays when null values are to be ignored. 105 | 106 | ## 0.8.3 107 | 108 | - Ignore ignored keys when checking top-level keys. 109 | 110 | ## 0.8.2 111 | 112 | - Avoid rendering anything if all top-level keys are null and nulls are to be ignored. 113 | 114 | ## 0.8.1 115 | 116 | - Fix tags with spaces. 117 | 118 | ## 0.8.0 119 | 120 | - Add `::part` to enable full tag customisation. 121 | 122 | ## 0.7.2 123 | 124 | - Fix internal link styles (`--metatable-internal-link-icon`, `--metatable-internal-link-color`, `--metatable-internal-link-color-hover`). 125 | 126 | ## 0.7.1 127 | 128 | - Fix numeric values. 129 | - Add evernote autolinking. 130 | - Add custom property `--metatable-tag-symbol`. 131 | 132 | ## 0.7.0 133 | 134 | - Add autolinking (under a feature flag). 135 | 136 | ## 0.6.1 137 | 138 | - Fix opening external links. 139 | 140 | ## 0.6.0 141 | 142 | - Make tags non-foldable. 143 | - Add toggle to ignore members with null values. 144 | 145 | ## 0.5.3 146 | 147 | - Add skip key to avoid displaying the metatable for a document. 148 | - Add ignored key list to not display any of these keys in the metatable. 149 | 150 | ## 0.5.2 151 | 152 | - Handle null values. 153 | - Add null value setting. 154 | - Autolink external links (http, https). 155 | 156 | ## 0.5.1 157 | 158 | - Link comma-separated tags. 159 | -------------------------------------------------------------------------------- /docs/decision_log/2021-04-19_web_component.md: -------------------------------------------------------------------------------- 1 | --- 2 | creation_date: 2021-04-19 3 | decision_date: 2021-04-19 4 | decision_outcome: accepted 5 | tags: [decision] 6 | --- 7 | # Use Web Component for better isolation 8 | 9 | [Web Components] have three main technologies: custom elements, shadow DOM and 10 | HTML Templates. 11 | 12 | ## Proposal 13 | 14 | Use a Web component to isolate the complexities of the plugin, reduce CSS 15 | conflicts and JavaScript clashes. 16 | 17 | 18 | ## Outcome 19 | 20 | The initial approach was to use both custom elements and shadow DOM. The goals 21 | were met. 22 | 23 | The Obidian reviewers pointed out that custom elements cannot be de-registered 24 | which at all effects pollute the global namespace. 25 | 26 | Take this scenario: 27 | 28 | 1. Install plugin with custom element. 29 | 2. Enable plugin: custom element registered. 30 | 3. Disable plugin: custom element still there. 31 | 4. Uninstall plugin: custom element still there. 32 | 33 | The fact that custom elements can't be de-registred is a problem in a system 34 | where plugins should be able to clean after themselves. 35 | 36 | The second approach was to just use a shadow DOM. The goals were met. 37 | 38 | Shadow DOM is what provides the boundary preventing CSS and JavaScript to 39 | affect the other side so by not using a custom element the main goal was 40 | preserved. 41 | 42 | 43 | ## Conclusion 44 | 45 | Using the shadow DOM mechanism provides the required level of isolation. And 46 | combined with [Custom Properties] enough flexibility to tweak how the table is 47 | rendered. 48 | 49 | 50 | [Web Components]: https://developer.mozilla.org/en-US/docs/Web/Web_Components 51 | [Custom Properties]: https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties 52 | -------------------------------------------------------------------------------- /docs/decision_log/2021-04-20_details_usage.md: -------------------------------------------------------------------------------- 1 | --- 2 | creation_date: 2021-04-20 3 | decision_date: 2021-04-22 4 | decision_outcome: rejected 5 | tags: [decision] 6 | --- 7 | # Use `details` instead of `table` 8 | 9 | The [`details`] element is designed from the start to handle situations where 10 | a expand/collapse behaviour is required. 11 | 12 | ## Proposal 13 | 14 | Use a set of nested `details` to render the frontmatter tree instead of a 15 | `table` such that the logic for toggling visibility is handled natively by the 16 | browser. 17 | 18 | ## Outcome 19 | 20 | The attempt to move from a `table` structure to a `details` one requires the 21 | aid of CSS to display things as a table. The [CSS Grid] layout system is 22 | a natural choice to have full control. 23 | 24 | As it turns out, browsers (tested with Firefox and Chromium) make `details` 25 | behave uniquely and _ignore_ the `display: grid` property. A quick attempt 26 | using [Flexbox] shows the same behaviour. 27 | 28 | This alone makes `details` a useless option for anything that is not exactly 29 | what the browsers have decided is useful. 30 | 31 | ## Conclusion 32 | 33 | Given that `details` refuses to be managed by robust layout systems the choice 34 | is to revert back to `table`, JavaScript and [ARIA]. 35 | 36 | 37 | 38 | [`details`]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details 39 | [CSS Grid]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout 40 | [Flexbox]: https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox 41 | [ARIA]: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA 42 | -------------------------------------------------------------------------------- /docs/decision_log/2021-04-28_css_grid.md: -------------------------------------------------------------------------------- 1 | --- 2 | creation_date: 2021-04-28 3 | decision_date: 2021-04-28 4 | decision_outcome: accepted 5 | tags: [decision] 6 | --- 7 | # Use CSS Grid 8 | 9 | The `table` layout is famous for being rigid and full of quirks making 10 | difficult to adjust properly. The struggle increases when you use nested 11 | tables. 12 | 13 | 14 | ## Proposal 15 | 16 | Use [CSS Grid] to render a `table` as a table. The Grid layout gives full 17 | control over the 2D plane, let's you control direction, alignment, etc without 18 | getting into the quirks of padding, margin and other tools more adequate for 19 | text-flow control. 20 | 21 | 22 | ## Outcome 23 | 24 | [CSS Grid] works perfectly with `table` giving the experience you would've 25 | wanted from the start. 26 | 27 | 28 | ## Conclusion 29 | 30 | The change is accepted. 31 | 32 | 33 | [CSS Grid]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout 34 | -------------------------------------------------------------------------------- /docs/decision_log/2021-05-10_customise_tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | creation_date: 2021-05-10 3 | decision_date: 2021-04-11 4 | decision_outcome: accepted 5 | tags: [decision] 6 | --- 7 | # Customise tags 8 | 9 | The default Obsidian behaviour allows users to customise tags with enough 10 | flexibility such that they can do things like [Tag Pills]. 11 | 12 | Metatable though can't offer this way to customise things givent that it uses 13 | a shadow DOM ([Web Components]) to set boundaries between the plugin and the 14 | rest. 15 | 16 | 17 | ## Proposal 18 | 19 | Use either the [slot element] or the [::part pseudo-element] to offer a 20 | controlled way into the shadow DOM without exposing the implementation details. 21 | 22 | 23 | ## Outcome 24 | 25 | The research on using the [slot element] suggests that it only works in 26 | combination with custom elements ([rejected in favour of plain shadow 27 | DOM](2021-04-19_web_component.md)). 28 | 29 | The [::part pseudo-element] on the other hand gives good results with "just CSS". 30 | 31 | Given a frontmatter such as: 32 | 33 | ```yaml 34 | tags: 35 | - important 36 | - example 37 | ``` 38 | 39 | it will be transformed into: 40 | 41 | ```html 42 | … 43 | 44 | tags 45 | 46 | 54 | 55 | 56 | … 57 | ``` 58 | 59 | which can then be styled using “Style Snippets” like: 60 | 61 | ```css 62 | .obsidian-metatable::part(tag) { 63 | background-color: pink; 64 | } 65 | 66 | .obsidian-metatable::part(tag):hover { 67 | background-color: var(--text-accent-hover); 68 | } 69 | 70 | .obsidian-metatable::part(tag important) { 71 | color: white; 72 | background-color: tomato; 73 | } 74 | 75 | .obsidian-metatable::part(tag example) { 76 | color: black; 77 | background-color: deepskyblue; 78 | } 79 | ``` 80 | 81 | 82 | ## Conclusion 83 | 84 | The use of the [::part element] provides a well balanced compromise between 85 | flexibility and abstraction. The only potential concern is the fact that it is 86 | a working draft rather than a well established specification which is highly 87 | mitigated by the fact that Obsidian is a controlled environment using Chromium 88 | (via Electron). 89 | 90 | 91 | [Web Components]: https://developer.mozilla.org/en-US/docs/Web/Web_Components 92 | [Custom Properties]: https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties 93 | [::part pseudo-element]: https://developer.mozilla.org/en-US/docs/Web/CSS/::part 94 | [Tag Pills]: https://forum.obsidian.md/t/meta-post-common-css-hacks/1978/13 95 | [slot element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot 96 | -------------------------------------------------------------------------------- /docs/decision_log/2022-08-29_sidebar_view.md: -------------------------------------------------------------------------------- 1 | --- 2 | creation_date: 2022-08-29 3 | decision_date: 2022-08-29 4 | decision_outcome: accepted 5 | tags: [decision] 6 | --- 7 | # Add a sidebar view 8 | 9 | Since the introduction of Live Preview, the plugin has lost usefulness given 10 | that most of the time is spent in Editing Mode and very rarely in Reading Mode. 11 | 12 | ## Proposal 13 | 14 | Add a Metatable view that renders on the right hand sidebar. 15 | 16 | ## Outcome 17 | 18 | Adding a new view given how the plugin works is low effort. Some of the 19 | original behaviour might feel unnecessary though, for example the ability to 20 | collapse/expand. 21 | 22 | 23 | ## Conclusion 24 | 25 | Having the sidebar, a ribbon icon and a command bring enough value that makes 26 | the Reading Mode irrelevant. 27 | -------------------------------------------------------------------------------- /docs/decision_log/2022-08-29_solidjs.md: -------------------------------------------------------------------------------- 1 | --- 2 | creation_date: 2022-08-29 3 | decision_date: 2022-08-29 4 | decision_outcome: accepted 5 | tags: [decision] 6 | --- 7 | # Use Solid.js for the UI 8 | 9 | [Solid.js] is a library for building reactive user interfaces in TypeScript and 10 | JSX without the need for a virtual DOM layer. 11 | 12 | ## Proposal 13 | 14 | Use [Solid.js] instead of plain DOM to improve the readability and 15 | maintainability of the plugin whilst maintaining a low footprint at runtime. 16 | 17 | ## Outcome 18 | 19 | The migration has been seamless bringing clarity in terms of UI 20 | responsibilities. 21 | 22 | From a performance point of view no tests have shown anything to be concerned 23 | about which aligns with the expected minimal footprint advertised by the 24 | library. 25 | 26 | 27 | ## Conclusion 28 | 29 | Using [Solid.js] dramatically increases readability as well as state management 30 | reasoning at a very low cost. 31 | 32 | 33 | 34 | [Solid.js]: https://www.solidjs.com/ 35 | -------------------------------------------------------------------------------- /docs/examples/aliases.md: -------------------------------------------------------------------------------- 1 | --- 2 | aliases: alpha, beta, gamma 3 | tags: foo, bar 4 | --- -------------------------------------------------------------------------------- /docs/examples/all_in_one.md: -------------------------------------------------------------------------------- 1 | --- 2 | aliases: [aio, embedded] 3 | tags: [example, embed] 4 | --- 5 | # All in one example 6 | 7 | 8 | ![[basic]] 9 | 10 | ![[links]] 11 | 12 | ![[skip_key]] 13 | 14 | ![[filtered_keys]] 15 | 16 | ![[null_values]] -------------------------------------------------------------------------------- /docs/examples/anatomy.md: -------------------------------------------------------------------------------- 1 | --- 2 | scalar: Lorem ipsum 3 | list: [alpha, beta, gamma] 4 | set: {x: 1, y: 2} 5 | --- 6 | # Anatomy example 7 | 8 | To see it at work, open the Preferences, go to Appearance and select the `anatomy` CSS snippet and open the [[sidebar_metatable]]. 9 | 10 | This example illustrates the anatomy of a metatable tree. -------------------------------------------------------------------------------- /docs/examples/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | string: Lorem ipsum 3 | number: 11 4 | boolean: true 5 | nil: null 6 | date: 2022-08-27 7 | in-link: %index% 8 | out-link: https://www.seachess.net 9 | list: [alpha, beta, gamma] 10 | set: {x: 1, y: 2} 11 | tags: [example, basic, valid_yaml] 12 | --- 13 | # Basic example 14 | 15 | This example illustrates a frontmatter with different types: 16 | 17 | - string 18 | - number 19 | - boolean 20 | - null 21 | - date (only accepts ISO dates) 22 | - lists (i.e. arrays) 23 | - sets (i.e. objects) 24 | - tags. Tags are a special kind of array. -------------------------------------------------------------------------------- /docs/examples/custom_properties.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2022-09-02 3 | is_example: true 4 | ultimate_question: 42 5 | score: null 6 | website: https://www.seachess.net 7 | summary: An example to showcase customisation. 8 | tags: [test, example, avocado] 9 | --- 10 | # Custom properties 11 | 12 | To see this example at work, open the Preferences, go to Appearance and select the `custom_properties` CSS snippet. 13 | -------------------------------------------------------------------------------- /docs/examples/filtered_keys.md: -------------------------------------------------------------------------------- 1 | --- 2 | guacamole: green 3 | metatable: false 4 | frontmatter: 42 5 | tags: [one, two, three] 6 | --- 7 | # Filtered keys 8 | 9 | This example shows the behaviour of the [[configuration#Filter | filter settings]]. When the “filter mode” is **ignore**, only the keys `guacamole` and `tags` should be displayed and when the value is **keep**, only `metatable` and `frontmatter` should be kept. 10 | 11 | This example assumes that the “filter keys” setting has the default values. 12 | 13 | If you modify the example with the following frontmatter you'll see that filtering is honoured regardless of how deep into the structure keys are found. 14 | 15 | ```yaml 16 | guacamole: green 17 | metatable: false 18 | frontmatter: 42 19 | deep: 20 | frontmatter: wave 21 | deeper: 22 | foo: 1 23 | bar: 24 | metatable: false 25 | value: qux 26 | tags: [one, two, three] 27 | ``` -------------------------------------------------------------------------------- /docs/examples/links.md: -------------------------------------------------------------------------------- 1 | --- 2 | url: https://www.obsidian.md 3 | local: 4 | - ../examples/null_values 5 | - ./filtered_keys 6 | - ./tests/title with spaces 7 | - ./tests/title%20with%20spaces 8 | wiki: 9 | - "[[autolinks]]" 10 | - "[[title with spaces]]" 11 | - "[[autolinks | Auto Links]]" 12 | frontmatter: 13 | - %autolinks% 14 | - %title with spaces% 15 | - %autolinks|Autolinks% 16 | md: 17 | - "[Basic configuration](../sections/configuration)" 18 | - "[Missing page](../missing)" 19 | - "[A remote page](https://www.obsidian.md)" 20 | - "[test spaces](../tests/title with spaces)" 21 | - "[changelog](changelog.md)" 22 | --- 23 | # Links 24 | 25 | **This example requires the [[configuration#Autolinks | Autolinks]] setting enabled.** 26 | -------------------------------------------------------------------------------- /docs/examples/null_values.md: -------------------------------------------------------------------------------- 1 | --- 2 | explicit: null 3 | commented: # this is a comment 4 | missing-value: 5 | empty-string: "" 6 | empty-list: [] 7 | empty-set: {} 8 | --- 9 | # Null values 10 | 11 | This example shows every possible type of null value: 12 | 13 | - An explicit `null` . 14 | - A commented value. 15 | - An empty string, including a missing value. 16 | - An empty list. 17 | - An empty set. -------------------------------------------------------------------------------- /docs/examples/parts.md: -------------------------------------------------------------------------------- 1 | --- 2 | string: Lorem ipsum 3 | number: 10 4 | boolean: true 5 | nil: null 6 | date: 2022-08-27 7 | internal-link: %customising_parts% 8 | external-link: https://www.seachess.net 9 | list: [alpha, beta, gamma] 10 | set: {x: 1, y: 2} 11 | tags: [test, important, example] 12 | --- 13 | # Parts 14 | 15 | This example demontrates the topic discussed in [[customising_parts]]. 16 | 17 | To see this example at work, open the Preferences, go to Appearance and select the `parts` CSS snippet. 18 | 19 | You might also be interested in the [[examples/anatomy]] and [[custom_properties]]. -------------------------------------------------------------------------------- /docs/examples/skip_key.md: -------------------------------------------------------------------------------- 1 | --- 2 | metatable: true 3 | foo: never displayed 4 | bar: also not displayed 5 | --- 6 | # Skip key 7 | 8 | This example will not display the inline metatable when the “skip key” seeting is set to `metatable` and the frontmatter has a `metatable: true` in it. -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | codebase: "[GitHub](https://github.com/arnau/obsidian-metatable)" 3 | tags: [index] 4 | --- 5 | # Obsidian Metatable 6 | 7 | **Obsidian Metatable** is an [Obsidian](https://www.obsidian.md) plugin to display the full frontmatter block instead of just the list of tags and aliases. 8 | 9 | ![[basic.png]] 10 | 11 | ## Table of contents 12 | 13 | 1. [[installation]] 14 | 2. [[getting_started]] 15 | 3. [[configuration]] 16 | 4. [[customising_colours_and_symbols]] 17 | 5. [[customising_parts]] 18 | 6. [[tags]] 19 | 7. [[autolinks]] 20 | 8. [[sections/anatomy]] 21 | 10. [[changelog]] 22 | 11. [[decision_log]] 23 | 24 | 25 | ## Licence 26 | 27 | Arnau Siches under the MIT License. 28 | -------------------------------------------------------------------------------- /docs/screenshots/anatomy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arnau/obsidian-metatable/df6b59af4b57e2219ef6c5e8e5bd956356da116e/docs/screenshots/anatomy.png -------------------------------------------------------------------------------- /docs/screenshots/basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arnau/obsidian-metatable/df6b59af4b57e2219ef6c5e8e5bd956356da116e/docs/screenshots/basic.png -------------------------------------------------------------------------------- /docs/screenshots/null_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arnau/obsidian-metatable/df6b59af4b57e2219ef6c5e8e5bd956356da116e/docs/screenshots/null_settings.png -------------------------------------------------------------------------------- /docs/sections/anatomy.md: -------------------------------------------------------------------------------- 1 | --- 2 | previous: %autolinks% 3 | tags: [section, advanced] 4 | --- 5 | # Anatomy 6 | 7 | The anatomy of a metatable reflects the hierarchical recursive structure found in YAML. 8 | 9 | Example: [[examples/anatomy]] 10 | 11 | ![[anatomy.png]] 12 | 13 | ## Root 14 | 15 | The root part (gold) as its name suggests is a wrapper around the whole metatable section, including its label. 16 | 17 | Note that the metatable is expected to start as a [[#Set]] but technically speaking it can be anything YAML allows for. 18 | 19 | 20 | ## Set 21 | 22 | The set part (light pink) wraps a set of [[#Member]] parts. 23 | 24 | 25 | ## Member 26 | 27 | The member part (brown) wraps a pair of [[#Key]], [[#Value]] parts. 28 | 29 | 30 | ## Key 31 | 32 | The key part (sky blue) contains the label of a set member. 33 | 34 | When the [[#Value]] contains either a [[#Set]] or a [[#List]], the key also includes a `toggle` part as well as either `expanded` or `collapsed`. 35 | 36 | 37 | ## Value 38 | 39 | The value part (light blue) contains the value of a set member. It can contain either a scalar value (string, number, null, date, boolean) or a collection ([[#Set]], [[#List]]). 40 | 41 | Whe the value is a collection it also contains a _marker_ which is expected to be displayed when the key toggle is collapsed. 42 | 43 | 44 | ## List 45 | 46 | The list part (light pink) wraps a set of [[#List item]] parts. 47 | 48 | 49 | ## List item 50 | 51 | The list item part (deep pink) behaves like the [[#Value]] part. 52 | 53 | 54 | ## Tag 55 | 56 | A tag part contains the text for the given tag. See [[sections/tags]] for a more in depth explanation of the particularities of tags. -------------------------------------------------------------------------------- /docs/sections/autolinks.md: -------------------------------------------------------------------------------- 1 | --- 2 | previous: %customising_parts% 3 | next: %anatomy% 4 | tags: [section] 5 | --- 6 | # Autolinks 7 | 8 | The term “autolinks” refers to the [[configuration#Autolinks | Autolinks setting]] which, when enabled, transforms certain patterns into links. 9 | 10 | Check the [[links]] example to see them at work. 11 | 12 | 13 | ## URL 14 | 15 | Any value that is a valid HTTP or HTTPS [URLs](https://developer.mozilla.org/en-US/docs/Web/API/URL) such as `https://www.seachess.net`. 16 | 17 | It also recognises: 18 | 19 | - [Evernote](https://evernote.com/) links using the `evernote:` protocol. 20 | - [Obsidian](https://www.obsidian.md/) links using the `obsidian:` protocol. 21 | - [Zotero](https://www.zotero.org/) links using the `zotero:` protocol. Links are expected to follow a pattern such as `zotero://select/items/@citekey` or `zotero://open-pdf/...`. When used with the [obsidian-citation-plugin](https://github.com/hans/obsidian-citation-plugin), the variable `{{zoteroSelectURI}}` can be used to open the linked citation directly. 22 | 23 | 24 | ## Local 25 | 26 | Any value starting with `./` or `../` is considered a local link. For example, `./projects/obsidian-metatable` will link to the `obsidian-metatable.md` under the `projects` folder. 27 | 28 | 29 | ## Markdown 30 | 31 | Any value of the form `[label](url)` where the URL is a [valid URL](#url) or a [valid local URL](#local). 32 | 33 | 34 | ## Wiki 35 | 36 | Any value starting with `[[` and ending with `]]` is considered a wiki link. The behaviour should be the same with any other wikilink you would write in Markdown. 37 | 38 | **Warning**: Square brackets `[]` in YAML are reserved for defining arrays so in order to actually use wikilinks you have to tell YAML that it's a string. 39 | 40 | For example, 41 | 42 | ```yaml 43 | quoted: "[[basic-alt]]" 44 | long-string: >- 45 | [[target]] 46 | ``` 47 | 48 | You can also customise the text displayed by using the following form: 49 | 50 | ``` 51 | [[target|Text to display]] 52 | ``` 53 | 54 | 55 | ## Frontmatter 56 | 57 | Any value starting and ending with `%` is considered a frontmatter link. The behaviour is the same as per wiki links. 58 | 59 | **Warning**: This format is non-standard. But it's more convenient than wiki links. -------------------------------------------------------------------------------- /docs/sections/configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | previous: %getting_started% 3 | next: %customising_colours_and_symbols% 4 | tags: [section] 5 | --- 6 | # Configuration 7 | 8 | **Note**: Most changes in configuration will require you to reopen the documents you have opened to be able to see their effect. 9 | 10 | You should find the Metatable settings section by opening the Obsidian Preferences and scrolling down the left sidebar until you see the Community Plugins section. 11 | 12 | 13 | ## Expansion level 14 | 15 | This option lets you choose whether the metatable is fully collapsed, fully expanded or something in between. 16 | 17 | This option is most useful if you use the in-document metatable and you have large sets of metadata. 18 | 19 | Possible values: 20 | 21 | - Fully expanded: Everything is visible. 22 | - Collapse leafs: The complex leafs (lists and sets) are collapsed. 23 | - Collapse all: TODO 24 | - Collapse root: The Metatable root is collapsed. 25 | 26 | 27 | ## Skip key 28 | 29 | This option lets you define a key that, when defined in the frontmatter as `true` it makes the [[inline_metatable]] to not be displayed at all. 30 | 31 | By default the skip key is `metatable` so the following frontmatter would not be displayed at all. 32 | 33 | ```yaml 34 | metatable: true 35 | foo: never displayed 36 | bar: also not displayed 37 | ``` 38 | 39 | **Warning**: This option has no effect on the [[sidebar_metatable]]. 40 | 41 | 42 | ## Null values 43 | 44 | For the purpose of the metatable, a "null value" is one of the following: 45 | 46 | - An explicit `null` value. 47 | - A commented value. 48 | - An empty string, including a missing value. 49 | - An empty list. 50 | - An empty set. 51 | 52 | Example: [[null_values]] 53 | 54 | Null values can be configured in two ways: ignoring them or displaying the with a custom value. 55 | 56 | ### Ignore null values 57 | 58 | This switch is disabled by default. When enabled it never displays any member of the metatable with a null value. 59 | 60 | ### Custom null value 61 | 62 | This text is empty by default. When filled in, every null value is replaced with it. 63 | 64 | 65 | ## Filter 66 | 67 | The filter settings let you control which keys should never be displayed or the keys that should only be displayed according to the filter mode. 68 | 69 | Example: [[filtered_keys]] 70 | 71 | ### Filter mode 72 | 73 | This option lets you choose whether the filtering is either **ignore** or **keep**. By default the mode is **ignore**. 74 | 75 | - **Ignore**: Any key in the “filter keys” list is ignored. 76 | - **Keep**: Any key not in the “filter keys” list is ignored. 77 | 78 | ### Filter keys 79 | 80 | This option lets you define the list of keys that should be kept or ignored by the “filter mode”. 81 | 82 | By default the values are `metatable` and `frontmatter`. 83 | 84 | 85 | ## Autolinks 86 | 87 | This option transforms certain value patterns into actual links. This option is disabled by default. 88 | 89 | Example: [[links]] 90 | 91 | Available patterns: 92 | 93 | - **URL**. Any URL-like value. 94 | - **Local**. Any value starting with `./` or `../`. 95 | - **Markdown**. Any value like a markdown link. 96 | - **Wiki**. Any value surrounded by `[[` and `]]`. 97 | - **Frontmatter**. Any value surrounded by `%`. 98 | 99 | You can find a full explanation for each pattern in [[autolinks]]. 100 | 101 | ## Naked mode 102 | 103 | This option lets you choose whether to sandbox the metatable widget using [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM). The default is to have the sandbox enabled. 104 | 105 | If you enable the naked mode no default CSS will be applied and will be your responsibility or the theme you use to style the metatable correctly. -------------------------------------------------------------------------------- /docs/sections/customising_colours_and_symbols.md: -------------------------------------------------------------------------------- 1 | --- 2 | previous: %configuration% 3 | next: %customising_parts% 4 | tags: [section] 5 | --- 6 | # Customising colours and symbols 7 | 8 | You can customise both colours and symbols using [CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties). 9 | 10 | There are two possible scopes to customise, the [[inline_metatable]] and the [[sidebar_metatable]]. 11 | 12 | The [[inline_metatable]] uses the `.obsidian-metatable` CSS class whilst the [[sidebar_metatable]] uses the `.obsidian-metatable-sidebar`. 13 | 14 | Example: [[custom_properties]]. 15 | 16 | ## Global palette 17 | 18 | The global palette is a small set of custom properties which the rest depend on. 19 | 20 | ### Fonts 21 | 22 | ```css 23 | --metatable-font-family 24 | --metatable-font-size 25 | ``` 26 | 27 | 28 | ### `:focus` pseudo-class 29 | 30 | ```css 31 | --metatable-background-focus 32 | --metatable-text-focus 33 | ``` 34 | 35 | 36 | ### Colours 37 | 38 | ```css 39 | /* global */ 40 | --metatable-background-primary 41 | --metatable-text-primary 42 | 43 | --metatable-text-secondary 44 | --metatable-background-secondary 45 | 46 | --metatable-background-primary-alt 47 | 48 | /* links */ 49 | --metatable-background-link 50 | --metatable-text-link 51 | --metatable-text-link-hover 52 | ``` 53 | 54 | ### Deprecated in 0.14.0 55 | 56 | The following custom properties are deprecated and will be removed in future versions. 57 | 58 | - `--metatable-foreground`: Use `--metatable-text-primary` instead. 59 | - `--metatable-background`: Use `--metatable-background-primary` instead. 60 | - `--metatable-key-focus`: Use `--metatable-key-background-focus` instead. 61 | - `--metatable-member-gap`. Use `::part(member)` instead. 62 | - `--metatable-key-border-color`. Use `::part(key)` instead. 63 | - `--metatable-key-border-color-focus`. Use `::part(key)` instead. 64 | 65 | 66 | ## Global symbols 67 | 68 | - `--metatable-collapsed-symbol` 69 | - `--metatable-expanded-symbol` 70 | - `--metatable-mark-symbol` 71 | - `--metatable-tag-symbol` 72 | 73 | 74 | ## Warning 75 | 76 | When the frontmatter YAML can't be parsed, a warning is shown. 77 | 78 | ```css 79 | --metatable-warning-background 80 | --metatable-warning-foreground 81 | --metatable-warning-border 82 | ``` 83 | 84 | 85 | ## Parts 86 | 87 | All part properties follow a pattern like: 88 | 89 | ``` 90 | --metatable-{where?}-{what} 91 | ``` 92 | 93 | For example, `--metatable-external-link-color-hover` has: 94 | 95 | - A `where` equal to `external-link`. 96 | - A `what` equal to `link-color-hover`, which implies it applies to the [CSS :hover pseudo-class](https://developer.mozilla.org/en-US/docs/Web/CSS/:hover). 97 | 98 | Read the [[sections/anatomy]] section to understand how parts compose. 99 | 100 | 101 | ### Root part 102 | ```css 103 | --metatable-root-background 104 | --metatable-root-color 105 | ``` 106 | 107 | ### Summary part 108 | 109 | **v0.14.6**: The following custom properties are no longer available: 110 | 111 | ```css 112 | --metatable-summary-background 113 | --metatable-summary-color 114 | --metatable-summary-background-focus 115 | --metatable-summary-color-focus 116 | ``` 117 | 118 | ### Set part 119 | ```css 120 | --metatable-set-background 121 | --metatable-set-color 122 | ``` 123 | 124 | ### Member part 125 | ```css 126 | --metatable-member-background 127 | --metatable-member-color 128 | ``` 129 | 130 | ### Key part 131 | ```css 132 | --metatable-key-background 133 | --metatable-key-color 134 | --metatable-key-background-focus 135 | --metatable-key-color-focus 136 | ``` 137 | 138 | ### Value part 139 | ```css 140 | --metatable-value-background 141 | --metatable-value-color 142 | ``` 143 | 144 | 145 | ### Tag part 146 | 147 | ```css 148 | --metatable-tag-background 149 | --metatable-tag-color 150 | --metatable-tag-border 151 | --metatable-tag-background-focus 152 | --metatable-tag-color-focus 153 | ``` 154 | 155 | ### External link part 156 | 157 | ```css 158 | --metatable-external-link-background 159 | --metatable-external-link-color 160 | --metatable-external-link-background-hover 161 | --metatable-external-link-color-hover 162 | --metatable-external-link-background-focus 163 | --metatable-external-link-color-focus 164 | --metatable-external-link-icon 165 | ``` 166 | 167 | ### Internal link part 168 | 169 | ```css 170 | --metatable-internal-link-background 171 | --metatable-internal-link-color 172 | --metatable-internal-link-background-hover 173 | --metatable-internal-link-color-hover 174 | --metatable-internal-link-background-focus 175 | --metatable-internal-link-color-focus 176 | ``` 177 | 178 | ### Leaf types 179 | 180 | ```css 181 | --metatable-leaf-number-color 182 | --metatable-leaf-boolean-color 183 | --metatable-leaf-date-color 184 | --metatable-leaf-nil-color 185 | ``` 186 | -------------------------------------------------------------------------------- /docs/sections/customising_parts.md: -------------------------------------------------------------------------------- 1 | --- 2 | previous: %customising_colours_and_symbols% 3 | next: %tags% 4 | tags: [section] 5 | --- 6 | # Customising parts 7 | 8 | Whilst [[customising_colours_and_symbols]] go a long way, it does have limits either shortcomings of the implementation or by design. I these scenarios, parts will allow you to go further. 9 | 10 | It's worth acquainting yourself with the [[sections/anatomy]] of the metatable to see how parts compose. 11 | 12 | When we say “part” we really refer to the [::part pseudo-element](https://developer.mozilla.org/en-US/docs/Web/CSS/::part). So, when we say that there is a “list part” we mean that there is an HTML element with an attribute `part="list"` which can be targeted from CSS using `::part(list)`. 13 | 14 | Note that parts are limited by design so you won't be able to influence children such as links or deep structures in values. If that's what you need, you will have to enable the [[configuration#Naked mode | naked mode]] and style everything yourself. 15 | 16 | Example: [[parts]] 17 | 18 | 19 | ## Parts 20 | 21 | The available parts are: 22 | 23 | - [[#Root and summary]] 24 | - [[#Set member key and value]] 25 | - [[#List and list item]] 26 | - [[#Scalars]] 27 | - [[#Tags]] 28 | - [[#Links]] 29 | 30 | 31 | ## Root and summary 32 | 33 | The root contains the summary and the actual metatable. 34 | 35 | Note that the metatable is expected to start as a [[sections/anatomy#Set]] but technically speaking it can be anything YAML allows for. 36 | 37 | The summary is the header for the metatable, it is a `summary` element for the [[inline_metatable]] and an `h1` element for the [[sidebar_metatable]]. 38 | 39 | 40 | ## Set, member, key and value 41 | 42 | A set is composed of members and members are composed of a key and a value. Effectively the same structure as an HTML table where you have a `table` (set), `tr` (member), `th` (key) and `td` (value). 43 | 44 | The structure uses multiple [CSS Grid Layout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout) to arrange each part in place. 45 | 46 | For example, if you want to give more room to keys and you could remove the grid layout: 47 | 48 | ```css 49 | .obsidian-metatable::part(member) { 50 | display: block; 51 | } 52 | 53 | .obsidian-metatable::part(value) { 54 | margin-left: 20px; 55 | } 56 | ``` 57 | 58 | Or, in a extreme case you could start by resetting everything for a part: 59 | 60 | ```css 61 | .obsidian-metatable::part(value) { 62 | all: unset; 63 | } 64 | ``` 65 | 66 | Finally, when values contain a collection (either set or list) there is a `marker` part that allows styling the, by default, `...` when the collection is collapsed. 67 | 68 | 69 | ## List and list item 70 | 71 | A list is composed of list items. Effectively an HTML `ul` element with a collection of `li` elements. 72 | 73 | The same logic described for [[#Set member key and value]] apply here. 74 | 75 | Note that although [[#Tags]] are a list, they have different rules and structure. To customise it further you can use the [[#Named Parts]]. 76 | 77 | ## Scalars 78 | 79 | Scalar parts are: 80 | 81 | - `string`: Any string not conforming to other more restrictive patterns. 82 | - `number`: Any number as per YAML. 83 | - `null`: Any value as per [[null_values]]. 84 | - `link` (and `internal-link`, `external-link`): Any value as per [[autolinks]]. 85 | - `isodate`: Any string conforming to an ISO date (e.g. 2022-09-03). 86 | 87 | 88 | ### Tags 89 | 90 | A tag has a `tag` part. 91 | 92 | For example, to reproduce the [Tag Pills](https://forum.obsidian.md/t/meta-post-common-css-hacks/1978/13) with this plugin you would do instead: 93 | 94 | ```css 95 | .obsidian-metatable::part(tag) { 96 | background-color: pink; 97 | } 98 | 99 | .obsidian-metatable::part(tag):hover { 100 | background-color: var(--text-accent-hover); 101 | } 102 | 103 | .obsidian-metatable::part(tag important) { 104 | color: white; 105 | background-color: tomato; 106 | } 107 | 108 | .obsidian-metatable::part(tag example) { 109 | color: black; 110 | background-color: deepskyblue; 111 | } 112 | ``` 113 | 114 | ### Links 115 | A link has a `link` part and either a `internal-link` or a `external-link` part. 116 | 117 | ```css 118 | .obsidian-metatable::part(link) { 119 | /* generic link tweaks */ 120 | } 121 | 122 | .obsidian-metatable::part(external-link) { 123 | /* external link tweaks */ 124 | } 125 | 126 | .obsidian-metatable::part(external-link):hover { 127 | /* external link hover tweaks */ 128 | } 129 | ``` 130 | 131 | 132 | ## Named Parts 133 | 134 | Both [[#Set member key and value|Sets]] and [[#List and list item|Lists]] have an extra part following the pattern `{collection_type}-{key}`. 135 | 136 | For example, the list for the key `tags` has a `list-tags` part and in turn each list item a `list-item-tags` part. 137 | 138 | -------------------------------------------------------------------------------- /docs/sections/decision_log.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: [section] 3 | --- 4 | # Decision log 5 | 6 | The decision log contains the big decisions made to architect and develop this plugin. 7 | 8 | - [[2021-04-19_web_component]] 9 | - [[2021-04-20_details_usage]] 10 | - [[2021-04-28_css_grid]] 11 | - [[2021-05-10_customise_tags]] 12 | - [[2022-08-29_sidebar_view]] 13 | - [[2022-08-29_solidjs]] 14 | -------------------------------------------------------------------------------- /docs/sections/getting_started.md: -------------------------------------------------------------------------------- 1 | --- 2 | previous: %installation% 3 | next: %configuration% 4 | tags: [section] 5 | --- 6 | # Getting started 7 | 8 | This plugin offers two ways of displaying the metadata for a given markdown document: the [[inline_metatable]] or the [[sidebar_metatable]]. 9 | 10 | Note that this version does not display the metatable in _editing mode_. It's a known limitation but contributions are welcome! 11 | 12 | After [[installation|installing the plugin]], the plugin will be ready to use straight away however it is best to have a quick tour to the [[configuration]] to tweak how the plugin displays the information. 13 | 14 | For example, if you tend to have large frontmatter structures you might want to consider [[configuration#Expansion level|tweaking the expansion level]]. I personally use a combination of having the [[sidebar_metatable]] open and collapsing just the root such that when I use the _reading mode_ I don't see the metatable again. 15 | 16 | This plugin has only been tested with the default theme so if you are like me and use a different one you might want to [[customising_colours_and_symbols|tweak a few colours]] or even going further and [[customising_parts|adjusting spacing, symbols, etc]]. 17 | 18 | Thanks for using the plugin and let me know if there is any unexpected behaviour! -------------------------------------------------------------------------------- /docs/sections/inline_metatable.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: [anatomy] 3 | --- 4 | # Inline metatable 5 | 6 | The inline metatable is a widget that gets displayed whilst viewing a markdown document in _reading mode_. 7 | 8 | Notice that when the mode is _editing_, the frontmatter is displayed as raw YAML. 9 | 10 | You might find convenient to open the [[sidebar_metatable]] whilst editing the frontmatter section. -------------------------------------------------------------------------------- /docs/sections/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | next: %getting_started% 3 | tags: [section] 4 | --- 5 | # Installation 6 | 7 | You can install this plugin in three ways, each one with its own strengths. 8 | 9 | ## From Obsidian 10 | 11 | Use this option if you want minimum friction both installing and updating. This is the recommended way for most people. 12 | 13 | - Ensure Community Plugins are enabled. 14 | - Browse community plugins searching for **metatable**. 15 | - Click install. 16 | - Enable plugin in the “Community Plugins” Settings section. 17 | - Open a file (notice that previously opened files won't get the effects of the plugin until reopened or changed). 18 | 19 | ## From release 20 | 21 | Use this option if you want to try a particular version outside of what the Community Plugins offer or if you rather sidestep Obsidian's installation system. 22 | 23 | - Download the `obsidian-metatable-{version}.zip` file from the chosen release, for example the [latest release]. 24 | - Ensure “Community Plugins” are enabled in Settings. 25 | - Ensure the `.obsidian/plugins/` directory exists in your vault directory. 26 | - Expand the zip file into the `.obsidian/plugins/` directory such that an `obsidian-metatable` directory is a direct child of `plugins`. 27 | - Enable plugin in the “Community Plugins” Settings section. 28 | - Open a file (notice that previously opened files won't get the effects of the plugin until reopened or changed). 29 | 30 | ## From source 31 | 32 | Use this option if you intent to contribute to the plugin development, you want to fork it out or don't find the previous two options suitable. 33 | 34 | - Clone the [source repository]. 35 | - Run `npm install`. 36 | - Run `npm run build`. 37 | - Create an `obsidian-metatable` directory under your vault's `.obsidian/plugins/` directory. 38 | - Copy over `main.js`, `versions.json` and `manifest.json`. 39 | - Enable plugin in the “Community Plugins” Settings section. 40 | - Open a file (notice that previously opened files won't get the effects of the plugin until reopened or changed). 41 | -------------------------------------------------------------------------------- /docs/sections/sidebar_metatable.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: [anatomy] 3 | --- 4 | # Sidebar metatable 5 | 6 | The sidebar metatable is a widget that you can open using the _open sidebar metatable_ or using the ribbon icon in the left pane. 7 | 8 | This widget displays the metadata for the current markdown file. -------------------------------------------------------------------------------- /docs/sections/tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | previous: %customising_parts% 3 | next: %autolinks% 4 | tags: [section] 5 | --- 6 | # Tags 7 | 8 | [Obsidian treats tags in a particular way](https://help.obsidian.md/How+to/Working+with+tags). From a YAML point of view it is treated in a non standard way, so this section covers this angle. 9 | 10 | The `tags` key (or any casing like `Tags`) expects a sequence of strings. In standard YAML there are two options. 11 | 12 | ## Compact notation 13 | 14 | ```yaml 15 | tags: [one, two, three] 16 | ``` 17 | 18 | ## Indented notation 19 | 20 | ```yaml 21 | tags: 22 | - one 23 | - two 24 | - three 25 | ``` 26 | 27 | ## Non standard notations 28 | 29 | However, the following forms are treated as valid forms by Obsidian (and by Obsidian Metatable to keep compatibility). 30 | 31 | **It is highly recommended that you stick with the standard notation to keep compatibility with other tools**. 32 | 33 | 34 | ### String (single) 35 | 36 | ```yaml 37 | tags: one 38 | ``` 39 | 40 | ### String (collection) 41 | 42 | ```yaml 43 | tags: one, two, three 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /docs/tests/broken-tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: {a: 1} 3 | --- 4 | # Test: Broken tags 5 | 6 | A test to verify tags that are not an expected value don't fail as long as the value is valid YAML. -------------------------------------------------------------------------------- /docs/tests/broken.md: -------------------------------------------------------------------------------- 1 | --- 2 | foo: 3 | bar: bad: yaml 4 | --- 5 | # Test: Broken 6 | 7 | A test to verify broken YAML displays a warning. -------------------------------------------------------------------------------- /docs/tests/chinese-tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: 剧情 喜剧 3 | --- 4 | # Test: chinese tags are handled properly -------------------------------------------------------------------------------- /docs/tests/emoji-tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: [🥑, 🥕] 3 | --- 4 | # Tags with emojis -------------------------------------------------------------------------------- /docs/tests/extreme.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Extreme example 3 | empty-list: [] 4 | empty-set: {} 5 | summary: An extreme example to show nested tables 6 | start_date: 2021-04-11 7 | end_date: none 8 | tags: 9 | - test 10 | - extreme 11 | options: 12 | - first 13 | - second with text 14 | - third with even more text 15 | social: 16 | - name: Twitter 17 | handle: "@metatable" 18 | - name: Instagram 19 | handle: "@metatable7612" 20 | a-table-inside: 21 | alpha: yada 22 | beta: badabum 23 | gamma: green 24 | list-in-list: 25 | - one 26 | - 27 | - x 28 | - y 29 | a-null: 30 | numeric: 2 31 | aliases: [extreme-test] 32 | deep-null: 33 | a-keeper: "foo" 34 | a-null: 35 | deep-ignore: 36 | frontmatter: foo 37 | --- 38 | # Test: An extreme test 39 | 40 | -------------------------------------------------------------------------------- /docs/tests/long-keys.md: -------------------------------------------------------------------------------- 1 | --- 2 | a-very-long-key-with-no-way-to-escape: tiny value? 3 | normal-key: lorem ipsum 4 | --- 5 | # Test: Long keys 6 | 7 | A test to verify how long keys behave. 8 | -------------------------------------------------------------------------------- /docs/tests/none.md: -------------------------------------------------------------------------------- 1 | # Test: none 2 | 3 | A test to verify how the absence of a frontmatter works. -------------------------------------------------------------------------------- /docs/tests/normalise-tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: foo bar, far 3 | --- 4 | # Test: Normalise tags -------------------------------------------------------------------------------- /docs/tests/pdf_export.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: [a, b] 3 | --- 4 | # Test: PDF export 5 | 6 | As reported in [bug #30](https://github.com/arnau/obsidian-metatable/issues/30) when exporting a note with an image embedded to PDF the metatable does not show up. 7 | 8 | ![n](screenshots/null_settings.png) 9 | -------------------------------------------------------------------------------- /docs/tests/tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | TAGS: one, two 3 | tagS: one 4 | Tags: [test] 5 | tags: [test, no-example] 6 | --- 7 | # Test: Tag list 8 | 9 | A test to verify tags are treated correctly regardless of casing or acceptable value. -------------------------------------------------------------------------------- /docs/tests/title with spaces.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: [test] 3 | --- 4 | # Test: title with spaces 5 | 6 | To test the [[autolinks]]. -------------------------------------------------------------------------------- /esbuild.config.mjs: -------------------------------------------------------------------------------- 1 | import esbuild from "esbuild"; 2 | import process from "process"; 3 | import builtins from "builtin-modules" 4 | import { solidPlugin } from "esbuild-plugin-solid" 5 | 6 | const banner = 7 | `/* 8 | THIS IS A GENERATED/BUNDLED FILE BY ESBUILD 9 | if you want to view the source, please visit the github repository of this plugin 10 | */ 11 | `; 12 | 13 | const prod = (process.argv[2] === 'production'); 14 | 15 | esbuild.build({ 16 | banner: { 17 | js: banner, 18 | }, 19 | entryPoints: ["src/main.ts"], 20 | bundle: true, 21 | external: [ 22 | "obsidian", 23 | "electron", 24 | "@codemirror/autocomplete", 25 | "@codemirror/collab", 26 | "@codemirror/commands", 27 | "@codemirror/language", 28 | "@codemirror/lint", 29 | "@codemirror/search", 30 | "@codemirror/state", 31 | "@codemirror/view", 32 | "@lezer/common", 33 | "@lezer/highlight", 34 | "@lezer/lr", 35 | ...builtins, 36 | ], 37 | format: "cjs", 38 | target: "es2018", 39 | logLevel: "info", 40 | sourcemap: prod ? false : "inline", 41 | treeShaking: true, 42 | outdir: "dist", 43 | plugins: [solidPlugin()], 44 | loader: { 45 | ".css": "text", 46 | }, 47 | }).catch(() => process.exit(1)); 48 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | verbose: true, 3 | preset: 'ts-jest', 4 | transform: { 5 | '^.+\\.ts$': 'ts-jest', 6 | }, 7 | moduleFileExtensions: ['js', 'ts'], 8 | testEnvironment: 'jsdom', 9 | }; 10 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "obsidian-metatable", 3 | "name": "Metatable", 4 | "version": "0.14.7", 5 | "minAppVersion": "0.15.9", 6 | "description": "Displays the full frontmatter as a table.", 7 | "author": "Arnau Siches", 8 | "authorUrl": "https://www.seachess.net/", 9 | "isDesktopOnly": false 10 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obsidian-metatable", 3 | "version": "0.14.7", 4 | "description": "An Obsidian plugin to render the full frontmatter as a table.", 5 | "keywords": [ 6 | "obsidian" 7 | ], 8 | "author": "Arnau Siches", 9 | "license": "MIT", 10 | "scripts": { 11 | "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", 12 | "dist": "rm -rf dist && mkdir dist && npm run build && cp styles.css versions.json manifest.json dist/", 13 | "docs": "npm run dist && cp dist/* docs/.obsidian/plugins/obsidian-metatable && cp CHANGELOG.md docs/changelog.md", 14 | "release": "node support/version-bump.mjs", 15 | "test": "jest --passWithNoTests" 16 | }, 17 | "devDependencies": { 18 | "@types/jest": "^29.0.1", 19 | "@types/node": "^20.4.0", 20 | "@typescript-eslint/eslint-plugin": "^5.33.1", 21 | "@typescript-eslint/parser": "^5.33.1", 22 | "builtin-modules": "^3.3.0", 23 | "esbuild": "^0.18.11", 24 | "esbuild-plugin-solid": "^0.5.0", 25 | "jest": "^29.0.3", 26 | "jest-environment-jsdom": "^29.0.3", 27 | "obsidian": "^1.1.1", 28 | "ts-jest": "^29.0.0", 29 | "tslib": "^2.0.3", 30 | "typescript": "^5.1.6" 31 | }, 32 | "dependencies": { 33 | "solid-js": "^1.4.7" 34 | } 35 | } -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arnau/obsidian-metatable/df6b59af4b57e2219ef6c5e8e5bd956356da116e/screenshot.png -------------------------------------------------------------------------------- /src/components/ExternalLink.tsx: -------------------------------------------------------------------------------- 1 | 2 | export function ExternalLink(props: any) { 3 | return ( 4 | 5 | ) 6 | } 7 | 8 | export function isExternalLink(value: string): boolean { 9 | const url = tryUrl(value) 10 | 11 | return isUrl(url) 12 | } 13 | 14 | function isUrl(url: URL | string): boolean { 15 | const allowedProtocols = ['http:', 'https:', 'evernote:', 'zotero:'] 16 | 17 | return (url instanceof URL && allowedProtocols.some(protocol => url.protocol == protocol)) 18 | } 19 | 20 | 21 | export function tryUrl(value: string): URL | string { 22 | try { 23 | return new URL(value) 24 | } catch (_) { 25 | return value 26 | } 27 | } 28 | 29 | /** 30 | * Represents an external link. 31 | */ 32 | export function Link(props: LinkProps) { 33 | const label = props.label 34 | const url = props.url 35 | 36 | return ( 37 | {label} 44 | ) 45 | } 46 | 47 | interface LinkProps { 48 | label: string; 49 | url: string; 50 | } 51 | -------------------------------------------------------------------------------- /src/components/Inline.tsx: -------------------------------------------------------------------------------- 1 | import { Match, Show, Switch } from "solid-js" 2 | import { ValueError, Value } from "src/value" 3 | import { parseFrontmatter } from "src/frontmatter" 4 | import { useMixture } from "src/mixture" 5 | import { ParseError } from "./ParseError" 6 | import { Metatable } from "./Metatable" 7 | 8 | // @ts-ignore 9 | import styles from "../metatable.css" 10 | 11 | interface InlineProps { 12 | data: string | null | undefined, 13 | } 14 | 15 | export function Inline(props: InlineProps) { 16 | let { settings, isOpen, cleanData } = useMixture() 17 | let metadata: Value | ValueError | undefined 18 | 19 | try { 20 | metadata = cleanData(parseFrontmatter(props.data)) 21 | } catch (err) { 22 | metadata = err as ValueError 23 | } 24 | 25 | return ( 26 | <> 27 | 28 | 29 | 30 | 31 | 32 | (metadata as ValueError)!.message!} /> 33 | 34 | 35 |
36 | Metatable 37 | 38 |
39 |
40 |
41 | 42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /src/components/InternalLink.tsx: -------------------------------------------------------------------------------- 1 | import { MarkdownView, getLinkpath } from "obsidian" 2 | import { Match, Switch, createEffect, createSignal } from "solid-js" 3 | import { useMixture } from "../mixture" 4 | 5 | /** 6 | * Represents any form of internal link. 7 | */ 8 | export function InternalLink(props: any) { 9 | const value = props.value 10 | 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ) 30 | } 31 | 32 | export function isInternalLink(value: string): boolean { 33 | return isWikiLink(value) 34 | || isFrontmatterLink(value) 35 | || isLocalLink(value) 36 | || isObsidianUrl(value) 37 | } 38 | 39 | 40 | /** 41 | * Represents a wiki link. It has the form `[[localId]]` or `[[localId|label]]`. 42 | */ 43 | function WikiLink(props: any) { 44 | let value = props.value.slice(2, -2) 45 | let url: string 46 | let label: string 47 | 48 | if (value.includes("|")) { 49 | const [urlValue, labelValue] = value.split("|") 50 | url = urlValue.trim() 51 | label = labelValue.trim() 52 | } else { 53 | label = value 54 | url = value 55 | } 56 | 57 | return ( 58 | 59 | ) 60 | } 61 | 62 | function isWikiLink(value: string): boolean { 63 | return (value.startsWith("[[") && value.endsWith("]]")) 64 | } 65 | 66 | 67 | /** 68 | * Represents a frontmatter link. It has the form `%localId%` or `%localId|label%`. 69 | */ 70 | function FrontmatterLink(props: any) { 71 | let value = props.value.slice(1, -1) 72 | let url: string 73 | let label: string 74 | 75 | if (value.includes("|")) { 76 | const [urlValue, labelValue] = value.split("|") 77 | url = urlValue.trim() 78 | label = labelValue.trim() 79 | } else { 80 | label = value 81 | url = value 82 | } 83 | 84 | return ( 85 | 86 | ) 87 | } 88 | 89 | function isFrontmatterLink(value: string): boolean { 90 | return (value.startsWith("%") && value.endsWith("%")) 91 | } 92 | 93 | 94 | /** 95 | * Reprents a local link of the form `./target/path`. 96 | */ 97 | function LocalLink(props: any) { 98 | return ( 99 | 100 | ) 101 | } 102 | 103 | function isLocalLink(value: string): boolean { 104 | return value.startsWith("./") || value.startsWith("../") 105 | } 106 | 107 | 108 | function ObsidianLink(props: any) { 109 | return ( 110 | 111 | ) 112 | } 113 | 114 | function isObsidianUrl(url: URL | string): boolean { 115 | return (url instanceof URL && url.protocol == "obsidian:") 116 | } 117 | 118 | function expandUrl(url: string, parent: string | null | undefined) { 119 | if (!url.startsWith(".") || !url.startsWith("..")) { return url } 120 | 121 | const parentTrail = parent?.split("/").filter(step => step.length > 0) ?? [] 122 | 123 | const [relativeStep, ...trail] = url.split("/") 124 | 125 | if (relativeStep === "..") { 126 | parentTrail.pop() 127 | } 128 | 129 | return `/${parentTrail.concat(trail).join("/")}` 130 | } 131 | 132 | /** 133 | * Represents an internal link. 134 | */ 135 | export function Link(props: LinkProps) { 136 | const { workspace } = useMixture() 137 | const [parent, setParent] = createSignal() 138 | const view = () => workspace.getActiveViewOfType(MarkdownView) 139 | createEffect(() => { 140 | setParent(view()?.file.parent?.path) 141 | }) 142 | 143 | const { openNote } = useMixture() 144 | const label = () => props.label 145 | const url = () => decodeURIComponent(props.url) 146 | const localUrl = () => getLinkpath(url()) 147 | const clickHandler = (event: any) => { 148 | event.preventDefault() 149 | const href = event.target.dataset.href! 150 | openNote(expandUrl(href, parent())) 151 | } 152 | 153 | return ( 154 | {label()} 163 | ) 164 | } 165 | 166 | interface LinkProps { 167 | label: string; 168 | url: string; 169 | } 170 | -------------------------------------------------------------------------------- /src/components/Leaf.tsx: -------------------------------------------------------------------------------- 1 | import { Match, Switch, createEffect } from "solid-js" 2 | import type { LeafValue } from "../value" 3 | import { useMixture } from "../mixture" 4 | import { Tag } from "./Tag" 5 | import { isInternalLink, InternalLink, Link as ILink } from "./InternalLink" 6 | import { isExternalLink, ExternalLink, Link as ELink } from "./ExternalLink" 7 | 8 | 9 | const ISODATE_RE = new RegExp(/^\d{4}-\d{2}-\d{2}$/) 10 | const MD_LINK_RE = new RegExp(/^\[(?