mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-07-05 01:11:19 +02:00
Added new placeholders
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
- Light color theme enhancements to folder cards
|
||||
- Added collapse and dashboard button to the view title of the FM Panel
|
||||
- Show content commands only when a supported file type is active
|
||||
- Added `{{year}}`, `{{month}}`, and `{{day}}` placeholders for fields
|
||||
- [#272](https://github.com/estruyf/vscode-front-matter/issues/272): New slide over panel for showing details of media files
|
||||
- [#276](https://github.com/estruyf/vscode-front-matter/issues/276): Add a Front Matter walkthrough for VS Code
|
||||
- [#270](https://github.com/estruyf/vscode-front-matter/issues/270): Only show media files from public folder if `pageBundle` is not enabled on any of the content types
|
||||
|
||||
@@ -15,6 +15,7 @@ import { Telemetry } from '../helpers/Telemetry';
|
||||
import { ParsedFrontMatter } from '../parsers';
|
||||
import { MediaListener } from '../listeners/panel';
|
||||
import { NavigationType } from '../dashboardWebView/models';
|
||||
import { processKnownPlaceholders } from '../helpers/PlaceholderHelper';
|
||||
|
||||
|
||||
export class Article {
|
||||
@@ -205,11 +206,12 @@ export class Article {
|
||||
// Update the fields containing a custom placeholder that depends on slug
|
||||
const placeholders = Settings.get<{id: string, value: string}[]>(SETTING_CONTENT_PLACEHOLDERS);
|
||||
const customPlaceholders = placeholders?.filter(p => p.value.includes("{{slug}}"));
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
for (const customPlaceholder of (customPlaceholders || [])) {
|
||||
const customPlaceholderFields = contentType.fields.filter(f => f.default === `{{${customPlaceholder.id}}}`);
|
||||
for (const pField of customPlaceholderFields) {
|
||||
article.data[pField.name] = customPlaceholder.value;
|
||||
article.data[pField.name] = ArticleHelper.processKnownPlaceholders(article.data[pField.name], articleTitle);
|
||||
article.data[pField.name] = processKnownPlaceholders(article.data[pField.name], articleTitle, dateFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -359,9 +361,12 @@ export class Article {
|
||||
const position = editor.selection.active;
|
||||
const selectionText = editor.document.getText(editor.selection);
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
|
||||
await vscode.commands.executeCommand(COMMAND_NAME.dashboard, {
|
||||
type: NavigationType.Snippets,
|
||||
data: {
|
||||
fileTitle: article?.data.title || "",
|
||||
filePath: editor.document.uri.fsPath,
|
||||
fieldName: basename(editor.document.uri.fsPath),
|
||||
position,
|
||||
|
||||
@@ -2,10 +2,11 @@ import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import * as React from 'react';
|
||||
import { useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { processKnownPlaceholders } from '../../../helpers/PlaceholderHelper';
|
||||
import { SnippetParser } from '../../../helpers/SnippetParser';
|
||||
import { Snippet, SnippetField, SnippetSpecialPlaceholders } from '../../../models';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { ViewDataSelector } from '../../state';
|
||||
import { SettingsAtom, ViewDataSelector } from '../../state';
|
||||
import { SnippetInputField } from './SnippetInputField';
|
||||
|
||||
|
||||
@@ -21,16 +22,19 @@ export interface SnippetFormHandle {
|
||||
const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFormProps> = ({ snippet, selection }, ref) => {
|
||||
const viewData = useRecoilValue(ViewDataSelector);
|
||||
const [ fields, setFields ] = useState<SnippetField[]>([]);
|
||||
const settings = useRecoilValue(SettingsAtom);
|
||||
|
||||
const onTextChange = useCallback((field: SnippetField, value: string) => {
|
||||
setFields(prevFields => prevFields.map(f => f.name === field.name ? { ...f, value } : f));
|
||||
}, [setFields]);
|
||||
|
||||
const insertSelectionValue = useCallback((value: SnippetSpecialPlaceholders) => {
|
||||
const insertPlaceholderValues = useCallback((value: SnippetSpecialPlaceholders) => {
|
||||
if (value === "FM_SELECTED_TEXT") {
|
||||
return selection || "";
|
||||
}
|
||||
|
||||
value = processKnownPlaceholders(value, viewData?.data?.fileTitle || "", settings?.date.format || "");
|
||||
|
||||
return value;
|
||||
}, [selection]);
|
||||
|
||||
@@ -81,7 +85,7 @@ const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFor
|
||||
if (field) {
|
||||
allFields.push({
|
||||
...field,
|
||||
value: insertSelectionValue(field.default || "")
|
||||
value: insertPlaceholderValues(field.default || "")
|
||||
});
|
||||
} else {
|
||||
allFields.push({
|
||||
|
||||
@@ -30,6 +30,7 @@ export interface Settings {
|
||||
dataTypes: DataType[] | undefined;
|
||||
isBacker: boolean | undefined;
|
||||
snippets: Snippets | undefined;
|
||||
date: { format: string };
|
||||
}
|
||||
|
||||
export interface DashboardState {
|
||||
|
||||
@@ -20,6 +20,7 @@ import { DEFAULT_FILE_TYPES } from '../constants/DefaultFileTypes';
|
||||
import { fromMarkdown } from 'mdast-util-from-markdown';
|
||||
import { Link, Parent } from 'mdast-util-from-markdown/lib';
|
||||
import { Content } from 'mdast';
|
||||
import { processKnownPlaceholders } from './PlaceholderHelper';
|
||||
|
||||
export class ArticleHelper {
|
||||
private static notifiedFiles: string[] = [];
|
||||
@@ -321,6 +322,7 @@ export class ArticleHelper {
|
||||
* @returns
|
||||
*/
|
||||
public static updatePlaceholders(data: any, title: string) {
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
const fmData = Object.assign({}, data);
|
||||
|
||||
for (const fieldName of Object.keys(fmData)) {
|
||||
@@ -334,40 +336,13 @@ export class ArticleHelper {
|
||||
fmData[fieldName] = SlugHelper.createSlug(title);
|
||||
}
|
||||
|
||||
fmData[fieldName] = this.processKnownPlaceholders(fmData[fieldName], title);
|
||||
fmData[fieldName] = processKnownPlaceholders(fmData[fieldName], title, dateFormat);
|
||||
fmData[fieldName] = this.processCustomPlaceholders(fmData[fieldName], title);
|
||||
}
|
||||
|
||||
return fmData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the known placeholders
|
||||
* @param value
|
||||
* @param title
|
||||
* @returns
|
||||
*/
|
||||
public static processKnownPlaceholders(value: string, title: string) {
|
||||
if (value && typeof value === "string") {
|
||||
if (value.includes("{{title}}")) {
|
||||
const regex = new RegExp("{{title}}", "g");
|
||||
value = value.replace(regex, title);
|
||||
}
|
||||
|
||||
if (value.includes("{{slug}}")) {
|
||||
const regex = new RegExp("{{slug}}", "g");
|
||||
value = value.replace(regex, SlugHelper.createSlug(title) || "");
|
||||
}
|
||||
|
||||
if (value.includes("{{now}}")) {
|
||||
const regex = new RegExp("{{now}}", "g");
|
||||
value = value.replace(regex, Article.formatDate(new Date()));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the custom placeholders
|
||||
* @param value
|
||||
@@ -376,12 +351,13 @@ export class ArticleHelper {
|
||||
*/
|
||||
public static processCustomPlaceholders(value: string, title: string) {
|
||||
if (value && typeof value === "string") {
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
const placeholders = Settings.get<{id: string, value: string}[]>(SETTING_CONTENT_PLACEHOLDERS);
|
||||
if (placeholders && placeholders.length > 0) {
|
||||
for (const placeholder of placeholders) {
|
||||
if (value.includes(`{{${placeholder.id}}}`)) {
|
||||
const regex = new RegExp(`{{${placeholder.id}}}`, "g");
|
||||
const updatedValue = this.processKnownPlaceholders(placeholder.value, title);
|
||||
const updatedValue = processKnownPlaceholders(placeholder.value, title, dateFormat);
|
||||
value = value.replace(regex, updatedValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PagesListener } from './../listeners/dashboard';
|
||||
import { ArticleHelper, Settings } from ".";
|
||||
import { SETTING_CONTENT_DRAFT_FIELD, SETTING_TAXONOMY_CONTENT_TYPES, TelemetryEvent } from "../constants";
|
||||
import { SETTING_CONTENT_DRAFT_FIELD, SETTING_DATE_FORMAT, SETTING_TAXONOMY_CONTENT_TYPES, TelemetryEvent } from "../constants";
|
||||
import { ContentType as IContentType, DraftField, Field } from '../models';
|
||||
import { Uri, commands } from 'vscode';
|
||||
import { Folders } from "../commands/Folders";
|
||||
@@ -9,6 +9,7 @@ import { writeFileSync } from "fs";
|
||||
import { Notifications } from "./Notifications";
|
||||
import { DEFAULT_CONTENT_TYPE_NAME } from "../constants/ContentType";
|
||||
import { Telemetry } from './Telemetry';
|
||||
import { processKnownPlaceholders } from './PlaceholderHelper';
|
||||
|
||||
|
||||
export class ContentType {
|
||||
@@ -140,10 +141,11 @@ export class ContentType {
|
||||
private static processFields(obj: IContentType | Field, titleValue: string, data: any) {
|
||||
|
||||
if (obj.fields) {
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
for (const field of obj.fields) {
|
||||
if (field.name === "title") {
|
||||
if (field.default) {
|
||||
data[field.name] = ArticleHelper.processKnownPlaceholders(field.default, titleValue);
|
||||
data[field.name] = processKnownPlaceholders(field.default, titleValue, dateFormat);
|
||||
data[field.name] = ArticleHelper.processCustomPlaceholders(data[field.name], titleValue);
|
||||
} else {
|
||||
data[field.name] = titleValue;
|
||||
@@ -152,7 +154,7 @@ export class ContentType {
|
||||
if (field.type === "fields") {
|
||||
data[field.name] = this.processFields(field, titleValue, {});
|
||||
} else {
|
||||
data[field.name] = field.default ? ArticleHelper.processKnownPlaceholders(field.default, titleValue) : "";
|
||||
data[field.name] = field.default ? processKnownPlaceholders(field.default, titleValue, dateFormat) : "";
|
||||
data[field.name] = field.default ? ArticleHelper.processCustomPlaceholders(data[field.name], titleValue) : "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { basename, join } from "path";
|
||||
import { workspace } from "vscode";
|
||||
import { Folders } from "../commands/Folders";
|
||||
import { Template } from "../commands/Template";
|
||||
import { CONTEXT, ExtensionState, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_SORTING, SETTING_CONTENT_SORTING_DEFAULT, SETTING_CONTENT_STATIC_FOLDER, SETTING_DASHBOARD_MEDIA_SNIPPET, SETTING_DASHBOARD_OPENONSTART, SETTING_DATA_FILES, SETTING_DATA_FOLDERS, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_MEDIA_SORTING_DEFAULT, SETTING_CUSTOM_SCRIPTS, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_CONTENT_SNIPPETS } from "../constants";
|
||||
import { CONTEXT, ExtensionState, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_SORTING, SETTING_CONTENT_SORTING_DEFAULT, SETTING_CONTENT_STATIC_FOLDER, SETTING_DASHBOARD_MEDIA_SNIPPET, SETTING_DASHBOARD_OPENONSTART, SETTING_DATA_FILES, SETTING_DATA_FOLDERS, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_MEDIA_SORTING_DEFAULT, SETTING_CUSTOM_SCRIPTS, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_CONTENT_SNIPPETS, SETTING_DATE_FORMAT } from "../constants";
|
||||
import { DashboardViewType, SortingOption, Settings as ISettings } from "../dashboardWebView/models";
|
||||
import { CustomScript, DraftField, ScriptType, Snippets, SortingSetting, TaxonomyType } from "../models";
|
||||
import { DataFile } from "../models/DataFile";
|
||||
@@ -39,6 +39,9 @@ export class DashboardSettings {
|
||||
crntFramework: Settings.get<string>(SETTING_FRAMEWORK_ID),
|
||||
framework: (!isInitialized && wsFolder) ? FrameworkDetector.get(wsFolder.fsPath) : null,
|
||||
scripts: (Settings.get<CustomScript[]>(SETTING_CUSTOM_SCRIPTS) || []),
|
||||
date: {
|
||||
format: Settings.get<string>(SETTING_DATE_FORMAT) || ""
|
||||
},
|
||||
dashboardState: {
|
||||
contents: {
|
||||
sorting: await ext.getState<SortingOption | undefined>(ExtensionState.Dashboard.Contents.Sorting, "workspace"),
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { format } from "date-fns";
|
||||
import { DateHelper } from "./DateHelper";
|
||||
import { SlugHelper } from "./SlugHelper";
|
||||
|
||||
/**
|
||||
* Replace the known placeholders
|
||||
* @param value
|
||||
* @param title
|
||||
* @returns
|
||||
*/
|
||||
export const processKnownPlaceholders = (value: string, title: string, dateFormat: string) => {
|
||||
if (value && typeof value === "string") {
|
||||
if (value.includes("{{title}}")) {
|
||||
const regex = new RegExp("{{title}}", "g");
|
||||
value = value.replace(regex, title);
|
||||
}
|
||||
|
||||
if (value.includes("{{slug}}")) {
|
||||
const regex = new RegExp("{{slug}}", "g");
|
||||
value = value.replace(regex, SlugHelper.createSlug(title) || "");
|
||||
}
|
||||
|
||||
if (value.includes("{{now}}")) {
|
||||
const regex = new RegExp("{{now}}", "g");
|
||||
|
||||
if (dateFormat && typeof dateFormat === "string") {
|
||||
value = value.replace(regex, format(new Date(), DateHelper.formatUpdate(dateFormat) as string));
|
||||
} else {
|
||||
return (new Date()).toISOString();
|
||||
}
|
||||
}
|
||||
|
||||
if (value.includes("{{year}}")) {
|
||||
const regex = new RegExp("{{year}}", "g");
|
||||
value = value.replace(regex, format(new Date(), "yyyy"));
|
||||
}
|
||||
|
||||
if (value.includes("{{month}}")) {
|
||||
const regex = new RegExp("{{month}}", "g");
|
||||
value = value.replace(regex, format(new Date(), "MM"));
|
||||
}
|
||||
|
||||
if (value.includes("{{day}}")) {
|
||||
const regex = new RegExp("{{day}}", "g");
|
||||
value = value.replace(regex, format(new Date(), "dd"));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
@@ -6,9 +6,10 @@ import { CommandToCode } from "../../panelWebView/CommandToCode";
|
||||
import { BaseListener } from "./BaseListener";
|
||||
import { commands, ThemeIcon, window } from 'vscode';
|
||||
import { ArticleHelper, Logger, Settings } from "../../helpers";
|
||||
import { COMMAND_NAME, DefaultFields, SETTING_COMMA_SEPARATED_FIELDS, SETTING_TAXONOMY_CONTENT_TYPES } from "../../constants";
|
||||
import { COMMAND_NAME, DefaultFields, SETTING_COMMA_SEPARATED_FIELDS, SETTING_DATE_FORMAT, SETTING_TAXONOMY_CONTENT_TYPES } from "../../constants";
|
||||
import { Article } from '../../commands';
|
||||
import { ParsedFrontMatter } from '../../parsers';
|
||||
import { processKnownPlaceholders } from '../../helpers/PlaceholderHelper';
|
||||
|
||||
const FILE_LIMIT = 10;
|
||||
|
||||
@@ -287,7 +288,8 @@ export class DataListener extends BaseListener {
|
||||
|
||||
private static updatePlaceholder(field: string, value: string, title: string) {
|
||||
if (field && value) {
|
||||
value = ArticleHelper.processKnownPlaceholders(value, title || "");
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
value = processKnownPlaceholders(value, title || "", dateFormat);
|
||||
value = ArticleHelper.processCustomPlaceholders(value, title || "");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
import { Position } from 'vscode';
|
||||
import { NavigationType } from '../dashboardWebView/models';
|
||||
import { BlockFieldData } from './BlockFieldData';
|
||||
|
||||
export interface DashboardData {
|
||||
type: NavigationType;
|
||||
data?: any;
|
||||
data?: ViewData;
|
||||
}
|
||||
|
||||
export interface ViewData {
|
||||
filePath?: string;
|
||||
fieldName?: string;
|
||||
position?: Position;
|
||||
fileTitle?: string;
|
||||
selection?: string;
|
||||
pageBundle?: boolean;
|
||||
metadataInsert?: boolean;
|
||||
blockData?: BlockFieldData;
|
||||
parents?: string[];
|
||||
multiple?: string[];
|
||||
value?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user