mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-03-28 17:42:40 +01:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
310f8e4a5e | ||
|
|
d79f3416a3 | ||
|
|
e194928291 | ||
|
|
32aa8f4223 | ||
|
|
c88d6be1d7 |
@@ -1,5 +1,12 @@
|
||||
# Change Log
|
||||
|
||||
## [2.3.0] - 2020-08-10
|
||||
|
||||
- Refactoring and showing other actions in the base view
|
||||
- Show `BaseView` in Front Matter panel when switching to `welcome` tab
|
||||
- [#31](https://github.com/estruyf/vscode-front-matter/issues/31): Automatically update the last modification date of the file when performing changes
|
||||
- [#53](https://github.com/estruyf/vscode-front-matter/issues/53): Create current Markdown file as template
|
||||
|
||||
## [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
|
||||
|
||||
40
README.md
40
README.md
@@ -53,14 +53,22 @@ Initially, this panel has been created to make it easier to add tags and categor
|
||||
|
||||
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:
|
||||
When you open the panel and the current file is not a 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" />
|
||||
<img src="./assets/v2.3.0/baseview.png" alt="Base view" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
> **Info**: both **Global Settings** and **Other Actions** sections are shown for the base view as when a Markdown file is openend.
|
||||
|
||||
When you open the Front Matter panel on a Markdown file, you get to see the following sections:
|
||||
|
||||
**Global Settings**
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/v2.3.0/global-settings.png.png" alt="Global settings" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
**SEO Status**
|
||||
|
||||
<p align="center">
|
||||
@@ -83,10 +91,8 @@ When you open the Front Matter panel on a Markdown file, you get to see the foll
|
||||
|
||||
**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" />
|
||||
<img src="./assets/v2.3.0/other-actions.png" alt="Other actions" style="display: inline-block" />
|
||||
</p>
|
||||
|
||||
## Custom actions
|
||||
@@ -143,14 +149,16 @@ When adding files in the folder, you'll be able to run the `Front Matter: New ar
|
||||
|
||||
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**
|
||||
**Front Matter: Create a template from current file**
|
||||
|
||||
This command allows you to create a new template from the current open Markdown file. It will ask you for the name of the template and if you want to keep the current file its content in the template.
|
||||
|
||||
> **Info**: The create as template action is also available from the `other actions` section in the Front Matter panel.
|
||||
|
||||
**Front Matter: New article from template**
|
||||
|
||||
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">
|
||||
@@ -193,7 +201,7 @@ Update the `date` property of the current article/post/... to the current date &
|
||||
|
||||
**Front Matter: Set lastmod date**
|
||||
|
||||
Update the `lastmod` (last modified) property of the current article/post/... to the current date & time.
|
||||
Update the `lastmod` (last modified) property of the current article/post/... to the current date & time. By setting the `frontMatter.content.autoUpdateDate` setting, it can be done automatically when performing changes to your markdown files.
|
||||
|
||||
> **note**: Uses the same date format settings key as current date: `frontMatter.taxonomy.dateFormat`.
|
||||
|
||||
@@ -355,6 +363,16 @@ This array of folders defines where the extension can easily create new content
|
||||
|
||||
> **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.
|
||||
|
||||
### `frontMatter.content.autoUpdateDate`
|
||||
|
||||
Specify if you want to automatically update the modification date of your markdown page when doing changes to it. Default: `false`.
|
||||
|
||||
```json
|
||||
{
|
||||
"frontMatter.content.autoUpdateDate": false
|
||||
}
|
||||
```
|
||||
|
||||
## Feedback / issues / ideas
|
||||
|
||||
Please submit them via creating an issue in the project repository: [issue list](https://github.com/estruyf/vscode-front-matter/issues).
|
||||
|
||||
@@ -21,10 +21,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
.relative {
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.absolute {
|
||||
position: absolute !important;
|
||||
}
|
||||
|
||||
.inherit {
|
||||
position: inherit !important;
|
||||
}
|
||||
|
||||
.z-10 { z-index: 10 !important; }
|
||||
.z-20 { z-index: 10 !important; }
|
||||
|
||||
.w-full {
|
||||
width: 100% !important;
|
||||
}
|
||||
@@ -249,6 +260,7 @@
|
||||
}
|
||||
|
||||
.article__actions > * + *,
|
||||
.other_actions > * + *,
|
||||
.base__actions > * + *,
|
||||
.base__information > * + * {
|
||||
--tw-space-y-reverse: 0;
|
||||
@@ -288,7 +300,7 @@
|
||||
padding: 0px 14px;
|
||||
user-select: none;
|
||||
text-decoration: none;
|
||||
width: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ext_link_block a:hover,
|
||||
|
||||
BIN
assets/v2.3.0/baseview.png
Normal file
BIN
assets/v2.3.0/baseview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
BIN
assets/v2.3.0/global-settings.png
Normal file
BIN
assets/v2.3.0/global-settings.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/v2.3.0/other-actions.png
Normal file
BIN
assets/v2.3.0/other-actions.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vscode-front-matter",
|
||||
"version": "2.2.0",
|
||||
"version": "2.3.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
18
package.json
18
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": "2.2.0",
|
||||
"version": "2.3.0",
|
||||
"preview": false,
|
||||
"publisher": "eliostruyf",
|
||||
"galleryBanner": {
|
||||
@@ -94,6 +94,11 @@
|
||||
"default": "lastmod",
|
||||
"description": "Specifies the modified date field name to use in your Front Matter"
|
||||
},
|
||||
"frontMatter.content.autoUpdateDate": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Specify if you want to automatically update the modified date of your article/page."
|
||||
},
|
||||
"frontMatter.taxonomy.tags": {
|
||||
"type": "array",
|
||||
"description": "Specifies the tags which can be used in the Front Matter"
|
||||
@@ -251,13 +256,18 @@
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.createContent",
|
||||
"title": "Create content",
|
||||
"title": "New article from template",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.init",
|
||||
"title": "Initialize project",
|
||||
"category": "Front matter"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.createTemplate",
|
||||
"title": "Create a template from current file",
|
||||
"category": "Front matter"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
@@ -282,6 +292,10 @@
|
||||
{
|
||||
"command": "frontMatter.init",
|
||||
"when": "frontMatterCanInit"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.createTemplate",
|
||||
"when": "!frontMatterCanInit"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SETTING_MODIFIED_FIELD, SETTING_SLUG_UPDATE_FILE_NAME, SETTING_TEMPLATES_PREFIX } from './../constants/settings';
|
||||
import { SETTING_AUTO_UPDATE_DATE, 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, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_DATE_FIELD } from "../constants/settings";
|
||||
@@ -10,6 +10,7 @@ import { extname, basename } from 'path';
|
||||
|
||||
|
||||
export class Article {
|
||||
private static prevContent = "";
|
||||
|
||||
/**
|
||||
* Insert taxonomy
|
||||
@@ -126,16 +127,17 @@ export class Article {
|
||||
return;
|
||||
}
|
||||
|
||||
const cloneArticle = Object.assign({}, article);
|
||||
const dateFormat = config.get(SETTING_DATE_FORMAT) as string;
|
||||
const dateField = config.get(SETTING_MODIFIED_FIELD) as string || "lastmod";
|
||||
try {
|
||||
if (dateFormat && typeof dateFormat === "string") {
|
||||
article.data[dateField] = format(new Date(), dateFormat);
|
||||
cloneArticle.data[dateField] = format(new Date(), dateFormat);
|
||||
} else {
|
||||
article.data[dateField] = new Date().toISOString();
|
||||
cloneArticle.data[dateField] = new Date().toISOString();
|
||||
}
|
||||
|
||||
ArticleHelper.update(editor, article);
|
||||
ArticleHelper.update(editor, cloneArticle);
|
||||
} catch (e) {
|
||||
Notifications.error(`Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`);
|
||||
console.log(e.message);
|
||||
@@ -220,6 +222,35 @@ export class Article {
|
||||
ArticleHelper.update(editor, article);
|
||||
}
|
||||
|
||||
/**
|
||||
* Article auto updater
|
||||
* @param fileChanges
|
||||
*/
|
||||
public static async autoUpdate(fileChanges: vscode.TextDocumentChangeEvent) {
|
||||
const txtChanges = fileChanges.contentChanges.map(c => c.text);
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
|
||||
if (txtChanges.length > 0 && editor && ArticleHelper.isMarkdownFile()) {
|
||||
const config = vscode.workspace.getConfiguration(CONFIG_KEY);
|
||||
const autoUpdate = config.get(SETTING_AUTO_UPDATE_DATE);
|
||||
|
||||
if (autoUpdate) {
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
if (!article) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (article.content === Article.prevContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
Article.prevContent = article.content;
|
||||
|
||||
Article.setLastModifiedDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the article date and return it
|
||||
* @param article
|
||||
|
||||
@@ -3,6 +3,7 @@ import { CONFIG_KEY, SETTING_TEMPLATES_FOLDER } from "../constants";
|
||||
import { join } from "path";
|
||||
import * as fs from "fs";
|
||||
import { Notifications } from "../helpers/Notifications";
|
||||
import { Template } from "./Template";
|
||||
|
||||
export class Project {
|
||||
|
||||
@@ -22,28 +23,43 @@ categories: []
|
||||
/**
|
||||
* Initialize a new "Project" instance.
|
||||
*/
|
||||
public static async init() {
|
||||
public static async init(sampleTemplate: boolean = true) {
|
||||
try {
|
||||
const config = workspace.getConfiguration(CONFIG_KEY);
|
||||
const folder = config.get<string>(SETTING_TEMPLATES_FOLDER);
|
||||
const folder = Template.getSettings();
|
||||
const templatePath = Project.templatePath();
|
||||
|
||||
const workspaceFolders = workspace.workspaceFolders;
|
||||
|
||||
if (!folder || !workspaceFolders || workspaceFolders.length === 0) {
|
||||
if (!folder || !templatePath) {
|
||||
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);
|
||||
if (!fs.existsSync(templatePath.fsPath)) {
|
||||
await workspace.fs.createDirectory(templatePath);
|
||||
}
|
||||
|
||||
fs.writeFileSync(article.fsPath, Project.content, { encoding: "utf-8" });
|
||||
|
||||
Notifications.info("Project initialized successfully.");
|
||||
if (sampleTemplate) {
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template path for the current project
|
||||
*/
|
||||
public static templatePath() {
|
||||
const folder = Template.getSettings();
|
||||
const workspaceFolders = workspace.workspaceFolders;
|
||||
|
||||
if (!folder || !workspaceFolders || workspaceFolders.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const workspaceFolder = workspaceFolders[0];
|
||||
const templatePath = Uri.file(join(workspaceFolder.uri.fsPath, folder));
|
||||
return templatePath;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export class StatusListener {
|
||||
const publishMsg = "to publish";
|
||||
|
||||
let editor = vscode.window.activeTextEditor;
|
||||
if (editor && ArticleHelper.isMarkdownDile()) {
|
||||
if (editor && ArticleHelper.isMarkdownFile()) {
|
||||
try {
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
|
||||
@@ -61,6 +61,11 @@ export class StatusListener {
|
||||
} catch (e) {
|
||||
// Nothing to do
|
||||
}
|
||||
} else {
|
||||
const panel = ExplorerView.getInstance();
|
||||
if (panel && panel.visible) {
|
||||
panel.pushMetadata(null);
|
||||
}
|
||||
}
|
||||
|
||||
frontMatterSB.hide();
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ArticleHelper } from '../helpers';
|
||||
import { Article } from '.';
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
import { CONTEXT } from '../constants/context';
|
||||
import { Project } from './Project';
|
||||
|
||||
export class Template {
|
||||
|
||||
@@ -23,9 +24,8 @@ export class Template {
|
||||
* 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;
|
||||
const folder = Template.getSettings();
|
||||
|
||||
if (!folder || !workspaceFolders || workspaceFolders.length === 0) {
|
||||
return false;
|
||||
@@ -42,6 +42,53 @@ export class Template {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a template
|
||||
*/
|
||||
public static async generate() {
|
||||
const folder = Template.getSettings();
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
|
||||
if (folder && editor && ArticleHelper.isMarkdownFile()) {
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
const clonedArticle = Object.assign({}, article);
|
||||
|
||||
const titleValue = await vscode.window.showInputBox({
|
||||
prompt: `What name would you like to give your template?`,
|
||||
placeHolder: `article`
|
||||
});
|
||||
|
||||
if (!titleValue) {
|
||||
Notifications.warning(`You did not specify a template title.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const keepContents = await vscode.window.showQuickPick(
|
||||
["yes", "no"],
|
||||
{
|
||||
canPickMany: false,
|
||||
placeHolder: `Do you want to keep the article its contents for the template?`,
|
||||
}
|
||||
);
|
||||
|
||||
if (!keepContents) {
|
||||
Notifications.warning(`You did not pick any of the options for keeping the template its content.`);
|
||||
return;
|
||||
}
|
||||
|
||||
await Project.init(false);
|
||||
const templatePath = Project.templatePath();
|
||||
if (templatePath) {
|
||||
let fileContents = ArticleHelper.stringifyFrontMatter(keepContents === "no" ? "" : clonedArticle.content, clonedArticle.data);
|
||||
|
||||
const templateFile = path.join(templatePath.fsPath, `${titleValue}.md`);
|
||||
fs.writeFileSync(templateFile, fileContents, { encoding: "utf-8" });
|
||||
|
||||
Notifications.info(`Template created and is now available in your ${folder} folder.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from a template
|
||||
*/
|
||||
@@ -136,4 +183,13 @@ export class Template {
|
||||
|
||||
Notifications.info(`Your new article has been created.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the folder settings
|
||||
*/
|
||||
public static getSettings() {
|
||||
const config = vscode.workspace.getConfiguration(CONFIG_KEY);
|
||||
const folder = config.get<string>(SETTING_TEMPLATES_FOLDER);
|
||||
return folder;
|
||||
}
|
||||
}
|
||||
@@ -19,5 +19,6 @@ export const COMMAND_NAME = {
|
||||
toggleDraft: getCommandName("toggleDraft"),
|
||||
registerFolder: getCommandName("registerFolder"),
|
||||
unregisterFolder: getCommandName("unregisterFolder"),
|
||||
createContent: getCommandName("createContent")
|
||||
createContent: getCommandName("createContent"),
|
||||
createTemplate: getCommandName("createTemplate")
|
||||
};
|
||||
@@ -7,6 +7,7 @@ export const SETTING_TAXONOMY_CATEGORIES = "taxonomy.categories";
|
||||
export const SETTING_DATE_FORMAT = "taxonomy.dateFormat";
|
||||
export const SETTING_DATE_FIELD = "taxonomy.dateField";
|
||||
export const SETTING_MODIFIED_FIELD = "taxonomy.modifiedField";
|
||||
export const SETTING_AUTO_UPDATE_DATE = "content.autoUpdateDate";
|
||||
|
||||
export const SETTING_SLUG_PREFIX = "taxonomy.slugPrefix";
|
||||
export const SETTING_SLUG_SUFFIX = "taxonomy.slugSuffix";
|
||||
|
||||
@@ -9,7 +9,8 @@ import { TagType } from './viewpanel/TagType';
|
||||
import { ExplorerView } from './webview/ExplorerView';
|
||||
|
||||
let frontMatterStatusBar: vscode.StatusBarItem;
|
||||
let debouncer: { (fnc: any, time: number): void; };
|
||||
let statusDebouncer: { (fnc: any, time: number): void; };
|
||||
let editDebounce: { (fnc: any, time: number): void; };
|
||||
let collection: vscode.DiagnosticCollection;
|
||||
|
||||
export async function activate({ subscriptions, extensionUri }: vscode.ExtensionContext) {
|
||||
@@ -69,6 +70,8 @@ export async function activate({ subscriptions, extensionUri }: vscode.Extension
|
||||
}
|
||||
});
|
||||
|
||||
let createTemplate = vscode.commands.registerCommand(COMMAND_NAME.createTemplate, Template.generate);
|
||||
|
||||
const toggleDraftCommand = COMMAND_NAME.toggleDraft;
|
||||
const toggleDraft = vscode.commands.registerCommand(toggleDraftCommand, async () => {
|
||||
await Article.toggleDraft();
|
||||
@@ -98,13 +101,19 @@ export async function activate({ subscriptions, extensionUri }: vscode.Extension
|
||||
frontMatterStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100);
|
||||
frontMatterStatusBar.command = toggleDraftCommand;
|
||||
subscriptions.push(frontMatterStatusBar);
|
||||
debouncer = debounceShowDraftTrigger();
|
||||
statusDebouncer = debounceCallback();
|
||||
|
||||
// Register listeners that make sure the status bar updates
|
||||
subscriptions.push(vscode.window.onDidChangeActiveTextEditor(triggerShowDraftStatus));
|
||||
subscriptions.push(vscode.window.onDidChangeTextEditorSelection(triggerShowDraftStatus));
|
||||
|
||||
// Automatically run the command
|
||||
triggerShowDraftStatus();
|
||||
|
||||
// Listener for file edit changes
|
||||
editDebounce = debounceCallback();
|
||||
subscriptions.push(vscode.workspace.onDidChangeTextDocument(triggerFileChange));
|
||||
|
||||
// Subscribe all commands
|
||||
subscriptions.push(
|
||||
insertTags,
|
||||
@@ -118,6 +127,7 @@ export async function activate({ subscriptions, extensionUri }: vscode.Extension
|
||||
setLastModifiedDate,
|
||||
generateSlug,
|
||||
createFromTemplate,
|
||||
createTemplate,
|
||||
toggleDraft,
|
||||
registerFolder,
|
||||
unregisterFolder,
|
||||
@@ -128,11 +138,15 @@ export async function activate({ subscriptions, extensionUri }: vscode.Extension
|
||||
|
||||
export function deactivate() {}
|
||||
|
||||
const triggerShowDraftStatus = () => {
|
||||
debouncer(() => { StatusListener.verify(frontMatterStatusBar, collection); }, 1000);
|
||||
const triggerFileChange = (e: vscode.TextDocumentChangeEvent) => {
|
||||
editDebounce(() => Article.autoUpdate(e), 1000);
|
||||
};
|
||||
|
||||
const debounceShowDraftTrigger = () => {
|
||||
const triggerShowDraftStatus = () => {
|
||||
statusDebouncer(() => { StatusListener.verify(frontMatterStatusBar, collection); }, 1000);
|
||||
};
|
||||
|
||||
const debounceCallback = () => {
|
||||
let timeout: NodeJS.Timeout;
|
||||
|
||||
return (fnc: any, time: number) => {
|
||||
|
||||
@@ -100,7 +100,7 @@ export class ArticleHelper {
|
||||
/**
|
||||
* Checks if the current file is a markdown file
|
||||
*/
|
||||
public static isMarkdownDile() {
|
||||
public static isMarkdownFile() {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
return (editor && editor.document && (editor.document.languageId.toLowerCase() === "markdown" || editor.document.languageId.toLowerCase() === "mdx"));
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface PanelSettings {
|
||||
freeform: boolean;
|
||||
scripts: CustomScript[];
|
||||
isInitialized: boolean;
|
||||
modifiedDateUpdate: boolean;
|
||||
contentInfo: FolderInfo[] | null;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,4 +15,6 @@ export enum CommandToCode {
|
||||
runCustomScript = "custom-script",
|
||||
initProject = "init-project",
|
||||
createContent = "create-content",
|
||||
updateModifiedUpdating = "update-modified-updates",
|
||||
createTemplate = "create-template",
|
||||
}
|
||||
@@ -1,19 +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 { GlobalSettings } from './components/GlobalSettings';
|
||||
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 { OtherActions } from './components/OtherActions';
|
||||
import { SeoStatus } from './components/SeoStatus';
|
||||
import { Spinner } from './components/Spinner';
|
||||
import { TagPicker } from './components/TagPicker';
|
||||
import { MessageHelper } from './helper/MessageHelper';
|
||||
import useMessages from './hooks/useMessages';
|
||||
import { TagType } from './TagType';
|
||||
|
||||
@@ -35,21 +31,11 @@ export const ViewPanel: React.FunctionComponent<IViewPanelProps> = (props: React
|
||||
);
|
||||
}
|
||||
|
||||
const openSettings = () => {
|
||||
MessageHelper.sendMessage(CommandToCode.openSettings);
|
||||
};
|
||||
|
||||
const openFile = () => {
|
||||
MessageHelper.sendMessage(CommandToCode.openFile);
|
||||
};
|
||||
|
||||
const openProject = () => {
|
||||
MessageHelper.sendMessage(CommandToCode.openProject);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="frontmatter">
|
||||
<div className={`ext_actions`}>
|
||||
<GlobalSettings settings={settings} />
|
||||
|
||||
{
|
||||
settings && settings.seo && <SeoStatus seo={settings.seo} data={metadata} />
|
||||
}
|
||||
@@ -57,7 +43,7 @@ export const ViewPanel: React.FunctionComponent<IViewPanelProps> = (props: React
|
||||
settings && metadata && <Actions metadata={metadata} settings={settings} />
|
||||
}
|
||||
|
||||
<Collapsible title="Metadata" className={`absolute w-full`}>
|
||||
<Collapsible title="Metadata" className={`inherit z-20`}>
|
||||
{
|
||||
<TagPicker type={TagType.keywords}
|
||||
icon={<SymbolKeywordIcon />}
|
||||
@@ -91,24 +77,8 @@ export const ViewPanel: React.FunctionComponent<IViewPanelProps> = (props: React
|
||||
)
|
||||
}
|
||||
</Collapsible>
|
||||
</div>
|
||||
|
||||
<div className={`ext_settings`}>
|
||||
<div className="ext_link_block">
|
||||
<button onClick={openSettings}><SettingsIcon /> Open settings</button>
|
||||
</div>
|
||||
|
||||
<div className="ext_link_block">
|
||||
<button onClick={openFile}><FileIcon /> Reveal file in folder</button>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<OtherActions isFile={true} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,8 @@ import { PanelSettings } from '../../models';
|
||||
import { CommandToCode } from '../CommandToCode';
|
||||
import { MessageHelper } from '../helper/MessageHelper';
|
||||
import { Collapsible } from './Collapsible';
|
||||
import { GlobalSettings } from './GlobalSettings';
|
||||
import { OtherActions } from './OtherActions';
|
||||
|
||||
export interface IBaseViewProps {
|
||||
settings: PanelSettings | undefined;
|
||||
@@ -21,6 +23,8 @@ export const BaseView: React.FunctionComponent<IBaseViewProps> = ({settings}: Re
|
||||
return (
|
||||
<div className="frontmatter">
|
||||
<div className={`ext_actions`}>
|
||||
<GlobalSettings settings={settings} />
|
||||
|
||||
<Collapsible title="Actions">
|
||||
<div className={`base__actions`}>
|
||||
<button onClick={initProject} disabled={settings?.isInitialized}>Initialize project</button>
|
||||
@@ -43,6 +47,8 @@ export const BaseView: React.FunctionComponent<IBaseViewProps> = ({settings}: Re
|
||||
</Collapsible>
|
||||
)
|
||||
}
|
||||
|
||||
<OtherActions isFile={false} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
28
src/viewpanel/components/GlobalSettings.tsx
Normal file
28
src/viewpanel/components/GlobalSettings.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import * as React from 'react';
|
||||
import { PanelSettings } from '../../models';
|
||||
import { CommandToCode } from '../CommandToCode';
|
||||
import { MessageHelper } from '../helper/MessageHelper';
|
||||
import { Collapsible } from './Collapsible';
|
||||
import { VsCheckbox } from './VscodeComponents';
|
||||
|
||||
export interface IGlobalSettingsProps {
|
||||
settings: PanelSettings | undefined;
|
||||
}
|
||||
|
||||
export const GlobalSettings: React.FunctionComponent<IGlobalSettingsProps> = ({settings}: React.PropsWithChildren<IGlobalSettingsProps>) => {
|
||||
const { modifiedDateUpdate } = settings || {};
|
||||
|
||||
const onCheck = () => {
|
||||
MessageHelper.sendMessage(CommandToCode.updateModifiedUpdating, !modifiedDateUpdate);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Collapsible title="Global settings">
|
||||
<div className={`base__actions`}>
|
||||
<VsCheckbox label="Auto-update modified date" checked={modifiedDateUpdate} onClick={onCheck} />
|
||||
</div>
|
||||
</Collapsible>
|
||||
</>
|
||||
);
|
||||
};
|
||||
11
src/viewpanel/components/Icons/TemplateIcon.tsx
Normal file
11
src/viewpanel/components/Icons/TemplateIcon.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface ITemplateIconProps {}
|
||||
|
||||
export const TemplateIcon: React.FunctionComponent<ITemplateIconProps> = (props: React.PropsWithChildren<ITemplateIconProps>) => {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.3} d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
58
src/viewpanel/components/OtherActions.tsx
Normal file
58
src/viewpanel/components/OtherActions.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import * as React from 'react';
|
||||
import { CommandToCode } from '../CommandToCode';
|
||||
import { MessageHelper } from '../helper/MessageHelper';
|
||||
import { Collapsible } from './Collapsible';
|
||||
import { BugIcon } from './Icons/BugIcon';
|
||||
import { FileIcon } from './Icons/FileIcon';
|
||||
import { FolderOpenedIcon } from './Icons/FolderOpenedIcon';
|
||||
import { SettingsIcon } from './Icons/SettingsIcon';
|
||||
import { TemplateIcon } from './Icons/TemplateIcon';
|
||||
|
||||
export interface IOtherActionsProps {
|
||||
isFile: boolean;
|
||||
}
|
||||
|
||||
export const OtherActions: React.FunctionComponent<IOtherActionsProps> = ({isFile}: React.PropsWithChildren<IOtherActionsProps>) => {
|
||||
|
||||
const openSettings = () => {
|
||||
MessageHelper.sendMessage(CommandToCode.openSettings);
|
||||
};
|
||||
|
||||
const openFile = () => {
|
||||
MessageHelper.sendMessage(CommandToCode.openFile);
|
||||
};
|
||||
|
||||
const openProject = () => {
|
||||
MessageHelper.sendMessage(CommandToCode.openProject);
|
||||
};
|
||||
|
||||
const createAsTemplate = () => {
|
||||
MessageHelper.sendMessage(CommandToCode.createTemplate);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Collapsible title="Other actions" className={`other_actions`}>
|
||||
<div className="ext_link_block">
|
||||
<button onClick={createAsTemplate} disabled={!isFile}><TemplateIcon /> Create as template</button>
|
||||
</div>
|
||||
|
||||
<div className="ext_link_block">
|
||||
<button onClick={openSettings}><SettingsIcon /> Open settings</button>
|
||||
</div>
|
||||
|
||||
<div className="ext_link_block">
|
||||
<button onClick={openFile} disabled={!isFile}><FileIcon /> Reveal file in folder</button>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</Collapsible>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -126,7 +126,7 @@ export const TagPicker: React.FunctionComponent<ITagPickerProps> = (props: React
|
||||
}, [crntSelected]);
|
||||
|
||||
return (
|
||||
<div className={`section article__tags`}>
|
||||
<div className={`article__tags`}>
|
||||
<h3>{icon} {type}</h3>
|
||||
|
||||
<Downshift ref={dsRef}
|
||||
|
||||
@@ -6,4 +6,5 @@ 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`);
|
||||
export const VsCollapsible = wrapWc(`vscode-collapsible`);
|
||||
export const VsCheckbox = wrapWc(`vscode-checkbox`);
|
||||
@@ -10,6 +10,7 @@ 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';
|
||||
import '@bendera/vscode-webview-elements/dist/vscode-checkbox';
|
||||
|
||||
declare const acquireVsCodeApi: <T = unknown>() => {
|
||||
getState: () => T;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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 { SETTING_AUTO_UPDATE_DATE, 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";
|
||||
@@ -146,6 +146,12 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
case CommandToCode.createContent:
|
||||
await commands.executeCommand(COMMAND_NAME.createContent);
|
||||
break;
|
||||
case CommandToCode.createTemplate:
|
||||
await commands.executeCommand(COMMAND_NAME.createTemplate);
|
||||
break;
|
||||
case CommandToCode.updateModifiedUpdating:
|
||||
this.updateModifiedUpdating(msg.data || false);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -262,7 +268,8 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
freeform: config.get(SETTING_PANEL_FREEFORM),
|
||||
scripts: config.get(SETTING_CUSTOM_SCRIPTS),
|
||||
isInitialized: await Template.isInitialized(),
|
||||
contentInfo: await Folders.getInfo() || null
|
||||
contentInfo: await Folders.getInfo() || null,
|
||||
modifiedDateUpdate: config.get(SETTING_AUTO_UPDATE_DATE) || false
|
||||
} as PanelSettings
|
||||
});
|
||||
}
|
||||
@@ -328,7 +335,7 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!ArticleHelper.isMarkdownDile()) {
|
||||
if (!ArticleHelper.isMarkdownFile()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -376,6 +383,12 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private async updateModifiedUpdating(autoUpdate: boolean) {
|
||||
const config = workspace.getConfiguration(CONFIG_KEY);
|
||||
await config.update(SETTING_AUTO_UPDATE_DATE, autoUpdate);
|
||||
this.getSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Post data to the panel
|
||||
* @param msg
|
||||
|
||||
Reference in New Issue
Block a user