Compare commits

...

12 Commits

Author SHA1 Message Date
Elio Struyf
c9d3eca431 Merge branch 'main' of github.com:estruyf/vscode-front-matter into main 2021-08-16 12:30:29 +02:00
Elio Struyf
486beaf650 2.4.0 2021-08-16 12:30:17 +02:00
Elio Struyf
6e82cf221e Updated changelog 2021-08-16 12:30:10 +02:00
Elio Struyf
46b9591859 Merge pull request #54 from estruyf/dependabot/npm_and_yarn/path-parse-1.0.7
Bump path-parse from 1.0.6 to 1.0.7
2021-08-16 12:29:40 +02:00
Elio Struyf
3e76da58f5 Updated documentation 2021-08-16 12:28:55 +02:00
Elio Struyf
9d42bd2f97 Update highlighting + documentation 2021-08-16 11:38:51 +02:00
Elio Struyf
75890ec6e8 #55 #56 #57 #58 #59 - multiple enhancements that are linked 2021-08-13 13:33:05 +02:00
Elio Struyf
fb0429e40f Updated changelog 2021-08-12 17:24:17 +02:00
Elio Struyf
8db813a661 #21 - Implemented the folding provider for front matter 2021-08-12 17:15:08 +02:00
dependabot[bot]
2655be9aae Bump path-parse from 1.0.6 to 1.0.7
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-11 09:39:10 +00:00
Elio Struyf
fc99756136 Merge branch 'main' of github.com:estruyf/vscode-front-matter into main 2021-08-10 20:09:53 +02:00
Elio Struyf
9159a98dbe Fix image URL 2021-08-10 20:09:46 +02:00
36 changed files with 418 additions and 86 deletions

View File

