diff --git a/CHANGELOG.md b/CHANGELOG.md index b30618f3..aa54654a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 0931003d..714b4a7f 100644 --- a/README.md +++ b/README.md @@ -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: + +

+ Base view +

+ +When you open the Front Matter panel on a Markdown file, you get to see the following sections: **SEO Status** diff --git a/assets/media/styles.css b/assets/media/styles.css index 526bf6c5..d74a8202 100644 --- a/assets/media/styles.css +++ b/assets/media/styles.css @@ -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)); diff --git a/assets/v2.2.0/baseview.png b/assets/v2.2.0/baseview.png new file mode 100644 index 00000000..9f3fda5f Binary files /dev/null and b/assets/v2.2.0/baseview.png differ diff --git a/src/commands/Folders.ts b/src/commands/Folders.ts index 346950dd..8dd4765a 100644 --- a/src/commands/Folders.ts +++ b/src/commands/Folders.ts @@ -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 { + 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 diff --git a/src/commands/StatusListener.ts b/src/commands/StatusListener.ts index e941d4b1..af1df44b 100644 --- a/src/commands/StatusListener.ts +++ b/src/commands/StatusListener.ts @@ -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); diff --git a/src/commands/Template.ts b/src/commands/Template.ts index b00760f4..47d24af5 100644 --- a/src/commands/Template.ts +++ b/src/commands/Template.ts @@ -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(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; } } diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts index 894b5145..b4947721 100644 --- a/src/helpers/ArticleHelper.ts +++ b/src/helpers/ArticleHelper.ts @@ -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")); + } } \ No newline at end of file diff --git a/src/models/PanelSettings.ts b/src/models/PanelSettings.ts index d15018f6..f2bfb351 100644 --- a/src/models/PanelSettings.ts +++ b/src/models/PanelSettings.ts @@ -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; diff --git a/src/viewpanel/CommandToCode.ts b/src/viewpanel/CommandToCode.ts index ebb4cdf1..1dc29d3c 100644 --- a/src/viewpanel/CommandToCode.ts +++ b/src/viewpanel/CommandToCode.ts @@ -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", } \ No newline at end of file diff --git a/src/viewpanel/ViewPanel.tsx b/src/viewpanel/ViewPanel.tsx index df782697..e2e279ea 100644 --- a/src/viewpanel/ViewPanel.tsx +++ b/src/viewpanel/ViewPanel.tsx @@ -31,7 +31,7 @@ export const ViewPanel: React.FunctionComponent = (props: React if (!metadata || Object.keys(metadata).length === 0) { return ( - + ); } diff --git a/src/viewpanel/components/BaseView.tsx b/src/viewpanel/components/BaseView.tsx index ba717605..4d022f7c 100644 --- a/src/viewpanel/components/BaseView.tsx +++ b/src/viewpanel/components/BaseView.tsx @@ -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 = ({settings}: React.PropsWithChildren) => { + + const initProject = () => { + MessageHelper.sendMessage(CommandToCode.initProject); + }; + + const createContent = () => { + MessageHelper.sendMessage(CommandToCode.createContent); + }; -export const BaseView: React.FunctionComponent = (props: React.PropsWithChildren) => { return (
- +
+ +
+ + +
+
+ + { + settings?.contentInfo && ( + +
+ { + settings.contentInfo.map(folder => ( +
+ {folder.title}: {folder.files} file{folder.files > 1 ? 's' : ''} +
+ )) + } +
+
+ ) + } +
); }; \ No newline at end of file diff --git a/src/webview/ExplorerView.ts b/src/webview/ExplorerView.ts index c53f11f0..4fc494f1 100644 --- a/src/webview/ExplorerView.ts +++ b/src/webview/ExplorerView.ts @@ -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);