mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-08-07 09:23:00 +02:00
#51 - Default panel actions
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
- [#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
|
||||
|
||||
|
||||
@@ -53,7 +53,13 @@ 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.
|
||||
|
||||
The panel consists of the following sections:
|
||||
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**
|
||||
|
||||
|
||||
@@ -248,7 +248,9 @@
|
||||
filter: contrast(60%);
|
||||
}
|
||||
|
||||
.article__actions > * + * {
|
||||
.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));
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
+30
-2
@@ -1,7 +1,7 @@
|
||||
import { commands, Uri, workspace, window } from "vscode";
|
||||
import { CONFIG_KEY, EXTENSION_NAME, SETTINGS_CONTENT_FOLDERS } from "../constants";
|
||||
import { CONFIG_KEY, SETTINGS_CONTENT_FOLDERS } from "../constants";
|
||||
import { basename } from "path";
|
||||
import { ContentFolder } from "../models";
|
||||
import { ContentFolder, FolderInfo } from "../models";
|
||||
import uniqBy = require("lodash.uniqby");
|
||||
import { Template } from "./Template";
|
||||
import { Notifications } from "../helpers/Notifications";
|
||||
@@ -118,6 +118,34 @@ export class Folders {
|
||||
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
|
||||
|
||||
@@ -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" || editor.document.languageId.toLowerCase() === "mdx")) {
|
||||
if (editor && ArticleHelper.isMarkdownDile()) {
|
||||
try {
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
|
||||
|
||||
@@ -15,24 +15,30 @@ 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) {
|
||||
vscode.commands.executeCommand('setContext', CONTEXT.canInit, true);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const workspaceFolder = workspaceFolders[0];
|
||||
const templatePath = vscode.Uri.file(path.join(workspaceFolder.uri.fsPath, folder));
|
||||
|
||||
try {
|
||||
await vscode.workspace.fs.stat(templatePath);
|
||||
vscode.commands.executeCommand('setContext', CONTEXT.canInit, false);
|
||||
return true;
|
||||
} catch (e) {
|
||||
vscode.commands.executeCommand('setContext', CONTEXT.canInit, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ export interface PanelSettings {
|
||||
categories: string[];
|
||||
freeform: boolean;
|
||||
scripts: CustomScript[];
|
||||
isInitialized: boolean;
|
||||
contentInfo: FolderInfo[] | null;
|
||||
}
|
||||
|
||||
export interface SEO {
|
||||
@@ -20,6 +22,11 @@ export interface Slug {
|
||||
suffix: number;
|
||||
}
|
||||
|
||||
export interface FolderInfo {
|
||||
title: string;
|
||||
files: number;
|
||||
}
|
||||
|
||||
export interface CustomScript {
|
||||
title: string;
|
||||
script: string;
|
||||
|
||||
@@ -12,5 +12,7 @@ export enum CommandToCode {
|
||||
openSettings = "open-settings",
|
||||
openFile = "open-file",
|
||||
openProject = "open-project",
|
||||
runCustomScript = "custom-script"
|
||||
runCustomScript = "custom-script",
|
||||
initProject = "init-project",
|
||||
createContent = "create-content",
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export const ViewPanel: React.FunctionComponent<IViewPanelProps> = (props: React
|
||||
|
||||
if (!metadata || Object.keys(metadata).length === 0) {
|
||||
return (
|
||||
<BaseView />
|
||||
<BaseView settings={settings} />
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +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 {}
|
||||
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);
|
||||
};
|
||||
|
||||
export const BaseView: React.FunctionComponent<IBaseViewProps> = (props: React.PropsWithChildren<IBaseViewProps>) => {
|
||||
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>
|
||||
);
|
||||
};
|
||||
+30
-15
@@ -1,3 +1,4 @@
|
||||
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';
|
||||
@@ -14,6 +15,8 @@ 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 {
|
||||
@@ -75,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();
|
||||
@@ -136,6 +139,13 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CommandToCode.initProject:
|
||||
await commands.executeCommand(COMMAND_NAME.init);
|
||||
this.getSettings();
|
||||
break;
|
||||
case CommandToCode.createContent:
|
||||
await commands.executeCommand(COMMAND_NAME.createContent);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -162,10 +172,15 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
* @param metadata
|
||||
*/
|
||||
public pushMetadata(metadata: any) {
|
||||
const articleDetails = this.getArticleDetails();
|
||||
|
||||
if (articleDetails) {
|
||||
metadata.articleDetails = articleDetails;
|
||||
}
|
||||
|
||||
this.postWebviewMessage({ command: Command.metadata, data: {
|
||||
...metadata,
|
||||
articleDetails: this.getArticleDetails()
|
||||
} });
|
||||
...metadata
|
||||
}});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,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({
|
||||
@@ -245,7 +260,9 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
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
|
||||
});
|
||||
}
|
||||
@@ -260,10 +277,7 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
}
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
this.postWebviewMessage({ command: Command.metadata, data: {
|
||||
...article!.data,
|
||||
articleDetails: this.getArticleDetails()
|
||||
}});
|
||||
this.pushMetadata(article!.data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,10 +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,
|
||||
articleDetails: this.getArticleDetails()
|
||||
}});
|
||||
this.pushMetadata(article!.data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,7 +325,11 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
|
||||
private getArticleDetails() {
|
||||
const editor = window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return "";
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!ArticleHelper.isMarkdownDile()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
|
||||
Reference in New Issue
Block a user