@@ -1,5 +1,14 @@
# Change Log
## [2.4.0] - 2020-08-16
- [#21](https://github.com/estruyf/vscode-front-matter/issues/21): Folding provider for Front Matter implemented
- [#55](https://github.com/estruyf/vscode-front-matter/issues/55): Highlight Front Matter in Markdown files
- [#56](https://github.com/estruyf/vscode-front-matter/issues/56): Action to collapse all Front Matter panel sections at once
- [#57](https://github.com/estruyf/vscode-front-matter/issues/57): New action added to provide better writing settings (only for Markdown files)
- [#58](https://github.com/estruyf/vscode-front-matter/issues/58): Sections remember their previous state (folded/unfolded)
- [#59](https://github.com/estruyf/vscode-front-matter/issues/59): Center layout view toggle action added
## [2.3.0] - 2020-08-10
- Refactoring and showing other actions in the base view

View File

@@ -35,6 +35,7 @@ In version v2.0.0 we released the newly redesigned sidebar panel with improved S
<details open="open">
<summary>Table of Contents</summary>
<ol>
<li><a href="#markdown-features">Markdown features</a></li>
<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>
@@ -45,6 +46,24 @@ In version v2.0.0 we released the newly redesigned sidebar panel with improved S
</ol>
</details>
## Markdown features
The Front Matter extension tries to make it easy to manage your Markdown pages/content. Within a Markdown page, we allow you to fold the file's Front Matter to be less distracting when writing. Also, do we highlight the Front Matter content to create a visual difference between content and metadata.
### Front Matter folding
<p align="center">
<img src="./assets/v2.4.0/folding.png" alt="Front Matter folding" style="display: inline-block" />
</p>
### Front Matter highlighting
<p align="center">
<img src="./assets/v2.4.0/fm-highlight.png" alt="Front Matter highlighting" style="display: inline-block" />
</p>
> **Info**: If you do not want this feature, you can disable it in the extension settings -> `Highlight Front Matter` or by setting the `frontMatter.content.fmHighlight` setting to `false`.
## 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.
@@ -56,7 +75,7 @@ To leverage most of the capabilities of the extension. SEO information and every
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.3.0/baseview.png" alt="Base view" style="display: inline-block" />
<img src="./assets/v2.4.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.
@@ -66,7 +85,7 @@ When you open the Front Matter panel on a Markdown file, you get to see the foll
**Global Settings**
<p align="center">
<img src="./assets/v2.3.0/global-settings.png.png" alt="Global settings" style="display: inline-block" />
<img src="./assets/v2.4.0/global-settings.png" alt="Global settings" style="display: inline-block" />
</p>
**SEO Status**
@@ -78,7 +97,7 @@ When you open the Front Matter panel on a Markdown file, you get to see the foll
**Actions**
<p align="center">
<img src="./assets/v2.0.0/actions.png" alt="Actions" style="display: inline-block" />
<img src="./assets/v2.4.0/actions.png" alt="Actions" style="display: inline-block" />
</p>
**Metadata: Keywords, Tags, Categories**
@@ -92,9 +111,11 @@ When you open the Front Matter panel on a Markdown file, you get to see the foll
**Other actions**
<p align="center">
<img src="./assets/v2.3.0/other-actions.png" alt="Other actions" style="display: inline-block" />
<img src="./assets/v2.4.0/other-actions.png" alt="Other actions" style="display: inline-block" />
</p>
**Info**: The `Enable write settings` action allow you to make Markdown specific changes to optimize the writing of your articles. It will change settings like the `fontSize`, `lineHeight`, `wordWrap`, `lineNumbers` and more.
## 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.
@@ -373,6 +394,16 @@ Specify if you want to automatically update the modification date of your markdo
}
```
### `frontMatter.content.fmHighlight`
Specify if you want to highlight the Front Matter in the Markdown file. Default: `true`.
```json
{
"frontMatter.content.fmHighlight": true
}
```
## Feedback / issues / ideas
Please submit them via creating an issue in the project repository: [issue list](https://github.com/estruyf/vscode-front-matter/issues).

View File

@@ -0,0 +1,4 @@
<svg width="32px" height="32px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#F3EFF5">
<path d="M9 9H4v1h5V9z" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 3l1-1h7l1 1v7l-1 1h-2v2l-1 1H3l-1-1V6l1-1h2V3zm1 2h4l1 1v4h2V3H6v2zm4 1H3v7h7V6z" />
</svg>

After

Width:  |  Height:  |  Size: 277 B

View File

@@ -0,0 +1,4 @@
<svg width="32px" height="32px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentcolor">
<path d="M9 9H4v1h5V9z" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 3l1-1h7l1 1v7l-1 1h-2v2l-1 1H3l-1-1V6l1-1h2V3zm1 2h4l1 1v4h2V3H6v2zm4 1H3v7h7V6z" />
</svg>

After

Width:  |  Height:  |  Size: 282 B

View File

@@ -278,10 +278,21 @@
.ext_link_block {
display: flex;
align-items: center;
width: 100%;
}
.ext_link_block svg {
margin-right: .5rem;
display: block;
width: 16px;
height: 16px;
min-width: 16px;
}
.ext_link_block button span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ext_link_block button,
@@ -301,6 +312,16 @@
user-select: none;
text-decoration: none;
width: 100%;
white-space: nowrap;
}
.ext_link_block button.active {
color: var(--vscode-button-foreground);
background: var(--vscode-button-background);
}
.ext_link_block button.active:hover {
cursor: pointer;
background: var(--vscode-button-hoverBackground);
}
.ext_link_block a:hover,

BIN
assets/v2.4.0/actions.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
assets/v2.4.0/baseview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
assets/v2.4.0/folding.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

8
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "vscode-front-matter",
"version": "2.3.0",
"version": "2.4.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -3565,9 +3565,9 @@
"dev": true
},
"path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"pbkdf2": {

View File

@@ -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.3.0",
"version": "2.4.0",
"preview": false,
"publisher": "eliostruyf",
"galleryBanner": {
@@ -57,6 +57,7 @@
"onCommand:frontMatter.unregisterFolder",
"onCommand:frontMatter.createContent",
"onCommand:frontMatter.init",
"onCommand:frontMatter.collapseSections",
"onView:frontMatter.explorer"
],
"main": "./dist/extension",
@@ -84,6 +85,31 @@
"configuration": {
"title": "Front Matter: Configuration",
"properties": {
"frontMatter.content.autoUpdateDate": {
"type": "boolean",
"default": false,
"description": "Specify if you want to automatically update the modified date of your article/page."
},
"frontMatter.content.fmHighlight": {
"type": "boolean",
"default": true,
"description": "Specify if you want to highlight the Front Matter in the Markdown file."
},
"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."
},
"frontMatter.custom.scripts": {
"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.panel.freeform": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies if you want to allow yourself from entering unknown tags/categories in the tag picker (when enabled, you will have the option to store them afterwards). Default: true."
},
"frontMatter.taxonomy.dateField": {
"type": "string",
"default": "date",
@@ -94,11 +120,6 @@
"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"
@@ -175,21 +196,6 @@
"type": "string",
"default": "yyyy-MM-dd",
"description": "Specify the prefix you want to add for your new article filenames."
},
"frontMatter.panel.freeform": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies if you want to allow yourself from entering unknown tags/categories in the tag picker (when enabled, you will have the option to store them afterwards). Default: true."
},
"frontMatter.custom.scripts": {
"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."
}
}
},
@@ -268,6 +274,15 @@
"command": "frontMatter.createTemplate",
"title": "Create a template from current file",
"category": "Front matter"
},
{
"command": "frontMatter.collapseSections",
"title": "Collapse sections",
"category": "Front matter",
"icon": {
"light": "assets/icons/close-light.svg",
"dark": "assets/icons/close-dark.svg"
}
}
],
"menus": {
@@ -296,6 +311,16 @@
{
"command": "frontMatter.createTemplate",
"when": "!frontMatterCanInit"
},
{
"command": "frontMatter.collapseSections",
"when": "false"
}
],
"view/title": [
{
"command": "frontMatter.collapseSections",
"group": "navigation"
}
]
},

View File

@@ -20,5 +20,6 @@ export const COMMAND_NAME = {
registerFolder: getCommandName("registerFolder"),
unregisterFolder: getCommandName("unregisterFolder"),
createContent: getCommandName("createContent"),
createTemplate: getCommandName("createTemplate")
createTemplate: getCommandName("createTemplate"),
collapseSections: getCommandName("collapseSections"),
};

View File

@@ -7,7 +7,6 @@ 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";
@@ -30,4 +29,6 @@ export const SETTING_PANEL_FREEFORM = "panel.freeform";
export const SETTING_CUSTOM_SCRIPTS = "custom.scripts";
export const SETTINGS_CONTENT_FOLDERS = "content.folders";
export const SETTING_AUTO_UPDATE_DATE = "content.autoUpdateDate";
export const SETTINGS_CONTENT_FOLDERS = "content.folders";
export const SETTINGS_CONTENT_FRONTMATTER_HIGHLIGHT = "content.fmHighlight";

View File

@@ -5,6 +5,7 @@ import { Project } from './commands/Project';
import { Template } from './commands/Template';
import { COMMAND_NAME } from './constants/Extension';
import { TaxonomyType } from './models';
import { MarkdownFoldingProvider } from './providers/MarkdownFoldingProvider';
import { TagType } from './viewpanel/TagType';
import { ExplorerView } from './webview/ExplorerView';
@@ -13,6 +14,8 @@ let statusDebouncer: { (fnc: any, time: number): void; };
let editDebounce: { (fnc: any, time: number): void; };
let collection: vscode.DiagnosticCollection;
const mdSelector: vscode.DocumentSelector = { language: 'markdown', scheme: 'file' };
export async function activate({ subscriptions, extensionUri }: vscode.ExtensionContext) {
collection = vscode.languages.createDiagnosticCollection('frontMatter');
@@ -23,6 +26,9 @@ export async function activate({ subscriptions, extensionUri }: vscode.Extension
}
});
// Folding the front matter of markdown files
vscode.languages.registerFoldingRangeProvider(mdSelector, new MarkdownFoldingProvider());
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');
@@ -68,7 +74,7 @@ export async function activate({ subscriptions, extensionUri }: vscode.Extension
if (folderPath) {
Template.create(folderPath);
}
});
});
let createTemplate = vscode.commands.registerCommand(COMMAND_NAME.createTemplate, Template.generate);
@@ -91,6 +97,11 @@ export async function activate({ subscriptions, extensionUri }: vscode.Extension
Template.init();
const projectInit = vscode.commands.registerCommand(COMMAND_NAME.init, Project.init);
// Collapse all sections in the webview
const collapseAll = vscode.commands.registerCommand(COMMAND_NAME.collapseSections, () => {
ExplorerView.getInstance()?.collapseAll();
});
// Things to do when configuration changes
vscode.workspace.onDidChangeConfiguration(() => {
Template.init();
@@ -132,7 +143,8 @@ export async function activate({ subscriptions, extensionUri }: vscode.Extension
registerFolder,
unregisterFolder,
createContent,
projectInit
projectInit,
collapseAll
);
}

View File

@@ -9,6 +9,8 @@ export interface PanelSettings {
isInitialized: boolean;
modifiedDateUpdate: boolean;
contentInfo: FolderInfo[] | null;
writingSettingsEnabled: boolean;
fmHighlighting: boolean;
}
export interface SEO {

View File

@@ -0,0 +1,13 @@
import { TextEditorDecorationType, window, ColorThemeKind } from "vscode";
export class FrontMatterDecorationProvider {
get(): TextEditorDecorationType {
const colorThemeKind = window.activeColorTheme.kind;
return window.createTextEditorDecorationType({
backgroundColor: colorThemeKind === ColorThemeKind.Dark ? "#ffffff14" : "#00000014",
isWholeLine: true,
});
}
}

View File

@@ -0,0 +1,57 @@
import { workspace } from 'vscode';
import { CancellationToken, FoldingContext, FoldingRange, FoldingRangeKind, FoldingRangeProvider, Range, TextDocument, window, Position } from 'vscode';
import { CONFIG_KEY, SETTINGS_CONTENT_FRONTMATTER_HIGHLIGHT } from '../constants';
import { FrontMatterDecorationProvider } from './FrontMatterDecorationProvider';
export class MarkdownFoldingProvider implements FoldingRangeProvider {
private static start: number | null = null;
private static end: number | null = null;
private static endLine: number | null = null;
public async provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken): Promise<FoldingRange[]> {
const ranges: FoldingRange[] = [];
const lines = document.getText().split('\n');
let start: number | null = null;
let end: number | null = null;
MarkdownFoldingProvider.start = null;
MarkdownFoldingProvider.end = null;
MarkdownFoldingProvider.endLine = null;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.startsWith('---')) {
if (i === 0 && start === null) {
start = i;
MarkdownFoldingProvider.start = start;
} else if (start !== null && end === null) {
end = i;
MarkdownFoldingProvider.end = end;
MarkdownFoldingProvider.endLine = line.length;
MarkdownFoldingProvider.triggerHighlighting();
ranges.push(new FoldingRange(start, end, FoldingRangeKind.Region));
return ranges;
}
}
}
return ranges;
}
public static triggerHighlighting() {
const config = workspace.getConfiguration(CONFIG_KEY);
const fmHighlight = config.get<boolean>(SETTINGS_CONTENT_FRONTMATTER_HIGHLIGHT);
if (MarkdownFoldingProvider.start !== null && MarkdownFoldingProvider.end !== null && MarkdownFoldingProvider.endLine !== null) {
const range = new Range(new Position(MarkdownFoldingProvider.start, 0), new Position(MarkdownFoldingProvider.end, MarkdownFoldingProvider.endLine));
if (fmHighlight) {
const decoration = new FrontMatterDecorationProvider().get();
window.activeTextEditor?.setDecorations(decoration, [range]);
}
}
}
}

View File

@@ -3,5 +3,6 @@ export enum Command {
metadata = "metadata",
settings = "settings",
focusOnTags = "focusOnTags",
focusOnCategories = "focusOnCategories"
focusOnCategories = "focusOnCategories",
closeSections = "closeSections",
}

View File

@@ -16,5 +16,8 @@ export enum CommandToCode {
initProject = "init-project",
createContent = "create-content",
updateModifiedUpdating = "update-modified-updates",
updateFmHighlight = "update-fm-highlight",
createTemplate = "create-template",
toggleCenterMode = "toggle-center-mode",
toggleWritingSettings = "toggle-writing-settings",
}

View File

@@ -43,7 +43,7 @@ export const ViewPanel: React.FunctionComponent<IViewPanelProps> = (props: React
settings && metadata && <Actions metadata={metadata} settings={settings} />
}
<Collapsible title="Metadata" className={`inherit z-20`}>
<Collapsible id={`tags`} title="Metadata" className={`inherit z-20`}>
{
<TagPicker type={TagType.keywords}
icon={<SymbolKeywordIcon />}
@@ -78,7 +78,7 @@ export const ViewPanel: React.FunctionComponent<IViewPanelProps> = (props: React
}
</Collapsible>
<OtherActions isFile={true} />
<OtherActions settings={settings} isFile={true} />
</div>
</div>
);

View File

@@ -0,0 +1,16 @@
import * as React from 'react';
export interface IActionButtonProps {
title: string;
className?: string;
disabled?: boolean;
onClick: (e: React.SyntheticEvent<HTMLButtonElement>) => void;
}
export const ActionButton: React.FunctionComponent<IActionButtonProps> = ({className, onClick, disabled,title}: React.PropsWithChildren<IActionButtonProps>) => {
return (
<div className={`article__action`}>
<button onClick={onClick} className={className || ""} disabled={disabled}>{title}</button>
</div>
);
};

View File

@@ -1,5 +1,8 @@
import * as React from 'react';
import { PanelSettings } from '../../models/PanelSettings';
import { CommandToCode } from '../CommandToCode';
import { MessageHelper } from '../helper/MessageHelper';
import { ActionButton } from './ActionButton';
import { Collapsible } from './Collapsible';
import { CustomScript } from './CustomScript';
import { DateAction } from './DateAction';
@@ -19,8 +22,11 @@ export const Actions: React.FunctionComponent<IActionsProps> = (props: React.Pro
}
return (
<Collapsible title="Actions">
<Collapsible id={`actions`} title="Actions">
<div className={`article__actions`}>
<ActionButton onClick={() => MessageHelper.sendMessage(CommandToCode.toggleCenterMode)} title={`Toggle center mode`} />
{ metadata && metadata.title && <SlugAction value={metadata.title} crntValue={metadata.slug} slugOpts={settings.slug} /> }
<DateAction />

View File

@@ -23,9 +23,9 @@ export const BaseView: React.FunctionComponent<IBaseViewProps> = ({settings}: Re
return (
<div className="frontmatter">
<div className={`ext_actions`}>
<GlobalSettings settings={settings} />
<GlobalSettings settings={settings} isBase />
<Collapsible title="Actions">
<Collapsible id={`base_actions`} 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>
@@ -34,7 +34,7 @@ export const BaseView: React.FunctionComponent<IBaseViewProps> = ({settings}: Re
{
settings?.contentInfo && (
<Collapsible title="Content information">
<Collapsible id={`base_content`} title="Content information">
<div className="base__information">
{
settings.contentInfo.map(folder => (
@@ -48,7 +48,7 @@ export const BaseView: React.FunctionComponent<IBaseViewProps> = ({settings}: Re
)
}
<OtherActions isFile={false} />
<OtherActions settings={settings} isFile={false} isBase />
</div>
</div>
);

View File

@@ -1,14 +1,22 @@
import * as React from 'react';
import { useEffect } from 'react';
import { Command } from '../Command';
import { VsCollapsible } from './VscodeComponents';
export interface ICollapsibleProps {
id: string;
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);
export const Collapsible: React.FunctionComponent<ICollapsibleProps> = ({id, children, title, sendUpdate, className}: React.PropsWithChildren<ICollapsibleProps>) => {
const [ isOpen, setIsOpen ] = React.useState(false);
const collapseKey = `collapse-${id}`;
const updateStorage = (value: boolean) => {
window.localStorage.setItem(collapseKey, value.toString());
}
// This is a work around for a lit-element issue of duplicate slot names
const triggerClick = (e: React.MouseEvent<HTMLElement>) => {
@@ -17,11 +25,29 @@ export const Collapsible: React.FunctionComponent<ICollapsibleProps> = ({childre
if (sendUpdate) {
sendUpdate(!prev);
}
updateStorage(!prev);
return !prev;
});
}
}
useEffect(() => {
const collapsed = window.localStorage.getItem(collapseKey);
if (collapsed === null || collapsed === 'true') {
setIsOpen(true);
updateStorage(true);
}
window.addEventListener('message', event => {
const message = event.data;
if (message.command === Command.closeSections) {
setIsOpen(false);
updateStorage(false);
}
});
}, ['']);
return (
<VsCollapsible title={title} onClick={triggerClick} open={isOpen}>
<div className={`section collapsible__body ${className || ""}`} slot="body">

View File

@@ -1,6 +1,7 @@
import * as React from 'react';
import { CommandToCode } from '../CommandToCode';
import { MessageHelper } from '../helper/MessageHelper';
import { ActionButton } from './ActionButton';
export interface ICustomScriptProps {
title: string;
@@ -14,8 +15,6 @@ export const CustomScript: React.FunctionComponent<ICustomScriptProps> = ({title
};
return (
<div className={`article__action`}>
<button onClick={runCustomScript}>{title}</button>
</div>
<ActionButton onClick={runCustomScript} title={title} />
);
};

View File

@@ -1,6 +1,7 @@
import * as React from 'react';
import { CommandToCode } from '../CommandToCode';
import { MessageHelper } from '../helper/MessageHelper';
import { ActionButton } from './ActionButton';
export interface IDateActionProps {}
@@ -16,12 +17,8 @@ export const DateAction: React.FunctionComponent<IDateActionProps> = (props: Rea
return (
<>
<div className={`article__action`}>
<button onClick={setDate}>Set publish date</button>
</div>
<div className={`article__action`}>
<button onClick={setLastMod}>Set modified date</button>
</div>
<ActionButton onClick={setDate} title={`Set publish date`} />
<ActionButton onClick={setLastMod} title={`Set modified date`} />
</>
);
};

View File

@@ -7,20 +7,28 @@ import { VsCheckbox } from './VscodeComponents';
export interface IGlobalSettingsProps {
settings: PanelSettings | undefined;
isBase?: boolean;
}
export const GlobalSettings: React.FunctionComponent<IGlobalSettingsProps> = ({settings}: React.PropsWithChildren<IGlobalSettingsProps>) => {
const { modifiedDateUpdate } = settings || {};
export const GlobalSettings: React.FunctionComponent<IGlobalSettingsProps> = ({settings, isBase}: React.PropsWithChildren<IGlobalSettingsProps>) => {
const { modifiedDateUpdate, fmHighlighting } = settings || {};
const onCheck = () => {
const onDateCheck = () => {
MessageHelper.sendMessage(CommandToCode.updateModifiedUpdating, !modifiedDateUpdate);
};
const onHighlightCheck = () => {
MessageHelper.sendMessage(CommandToCode.updateFmHighlight, !fmHighlighting);
};
return (
<>
<Collapsible title="Global settings">
<Collapsible id={`${isBase ? "base_" : ""}settings`} title="Global settings">
<div className={`base__actions`}>
<VsCheckbox label="Auto-update modified date" checked={modifiedDateUpdate} onClick={onCheck} />
<VsCheckbox label="Auto-update modified date" checked={modifiedDateUpdate} onClick={onDateCheck} />
</div>
<div className={`base__actions`}>
<VsCheckbox label="Highlight Front Matter" checked={fmHighlighting} onClick={onHighlightCheck} />
</div>
</Collapsible>
</>

View File

@@ -0,0 +1,9 @@
import * as React from 'react';
export interface IWritingIconProps {}
export const WritingIcon: React.FunctionComponent<IWritingIconProps> = (props: React.PropsWithChildren<IWritingIconProps>) => {
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.223 10.933c.326.192.699.29 1.077.282a2.159 2.159 0 0 0 1.754-.842 3.291 3.291 0 0 0 .654-2.113 2.886 2.886 0 0 0-.576-1.877 1.99 1.99 0 0 0-1.634-.733 2.294 2.294 0 0 0-1.523.567V3.475h-.991V11.1h.995v-.344c.076.066.158.125.244.177zM7.85 6.7c.186-.079.388-.113.59-.1a1.08 1.08 0 0 1 .896.428c.257.363.382.802.357 1.245a2.485 2.485 0 0 1-.4 1.484 1.133 1.133 0 0 1-.96.508 1.224 1.224 0 0 1-.976-.417A1.522 1.522 0 0 1 6.975 8.8v-.6a1.722 1.722 0 0 1 .393-1.145c.13-.154.296-.276.482-.355zM3.289 5.675a3.03 3.03 0 0 0-.937.162 2.59 2.59 0 0 0-.8.4l-.1.077v1.2l.423-.359a2.1 2.1 0 0 1 1.366-.572.758.758 0 0 1 .661.282c.15.232.23.503.231.779L2.9 7.825a2.6 2.6 0 0 0-1.378.575 1.65 1.65 0 0 0-.022 2.336 1.737 1.737 0 0 0 1.253.454 1.96 1.96 0 0 0 1.107-.332c.102-.068.197-.145.286-.229v.444h.941V7.715a2.193 2.193 0 0 0-.469-1.5 1.687 1.687 0 0 0-1.329-.54zm.857 3.041c.02.418-.12.829-.391 1.148a1.221 1.221 0 0 1-.955.422.832.832 0 0 1-.608-.2.833.833 0 0 1 0-1.091c.281-.174.6-.277.93-.3l1.02-.148.004.169zm8.313 2.317c.307.13.64.193.973.182.495.012.983-.114 1.41-.365l.123-.075.013-.007V9.615l-.446.32c-.316.224-.696.34-1.084.329A1.3 1.3 0 0 1 12.4 9.8a1.975 1.975 0 0 1-.4-1.312 2.01 2.01 0 0 1 .453-1.381A1.432 1.432 0 0 1 13.6 6.6a1.8 1.8 0 0 1 .971.279l.43.265V5.97l-.17-.073a2.9 2.9 0 0 0-1.17-.247 2.52 2.52 0 0 0-1.929.817 2.9 2.9 0 0 0-.747 2.049c-.028.707.21 1.4.67 1.939.222.249.497.446.804.578z"/></svg>
);
};

View File

@@ -0,0 +1,15 @@
import * as React from 'react';
export interface IOtherActionButtonProps {
className?: string;
disabled?: boolean;
onClick: (e: React.SyntheticEvent<HTMLButtonElement>) => void;
}
export const OtherActionButton: React.FunctionComponent<IOtherActionButtonProps> = ({ className, disabled, onClick, children}: React.PropsWithChildren<IOtherActionButtonProps>) => {
return (
<div className={`ext_link_block`}>
<button onClick={onClick} className={className || ""} disabled={disabled}>{children}</button>
</div>
);
};

View File

@@ -1,4 +1,5 @@
import * as React from 'react';
import { PanelSettings } from '../../models';
import { CommandToCode } from '../CommandToCode';
import { MessageHelper } from '../helper/MessageHelper';
import { Collapsible } from './Collapsible';
@@ -7,12 +8,16 @@ import { FileIcon } from './Icons/FileIcon';
import { FolderOpenedIcon } from './Icons/FolderOpenedIcon';
import { SettingsIcon } from './Icons/SettingsIcon';
import { TemplateIcon } from './Icons/TemplateIcon';
import { WritingIcon } from './Icons/WritingIcon';
import { OtherActionButton } from './OtherActionButton';
export interface IOtherActionsProps {
isFile: boolean;
settings: PanelSettings | undefined;
isBase?: boolean;
}
export const OtherActions: React.FunctionComponent<IOtherActionsProps> = ({isFile}: React.PropsWithChildren<IOtherActionsProps>) => {
export const OtherActions: React.FunctionComponent<IOtherActionsProps> = ({isFile, settings, isBase}: React.PropsWithChildren<IOtherActionsProps>) => {
const openSettings = () => {
MessageHelper.sendMessage(CommandToCode.openSettings);
@@ -30,27 +35,25 @@ export const OtherActions: React.FunctionComponent<IOtherActionsProps> = ({isFil
MessageHelper.sendMessage(CommandToCode.createTemplate);
};
const toggleWritingSettings = () => {
MessageHelper.sendMessage(CommandToCode.toggleWritingSettings);
};
return (
<>
<Collapsible title="Other actions" className={`other_actions`}>
<div className="ext_link_block">
<button onClick={createAsTemplate} disabled={!isFile}><TemplateIcon /> Create as template</button>
</div>
<Collapsible id={`${isBase ? "base_" : ""}other_actions`} title="Other actions" className={`other_actions`}>
<OtherActionButton className={settings?.writingSettingsEnabled ? "active" : ""} onClick={toggleWritingSettings} disabled={typeof settings?.writingSettingsEnabled === "undefined"}><WritingIcon /> <span>{settings?.writingSettingsEnabled ? "Writing settings enabled" : "Enable writing settings"}</span></OtherActionButton>
<OtherActionButton onClick={createAsTemplate} disabled={!isFile}><TemplateIcon /> <span>Create as template</span></OtherActionButton>
<OtherActionButton onClick={openSettings}><SettingsIcon /> <span>Open settings</span></OtherActionButton>
<OtherActionButton onClick={openFile} disabled={!isFile}><FileIcon /> <span>Reveal file in folder</span></OtherActionButton>
<OtherActionButton onClick={openProject}><FolderOpenedIcon /> <span>Reveal project folder</span></OtherActionButton>
<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>
<a href="https://github.com/estruyf/vscode-front-matter/issues" title="Open an issue on GitHub"><BugIcon /> <span>Report an issue</span></a>
</div>
</Collapsible>
</>

View File

@@ -3,6 +3,7 @@
import * as React from 'react';
import { CommandToCode } from '../CommandToCode';
import { MessageHelper } from '../helper/MessageHelper';
import { ActionButton } from './ActionButton';
export interface IPublishActionProps {
draft: boolean;
@@ -16,8 +17,6 @@ export const PublishAction: React.FunctionComponent<IPublishActionProps> = (prop
};
return (
<div className={`article__action`}>
<button onClick={publish} className={`${draft ? "" : "secondary"}`}>{draft ? "Publish" : "Revert to draft"}</button>
</div>
<ActionButton onClick={publish} className={`${draft ? "" : "secondary"}`} title={draft ? "Publish" : "Revert to draft"} />
);
};

View File

@@ -88,7 +88,7 @@ export const SeoStatus: React.FunctionComponent<ISeoStatusProps> = (props: React
}, [title, data[descriptionField], data?.articleDetails?.wordCount]);
return (
<Collapsible title="SEO Status" sendUpdate={(value) => setIsOpen(value)}>
<Collapsible id={`seo`} title="SEO Status" sendUpdate={(value) => setIsOpen(value)}>
{ renderContent() }
</Collapsible>
);

View File

@@ -3,6 +3,7 @@ import { SlugHelper } from '../../helpers/SlugHelper';
import { Slug } from '../../models/PanelSettings';
import { CommandToCode } from '../CommandToCode';
import { MessageHelper } from '../helper/MessageHelper';
import { ActionButton } from './ActionButton';
export interface ISlugActionProps {
value: string;
@@ -21,8 +22,6 @@ export const SlugAction: React.FunctionComponent<ISlugActionProps> = (props: Rea
};
return (
<div className={`article__action`}>
<button onClick={optimize} disabled={crntValue === slug}>Optimize slug</button>
</div>
<ActionButton onClick={optimize} disabled={crntValue === slug} title={`Optimize slug`} />
);
};

View File

@@ -1,5 +1,5 @@
import { Template } from './../commands/Template';
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 { SETTINGS_CONTENT_FRONTMATTER_HIGHLIGHT, 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";
@@ -152,6 +152,15 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
case CommandToCode.updateModifiedUpdating:
this.updateModifiedUpdating(msg.data || false);
break;
case CommandToCode.toggleWritingSettings:
this.toggleWritingSettings();
break;
case CommandToCode.updateFmHighlight:
this.updateFmHighlight((msg.data !== null && msg.data !== undefined) ? msg.data : false);
break;
case CommandToCode.toggleCenterMode:
await commands.executeCommand(`workbench.action.toggleCenteredLayout`);
break;
}
});
@@ -201,6 +210,13 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
}
}
/**
* Trigger all sections to close
*/
public collapseAll() {
this.postWebviewMessage({ command: Command.closeSections });
}
/**
* Run a custom script
* @param msg
@@ -269,7 +285,9 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
scripts: config.get(SETTING_CUSTOM_SCRIPTS),
isInitialized: await Template.isInitialized(),
contentInfo: await Folders.getInfo() || null,
modifiedDateUpdate: config.get(SETTING_AUTO_UPDATE_DATE) || false
modifiedDateUpdate: config.get(SETTING_AUTO_UPDATE_DATE) || false,
writingSettingsEnabled: this.isWritingSettingsEnabled() || false,
fmHighlighting: config.get(SETTINGS_CONTENT_FRONTMATTER_HIGHLIGHT),
} as PanelSettings
});
}
@@ -383,6 +401,57 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
}
}
/**
* Toggle the writing settings
*/
private async toggleWritingSettings() {
const config = workspace.getConfiguration("", { languageId: "markdown" });
const enabled = this.isWritingSettingsEnabled();
await config.update("editor.fontSize", enabled ? undefined : 14, false, true);
await config.update("editor.lineHeight", enabled ? undefined : 26, false, true);
await config.update("editor.wordWrap", enabled ? undefined : "wordWrapColumn", false, true);
await config.update("editor.wordWrapColumn", enabled ? undefined : 64, false, true);
await config.update("editor.lineNumbers", enabled ? undefined : "off", false, true);
await config.update("editor.quickSuggestions", enabled ? undefined : false, false, true);
await config.update("editor.minimap.enabled", enabled ? undefined : false, false, true);
this.getSettings();
}
/**
* Check if the writing settings are enabled
*/
private isWritingSettingsEnabled() {
const config = workspace.getConfiguration("", { languageId: "markdown" });
const fontSize = config.get("editor.fontSize");
const lineHeight = config.get("editor.lineHeight");
const wordWrap = config.get("editor.wordWrap");
const wordWrapColumn = config.get("editor.wordWrapColumn");
const lineNumbers = config.get("editor.lineNumbers");
const quickSuggestions = config.get<boolean>("editor.quickSuggestions");
return fontSize && lineHeight && wordWrap && wordWrapColumn && lineNumbers && quickSuggestions !== undefined;
}
/**
* Toggle the Front Matter highlighting
*/
private async updateFmHighlight(autoUpdate: boolean) {
const config = workspace.getConfiguration(CONFIG_KEY);
await config.update(SETTINGS_CONTENT_FRONTMATTER_HIGHLIGHT, autoUpdate);
this.getSettings();
if (ArticleHelper.isMarkdownFile()) {
// To unset the decorations, we need to reload the whole document/instance
commands.executeCommand(`workbench.action.reloadWindow`);
}
}
/**
* Toggle the modified auto-update setting
*/
private async updateModifiedUpdating(autoUpdate: boolean) {
const config = workspace.getConfiguration(CONFIG_KEY);
await config.update(SETTING_AUTO_UPDATE_DATE, autoUpdate);
@@ -397,7 +466,9 @@ export class ExplorerView implements WebviewViewProvider, Disposable {
this.panel!.webview.postMessage(msg);
}
/**
* Generate a unique nonce
*/
private getNonce() {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';