Skip to content

Commit 1b4e39b

Browse files
authored
Merge pull request #924 from estruyf/beta
v10.8.0 release
2 parents 88cad8c + 1fa73ef commit 1b4e39b

30 files changed

+223
-48
lines changed

Diff for: CHANGELOG.md

+16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Change Log
22

3+
## [10.8.0] - 2025-02-27 - [Release notes](https://beta.frontmatter.codes/updates/v10.8.0)
4+
5+
### 🎨 Enhancements
6+
7+
- [#915](https://github.com/estruyf/vscode-front-matter/issues/915): Added a new setting `frontMatter.panel.openOnSupportedFile` which allows you to open the panel view on supported files
8+
- [#921](https://github.com/estruyf/vscode-front-matter/issues/921): Improve the filename sanitization
9+
- [#922](https://github.com/estruyf/vscode-front-matter/issues/922): Added `{{fileName}}` and `{{sluggedFileName}}` placeholders for the slug template setting
10+
11+
### 🐞 Fixes
12+
13+
- Fix for media folder parsing on Windows
14+
- Refresh button was not available on the media dashboard when having custom scripts defined
15+
- [#909](https://github.com/estruyf/vscode-front-matter/issues/909): Schema fix for the view modes
16+
- [#913](https://github.com/estruyf/vscode-front-matter/issues/913): Fix for relative media paths in page bundles
17+
- [#914](https://github.com/estruyf/vscode-front-matter/issues/914): Fix sanitizing of default filenames with an `_` in it
18+
319
## [10.7.0] - 2024-12-31 - [Release notes](https://beta.frontmatter.codes/updates/v10.7.0)
420

521
### 🎨 Enhancements

Diff for: l10n/bundle.l10n.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
"settings.view.integration": "Integration",
5757

5858
"settings.openOnStartup": "Open dashboard on startup",
59+
"settings.openPanelForSupportedFiles": "Open panel for supported files",
60+
"settings.openPanelForSupportedFiles.label": "Do you want to open the panel for supported files?",
5961
"settings.contentTypes": "Content types",
6062
"settings.contentFolders": "Content folders",
6163
"settings.diagnostic": "Diagnostic",
@@ -799,7 +801,6 @@
799801
"listeners.panel.dataListener.createDataFile.error": "No data file id or path defined.",
800802
"listeners.panel.dataListener.createDataFile.noFileName": "No filename provided.",
801803

802-
803804
"listeners.panel.taxonomyListener.aiSuggestTaxonomy.noEditor.error": "No active editor",
804805
"listeners.panel.taxonomyListener.aiSuggestTaxonomy.noData.error": "No article data",
805806

@@ -817,4 +818,4 @@
817818
"services.sponsorAi.getTaxonomySuggestions.warning": "The AI taxonomy generation took too long. Please try again later.",
818819

819820
"services.terminal.openLocalServerTerminal.terminalOption.message": "Starting local server"
820-
}
821+
}

Diff for: package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+9-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "Front Matter CMS",
44
"description": "Front Matter is a CMS that runs within Visual Studio Code. It gives you the power and control of a full-blown CMS while also providing you the flexibility and speed of the static site generator of your choice like: Hugo, Jekyll, Docusaurus, NextJs, Gatsby, and many more...",
55
"icon": "assets/frontmatter-teal-128x128.png",
6-
"version": "10.7.0",
6+
"version": "10.8.0",
77
"preview": false,
88
"publisher": "eliostruyf",
99
"galleryBanner": {
@@ -1061,8 +1061,9 @@
10611061
"panel.globalSettings",
10621062
"panel.seo",
10631063
"panel.actions",
1064-
"panel.contentType",
10651064
"panel.metadata",
1065+
"panel.contentType",
1066+
"panel.gitActions",
10661067
"panel.recentlyModified",
10671068
"panel.otherActions",
10681069
"dashboard.snippets.view",
@@ -1213,6 +1214,12 @@
12131214
},
12141215
"scope": "Media"
12151216
},
1217+
"frontMatter.panel.openOnSupportedFile": {
1218+
"type": "boolean",
1219+
"default": false,
1220+
"markdownDescription": "%setting.frontMatter.panel.openOnSupportedFile.markdownDescription%",
1221+
"scope": "Dashboard"
1222+
},
12161223
"frontMatter.panel.freeform": {
12171224
"type": "boolean",
12181225
"default": true,

Diff for: package.nls.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@
184184
"setting.frontMatter.media.contentTypes.items.properties.fields.properties.type.description": "Define the type of field",
185185
"setting.frontMatter.media.contentTypes.items.properties.fields.properties.single.description": "Is a single line field",
186186

187+
"setting.frontMatter.panel.openOnSupportedFile.markdownDescription": "Specifies if you want to open the panel when opening a supported file. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.panel.openonsupportedfile) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.panel.openonsupportedfile%22%5D)",
187188
"setting.frontMatter.panel.freeform.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. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.panel.freeform) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.panel.freeform%22%5D)",
188189
"setting.frontMatter.panel.actions.disabled.markdownDescription": "Specify the actions you want to disable in the panel. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.panel.actions.disabled) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.panel.actions.disabled%22%5D)",
189190
"setting.frontMatter.preview.host.markdownDescription": "Specify the host URL (example: http://localhost:1313) to be used when opening the preview. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.preview.host) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.preview.host%22%5D)",
@@ -292,4 +293,4 @@
292293
"setting.frontMatter.git.disableOnBranches.markdownDescription": "Specify the branches on which you want to disable the Git actions. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.git.disableonbranches) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.git.disableonbranches%22%5D)",
293294
"setting.frontMatter.git.requiresCommitMessage.markdownDescription": "Specify if you want to require a commit message when publishing your changes for a specified branch. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.git.requirescommitmessage) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.git.requirescommitmessage%22%5D)",
294295
"setting.frontMatter.copilot.family.markdownDescription": "Specify the LLM family of the Copilot you want to use. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.copilot.family) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.copilot.family%22%5D)"
295-
}
296+
}

Diff for: src/commands/Article.ts

+16-5
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,12 @@ export class Article {
172172
/**
173173
* Generate the new slug
174174
*/
175-
public static generateSlug(title: string, article?: ParsedFrontMatter, slugTemplate?: string) {
175+
public static generateSlug(
176+
title: string,
177+
article?: ParsedFrontMatter,
178+
filePath?: string,
179+
slugTemplate?: string
180+
) {
176181
if (!title) {
177182
return;
178183
}
@@ -181,7 +186,7 @@ export class Article {
181186
const suffix = Settings.get(SETTING_SLUG_SUFFIX) as string;
182187

183188
if (article?.data) {
184-
const slug = SlugHelper.createSlug(title, article?.data, slugTemplate);
189+
const slug = SlugHelper.createSlug(title, article?.data, filePath, slugTemplate);
185190

186191
if (typeof slug === 'string') {
187192
return {
@@ -224,7 +229,12 @@ export class Article {
224229
articleDate
225230
);
226231

227-
const slugInfo = Article.generateSlug(articleTitle, article, contentType.slugTemplate);
232+
const slugInfo = Article.generateSlug(
233+
articleTitle,
234+
article,
235+
editor.document.uri.fsPath,
236+
contentType.slugTemplate
237+
);
228238

229239
if (
230240
slugInfo &&
@@ -255,7 +265,8 @@ export class Article {
255265
article.data[pField.name] = processArticlePlaceholdersFromData(
256266
article.data[pField.name],
257267
article.data,
258-
contentType
268+
contentType,
269+
editor.document.uri.fsPath
259270
);
260271
article.data[pField.name] = processTimePlaceholders(
261272
article.data[pField.name],
@@ -335,7 +346,7 @@ export class Article {
335346
} else {
336347
const article = ArticleHelper.getFrontMatter(editor);
337348
if (article?.data) {
338-
return SlugHelper.createSlug(article.data[titleField], article.data, slugTemplate);
349+
return SlugHelper.createSlug(article.data[titleField], article.data, file, slugTemplate);
339350
}
340351
}
341352
}

Diff for: src/commands/Folders.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,9 @@ export class Folders {
219219
: Folders.getAbsFilePath(assetFolder);
220220
const wsFolder = Folders.getWorkspaceFolder();
221221
if (wsFolder) {
222-
const relativePath = relative(parseWinPath(wsFolder.fsPath), parseWinPath(assetFolder));
222+
const relativePath = parseWinPath(
223+
relative(parseWinPath(wsFolder.fsPath), parseWinPath(assetFolder))
224+
);
223225
return relativePath === '' ? '/' : relativePath;
224226
}
225227
}
@@ -636,15 +638,23 @@ export class Folders {
636638
}
637639
}
638640

641+
// For Windows, we need to make sure the drive letter is lowercased for consistency
642+
if (isWindows()) {
643+
folders = folders.map((folder) => parseWinPath(folder));
644+
}
645+
639646
// Filter out the workspace folder
640647
if (wsFolder) {
641-
folders = folders.filter((folder) => folder !== wsFolder.fsPath);
648+
folders = folders.filter((folder) => folder !== parseWinPath(wsFolder.fsPath));
642649
}
643650

644651
const uniqueFolders = [...new Set(folders)];
652+
const relativeFolderPaths = uniqueFolders.map((folder) =>
653+
parseWinPath(relative(parseWinPath(wsFolder.fsPath), folder))
654+
);
645655

646656
Logger.verbose('Folders:getContentFolders:end');
647-
return uniqueFolders.map((folder) => relative(wsFolder?.path || '', folder));
657+
return relativeFolderPaths;
648658
}
649659

650660
/**

Diff for: src/constants/Features.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ export const FEATURE_FLAG = {
44
seo: 'panel.seo',
55
actions: 'panel.actions',
66
metadata: 'panel.metadata',
7-
recentlyModified: 'panel.recentlyModified',
8-
otherActions: 'panel.otherActions',
97
contentType: 'panel.contentType',
10-
gitActions: 'panel.gitActions'
8+
gitActions: 'panel.gitActions',
9+
recentlyModified: 'panel.recentlyModified',
10+
otherActions: 'panel.otherActions'
1111
},
1212
dashboard: {
1313
snippets: {

Diff for: src/constants/settings.ts

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export const SETTING_TEMPLATES_FOLDER = 'templates.folder';
4646
export const SETTING_TEMPLATES_PREFIX = 'templates.prefix';
4747
export const SETTING_TEMPLATES_ENABLED = 'templates.enabled';
4848

49+
export const SETTING_PANEL_OPEN_ON_SUPPORTED_FILE = 'panel.openOnSupportedFile';
4950
export const SETTING_PANEL_FREEFORM = 'panel.freeform';
5051
export const SETTING_PANEL_ACTIONS_DISABLED = 'panel.actions.disabled';
5152

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import * as React from 'react';
2+
import { Messenger } from '@estruyf/vscode/dist/client';
3+
import { DashboardMessage } from '../../DashboardMessage';
4+
import { Checkbox as VSCodeCheckbox } from 'vscrui';
5+
6+
export interface IBooleanOptionProps {
7+
value: boolean | undefined | null;
8+
name: string;
9+
label: string;
10+
}
11+
12+
export const BooleanOption: React.FunctionComponent<IBooleanOptionProps> = ({
13+
value,
14+
name,
15+
label
16+
}: React.PropsWithChildren<IBooleanOptionProps>) => {
17+
const [isChecked, setIsChecked] = React.useState(false);
18+
19+
const onChange = React.useCallback((newValue: boolean) => {
20+
setIsChecked(newValue);
21+
Messenger.send(DashboardMessage.updateSetting, {
22+
name: name,
23+
value: newValue
24+
});
25+
}, [name]);
26+
27+
React.useEffect(() => {
28+
setIsChecked(!!value);
29+
}, [value]);
30+
31+
return (
32+
<VSCodeCheckbox
33+
onChange={onChange}
34+
checked={isChecked}>
35+
{label}
36+
</VSCodeCheckbox>
37+
);
38+
};

Diff for: src/dashboardWebView/components/Media/FolderCreation.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ export const FolderCreation: React.FunctionComponent<IFolderCreationProps> = (
9191

9292
if (scripts.length > 0) {
9393
return (
94-
<div className="flex flex-1 justify-start">
94+
<div className="flex flex-1 justify-start space-x-2">
9595
{renderPostAssetsButton}
96+
9697
<ChoiceButton
9798
title={l10n.t(LocalizationKey.dashboardMediaFolderCreationFolderCreate)}
9899
choices={scripts.map((s) => ({
@@ -103,6 +104,8 @@ export const FolderCreation: React.FunctionComponent<IFolderCreationProps> = (
103104
onClick={onFolderCreation}
104105
disabled={!settings?.initialized}
105106
/>
107+
108+
<RefreshDashboardData />
106109
</div>
107110
);
108111
}

Diff for: src/dashboardWebView/components/Media/Item.tsx

+11-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
PlusIcon,
88
VideoCameraIcon,
99
} from '@heroicons/react/24/outline';
10-
import { basename } from 'path';
10+
import { basename, parse } from 'path';
1111
import * as React from 'react';
1212
import { useCallback, useEffect, useMemo, useState } from 'react';
1313
import { useRecoilState, useRecoilValue } from 'recoil';
@@ -55,8 +55,17 @@ export const Item: React.FunctionComponent<IItemProps> = ({
5555
const { mediaFolder, mediaDetails, isAudio, isImage, isVideo } = useMediaInfo(media);
5656

5757
const relPath = useMemo(() => {
58+
if (viewData?.data?.pageBundle && viewData?.data?.filePath) {
59+
const articlePath = viewData?.data?.filePath;
60+
const articleDir = parse(parseWinPath(articlePath)).dir;
61+
62+
const mediaPath = parseWinPath(media.fsPath);
63+
if (mediaPath.startsWith(articleDir)) {
64+
return getRelPath(media.fsPath, undefined, articleDir);
65+
}
66+
}
5867
return getRelPath(media.fsPath, settings?.staticFolder, settings?.wsFolder);
59-
}, [media.fsPath, settings?.staticFolder, settings?.wsFolder]);
68+
}, [media.fsPath, settings?.staticFolder, settings?.wsFolder, viewData?.data?.pageBundle, viewData?.data?.filePath]);
6069

6170
const hasViewData = useMemo(() => {
6271
return viewData?.data?.filePath !== undefined;

Diff for: src/dashboardWebView/components/SettingsView/CommonSettings.tsx

+11-1
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ import { useRecoilValue } from 'recoil';
66
import { SettingsSelector } from '../../state';
77
import { SettingsInput } from './SettingsInput';
88
import { Button as VSCodeButton } from 'vscrui';
9-
import { DOCS_SUBMODULES, FrameworkDetectors, GIT_CONFIG, SETTING_FRAMEWORK_START, SETTING_GIT_COMMIT_MSG, SETTING_GIT_ENABLED, SETTING_PREVIEW_HOST, SETTING_WEBSITE_URL } from '../../../constants';
9+
import { DOCS_SUBMODULES, FrameworkDetectors, GIT_CONFIG, SETTING_FRAMEWORK_START, SETTING_GIT_COMMIT_MSG, SETTING_GIT_ENABLED, SETTING_PANEL_OPEN_ON_SUPPORTED_FILE, SETTING_PREVIEW_HOST, SETTING_WEBSITE_URL } from '../../../constants';
1010
import { messageHandler } from '@estruyf/vscode/dist/client';
1111
import { DashboardMessage } from '../../DashboardMessage';
1212
import { SettingsCheckbox } from './SettingsCheckbox';
1313
import { ChevronRightIcon } from '@heroicons/react/24/outline';
14+
import { BooleanOption } from '../Header/BooleanOption';
1415

1516
export interface ICommonSettingsProps { }
1617

@@ -73,6 +74,15 @@ export const CommonSettings: React.FunctionComponent<ICommonSettingsProps> = (pr
7374
<Startup settings={settings} />
7475
</div>
7576

77+
<div className='py-4'>
78+
<h2 className='text-xl mb-2'>{l10n.t(LocalizationKey.settingsOpenPanelForSupportedFiles)}</h2>
79+
80+
<BooleanOption
81+
label={l10n.t(LocalizationKey.settingsOpenPanelForSupportedFilesLabel)}
82+
name={SETTING_PANEL_OPEN_ON_SUPPORTED_FILE}
83+
value={settings?.openPanelForSupportedFiles} />
84+
</div>
85+
7686
<div className='py-4'>
7787
<h2 className='text-xl mb-2'>{l10n.t(LocalizationKey.settingsGit)}</h2>
7888

Diff for: src/dashboardWebView/models/Settings.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export interface Settings {
3131
categories: string[];
3232
customTaxonomy: CustomTaxonomy[];
3333
openOnStart: boolean | null;
34+
openPanelForSupportedFiles: boolean | null;
3435
versionInfo: VersionInfo;
3536
pageViewType: DashboardViewType | undefined;
3637
contentTypes: ContentType[];

Diff for: src/extension.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -245,13 +245,14 @@ export async function activate(context: vscode.ExtensionContext) {
245245
// eslint-disable-next-line @typescript-eslint/no-empty-function
246246
export function deactivate() {}
247247

248-
const triggerPageUpdate = (location: string) => {
248+
const triggerPageUpdate = async (location: string) => {
249249
Logger.verbose(`Trigger page update: ${location}`);
250250
pageUpdateDebouncer(() => {
251251
StatusListener.verify(collection);
252252
}, 1000);
253253

254254
if (location === 'onDidChangeActiveTextEditor') {
255+
await PanelProvider.openOnSupportedFile();
255256
PanelProvider.getInstance()?.updateCurrentFile();
256257
}
257258
};

Diff for: src/helpers/ArticleHelper.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ export class ArticleHelper {
572572
await mkdirAsync(newFolder, { recursive: true });
573573
newFilePath = join(
574574
newFolder,
575-
`${sanitize(contentType.defaultFileName ?? `index`)}.${
575+
`${sanitize(contentType.defaultFileName || `index`, { isFileName: true })}.${
576576
fileExtension || contentType.fileType || fileType
577577
}`
578578
);
@@ -684,7 +684,7 @@ export class ArticleHelper {
684684
}
685685

686686
if (fieldName === 'slug' && (fieldValue === null || fieldValue === '')) {
687-
fmData[fieldName] = SlugHelper.createSlug(title, fmData, slugTemplate);
687+
fmData[fieldName] = SlugHelper.createSlug(title, fmData, filePath, slugTemplate);
688688
}
689689

690690
fmData[fieldName] = await processArticlePlaceholdersFromPath(fmData[fieldName], filePath);

Diff for: src/helpers/ContentType.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,8 @@ export class ContentType {
10631063
data[field.name] = processArticlePlaceholdersFromData(
10641064
field.default as string,
10651065
data,
1066-
contentType
1066+
contentType,
1067+
filePath
10671068
);
10681069
data[field.name] = processTimePlaceholders(
10691070
data[field.name],

0 commit comments

Comments
 (0)