mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-08-08 09:53:20 +02:00
#25 - Moved from Material UI to Downshift
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
# Change Log
|
||||
|
||||
## [1.11.0] - 2020-12-10
|
||||
|
||||
- Moved from Material UI Autocomplete to Downshift. This gives more flexibility, and allows to focus the inputs from a VSCode command.
|
||||
- Changed the `Front Matter: Insert <tags | categories>` functionality to open in the panel, instead of using the VSCode dialogs.
|
||||
|
||||
## [1.10.0] - 2020-12-03
|
||||
|
||||
- FrontMatter panel implemented. This panel allows you to control all extension actions, but not only that. It makes adding tags and categories in a easier way to your page.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
[](https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter&ssr=false#review-details)
|
||||
|
||||
This VSCode extension simplifies working with front matter of your markdown articles when using a static site generator like Hugo, Jekyll, Hexo, NextJs, Gatsby, and many more... For example, with the extension, you can keep a list of used tags, categories and add/remove them from your article.
|
||||
This VSCode extension simplifies working with your markdown articles' front matter when using a static site generator like Hugo, Jekyll, Hexo, NextJs, Gatsby, and many more... For example, you can keep a list of used tags, categories and add/remove them from your article with the extension.
|
||||
|
||||
The extension will automatically verify if your title and description are SEO compliant. If this would not be the case, it will give you a warning.
|
||||
|
||||
@@ -16,21 +16,21 @@ In version `1.10.0` of this extension, the FrontMatter panel got introduced. Thi
|
||||
|
||||

|
||||
|
||||
Originally this panel was created to make it easier to add tags and categories to your articles. As the current vscode multi-select is not optimal to use.
|
||||
Initially, this panel has been created to make it easier to add tags and categories to your articles as the current VSCode multi-select is not optimal to use.
|
||||
|
||||
To leverage most of the capabilities of the extension. SEO information and common actions like slug optimization, updating the date and publish/drafting the article.
|
||||
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.
|
||||
|
||||
> **Info**: By default the tags/categories picker allows you to insert none existing tags/categories. When you enter a none existing tag/category, the panel shows an add `+` icon in front of that button. This allows you to store this tag/category to your settings. If you want to disable this feature, you can do that by setting the `frontMatter.panel.freeform` setting to `false`.
|
||||
> **Info**: By default, the tags/categories picker allows you to insert existing and none tags/categories. When you enter a none existing tag/category, the panel shows an add `+` icon in front of that button. This functionality allows you to store this tag/category in your settings. If you want to disable this feature, you can do that by setting the `frontMatter.panel.freeform` setting to `false`.
|
||||
|
||||
## Creating articles from templates
|
||||
|
||||
By default, the extension looks for files stored in a `.templates` folder which should be located in the root of your website project.
|
||||
By default, the extension looks for files stored in a `.templates` folder that should be located in your website project's root.
|
||||
|
||||
> **Info**: You can overwrite the path, by specifying it with the `frontMatter.templates.folder` setting.
|
||||
> **Info**: You can overwrite the path by specifying it with the `frontMatter.templates.folder` setting.
|
||||
|
||||
When adding files in the folder, you'll be able to runt the `Front Matter: New article from template` from a command or explorer menu. It will present you with the article template options. Once you pick one, and specify the title. It creates the file and updates its front matter.
|
||||
When adding files in the folder, you'll be able to run the `Front Matter: New article from template` from a command or explorer menu. It will present you with the article template options once you pick one and specify the title. It creates the file and updates its front matter.
|
||||
|
||||
> **Info**: By default the extension will create articles with a `yyyy-MM-dd` prefix. If you do not want that, or change the date format, you can do this by updating the `frontMatter.templates.prefix` setting.
|
||||
> **Info**: By default, the extension will create articles with a `yyyy-MM-dd` prefix. If you do not want that or change the date format, you can update the `frontMatter.templates.prefix` setting.
|
||||
|
||||
## Syntax highlighting for Hugo Shortcodes
|
||||
|
||||
@@ -46,25 +46,25 @@ Creates a new <tag | category> and allows you to include it into your post autom
|
||||
|
||||
**Front Matter: Insert <tags | categories>**
|
||||
|
||||
Inserts a selected <tags | categories> into the front matter of your article/post/...
|
||||
Inserts a selected <tags | categories> into the front matter of your article/post/... - When using this command, the FrontMatter panel opens and focuses on the specified type.
|
||||
|
||||

|
||||
> **Info**: This experience changed in version `1.11.0`.
|
||||
|
||||
**Front Matter: Export all tags & categories to your settings**
|
||||
|
||||
Export all the already used tags & categories in your articles/posts/... to your user settings
|
||||
Export all the already used tags & categories in your articles/posts/... to your user settings.
|
||||
|
||||
**Front Matter: Remap or remove tag/category in all articles**
|
||||
|
||||
This command helps you quickly update/remap or delete a tag or category in your markdown files. The extension will ask you to select the taxonomy type (*tag* or *category*), the old taxonomy value, and the new one (leave the input field *blank* to remove the tag/category).
|
||||
|
||||
> **Info**: Once the remapping/deleting process is completed. The user settings will be updated with all new taxonomy tags/categories.
|
||||
> **Info**: Once the remapping/deleting process completes. Your VSCode settings update with all new taxonomy tags/categories.
|
||||
|
||||
**Front Matter: Set current date**
|
||||
|
||||
Update the `date` property of the current article/post/... to the current date & time.
|
||||
|
||||
**Optional**: if you want, you can specify the date property format by adding your preference in your settings. Settings key: `frontMatter.taxonomy.dateFormat`. Check [date-fns formatting](https://date-fns.org/v2.0.1/docs/format) for more information on which patterns you can use.
|
||||
**Optional**: if you want, you can specify the date property format by adding your settings' preference. Settings key: `frontMatter.taxonomy.dateFormat`. Check [date-fns formatting](https://date-fns.org/v2.0.1/docs/format) for more information on which patterns you can use.
|
||||
|
||||
**Front Matter: Set lastmod date**
|
||||
|
||||
@@ -84,7 +84,7 @@ slug: sample-page-title
|
||||
|
||||
You can also specify a prefix and suffix, which can be added to the slug if you want. Use the following settings to do this: `frontMatter.taxonomy.slugPrefix` and `frontMatter.taxonomy.slugSuffix`. By default, both options are not provided and will not add anything to the slug.
|
||||
|
||||
> **Info**: At the moment, only English stop words are supported.
|
||||
> **Info**: At the moment, the extension only supports English stopwords.
|
||||
|
||||
## Where is the data stored?
|
||||
|
||||
@@ -99,7 +99,7 @@ The tags and categories are stored in the project VSCode user settings. You can
|
||||
|
||||
## Additional extension settings
|
||||
|
||||
The extension has more settings that allow you to configure it to your needs further. Here is a list of settings which you can set:
|
||||
The extension has more settings that allow you to configure it to your needs further. Here is a list of settings that you can set:
|
||||
|
||||
### `frontMatter.taxonomy.seoTitleLength`
|
||||
|
||||
@@ -142,7 +142,7 @@ Specify if arrays in the front matter are indented. Default: `true`. If you do n
|
||||
|
||||
### `frontMatter.taxonomy.noPropertyValueQuotes`
|
||||
|
||||
Specify the property names of which you want to remove the quotes in the output value. **Warning**: only use this when you know what you are doing. If you want to, for instance, remove the quotes from the date property, you can add the following:
|
||||
Specify the property names of which you want to remove the quotes in the output value. **Warning**: only use this when you know what you are doing. If you're going to, for instance, remove the quotes from the date property, you can add the following:
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
@@ -98,6 +98,9 @@
|
||||
list-style: none;
|
||||
overflow: auto;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.article__tags__dropbox.open {
|
||||
border: 1px solid rgba(0, 0, 0, .9);
|
||||
}
|
||||
|
||||
@@ -120,7 +123,7 @@
|
||||
background-color: var(--vscode-button-background);
|
||||
}
|
||||
|
||||
.article__tags li[data-focus="true"] {
|
||||
.article__tags li[aria-selected="true"] {
|
||||
color: var(--vscode-button-foreground);
|
||||
background-color: var(--vscode-button-hoverBackground);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import useAutocomplete from '@material-ui/lab/useAutocomplete';
|
||||
import { Tags } from './Tags';
|
||||
import { usePrevious } from '../hooks/usePrevious';
|
||||
import { CommandToCode } from '../CommandToCode';
|
||||
import { TagType } from '../TagType';
|
||||
import { MessageHelper } from '../helper/MessageHelper';
|
||||
import { TextField } from '@material-ui/core';
|
||||
import Downshift from 'downshift'
|
||||
import Downshift from 'downshift';
|
||||
|
||||
export interface ITagPickerProps {
|
||||
type: string;
|
||||
@@ -17,51 +15,92 @@ export interface ITagPickerProps {
|
||||
unsetFocus: () => void;
|
||||
}
|
||||
|
||||
// https://v4-2-1.material-ui.com/components/autocomplete/
|
||||
// https://github.com/downshift-js/downshift/issues/751
|
||||
|
||||
export const TagPicker: React.FunctionComponent<ITagPickerProps> = (props: React.PropsWithChildren<ITagPickerProps>) => {
|
||||
const { type, crntSelected, options, freeform, focussed, unsetFocus } = props;
|
||||
const [ selected, setSelected ] = React.useState<string[]>([]);
|
||||
const [ inputValue, setInputValue ] = React.useState<string>("");
|
||||
const prevSelected = usePrevious(crntSelected);
|
||||
const inputRef = React.useRef<HTMLInputElement | null>(null);
|
||||
const dsRef = React.useRef<Downshift<string> | null>(null);
|
||||
|
||||
const { getRootProps, getInputProps, getListboxProps, getOptionProps, groupedOptions } = useAutocomplete({
|
||||
id: 'use-autocomplete',
|
||||
options: options,
|
||||
multiple: true,
|
||||
freeSolo: freeform,
|
||||
value: crntSelected,
|
||||
getOptionDisabled: (option) => selected.includes(option),
|
||||
onChange: (e, values: string[]) => {
|
||||
const uniqValues = Array.from(new Set([...selected, ...values]));
|
||||
setSelected(uniqValues);
|
||||
sendUpdate(uniqValues);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Removes an option
|
||||
* @param tag
|
||||
*/
|
||||
const onRemove = (tag: string) => {
|
||||
const newSelection = selected.filter(s => s !== tag);
|
||||
setSelected(newSelection);
|
||||
sendUpdate(newSelection);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the tag
|
||||
* @param tag
|
||||
*/
|
||||
const onCreate = (tag: string) => {
|
||||
const cmdType = type === TagType.tags ? CommandToCode.addTagToSettings : CommandToCode.addCategoryToSettings;
|
||||
MessageHelper.sendMessage(cmdType, tag);
|
||||
};
|
||||
|
||||
/**
|
||||
* Send an update to VSCode
|
||||
* @param values
|
||||
*/
|
||||
const sendUpdate = (values: string[]) => {
|
||||
const cmdType = type === TagType.tags ? CommandToCode.updateTags : CommandToCode.updateCategories;
|
||||
MessageHelper.sendMessage(cmdType, values);
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggers the focus to the input when command is executed
|
||||
*/
|
||||
const triggerFocus = () => {
|
||||
if (focussed && inputRef && inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On item selection
|
||||
* @param selectedItem
|
||||
* @param compState
|
||||
*/
|
||||
const onSelect = (selectedItem: string | null) => {
|
||||
if (selectedItem) {
|
||||
const uniqValues = Array.from(new Set([...selected, selectedItem]));
|
||||
setSelected(uniqValues);
|
||||
sendUpdate(uniqValues);
|
||||
setInputValue("");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow free value entries
|
||||
* @param event
|
||||
*/
|
||||
const onEnterSelection = (event: React.KeyboardEvent<HTMLInputElement>, closeCb: () => void) => {
|
||||
if (freeform && event.key === "Enter" && inputValue) {
|
||||
onSelect(inputValue);
|
||||
|
||||
if (closeCb) {
|
||||
closeCb();
|
||||
}
|
||||
} else if (event.key === "Escape") {
|
||||
if (closeCb) {
|
||||
closeCb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the options which can be selected
|
||||
* @param option
|
||||
* @param inputValue
|
||||
*/
|
||||
const filterList = (option: string, inputValue: string | null) => {
|
||||
return !selected.includes(option) && option.toLowerCase().includes((inputValue || "").toLowerCase());
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
setTimeout(() => {
|
||||
triggerFocus();
|
||||
@@ -76,67 +115,37 @@ export const TagPicker: React.FunctionComponent<ITagPickerProps> = (props: React
|
||||
|
||||
return (
|
||||
<div className={`article__tags`}>
|
||||
<h3>{type} - {focussed ? 'true' : 'false'}</h3>
|
||||
<h3>{type}</h3>
|
||||
|
||||
<Downshift ref={dsRef}
|
||||
onChange={onSelect}
|
||||
itemToString={item => (item ? item : '')}
|
||||
inputValue={inputValue}
|
||||
onInputValueChange={(value) => setInputValue(value)}>
|
||||
{
|
||||
({ getInputProps, getItemProps, getMenuProps, isOpen, inputValue, getRootProps, openMenu, closeMenu }) => (
|
||||
<>
|
||||
<div {...getRootProps(undefined, {suppressRefError: true})}>
|
||||
<input {...getInputProps({ ref: inputRef, onFocus: openMenu })}
|
||||
onBlur={() => { closeMenu(); unsetFocus(); } }
|
||||
placeholder={`Pick your ${type.toLowerCase()}`}
|
||||
onKeyDown={(e) => onEnterSelection(e, closeMenu)} />
|
||||
</div>
|
||||
|
||||
<Downshift onChange={selection =>
|
||||
alert(selection ? `You selected ${selection.value}` : 'Selection Cleared')
|
||||
<ul className={`article__tags__dropbox ${isOpen ? "open" : "closed" }`} {...getMenuProps()}>
|
||||
{
|
||||
isOpen ? options.filter((option) => filterList(option, inputValue)).map((item, index) => (
|
||||
<li {...getItemProps({ key: item, index, item })} >
|
||||
{ item }
|
||||
</li>
|
||||
)) : null
|
||||
}
|
||||
</ul>
|
||||
</>
|
||||
)
|
||||
}
|
||||
itemToString={item => (item ? item.value : '')}>
|
||||
{({
|
||||
getInputProps,
|
||||
getItemProps,
|
||||
getMenuProps,
|
||||
isOpen,
|
||||
inputValue,
|
||||
highlightedIndex,
|
||||
selectedItem,
|
||||
getRootProps,
|
||||
openMenu
|
||||
}) => (
|
||||
<>
|
||||
<div
|
||||
style={{display: 'inline-block'}}
|
||||
{...getRootProps(undefined, {suppressRefError: true})}
|
||||
>
|
||||
<input {...getInputProps({ ref: inputRef, onFocus: openMenu })} onBlur={unsetFocus} />
|
||||
</div>
|
||||
<ul {...getMenuProps()}>
|
||||
{ isOpen ? options.filter(item => !inputValue || item.includes(inputValue)).map((item, index) => (
|
||||
<li
|
||||
{...getItemProps({
|
||||
key: item,
|
||||
index,
|
||||
item,
|
||||
style: {
|
||||
backgroundColor: highlightedIndex === index ? 'lightgray' : 'white',
|
||||
fontWeight: selectedItem === item ? 'bold' : 'normal',
|
||||
}
|
||||
})}
|
||||
>
|
||||
{item}
|
||||
</li>
|
||||
))
|
||||
: null}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</Downshift>
|
||||
|
||||
<div {...getRootProps()}>
|
||||
<TextField {...getInputProps()} placeholder={`Pick your ${type.toLowerCase()}`} />
|
||||
</div>
|
||||
|
||||
{
|
||||
groupedOptions.length > 0 ? (
|
||||
<ul className={`article__tags__dropbox`} {...getListboxProps()}>
|
||||
{groupedOptions.map((option, index) => (
|
||||
<li key={index} {...getOptionProps({ option, index })}>{option}</li>
|
||||
))}
|
||||
</ul>
|
||||
) : null
|
||||
}
|
||||
|
||||
<Tags values={selected} onRemove={onRemove} onCreate={onCreate} options={options} />
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user