Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b1dc55da7 | ||
|
|
bfbc81c90f | ||
|
|
cefbf74582 | ||
|
|
0780842365 | ||
|
|
1f94a87993 | ||
|
|
157228edb5 | ||
|
|
10268fc60f | ||
|
|
e51911ed83 | ||
|
|
e1429bc666 | ||
|
|
a2d6d361d6 | ||
|
|
c581ead809 | ||
|
|
3ed5fda4e7 | ||
|
|
33dcfcb09a | ||
|
|
df84c25e01 | ||
|
|
b8dc7990f7 | ||
|
|
a1ee808ed5 | ||
|
|
3a35eeb1d5 | ||
|
|
c6412760fc | ||
|
|
cc21043053 | ||
|
|
b1816a0567 | ||
|
|
29b170a8bd | ||
|
|
3ed144f003 | ||
|
|
613d7f2adb | ||
|
|
82260d7030 | ||
|
|
dbd8b1c0ce | ||
|
|
d2a4a281a3 | ||
|
|
37021e7a0a | ||
|
|
02c171d64c | ||
|
|
a99f20b9f1 | ||
|
|
14d66203d3 | ||
|
|
6e1b28c59e | ||
|
|
53a1b19e07 | ||
|
|
87e735faa9 | ||
|
|
b2f0d51aa2 | ||
|
|
9a6403a6cd | ||
|
|
021b3952ec | ||
|
|
8ddeab7a88 | ||
|
|
bea11bf7df | ||
|
|
323807c0e1 | ||
|
|
d55b122d33 | ||
|
|
a118b461a7 | ||
|
|
c572a821e9 | ||
|
|
a3f18bb143 | ||
|
|
525a289a2c | ||
|
|
d8d058360b | ||
|
|
5ccb528e02 | ||
|
|
d9818f4b2d | ||
|
|
4e905d0334 | ||
|
|
033b08b1bb | ||
|
|
430775649c | ||
|
|
0bd714bb02 | ||
|
|
0d0289cbf7 | ||
|
|
6b21c76332 | ||
|
|
59c962d8fc | ||
|
|
13cb8fcff5 | ||
|
|
4d6317f3bc | ||
|
|
1b4ce2b925 | ||
|
|
8f7f61f2af | ||
|
|
f11b884bed | ||
|
|
3a968a305f | ||
|
|
847cce915b | ||
|
|
976a473d39 |
12
.vscode/launch.json
vendored
@@ -18,6 +18,18 @@
|
||||
],
|
||||
"preLaunchTask": "npm: build:ext"
|
||||
},
|
||||
{
|
||||
"name": "Attach Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Extension Tests",
|
||||
"type": "extensionHost",
|
||||
|
||||
38
CHANGELOG.md
@@ -1,5 +1,43 @@
|
||||
# Change Log
|
||||
|
||||
## [2.2.0] - 2020-08-06
|
||||
|
||||
- [#28](https://github.com/estruyf/vscode-front-matter/issues/28): Align the file its name with the article slug
|
||||
- [#47](https://github.com/estruyf/vscode-front-matter/issues/47): Fix when table shows only value `0`
|
||||
- [#48](https://github.com/estruyf/vscode-front-matter/issues/48): Added new folder registration message + notification helper
|
||||
- [#49](https://github.com/estruyf/vscode-front-matter/issues/49): New initialize project command
|
||||
- [#50](https://github.com/estruyf/vscode-front-matter/issues/50): Fix in the table rendering of rows
|
||||
- [#51](https://github.com/estruyf/vscode-front-matter/issues/51): Panel actions base view enhanced to show project actions and information
|
||||
|
||||
## [2.1.0] - 2020-08-04
|
||||
|
||||
- [#44](https://github.com/estruyf/vscode-front-matter/issues/45): Added article creation command
|
||||
- [#45](https://github.com/estruyf/vscode-front-matter/issues/45): WSL support added
|
||||
- [#46](https://github.com/estruyf/vscode-front-matter/issues/46): Make the tag pickers render in full width
|
||||
|
||||
## [2.0.1] - 2020-07-27
|
||||
|
||||
- [#42](https://github.com/estruyf/vscode-front-matter/issues/42): Small enhancement to the table layout
|
||||
- [#43](https://github.com/estruyf/vscode-front-matter/issues/43): Fix for collapsible sections and taxonomy picker
|
||||
|
||||
## [2.0.0] - 2020-07-23
|
||||
|
||||
- Redesigned sidebar panel
|
||||
- Sidebar background styling match the VSCode defined sidebar color
|
||||
- Added support for `mdx` files
|
||||
- Added support for `enter` press in the combobox
|
||||
- [#41](https://github.com/estruyf/vscode-front-matter/issues/41): Word count implementation + extra details
|
||||
- [#40](https://github.com/estruyf/vscode-front-matter/issues/40): Added checks for the keyword usage in title, description, slug, and content
|
||||
|
||||
## [1.18.0] - 2020-07-20
|
||||
|
||||
- Updated README
|
||||
|
||||
## [1.17.1] - 2020-06-28
|
||||
|
||||
- [#34](https://github.com/estruyf/vscode-front-matter/issues/34): Fix that last modification date does not update the publication date
|
||||
- [#38](https://github.com/estruyf/vscode-front-matter/issues/38): Update the last modification date on new page creation from the template
|
||||
|
||||
## [1.17.0] - 2020-06-14
|
||||
|
||||
- [#36](https://github.com/estruyf/vscode-front-matter/issues/36): Add the option to change the Front Matter its description field
|
||||
|
||||
191
README.md
@@ -1,8 +1,24 @@
|
||||
[](https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter)
|
||||
|
||||
[](https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter)
|
||||
|
||||
[](https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter&ssr=false#review-details)
|
||||
<h1 align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter">
|
||||
<img alt="Front Matter" src="./assets/front-matter.png">
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<h2 align="center">Front Matter is an essential Visual Studio Code extension when you want to manage the markdown pages of your static sites.</h2>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter" title="Check it out on the Visual Studio Marketplace">
|
||||
<img src="https://vsmarketplacebadge.apphb.com/version/eliostruyf.vscode-front-matter.svg" alt="Visual Studio Marketplace" style="display: inline-block" />
|
||||
</a>
|
||||
|
||||
<img src="https://vsmarketplacebadge.apphb.com/installs/eliostruyf.vscode-front-matter.svg" alt="Number of installs" style="display: inline-block;margin-left:10px" />
|
||||
|
||||
<img src="https://vsmarketplacebadge.apphb.com/rating/eliostruyf.vscode-front-matter.svg" alt="Ratings" style="display: inline-block;margin-left:10px" />
|
||||
|
||||
<a href="https://www.buymeacoffee.com/zMeFRy9" title="Buy me a coffee" style="margin-left:10px">
|
||||
<img src="https://img.shields.io/badge/Buy%20me%20a%20coffee-€%203-blue?logo=buy-me-a-coffee&style=flat" alt="Buy me a coffee" style="display: inline-block" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
This VSCode extension simplifies working with your markdown articles' front matter when using a static site generator like Hugo, Jekyll, Hexo, NextJs, Gatsby, and many more... For example, you can keep a list of used tags, categories and add/remove them from your article with the extension.
|
||||
|
||||
@@ -10,37 +26,100 @@ The extension will automatically verify if your title and description are SEO co
|
||||
|
||||
> If you see something missing in your article creation flow, please feel free to reach out.
|
||||
|
||||
## FrontMatter Panel (introduced in 1.10.0)
|
||||
**Version 2**
|
||||
|
||||
In version `1.10.0` of this extension, the FrontMatter panel got introduced. This panel allows you to perform most of the extension actions by just a click on the button.
|
||||
In version v2.0.0 we released the newly redesigned sidebar panel with improved SEO support. This extension makes it the only extension to manage your Markdown pages for your static sites in Visual Studio Code.
|
||||
|
||||

|
||||
<h2 id="table-of-contents">Table of Contents</h2>
|
||||
|
||||
<details open="open">
|
||||
<summary>Table of Contents</summary>
|
||||
<ol>
|
||||
<li><a href="#the-panel">The panel</a></li>
|
||||
<li><a href="#custom-actions">Custom actions</a></li>
|
||||
<li><a href="#creating-articles-from-templates">Create articles from templates</a></li>
|
||||
<li><a href="#syntax-highlighting-for-hugo-shortcodes">Syntax highlighting for Hugo Shortcodes</a></li>
|
||||
<li><a href="#available-commands">Available commands</a></li>
|
||||
<li><a href="#extension-settings">Extension settings</a></li>
|
||||
<li><a href="#feedback--issues--ideas">Feedback / issues / ideas</a></li>
|
||||
</ol>
|
||||
</details>
|
||||
|
||||
## The panel
|
||||
|
||||
The Front Matter panel allows you to perform most of the extension actions by just a click on the button and it shows the SEO statuses of your title, description, and more.
|
||||
|
||||
Initially, this panel has been created to make it easier to add tags and categories to your articles as the current VSCode multi-select is not optimal to use.
|
||||
|
||||
To leverage most of the capabilities of the extension. SEO information and everyday actions like slug optimization, updating the date, and publish/drafting the article.
|
||||
|
||||
When the panel opens on a none markdown file, it will contain the following sections:
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/v2.2.0/baseview.png" alt="Base view" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
When you open the Front Matter panel on a Markdown file, you get to see the following sections:
|
||||
|
||||
**SEO Status**
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/v2.0.0/seo.png" alt="SEO article status" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
**Actions**
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/v2.0.0/actions.png" alt="Actions" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
**Metadata: Keywords, Tags, Categories**
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/v2.0.0/metadata.png" alt="Article metadata" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
> **Info**: By default, the tags/categories picker allows you to insert existing and none tags/categories. When you enter a none existing tag/category, the panel shows an add `+` icon in front of that button. This functionality allows you to store this tag/category in your settings. If you want to disable this feature, you can do that by setting the `frontMatter.panel.freeform` setting to `false`.
|
||||
|
||||
Since version `1.15.0`, the extension allows you to create your own custom actions, by running Node.js scripts from your project. In order to use this functionality, you will need to configure the [`frontMatter.custom.scripts`](#frontMatter.custom.scripts) setting for your project.
|
||||
**Other actions**
|
||||
|
||||
At the bottom of the panel you can find the following actions:
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/v2.0.0/other-actions.png" alt="Other actions" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
## Custom actions
|
||||
|
||||
Since version `1.15.0`, the extension allows you to create your own custom actions, by running Node.js scripts from your project. In order to use this functionality, you will need to configure the [`frontMatter.custom.scripts`](#frontmattercustomscripts) setting for your project.
|
||||
|
||||
Once a custom action has been configured, it will appear on the Front Matter panel.
|
||||
|
||||

|
||||
<p align="center">
|
||||
<img src="./assets/v2.0.0/custom-action.png" alt="Custom action" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
The current workspace-, file-path, and front matter data will be passed as an argument. In your script fetch these arguments as follows:
|
||||
|
||||
```javascript
|
||||
const arguments = process.argv;
|
||||
const workspaceArg = arguments[2];
|
||||
const fileArg = arguments[3];
|
||||
const dataArg = arguments[4];
|
||||
const data = dataArg && typeof dataArg === "string" ? JSON.parse(dataArg) : null;
|
||||
|
||||
if (arguments && arguments.length > 0) {
|
||||
const workspaceArg = arguments[2]; // The workspace path
|
||||
const fileArg = arguments[3]; // The file path
|
||||
const frontMatterArg = arguments[4]; // Front matter data
|
||||
|
||||
console.log(`The content returned for your notification.`);
|
||||
}
|
||||
```
|
||||
|
||||
> A sample file can be found here: [script-sample.js](./sample/script-sample.js)
|
||||
|
||||
The output of the script will be passed as a notification, and it allows you to copy the output.
|
||||
|
||||

|
||||
<p align="center">
|
||||
<img src="./assets/custom-action-notification.png" alt="Custom action notification" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
## Creating articles from templates
|
||||
|
||||
@@ -54,19 +133,45 @@ When adding files in the folder, you'll be able to run the `Front Matter: New ar
|
||||
|
||||
## Syntax highlighting for Hugo Shortcodes
|
||||
|
||||

|
||||
<p align="center">
|
||||
<img src="./assets/syntax-highlighting.png" alt="Shortcode syntax highlighting" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
## Available commands:
|
||||
## Available commands
|
||||
|
||||
**Front Matter: Initialize project**
|
||||
|
||||
This command will initialize the project with a template folder and an article template. It makes it easier to get you started with the extension and creating your content.
|
||||
|
||||
**Front Matter: Create content**
|
||||
|
||||
With this command, you can easily create content in your project within the registered folders and provided templates.
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/v2.1.0/create-content.png" alt="Create content" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
You can register and unregister folders by right-clicking on the folder in your VSCode explorer panel.
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/v2.1.0/register-folder.png" alt="Register/unregister a folder" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
Once you registered a folder and a template has been defined ([how to create a template](#creating-articles-from-templates)), you can make use of this command.
|
||||
|
||||
> **Info**: The benefit of this command is that you do not need to search the folder in which you want to create a new article/page/... The extension will do it automatically for you.
|
||||
|
||||
**Front Matter: Create <tag | category>**
|
||||
|
||||
Creates a new <tag | category> and allows you to include it into your post automatically
|
||||
|
||||

|
||||
<p align="center">
|
||||
<img src="./assets/create-tag-category.gif" alt="Create tag or category" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
**Front Matter: Insert <tags | categories>**
|
||||
|
||||
Inserts a selected <tags | categories> into the front matter of your article/post/... - When using this command, the FrontMatter panel opens and focuses on the specified type.
|
||||
Inserts a selected <tags | categories> into the front matter of your article/post/... - When using this command, the Front Matter panel opens and focuses on the specified type.
|
||||
|
||||
> **Info**: This experience changed in version `1.11.0`.
|
||||
|
||||
@@ -97,15 +202,23 @@ Update the `lastmod` (last modified) property of the current article/post/... to
|
||||
This command generates a clean slug for your article. It removes known stop words, punctuations, and special characters.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
title: Just a sample page with a title
|
||||
slug: sample-page-title
|
||||
```
|
||||
|
||||
You can also specify a prefix and suffix, which can be added to the slug if you want. Use the following settings to do this: `frontMatter.taxonomy.slugPrefix` and `frontMatter.taxonomy.slugSuffix`. By default, both options are not provided and will not add anything to the slug.
|
||||
You can also specify a prefix and suffix, which can be added to the slug if you want. Use the following settings to do this: `frontMatter.taxonomy.slugPrefix` and `frontMatter.taxonomy.slugSuffix`. By default, both options are not provided and will not add anything to the slug. Another setting is to allow you to sync the filename with the generated slug. The setting you need to turn on enable for this is `frontMatter.taxonomy.alignFilename`.
|
||||
|
||||
> **Info**: At the moment, the extension only supports English stopwords.
|
||||
|
||||
### Usage
|
||||
|
||||
- Start by opening the command prompt:
|
||||
- Windows: ⇧+ctrl+P
|
||||
- Mac: ⇧+⌘+P
|
||||
- Use one of the commands from above
|
||||
|
||||
## Where is the data stored?
|
||||
|
||||
The tags and categories are stored in the project VSCode user settings. You can find them back under: `.vscode/settings.json`.
|
||||
@@ -117,7 +230,7 @@ The tags and categories are stored in the project VSCode user settings. You can
|
||||
}
|
||||
```
|
||||
|
||||
## Additional extension settings
|
||||
## Extension settings
|
||||
|
||||
The extension has more settings that allow you to configure it to your needs further. Here is a list of settings that you can set:
|
||||
|
||||
@@ -139,6 +252,17 @@ Specifies the optimal description length for SEO (set to `-1` to turn it off). D
|
||||
"frontMatter.taxonomy.seoDescriptionLength": 160
|
||||
}
|
||||
```
|
||||
|
||||
### `frontMatter.taxonomy.seoContentLength`
|
||||
|
||||
Specifies the optimal minimum length for your articles. Between 1,760 words – 2,400 is the absolute ideal article length for SEO in 2021. (set to `-1` to turn it off).
|
||||
|
||||
```json
|
||||
{
|
||||
"frontMatter.taxonomy.seoContentLength": 1760
|
||||
}
|
||||
```
|
||||
|
||||
### `frontMatter.taxonomy.seoDescriptionLength`
|
||||
|
||||
Specifies the name of the SEO description field for your page. Default is `description`.
|
||||
@@ -215,13 +339,28 @@ Allows you to specify a title and script path (starting relative from the root o
|
||||
|
||||
> **Important**: When the command execution would fail when it cannot find the `node` command. You are able to specify your path to the node app. This is for instance required when using `nvm`.
|
||||
|
||||
## Usage
|
||||
### `frontMatter.content.folders`
|
||||
|
||||
- Start by opening the command prompt:
|
||||
- Windows: ⇧+ctrl+P
|
||||
- Mac: ⇧+⌘+P
|
||||
- Use one of the commands from above
|
||||
This array of folders defines where the extension can easily create new content by running the create article command.
|
||||
|
||||
```json
|
||||
{
|
||||
"frontMatter.content.folders": [{
|
||||
"title": "Articles",
|
||||
"fsPath": "<the path to the folder>",
|
||||
"paths": ["<wsl-folder-path>"]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
> **Important**: This setting can be configured by right-clicking on a folder in the VSCode file explorer view and clicking on the `Front Matter: Register folder` menu item.
|
||||
|
||||
## Feedback / issues / ideas
|
||||
|
||||
Please submit them via creating an issue in the project repository: [issue list](https://github.com/estruyf/vscode-front-matter/issues).
|
||||
|
||||
<p align="center">
|
||||
<a href="#">
|
||||
<img src="https://estruyf-github.azurewebsites.net/api/VisitorHit?user=estruyf&repo=vscode-front-matter&countColor=%23F05450&labelColor=%230E131F" />
|
||||
</a>
|
||||
</p>
|
||||
@@ -21,6 +21,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
.absolute {
|
||||
position: absolute !important;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.collapsible__body,
|
||||
.ext_settings {
|
||||
padding: 1rem 1.25rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#app, .frontmatter {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.spinner,
|
||||
.spinner:before,
|
||||
.spinner:after {
|
||||
@@ -58,6 +76,13 @@
|
||||
left: 3.5em;
|
||||
}
|
||||
|
||||
.frontmatter {
|
||||
padding-top: 0;
|
||||
padding-bottom: var(--input-margin-vertical);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.frontmatter h3 {
|
||||
margin-bottom: 1rem;
|
||||
@@ -69,22 +94,34 @@
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
.seo__status__details {
|
||||
margin-bottom: 2rem;
|
||||
.article__tags h3,
|
||||
.seo__status h3 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.section {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.section h3 svg {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.seo__status__details, .seo__status__keywords {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.collapsible__body h4 {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.not-valid {
|
||||
color: var(--vscode-errorForeground);
|
||||
}
|
||||
|
||||
.article__actions {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.article__action {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.article__tags {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@@ -118,9 +155,15 @@
|
||||
|
||||
.article__tags__input button {
|
||||
position: absolute;
|
||||
bottom: 1px;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
width: 30px;
|
||||
padding-bottom: 2px;
|
||||
padding-top: 2px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.article__tags ul {
|
||||
@@ -151,6 +194,12 @@
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.article__tags__items__item {
|
||||
display: inline-flex;
|
||||
margin-bottom: .5rem;
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.article__tags__items__item {
|
||||
display: inline-block;
|
||||
margin-bottom: .5rem;
|
||||
@@ -199,18 +248,72 @@
|
||||
filter: contrast(60%);
|
||||
}
|
||||
|
||||
.ext_link_block {
|
||||
margin-bottom: .5rem;
|
||||
text-align: right;
|
||||
.article__actions > * + *,
|
||||
.base__actions > * + *,
|
||||
.base__information > * + * {
|
||||
--tw-space-y-reverse: 0;
|
||||
margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
|
||||
margin-bottom: calc(1rem * var(--tw-space-y-reverse));
|
||||
}
|
||||
|
||||
.seo__status__details ul > * + *,
|
||||
.ext_settings > * + * {
|
||||
--tw-space-y-reverse: 0;
|
||||
margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
|
||||
margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
|
||||
}
|
||||
|
||||
.ext_link_block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ext_link_block svg {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.ext_link_block button,
|
||||
.ext_link_block a {
|
||||
color: var(--vscode-textLink-foreground);
|
||||
align-items: center;
|
||||
color: var(--vscode-button-secondaryForeground);
|
||||
background-color: var(--vscode-button-secondaryBackground);
|
||||
border: 0px;
|
||||
border-radius: 0px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
font-size: var(--vscode-font-size);
|
||||
font-weight: var(--vscode-font-weight);
|
||||
line-height: 26px;
|
||||
padding: 0px 14px;
|
||||
user-select: none;
|
||||
text-decoration: none;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.ext_link_block a:hover,
|
||||
.ext_link_block a:active,
|
||||
.ext_link_block a:focus,
|
||||
.ext_link_block a:visited {
|
||||
color: var(--vscode-textLink-activeForeground);
|
||||
color: var(--vscode-button-secondaryForeground);
|
||||
}
|
||||
|
||||
.table__cell {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table__title {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.table__cell__validation {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.table__cell__validation .valid {
|
||||
color: #46EC86;
|
||||
}
|
||||
|
||||
.table__cell__validation .warning {
|
||||
color: #E6AF2E;
|
||||
}
|
||||
@@ -1,29 +1,26 @@
|
||||
:root {
|
||||
--container-paddding: 20px;
|
||||
--container-padding: 20px;
|
||||
--input-padding-vertical: 6px;
|
||||
--input-padding-horizontal: 4px;
|
||||
--input-margin-vertical: 4px;
|
||||
--input-margin-horizontal: 0;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0 var(--container-paddding);
|
||||
color: var(--vscode-foreground);
|
||||
font-size: var(--vscode-font-size);
|
||||
font-weight: var(--vscode-font-weight);
|
||||
font-family: var(--vscode-font-family);
|
||||
background-color: var(--vscode-editor-background);
|
||||
background-color: var(--vscode-sideBar-background);
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: var(--container-paddding);
|
||||
}
|
||||
|
||||
body > *,
|
||||
form > * {
|
||||
margin-block-start: var(--input-margin-vertical);
|
||||
margin-block-end: var(--input-margin-vertical);
|
||||
padding-left: var(--container-padding);
|
||||
}
|
||||
|
||||
*:focus {
|
||||
@@ -53,6 +50,7 @@ button {
|
||||
outline-offset: 2px !important;
|
||||
color: var(--vscode-button-foreground);
|
||||
background: var(--vscode-button-background);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
|
||||
BIN
assets/v2.0.0/actions.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
assets/v2.0.0/custom-action.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
assets/v2.0.0/metadata.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
assets/v2.0.0/other-actions.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
assets/v2.0.0/seo.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
assets/v2.1.0/create-content.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
assets/v2.1.0/register-folder.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
assets/v2.2.0/baseview.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
715
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vscode-front-matter",
|
||||
"version": "1.17.0",
|
||||
"version": "2.2.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -39,11 +39,14 @@
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
},
|
||||
"@emotion/hash": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
|
||||
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==",
|
||||
"dev": true
|
||||
"@bendera/vscode-webview-elements": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@bendera/vscode-webview-elements/-/vscode-webview-elements-0.6.2.tgz",
|
||||
"integrity": "sha512-smtr+KvCKV2MwjVrmyvrhonpaXVpxCjTMXUQOwDwWSAQ42x5pnlpjCGElz2dljc5VHS1Mh1ovPSQ/P3jAm7vMQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lit-element": "^2.5.1"
|
||||
}
|
||||
},
|
||||
"@iarna/toml": {
|
||||
"version": "2.2.3",
|
||||
@@ -51,123 +54,18 @@
|
||||
"integrity": "sha512-FmuxfCuolpLl0AnQ2NHSzoUKWEJDFl63qXjzdoWBVyFCXzMGm1spBzk7LeHNoVCiWCF7mRVms9e6jEV9+MoPbg==",
|
||||
"dev": true
|
||||
},
|
||||
"@material-ui/core": {
|
||||
"version": "4.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.1.tgz",
|
||||
"integrity": "sha512-aesI8lOaaw0DRIfNG+Anepf61NH5Q+cmkxJOZvI1oHkmD5cKubkZ0C7INqFKjfFpSFlFnqHkTasoM7ogFAvzOg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.4.4",
|
||||
"@material-ui/styles": "^4.11.1",
|
||||
"@material-ui/system": "^4.9.14",
|
||||
"@material-ui/types": "^5.1.0",
|
||||
"@material-ui/utils": "^4.10.2",
|
||||
"@types/react-transition-group": "^4.2.0",
|
||||
"clsx": "^1.0.4",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"popper.js": "1.16.1-lts",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-is": "^16.8.0",
|
||||
"react-transition-group": "^4.4.0"
|
||||
}
|
||||
},
|
||||
"@material-ui/icons": {
|
||||
"version": "4.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz",
|
||||
"integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.4.4"
|
||||
}
|
||||
},
|
||||
"@material-ui/lab": {
|
||||
"version": "4.0.0-alpha.56",
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.56.tgz",
|
||||
"integrity": "sha512-xPlkK+z/6y/24ka4gVJgwPfoCF4RCh8dXb1BNE7MtF9bXEBLN/lBxNTK8VAa0qm3V2oinA6xtUIdcRh0aeRtVw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.4.4",
|
||||
"@material-ui/utils": "^4.10.2",
|
||||
"clsx": "^1.0.4",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-is": "^16.8.0"
|
||||
}
|
||||
},
|
||||
"@material-ui/styles": {
|
||||
"version": "4.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.1.tgz",
|
||||
"integrity": "sha512-GqzsFsVWT8jXa8OWAd1WD6WIaqtXr2mUPbRZ1EjkiM3Dlta4mCRaToDxkFVv6ZHfXlFjMJzdaIEvCpZOCvZTvg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.4.4",
|
||||
"@emotion/hash": "^0.8.0",
|
||||
"@material-ui/types": "^5.1.0",
|
||||
"@material-ui/utils": "^4.9.6",
|
||||
"clsx": "^1.0.4",
|
||||
"csstype": "^2.5.2",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"jss": "^10.0.3",
|
||||
"jss-plugin-camel-case": "^10.0.3",
|
||||
"jss-plugin-default-unit": "^10.0.3",
|
||||
"jss-plugin-global": "^10.0.3",
|
||||
"jss-plugin-nested": "^10.0.3",
|
||||
"jss-plugin-props-sort": "^10.0.3",
|
||||
"jss-plugin-rule-value-function": "^10.0.3",
|
||||
"jss-plugin-vendor-prefixer": "^10.0.3",
|
||||
"prop-types": "^15.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"csstype": {
|
||||
"version": "2.6.14",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.14.tgz",
|
||||
"integrity": "sha512-2mSc+VEpGPblzAxyeR+vZhJKgYg0Og0nnRi7pmRXFYYxSfnOnW8A5wwQb4n4cE2nIOzqKOAzLCaEX6aBmNEv8A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@material-ui/system": {
|
||||
"version": "4.9.14",
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.9.14.tgz",
|
||||
"integrity": "sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.4.4",
|
||||
"@material-ui/utils": "^4.9.6",
|
||||
"csstype": "^2.5.2",
|
||||
"prop-types": "^15.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"csstype": {
|
||||
"version": "2.6.14",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.14.tgz",
|
||||
"integrity": "sha512-2mSc+VEpGPblzAxyeR+vZhJKgYg0Og0nnRi7pmRXFYYxSfnOnW8A5wwQb4n4cE2nIOzqKOAzLCaEX6aBmNEv8A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@material-ui/types": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
|
||||
"integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
|
||||
"dev": true
|
||||
},
|
||||
"@material-ui/utils": {
|
||||
"version": "4.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.10.2.tgz",
|
||||
"integrity": "sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.4.4",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-is": "^16.8.0"
|
||||
}
|
||||
},
|
||||
"@types/anymatch": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz",
|
||||
"integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/debug": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.6.tgz",
|
||||
"integrity": "sha512-7fDOJFA/x8B+sO1901BmHlf5dE1cxBU8mRXj8QOEDnn16hhGJv/IHxJtZhvsabZsIMn0eLIyeOKAeqSNJJYTpA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/glob": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
|
||||
@@ -196,6 +94,30 @@
|
||||
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.172",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.172.tgz",
|
||||
"integrity": "sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash.uniqby": {
|
||||
"version": "4.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash.uniqby/-/lodash.uniqby-4.7.6.tgz",
|
||||
"integrity": "sha512-9wBhrm1y6asW50Joj6tsySCNUgzK2tCqL7vtKIej0E9RyeBFdcte7fxUosmFuMoOU0eHqOMK76kCCrK99jxHgg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
},
|
||||
"@types/mdast": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.7.tgz",
|
||||
"integrity": "sha512-YwR7OK8aPmaBvMMUi+pZXBNoW2unbVbfok4YRqGMJBe1dpDlzpRkJrYEYmvjxgs5JhuQmKfDexrN98u941Zasg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"@types/minimatch": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
||||
@@ -239,15 +161,6 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-transition-group": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz",
|
||||
"integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/source-list-map": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
|
||||
@@ -277,6 +190,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/unist": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
|
||||
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/vscode": {
|
||||
"version": "1.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.51.0.tgz",
|
||||
@@ -324,6 +243,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vscode/codicons": {
|
||||
"version": "0.0.20",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.20.tgz",
|
||||
"integrity": "sha512-LlO6K7nzrIWDCZN1Zi6J6ibxrpMibSAct+zNjAwpkNkwup6cJLx5diYvsOJODMPWOuQlBO21qkxtdkSRzW6+Jw==",
|
||||
"dev": true
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
|
||||
@@ -1004,6 +929,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"character-entities": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.0.tgz",
|
||||
"integrity": "sha512-oHqMj3eAuJ77/P5PaIRcqk+C3hdfNwyCD2DAUcD5gyXkegAuF2USC40CEqPscDk4I8FRGMTojGJQkXDsN5QlJA==",
|
||||
"dev": true
|
||||
},
|
||||
"character-entities-legacy": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-2.0.0.tgz",
|
||||
"integrity": "sha512-YwaEtEvWLpFa6Wh3uVLrvirA/ahr9fki/NUd/Bd4OR6EdJ8D22hovYQEOUCBfQfcqnC4IAMGMsHXY1eXgL4ZZA==",
|
||||
"dev": true
|
||||
},
|
||||
"character-reference-invalid": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.0.tgz",
|
||||
"integrity": "sha512-pE3Z15lLRxDzWJy7bBHBopRwfI20sbrMVLQTC7xsPglCHf4Wv1e167OgYAFP78co2XlhojDyAqA+IAJse27//g==",
|
||||
"dev": true
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
|
||||
@@ -1086,12 +1029,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"clsx": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
|
||||
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==",
|
||||
"dev": true
|
||||
},
|
||||
"collection-visit": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
|
||||
@@ -1286,16 +1223,6 @@
|
||||
"nth-check": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"css-vendor": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
|
||||
"integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"is-in-browser": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
|
||||
@@ -1320,6 +1247,15 @@
|
||||
"integrity": "sha512-C14oTzTZy8DH1Eq8N78owrCWvf3+cnJw88BTK/N3DYWVxDJuJzPaNdplzYxDYuuXXGvqBcO4Vy5SOrwAooXSWw==",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
@@ -1426,16 +1362,6 @@
|
||||
"utila": "~0.4"
|
||||
}
|
||||
},
|
||||
"dom-helpers": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz",
|
||||
"integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"dom-serializer": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
|
||||
@@ -2279,15 +2205,6 @@
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"homedir-polyfill": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
|
||||
@@ -2476,12 +2393,6 @@
|
||||
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
|
||||
"dev": true
|
||||
},
|
||||
"hyphenate-style-name": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
|
||||
"integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
@@ -2510,15 +2421,6 @@
|
||||
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
|
||||
"dev": true
|
||||
},
|
||||
"indefinite-observable": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-2.0.1.tgz",
|
||||
"integrity": "sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"symbol-observable": "1.2.0"
|
||||
}
|
||||
},
|
||||
"infer-owner": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
|
||||
@@ -2579,6 +2481,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"is-alphabetical": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.0.tgz",
|
||||
"integrity": "sha512-5OV8Toyq3oh4eq6sbWTYzlGdnMT/DPI5I0zxUBxjiigQsZycpkKF3kskkao3JyYGuYDHvhgJF+DrjMQp9SX86w==",
|
||||
"dev": true
|
||||
},
|
||||
"is-alphanumerical": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.0.tgz",
|
||||
"integrity": "sha512-t+2GlJ+hO9yagJ+jU3+HSh80VKvz/3cG2cxbGGm4S0hjKuhWQXgPVUVOZz3tqZzMjhmphZ+1TIJTlRZRoe6GCQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-alphabetical": "^2.0.0",
|
||||
"is-decimal": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
@@ -2636,6 +2554,12 @@
|
||||
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
|
||||
"dev": true
|
||||
},
|
||||
"is-decimal": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.0.tgz",
|
||||
"integrity": "sha512-QfrfjQV0LjoWQ1K1XSoEZkTAzSa14RKVMa5zg3SdAfzEmQzRM4+tbSFWb78creCeA9rNBzaZal92opi1TwPWZw==",
|
||||
"dev": true
|
||||
},
|
||||
"is-descriptor": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
|
||||
@@ -2682,10 +2606,10 @@
|
||||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"is-in-browser": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
|
||||
"integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=",
|
||||
"is-hexadecimal": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.0.tgz",
|
||||
"integrity": "sha512-vGOtYkiaxwIiR0+Ng/zNId+ZZehGfINwTzdrDqc6iubbnQWhnPuYymOzOKUDqa2cSl59yHnEh2h6MvRLQsyNug==",
|
||||
"dev": true
|
||||
},
|
||||
"is-number": {
|
||||
@@ -2796,99 +2720,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"jss": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jss/-/jss-10.5.0.tgz",
|
||||
"integrity": "sha512-B6151NvG+thUg3murLNHRPLxTLwQ13ep4SH5brj4d8qKtogOx/jupnpfkPGSHPqvcwKJaCLctpj2lEk+5yGwMw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"csstype": "^3.0.2",
|
||||
"indefinite-observable": "^2.0.1",
|
||||
"is-in-browser": "^1.1.3",
|
||||
"tiny-warning": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"jss-plugin-camel-case": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.5.0.tgz",
|
||||
"integrity": "sha512-GSjPL0adGAkuoqeYiXTgO7PlIrmjv5v8lA6TTBdfxbNYpxADOdGKJgIEkffhlyuIZHlPuuiFYTwUreLUmSn7rg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"hyphenate-style-name": "^1.0.3",
|
||||
"jss": "10.5.0"
|
||||
}
|
||||
},
|
||||
"jss-plugin-default-unit": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.5.0.tgz",
|
||||
"integrity": "sha512-rsbTtZGCMrbcb9beiDd+TwL991NGmsAgVYH0hATrYJtue9e+LH/Gn4yFD1ENwE+3JzF3A+rPnM2JuD9L/SIIWw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"jss": "10.5.0"
|
||||
}
|
||||
},
|
||||
"jss-plugin-global": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.5.0.tgz",
|
||||
"integrity": "sha512-FZd9+JE/3D7HMefEG54fEC0XiQ9rhGtDHAT/ols24y8sKQ1D5KIw6OyXEmIdKFmACgxZV2ARQ5pAUypxkk2IFQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"jss": "10.5.0"
|
||||
}
|
||||
},
|
||||
"jss-plugin-nested": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.5.0.tgz",
|
||||
"integrity": "sha512-ejPlCLNlEGgx8jmMiDk/zarsCZk+DV0YqXfddpgzbO9Toamo0HweCFuwJ3ZO40UFOfqKwfpKMVH/3HUXgxkTMg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"jss": "10.5.0",
|
||||
"tiny-warning": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"jss-plugin-props-sort": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.5.0.tgz",
|
||||
"integrity": "sha512-kTLRvrOetFKz5vM88FAhLNeJIxfjhCepnvq65G7xsAQ/Wgy7HwO1BS/2wE5mx8iLaAWC6Rj5h16mhMk9sKdZxg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"jss": "10.5.0"
|
||||
}
|
||||
},
|
||||
"jss-plugin-rule-value-function": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.5.0.tgz",
|
||||
"integrity": "sha512-jXINGr8BSsB13JVuK274oEtk0LoooYSJqTBCGeBu2cG/VJ3+4FPs1gwLgsq24xTgKshtZ+WEQMVL34OprLidRA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"jss": "10.5.0",
|
||||
"tiny-warning": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"jss-plugin-vendor-prefixer": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.5.0.tgz",
|
||||
"integrity": "sha512-rux3gmfwDdOKCLDx0IQjTwTm03IfBa+Rm/hs747cOw5Q7O3RaTUIMPKjtVfc31Xr/XI9Abz2XEupk1/oMQ7zRA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"css-vendor": "^2.0.8",
|
||||
"jss": "10.5.0"
|
||||
}
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
|
||||
"dev": true
|
||||
},
|
||||
"lit-element": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-2.5.1.tgz",
|
||||
"integrity": "sha512-ogu7PiJTA33bEK0xGu1dmaX5vhcRjBXCFexPja0e7P7jqLhTpNKYRPmE+GmiCaRVAbiQKGkUgkh/i6+bh++dPQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lit-html": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"lit-html": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-1.4.1.tgz",
|
||||
"integrity": "sha512-B9btcSgPYb1q4oSOb/PrOT6Z/H+r6xuNzfH4lFli/AWhYwdtrgQkQWBbIc6mdnf6E2IL3gDXdkkqNktpU0OZQA==",
|
||||
"dev": true
|
||||
},
|
||||
"loader-runner": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
|
||||
@@ -2917,11 +2769,16 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.uniqby": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz",
|
||||
"integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI="
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
@@ -2985,6 +2842,30 @@
|
||||
"safe-buffer": "^5.1.2"
|
||||
}
|
||||
},
|
||||
"mdast-util-from-markdown": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.0.0.tgz",
|
||||
"integrity": "sha512-uj2G60sb7z1PNOeElFwCC9b/Se/lFXuLhVKFOAY2EHz/VvgbupTQRNXPoZl7rGpXYL6BNZgcgaybrlSWbo7n/g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/mdast": "^3.0.0",
|
||||
"@types/unist": "^2.0.0",
|
||||
"mdast-util-to-string": "^3.0.0",
|
||||
"micromark": "^3.0.0",
|
||||
"micromark-util-decode-numeric-character-reference": "^1.0.0",
|
||||
"micromark-util-normalize-identifier": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0",
|
||||
"parse-entities": "^3.0.0",
|
||||
"unist-util-stringify-position": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"mdast-util-to-string": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz",
|
||||
"integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==",
|
||||
"dev": true
|
||||
},
|
||||
"memory-fs": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
|
||||
@@ -2995,6 +2876,222 @@
|
||||
"readable-stream": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"micromark": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.1.tgz",
|
||||
"integrity": "sha512-DqC0I0V6D3wy/XmJTK1Tn+JPlMk7phhtDQ7ZJIZgAzHTyeVXMDdOaHQ2WQ7i5z3Bh4JK66nLBmjtgMrWwe8eMw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/debug": "^4.0.0",
|
||||
"debug": "^4.0.0",
|
||||
"micromark-core-commonmark": "^1.0.0",
|
||||
"micromark-factory-space": "^1.0.0",
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-chunked": "^1.0.0",
|
||||
"micromark-util-combine-extensions": "^1.0.0",
|
||||
"micromark-util-decode-numeric-character-reference": "^1.0.0",
|
||||
"micromark-util-encode": "^1.0.0",
|
||||
"micromark-util-normalize-identifier": "^1.0.0",
|
||||
"micromark-util-resolve-all": "^1.0.0",
|
||||
"micromark-util-sanitize-uri": "^1.0.0",
|
||||
"micromark-util-subtokenize": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0",
|
||||
"parse-entities": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-core-commonmark": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.0.tgz",
|
||||
"integrity": "sha512-y9g7zymcKRBHM/aNBekstvs/Grpf+y4OEBULUTYvGZcusnp+JeOxmilJY4GMpo2/xY7iHQL9fjz5pD9pSAud9A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-factory-destination": "^1.0.0",
|
||||
"micromark-factory-label": "^1.0.0",
|
||||
"micromark-factory-space": "^1.0.0",
|
||||
"micromark-factory-title": "^1.0.0",
|
||||
"micromark-factory-whitespace": "^1.0.0",
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-chunked": "^1.0.0",
|
||||
"micromark-util-classify-character": "^1.0.0",
|
||||
"micromark-util-html-tag-name": "^1.0.0",
|
||||
"micromark-util-normalize-identifier": "^1.0.0",
|
||||
"micromark-util-resolve-all": "^1.0.0",
|
||||
"micromark-util-subtokenize": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0",
|
||||
"parse-entities": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-factory-destination": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz",
|
||||
"integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-factory-label": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.0.tgz",
|
||||
"integrity": "sha512-XWEucVZb+qBCe2jmlOnWr6sWSY6NHx+wtpgYFsm4G+dufOf6tTQRRo0bdO7XSlGPu5fyjpJenth6Ksnc5Mwfww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-factory-space": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz",
|
||||
"integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-factory-title": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.0.tgz",
|
||||
"integrity": "sha512-flvC7Gx0dWVWorXuBl09Cr3wB5FTuYec8pMGVySIp2ZlqTcIjN/lFohZcP0EG//krTptm34kozHk7aK/CleCfA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-factory-space": "^1.0.0",
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-factory-whitespace": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz",
|
||||
"integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-factory-space": "^1.0.0",
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-util-character": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.0.0.tgz",
|
||||
"integrity": "sha512-VdfDsHtUn/ocN2hGBkMunHHWcaN33llgwU0bmw2LA0tY1JvVkjHGvdiQSIk0pS3XeGCJLT6syS5i8y+1xbwDnQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-util-chunked": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz",
|
||||
"integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-symbol": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-util-classify-character": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz",
|
||||
"integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-util-combine-extensions": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz",
|
||||
"integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-chunked": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-util-decode-numeric-character-reference": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz",
|
||||
"integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-symbol": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-util-encode": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.0.tgz",
|
||||
"integrity": "sha512-cJpFVM768h6zkd8qJ1LNRrITfY4gwFt+tziPcIf71Ui8yFzY9wG3snZQqiWVq93PG4Sw6YOtcNiKJfVIs9qfGg==",
|
||||
"dev": true
|
||||
},
|
||||
"micromark-util-html-tag-name": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.0.0.tgz",
|
||||
"integrity": "sha512-NenEKIshW2ZI/ERv9HtFNsrn3llSPZtY337LID/24WeLqMzeZhBEE6BQ0vS2ZBjshm5n40chKtJ3qjAbVV8S0g==",
|
||||
"dev": true
|
||||
},
|
||||
"micromark-util-normalize-identifier": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz",
|
||||
"integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-symbol": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-util-resolve-all": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz",
|
||||
"integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-types": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-util-sanitize-uri": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz",
|
||||
"integrity": "sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-encode": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-util-subtokenize": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.0.tgz",
|
||||
"integrity": "sha512-EsnG2qscmcN5XhkqQBZni/4oQbLFjz9yk3ZM/P8a3YUjwV6+6On2wehr1ALx0MxK3+XXXLTzuBKHDFeDFYRdgQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromark-util-chunked": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"micromark-util-symbol": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.0.tgz",
|
||||
"integrity": "sha512-NZA01jHRNCt4KlOROn8/bGi6vvpEmlXld7EHcRH+aYWUfL3Wc8JLUNNlqUMKa0hhz6GrpUWsHtzPmKof57v0gQ==",
|
||||
"dev": true
|
||||
},
|
||||
"micromark-util-types": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.0.tgz",
|
||||
"integrity": "sha512-psf1WAaP1B77WpW4mBGDkTr+3RsPuDAgsvlP47GJzbH1jmjH8xjOx7Z6kp84L8oqHmy5pYO3Ev46odosZV+3AA==",
|
||||
"dev": true
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
|
||||
@@ -3114,6 +3211,12 @@
|
||||
"run-queue": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.14.2",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
|
||||
@@ -3394,6 +3497,20 @@
|
||||
"safe-buffer": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"parse-entities": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-3.0.0.tgz",
|
||||
"integrity": "sha512-AJlcIFDNPEP33KyJLguv0xJc83BNvjxwpuUIcetyXUsLpVXAUCePJ5kIoYtEN2R1ac0cYaRu/vk9dVFkewHQhQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"character-entities": "^2.0.0",
|
||||
"character-entities-legacy": "^2.0.0",
|
||||
"character-reference-invalid": "^2.0.0",
|
||||
"is-alphanumerical": "^2.0.0",
|
||||
"is-decimal": "^2.0.0",
|
||||
"is-hexadecimal": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"parse-passwd": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
|
||||
@@ -3487,12 +3604,6 @@
|
||||
"find-up": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"popper.js": {
|
||||
"version": "1.16.1-lts",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz",
|
||||
"integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==",
|
||||
"dev": true
|
||||
},
|
||||
"posix-character-classes": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
|
||||
@@ -3507,14 +3618,6 @@
|
||||
"requires": {
|
||||
"lodash": "^4.17.20",
|
||||
"renderkid": "^2.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": {
|
||||
"version": "4.17.20",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"process": {
|
||||
@@ -3671,18 +3774,6 @@
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"dev": true
|
||||
},
|
||||
"react-transition-group": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
||||
"integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"dom-helpers": "^5.0.1",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
@@ -3777,12 +3868,6 @@
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.20",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
||||
"dev": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
@@ -4310,12 +4395,6 @@
|
||||
"integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=",
|
||||
"dev": true
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
|
||||
"dev": true
|
||||
},
|
||||
"tapable": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
|
||||
@@ -4385,12 +4464,6 @@
|
||||
"setimmediate": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
|
||||
"dev": true
|
||||
},
|
||||
"to-arraybuffer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
|
||||
@@ -4584,6 +4657,15 @@
|
||||
"imurmurhash": "^0.1.4"
|
||||
}
|
||||
},
|
||||
"unist-util-stringify-position": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.0.tgz",
|
||||
"integrity": "sha512-SdfAl8fsDclywZpfMDTVDxA2V7LjtRDTOFd44wUJamgl6OlVngsqWjxvermMYf60elWHbxhuRCZml7AnuXCaSA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/unist": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"unset-value": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
|
||||
@@ -4993,6 +5075,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"wc-react": {
|
||||
"version": "github:estruyf/wc-react#0989e37af55d3ee97392bf2747a818e4873243fa",
|
||||
"from": "github:estruyf/wc-react",
|
||||
"dev": true
|
||||
},
|
||||
"webpack": {
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz",
|
||||
|
||||
103
package.json
@@ -3,7 +3,7 @@
|
||||
"displayName": "Front Matter",
|
||||
"description": "Simplifies working with front matter of your articles. Useful extension when you are using a static site generator like: Hugo, Jekyll, Hexo, NextJs, Gatsby, and many more...",
|
||||
"icon": "assets/front-matter.png",
|
||||
"version": "1.17.0",
|
||||
"version": "2.2.0",
|
||||
"preview": false,
|
||||
"publisher": "eliostruyf",
|
||||
"galleryBanner": {
|
||||
@@ -15,6 +15,11 @@
|
||||
"description": "version",
|
||||
"url": "https://img.shields.io/github/package-json/v/estruyf/vscode-front-matter?color=green&label=vscode-front-matter&style=flat-square",
|
||||
"href": "https://github.com/estruyf/vscode-front-matter"
|
||||
},
|
||||
{
|
||||
"description": "Buy me a coffee",
|
||||
"url": "https://img.shields.io/badge/Buy%20me%20a%20coffee-€%203-blue?logo=buy-me-a-coffee&style=flat-square",
|
||||
"href": "https://www.buymeacoffee.com/zMeFRy9"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
@@ -48,6 +53,10 @@
|
||||
"onCommand:frontMatter.setLastModifiedDate",
|
||||
"onCommand:frontMatter.generateSlug",
|
||||
"onCommand:frontMatter.createFromTemplate",
|
||||
"onCommand:frontMatter.registerFolder",
|
||||
"onCommand:frontMatter.unregisterFolder",
|
||||
"onCommand:frontMatter.createContent",
|
||||
"onCommand:frontMatter.init",
|
||||
"onView:frontMatter.explorer"
|
||||
],
|
||||
"main": "./dist/extension",
|
||||
@@ -105,6 +114,11 @@
|
||||
"type": "string",
|
||||
"markdownDescription": "Specify a suffix for the slug"
|
||||
},
|
||||
"frontMatter.taxonomy.alignFilename": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"markdownDescription": "Align the filename with the new slug when it gets generated."
|
||||
},
|
||||
"frontMatter.taxonomy.indentArrays": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
@@ -137,6 +151,11 @@
|
||||
"default": 160,
|
||||
"description": "Specifies the optimal description length for SEO (set to `-1` to turn it off)."
|
||||
},
|
||||
"frontMatter.taxonomy.seoContentLengh": {
|
||||
"type": "number",
|
||||
"default": 1760,
|
||||
"description": "Specifies the optimal minimum length for your articles. Between 1,760 words – 2,400 is the absolute ideal article length for SEO in 2021. (set to `-1` to turn it off)."
|
||||
},
|
||||
"frontMatter.taxonomy.seoDescriptionField": {
|
||||
"type": "string",
|
||||
"default": "description",
|
||||
@@ -161,49 +180,84 @@
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"markdownDescription": "Specify the path to a Node.js script to execute. The current file path will be provided as an argument."
|
||||
},
|
||||
"frontMatter.content.folders": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"markdownDescription": "This array of folders defines where the extension can easily create new content by running the create article command."
|
||||
}
|
||||
}
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"command": "frontMatter.insertTags",
|
||||
"title": "Front Matter: Insert tags"
|
||||
"title": "Insert tags",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.insertCategories",
|
||||
"title": "Front Matter: Insert categories"
|
||||
"title": "Insert categories",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.createTag",
|
||||
"title": "Front Matter: Create tag"
|
||||
"title": "Create tag",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.createCategory",
|
||||
"title": "Front Matter: Create category"
|
||||
"title": "Create category",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.exportTaxonomy",
|
||||
"title": "Front Matter: Export all tags & categories to your settings"
|
||||
"title": "Export all tags & categories to your settings",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.remap",
|
||||
"title": "Front Matter: Remap or remove tag/category in all articles"
|
||||
"title": "Remap or remove tag/category in all articles",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.setDate",
|
||||
"title": "Front Matter: Set current date"
|
||||
"title": "Set current date",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.setLastModifiedDate",
|
||||
"title": "Front Matter: Set lastmod date"
|
||||
"title": "Set lastmod date",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.generateSlug",
|
||||
"title": "Front Matter: Generate slug based on article title"
|
||||
"title": "Generate slug based on article title",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.createFromTemplate",
|
||||
"title": "Front Matter: New article from template"
|
||||
"title": "New article from template",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.registerFolder",
|
||||
"title": "Register folder",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.unregisterFolder",
|
||||
"title": "Unregister folder",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.createContent",
|
||||
"title": "Create content",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.init",
|
||||
"title": "Initialize project",
|
||||
"category": "Front matter"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
@@ -212,6 +266,22 @@
|
||||
"command": "frontMatter.createFromTemplate",
|
||||
"when": "explorerResourceIsFolder",
|
||||
"group": "Front Matter@1"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.registerFolder",
|
||||
"when": "explorerResourceIsFolder",
|
||||
"group": "Front Matter@2"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.unregisterFolder",
|
||||
"when": "explorerResourceIsFolder && resourcePath in frontMatter.registeredFolders",
|
||||
"group": "Front Matter@3"
|
||||
}
|
||||
],
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "frontMatter.init",
|
||||
"when": "frontMatterCanInit"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -233,29 +303,34 @@
|
||||
"clean": "rm -rf dist"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@bendera/vscode-webview-elements": "0.6.2",
|
||||
"@iarna/toml": "2.2.3",
|
||||
"@material-ui/core": "4.11.1",
|
||||
"@material-ui/icons": "4.11.2",
|
||||
"@material-ui/lab": "4.0.0-alpha.56",
|
||||
"@types/glob": "7.1.3",
|
||||
"@types/js-yaml": "3.12.1",
|
||||
"@types/lodash.uniqby": "4.7.6",
|
||||
"@types/mocha": "^5.2.6",
|
||||
"@types/node": "10.17.48",
|
||||
"@types/react": "17.0.0",
|
||||
"@types/react-dom": "17.0.0",
|
||||
"@types/vscode": "1.51.0",
|
||||
"@vscode/codicons": "0.0.20",
|
||||
"date-fns": "2.0.1",
|
||||
"downshift": "6.0.6",
|
||||
"glob": "7.1.6",
|
||||
"gray-matter": "4.0.2",
|
||||
"html-loader": "1.3.2",
|
||||
"html-webpack-plugin": "4.5.0",
|
||||
"mdast-util-from-markdown": "1.0.0",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1",
|
||||
"ts-loader": "8.0.3",
|
||||
"tslint": "6.1.3",
|
||||
"typescript": "4.0.2",
|
||||
"wc-react": "github:estruyf/wc-react",
|
||||
"webpack": "4.44.2",
|
||||
"webpack-cli": "3.3.12"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash.uniqby": "4.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
10
sample/script-sample.js
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
const arguments = process.argv;
|
||||
|
||||
if (arguments && arguments.length > 0) {
|
||||
const workspaceArg = arguments[2]; // The workspace path
|
||||
const fileArg = arguments[3]; // The file path
|
||||
const frontMatterArg = arguments[4]; // Front matter data
|
||||
|
||||
console.log(`The content returned for your notification.`);
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
import { SETTING_MODIFIED_FIELD } from './../constants/settings';
|
||||
import { SETTING_MODIFIED_FIELD, SETTING_SLUG_UPDATE_FILE_NAME, SETTING_TEMPLATES_PREFIX } from './../constants/settings';
|
||||
import * as vscode from 'vscode';
|
||||
import { TaxonomyType } from "../models";
|
||||
import { CONFIG_KEY, SETTING_DATE_FORMAT, EXTENSION_NAME, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_DATE_FIELD } from "../constants/settings";
|
||||
import { CONFIG_KEY, SETTING_DATE_FORMAT, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_DATE_FIELD } from "../constants/settings";
|
||||
import { format } from "date-fns";
|
||||
import { ArticleHelper, SettingsHelper, SlugHelper } from '../helpers';
|
||||
import matter = require('gray-matter');
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
import { extname, basename } from 'path';
|
||||
|
||||
|
||||
export class Article {
|
||||
@@ -53,7 +55,7 @@ export class Article {
|
||||
}
|
||||
|
||||
if (options.length === 0) {
|
||||
vscode.window.showInformationMessage(`${EXTENSION_NAME}: No ${type === TaxonomyType.Tag ? "tags" : "categories"} configured.`);
|
||||
Notifications.info(`No ${type === TaxonomyType.Tag ? "tags" : "categories"} configured.`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -88,7 +90,7 @@ export class Article {
|
||||
try {
|
||||
ArticleHelper.update(editor, article);
|
||||
} catch (e) {
|
||||
vscode.window.showErrorMessage(`${EXTENSION_NAME}: Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`);
|
||||
Notifications.error(`Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`);
|
||||
console.log(e.message);
|
||||
}
|
||||
}
|
||||
@@ -101,14 +103,11 @@ export class Article {
|
||||
const config = vscode.workspace.getConfiguration(CONFIG_KEY);
|
||||
const dateFormat = config.get(SETTING_DATE_FORMAT) as string;
|
||||
const dateField = config.get(SETTING_DATE_FIELD) as string || "date";
|
||||
const modField = config.get(SETTING_MODIFIED_FIELD) as string || "date";
|
||||
|
||||
article = this.articleDate(article, dateFormat, dateField, forceCreate);
|
||||
article = this.articleDate(article, dateFormat, modField, false);
|
||||
|
||||
if (typeof article.data[dateField] !== "undefined" || forceCreate) {
|
||||
if (dateFormat && typeof dateFormat === "string") {
|
||||
article.data[dateField] = format(new Date(), dateFormat);
|
||||
} else {
|
||||
article.data[dateField] = new Date();
|
||||
}
|
||||
}
|
||||
return article;
|
||||
}
|
||||
|
||||
@@ -133,12 +132,12 @@ export class Article {
|
||||
if (dateFormat && typeof dateFormat === "string") {
|
||||
article.data[dateField] = format(new Date(), dateFormat);
|
||||
} else {
|
||||
article.data[dateField] = new Date();
|
||||
article.data[dateField] = new Date().toISOString();
|
||||
}
|
||||
|
||||
ArticleHelper.update(editor, article);
|
||||
} catch (e) {
|
||||
vscode.window.showErrorMessage(`${EXTENSION_NAME}: Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`);
|
||||
Notifications.error(`Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`);
|
||||
console.log(e.message);
|
||||
}
|
||||
}
|
||||
@@ -146,11 +145,14 @@ export class Article {
|
||||
/**
|
||||
* Generate the slug based on the article title
|
||||
*/
|
||||
public static generateSlug() {
|
||||
public static async generateSlug() {
|
||||
const config = vscode.workspace.getConfiguration(CONFIG_KEY);
|
||||
const prefix = config.get(SETTING_SLUG_PREFIX) as string;
|
||||
const suffix = config.get(SETTING_SLUG_SUFFIX) as string;
|
||||
const updateFileName = config.get(SETTING_SLUG_UPDATE_FILE_NAME) as string;
|
||||
const filePrefix = config.get<string>(SETTING_TEMPLATES_PREFIX);
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
@@ -161,10 +163,42 @@ export class Article {
|
||||
}
|
||||
|
||||
const articleTitle: string = article.data["title"];
|
||||
const slug = SlugHelper.createSlug(articleTitle);
|
||||
let slug = SlugHelper.createSlug(articleTitle);
|
||||
if (slug) {
|
||||
article.data["slug"] = `${prefix}${slug}${suffix}`;
|
||||
slug = `${prefix}${slug}${suffix}`;
|
||||
article.data["slug"] = slug;
|
||||
ArticleHelper.update(editor, article);
|
||||
|
||||
// Check if the file name should be updated by the slug
|
||||
// This is required for systems like Jekyll
|
||||
if (updateFileName) {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor) {
|
||||
const ext = extname(editor.document.fileName);
|
||||
const fileName = basename(editor.document.fileName);
|
||||
|
||||
let slugName = slug.startsWith("/") ? slug.substring(1) : slug;
|
||||
slugName = slugName.endsWith("/") ? slugName.substring(0, slugName.length - 1) : slugName;
|
||||
|
||||
let newFileName = `${slugName}${ext}`;
|
||||
if (filePrefix && typeof filePrefix === "string") {
|
||||
newFileName = `${format(new Date(), filePrefix)}-${newFileName}`;
|
||||
}
|
||||
|
||||
const newPath = editor.document.uri.fsPath.replace(fileName, newFileName);
|
||||
|
||||
try {
|
||||
await editor.document.save();
|
||||
|
||||
await vscode.workspace.fs.rename(editor.document.uri, vscode.Uri.file(newPath), {
|
||||
overwrite: false
|
||||
});
|
||||
} catch (e) {
|
||||
Notifications.error(`Failed to rename file.`);
|
||||
console.log(e?.message || e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,4 +219,22 @@ export class Article {
|
||||
article.data["draft"] = newDraftStatus;
|
||||
ArticleHelper.update(editor, article);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the article date and return it
|
||||
* @param article
|
||||
* @param dateFormat
|
||||
* @param field
|
||||
* @param forceCreate
|
||||
*/
|
||||
private static articleDate(article: matter.GrayMatterFile<string>, dateFormat: string, field: string, forceCreate: boolean) {
|
||||
if (typeof article.data[field] !== "undefined" || forceCreate) {
|
||||
if (dateFormat && typeof dateFormat === "string") {
|
||||
article.data[field] = format(new Date(), dateFormat);
|
||||
} else {
|
||||
article.data[field] = new Date().toISOString();
|
||||
}
|
||||
}
|
||||
return article;
|
||||
}
|
||||
}
|
||||
|
||||
167
src/commands/Folders.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import { commands, Uri, workspace, window } from "vscode";
|
||||
import { CONFIG_KEY, SETTINGS_CONTENT_FOLDERS } from "../constants";
|
||||
import { basename } from "path";
|
||||
import { ContentFolder, FolderInfo } from "../models";
|
||||
import uniqBy = require("lodash.uniqby");
|
||||
import { Template } from "./Template";
|
||||
import { Notifications } from "../helpers/Notifications";
|
||||
import { CONTEXT } from "../constants/context";
|
||||
|
||||
export class Folders {
|
||||
|
||||
/**
|
||||
* Create content in a registered folder
|
||||
* @returns
|
||||
*/
|
||||
public static async create() {
|
||||
const folders = Folders.get();
|
||||
|
||||
if (!folders || folders.length === 0) {
|
||||
Notifications.warning(`There are no known content locations defined in this project.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedFolder = await window.showQuickPick(folders.map(f => f.title), {
|
||||
placeHolder: `Select where you want to create your content`
|
||||
});
|
||||
|
||||
if (!selectedFolder) {
|
||||
Notifications.warning(`You didn't select a place where you wanted to create your content.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const location = folders.find(f => f.title === selectedFolder);
|
||||
if (location) {
|
||||
const folderPath = Folders.getFolderPath(Uri.file(location.fsPath));
|
||||
if (folderPath) {
|
||||
Template.create(folderPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the new folder path
|
||||
* @param folder
|
||||
*/
|
||||
public static async register(folder: Uri) {
|
||||
if (folder && folder.fsPath) {
|
||||
const wslPath = folder.fsPath.replace(/\//g, '\\');
|
||||
|
||||
let folders = Folders.get();
|
||||
|
||||
const exists = folders.find(f => f.paths.includes(folder.fsPath) || f.paths.includes(wslPath));
|
||||
|
||||
if (exists) {
|
||||
Notifications.warning(`Folder is already registered`);
|
||||
return;
|
||||
}
|
||||
|
||||
const folderName = await window.showInputBox({
|
||||
prompt: `Which name would you like to specify for this folder?`,
|
||||
placeHolder: `Folder name`,
|
||||
value: basename(folder.fsPath)
|
||||
});
|
||||
|
||||
folders.push({
|
||||
title: folderName,
|
||||
fsPath: folder.fsPath,
|
||||
paths: folder.fsPath === wslPath ? [folder.fsPath] : [folder.fsPath, wslPath]
|
||||
} as ContentFolder);
|
||||
|
||||
folders = uniqBy(folders, f => f.fsPath);
|
||||
await Folders.update(folders);
|
||||
|
||||
Notifications.info(`Folder registered`);
|
||||
}
|
||||
|
||||
Folders.updateVsCodeCtx();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a folder path
|
||||
* @param folder
|
||||
*/
|
||||
public static async unregister(folder: Uri) {
|
||||
if (folder && folder.path) {
|
||||
let folders = Folders.get();
|
||||
folders = folders.filter(f => f.fsPath !== folder.fsPath);
|
||||
await Folders.update(folders);
|
||||
}
|
||||
|
||||
Folders.updateVsCodeCtx();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the registered folders context
|
||||
*/
|
||||
public static updateVsCodeCtx() {
|
||||
const folders = Folders.get();
|
||||
let allFolders: string[] = [];
|
||||
for (const folder of folders) {
|
||||
allFolders = [...allFolders, ...folder.paths]
|
||||
}
|
||||
commands.executeCommand('setContext', CONTEXT.registeredFolders, allFolders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the folder path
|
||||
* @param folder
|
||||
* @returns
|
||||
*/
|
||||
public static getFolderPath(folder: Uri) {
|
||||
let folderPath = "";
|
||||
if (folder && folder.fsPath) {
|
||||
folderPath = folder.fsPath;
|
||||
} else if (workspace.workspaceFolders && workspace.workspaceFolders.length > 0) {
|
||||
folderPath = workspace.workspaceFolders[0].uri.fsPath;
|
||||
}
|
||||
return folderPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the registered folders information
|
||||
*/
|
||||
public static async getInfo(): Promise<FolderInfo[] | null> {
|
||||
const folders = Folders.get();
|
||||
if (folders && folders.length > 0) {
|
||||
let folderInfo: FolderInfo[] = [];
|
||||
|
||||
for (const folder of folders) {
|
||||
try {
|
||||
const files = await workspace.fs.readDirectory(Uri.file(folder.fsPath));
|
||||
if (files) {
|
||||
folderInfo.push({
|
||||
title: folder.title,
|
||||
files: files.length
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// Skip the current folder
|
||||
}
|
||||
}
|
||||
|
||||
return folderInfo;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the folder settings
|
||||
* @returns
|
||||
*/
|
||||
private static get() {
|
||||
const config = workspace.getConfiguration(CONFIG_KEY);
|
||||
const folders: ContentFolder[] = config.get(SETTINGS_CONTENT_FOLDERS) as ContentFolder[];
|
||||
return folders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the folder settings
|
||||
* @param folders
|
||||
*/
|
||||
private static async update(folders: ContentFolder[]) {
|
||||
const config = workspace.getConfiguration(CONFIG_KEY);
|
||||
await config.update(SETTINGS_CONTENT_FOLDERS, folders);
|
||||
}
|
||||
}
|
||||
49
src/commands/Project.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { workspace, Uri } from "vscode";
|
||||
import { CONFIG_KEY, SETTING_TEMPLATES_FOLDER } from "../constants";
|
||||
import { join } from "path";
|
||||
import * as fs from "fs";
|
||||
import { Notifications } from "../helpers/Notifications";
|
||||
|
||||
export class Project {
|
||||
|
||||
private static content = `---
|
||||
title: "{{name}}"
|
||||
slug: "/{{kebabCase name}}/"
|
||||
description:
|
||||
author:
|
||||
date: 2019-08-22T15:20:28.000Z
|
||||
lastmod: 2019-08-22T15:20:28.000Z
|
||||
draft: true
|
||||
tags: []
|
||||
categories: []
|
||||
---
|
||||
`;
|
||||
|
||||
/**
|
||||
* Initialize a new "Project" instance.
|
||||
*/
|
||||
public static async init() {
|
||||
try {
|
||||
const config = workspace.getConfiguration(CONFIG_KEY);
|
||||
const folder = config.get<string>(SETTING_TEMPLATES_FOLDER);
|
||||
|
||||
const workspaceFolders = workspace.workspaceFolders;
|
||||
|
||||
if (!folder || !workspaceFolders || workspaceFolders.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const workspaceFolder = workspaceFolders[0];
|
||||
const templatePath = Uri.file(join(workspaceFolder.uri.fsPath, folder));
|
||||
const article = Uri.file(join(templatePath.fsPath, "article.md"));
|
||||
|
||||
await workspace.fs.createDirectory(templatePath);
|
||||
|
||||
fs.writeFileSync(article.fsPath, Project.content, { encoding: "utf-8" });
|
||||
|
||||
Notifications.info("Project initialized successfully.");
|
||||
} catch (err) {
|
||||
Notifications.error(`Sorry, something went wrong - ${err?.message || err}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { CONFIG_KEY, SETTING_TAXONOMY_TAGS, SETTING_TAXONOMY_CATEGORIES, EXTENSI
|
||||
import { ArticleHelper, SettingsHelper, FilesHelper } from '../helpers';
|
||||
import { TomlEngine, getFmLanguage, getFormatOpts } from '../helpers/TomlEngine';
|
||||
import { DumpOptions } from 'js-yaml';
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
|
||||
export class Settings {
|
||||
|
||||
@@ -29,7 +30,7 @@ export class Settings {
|
||||
}
|
||||
|
||||
if (options.find(o => o === newOption)) {
|
||||
vscode.window.showInformationMessage(`${EXTENSION_NAME}: The provided ${type === TaxonomyType.Tag ? "tag" : "category"} already exists.`);
|
||||
Notifications.info(`The provided ${type === TaxonomyType.Tag ? "tag" : "category"} already exists.`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -145,7 +146,7 @@ export class Settings {
|
||||
await config.update(SETTING_TAXONOMY_CATEGORIES, crntCategories);
|
||||
|
||||
// Done
|
||||
vscode.window.showInformationMessage(`${EXTENSION_NAME}: Export completed. Tags: ${crntTags.length} - Categories: ${crntCategories.length}.`);
|
||||
Notifications.info(`Export completed. Tags: ${crntTags.length} - Categories: ${crntCategories.length}.`);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -171,7 +172,7 @@ export class Settings {
|
||||
let options = SettingsHelper.getTaxonomy(type);
|
||||
|
||||
if (!options || options.length === 0) {
|
||||
vscode.window.showInformationMessage(`${EXTENSION_NAME}: No ${type === TaxonomyType.Tag ? "tags" : "categories"} configured.`);
|
||||
Notifications.info(`No ${type === TaxonomyType.Tag ? "tags" : "categories"} configured.`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -273,7 +274,7 @@ export class Settings {
|
||||
}
|
||||
await SettingsHelper.update(type, options);
|
||||
|
||||
vscode.window.showInformationMessage(`${EXTENSION_NAME}: ${newOptionValue ? "Remapping" : "Deleation"} of the ${selectedOption} ${type === TaxonomyType.Tag ? "tag" : "category"} completed.`);
|
||||
Notifications.info(`${newOptionValue ? "Remapping" : "Deleation"} of the ${selectedOption} ${type === TaxonomyType.Tag ? "tag" : "category"} completed.`);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export class StatusListener {
|
||||
const publishMsg = "to publish";
|
||||
|
||||
let editor = vscode.window.activeTextEditor;
|
||||
if (editor && editor.document && editor.document.languageId.toLowerCase() === "markdown") {
|
||||
if (editor && ArticleHelper.isMarkdownDile()) {
|
||||
try {
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
|
||||
|
||||
@@ -1,14 +1,47 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { CONFIG_KEY, EXTENSION_NAME, SETTING_TEMPLATES_FOLDER, SETTING_TEMPLATES_PREFIX } from '../constants';
|
||||
import { CONFIG_KEY, SETTING_TEMPLATES_FOLDER, SETTING_TEMPLATES_PREFIX } from '../constants';
|
||||
import { format } from 'date-fns';
|
||||
import sanitize from '../helpers/Sanitize';
|
||||
import { ArticleHelper } from '../helpers';
|
||||
import { Article } from '.';
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
import { CONTEXT } from '../constants/context';
|
||||
|
||||
export class Template {
|
||||
|
||||
/**
|
||||
* Check if the template folder is available
|
||||
*/
|
||||
public static async init() {
|
||||
const isInitialized = await Template.isInitialized();
|
||||
await vscode.commands.executeCommand('setContext', CONTEXT.canInit, !isInitialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the project is already initialized
|
||||
*/
|
||||
public static async isInitialized() {
|
||||
const config = vscode.workspace.getConfiguration(CONFIG_KEY);
|
||||
const folder = config.get<string>(SETTING_TEMPLATES_FOLDER);
|
||||
const workspaceFolders = vscode.workspace.workspaceFolders;
|
||||
|
||||
if (!folder || !workspaceFolders || workspaceFolders.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const workspaceFolder = workspaceFolders[0];
|
||||
const templatePath = vscode.Uri.file(path.join(workspaceFolder.uri.fsPath, folder));
|
||||
|
||||
try {
|
||||
await vscode.workspace.fs.stat(templatePath);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from a template
|
||||
*/
|
||||
@@ -18,18 +51,18 @@ export class Template {
|
||||
const prefix = config.get<string>(SETTING_TEMPLATES_PREFIX);
|
||||
|
||||
if (!folderPath) {
|
||||
this.showNoTemplates(`Incorrect project folder path retrieved.`);
|
||||
Notifications.warning(`Incorrect project folder path retrieved.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!folder) {
|
||||
this.showNoTemplates(`No templates found.`);
|
||||
Notifications.warning(`No templates found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const templates = await vscode.workspace.findFiles(`${folder}/**/*`, "**/node_modules/**,**/archetypes/**");
|
||||
if (!templates || templates.length === 0) {
|
||||
this.showNoTemplates(`No templates found.`);
|
||||
Notifications.warning(`No templates found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -37,7 +70,7 @@ export class Template {
|
||||
placeHolder: `Select the article template to use`
|
||||
});
|
||||
if (!selectedTemplate) {
|
||||
this.showNoTemplates(`No template selected.`);
|
||||
Notifications.warning(`No template selected.`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -46,14 +79,14 @@ export class Template {
|
||||
placeHolder: `Article title`
|
||||
});
|
||||
if (!titleValue) {
|
||||
this.showNoTemplates(`You did not specify an article title.`);
|
||||
Notifications.warning(`You did not specify an article title.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start the template read
|
||||
const template = templates.find(t => t.fsPath.endsWith(selectedTemplate));
|
||||
if (!template) {
|
||||
this.showNoTemplates(`Article template could not be found.`);
|
||||
Notifications.warning(`Article template could not be found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -66,7 +99,7 @@ export class Template {
|
||||
|
||||
const newFilePath = path.join(folderPath, newFileName);
|
||||
if (fs.existsSync(newFilePath)) {
|
||||
this.showNoTemplates(`File already exists, please remove it before creating a new one with the same title.`);
|
||||
Notifications.warning(`File already exists, please remove it before creating a new one with the same title.`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -76,7 +109,7 @@ export class Template {
|
||||
// Update the properties inside the template
|
||||
let frontMatter = ArticleHelper.getFrontMatterByPath(newFilePath);
|
||||
if (!frontMatter) {
|
||||
this.showNoTemplates(`Something failed when retrieving the newly created file.`);
|
||||
Notifications.warning(`Something failed when retrieving the newly created file.`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -101,13 +134,6 @@ export class Template {
|
||||
vscode.window.showTextDocument(txtDoc);
|
||||
}
|
||||
|
||||
vscode.window.showInformationMessage(`${EXTENSION_NAME}: Your new article has been created.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a warning message when no templates are found
|
||||
*/
|
||||
private static showNoTemplates(value: string) {
|
||||
vscode.window.showWarningMessage(`${EXTENSION_NAME}: ${value}`);
|
||||
Notifications.info(`Your new article has been created.`);
|
||||
}
|
||||
}
|
||||
23
src/constants/Extension.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
const extensionName = "frontMatter";
|
||||
|
||||
export const getCommandName = (command: string) => {
|
||||
return `${extensionName}.${command}`;
|
||||
};
|
||||
|
||||
export const COMMAND_NAME = {
|
||||
init: getCommandName("init"),
|
||||
insertTags: getCommandName("insertTags"),
|
||||
insertCategories: getCommandName("insertCategories"),
|
||||
createTag: getCommandName("createTag"),
|
||||
createCategory: getCommandName("createCategory"),
|
||||
exportTaxonomy: getCommandName("exportTaxonomy"),
|
||||
remap: getCommandName("remap"),
|
||||
setDate: getCommandName("setDate"),
|
||||
setLastModifiedDate: getCommandName("setLastModifiedDate"),
|
||||
generateSlug: getCommandName("generateSlug"),
|
||||
createFromTemplate: getCommandName("createFromTemplate"),
|
||||
toggleDraft: getCommandName("toggleDraft"),
|
||||
registerFolder: getCommandName("registerFolder"),
|
||||
unregisterFolder: getCommandName("unregisterFolder"),
|
||||
createContent: getCommandName("createContent")
|
||||
};
|
||||
6
src/constants/context.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
export const CONTEXT = {
|
||||
canInit: "frontMatterCanInit",
|
||||
registeredFolders: 'frontMatter.registeredFolders'
|
||||
};
|
||||
@@ -10,6 +10,7 @@ export const SETTING_MODIFIED_FIELD = "taxonomy.modifiedField";
|
||||
|
||||
export const SETTING_SLUG_PREFIX = "taxonomy.slugPrefix";
|
||||
export const SETTING_SLUG_SUFFIX = "taxonomy.slugSuffix";
|
||||
export const SETTING_SLUG_UPDATE_FILE_NAME = "taxonomy.alignFilename";
|
||||
|
||||
export const SETTING_INDENT_ARRAY = "taxonomy.indentArrays";
|
||||
export const SETTING_REMOVE_QUOTES = "taxonomy.noPropertyValueQuotes";
|
||||
@@ -18,6 +19,7 @@ export const SETTING_FRONTMATTER_TYPE = "taxonomy.frontMatterType";
|
||||
|
||||
export const SETTING_SEO_TITLE_LENGTH = "taxonomy.seoTitleLength";
|
||||
export const SETTING_SEO_DESCRIPTION_LENGTH = "taxonomy.seoDescriptionLength";
|
||||
export const SETTING_SEO_CONTENT_MIN_LENGTH = "taxonomy.seoContentLengh";
|
||||
export const SETTING_SEO_DESCRIPTION_FIELD = "taxonomy.seoDescriptionField";
|
||||
|
||||
export const SETTING_TEMPLATES_FOLDER = "templates.folder";
|
||||
@@ -25,4 +27,6 @@ export const SETTING_TEMPLATES_PREFIX = "templates.prefix";
|
||||
|
||||
export const SETTING_PANEL_FREEFORM = "panel.freeform";
|
||||
|
||||
export const SETTING_CUSTOM_SCRIPTS = "custom.scripts";
|
||||
export const SETTING_CUSTOM_SCRIPTS = "custom.scripts";
|
||||
|
||||
export const SETTINGS_CONTENT_FOLDERS = "content.folders";
|
||||
@@ -1,6 +1,9 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { Article, Settings, StatusListener } from './commands';
|
||||
import { Folders } from './commands/Folders';
|
||||
import { Project } from './commands/Project';
|
||||
import { Template } from './commands/Template';
|
||||
import { COMMAND_NAME } from './constants/Extension';
|
||||
import { TaxonomyType } from './models';
|
||||
import { TagType } from './viewpanel/TagType';
|
||||
import { ExplorerView } from './webview/ExplorerView';
|
||||
@@ -9,7 +12,7 @@ let frontMatterStatusBar: vscode.StatusBarItem;
|
||||
let debouncer: { (fnc: any, time: number): void; };
|
||||
let collection: vscode.DiagnosticCollection;
|
||||
|
||||
export function activate({ subscriptions, extensionUri }: vscode.ExtensionContext) {
|
||||
export async function activate({ subscriptions, extensionUri }: vscode.ExtensionContext) {
|
||||
collection = vscode.languages.createDiagnosticCollection('frontMatter');
|
||||
|
||||
const explorerSidebar = ExplorerView.getInstance(extensionUri);
|
||||
@@ -19,62 +22,78 @@ export function activate({ subscriptions, extensionUri }: vscode.ExtensionContex
|
||||
}
|
||||
});
|
||||
|
||||
let insertTags = vscode.commands.registerCommand('frontMatter.insertTags', async () => {
|
||||
let insertTags = vscode.commands.registerCommand(COMMAND_NAME.insertTags, async () => {
|
||||
await vscode.commands.executeCommand('workbench.view.extension.frontmatter-explorer');
|
||||
await vscode.commands.executeCommand('workbench.action.focusSideBar');
|
||||
explorerSidebar.triggerInputFocus(TagType.tags);
|
||||
});
|
||||
|
||||
let insertCategories = vscode.commands.registerCommand('frontMatter.insertCategories', async () => {
|
||||
let insertCategories = vscode.commands.registerCommand(COMMAND_NAME.insertCategories, async () => {
|
||||
await vscode.commands.executeCommand('workbench.view.extension.frontmatter-explorer');
|
||||
await vscode.commands.executeCommand('workbench.action.focusSideBar');
|
||||
explorerSidebar.triggerInputFocus(TagType.categories);
|
||||
});
|
||||
|
||||
let createTag = vscode.commands.registerCommand('frontMatter.createTag', () => {
|
||||
let createTag = vscode.commands.registerCommand(COMMAND_NAME.createTag, () => {
|
||||
Settings.create(TaxonomyType.Tag);
|
||||
});
|
||||
|
||||
let createCategory = vscode.commands.registerCommand('frontMatter.createCategory', () => {
|
||||
let createCategory = vscode.commands.registerCommand(COMMAND_NAME.createCategory, () => {
|
||||
Settings.create(TaxonomyType.Category);
|
||||
});
|
||||
|
||||
let exportTaxonomy = vscode.commands.registerCommand('frontMatter.exportTaxonomy', () => {
|
||||
let exportTaxonomy = vscode.commands.registerCommand(COMMAND_NAME.exportTaxonomy, () => {
|
||||
Settings.export();
|
||||
});
|
||||
|
||||
let remap = vscode.commands.registerCommand('frontMatter.remap', () => {
|
||||
let remap = vscode.commands.registerCommand(COMMAND_NAME.remap, () => {
|
||||
Settings.remap();
|
||||
});
|
||||
|
||||
let setDate = vscode.commands.registerCommand('frontMatter.setDate', () => {
|
||||
let setDate = vscode.commands.registerCommand(COMMAND_NAME.setDate, () => {
|
||||
Article.setDate();
|
||||
});
|
||||
|
||||
let setLastModifiedDate = vscode.commands.registerCommand('frontMatter.setLastModifiedDate', () => {
|
||||
let setLastModifiedDate = vscode.commands.registerCommand(COMMAND_NAME.setLastModifiedDate, () => {
|
||||
Article.setLastModifiedDate();
|
||||
});
|
||||
|
||||
let generateSlug = vscode.commands.registerCommand('frontMatter.generateSlug', () => {
|
||||
let generateSlug = vscode.commands.registerCommand(COMMAND_NAME.generateSlug, () => {
|
||||
Article.generateSlug();
|
||||
});
|
||||
|
||||
let createFromTemplate = vscode.commands.registerCommand('frontMatter.createFromTemplate', (e: vscode.Uri) => {
|
||||
let folderPath = "";
|
||||
if (e && e.fsPath) {
|
||||
folderPath = e.fsPath;
|
||||
} else if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
|
||||
folderPath = vscode.workspace.workspaceFolders[0].uri.fsPath;
|
||||
}
|
||||
Template.create(folderPath);
|
||||
let createFromTemplate = vscode.commands.registerCommand(COMMAND_NAME.createFromTemplate, (folder: vscode.Uri) => {
|
||||
const folderPath = Folders.getFolderPath(folder);
|
||||
if (folderPath) {
|
||||
Template.create(folderPath);
|
||||
}
|
||||
});
|
||||
|
||||
const toggleDraftCommand = 'frontMatter.toggleDraft';
|
||||
const toggleDraftCommand = COMMAND_NAME.toggleDraft;
|
||||
const toggleDraft = vscode.commands.registerCommand(toggleDraftCommand, async () => {
|
||||
await Article.toggleDraft();
|
||||
triggerShowDraftStatus();
|
||||
});
|
||||
|
||||
// Register project folders
|
||||
const registerFolder = vscode.commands.registerCommand(COMMAND_NAME.registerFolder, Folders.register);
|
||||
|
||||
const unregisterFolder = vscode.commands.registerCommand(COMMAND_NAME.unregisterFolder, Folders.unregister);
|
||||
|
||||
const createContent = vscode.commands.registerCommand(COMMAND_NAME.createContent, Folders.create);
|
||||
|
||||
Folders.updateVsCodeCtx();
|
||||
|
||||
// Initialize command
|
||||
Template.init();
|
||||
const projectInit = vscode.commands.registerCommand(COMMAND_NAME.init, Project.init);
|
||||
|
||||
// Things to do when configuration changes
|
||||
vscode.workspace.onDidChangeConfiguration(() => {
|
||||
Template.init();
|
||||
Folders.updateVsCodeCtx();
|
||||
});
|
||||
|
||||
// Create the status bar
|
||||
frontMatterStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100);
|
||||
frontMatterStatusBar.command = toggleDraftCommand;
|
||||
@@ -87,18 +106,24 @@ export function activate({ subscriptions, extensionUri }: vscode.ExtensionContex
|
||||
triggerShowDraftStatus();
|
||||
|
||||
// Subscribe all commands
|
||||
subscriptions.push(insertTags);
|
||||
subscriptions.push(explorerView);
|
||||
subscriptions.push(insertCategories);
|
||||
subscriptions.push(createTag);
|
||||
subscriptions.push(createCategory);
|
||||
subscriptions.push(exportTaxonomy);
|
||||
subscriptions.push(remap);
|
||||
subscriptions.push(setDate);
|
||||
subscriptions.push(setLastModifiedDate);
|
||||
subscriptions.push(generateSlug);
|
||||
subscriptions.push(createFromTemplate);
|
||||
subscriptions.push(toggleDraft);
|
||||
subscriptions.push(
|
||||
insertTags,
|
||||
explorerView,
|
||||
insertCategories,
|
||||
createTag,
|
||||
createCategory,
|
||||
exportTaxonomy,
|
||||
remap,
|
||||
setDate,
|
||||
setLastModifiedDate,
|
||||
generateSlug,
|
||||
createFromTemplate,
|
||||
toggleDraft,
|
||||
registerFolder,
|
||||
unregisterFolder,
|
||||
createContent,
|
||||
projectInit
|
||||
);
|
||||
}
|
||||
|
||||
export function deactivate() {}
|
||||
@@ -113,6 +138,6 @@ const debounceShowDraftTrigger = () => {
|
||||
return (fnc: any, time: number) => {
|
||||
const functionCall = (...args: any[]) => fnc.apply(args);
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(functionCall, time);
|
||||
timeout = setTimeout(functionCall, time) as any;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -96,4 +96,12 @@ export class ArticleHelper {
|
||||
indent: spaces || 2
|
||||
} as DumpOptions as any));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current file is a markdown file
|
||||
*/
|
||||
public static isMarkdownDile() {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
return (editor && editor.document && (editor.document.languageId.toLowerCase() === "markdown" || editor.document.languageId.toLowerCase() === "mdx"));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { EXTENSION_NAME } from '../constants';
|
||||
import { Notifications } from './Notifications';
|
||||
|
||||
export class FilesHelper {
|
||||
|
||||
@@ -9,12 +10,13 @@ export class FilesHelper {
|
||||
public static async getMdFiles(): Promise<vscode.Uri[] | null> {
|
||||
const mdFiles = await vscode.workspace.findFiles('**/*.md', "**/node_modules/**,**/archetypes/**");
|
||||
const markdownFiles = await vscode.workspace.findFiles('**/*.markdown', "**/node_modules/**,**/archetypes/**");
|
||||
const mdxFiles = await vscode.workspace.findFiles('**/*.mdx', "**/node_modules/**,**/archetypes/**");
|
||||
if (!mdFiles && !markdownFiles) {
|
||||
vscode.window.showInformationMessage(`${EXTENSION_NAME}: No MD files found.`);
|
||||
Notifications.info(`No MD files found.`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const allMdFiles = mdFiles.concat(markdownFiles);
|
||||
const allMdFiles = [...mdFiles, ...markdownFiles, ...mdxFiles];
|
||||
return allMdFiles;
|
||||
}
|
||||
}
|
||||
18
src/helpers/Notifications.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { window } from "vscode";
|
||||
import { EXTENSION_NAME } from "../constants";
|
||||
|
||||
|
||||
export class Notifications {
|
||||
|
||||
public static info(message: string) {
|
||||
window.showInformationMessage(`${EXTENSION_NAME}: ${message}`);
|
||||
}
|
||||
|
||||
public static warning(message: string) {
|
||||
window.showWarningMessage(`${EXTENSION_NAME}: ${message}`);
|
||||
}
|
||||
|
||||
public static error(message: string) {
|
||||
window.showErrorMessage(`${EXTENSION_NAME}: ${message}`);
|
||||
}
|
||||
}
|
||||
5
src/models/ContentFolder.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface ContentFolder {
|
||||
title: string;
|
||||
fsPath: string;
|
||||
paths: string[];
|
||||
}
|
||||
@@ -6,11 +6,14 @@ export interface PanelSettings {
|
||||
categories: string[];
|
||||
freeform: boolean;
|
||||
scripts: CustomScript[];
|
||||
isInitialized: boolean;
|
||||
contentInfo: FolderInfo[] | null;
|
||||
}
|
||||
|
||||
export interface SEO {
|
||||
title: number;
|
||||
description: number;
|
||||
content: number;
|
||||
descriptionField: string;
|
||||
}
|
||||
|
||||
@@ -19,6 +22,11 @@ export interface Slug {
|
||||
suffix: number;
|
||||
}
|
||||
|
||||
export interface FolderInfo {
|
||||
title: string;
|
||||
files: number;
|
||||
}
|
||||
|
||||
export interface CustomScript {
|
||||
title: string;
|
||||
script: string;
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
export * from './ContentFolder';
|
||||
export * from './PanelSettings';
|
||||
export * from './TaxonomyType';
|
||||
|
||||
@@ -6,10 +6,13 @@ export enum CommandToCode {
|
||||
publish = 'publish',
|
||||
updateTags = "update-tags",
|
||||
updateCategories = "update-categories",
|
||||
updateKeywords = "update-keywords",
|
||||
addTagToSettings = "add-tag",
|
||||
addCategoryToSettings = "add-category",
|
||||
openSettings = "open-settings",
|
||||
openFile = "open-file",
|
||||
openProject = "open-project",
|
||||
runCustomScript = "custom-script"
|
||||
runCustomScript = "custom-script",
|
||||
initProject = "init-project",
|
||||
createContent = "create-content",
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export enum TagType {
|
||||
tags = "Tags",
|
||||
categories = "Categories"
|
||||
categories = "Categories",
|
||||
keywords = "Keywords"
|
||||
}
|
||||
@@ -1,6 +1,15 @@
|
||||
import * as React from 'react';
|
||||
import { CommandToCode } from './CommandToCode';
|
||||
import { Actions } from './components/Actions';
|
||||
import { BaseView } from './components/BaseView';
|
||||
import { Collapsible } from './components/Collapsible';
|
||||
import { BugIcon } from './components/Icons/BugIcon';
|
||||
import { FileIcon } from './components/Icons/FileIcon';
|
||||
import { FolderOpenedIcon } from './components/Icons/FolderOpenedIcon';
|
||||
import { ListUnorderedIcon } from './components/Icons/ListUnorderedIcon';
|
||||
import { SettingsIcon } from './components/Icons/SettingsIcon';
|
||||
import { SymbolKeywordIcon } from './components/Icons/SymbolKeywordIcon';
|
||||
import { TagIcon } from './components/Icons/TagIcon';
|
||||
import { SeoStatus } from './components/SeoStatus';
|
||||
import { Spinner } from './components/Spinner';
|
||||
import { TagPicker } from './components/TagPicker';
|
||||
@@ -22,9 +31,7 @@ export const ViewPanel: React.FunctionComponent<IViewPanelProps> = (props: React
|
||||
|
||||
if (!metadata || Object.keys(metadata).length === 0) {
|
||||
return (
|
||||
<div className="frontmatter">
|
||||
<p>Current view/file is not supported by FrontMatter.</p>
|
||||
</div>
|
||||
<BaseView settings={settings} />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -42,48 +49,66 @@ export const ViewPanel: React.FunctionComponent<IViewPanelProps> = (props: React
|
||||
|
||||
return (
|
||||
<div className="frontmatter">
|
||||
{
|
||||
settings && settings.seo && <SeoStatus seo={settings.seo} data={metadata} />
|
||||
}
|
||||
{
|
||||
settings && metadata && <Actions metadata={metadata} settings={settings} />
|
||||
}
|
||||
<div className={`ext_actions`}>
|
||||
{
|
||||
settings && settings.seo && <SeoStatus seo={settings.seo} data={metadata} />
|
||||
}
|
||||
{
|
||||
settings && metadata && <Actions metadata={metadata} settings={settings} />
|
||||
}
|
||||
|
||||
{
|
||||
(settings && settings.tags && settings.tags.length > 0) && (
|
||||
<TagPicker type={TagType.tags}
|
||||
crntSelected={metadata.tags || []}
|
||||
options={settings.tags}
|
||||
freeform={settings.freeform}
|
||||
focussed={focusElm === TagType.tags}
|
||||
unsetFocus={unsetFocus} />
|
||||
)
|
||||
}
|
||||
{
|
||||
(settings && settings.categories && settings.categories.length > 0) && (
|
||||
<TagPicker type={TagType.categories}
|
||||
crntSelected={metadata.categories || []}
|
||||
options={settings.categories}
|
||||
freeform={settings.freeform}
|
||||
focussed={focusElm === TagType.categories}
|
||||
unsetFocus={unsetFocus} />
|
||||
)
|
||||
}
|
||||
|
||||
<div className="ext_link_block">
|
||||
<a href="javascript:;" onClick={openSettings}>Open settings</a>
|
||||
<Collapsible title="Metadata" className={`absolute w-full`}>
|
||||
{
|
||||
<TagPicker type={TagType.keywords}
|
||||
icon={<SymbolKeywordIcon />}
|
||||
crntSelected={metadata.keywords || []}
|
||||
options={[]}
|
||||
freeform={true}
|
||||
focussed={focusElm === TagType.keywords}
|
||||
unsetFocus={unsetFocus}
|
||||
disableConfigurable />
|
||||
}
|
||||
{
|
||||
(settings && settings.tags && settings.tags.length > 0) && (
|
||||
<TagPicker type={TagType.tags}
|
||||
icon={<TagIcon />}
|
||||
crntSelected={metadata.tags || []}
|
||||
options={settings.tags}
|
||||
freeform={settings.freeform}
|
||||
focussed={focusElm === TagType.tags}
|
||||
unsetFocus={unsetFocus} />
|
||||
)
|
||||
}
|
||||
{
|
||||
(settings && settings.categories && settings.categories.length > 0) && (
|
||||
<TagPicker type={TagType.categories}
|
||||
icon={<ListUnorderedIcon />}
|
||||
crntSelected={metadata.categories || []}
|
||||
options={settings.categories}
|
||||
freeform={settings.freeform}
|
||||
focussed={focusElm === TagType.categories}
|
||||
unsetFocus={unsetFocus} />
|
||||
)
|
||||
}
|
||||
</Collapsible>
|
||||
</div>
|
||||
|
||||
<div className="ext_link_block">
|
||||
<a href="javascript:;" onClick={openFile}>Reveal file in folder</a>
|
||||
</div>
|
||||
<div className={`ext_settings`}>
|
||||
<div className="ext_link_block">
|
||||
<button onClick={openSettings}><SettingsIcon /> Open settings</button>
|
||||
</div>
|
||||
|
||||
<div className="ext_link_block">
|
||||
<a href="javascript:;" onClick={openProject}>Reveal project folder</a>
|
||||
</div>
|
||||
<div className="ext_link_block">
|
||||
<button onClick={openFile}><FileIcon /> Reveal file in folder</button>
|
||||
</div>
|
||||
|
||||
<div className="ext_link_block">
|
||||
<a href="https://github.com/estruyf/vscode-front-matter/issues" title="Open an issue on GitHub">Report an issue</a>
|
||||
<div className="ext_link_block">
|
||||
<button onClick={openProject}><FolderOpenedIcon /> Reveal project folder</button>
|
||||
</div>
|
||||
|
||||
<div className="ext_link_block">
|
||||
<a href="https://github.com/estruyf/vscode-front-matter/issues" title="Open an issue on GitHub"><BugIcon /> Report an issue</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { PanelSettings } from '../../models/PanelSettings';
|
||||
import { Collapsible } from './Collapsible';
|
||||
import { CustomScript } from './CustomScript';
|
||||
import { DateAction } from './DateAction';
|
||||
import { PublishAction } from './PublishAction';
|
||||
@@ -18,22 +19,22 @@ export const Actions: React.FunctionComponent<IActionsProps> = (props: React.Pro
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`article__actions`}>
|
||||
<h3>Actions</h3>
|
||||
<Collapsible title="Actions">
|
||||
<div className={`article__actions`}>
|
||||
{ metadata && metadata.title && <SlugAction value={metadata.title} crntValue={metadata.slug} slugOpts={settings.slug} /> }
|
||||
|
||||
{ metadata && metadata.title && <SlugAction value={metadata.title} crntValue={metadata.slug} slugOpts={settings.slug} /> }
|
||||
|
||||
<DateAction />
|
||||
<DateAction />
|
||||
|
||||
{ metadata && typeof metadata.draft !== undefined && <PublishAction draft={metadata.draft} />}
|
||||
{ metadata && typeof metadata.draft !== undefined && <PublishAction draft={metadata.draft} />}
|
||||
|
||||
{
|
||||
(settings && settings.scripts && settings.scripts.length > 0) && (
|
||||
settings.scripts.map((value) => (
|
||||
<CustomScript {...value} />
|
||||
))
|
||||
)
|
||||
}
|
||||
</div>
|
||||
{
|
||||
(settings && settings.scripts && settings.scripts.length > 0) && (
|
||||
settings.scripts.map((value) => (
|
||||
<CustomScript key={value.title.replace(/ /g, '')} {...value} />
|
||||
))
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
49
src/viewpanel/components/ArticleDetails.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import * as React from 'react';
|
||||
import { VsTable, VsTableBody, VsTableHeader, VsTableHeaderCell, VsTableRow, VsTableCell } from './VscodeComponents';
|
||||
|
||||
export interface IArticleDetailsProps {
|
||||
details: {
|
||||
headings: number;
|
||||
paragraphs: number;
|
||||
wordCount: number;
|
||||
}
|
||||
}
|
||||
|
||||
export const ArticleDetails: React.FunctionComponent<IArticleDetailsProps> = ({details}: React.PropsWithChildren<IArticleDetailsProps>) => {
|
||||
|
||||
if (!details || (details.headings === undefined && details.paragraphs === undefined)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`seo__status__details valid`}>
|
||||
<h4>More details</h4>
|
||||
|
||||
<VsTable bordered>
|
||||
<VsTableHeader slot="header">
|
||||
<VsTableHeaderCell>Type</VsTableHeaderCell>
|
||||
<VsTableHeaderCell>Total</VsTableHeaderCell>
|
||||
</VsTableHeader>
|
||||
<VsTableBody slot="body">
|
||||
{
|
||||
details?.headings !== undefined && (
|
||||
<VsTableRow>
|
||||
<VsTableCell>Headings</VsTableCell>
|
||||
<VsTableCell>{details.headings}</VsTableCell>
|
||||
</VsTableRow>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
details?.paragraphs !== undefined && (
|
||||
<VsTableRow>
|
||||
<VsTableCell>Paragraphs</VsTableCell>
|
||||
<VsTableCell>{details.paragraphs}</VsTableCell>
|
||||
</VsTableRow>
|
||||
)
|
||||
}
|
||||
</VsTableBody>
|
||||
</VsTable>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
49
src/viewpanel/components/BaseView.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import * as React from 'react';
|
||||
import { PanelSettings } from '../../models';
|
||||
import { CommandToCode } from '../CommandToCode';
|
||||
import { MessageHelper } from '../helper/MessageHelper';
|
||||
import { Collapsible } from './Collapsible';
|
||||
|
||||
export interface IBaseViewProps {
|
||||
settings: PanelSettings | undefined;
|
||||
}
|
||||
|
||||
export const BaseView: React.FunctionComponent<IBaseViewProps> = ({settings}: React.PropsWithChildren<IBaseViewProps>) => {
|
||||
|
||||
const initProject = () => {
|
||||
MessageHelper.sendMessage(CommandToCode.initProject);
|
||||
};
|
||||
|
||||
const createContent = () => {
|
||||
MessageHelper.sendMessage(CommandToCode.createContent);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="frontmatter">
|
||||
<div className={`ext_actions`}>
|
||||
<Collapsible title="Actions">
|
||||
<div className={`base__actions`}>
|
||||
<button onClick={initProject} disabled={settings?.isInitialized}>Initialize project</button>
|
||||
<button onClick={createContent} disabled={!settings?.isInitialized}>Create new content</button>
|
||||
</div>
|
||||
</Collapsible>
|
||||
|
||||
{
|
||||
settings?.contentInfo && (
|
||||
<Collapsible title="Content information">
|
||||
<div className="base__information">
|
||||
{
|
||||
settings.contentInfo.map(folder => (
|
||||
<div key={folder.title}>
|
||||
{folder.title}: {folder.files} file{folder.files > 1 ? 's' : ''}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Collapsible>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
32
src/viewpanel/components/Collapsible.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import * as React from 'react';
|
||||
import { VsCollapsible } from './VscodeComponents';
|
||||
|
||||
export interface ICollapsibleProps {
|
||||
title: string;
|
||||
className?: string;
|
||||
sendUpdate?: (open: boolean) => void;
|
||||
}
|
||||
|
||||
export const Collapsible: React.FunctionComponent<ICollapsibleProps> = ({children, title, sendUpdate, className}: React.PropsWithChildren<ICollapsibleProps>) => {
|
||||
const [ isOpen, setIsOpen ] = React.useState(true);
|
||||
|
||||
// This is a work around for a lit-element issue of duplicate slot names
|
||||
const triggerClick = (e: React.MouseEvent<HTMLElement>) => {
|
||||
if ((e.target as any).tagName.toUpperCase() === 'VSCODE-COLLAPSIBLE') {
|
||||
setIsOpen(prev => {
|
||||
if (sendUpdate) {
|
||||
sendUpdate(!prev);
|
||||
}
|
||||
return !prev;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<VsCollapsible title={title} onClick={triggerClick} open={isOpen}>
|
||||
<div className={`section collapsible__body ${className || ""}`} slot="body">
|
||||
{children}
|
||||
</div>
|
||||
</VsCollapsible>
|
||||
);
|
||||
};
|
||||
10
src/viewpanel/components/Icon.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface IIconProps {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const Icon: React.FunctionComponent<IIconProps> = ({ name }: React.PropsWithChildren<IIconProps>) => {
|
||||
|
||||
return (<i className={`codicon codicon-${name}`}></i>);
|
||||
};
|
||||
9
src/viewpanel/components/Icons/AddIcon.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface IAddIconProps {}
|
||||
|
||||
export const AddIcon: React.FunctionComponent<IAddIconProps> = (props: React.PropsWithChildren<IAddIconProps>) => {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M14 7v1H8v6H7V8H1V7h6V1h1v6h6z"/></svg>
|
||||
);
|
||||
};
|
||||
9
src/viewpanel/components/Icons/ArchiveIcon.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface IArchiveIconProps {}
|
||||
|
||||
export const ArchiveIcon: React.FunctionComponent<IArchiveIconProps> = (props: React.PropsWithChildren<IArchiveIconProps>) => {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path fillRule="evenodd" clipRule="evenodd" d="M14.5 1h-13l-.5.5v3l.5.5H2v8.5l.5.5h11l.5-.5V5h.5l.5-.5v-3l-.5-.5zm-1 3H2V2h12v2h-.5zM3 13V5h10v8H3zm8-6H5v1h6V7z"/></svg>
|
||||
);
|
||||
};
|
||||
9
src/viewpanel/components/Icons/BugIcon.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface IBugIconProps {}
|
||||
|
||||
export const BugIcon: React.FunctionComponent<IBugIconProps> = (props: React.PropsWithChildren<IBugIconProps>) => {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path fillRule="evenodd" clipRule="evenodd" d="M10.877 4.5v-.582a2.918 2.918 0 1 0-5.836 0V4.5h-.833L2.545 2.829l-.593.59 1.611 1.619-.019.049a8.03 8.03 0 0 0-.503 2.831c0 .196.007.39.02.58l.003.045H1v.836h2.169l.006.034c.172.941.504 1.802.954 2.531l.034.055L2.2 13.962l.592.592 1.871-1.872.058.066c.868.992 2.002 1.589 3.238 1.589 1.218 0 2.336-.579 3.199-1.544l.057-.064 1.91 1.92.593-.591-1.996-2.006.035-.056c.467-.74.81-1.619.986-2.583l.006-.034h2.171v-.836h-2.065l.003-.044a8.43 8.43 0 0 0 .02-.58 8.02 8.02 0 0 0-.517-2.866l-.019-.05 1.57-1.57-.592-.59L11.662 4.5h-.785zm-5 0v-.582a2.082 2.082 0 1 1 4.164 0V4.5H5.878zm5.697.837l.02.053c.283.753.447 1.61.447 2.528 0 1.61-.503 3.034-1.274 4.037-.77 1.001-1.771 1.545-2.808 1.545-1.036 0-2.037-.544-2.807-1.545-.772-1.003-1.275-2.427-1.275-4.037 0-.918.164-1.775.448-2.528l.02-.053h7.229z"/></svg>
|
||||
);
|
||||
};
|
||||
9
src/viewpanel/components/Icons/CheckIcon.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface ICheckIconProps {}
|
||||
|
||||
export const CheckIcon: React.FunctionComponent<ICheckIconProps> = (props: React.PropsWithChildren<ICheckIconProps>) => {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path fillRule="evenodd" clipRule="evenodd" d="M14.431 3.323l-8.47 10-.79-.036-3.35-4.77.818-.574 2.978 4.24 8.051-9.506.764.646z"/></svg>
|
||||
);
|
||||
};
|
||||
9
src/viewpanel/components/Icons/FileIcon.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface IFileIconProps {}
|
||||
|
||||
export const FileIcon: React.FunctionComponent<IFileIconProps> = (props: React.PropsWithChildren<IFileIconProps>) => {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path fillRule="evenodd" clipRule="evenodd" d="M13.71 4.29l-3-3L10 1H4L3 2v12l1 1h9l1-1V5l-.29-.71zM13 14H4V2h5v4h4v8zm-3-9V2l3 3h-3z"/></svg>
|
||||
);
|
||||
};
|
||||
9
src/viewpanel/components/Icons/FolderOpenedIcon.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface IFolderOpenedIconProps {}
|
||||
|
||||
export const FolderOpenedIcon: React.FunctionComponent<IFolderOpenedIconProps> = (props: React.PropsWithChildren<IFolderOpenedIconProps>) => {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M1.5 14h11l.48-.37 2.63-7-.48-.63H14V3.5l-.5-.5H7.71l-.86-.85L6.5 2h-5l-.5.5v11l.5.5zM2 3h4.29l.86.85.35.15H13v2H8.5l-.35.15-.86.85H3.5l-.47.34-1 3.08L2 3zm10.13 10H2.19l1.67-5H7.5l.35-.15.86-.85h5.79l-2.37 6z"/></svg>
|
||||
);
|
||||
};
|
||||
9
src/viewpanel/components/Icons/ListUnorderedIcon.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface IListUnorderedIconProps {}
|
||||
|
||||
export const ListUnorderedIcon: React.FunctionComponent<IListUnorderedIconProps> = (props: React.PropsWithChildren<IListUnorderedIconProps>) => {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path fillRule="evenodd" clipRule="evenodd" d="M2 3H1v1h1V3zm0 3H1v1h1V6zM1 9h1v1H1V9zm1 3H1v1h1v-1zm2-9h11v1H4V3zm11 3H4v1h11V6zM4 9h11v1H4V9zm11 3H4v1h11v-1z"/></svg>
|
||||
);
|
||||
};
|
||||
9
src/viewpanel/components/Icons/SettingsIcon.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface ISettingsIconProps {}
|
||||
|
||||
export const SettingsIcon: React.FunctionComponent<ISettingsIconProps> = (props: React.PropsWithChildren<ISettingsIconProps>) => {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path fillRule="evenodd" clipRule="evenodd" d="M3.5 2h-1v5h1V2zm6.1 5H6.4L6 6.45v-1L6.4 5h3.2l.4.5v1l-.4.5zm-5 3H1.4L1 9.5v-1l.4-.5h3.2l.4.5v1l-.4.5zm3.9-8h-1v2h1V2zm-1 6h1v6h-1V8zm-4 3h-1v3h1v-3zm7.9 0h3.19l.4-.5v-.95l-.4-.5H11.4l-.4.5v.95l.4.5zm2.1-9h-1v6h1V2zm-1 10h1v2h-1v-2z"/></svg>
|
||||
);
|
||||
};
|
||||
9
src/viewpanel/components/Icons/SymbolKeywordIcon.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface ISymbolKeywordIconProps {}
|
||||
|
||||
export const SymbolKeywordIcon: React.FunctionComponent<ISymbolKeywordIconProps> = (props: React.PropsWithChildren<ISymbolKeywordIconProps>) => {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M15 4h-5V3h5v1zm-1 3h-2v1h2V7zm-4 0H1v1h9V7zm2 6H1v1h11v-1zm-5-3H1v1h6v-1zm8 0h-5v1h5v-1zM8 2v3H1V2h7zM7 3H2v1h5V3z"/></svg>
|
||||
);
|
||||
};
|
||||
9
src/viewpanel/components/Icons/TagIcon.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface ITagIconProps {}
|
||||
|
||||
export const TagIcon: React.FunctionComponent<ITagIconProps> = (props: React.PropsWithChildren<ITagIconProps>) => {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path fillRule="evenodd" clipRule="evenodd" d="M13.2 2H8.017l-.353.146L1 8.81v.707L6.183 14.7h.707l2.215-2.215A4.48 4.48 0 0 0 15.65 9c.027-.166.044-.332.051-.5a4.505 4.505 0 0 0-2-3.74V2.5l-.5-.5zm-.5 2.259A4.504 4.504 0 0 0 11.2 4a.5.5 0 1 0 0 1 3.5 3.5 0 0 1 1.5.338v2.138L8.775 11.4a.506.506 0 0 0-.217.217l-2.022 2.022-4.475-4.476L8.224 3H12.7v1.259zm1 1.792a3.5 3.5 0 0 1 1 2.449 3.438 3.438 0 0 1-.051.5 3.487 3.487 0 0 1-4.793 2.735l3.698-3.698.146-.354V6.051z"/></svg>
|
||||
);
|
||||
};
|
||||
9
src/viewpanel/components/Icons/WarningIcon.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface IWarningIconProps {}
|
||||
|
||||
export const WarningIcon: React.FunctionComponent<IWarningIconProps> = (props: React.PropsWithChildren<IWarningIconProps>) => {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path fillRule="evenodd" clipRule="evenodd" d="M7.56 1h.88l6.54 12.26-.44.74H1.44L1 13.26 7.56 1zM8 2.28L2.28 13H13.7L8 2.28zM8.625 12v-1h-1.25v1h1.25zm-1.25-2V6h1.25v4h-1.25z"/></svg>
|
||||
);
|
||||
};
|
||||
@@ -1,21 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import { VsTable, VsTableBody, VsTableHeader, VsTableHeaderCell, VsTableRow, VsTableCell } from './VscodeComponents';
|
||||
|
||||
export interface ISeoDetailsProps {
|
||||
allowedLength: number;
|
||||
title: string;
|
||||
value: string;
|
||||
value: number;
|
||||
valueTitle: string;
|
||||
noValidation?: boolean;
|
||||
}
|
||||
|
||||
export const SeoDetails: React.FunctionComponent<ISeoDetailsProps> = (props: React.PropsWithChildren<ISeoDetailsProps>) => {
|
||||
const { allowedLength, title, value } = props;
|
||||
const { allowedLength, title, value, valueTitle, noValidation } = props;
|
||||
|
||||
const validate = () => {
|
||||
if (noValidation) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return value <= allowedLength ? "valid" : "not-valid"
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`seo__status__details ${value.length <= allowedLength ? "valid" : "not-valid"}`}>
|
||||
<h4><strong>{title}</strong></h4>
|
||||
<ul>
|
||||
<li><b>Length</b>: {value.length}</li>
|
||||
<li><b>Recommended length</b>: {allowedLength}</li>
|
||||
</ul>
|
||||
<div className={`seo__status__details ${validate()}`}>
|
||||
<h4>{title}</h4>
|
||||
|
||||
<VsTable bordered>
|
||||
<VsTableHeader slot="header">
|
||||
<VsTableHeaderCell className={validate()}>{valueTitle}</VsTableHeaderCell>
|
||||
<VsTableHeaderCell>Recommended</VsTableHeaderCell>
|
||||
</VsTableHeader>
|
||||
<VsTableBody slot="body">
|
||||
<VsTableRow>
|
||||
<VsTableCell className={validate()}>{value}</VsTableCell>
|
||||
<VsTableCell>{allowedLength}</VsTableCell>
|
||||
</VsTableRow>
|
||||
</VsTableBody>
|
||||
</VsTable>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
22
src/viewpanel/components/SeoFieldInfo.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import * as React from 'react';
|
||||
import { ValidInfo } from './ValidInfo';
|
||||
import { VsTableCell, VsTableRow } from './VscodeComponents';
|
||||
|
||||
export interface ISeoFieldInfoProps {
|
||||
title: string;
|
||||
value: any;
|
||||
recommendation: any;
|
||||
isValid?: boolean;
|
||||
}
|
||||
|
||||
export const SeoFieldInfo: React.FunctionComponent<ISeoFieldInfoProps> = ({ title, value, recommendation, isValid }: React.PropsWithChildren<ISeoFieldInfoProps>) => {
|
||||
return (
|
||||
<VsTableRow>
|
||||
<VsTableCell className={`table__cell table__title`}>{title}</VsTableCell>
|
||||
<VsTableCell className={`table__cell`}>{value}/{recommendation}</VsTableCell>
|
||||
<VsTableCell className={`table__cell table__cell__validation`}>
|
||||
{ isValid !== undefined ? <ValidInfo isValid={isValid} /> : <span>-</span> }
|
||||
</VsTableCell>
|
||||
</VsTableRow>
|
||||
);
|
||||
};
|
||||
32
src/viewpanel/components/SeoKeywordInfo.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import * as React from 'react';
|
||||
import { ValidInfo } from './ValidInfo';
|
||||
import { VsTableCell, VsTableRow } from './VscodeComponents';
|
||||
|
||||
export interface ISeoKeywordInfoProps {
|
||||
keyword: string;
|
||||
title: string;
|
||||
description: string;
|
||||
slug: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export const SeoKeywordInfo: React.FunctionComponent<ISeoKeywordInfoProps> = ({keyword, title, description, slug, content}: React.PropsWithChildren<ISeoKeywordInfoProps>) => {
|
||||
|
||||
return (
|
||||
<VsTableRow>
|
||||
<VsTableCell className={`table__cell`}>{keyword}</VsTableCell>
|
||||
<VsTableCell className={`table__cell table__cell__validation`}>
|
||||
<ValidInfo isValid={!!title && title.toLowerCase().includes(keyword.toLowerCase())} />
|
||||
</VsTableCell>
|
||||
<VsTableCell className={`table__cell table__cell__validation`}>
|
||||
<ValidInfo isValid={!!description && description.toLowerCase().includes(keyword.toLowerCase())} />
|
||||
</VsTableCell>
|
||||
<VsTableCell className={`table__cell table__cell__validation`}>
|
||||
<ValidInfo isValid={!!slug && (slug.toLowerCase().includes(keyword.toLowerCase()) || slug.toLowerCase().includes(keyword.replace(/ /g, '-').toLowerCase()))} />
|
||||
</VsTableCell>
|
||||
<VsTableCell className={`table__cell table__cell__validation`}>
|
||||
<ValidInfo isValid={!!content && content.toLowerCase().includes(keyword.toLowerCase())} />
|
||||
</VsTableCell>
|
||||
</VsTableRow>
|
||||
);
|
||||
};
|
||||
46
src/viewpanel/components/SeoKeywords.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import * as React from 'react';
|
||||
import { SeoKeywordInfo } from './SeoKeywordInfo';
|
||||
import { VsTable, VsTableBody, VsTableCell, VsTableHeader, VsTableHeaderCell, VsTableRow } from './VscodeComponents';
|
||||
|
||||
export interface ISeoKeywordsProps {
|
||||
keywords: string[] | null;
|
||||
|
||||
title: string;
|
||||
description: string;
|
||||
slug: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export const SeoKeywords: React.FunctionComponent<ISeoKeywordsProps> = ({keywords, ...data}: React.PropsWithChildren<ISeoKeywordsProps>) => {
|
||||
|
||||
if (!keywords || keywords.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`seo__status__keywords`}>
|
||||
<h4>Keywords</h4>
|
||||
|
||||
<VsTable bordered>
|
||||
<VsTableHeader slot="header">
|
||||
<VsTableHeaderCell className={`table__cell`}>Keyword</VsTableHeaderCell>
|
||||
<VsTableHeaderCell className={`table__cell`}>Title</VsTableHeaderCell>
|
||||
<VsTableHeaderCell className={`table__cell`}>Description</VsTableHeaderCell>
|
||||
<VsTableHeaderCell className={`table__cell`}>Slug</VsTableHeaderCell>
|
||||
<VsTableHeaderCell className={`table__cell`}>Content</VsTableHeaderCell>
|
||||
</VsTableHeader>
|
||||
<VsTableBody slot="body">
|
||||
{
|
||||
keywords.map((keyword, index) => {
|
||||
return (
|
||||
<SeoKeywordInfo key={index} keyword={keyword} {...data} />
|
||||
);
|
||||
})
|
||||
}
|
||||
</VsTableBody>
|
||||
</VsTable>
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import { SEO } from '../../models/PanelSettings';
|
||||
import { SeoDetails } from './SeoDetails';
|
||||
import { ArticleDetails } from './ArticleDetails';
|
||||
import { Collapsible } from './Collapsible';
|
||||
import { SeoFieldInfo } from './SeoFieldInfo';
|
||||
import { SeoKeywords } from './SeoKeywords';
|
||||
import { VsTable, VsTableBody, VsTableHeader, VsTableHeaderCell } from './VscodeComponents';
|
||||
|
||||
export interface ISeoStatusProps {
|
||||
seo: SEO;
|
||||
@@ -9,7 +13,9 @@ export interface ISeoStatusProps {
|
||||
|
||||
export const SeoStatus: React.FunctionComponent<ISeoStatusProps> = (props: React.PropsWithChildren<ISeoStatusProps>) => {
|
||||
const { data, seo } = props;
|
||||
const { title, description } = data;
|
||||
const { title } = data;
|
||||
const [ isOpen, setIsOpen ] = React.useState(true);
|
||||
const tableRef = React.useRef<HTMLElement>();
|
||||
|
||||
const { descriptionField } = seo;
|
||||
|
||||
@@ -17,11 +23,73 @@ export const SeoStatus: React.FunctionComponent<ISeoStatusProps> = (props: React
|
||||
return null;
|
||||
}
|
||||
|
||||
const renderContent = () => {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={`seo__status__details`}>
|
||||
<h4>Recommendations</h4>
|
||||
|
||||
<VsTable ref={tableRef} bordered zebra>
|
||||
<VsTableHeader slot="header">
|
||||
<VsTableHeaderCell className={`table__cell`}>Property</VsTableHeaderCell>
|
||||
<VsTableHeaderCell className={`table__cell`}>Length</VsTableHeaderCell>
|
||||
<VsTableHeaderCell className={`table__cell`}>Valid</VsTableHeaderCell>
|
||||
</VsTableHeader>
|
||||
<VsTableBody slot="body">
|
||||
{
|
||||
(title && seo.title > 0) && (
|
||||
<SeoFieldInfo title={`title`} value={title.length} recommendation={`${seo.title} chars`} isValid={title.length <= seo.title} />
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
(data[descriptionField] && seo.description > 0) && (
|
||||
<SeoFieldInfo title={descriptionField} value={data[descriptionField].length} recommendation={`${seo.description} chars`} isValid={data[descriptionField].length <= seo.description} />
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
(seo.content > 0 && data?.articleDetails?.wordCount > 0) && (
|
||||
<SeoFieldInfo title={`Article length`} value={data?.articleDetails?.wordCount} recommendation={`${seo.content} words`} />
|
||||
)
|
||||
}
|
||||
</VsTableBody>
|
||||
</VsTable>
|
||||
</div>
|
||||
|
||||
<SeoKeywords keywords={data?.keywords}
|
||||
title={title}
|
||||
description={data[descriptionField]}
|
||||
slug={data.slug}
|
||||
content={data?.articleDetails?.content} />
|
||||
|
||||
<ArticleDetails details={data.articleDetails} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Workaround for lit components not updating render
|
||||
React.useEffect(() => {
|
||||
setTimeout(() => {
|
||||
let height = 0;
|
||||
|
||||
tableRef.current?.childNodes.forEach((elm: any) => {
|
||||
height += elm.clientHeight;
|
||||
});
|
||||
|
||||
if (height > 0 && tableRef.current) {
|
||||
tableRef.current.style.height = `${height}px`;
|
||||
}
|
||||
}, 10);
|
||||
}, [title, data[descriptionField], data?.articleDetails?.wordCount]);
|
||||
|
||||
return (
|
||||
<div className="seo__status">
|
||||
<h3>SEO Status</h3>
|
||||
{ (title && seo.title > 0) && <SeoDetails title="Title" allowedLength={seo.title} value={title} /> }
|
||||
{ (data[descriptionField] && seo.description > 0) && <SeoDetails title="Description" allowedLength={seo.description} value={data[descriptionField]} /> }
|
||||
</div>
|
||||
<Collapsible title="SEO Status" sendUpdate={(value) => setIsOpen(value)}>
|
||||
{ renderContent() }
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
@@ -1,26 +1,28 @@
|
||||
import * as React from 'react';
|
||||
import AddIcon from '@material-ui/icons/Add';
|
||||
import DeleteIcon from '@material-ui/icons/Delete';
|
||||
import { AddIcon } from './Icons/AddIcon';
|
||||
import { ArchiveIcon } from './Icons/ArchiveIcon';
|
||||
|
||||
export interface ITagProps {
|
||||
className: string;
|
||||
value: string;
|
||||
title: string;
|
||||
|
||||
disableConfigurable?: boolean;
|
||||
|
||||
onCreate?: (tags: string) => void;
|
||||
onRemove: (tags: string) => void;
|
||||
}
|
||||
|
||||
export const Tag: React.FunctionComponent<ITagProps> = (props: React.PropsWithChildren<ITagProps>) => {
|
||||
const { value, className, title, onRemove, onCreate } = props;
|
||||
const { value, className, title, onRemove, onCreate, disableConfigurable } = props;
|
||||
|
||||
return (
|
||||
<div className={`article__tags__items__item`}>
|
||||
{
|
||||
onCreate &&
|
||||
!disableConfigurable && onCreate &&
|
||||
<button title={`Add ${value} to your settings`} className={`article__tags__items__item_add`} onClick={() => onCreate(value)}><AddIcon /></button>
|
||||
}
|
||||
<button title={title} className={`article__tags__items__item_delete ${className}`} onClick={() => onRemove(value)}>{value} <span><DeleteIcon /></span></button>
|
||||
<button title={title} className={`article__tags__items__item_delete ${className}`} onClick={() => onRemove(value)}>{value} <span><ArchiveIcon /></span></button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -5,18 +5,21 @@ import { CommandToCode } from '../CommandToCode';
|
||||
import { TagType } from '../TagType';
|
||||
import { MessageHelper } from '../helper/MessageHelper';
|
||||
import Downshift from 'downshift';
|
||||
import { AddIcon } from './Icons/AddIcon';
|
||||
|
||||
export interface ITagPickerProps {
|
||||
type: string;
|
||||
icon: JSX.Element;
|
||||
crntSelected: string[];
|
||||
options: string[];
|
||||
freeform: boolean;
|
||||
focussed: boolean;
|
||||
unsetFocus: () => void;
|
||||
disableConfigurable?: boolean;
|
||||
}
|
||||
|
||||
export const TagPicker: React.FunctionComponent<ITagPickerProps> = (props: React.PropsWithChildren<ITagPickerProps>) => {
|
||||
const { type, crntSelected, options, freeform, focussed, unsetFocus } = props;
|
||||
const { icon, type, crntSelected, options, freeform, focussed, unsetFocus, disableConfigurable } = props;
|
||||
const [ selected, setSelected ] = React.useState<string[]>([]);
|
||||
const [ inputValue, setInputValue ] = React.useState<string>("");
|
||||
const prevSelected = usePrevious(crntSelected);
|
||||
@@ -47,7 +50,16 @@ export const TagPicker: React.FunctionComponent<ITagPickerProps> = (props: React
|
||||
* @param values
|
||||
*/
|
||||
const sendUpdate = (values: string[]) => {
|
||||
const cmdType = type === TagType.tags ? CommandToCode.updateTags : CommandToCode.updateCategories;
|
||||
let cmdType = CommandToCode.updateCategories;
|
||||
|
||||
if (type === TagType.tags) {
|
||||
cmdType = CommandToCode.updateTags;
|
||||
} else if (type === TagType.categories) {
|
||||
cmdType = CommandToCode.updateCategories;
|
||||
} else if (type === TagType.keywords) {
|
||||
cmdType = CommandToCode.updateKeywords;
|
||||
}
|
||||
|
||||
MessageHelper.sendMessage(cmdType, values);
|
||||
};
|
||||
|
||||
@@ -114,8 +126,8 @@ export const TagPicker: React.FunctionComponent<ITagPickerProps> = (props: React
|
||||
}, [crntSelected]);
|
||||
|
||||
return (
|
||||
<div className={`article__tags`}>
|
||||
<h3>{type}</h3>
|
||||
<div className={`section article__tags`}>
|
||||
<h3>{icon} {type}</h3>
|
||||
|
||||
<Downshift ref={dsRef}
|
||||
onChange={(selected) => onSelect(selected || "")}
|
||||
@@ -144,9 +156,12 @@ export const TagPicker: React.FunctionComponent<ITagPickerProps> = (props: React
|
||||
|
||||
{
|
||||
freeform && (
|
||||
<button title={`Add the unknown tag`}
|
||||
<button className={`article__tags__input__button`}
|
||||
title={`Add the unknown tag`}
|
||||
disabled={!inputValue}
|
||||
onClick={() => insertUnkownTag(closeMenu)}>+</button>
|
||||
onClick={() => insertUnkownTag(closeMenu)}>
|
||||
<AddIcon />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
@@ -154,7 +169,7 @@ export const TagPicker: React.FunctionComponent<ITagPickerProps> = (props: React
|
||||
<ul className={`article__tags__dropbox ${isOpen ? "open" : "closed" }`} {...getMenuProps()}>
|
||||
{
|
||||
isOpen ? options.filter((option) => filterList(option, inputValue)).map((item, index) => (
|
||||
<li {...getItemProps({ key: item, index, item })} >
|
||||
<li {...getItemProps({ key: item, index, item })}>
|
||||
{ item }
|
||||
</li>
|
||||
)) : null
|
||||
@@ -165,7 +180,7 @@ export const TagPicker: React.FunctionComponent<ITagPickerProps> = (props: React
|
||||
}
|
||||
</Downshift>
|
||||
|
||||
<Tags values={selected.sort((a: string, b: string) => a.toLowerCase() < b.toLowerCase() ? -1 : 1 )} onRemove={onRemove} onCreate={onCreate} options={options} />
|
||||
<Tags values={selected.sort((a: string, b: string) => a.toLowerCase() < b.toLowerCase() ? -1 : 1 )} onRemove={onRemove} onCreate={onCreate} options={options} disableConfigurable={!!disableConfigurable} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -5,12 +5,14 @@ export interface ITagsProps {
|
||||
values: string[];
|
||||
options: string[];
|
||||
|
||||
disableConfigurable?: boolean;
|
||||
|
||||
onCreate: (tags: string) => void;
|
||||
onRemove: (tags: string) => void;
|
||||
}
|
||||
|
||||
export const Tags: React.FunctionComponent<ITagsProps> = (props: React.PropsWithChildren<ITagsProps>) => {
|
||||
const { values, options, onCreate, onRemove } = props;
|
||||
const { values, options, onCreate, onRemove, disableConfigurable } = props;
|
||||
|
||||
const knownTags = values.filter(v => options.includes(v));
|
||||
const unknownTags = values.filter(v => !options.includes(v));
|
||||
@@ -24,7 +26,7 @@ export const Tags: React.FunctionComponent<ITagsProps> = (props: React.PropsWith
|
||||
}
|
||||
{
|
||||
unknownTags.map(t => (
|
||||
<Tag key={t.replace(/ /g, "_")} value={t} className={`article__tags__items__pill_notexists`} onRemove={onRemove} onCreate={onCreate} title={`Be aware, this tag "${t}" is not saved in your settings. Once removed, it will be gone forever.`} />
|
||||
<Tag key={t.replace(/ /g, "_")} value={t} className={`article__tags__items__pill_notexists`} onRemove={onRemove} onCreate={onCreate} title={`Be aware, this tag "${t}" is not saved in your settings. Once removed, it will be gone forever.`} disableConfigurable={disableConfigurable} />
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
21
src/viewpanel/components/ValidInfo.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import * as React from 'react';
|
||||
import { CheckIcon } from './Icons/CheckIcon';
|
||||
import { WarningIcon } from './Icons/WarningIcon';
|
||||
|
||||
export interface IValidInfoProps {
|
||||
isValid: boolean;
|
||||
}
|
||||
|
||||
export const ValidInfo: React.FunctionComponent<IValidInfoProps> = ({isValid}: React.PropsWithChildren<IValidInfoProps>) => {
|
||||
return (
|
||||
<>
|
||||
{
|
||||
isValid ? (
|
||||
<span className="valid"><CheckIcon /></span>
|
||||
) : (
|
||||
<span className="warning"><WarningIcon /></span>
|
||||
)
|
||||
}
|
||||
</>
|
||||
);
|
||||
};
|
||||
9
src/viewpanel/components/VscodeComponents.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import {wrapWc} from 'wc-react';
|
||||
|
||||
export const VsTable = wrapWc(`vscode-table`);
|
||||
export const VsTableHeader = wrapWc(`vscode-table-header`);
|
||||
export const VsTableHeaderCell = wrapWc(`vscode-table-header-cell`);
|
||||
export const VsTableBody = wrapWc(`vscode-table-body`);
|
||||
export const VsTableRow = wrapWc(`vscode-table-row`);
|
||||
export const VsTableCell = wrapWc(`vscode-table-cell`);
|
||||
export const VsCollapsible = wrapWc(`vscode-collapsible`);
|
||||
@@ -2,6 +2,15 @@ import * as React from "react";
|
||||
import { render } from "react-dom";
|
||||
import { ViewPanel } from "./ViewPanel";
|
||||
|
||||
// require('@vscode/codicons/dist/codicon.css');
|
||||
import '@bendera/vscode-webview-elements/dist/vscode-table';
|
||||
import '@bendera/vscode-webview-elements/dist/vscode-table-header';
|
||||
import '@bendera/vscode-webview-elements/dist/vscode-table-header-cell';
|
||||
import '@bendera/vscode-webview-elements/dist/vscode-table-body';
|
||||
import '@bendera/vscode-webview-elements/dist/vscode-table-row';
|
||||
import '@bendera/vscode-webview-elements/dist/vscode-table-cell';
|
||||
import '@bendera/vscode-webview-elements/dist/vscode-collapsible';
|
||||
|
||||
declare const acquireVsCodeApi: <T = unknown>() => {
|
||||
getState: () => T;
|
||||
setState: (data: T) => void;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { SETTING_CUSTOM_SCRIPTS, SETTING_SEO_DESCRIPTION_FIELD } from './../constants/settings';
|
||||
import { Template } from './../commands/Template';
|
||||
import { SETTING_CUSTOM_SCRIPTS, SETTING_SEO_CONTENT_MIN_LENGTH, SETTING_SEO_DESCRIPTION_FIELD, SETTING_SLUG_UPDATE_FILE_NAME } from './../constants/settings';
|
||||
import * as os from 'os';
|
||||
import { PanelSettings, CustomScript } from './../models/PanelSettings';
|
||||
import { CancellationToken, Disposable, Uri, Webview, WebviewView, WebviewViewProvider, WebviewViewResolveContext, window, workspace, commands, env as vscodeEnv } from "vscode";
|
||||
@@ -11,6 +12,11 @@ import { TagType } from '../viewpanel/TagType';
|
||||
import { TaxonomyType } from '../models';
|
||||
import { exec } from 'child_process';
|
||||
import * as path from 'path';
|
||||
import { fromMarkdown } from 'mdast-util-from-markdown';
|
||||
import { Content } from 'mdast';
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
import { COMMAND_NAME } from '../constants/Extension';
|
||||
import { Folders } from '../commands/Folders';
|
||||
|
||||
|
||||
export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
@@ -58,8 +64,6 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
*/
|
||||
public async resolveWebviewView(webviewView: WebviewView, context: WebviewViewResolveContext, token: CancellationToken): Promise<void> {
|
||||
|
||||
console.log(context);
|
||||
|
||||
this.panel = webviewView;
|
||||
|
||||
webviewView.webview.options = {
|
||||
@@ -74,7 +78,7 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
webviewView.onDidDispose(() => { webviewView.webview.html = ""; }, this),
|
||||
);
|
||||
|
||||
webviewView.webview.onDidReceiveMessage(msg => {
|
||||
webviewView.webview.onDidReceiveMessage(async (msg) => {
|
||||
switch(msg.command) {
|
||||
case CommandToCode.getData:
|
||||
this.getSettings();
|
||||
@@ -98,6 +102,9 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
case CommandToCode.updateCategories:
|
||||
this.updateTags(TagType.categories, msg.data || []);
|
||||
break;
|
||||
case CommandToCode.updateKeywords:
|
||||
this.updateTags(TagType.keywords, msg.data || []);
|
||||
break;
|
||||
case CommandToCode.addTagToSettings:
|
||||
this.addTags(TagType.tags, msg.data);
|
||||
break;
|
||||
@@ -108,7 +115,11 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
commands.executeCommand('workbench.action.openSettings', '@ext:eliostruyf.vscode-front-matter');
|
||||
break;
|
||||
case CommandToCode.openFile:
|
||||
commands.executeCommand('revealFileInOS');
|
||||
if (os.type() === "Linux" && vscodeEnv.remoteName?.toLowerCase() === "wsl") {
|
||||
commands.executeCommand('remote-wsl.revealInExplorer');
|
||||
} else {
|
||||
commands.executeCommand('revealFileInOS');
|
||||
}
|
||||
break;
|
||||
case CommandToCode.runCustomScript:
|
||||
this.runCustomScript(msg);
|
||||
@@ -121,11 +132,20 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
exec(`open ${wsPath}`);
|
||||
} else if (os.type() === "Windows_NT") {
|
||||
exec(`explorer ${wsPath}`);
|
||||
} else if (os.type() === "Linux" && vscodeEnv.remoteName?.toLowerCase() === "wsl") {
|
||||
exec('explorer.exe `wslpath -w "$PWD"`');
|
||||
} else {
|
||||
exec(`xdg-open ${wsPath}`);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CommandToCode.initProject:
|
||||
await commands.executeCommand(COMMAND_NAME.init);
|
||||
this.getSettings();
|
||||
break;
|
||||
case CommandToCode.createContent:
|
||||
await commands.executeCommand(COMMAND_NAME.createContent);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -152,7 +172,15 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
* @param metadata
|
||||
*/
|
||||
public pushMetadata(metadata: any) {
|
||||
this.postWebviewMessage({ command: Command.metadata, data: metadata });
|
||||
const articleDetails = this.getArticleDetails();
|
||||
|
||||
if (articleDetails) {
|
||||
metadata.articleDetails = articleDetails;
|
||||
}
|
||||
|
||||
this.postWebviewMessage({ command: Command.metadata, data: {
|
||||
...metadata
|
||||
}});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +222,7 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
|
||||
exec(`${customScript.nodeBin || "node"} ${path.join(wsPath, msg.data.script)} "${wsPath}" "${editor?.document.uri.fsPath}" ${articleData}`, (error, stdout) => {
|
||||
if (error) {
|
||||
window.showErrorMessage(`${msg?.data?.title}: ${error.message}`);
|
||||
Notifications.error(`${msg?.data?.title}: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -212,7 +240,7 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
/**
|
||||
* Retrieve the extension settings
|
||||
*/
|
||||
private getSettings() {
|
||||
private async getSettings() {
|
||||
const config = workspace.getConfiguration(CONFIG_KEY);
|
||||
|
||||
this.postWebviewMessage({
|
||||
@@ -221,16 +249,20 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
seo: {
|
||||
title: config.get(SETTING_SEO_TITLE_LENGTH) as number || -1,
|
||||
description: config.get(SETTING_SEO_DESCRIPTION_LENGTH) as number || -1,
|
||||
content: config.get(SETTING_SEO_CONTENT_MIN_LENGTH) as number || -1,
|
||||
descriptionField: config.get(SETTING_SEO_DESCRIPTION_FIELD) as string || "description"
|
||||
},
|
||||
slug: {
|
||||
prefix: config.get(SETTING_SLUG_PREFIX) || "",
|
||||
suffix: config.get(SETTING_SLUG_SUFFIX) || ""
|
||||
suffix: config.get(SETTING_SLUG_SUFFIX) || "",
|
||||
updateFileName: !!config.get<boolean>(SETTING_SLUG_UPDATE_FILE_NAME),
|
||||
},
|
||||
tags: config.get(SETTING_TAXONOMY_TAGS) || [],
|
||||
categories: config.get(SETTING_TAXONOMY_CATEGORIES) || [],
|
||||
freeform: config.get(SETTING_PANEL_FREEFORM),
|
||||
scripts: config.get(SETTING_CUSTOM_SCRIPTS)
|
||||
scripts: config.get(SETTING_CUSTOM_SCRIPTS),
|
||||
isInitialized: await Template.isInitialized(),
|
||||
contentInfo: await Folders.getInfo() || null
|
||||
} as PanelSettings
|
||||
});
|
||||
}
|
||||
@@ -245,7 +277,7 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
}
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
this.postWebviewMessage({ command: Command.metadata, data: article!.data });
|
||||
this.pushMetadata(article!.data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,7 +295,7 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
if (article && article.data) {
|
||||
article.data[tagType.toLowerCase()] = values || [];
|
||||
ArticleHelper.update(editor, article);
|
||||
this.postWebviewMessage({ command: Command.metadata, data: article.data });
|
||||
this.pushMetadata(article!.data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,6 +319,63 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get article details
|
||||
*/
|
||||
private getArticleDetails() {
|
||||
const editor = window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!ArticleHelper.isMarkdownDile()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
|
||||
if (article && article.content) {
|
||||
let content = article.content;
|
||||
content = content.replace(/({{(.*?)}})/g, ''); // remove hugo shortcodes
|
||||
|
||||
const mdTree = fromMarkdown(content);
|
||||
const headings = mdTree.children.filter(node => node.type === 'heading').length;
|
||||
const paragraphs = mdTree.children.filter(node => node.type === 'paragraph').length;
|
||||
const wordCount = this.wordCount(0, mdTree);
|
||||
|
||||
return {
|
||||
headings,
|
||||
paragraphs,
|
||||
wordCount,
|
||||
content: article.content
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private counts(acc: any, node: any) {
|
||||
// add 1 to an initial or existing value
|
||||
acc[node.type] = (acc[node.type] || 0) + 1;
|
||||
|
||||
// find and add up the counts from all of this node's children
|
||||
return (node.children || []).reduce(
|
||||
(childAcc: any, childNode: any) => this.counts(childAcc, childNode),
|
||||
acc
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the word count for the current document
|
||||
*/
|
||||
private wordCount(count: number, node: Content | any) {
|
||||
if (node.type === "text") {
|
||||
return count + node.value.split(" ").length;
|
||||
} else {
|
||||
return (node.children || []).reduce((childCount: number, childNode: any) => this.wordCount(childCount, childNode), count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post data to the panel
|
||||
* @param msg
|
||||
@@ -314,23 +403,26 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
const styleResetUri = webView.asWebviewUri(Uri.joinPath(this.extPath, 'assets/media', 'reset.css'));
|
||||
const stylesUri = webView.asWebviewUri(Uri.joinPath(this.extPath, 'assets/media', 'styles.css'));
|
||||
const scriptUri = webView.asWebviewUri(Uri.joinPath(this.extPath, 'dist', 'viewpanel.js'));
|
||||
|
||||
const nonce = this.getNonce();
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${webView.cspSource} 'self' 'unsafe-inline'; script-src 'nonce-${nonce}'; style-src ${webView.cspSource} 'self' 'unsafe-inline'; font-src ${webView.cspSource}">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${webView.cspSource} https://api.visitorbadge.io 'self' 'unsafe-inline'; script-src 'nonce-${nonce}'; style-src ${webView.cspSource} 'self' 'unsafe-inline'; font-src ${webView.cspSource}">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="${styleResetUri}" rel="stylesheet">
|
||||
<link href="${styleVSCodeUri}" rel="stylesheet">
|
||||
<link href="${stylesUri}" rel="stylesheet">
|
||||
|
||||
<title>FrontMatter</title>
|
||||
<title>Front Matter</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<img style="display:none" src="https://api.visitorbadge.io/api/combined?user=estruyf&repo=frontmatter-usage&countColor=%23263759" alt="Daily usage" />
|
||||
|
||||
<script nonce="${nonce}" src="${scriptUri}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -49,13 +49,15 @@ module.exports = [
|
||||
extensions: ['.ts', '.js', '.tsx', '.jsx']
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.(ts|tsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: [{
|
||||
loader: 'ts-loader'
|
||||
}]
|
||||
}]
|
||||
rules: [
|
||||
{
|
||||
test: /\.(ts|tsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: [{
|
||||
loader: 'ts-loader'
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 400000,
|
||||
|
||||