mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-03-28 17:42:40 +01:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36ae7081d1 | ||
|
|
7e4c5b0469 | ||
|
|
5fcd8d6fe7 | ||
|
|
0f07be3e3b | ||
|
|
5444925cf4 | ||
|
|
2b89dda08c | ||
|
|
c4feb205fc | ||
|
|
78bfa62ed4 | ||
|
|
f350d4af91 | ||
|
|
d15f2554a1 | ||
|
|
ab603d9419 | ||
|
|
1acf85c6da | ||
|
|
3383a770b4 | ||
|
|
a6d2fffeb9 | ||
|
|
3d530f7929 | ||
|
|
f02f994174 | ||
|
|
343dfb2d5d | ||
|
|
9ddaedaaf2 | ||
|
|
32c6b4c5ea | ||
|
|
90f4d92741 | ||
|
|
580b1dca6d | ||
|
|
520bdf2be3 | ||
|
|
9724168c3f | ||
|
|
ab02e64708 | ||
|
|
f857b0eaa8 | ||
|
|
03aee57221 | ||
|
|
07db685666 | ||
|
|
8684f32d98 | ||
|
|
2e536a4de7 | ||
|
|
739dffe274 | ||
|
|
41d2f3f22b | ||
|
|
e285e8d775 | ||
|
|
9cf4ae46dd | ||
|
|
72c9d1e25f | ||
|
|
5f13d318c2 | ||
|
|
ffdf8262d7 | ||
|
|
7fcbdb4ade | ||
|
|
a8407920bc | ||
|
|
e1f6c90fc0 | ||
|
|
11354ad8e5 | ||
|
|
af3e63046c | ||
|
|
cee4621964 | ||
|
|
8db76abf51 | ||
|
|
3ca50bbe58 | ||
|
|
e4cb93274b | ||
|
|
39ad0e034e | ||
|
|
cef607ffc8 | ||
|
|
258c5fe670 | ||
|
|
046b24337d | ||
|
|
24fb1347df | ||
|
|
3665823803 | ||
|
|
a020b9ad8c | ||
|
|
2c026ff5e5 | ||
|
|
966d0107d9 | ||
|
|
c770a9035f | ||
|
|
f4816afa65 | ||
|
|
6d43ff11a4 | ||
|
|
1c5e98d40c | ||
|
|
ff1c00167c | ||
|
|
599d43b254 |
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,19 +1,29 @@
|
||||
# Change Log
|
||||
|
||||
## [9.4.0] - 2023-xx-xx
|
||||
## [9.4.0] - 2023-12-12 - [Release notes](https://beta.frontmatter.codes/updates/v9.4.0)
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- Localization implemented for the whole extension
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- [#273](https://github.com/estruyf/vscode-front-matter/issues/273): Allow single value arrays to be set as a string with the `singleValueAsString` field property
|
||||
- [#686](https://github.com/estruyf/vscode-front-matter/issues/686): Allow script authors to ask questions during script execution
|
||||
- [#688](https://github.com/estruyf/vscode-front-matter/issues/688): Allow to show the scheduled articles in the content dashboard (filter and group)
|
||||
- [#690](https://github.com/estruyf/vscode-front-matter/issues/690): Added the ability to filter values in the `contentRelationship` field
|
||||
- [#700](https://github.com/estruyf/vscode-front-matter/issues/700): Added the `{{pathToken.relPath}}` placeholder for the `previewPath` property
|
||||
- [#706](https://github.com/estruyf/vscode-front-matter/issues/706): Show the error of scripts failing in the Front Matter output panel
|
||||
- [#709](https://github.com/estruyf/vscode-front-matter/issues/709): Take "where clause" into account on content creation
|
||||
- [#710](https://github.com/estruyf/vscode-front-matter/issues/710): Hide child field when parent field its "when clause" is not met, also remove the fields from the content
|
||||
- [#713](https://github.com/estruyf/vscode-front-matter/issues/713): Add the ability to always use quotes around string values in front matter
|
||||
- [#722](https://github.com/estruyf/vscode-front-matter/issues/722): Allow to create sub-content which shows a dialog to select the parent folder
|
||||
|
||||
### ⚡️ Optimizations
|
||||
|
||||
- Dashboard layout grid optimizations
|
||||
- Added the content-type name to the metadata section in the panel
|
||||
- New implementation of the combobox for the `contentRelationship` field
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
@@ -22,6 +32,15 @@
|
||||
- [#694](https://github.com/estruyf/vscode-front-matter/issues/694): Start terminal session from the folder where the `frontmatter.json` file is located
|
||||
- [#696](https://github.com/estruyf/vscode-front-matter/issues/696): Close the local server terminal on restart
|
||||
- [#699](https://github.com/estruyf/vscode-front-matter/issues/699): Changing border theme variable for the dashboard header
|
||||
- [#703](https://github.com/estruyf/vscode-front-matter/issues/703): Fix retrieval of Astro Collections for `pnpm` projects
|
||||
- [#704](https://github.com/estruyf/vscode-front-matter/issues/704): Fix `zod` schema script for optional fields
|
||||
- [#707](https://github.com/estruyf/vscode-front-matter/issues/707): Fix `clearEmpty` issue with `draft` and `boolean` fields which are by default set to `true`
|
||||
- [#711](https://github.com/estruyf/vscode-front-matter/issues/711): Fix in character mapping in the slug field
|
||||
- [#712](https://github.com/estruyf/vscode-front-matter/issues/712): Keep the search context when deleting media files
|
||||
- [#714](https://github.com/estruyf/vscode-front-matter/issues/714): Fix for taxonomy filtering from taxonomy view to content view
|
||||
- [#717](https://github.com/estruyf/vscode-front-matter/issues/717): Fix in loading yaml data files
|
||||
- [#718](https://github.com/estruyf/vscode-front-matter/issues/718): Fix JSON schema for the `frontMatter.panel.actions.disabled` setting
|
||||
- [#719](https://github.com/estruyf/vscode-front-matter/issues/719): Fix styling on data view with objects views
|
||||
|
||||
## [9.3.1] - 2023-10-27
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ Eager to start contributing? Great 🤩, you can contribute to the following pro
|
||||
|
||||
- Start by forking this project;
|
||||
- Clone your fork to your local machine;
|
||||
- Run `pnpm i`;
|
||||
- Run `npm i`;
|
||||
- Open the project in VS Code;
|
||||
- To start developing, run `pnpm dev:ext` and press `f5` to start the debugging session.
|
||||
- To start developing, run `npm run dev:ext` and press `f5` to start the debugging session.
|
||||
|
||||
### Tips
|
||||
|
||||
|
||||
1
l10n/bundle.l10n.es.json
Normal file
1
l10n/bundle.l10n.es.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -28,6 +28,13 @@
|
||||
"common.pin": "Pin",
|
||||
"common.unpin": "Unpin",
|
||||
"common.noResults": "No results",
|
||||
"common.error": "Sorry, something went wrong.",
|
||||
"common.yes": "yes",
|
||||
"common.no": "no",
|
||||
"common.openSettings": "Open settings",
|
||||
|
||||
"notifications.outputChannel.link": "output window",
|
||||
"notifications.outputChannel.description": "Check the {0} for more details.",
|
||||
|
||||
"settings.view.common": "Common",
|
||||
"settings.view.contentFolders": "Content folders",
|
||||
@@ -269,6 +276,7 @@
|
||||
"dashboard.steps.stepsToGetStarted.showDashboard.description": "Once all actions are completed, the dashboard can be loaded.",
|
||||
"dashboard.steps.stepsToGetStarted.template.name": "Use a configuration template",
|
||||
"dashboard.steps.stepsToGetStarted.template.description": "Select a template to prefill the frontmatter.json file with the recommended settings.",
|
||||
"dashboard.steps.stepsToGetStarted.template.warning": "Selecting a template applies a whole configuration to your project and closes this configuration view.",
|
||||
"dashboard.steps.stepsToGetStarted.astroContentTypes.name": "Create Content-Types for your Astro Content Collections",
|
||||
|
||||
"dashboard.taxonomyView.button.add.title": "Add {0} to taxonomy settings",
|
||||
@@ -312,7 +320,7 @@
|
||||
"dashboard.media.detailsSlideOver.unmapped.description": "Do you want to remap the metadata of unmapped files?",
|
||||
|
||||
"dashboard.configuration.astro.astroContentTypes.empty": "No Astro Content Collections found.",
|
||||
"dashboard.configuration.astro.astroContentTypes.description": "The following Astro Content Collections and can be used to generate a content-type.",
|
||||
"dashboard.configuration.astro.astroContentTypes.description": "The following Astro Content Collections can be used to generate a content-type.",
|
||||
|
||||
"panel.contentType.contentTypeValidator.title": "Content-type",
|
||||
"panel.contentType.contentTypeValidator.hint": "We noticed field differences between the content-type and the front matter data. \n Would you like to create, update, or set the content-type for this content?",
|
||||
@@ -457,5 +465,250 @@
|
||||
|
||||
"panel.viewPanel.mediaInsert": "Continue in the media dashboard to select the image you want to insert.",
|
||||
|
||||
"listeners.dashboard.settingsListener.triggerTemplate.notification": "Template files copied."
|
||||
"commands.article.notification.noTaxonomy": "No {0} configured.",
|
||||
"commands.article.quickPick.placeholder": "Select your {0} to insert.",
|
||||
"commands.article.setDate.error": "Something failed while parsing the date format. Check your \"{0}\" setting.",
|
||||
"commands.article.updateSlug.error": "Failed to rename file: {0}",
|
||||
|
||||
"commands.cache.cleared": "Cache cleared",
|
||||
|
||||
"commands.chatbot.title": "Ask me anything",
|
||||
|
||||
"commands.content.option.contentType.label": "Create content by content type",
|
||||
"commands.content.option.contentType.description": "Select if you want to create new content by the available content type(s)",
|
||||
"commands.content.option.template.label": "Create content by template",
|
||||
"commands.content.option.template.description": "Select if you want to create new content by the available template(s)",
|
||||
"commands.content.quickPick.title": "Create content",
|
||||
"commands.content.quickPick.placeholder": "Select how you want to create your new content",
|
||||
|
||||
"commands.dashboard.title": "Dashboard",
|
||||
|
||||
"commands.folders.addMediaFolder.inputBox.title": "Add media folder",
|
||||
"commands.folders.addMediaFolder.inputBox.prompt": "Which name would you like to give to your folder (use \"/\" to create multi-level folders)?",
|
||||
"commands.folders.addMediaFolder.noFolder.warning": "No folder name was specified.",
|
||||
"commands.folders.create.folderExists.warning": "Folder is already registered",
|
||||
"commands.folders.create.input.title": "Register folder",
|
||||
"commands.folders.create.input.prompt": "Which name would you like to specify for this folder?",
|
||||
"commands.folders.create.input.placeholder": "Folder name",
|
||||
"commands.folders.create.success": "Folder registered",
|
||||
"commands.folders.getWorkspaceFolder.workspaceFolderPick.placeholder": "Please select the main workspace folder for Front Matter to use.",
|
||||
"commands.folders.get.notificationError.title": "Folder \"{0}\" does not exist. Please remove it from the settings.",
|
||||
"commands.folders.get.notificationError.remove.action": "Remove folder",
|
||||
"commands.folders.get.notificationError.create.action": "Create folder",
|
||||
|
||||
"commands.preview.panel.title": "Preview: {0}",
|
||||
"commands.preview.askUserToPickFolder.title": "Select the folder of the article to preview",
|
||||
|
||||
"commands.project.initialize.success": "Project initialized successfully.",
|
||||
"commands.project.switchProject.title": "To which project do you want to switch?",
|
||||
"commands.project.createSampleTemplate.info": "Sample template created.",
|
||||
|
||||
"commands.settings.create.input.prompt": "Insert the value of the {0} that you want to add to your configuration.",
|
||||
"commands.settings.create.input.placeholder": "Name of the {0}",
|
||||
"commands.settings.create.warning": "The provided {0} already exists.",
|
||||
"commands.settings.create.quickPick.placeholder": "Do you want to add the new {0} to the page?",
|
||||
"commands.settings.export.progress.title": "{0}: exporting tags and categories",
|
||||
"commands.settings.export.progress.success": "Export completed. Tags: {0} - Categories: {1}.",
|
||||
"commands.settings.remap.quickpick.title": "Remap",
|
||||
"commands.settings.remap.quickpick.placeholder": "What do you want to remap?",
|
||||
"commands.settings.remap.noTaxonomy.warning": "No {0} configured.",
|
||||
"commands.settings.remap.selectTaxonomy.placeholder": "Select your {0} to insert.",
|
||||
"commands.settings.remap.newOption.input.prompt": "Specify the value of the {0} with which you want to remap \"{1}\". Leave the input <blank> if you want to remove the {0} from all articles.",
|
||||
"commands.settings.remap.newOption.input.placeholder": "Name of the {0}",
|
||||
"commands.settings.remap.delete.placeholder": "Delete {0} {1}?",
|
||||
|
||||
"commands.statusListener.verifyRequiredFields.diagnostic.emptyField": "The {0} field is required. Please define a value for the field.",
|
||||
"commands.statusListener.verifyRequiredFields.notification.error": "The following fields are required to contain a value: {0}",
|
||||
|
||||
"commands.template.generate.input.title": "Template title",
|
||||
"commands.template.generate.input.prompt": "Which name would you like to give your template?",
|
||||
"commands.template.generate.input.placeholder": "article",
|
||||
"commands.template.generate.noTitle.warning": "You did not specify a template title.",
|
||||
"commands.template.generate.keepContents.title": "Keep content",
|
||||
"commands.template.generate.keepContents.placeholder": "Do you want to keep the contents for the template?",
|
||||
"commands.template.generate.keepContents.noOption.warning": "You did not pick any of the options for keeping the template its content.",
|
||||
"commands.template.generate.keepContents.success": "Template created and is now available in your {0} folder.",
|
||||
"commands.template.getTemplates.warning": "No templates found.",
|
||||
"commands.template.create.folderPath.warning": "Incorrect project folder path retrieved.",
|
||||
"commands.template.create.noTemplates.warning": "No templates found.",
|
||||
"commands.template.create.selectTemplate.title": "Select a template",
|
||||
"commands.template.create.selectTemplate.placeholder": "Select the content template to use",
|
||||
"commands.template.create.selectTemplate.noTemplate.warning": "No template selected.",
|
||||
"commands.template.create.selectTemplate.notFound.warning": "Content template could not be found.",
|
||||
"commands.template.create.success": "Your new content is now available.",
|
||||
|
||||
"commands.wysiwyg.command.unorderedList.label": "Unordered list",
|
||||
"commands.wysiwyg.command.unorderedList.detail": "Add an unordered list",
|
||||
"commands.wysiwyg.command.orderedList.label": "Ordered list",
|
||||
"commands.wysiwyg.command.orderedList.detail": "Add an ordered list",
|
||||
"commands.wysiwyg.command.taskList.label": "Task list",
|
||||
"commands.wysiwyg.command.taskList.detail": "Add a task list",
|
||||
"commands.wysiwyg.command.code.label": "Code",
|
||||
"commands.wysiwyg.command.code.detail": "Add inline code snippet",
|
||||
"commands.wysiwyg.command.codeblock.label": "Code block",
|
||||
"commands.wysiwyg.command.codeblock.detail": "Add a code block",
|
||||
"commands.wysiwyg.command.blockquote.label": "Blockquote",
|
||||
"commands.wysiwyg.command.blockquote.detail": "Add a blockquote",
|
||||
"commands.wysiwyg.command.strikethrough.label": "Strikethrough",
|
||||
"commands.wysiwyg.command.strikethrough.detail": "Add strikethrough text",
|
||||
"commands.wysiwyg.quickPick.title": "WYSIWYG Options",
|
||||
"commands.wysiwyg.quickPick.placeholder": "Which type of markup would you like to insert?",
|
||||
"commands.wysiwyg.addHyperlink.hyperlinkInput.title": "WYSIWYG Hyperlink",
|
||||
"commands.wysiwyg.addHyperlink.hyperlinkInput.prompt": "Enter the URL",
|
||||
"commands.wysiwyg.addHyperlink.textInput.title": "WYSIWYG Text",
|
||||
"commands.wysiwyg.addHyperlink.textInput.prompt": "Enter the text for the hyperlink",
|
||||
"commands.wysiwyg.insertText.heading.input.title": "Heading level",
|
||||
"commands.wysiwyg.insertText.heading.input.placeholder": "Which heading level do you want to insert?",
|
||||
|
||||
"helpers.articleHelper.createContent.pageBundle.error": "A page bundle with the name {0} already exists in {1}.",
|
||||
"helpers.articleHelper.createContent.contentExists.warning": "Content with the title already exists. Please specify a new title.",
|
||||
"helpers.articleHelper.processCustomPlaceholders.placeholder.error": "Error while processing the {0} placeholder.",
|
||||
"helpers.articleHelper.parseFile.diagnostic.error": "Error parsing the front matter of {0}.",
|
||||
|
||||
"helpers.contentType.generate.noFrontMatter.error": "No front matter data found to generate a content type.",
|
||||
"helpers.contentType.generate.override.quickPick.title": "Override the default content type",
|
||||
"helpers.contentType.generate.override.quickPick.placeholder": "Do you want to overwrite the default content type configuration with the fields used in the current field?",
|
||||
"helpers.contentType.generate.contentTypeInput.title": "Generate Content Type",
|
||||
"helpers.contentType.generate.contentTypeInput.prompt": "Enter the name of the content type to generate",
|
||||
"helpers.contentType.generate.contentTypeInput.validation.enterName": "Please enter a name for the content type.",
|
||||
"helpers.contentType.generate.contentTypeInput.validation.nameExists": "A content type with this name already exists.",
|
||||
"helpers.contentType.generate.noContentTypeName.warning": "You didn't specify a name for the content type.",
|
||||
"helpers.contentType.generate.pageBundle.quickPick.title": "Use as a page bundle",
|
||||
"helpers.contentType.generate.pageBundle.quickPick.placeHolder": "Do you want to use this content type as a page bundle?",
|
||||
"helpers.contentType.generate.updated.success": "Content type {0} has been updated.",
|
||||
"helpers.contentType.generate.generated.success": "Content type {0} has been generated.",
|
||||
"helpers.contentType.addMissingFields.noFrontMatter.warning": "No front matter data found to add missing fields.",
|
||||
"helpers.contentType.addMissingFields.updated.success": "Content type {0} has been updated.",
|
||||
"helpers.contentType.setContentType.noFrontMatter.warning": "No front matter data found to set the content type.",
|
||||
"helpers.contentType.setContentType.quickPick.title": "Select the content type",
|
||||
"helpers.contentType.setContentType.quickPick.placeholder": "Which content type would you like to use?",
|
||||
"helpers.contentType.create.allowSubContent.title": "Do you want to create it as sub-content?",
|
||||
"helpers.contentType.create.allowSubContent.placeHolder": "Do you want to create it as sub-content?",
|
||||
"helpers.contentType.create.allowSubContent.showOpenDialog.openLabel": "Select folder",
|
||||
"helpers.contentType.create.allowSubContent.showOpenDialog.title": "Select folder to create the content",
|
||||
"helpers.contentType.create.pageBundle.title": "Create as a page bundle?",
|
||||
"helpers.contentType.create.pageBundle.placeHolder": "Do you want to create the sub-content as a page bundle?",
|
||||
"helpers.contentType.create.progress.title": "{0}: Creating content...",
|
||||
"helpers.contentType.create.success": "Your new content has been created.",
|
||||
"helpers.contentType.verify.warning": "The content type actions are not available in this mode.",
|
||||
|
||||
"helpers.customScript.executing": "Executing: {0}",
|
||||
"helpers.customScript.singleRun.article.warning": "{0}: Article couldn't be retrieved.",
|
||||
"helpers.customScript.bulkRun.noFiles.warning": "{0}: No files found",
|
||||
"helpers.customScript.runMediaScript.noFolder.warning": "{0}: There was no folder or media path specified.",
|
||||
"helpers.customScript.showOutput.frontMatter.success": "{0}: front matter updated.",
|
||||
"helpers.customScript.showOutput.copyOutput.action": "Copy output",
|
||||
"helpers.customScript.showOutput.success": "{0}: Executed your custom script.",
|
||||
"helpers.customScript.validateCommand.error": "Invalid command: {0}",
|
||||
|
||||
"helpers.dataFileHelper.process.error": "Something went wrong while processing the data file.",
|
||||
|
||||
"helpers.extension.getVersion.changelog": "Check the changelog",
|
||||
"helpers.extension.getVersion.starIt": "Give it a ⭐️",
|
||||
"helpers.extension.getVersion.update.notification": "{0} has been updated to v{1} — check out what's new!",
|
||||
"helpers.extension.migrateSettings.deprecated.warning": "The \"{0}\" and \"{1}\" settings have been deprecated. Please use the \"isPublishDate\" and \"isModifiedDate\" datetime field properties instead.",
|
||||
"helpers.extension.migrateSettings.deprecated.warning.hide": "Hide",
|
||||
"helpers.extension.migrateSettings.deprecated.warning.seeGuide": "See migration guide",
|
||||
"helpers.extension.migrateSettings.templates.quickPick.title": "{0} - Templates",
|
||||
"helpers.extension.migrateSettings.templates.quickPick.placeholder": "Do you want to keep on using the template functionality?",
|
||||
"helpers.extension.checkIfExtensionCanRun.warning": "Front Matter BETA cannot be used while the stable version is installed. Please ensure that you have only over version installed.",
|
||||
|
||||
"helpers.mediaHelper.saveFile.folder.error": "We couldn't find your selected folder.",
|
||||
"helpers.mediaHelper.saveFile.file.uploaded.success": "File {0} uploaded to: {1}",
|
||||
"helpers.mediaHelper.saveFile.file.uploaded.failed": "Sorry, something went wrong uploading {0}",
|
||||
"helpers.mediaHelper.deleteFile.file.deletion.failed": "Sorry, something went wrong deleting {0}",
|
||||
|
||||
"helpers.mediaLibrary.remove.warning": "The name \"{0}\" already exists at the file location.",
|
||||
"helpers.mediaLibrary.remove.error": "Sorry, something went wrong updating \"{0}\" to \"{1}\".",
|
||||
|
||||
"helpers.openFileInEditor.error": "Couldn't open the file.",
|
||||
|
||||
"helpers.questions.contentTitle.aiInput.title": "Title or description",
|
||||
"helpers.questions.contentTitle.aiInput.prompt": "What would you like to write about?",
|
||||
"helpers.questions.contentTitle.aiInput.placeholder": "What would you like to write about?",
|
||||
"helpers.questions.contentTitle.aiInput.quickPick.title.separator": "your title/description",
|
||||
"helpers.questions.contentTitle.aiInput.quickPick.ai.separator": "AI generated title",
|
||||
"helpers.questions.contentTitle.aiInput.select.title": "Select a title",
|
||||
"helpers.questions.contentTitle.aiInput.select.placeholder": "Select a title for your content",
|
||||
"helpers.questions.contentTitle.aiInput.failed": "Failed fetching the AI title. Please try to use your own title or try again later.",
|
||||
"helpers.questions.contentTitle.aiInput.warning": "You did not specify a title for your content.",
|
||||
"helpers.questions.contentTitle.titleInput.title": "Content title",
|
||||
"helpers.questions.contentTitle.titleInput.prompt": "What would you like to use as a title for the content to create?",
|
||||
"helpers.questions.contentTitle.titleInput.placeholder": "Content title",
|
||||
"helpers.questions.contentTitle.titleInput.warning": "You did not specify a title for your content.",
|
||||
"helpers.questions.selectContentFolder.quickPick.title": "Select a folder",
|
||||
"helpers.questions.selectContentFolder.quickPick.placeholder": "Select where you want to create your content",
|
||||
"helpers.questions.selectContentFolder.quickPick.noFolders.warning": "No page folders were configured.",
|
||||
"helpers.questions.selectContentFolder.quickPick.noSelection.warning": "You didn't select a place where you wanted to create your content.",
|
||||
"helpers.questions.selectContentType.noContentType.warning": "No content types found. Please create a content type first.",
|
||||
"helpers.questions.selectContentType.quickPick.title": "Content type",
|
||||
"helpers.questions.selectContentType.quickPick.placeholder": "Select the content type to create your new content",
|
||||
"helpers.questions.selectContentType.noSelection.warning": "No content type was selected.",
|
||||
|
||||
"helpers.seoHelper.checkLength.diagnostic.message": "Article {0} is longer than {1} characters (current length: {2}). For SEO reasons, it would be better to make it less than {1} characters.",
|
||||
|
||||
"helpers.settingsHelper.checkToPromote.message": "You have local settings. Would you like to promote them to the global settings (\"frontmatter.json\")?",
|
||||
"helpers.settingsHelper.promote.success": "All settings promoted to team level.",
|
||||
"helpers.settingsHelper.readConfig.progress.title": "{0}: Reading dynamic config file...",
|
||||
"helpers.settingsHelper.readConfig.error": "Error reading your configuration.",
|
||||
"helpers.settingsHelper.refreshConfig.success": "Settings have been refreshed.",
|
||||
|
||||
"helpers.taxonomyHelper.rename.input.title": "Rename the {0}",
|
||||
"helpers.taxonomyHelper.rename.validate.equalValue": "The new value must be different from the old one.",
|
||||
"helpers.taxonomyHelper.rename.validate.noValue": "A new value must be provided.",
|
||||
"helpers.taxonomyHelper.merge.quickPick.title": "Merge the \"{0}\" with another {1} value",
|
||||
"helpers.taxonomyHelper.merge.quickPick.placeholder": "Select the {0} value to merge with",
|
||||
"helpers.taxonomyHelper.delete.quickPick.title": "Delete the \"{0}\" {1} value",
|
||||
"helpers.taxonomyHelper.delete.quickPick.placeholder": "Are you sure you want to delete the \"{0}\" {1} value?",
|
||||
"helpers.taxonomyHelper.createNew.input.title": "Create a new {0} value",
|
||||
"helpers.taxonomyHelper.createNew.input.placeholder": "Enter the value you want to add",
|
||||
"helpers.taxonomyHelper.createNew.input.validate.noValue": "A value must be provided.",
|
||||
"helpers.taxonomyHelper.createNew.input.validate.exists": "The value already exists.",
|
||||
"helpers.taxonomyHelper.process.edit": "{0}: Renaming \"{1}\" from {2} to {3}.",
|
||||
"helpers.taxonomyHelper.process.merge": "{0}: Merging \"{1}\" from {2} to {3}.",
|
||||
"helpers.taxonomyHelper.process.delete": "{0}: Deleting \"{1}\" from {2}.",
|
||||
"helpers.taxonomyHelper.process.edit.success": "Edit completed.",
|
||||
"helpers.taxonomyHelper.process.merge.success": "Merge completed.",
|
||||
"helpers.taxonomyHelper.process.delete.success": "Deletion completed.",
|
||||
"helpers.taxonomyHelper.move.quickPick.title": "Move the \"{0}\" to another type",
|
||||
"helpers.taxonomyHelper.move.quickPick.placeholder": "Select the type to move to",
|
||||
"helpers.taxonomyHelper.move.progress.title": "{0}: Moving \"{1}\" from {2} to \"${3}\".",
|
||||
"helpers.taxonomyHelper.move.success": "Move completed.",
|
||||
|
||||
"listeners.dashboard.dashboardListener.openConfig.notification": "Open the \"frontmatter.json\" file if you want to review the configuration.",
|
||||
"listeners.dashboard.dashboardListener.pinItem.noPath.error": "No path provided.",
|
||||
"listeners.dashboard.dashboardListener.pinItem.coundNotPin.error": "Could not pin item.",
|
||||
"listeners.dashboard.dashboardListener.pinItem.coundNotUnPin.error": "Could not unpin item.",
|
||||
|
||||
"listeners.dashboard.settingsListener.triggerTemplate.notification": "Template files copied.",
|
||||
"listeners.dashboard.settingsListener.triggerTemplate.progress.title": "Downloading and initializing the template...",
|
||||
"listeners.dashboard.settingsListener.triggerTemplate.download.error": "Failed to download the template.",
|
||||
"listeners.dashboard.settingsListener.triggerTemplate.init.error": "Failed to initialize the template.",
|
||||
|
||||
"listeners.dashboard.snippetListener.addSnippet.missingFields.warning": "Snippet missing title or body",
|
||||
"listeners.dashboard.snippetListener.addSnippet.exists.warning": "Snippet with the same title already exists",
|
||||
"listeners.dashboard.snippetListener.updateSnippet.noSnippets.warning": "No snippets to update",
|
||||
|
||||
"listeners.general.gitListener.push.error": "Failed to push submodules.",
|
||||
|
||||
"listeners.panel.dataListener.aiSuggestTaxonomy.noEditor.error": "No active editor",
|
||||
"listeners.panel.dataListener.aiSuggestTaxonomy.noData.error": "No article data",
|
||||
"listeners.panel.dataListener.getDataFileEntries.noDataFiles.error": "Couldn't find data file entries",
|
||||
|
||||
|
||||
"listeners.panel.taxonomyListener.aiSuggestTaxonomy.noEditor.error": "No active editor",
|
||||
"listeners.panel.taxonomyListener.aiSuggestTaxonomy.noData.error": "No article data",
|
||||
|
||||
"services.modeSwitch.switchMode.quickPick.placeholder": "Select the mode you want to use",
|
||||
"services.modeSwitch.switchMode.quickPick.title": "{0}: Mode selection",
|
||||
"services.modeSwitch.setText.mode": "Mode: {0}",
|
||||
|
||||
"services.pagesParser.parsePages.statusBar.text": "Processing...",
|
||||
"services.pagesParser.parsePages.file.error": "File error: {0}",
|
||||
|
||||
"services.sponsorAi.getTitles.warning": "The AI title generation took too long. Please try again later.",
|
||||
"services.sponsorAi.getDescription.warning": "The AI description generation took too long. Please try again later.",
|
||||
"services.sponsorAi.getTaxonomySuggestions.warning": "The AI taxonomy generation took too long. Please try again later.",
|
||||
|
||||
"services.terminal.openLocalServerTerminal.terminalOption.message": "Starting local server"
|
||||
}
|
||||
1
l10n/bundle.l10n.ko.json
Normal file
1
l10n/bundle.l10n.ko.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
l10n/bundle.l10n.pt-br.json
Normal file
1
l10n/bundle.l10n.pt-br.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
41
package.json
41
package.json
@@ -1005,15 +1005,18 @@
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"markdownDescription": "%setting.frontMatter.panel.actions.disabled.markdownDescription%",
|
||||
"enum": [
|
||||
"openDashboard",
|
||||
"createContent",
|
||||
"optimizeSlug",
|
||||
"preview",
|
||||
"openOnWebsite",
|
||||
"startStopServer",
|
||||
"customActions"
|
||||
]
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"openDashboard",
|
||||
"createContent",
|
||||
"optimizeSlug",
|
||||
"preview",
|
||||
"openOnWebsite",
|
||||
"startStopServer",
|
||||
"customActions"
|
||||
]
|
||||
}
|
||||
},
|
||||
"frontMatter.preview.host": {
|
||||
"type": "string",
|
||||
@@ -1082,7 +1085,17 @@
|
||||
"clearEmpty": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.clearEmpty.description%"
|
||||
"description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.clearEmpty.description%"
|
||||
},
|
||||
"allowAsSubContent": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.allowAsSubContent.description%"
|
||||
},
|
||||
"isSubContent": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.isSubContent.description%"
|
||||
},
|
||||
"fields": {
|
||||
"$id": "#contenttypefield",
|
||||
@@ -1743,6 +1756,12 @@
|
||||
"markdownDescription": "%setting.frontMatter.taxonomy.modifiedField.markdownDescription%",
|
||||
"deprecationMessage": "%setting.frontMatter.taxonomy.modifiedField.deprecationMessage%"
|
||||
},
|
||||
"frontMatter.taxonomy.quoteStringValues": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"markdownDescription": "%setting.frontMatter.taxonomy.quoteStringValues.markdownDescription%",
|
||||
"scope": "Taxonomy"
|
||||
},
|
||||
"frontMatter.taxonomy.noPropertyValueQuotes": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
@@ -2514,7 +2533,7 @@
|
||||
"clean": "rimraf dist",
|
||||
"start:site": "cd ./docs && npm run dev",
|
||||
"clean:test": "rm ./e2e/sample/frontmatter.json || exit 0 && rm -rf ./e2e/sample/.frontmatter || exit 0",
|
||||
"test": "pnpm lint; tsc -p tsconfig.e2e.json && npm run clean:test && pnpm i -g @vscode/vsce && node ./e2e/out/runTests.js",
|
||||
"test": "npm run lint; tsc -p tsconfig.e2e.json && npm run clean:test && npm run i -g @vscode/vsce && node ./e2e/out/runTests.js",
|
||||
"lint": "eslint --max-warnings=0 ./src/{commands,components}",
|
||||
"prettier": "prettier --write ./src",
|
||||
"localization:watch": "node ./scripts/watch-localization.js",
|
||||
|
||||
@@ -225,6 +225,7 @@
|
||||
"setting.frontMatter.taxonomy.frontMatterType.markdownDescription": "Specify the type of Front Matter to use. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.frontmattertype)",
|
||||
"setting.frontMatter.taxonomy.indentArrays.markdownDescription": "Specify if arrays in front matter are indented. Default: true. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.indentarrays)",
|
||||
"setting.frontMatter.taxonomy.modifiedField.markdownDescription": "This setting is used to define the modified date field of your articles. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.modifiedfield)",
|
||||
"setting.frontMatter.taxonomy.quoteStringValues.markdownDescription": "Specify if you want to quote string values in the front matter. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.quotestringvalues)",
|
||||
"setting.frontMatter.taxonomy.noPropertyValueQuotes.markdownDescription": "Specify the properties from which quotes need to be removed. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.nopropertyvaluequotes)",
|
||||
"setting.frontMatter.taxonomy.noPropertyValueQuotes.items.description": "Name of the properties you want to remove quotes from.",
|
||||
"setting.frontMatter.taxonomy.seoContentLengh.markdownDescription": "Specifies the optimal minimum length for your articles. Between 1,760 words – 2,400 is the absolute ideal article length for SEO in 2021. (set to `-1` to turn it off). [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.seocontentlengh)",
|
||||
@@ -244,8 +245,10 @@
|
||||
"setting.frontMatter.taxonomy.dateField.deprecationMessage": "This setting is deprecated and will be removed in the next major version. Please use the new `isPublishDate` settings instead in your content types date fields.",
|
||||
"setting.frontMatter.taxonomy.modifiedField.deprecationMessage": "This setting is deprecated and will be removed in the next major version. Please use the new `isModifiedDate` settings instead in your content types date fields.",
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.customType.description": "Specify the name of the custom field type to use.",
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.clearEmpty.description": "Specify if the empty values should be cleared.",
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.clearEmpty.description": "Specify if the empty values should be cleared.",
|
||||
"setting.frontMatter.website.host.markdownDescription": "Specify the host URL of your website. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.website.url)",
|
||||
"command.frontMatter.settings.refresh": "Refresh Front Matter Settings",
|
||||
"setting.frontMatter.config.dynamicFilePath.markdownDescription": "Specify the path to the dynamic config file (ex: [[workspace]]/config.js). [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.config.dynamicfilepath)"
|
||||
"setting.frontMatter.config.dynamicFilePath.markdownDescription": "Specify the path to the dynamic config file (ex: [[workspace]]/config.js). [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.config.dynamicfilepath)",
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.allowAsSubContent.description": "Specify if the content type can be used as sub content.",
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.isSubContent.description": "Specify if the content type is sub content."
|
||||
}
|
||||
8237
pnpm-lock.yaml
generated
8237
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const jsoncParser = require('jsonc-parser');
|
||||
|
||||
const camlCase = (str) => {
|
||||
const words = str.split('.');
|
||||
@@ -15,12 +16,14 @@ const camlCase = (str) => {
|
||||
const enFile = fs.readFileSync(path.join(__dirname, '../l10n/bundle.l10n.json'), 'utf8');
|
||||
|
||||
// Parse the EN file
|
||||
const en = JSON.parse(enFile);
|
||||
const en = jsoncParser.parse(enFile);
|
||||
|
||||
const keys = Object.keys(en);
|
||||
|
||||
// Create an enum file
|
||||
const enumFile = fs.createWriteStream(path.join(__dirname, '../src/localization/localization.enum.ts'));
|
||||
const enumFile = fs.createWriteStream(
|
||||
path.join(__dirname, '../src/localization/localization.enum.ts')
|
||||
);
|
||||
|
||||
// Write the enum file header
|
||||
enumFile.write(`export enum LocalizationKey {\n`);
|
||||
@@ -38,4 +41,4 @@ const camlCase = (str) => {
|
||||
|
||||
// Close the enum file
|
||||
enumFile.close();
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -29,6 +29,8 @@ import { NavigationType } from '../dashboardWebView/models';
|
||||
import { processKnownPlaceholders } from '../helpers/PlaceholderHelper';
|
||||
import { Position } from 'vscode';
|
||||
import { SNIPPET } from '../constants/Snippet';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Article {
|
||||
/**
|
||||
@@ -80,12 +82,20 @@ export class Article {
|
||||
}
|
||||
|
||||
if (options.length === 0) {
|
||||
Notifications.info(`No ${type === TaxonomyType.Tag ? 'tags' : 'categories'} configured.`);
|
||||
Notifications.info(
|
||||
l10n.t(
|
||||
LocalizationKey.commandsArticleNotificationNoTaxonomy,
|
||||
type === TaxonomyType.Tag ? 'tags' : 'categories'
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedOptions = await vscode.window.showQuickPick(options, {
|
||||
placeHolder: `Select your ${type === TaxonomyType.Tag ? 'tags' : 'categories'} to insert`,
|
||||
placeHolder: l10n.t(
|
||||
LocalizationKey.commandsArticleQuickPickPlaceholder,
|
||||
type === TaxonomyType.Tag ? 'tags' : 'categories'
|
||||
),
|
||||
canPickMany: true,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
@@ -117,7 +127,7 @@ export class Article {
|
||||
ArticleHelper.update(editor, article);
|
||||
} catch (e) {
|
||||
Notifications.error(
|
||||
`Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`
|
||||
l10n.t(LocalizationKey.commandsArticleSetDateError, `${CONFIG_KEY}${SETTING_DATE_FORMAT}`)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -180,7 +190,7 @@ export class Article {
|
||||
return cloneArticle;
|
||||
} catch (e: unknown) {
|
||||
Notifications.error(
|
||||
`Something failed while parsing the date format. Check your "${CONFIG_KEY}${SETTING_DATE_FORMAT}" setting.`
|
||||
l10n.t(LocalizationKey.commandsArticleSetDateError, `${CONFIG_KEY}${SETTING_DATE_FORMAT}`)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -292,7 +302,12 @@ export class Article {
|
||||
overwrite: false
|
||||
});
|
||||
} catch (e: unknown) {
|
||||
Notifications.error(`Failed to rename file: ${(e as Error).message || e}`);
|
||||
Notifications.error(
|
||||
l10n.t(
|
||||
LocalizationKey.commandsArticleUpdateSlugError,
|
||||
((e as Error).message || e) as string
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +1,65 @@
|
||||
import { commands, ExtensionContext } from 'vscode';
|
||||
import { authentication, commands, ExtensionContext } from 'vscode';
|
||||
import { COMMAND_NAME, CONTEXT } from '../constants';
|
||||
import { Extension } from '../helpers';
|
||||
import { Credentials } from '../services/Credentials';
|
||||
import { Extension, Logger } from '../helpers';
|
||||
import fetch from 'node-fetch';
|
||||
import { Dashboard } from './Dashboard';
|
||||
import { SettingsListener } from '../listeners/panel';
|
||||
import { PanelProvider } from '../panelWebView/PanelProvider';
|
||||
|
||||
export class Backers {
|
||||
private static creds: Credentials | null = null;
|
||||
|
||||
public static async init(context: ExtensionContext) {
|
||||
Backers.creds = new Credentials();
|
||||
await Backers.creds.initialize(context, Backers.tryUsernameCheck);
|
||||
|
||||
Backers.tryUsernameCheck();
|
||||
Backers.checkSponsor();
|
||||
|
||||
context.subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.authenticate, async () => {
|
||||
Backers.tryUsernameCheck();
|
||||
await authentication.getSession('github', ['read:user'], { createIfNone: true });
|
||||
Backers.checkSponsor();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public static async tryUsernameCheck() {
|
||||
try {
|
||||
const username = await Backers.getUsername();
|
||||
Backers.validate(username || '');
|
||||
} catch (e) {
|
||||
Backers.validate('');
|
||||
}
|
||||
}
|
||||
|
||||
public static async getUsername() {
|
||||
const octokit = await Backers.creds?.getOctokit();
|
||||
const user = await octokit?.users.getAuthenticated();
|
||||
|
||||
if (user?.data?.login) {
|
||||
return user?.data?.login;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public static async validate(username: string) {
|
||||
public static async checkSponsor() {
|
||||
const ext = Extension.getInstance();
|
||||
const githubAuth = await authentication.getSession('github', ['read:user'], { silent: true });
|
||||
if (githubAuth && githubAuth.accessToken) {
|
||||
try {
|
||||
const isBeta = ext.isBetaVersion();
|
||||
const response = await fetch(
|
||||
`https://${isBeta ? `beta.` : ``}frontmatter.codes/api/v2/backers`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
accept: 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
token: githubAuth.accessToken
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
if (!username) {
|
||||
ext.setState(CONTEXT.backer, undefined, 'global');
|
||||
}
|
||||
if (response.ok) {
|
||||
const prevData = await ext.getState<boolean>(CONTEXT.backer, 'global');
|
||||
await ext.setState(CONTEXT.backer, true, 'global');
|
||||
|
||||
const isBeta = ext.isBetaVersion();
|
||||
if (!prevData) {
|
||||
const PanelView = PanelProvider.getInstance();
|
||||
if (PanelView.visible) {
|
||||
SettingsListener.getSettings();
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
`https://${isBeta ? `beta.` : ``}frontmatter.codes/api/backers?backer=${username}`
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
const prevData = await ext.getState<boolean>(CONTEXT.backer, 'global');
|
||||
await ext.setState(CONTEXT.backer, true, 'global');
|
||||
|
||||
if (!prevData) {
|
||||
const PanelView = PanelProvider.getInstance();
|
||||
if (PanelView.visible) {
|
||||
SettingsListener.getSettings();
|
||||
}
|
||||
|
||||
if (Dashboard.isOpen) {
|
||||
Dashboard.reload();
|
||||
if (Dashboard.isOpen) {
|
||||
Dashboard.reload();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ext.setState(CONTEXT.backer, false, 'global');
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.error(`Failed to check if user is a sponsor: ${(e as Error).message}`);
|
||||
}
|
||||
} else {
|
||||
ext.setState(CONTEXT.backer, false, 'global');
|
||||
ext.setState(CONTEXT.backer, undefined, 'global');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { commands } from 'vscode';
|
||||
import { COMMAND_NAME, ExtensionState } from '../constants';
|
||||
import { Extension, Logger, Notifications } from '../helpers';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Cache {
|
||||
public static async registerCommands() {
|
||||
@@ -28,9 +30,9 @@ export class Cache {
|
||||
await ext.setState(ExtensionState.Settings.Extends, undefined, 'workspace', true);
|
||||
|
||||
if (showNotification) {
|
||||
Notifications.info('Cache cleared');
|
||||
Notifications.info(l10n.t(LocalizationKey.commandsCacheCleared));
|
||||
} else {
|
||||
Logger.info('Cache cleared');
|
||||
Logger.info(l10n.t(LocalizationKey.commandsCacheCleared));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ import { Telemetry } from './../helpers/Telemetry';
|
||||
import { TelemetryEvent, PreviewCommands, GeneralCommands } from './../constants';
|
||||
import { join } from 'path';
|
||||
import { commands, Uri, ViewColumn, window } from 'vscode';
|
||||
import { Extension, Settings } from '../helpers';
|
||||
import { Extension } from '../helpers';
|
||||
import { WebviewHelper } from '@estruyf/vscode';
|
||||
import { getLocalizationFile } from '../utils/getLocalizationFile';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Chatbot {
|
||||
/**
|
||||
@@ -14,7 +16,7 @@ export class Chatbot {
|
||||
// Create the preview webview
|
||||
const webView = window.createWebviewPanel(
|
||||
'frontMatterChatbot',
|
||||
'Front Matter AI - Ask me anything',
|
||||
`Front Matter AI - ${l10n.t(LocalizationKey.commandsChatbotTitle)}`,
|
||||
{
|
||||
viewColumn: ViewColumn.Beside,
|
||||
preserveFocus: true
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { commands, QuickPickItem, window } from 'vscode';
|
||||
import { COMMAND_NAME, SETTING_TEMPLATES_ENABLED } from '../constants';
|
||||
import { Settings } from '../helpers';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Content {
|
||||
public static async create() {
|
||||
@@ -12,18 +14,18 @@ export class Content {
|
||||
|
||||
const options: QuickPickItem[] = [
|
||||
{
|
||||
label: 'Create content by content type',
|
||||
description: 'Select if you want to create new content by the available content type(s)'
|
||||
label: l10n.t(LocalizationKey.commandsContentOptionContentTypeLabel),
|
||||
description: l10n.t(LocalizationKey.commandsContentOptionContentTypeDescription)
|
||||
},
|
||||
{
|
||||
label: 'Create content by template',
|
||||
description: 'Select if you want to create new content by the available template(s)'
|
||||
label: l10n.t(LocalizationKey.commandsContentOptionTemplateLabel),
|
||||
description: l10n.t(LocalizationKey.commandsContentOptionTemplateDescription)
|
||||
} as QuickPickItem
|
||||
];
|
||||
|
||||
const selectedOption = await window.showQuickPick(options, {
|
||||
title: 'Create content',
|
||||
placeHolder: `Select how you want to create your new content`,
|
||||
title: l10n.t(LocalizationKey.commandsContentQuickPickTitle),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsContentQuickPickPlaceholder),
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
@@ -29,6 +29,8 @@ import {
|
||||
import { MediaListener as PanelMediaListener } from '../listeners/panel';
|
||||
import { GitListener, ModeListener } from '../listeners/general';
|
||||
import { Folders } from './Folders';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Dashboard {
|
||||
private static webview: WebviewPanel | null = null;
|
||||
@@ -119,7 +121,7 @@ export class Dashboard {
|
||||
// Create the preview webview
|
||||
Dashboard.webview = window.createWebviewPanel(
|
||||
'frontMatterDashboard',
|
||||
'FrontMatter Dashboard',
|
||||
`Front Matter ${l10n.t(LocalizationKey.commandsDashboardTitle)}`,
|
||||
ViewColumn.One,
|
||||
{
|
||||
enableScripts: true,
|
||||
|
||||
@@ -25,6 +25,8 @@ import { Telemetry } from '../helpers/Telemetry';
|
||||
import { glob } from 'glob';
|
||||
import { mkdirAsync } from '../utils/mkdirAsync';
|
||||
import { existsAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export const WORKSPACE_PLACEHOLDER = `[[workspace]]`;
|
||||
|
||||
@@ -57,15 +59,15 @@ export class Folders {
|
||||
}
|
||||
|
||||
const folderName = await window.showInputBox({
|
||||
title: `Add media folder`,
|
||||
prompt: `Which name would you like to give to your folder (use "/" to create multi-level folders)?`,
|
||||
title: l10n.t(LocalizationKey.commandsFoldersAddMediaFolderInputBoxTitle),
|
||||
prompt: l10n.t(LocalizationKey.commandsFoldersAddMediaFolderInputBoxPrompt),
|
||||
value: startPath,
|
||||
ignoreFocusOut: true,
|
||||
placeHolder: `${format(new Date(), `yyyy/MM`)}`
|
||||
});
|
||||
|
||||
if (!folderName) {
|
||||
Notifications.warning(`No folder name was specified.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.commandsFoldersAddMediaFolderNoFolderWarning));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -126,15 +128,15 @@ export class Folders {
|
||||
);
|
||||
|
||||
if (exists) {
|
||||
Notifications.warning(`Folder is already registered`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.commandsFoldersCreateFolderExistsWarning));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!folderName) {
|
||||
folderName = await window.showInputBox({
|
||||
title: `Register folder`,
|
||||
prompt: `Which name would you like to specify for this folder?`,
|
||||
placeHolder: `Folder name`,
|
||||
title: l10n.t(LocalizationKey.commandsFoldersCreateInputTitle),
|
||||
prompt: l10n.t(LocalizationKey.commandsFoldersCreateInputPrompt),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsFoldersCreateInputPlaceholder),
|
||||
value: basename(folder.fsPath),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
@@ -154,7 +156,7 @@ export class Folders {
|
||||
folders = uniqBy(folders, (f) => f.path);
|
||||
await Folders.update(folders);
|
||||
|
||||
Notifications.info(`Folder registered`);
|
||||
Notifications.info(l10n.t(LocalizationKey.commandsFoldersCreateSuccess));
|
||||
|
||||
Telemetry.send(TelemetryEvent.registerFolder);
|
||||
|
||||
@@ -245,7 +247,9 @@ export class Folders {
|
||||
if (!projectFolder) {
|
||||
window
|
||||
.showWorkspaceFolderPick({
|
||||
placeHolder: `Please select the main workspace folder for Front Matter to use.`
|
||||
placeHolder: l10n.t(
|
||||
LocalizationKey.commandsFoldersGetWorkspaceFolderWorkspaceFolderPickPlaceholder
|
||||
)
|
||||
})
|
||||
.then(async (selectedFolder) => {
|
||||
if (selectedFolder) {
|
||||
@@ -378,14 +382,21 @@ export class Folders {
|
||||
} else {
|
||||
if (folderPath && !existsSync(folderPath)) {
|
||||
Notifications.errorShowOnce(
|
||||
`Folder "${folder.title} (${folder.path})" does not exist. Please remove it from the settings.`,
|
||||
'Remove folder',
|
||||
'Create folder'
|
||||
l10n.t(
|
||||
LocalizationKey.commandsFoldersGetNotificationErrorTitle,
|
||||
`${folder.title} (${folder.path})`
|
||||
),
|
||||
l10n.t(LocalizationKey.commandsFoldersGetNotificationErrorRemoveAction),
|
||||
l10n.t(LocalizationKey.commandsFoldersGetNotificationErrorCreateAction)
|
||||
).then((answer) => {
|
||||
if (answer === 'Remove folder') {
|
||||
if (
|
||||
answer === l10n.t(LocalizationKey.commandsFoldersGetNotificationErrorRemoveAction)
|
||||
) {
|
||||
const folders = Folders.get();
|
||||
Folders.update(folders.filter((f) => f.path !== folder.path));
|
||||
} else if (answer === 'Create folder') {
|
||||
} else if (
|
||||
answer === l10n.t(LocalizationKey.commandsFoldersGetNotificationErrorCreateAction)
|
||||
) {
|
||||
mkdirAsync(folderPath as string, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -24,6 +24,8 @@ import { WebviewHelper } from '@estruyf/vscode';
|
||||
import { Folders } from './Folders';
|
||||
import { ParsedFrontMatter } from '../parsers';
|
||||
import { getLocalizationFile } from '../utils/getLocalizationFile';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Preview {
|
||||
public static filePath: string | undefined = undefined;
|
||||
@@ -71,7 +73,9 @@ export class Preview {
|
||||
// Create the preview webview
|
||||
const webView = window.createWebviewPanel(
|
||||
'frontMatterPreview',
|
||||
article?.data?.title ? `Preview: ${article?.data?.title}` : 'FrontMatter Preview',
|
||||
article?.data?.title
|
||||
? l10n.t(LocalizationKey.commandsPreviewPanelTitle, article?.data.title)
|
||||
: 'Front Matter Preview',
|
||||
{
|
||||
viewColumn: ViewColumn.Beside,
|
||||
preserveFocus: true
|
||||
@@ -393,7 +397,7 @@ export class Preview {
|
||||
const folderNames = crntFolders.map((folder) => folder.title);
|
||||
const selectedFolderName = await window.showQuickPick(folderNames, {
|
||||
canPickMany: false,
|
||||
title: 'Select the folder of the article to preview'
|
||||
title: l10n.t(LocalizationKey.commandsPreviewAskUserToPickFolderTitle)
|
||||
});
|
||||
|
||||
if (selectedFolderName) {
|
||||
|
||||
@@ -21,6 +21,8 @@ import {
|
||||
} from '../constants';
|
||||
import { SettingsListener } from '../listeners/dashboard';
|
||||
import { existsAsync, writeFileAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Project {
|
||||
private static content = `---
|
||||
@@ -66,7 +68,7 @@ categories: []
|
||||
if (sampleTemplate !== undefined) {
|
||||
await Project.createSampleTemplate();
|
||||
} else {
|
||||
Notifications.info('Project initialized successfully.');
|
||||
Notifications.info(l10n.t(LocalizationKey.commandsProjectInitializeSuccess));
|
||||
}
|
||||
|
||||
// Initialize the media library
|
||||
@@ -89,10 +91,14 @@ categories: []
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
Logger.error(`Project::init: ${err?.message || err}`);
|
||||
Notifications.error(`Sorry, something went wrong - ${err?.message || err}`);
|
||||
Notifications.errorWithOutput(l10n.t(LocalizationKey.commonError));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Project switcher
|
||||
* @returns
|
||||
*/
|
||||
public static async switchProject() {
|
||||
const projects = Settings.getProjects();
|
||||
const project = await window.showQuickPick(
|
||||
@@ -100,7 +106,7 @@ categories: []
|
||||
{
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true,
|
||||
title: 'Select a project to switch to'
|
||||
title: l10n.t(LocalizationKey.commandsProjectSwitchProjectTitle)
|
||||
}
|
||||
);
|
||||
|
||||
@@ -136,7 +142,7 @@ categories: []
|
||||
await writeFileAsync(article.fsPath, Project.content, {
|
||||
encoding: 'utf-8'
|
||||
});
|
||||
Notifications.info('Sample template created.');
|
||||
Notifications.info(l10n.t(LocalizationKey.commandsProjectCreateSampleTemplateInfo));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import { EXTENSION_NAME } from '../constants';
|
||||
import { ArticleHelper, FilesHelper } from '../helpers';
|
||||
import { FrontMatterParser } from '../parsers';
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Settings {
|
||||
/**
|
||||
@@ -13,11 +15,11 @@ export class Settings {
|
||||
* @param type
|
||||
*/
|
||||
public static async create(type: TaxonomyType) {
|
||||
const taxonomy = type === TaxonomyType.Tag ? 'tag' : 'category';
|
||||
|
||||
const newOption = await vscode.window.showInputBox({
|
||||
prompt: `Insert the value of the ${
|
||||
type === TaxonomyType.Tag ? 'tag' : 'category'
|
||||
} that you want to add to your configuration.`,
|
||||
placeHolder: `Name of the ${type === TaxonomyType.Tag ? 'tag' : 'category'}`,
|
||||
prompt: l10n.t(LocalizationKey.commandsFoldersCreateInputPrompt, taxonomy),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsFoldersCreateInputPlaceholder, taxonomy),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
@@ -25,9 +27,7 @@ export class Settings {
|
||||
let options = (await TaxonomyHelper.get(type)) || [];
|
||||
|
||||
if (options.find((o) => o === newOption)) {
|
||||
Notifications.info(
|
||||
`The provided ${type === TaxonomyType.Tag ? 'tag' : 'category'} already exists.`
|
||||
);
|
||||
Notifications.warning(l10n.t(LocalizationKey.commandsSettingsCreateWarning, taxonomy));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35,15 +35,16 @@ export class Settings {
|
||||
TaxonomyHelper.update(type, options);
|
||||
|
||||
// Ask if the new term needs to be added to the page
|
||||
const addToPage = await vscode.window.showQuickPick(['yes', 'no'], {
|
||||
canPickMany: false,
|
||||
placeHolder: `Do you want to add the new ${
|
||||
type === TaxonomyType.Tag ? 'tag' : 'category'
|
||||
} to the page?`,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
const addToPage = await vscode.window.showQuickPick(
|
||||
[l10n.t(LocalizationKey.commonYes), l10n.t(LocalizationKey.commonNo)],
|
||||
{
|
||||
canPickMany: false,
|
||||
placeHolder: l10n.t(LocalizationKey.commandsSettingsCreateQuickPickPlaceholder, taxonomy),
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
|
||||
if (addToPage && addToPage === 'yes') {
|
||||
if (addToPage && addToPage === l10n.t(LocalizationKey.commonYes)) {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return;
|
||||
@@ -54,7 +55,7 @@ export class Settings {
|
||||
return;
|
||||
}
|
||||
|
||||
const matterProp: string = type === TaxonomyType.Tag ? 'tags' : 'categories';
|
||||
const matterProp: string = taxonomy;
|
||||
// Add the selected options to the options array
|
||||
if (article.data[matterProp]) {
|
||||
const propData: string[] = article.data[matterProp];
|
||||
@@ -83,7 +84,7 @@ export class Settings {
|
||||
vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: `${EXTENSION_NAME}: exporting tags and categories`,
|
||||
title: l10n.t(LocalizationKey.commandsSettingsExportProgressTitle, EXTENSION_NAME),
|
||||
cancellable: false
|
||||
},
|
||||
async (progress) => {
|
||||
@@ -146,7 +147,11 @@ export class Settings {
|
||||
|
||||
// Done
|
||||
Notifications.info(
|
||||
`Export completed. Tags: ${crntTags.length} - Categories: ${crntCategories.length}.`
|
||||
l10n.t(
|
||||
LocalizationKey.commandsSettingsExportProgressSuccess,
|
||||
crntTags.length,
|
||||
crntCategories.length
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -157,8 +162,8 @@ export class Settings {
|
||||
*/
|
||||
public static async remap() {
|
||||
const taxType = await vscode.window.showQuickPick(['Tag', 'Category'], {
|
||||
title: `Remap`,
|
||||
placeHolder: `What do you want to remap?`,
|
||||
title: l10n.t(LocalizationKey.commandsSettingsRemapQuickpickTitle),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsSettingsRemapQuickpickPlaceholder),
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
@@ -168,15 +173,18 @@ export class Settings {
|
||||
}
|
||||
|
||||
const type = taxType === 'Tag' ? TaxonomyType.Tag : TaxonomyType.Category;
|
||||
const taxonomy = type === TaxonomyType.Tag ? 'tags' : 'categories';
|
||||
const options = (await TaxonomyHelper.get(type)) || [];
|
||||
|
||||
if (!options || options.length === 0) {
|
||||
Notifications.info(`No ${type === TaxonomyType.Tag ? 'tags' : 'categories'} configured.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.commandsSettingsRemapNoTaxonomyWarning, taxonomy)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedOption = await vscode.window.showQuickPick(options, {
|
||||
placeHolder: `Select your ${type === TaxonomyType.Tag ? 'tags' : 'categories'} to insert`,
|
||||
placeHolder: l10n.t(LocalizationKey.commandsSettingsRemapSelectTaxonomyPlaceholder, taxonomy),
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
@@ -186,19 +194,23 @@ export class Settings {
|
||||
}
|
||||
|
||||
const newOptionValue = await vscode.window.showInputBox({
|
||||
prompt: `Specify the value of the ${
|
||||
type === TaxonomyType.Tag ? 'tag' : 'category'
|
||||
} with which you want to remap "${selectedOption}". Leave the input <blank> if you want to remove the ${
|
||||
type === TaxonomyType.Tag ? 'tag' : 'category'
|
||||
} from all articles.`,
|
||||
placeHolder: `Name of the ${type === TaxonomyType.Tag ? 'tag' : 'category'}`,
|
||||
prompt: l10n.t(
|
||||
LocalizationKey.commandsSettingsRemapNewOptionInputPrompt,
|
||||
taxonomy,
|
||||
selectedOption
|
||||
),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsSettingsRemapNewOptionInputPlaceholder, taxonomy),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!newOptionValue) {
|
||||
const deleteAnswer = await vscode.window.showQuickPick(['yes', 'no'], {
|
||||
canPickMany: false,
|
||||
placeHolder: `Delete ${selectedOption} ${type === TaxonomyType.Tag ? 'tag' : 'category'}?`,
|
||||
placeHolder: l10n.t(
|
||||
LocalizationKey.commandsSettingsRemapDeletePlaceholder,
|
||||
selectedOption,
|
||||
taxonomy
|
||||
),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
if (deleteAnswer === 'no') {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ParsedFrontMatter } from './../parsers/FrontMatterParser';
|
||||
import {
|
||||
CONTEXT,
|
||||
EXTENSION_NAME,
|
||||
NOTIFICATION_TYPE,
|
||||
SETTING_SEO_DESCRIPTION_FIELD,
|
||||
SETTING_SEO_DESCRIPTION_LENGTH,
|
||||
@@ -16,6 +17,8 @@ import { DataListener } from '../listeners/panel';
|
||||
import { commands } from 'vscode';
|
||||
import { Field } from '../models';
|
||||
import { Preview } from './Preview';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class StatusListener {
|
||||
/**
|
||||
@@ -135,12 +138,13 @@ export class StatusListener {
|
||||
|
||||
const diagnostic: vscode.Diagnostic = {
|
||||
code: '',
|
||||
message: `This ${fields
|
||||
.map((f) => f.name)
|
||||
.join('/')} field is required to contain a value.`,
|
||||
message: l10n.t(
|
||||
LocalizationKey.commandsStatusListenerVerifyRequiredFieldsDiagnosticEmptyField,
|
||||
fields.map((f) => f.name).join('/')
|
||||
),
|
||||
range: new vscode.Range(posStart, posEnd),
|
||||
severity: vscode.DiagnosticSeverity.Error,
|
||||
source: 'Front Matter'
|
||||
source: EXTENSION_NAME
|
||||
};
|
||||
|
||||
requiredDiagnostics.push(diagnostic);
|
||||
@@ -158,7 +162,10 @@ export class StatusListener {
|
||||
Notifications.showIfNotDisabled(
|
||||
NOTIFICATION_TYPE.requiredFieldValidation,
|
||||
'ERROR_ONCE',
|
||||
`The following fields are required to contain a value: ${fieldsToReport.join(', ')}`
|
||||
l10n.t(
|
||||
LocalizationKey.commandsStatusListenerVerifyRequiredFieldsNotificationError,
|
||||
fieldsToReport.join(', ')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ import { PagesListener } from '../listeners/dashboard';
|
||||
import { extname } from 'path';
|
||||
import { Telemetry } from '../helpers/Telemetry';
|
||||
import { writeFileAsync, copyFileAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Template {
|
||||
/**
|
||||
@@ -31,27 +33,30 @@ export class Template {
|
||||
const clonedArticle = Object.assign({}, article);
|
||||
|
||||
const titleValue = await vscode.window.showInputBox({
|
||||
title: `Template title`,
|
||||
prompt: `What name would you like to give your template?`,
|
||||
placeHolder: `article`,
|
||||
title: l10n.t(LocalizationKey.commandsTemplateGenerateInputTitle),
|
||||
prompt: l10n.t(LocalizationKey.commandsTemplateGenerateInputPrompt),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsTemplateGenerateInputPlaceholder),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!titleValue) {
|
||||
Notifications.warning(`You did not specify a template title.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.commandsTemplateGenerateNoTitleWarning));
|
||||
return;
|
||||
}
|
||||
|
||||
const keepContents = await vscode.window.showQuickPick(['yes', 'no'], {
|
||||
title: `Keep contents`,
|
||||
canPickMany: false,
|
||||
placeHolder: `Do you want to keep the contents for the template?`,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
const keepContents = await vscode.window.showQuickPick(
|
||||
[l10n.t(LocalizationKey.commonYes), l10n.t(LocalizationKey.commonNo)],
|
||||
{
|
||||
title: l10n.t(LocalizationKey.commandsTemplateGenerateKeepContentsTitle),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsTemplateGenerateKeepContentsPlaceholder),
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
|
||||
if (!keepContents) {
|
||||
Notifications.warning(
|
||||
`You did not pick any of the options for keeping the template its content.`
|
||||
l10n.t(LocalizationKey.commandsTemplateGenerateKeepContentsNoOptionWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -60,14 +65,16 @@ export class Template {
|
||||
const templatePath = Project.templatePath();
|
||||
if (templatePath) {
|
||||
const fileContents = ArticleHelper.stringifyFrontMatter(
|
||||
keepContents === 'no' ? '' : clonedArticle.content,
|
||||
keepContents === l10n.t(LocalizationKey.commonNo) ? '' : clonedArticle.content,
|
||||
clonedArticle.data
|
||||
);
|
||||
|
||||
const templateFile = path.join(templatePath.fsPath, `${titleValue}.${fileType}`);
|
||||
await writeFileAsync(templateFile, fileContents, { encoding: 'utf-8' });
|
||||
|
||||
Notifications.info(`Template created and is now available in your ${folder} folder.`);
|
||||
Notifications.info(
|
||||
l10n.t(LocalizationKey.commandsTemplateGenerateKeepContentsSuccess, folder)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +86,7 @@ export class Template {
|
||||
const folder = Settings.get<string>(SETTING_TEMPLATES_FOLDER);
|
||||
|
||||
if (!folder) {
|
||||
Notifications.warning(`No templates found.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.commandsTemplateGetTemplatesWarning));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -96,26 +103,28 @@ export class Template {
|
||||
const contentTypes = ContentType.getAll();
|
||||
|
||||
if (!folderPath) {
|
||||
Notifications.warning(`Incorrect project folder path retrieved.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.commandsTemplateCreateFolderPathWarning));
|
||||
return;
|
||||
}
|
||||
|
||||
const templates = await Template.getTemplates();
|
||||
if (!templates || templates.length === 0) {
|
||||
Notifications.warning(`No templates found.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.commandsTemplateCreateNoTemplatesWarning));
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedTemplate = await vscode.window.showQuickPick(
|
||||
templates.map((t) => path.basename(t.fsPath)),
|
||||
{
|
||||
title: `Select a template`,
|
||||
placeHolder: `Select the content template to use`,
|
||||
title: l10n.t(LocalizationKey.commandsTemplateCreateSelectTemplateTitle),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsTemplateCreateSelectTemplatePlaceholder),
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
if (!selectedTemplate) {
|
||||
Notifications.warning(`No template selected.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.commandsTemplateCreateSelectTemplateNoTemplateWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -127,7 +136,9 @@ export class Template {
|
||||
// Start the template read
|
||||
const template = templates.find((t) => t.fsPath.endsWith(selectedTemplate));
|
||||
if (!template) {
|
||||
Notifications.warning(`Content template could not be found.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.commandsTemplateCreateSelectTemplateNotFoundWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,7 +165,7 @@ export class Template {
|
||||
// Update the properties inside the template
|
||||
let frontMatter = await ArticleHelper.getFrontMatterByPath(newFilePath);
|
||||
if (!frontMatter) {
|
||||
Notifications.warning(`Something failed when retrieving the newly created file.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.commonError));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -185,7 +196,7 @@ export class Template {
|
||||
vscode.window.showTextDocument(txtDoc);
|
||||
}
|
||||
|
||||
Notifications.info(`Your new content has been created.`);
|
||||
Notifications.info(l10n.t(LocalizationKey.commandsTemplateCreateSuccess));
|
||||
|
||||
Telemetry.send(TelemetryEvent.createContentFromTemplate);
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { commands, window, Selection, QuickPickItem, TextEditor } from 'vscode';
|
||||
import { COMMAND_NAME, CONTEXT, SETTING_CONTENT_WYSIWYG } from '../constants';
|
||||
import { Settings } from '../helpers';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
enum MarkupType {
|
||||
bold = 1,
|
||||
@@ -81,45 +83,45 @@ export class Wysiwyg {
|
||||
commands.registerCommand(COMMAND_NAME.options, async () => {
|
||||
const qpItems: QuickPickItem[] = [
|
||||
{
|
||||
label: '$(list-unordered) Unordered list',
|
||||
detail: 'Add an unordered list',
|
||||
label: `$(list-unordered) ${LocalizationKey.commandsWysiwygCommandUnorderedListLabel}`,
|
||||
detail: LocalizationKey.commandsWysiwygCommandUnorderedListDetail,
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(list-ordered) Ordered list',
|
||||
detail: 'Add an ordered list',
|
||||
label: `$(list-ordered) ${LocalizationKey.commandsWysiwygCommandOrderedListLabel}`,
|
||||
detail: LocalizationKey.commandsWysiwygCommandOrderedListDetail,
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(tasklist) Task list',
|
||||
detail: 'Add a task list',
|
||||
label: `$(tasklist) ${LocalizationKey.commandsWysiwygCommandTaskListLabel}`,
|
||||
detail: LocalizationKey.commandsWysiwygCommandTaskListDetail,
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(code) Code',
|
||||
detail: 'Add inline code snippet',
|
||||
label: `$(code) ${LocalizationKey.commandsWysiwygCommandCodeLabel}`,
|
||||
detail: LocalizationKey.commandsWysiwygCommandCodeDetail,
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(symbol-namespace) Code block',
|
||||
detail: 'Add a code block',
|
||||
label: `$(symbol-namespace) ${LocalizationKey.commandsWysiwygCommandCodeblockLabel}`,
|
||||
detail: LocalizationKey.commandsWysiwygCommandCodeblockDetail,
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(quote) Blockquote',
|
||||
detail: 'Add a blockquote',
|
||||
label: `$(quote) ${LocalizationKey.commandsWysiwygCommandBlockquoteLabel}`,
|
||||
detail: LocalizationKey.commandsWysiwygCommandBlockquoteDetail,
|
||||
alwaysShow: true
|
||||
},
|
||||
{
|
||||
label: '$(symbol-text) Strikethrough',
|
||||
detail: 'Add a strikethrough',
|
||||
label: `$(symbol-text) ${LocalizationKey.commandsWysiwygCommandStrikethroughLabel}`,
|
||||
detail: LocalizationKey.commandsWysiwygCommandStrikethroughDetail,
|
||||
alwaysShow: true
|
||||
}
|
||||
];
|
||||
|
||||
const option = await window.showQuickPick([...qpItems], {
|
||||
title: 'WYSIWYG Options',
|
||||
placeHolder: 'Which type of markup would you like to insert?',
|
||||
title: l10n.t(LocalizationKey.commandsWysiwygQuickPickTitle),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsWysiwygQuickPickPlaceholder),
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
@@ -209,17 +211,17 @@ export class Wysiwyg {
|
||||
const linkText = hasTextSelection ? editor.document.getText(selection) : '';
|
||||
|
||||
const link = await window.showInputBox({
|
||||
title: 'WYSIWYG Hyperlink',
|
||||
placeHolder: 'Enter the URL',
|
||||
prompt: 'Enter the URL',
|
||||
title: l10n.t(LocalizationKey.commandsWysiwygAddHyperlinkHyperlinkInputTitle),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsWysiwygAddHyperlinkHyperlinkInputPrompt),
|
||||
prompt: l10n.t(LocalizationKey.commandsWysiwygAddHyperlinkHyperlinkInputPrompt),
|
||||
value: linkText,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
const text = await window.showInputBox({
|
||||
title: 'WYSIWYG Text',
|
||||
prompt: 'Enter the text for the hyperlink',
|
||||
placeHolder: 'Enter the text for the hyperlink',
|
||||
title: l10n.t(LocalizationKey.commandsWysiwygAddHyperlinkTextInputTitle),
|
||||
prompt: l10n.t(LocalizationKey.commandsWysiwygAddHyperlinkTextInputPrompt),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsWysiwygAddHyperlinkTextInputPrompt),
|
||||
value: linkText,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
@@ -278,9 +280,9 @@ export class Wysiwyg {
|
||||
const headingLvl = await window.showQuickPick(
|
||||
['Heading 1', 'Heading 2', 'Heading 3', 'Heading 4', 'Heading 5', 'Heading 6'],
|
||||
{
|
||||
title: 'Heading Level',
|
||||
title: l10n.t(LocalizationKey.commandsWysiwygInsertTextHeadingInputTitle),
|
||||
placeHolder: l10n.t(LocalizationKey.commandsWysiwygInsertTextHeadingInputPlaceholder),
|
||||
canPickMany: false,
|
||||
placeHolder: 'Which heading level do you want to insert?',
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ContentType } from './../models/PanelSettings';
|
||||
export const DEFAULT_CONTENT_TYPE_NAME = 'default';
|
||||
|
||||
export const DEFAULT_CONTENT_TYPE: ContentType = {
|
||||
name: 'default',
|
||||
name: DEFAULT_CONTENT_TYPE_NAME,
|
||||
pageBundle: false,
|
||||
previewPath: null,
|
||||
fields: [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const EXTENSION_NAME = '𝖥𝗋𝗈𝗇𝗍 𝖬𝖺𝗍𝗍𝖾𝗋 𝖢𝖬𝖲';
|
||||
export const EXTENSION_NAME = 'Front Matter CMS';
|
||||
|
||||
export const CONFIG_KEY = 'frontMatter';
|
||||
|
||||
@@ -29,6 +29,7 @@ export const SETTING_SLUG_UPDATE_FILE_NAME = 'taxonomy.alignFilename';
|
||||
|
||||
export const SETTING_INDENT_ARRAY = 'taxonomy.indentArrays';
|
||||
export const SETTING_REMOVE_QUOTES = 'taxonomy.noPropertyValueQuotes';
|
||||
export const SETTING_QUOTE_STRINGS = 'taxonomy.quoteStringValues';
|
||||
|
||||
export const SETTING_FRONTMATTER_TYPE = 'taxonomy.frontMatterType';
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ export enum DashboardMessage {
|
||||
setPageViewType = 'setPageViewType',
|
||||
getMode = 'getMode',
|
||||
showWarning = 'showWarning',
|
||||
openConfig = 'openConfig',
|
||||
|
||||
// Project switching
|
||||
switchProject = 'switchProject',
|
||||
|
||||
@@ -3,18 +3,20 @@ import * as l10n from '@vscode/l10n';
|
||||
import { messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import { DashboardMessage } from '../../../DashboardMessage';
|
||||
import { AstroCollection } from '../../../../models';
|
||||
import { Settings } from '../../../models';
|
||||
import { Settings, Status } from '../../../models';
|
||||
import { SelectItem } from '../../Steps/SelectItem';
|
||||
import { LocalizationKey } from '../../../../localization';
|
||||
|
||||
export interface IAstroContentTypesProps {
|
||||
settings: Settings
|
||||
triggerLoading: (isLoading: boolean) => void;
|
||||
setStatus: (status: Status) => void;
|
||||
}
|
||||
|
||||
export const AstroContentTypes: React.FunctionComponent<IAstroContentTypesProps> = ({
|
||||
settings,
|
||||
triggerLoading
|
||||
triggerLoading,
|
||||
setStatus
|
||||
}: React.PropsWithChildren<IAstroContentTypesProps>) => {
|
||||
const [collections, setCollections] = React.useState<AstroCollection[]>([]);
|
||||
|
||||
@@ -26,12 +28,26 @@ export const AstroContentTypes: React.FunctionComponent<IAstroContentTypesProps>
|
||||
});
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (collections.length > 0 && settings?.contentTypes?.length > 0) {
|
||||
// Find created content types from the collections
|
||||
const astroCollection = collections.find(c => settings.contentTypes.find((ct) => ct.name === c.name));
|
||||
console.log(`astroCollection`, astroCollection)
|
||||
if (astroCollection) {
|
||||
setStatus(Status.Completed);
|
||||
} else {
|
||||
setStatus(Status.Active);
|
||||
}
|
||||
}
|
||||
}, [collections, settings.contentTypes])
|
||||
|
||||
const generateContentType = (collection: AstroCollection) => {
|
||||
triggerLoading(true);
|
||||
messageHandler.request(DashboardMessage.ssgSetAstroContentTypes, {
|
||||
collection
|
||||
}).then((result) => {
|
||||
triggerLoading(false);
|
||||
setStatus(Status.Completed);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { NavigationType, Page } from '../../models';
|
||||
import { DashboardViewAtom, SettingsSelector } from '../../state';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Page } from '../../models';
|
||||
import { SettingsSelector } from '../../state';
|
||||
import { Overview } from './Overview';
|
||||
import { Spinner } from '../Common/Spinner';
|
||||
import { SponsorMsg } from '../Layout/SponsorMsg';
|
||||
@@ -23,13 +23,10 @@ export const Contents: React.FunctionComponent<IContentsProps> = ({
|
||||
}: React.PropsWithChildren<IContentsProps>) => {
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
const { pageItems } = usePages(pages);
|
||||
const [, setView] = useRecoilState(DashboardViewAtom);
|
||||
|
||||
const pageFolders = [...new Set(pageItems.map((page) => page.fmFolder))];
|
||||
|
||||
useEffect(() => {
|
||||
setView(NavigationType.Contents);
|
||||
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewContentsView
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { Header } from '../Header';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { DashboardViewAtom, SettingsSelector } from '../../state';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { SettingsSelector } from '../../state';
|
||||
import { DataForm } from './DataForm';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { DataFile } from '../../../models/DataFile';
|
||||
@@ -36,7 +36,6 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (
|
||||
const [dataEntries, setDataEntries] = useState<any | any[] | null>(null);
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
const { getColors } = useThemeColors();
|
||||
const [, setView] = useRecoilState(DashboardViewAtom);
|
||||
|
||||
const setSchema = (dataFile: DataFile) => {
|
||||
setSelectedData(dataFile);
|
||||
@@ -137,7 +136,6 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (
|
||||
}, [selectedData, , dataEntries, selectedIndex]);
|
||||
|
||||
useEffect(() => {
|
||||
setView(NavigationType.Data);
|
||||
Messenger.listen(messageListener);
|
||||
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { UploadIcon } from '@heroicons/react/outline';
|
||||
import * as React from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import {
|
||||
DashboardViewAtom,
|
||||
LoadingAtom,
|
||||
MediaFoldersAtom,
|
||||
SelectedMediaFolderAtom,
|
||||
@@ -43,7 +42,6 @@ export const Media: React.FunctionComponent<IMediaProps> = (
|
||||
const folders = useRecoilValue(MediaFoldersAtom);
|
||||
const loading = useRecoilValue(LoadingAtom);
|
||||
const { getColors } = useThemeColors();
|
||||
const [, setView] = useRecoilState(DashboardViewAtom);
|
||||
|
||||
const currentStaticFolder = useMemo(() => {
|
||||
if (settings?.staticFolder) {
|
||||
@@ -153,7 +151,6 @@ export const Media: React.FunctionComponent<IMediaProps> = (
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setView(NavigationType.Media);
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewMediaView
|
||||
});
|
||||
|
||||
@@ -76,7 +76,8 @@ export const SettingsView: React.FunctionComponent<ISettingsViewProps> = (_: Rea
|
||||
|
||||
<AstroContentTypes
|
||||
settings={settings}
|
||||
triggerLoading={(isLoading) => setLoading(isLoading)} />
|
||||
triggerLoading={(isLoading) => setLoading(isLoading)}
|
||||
setStatus={_ => null} />
|
||||
</div>
|
||||
</VSCodePanelView>
|
||||
)
|
||||
|
||||
@@ -2,14 +2,14 @@ import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { CodeIcon, PlusSmIcon } from '@heroicons/react/outline';
|
||||
import * as React from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { FeatureFlag } from '../../../components/features/FeatureFlag';
|
||||
import { FEATURE_FLAG } from '../../../constants';
|
||||
import { TelemetryEvent } from '../../../constants/TelemetryEvent';
|
||||
import { SnippetParser } from '../../../helpers/SnippetParser';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import useThemeColors from '../../hooks/useThemeColors';
|
||||
import { DashboardViewAtom, ModeAtom, SettingsSelector, ViewDataSelector } from '../../state';
|
||||
import { ModeAtom, SettingsSelector, ViewDataSelector } from '../../state';
|
||||
import { FilterInput } from '../Header/FilterInput';
|
||||
import { PageLayout } from '../Layout/PageLayout';
|
||||
import { FormDialog } from '../Modals/FormDialog';
|
||||
@@ -18,7 +18,6 @@ import { Item } from './Item';
|
||||
import { NewForm } from './NewForm';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { NavigationType } from '../../models';
|
||||
|
||||
export interface ISnippetsProps { }
|
||||
|
||||
@@ -35,7 +34,6 @@ export const Snippets: React.FunctionComponent<ISnippetsProps> = (
|
||||
const [mediaSnippet, setMediaSnippet] = useState(false);
|
||||
const [snippetFilter, setSnippetFilter] = useState<string>('');
|
||||
const { getColors } = useThemeColors();
|
||||
const [, setView] = useRecoilState(DashboardViewAtom);
|
||||
|
||||
const snippets = settings?.snippets || {};
|
||||
const snippetKeys = useMemo(() => {
|
||||
@@ -84,7 +82,6 @@ export const Snippets: React.FunctionComponent<ISnippetsProps> = (
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setView(NavigationType.Snippets);
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewSnippetsView
|
||||
});
|
||||
|
||||
@@ -4,7 +4,6 @@ import { CheckCircleIcon as CheckCircleIconSolid, PlusCircleIcon as PlusCircleIc
|
||||
|
||||
export interface ISelectItemProps {
|
||||
title: string;
|
||||
icon?: "add" | "select";
|
||||
buttonTitle: string;
|
||||
isSelected: boolean;
|
||||
disabled?: boolean;
|
||||
@@ -13,7 +12,6 @@ export interface ISelectItemProps {
|
||||
|
||||
export const SelectItem: React.FunctionComponent<ISelectItemProps> = ({
|
||||
title,
|
||||
icon = "select",
|
||||
buttonTitle,
|
||||
isSelected,
|
||||
disabled,
|
||||
@@ -30,17 +28,9 @@ export const SelectItem: React.FunctionComponent<ISelectItemProps> = ({
|
||||
disabled={disabled}
|
||||
>
|
||||
{isSelected ? (
|
||||
icon === "add" ? (
|
||||
<PlusCircleIconSolid className={`h-4 w-4`} />
|
||||
) : (
|
||||
<CheckCircleIconSolid className={`h-4 w-4`} />
|
||||
)
|
||||
<CheckCircleIconSolid className={`h-4 w-4`} />
|
||||
) : (
|
||||
icon === "add" ? (
|
||||
<PlusCircleIcon className={`h-4 w-4`} />
|
||||
) : (
|
||||
<CheckCircleIcon className={`h-4 w-4`} />
|
||||
)
|
||||
<PlusCircleIcon className={`h-4 w-4`} />
|
||||
)}
|
||||
<span>{title}</span>
|
||||
</button>
|
||||
|
||||
@@ -31,6 +31,7 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
const [framework, setFramework] = useState<string | null>(null);
|
||||
const [taxImported, setTaxImported] = useState<boolean>(false);
|
||||
const [templates, setTemplates] = useState<Template[]>([]);
|
||||
const [astroCollectionsStatus, setAstroCollectionsStatus] = useState<Status>(Status.Optional)
|
||||
const { getColors } = useThemeColors();
|
||||
|
||||
const frameworks: Framework[] = FrameworkDetectors.map((detector: any) => detector.framework);
|
||||
@@ -54,6 +55,10 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
});
|
||||
}
|
||||
|
||||
const showNotification = () => {
|
||||
Messenger.send(DashboardMessage.openConfig);
|
||||
};
|
||||
|
||||
const reload = () => {
|
||||
const crntState: any = Messenger.getState() || {};
|
||||
|
||||
@@ -175,6 +180,9 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<p className='mt-4 text-[var(--vscode-editorWarning-foreground)]'>
|
||||
<b>{l10n.t(LocalizationKey.commonImportant)}</b>: {l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedTemplateWarning)}</p>
|
||||
</div>
|
||||
),
|
||||
show: (crntTemplates || []).length > 0,
|
||||
@@ -186,10 +194,11 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
description: (
|
||||
<AstroContentTypes
|
||||
settings={settings}
|
||||
triggerLoading={(isLoading) => setLoading(isLoading)} />
|
||||
triggerLoading={(isLoading) => setLoading(isLoading)}
|
||||
setStatus={(status) => setAstroCollectionsStatus(status)} />
|
||||
),
|
||||
show: settings.crntFramework === 'astro',
|
||||
status: Status.Optional
|
||||
status: astroCollectionsStatus
|
||||
},
|
||||
{
|
||||
id: `welcome-content-folders`,
|
||||
@@ -255,11 +264,14 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
: Status.NotStarted,
|
||||
onClick:
|
||||
settings.initialized && settings.contentFolders && settings.contentFolders.length > 0
|
||||
? reload
|
||||
? () => {
|
||||
showNotification();
|
||||
reload();
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
]
|
||||
), [settings, framework, taxImported, templates]);
|
||||
), [settings, framework, taxImported, templates, astroCollectionsStatus]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (settings.crntFramework || settings.framework?.name) {
|
||||
|
||||
@@ -2,12 +2,12 @@ import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { ChevronRightIcon, DownloadIcon } from '@heroicons/react/outline';
|
||||
import * as React from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { TelemetryEvent } from '../../../constants';
|
||||
import { TaxonomyData } from '../../../models';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { NavigationType, Page } from '../../models';
|
||||
import { DashboardViewAtom, SettingsSelector } from '../../state';
|
||||
import { Page } from '../../models';
|
||||
import { SettingsSelector } from '../../state';
|
||||
import { NavigationBar, NavigationItem } from '../Layout';
|
||||
import { PageLayout } from '../Layout/PageLayout';
|
||||
import { SponsorMsg } from '../Layout/SponsorMsg';
|
||||
@@ -25,7 +25,6 @@ export const TaxonomyView: React.FunctionComponent<ITaxonomyViewProps> = ({
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
const [taxonomySettings, setTaxonomySettings] = useState<TaxonomyData>();
|
||||
const [selectedTaxonomy, setSelectedTaxonomy] = useState<string | null>(`tags`);
|
||||
const [, setView] = useRecoilState(DashboardViewAtom);
|
||||
|
||||
const onImport = () => {
|
||||
Messenger.send(DashboardMessage.importTaxonomy);
|
||||
@@ -40,7 +39,6 @@ export const TaxonomyView: React.FunctionComponent<ITaxonomyViewProps> = ({
|
||||
}, [settings?.tags, settings?.categories, settings?.customTaxonomy]);
|
||||
|
||||
useEffect(() => {
|
||||
setView(NavigationType.Taxonomy);
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewTaxonomyDashboard
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { EventData } from '@estruyf/vscode/dist/models';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useState, useEffect, useCallback, useMemo } from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { MediaInfo, MediaPaths } from '../../models';
|
||||
import { DashboardCommand } from '../DashboardCommand';
|
||||
@@ -52,27 +52,11 @@ export default function useMedia() {
|
||||
}
|
||||
}, [search, prevSearch]);
|
||||
|
||||
const getMedia = useCallback(() => {
|
||||
const allMedia = useMemo(() => {
|
||||
return searchedMedia.slice(page * pageSetNr, (page + 1) * pageSetNr);
|
||||
}, [searchedMedia, page, pageSetNr]);
|
||||
|
||||
const messageListener = (
|
||||
message: MessageEvent<EventData<MediaPaths | { key: string; value: any }>>
|
||||
) => {
|
||||
if (message.data.command === DashboardCommand.media) {
|
||||
const payload: MediaPaths = message.data.payload as MediaPaths;
|
||||
setLoading(false);
|
||||
setMedia(payload.media);
|
||||
setTotal(payload.total);
|
||||
setFolders(payload.folders);
|
||||
setSelectedFolder(payload.selectedFolder);
|
||||
setSearchedMedia(payload.media);
|
||||
setAllContentFolders(payload.allContentFolders);
|
||||
setAllStaticFolders(payload.allStaticfolders);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const searchMedia = (search: string, media: MediaInfo[]) => {
|
||||
if (search) {
|
||||
const fuse = new Fuse(media, fuseOptions);
|
||||
const results = fuse.search(search);
|
||||
@@ -86,6 +70,28 @@ export default function useMedia() {
|
||||
|
||||
setTotal(media.length);
|
||||
setSearchedMedia(media);
|
||||
}
|
||||
|
||||
const messageListener = useCallback((message: MessageEvent<EventData<MediaPaths | { key: string; value: any }>>) => {
|
||||
if (message.data.command === DashboardCommand.media) {
|
||||
const payload: MediaPaths = message.data.payload as MediaPaths;
|
||||
setLoading(false);
|
||||
setMedia(payload.media);
|
||||
setTotal(payload.total);
|
||||
setFolders(payload.folders);
|
||||
setSelectedFolder(payload.selectedFolder);
|
||||
if (search) {
|
||||
searchMedia(search, payload.media);
|
||||
} else {
|
||||
setSearchedMedia(payload.media);
|
||||
}
|
||||
setAllContentFolders(payload.allContentFolders);
|
||||
setAllStaticFolders(payload.allStaticfolders);
|
||||
}
|
||||
}, [search]);
|
||||
|
||||
useEffect(() => {
|
||||
searchMedia(search, media);
|
||||
}, [search, media]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -94,9 +100,9 @@ export default function useMedia() {
|
||||
return () => {
|
||||
Messenger.unlisten(messageListener);
|
||||
};
|
||||
}, []);
|
||||
}, [search]);
|
||||
|
||||
return {
|
||||
media: getMedia()
|
||||
media: allMedia
|
||||
};
|
||||
}
|
||||
|
||||
@@ -144,9 +144,18 @@
|
||||
@apply bg-gray-500 opacity-50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fields {
|
||||
> .fields {
|
||||
> div > label:first-of-type {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
> div:not(:first-child) > label:first-of-type {
|
||||
margin-block-start: 2rem;
|
||||
border-block-start: 1px solid;
|
||||
padding-block-start: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-list.ant-list-bordered {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { GitListener } from './listeners/general/GitListener';
|
||||
import * as vscode from 'vscode';
|
||||
import { COMMAND_NAME, TelemetryEvent } from './constants';
|
||||
import { COMMAND_NAME, EXTENSION_NAME, TelemetryEvent } from './constants';
|
||||
import { MarkdownFoldingProvider } from './providers/MarkdownFoldingProvider';
|
||||
import { TagType } from './panelWebView/TagType';
|
||||
import { PanelProvider } from './panelWebView/PanelProvider';
|
||||
@@ -281,7 +281,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
);
|
||||
fmStatusBarItem.command = COMMAND_NAME.dashboard;
|
||||
fmStatusBarItem.text = `$(fm-logo)`;
|
||||
fmStatusBarItem.tooltip = `Front Matter CMS`;
|
||||
fmStatusBarItem.tooltip = EXTENSION_NAME;
|
||||
fmStatusBarItem.show();
|
||||
|
||||
// Register listeners that make sure the status bar updates
|
||||
|
||||
@@ -42,6 +42,8 @@ import { CustomScript } from './CustomScript';
|
||||
import { Folders } from '../commands/Folders';
|
||||
import { existsAsync, readFileAsync } from '../utils';
|
||||
import { mkdirAsync } from '../utils/mkdirAsync';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class ArticleHelper {
|
||||
private static notifiedFiles: string[] = [];
|
||||
@@ -442,7 +444,11 @@ export class ArticleHelper {
|
||||
const newFolder = join(folderPath, sanitizedName);
|
||||
if (await existsAsync(newFolder)) {
|
||||
Notifications.error(
|
||||
`A page bundle with the name ${sanitizedName} already exists in ${folderPath}`
|
||||
l10n.t(
|
||||
LocalizationKey.helpersArticleHelperCreateContentPageBundleError,
|
||||
sanitizedName,
|
||||
folderPath
|
||||
)
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
@@ -466,7 +472,9 @@ export class ArticleHelper {
|
||||
await mkdirAsync(folderPath, { recursive: true });
|
||||
|
||||
if (await existsAsync(newFilePath)) {
|
||||
Notifications.warning(`Content with the title already exists. Please specify a new title.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersArticleHelperCreateContentContentExistsWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -597,7 +605,12 @@ export class ArticleHelper {
|
||||
value = value.replace(regex, updatedValue);
|
||||
}
|
||||
} catch (e) {
|
||||
Notifications.error(`Error while processing the ${placeholder.id} placeholder`);
|
||||
Notifications.error(
|
||||
l10n.t(
|
||||
LocalizationKey.helpersArticleHelperProcessCustomPlaceholdersPlaceholderError,
|
||||
placeholder.id
|
||||
)
|
||||
);
|
||||
Logger.error((e as Error).message);
|
||||
|
||||
value = DefaultFieldValues.faultyCustomPlaceholder;
|
||||
@@ -795,9 +808,10 @@ export class ArticleHelper {
|
||||
Extension.getInstance().diagnosticCollection.set(editor.document.uri, [
|
||||
{
|
||||
severity: DiagnosticSeverity.Error,
|
||||
message: `${
|
||||
error.name ? `${error.name}: ` : ''
|
||||
}Error parsing the front matter of ${fileName}`,
|
||||
message: `${error.name ? `${error.name}: ` : ''}${l10n.t(
|
||||
LocalizationKey.helpersArticleHelperParseFileDiagnosticError,
|
||||
fileName
|
||||
)}`,
|
||||
range: fmRange
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { ModeListener } from './../listeners/general/ModeListener';
|
||||
import { PagesListener } from './../listeners/dashboard';
|
||||
import { ArticleHelper, CustomScript, Settings } from '.';
|
||||
import { ArticleHelper, CustomScript, Logger, Settings } from '.';
|
||||
import {
|
||||
DefaultFieldValues,
|
||||
EXTENSION_NAME,
|
||||
FEATURE_FLAG,
|
||||
SETTING_CONTENT_DRAFT_FIELD,
|
||||
SETTING_DATE_FORMAT,
|
||||
@@ -28,7 +29,9 @@ import { Telemetry } from './Telemetry';
|
||||
import { processKnownPlaceholders } from './PlaceholderHelper';
|
||||
import { basename } from 'path';
|
||||
import { ParsedFrontMatter } from '../parsers';
|
||||
import { encodeEmoji, existsAsync, writeFileAsync } from '../utils';
|
||||
import { encodeEmoji, existsAsync, fieldWhenClause, writeFileAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class ContentType {
|
||||
/**
|
||||
@@ -173,30 +176,34 @@ export class ContentType {
|
||||
const filePath = editor?.document.uri.fsPath;
|
||||
|
||||
if (!content || !content.data) {
|
||||
Notifications.warning(`No front matter data found to generate a content type.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.helpersContentTypeGenerateNoFrontMatterError));
|
||||
return;
|
||||
}
|
||||
|
||||
const override = await window.showQuickPick(['Yes', 'No'], {
|
||||
title: 'Override default content type',
|
||||
placeHolder:
|
||||
'Do you want to overwrite the default content type configuration with the fields used in the current field?',
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
const overrideBool = override === 'Yes';
|
||||
const override = await window.showQuickPick(
|
||||
[l10n.t(LocalizationKey.commonYes), l10n.t(LocalizationKey.commonNo)],
|
||||
{
|
||||
title: l10n.t(LocalizationKey.helpersContentTypeGenerateOverrideQuickPickTitle),
|
||||
placeHolder: l10n.t(LocalizationKey.helpersContentTypeGenerateOverrideQuickPickPlaceholder),
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
const overrideBool = override === l10n.t(LocalizationKey.commonYes);
|
||||
|
||||
let contentTypeName: string | undefined = `default`;
|
||||
|
||||
// Ask for the new content type name
|
||||
if (!overrideBool) {
|
||||
contentTypeName = await window.showInputBox({
|
||||
title: 'Generate Content Type',
|
||||
placeHolder: 'Enter the name of the content type to generate',
|
||||
prompt: 'Enter the name of the content type to generate',
|
||||
title: l10n.t(LocalizationKey.helpersContentTypeGenerateContentTypeInputTitle),
|
||||
placeHolder: l10n.t(LocalizationKey.helpersContentTypeGenerateContentTypeInputPrompt),
|
||||
prompt: l10n.t(LocalizationKey.helpersContentTypeGenerateContentTypeInputPrompt),
|
||||
ignoreFocusOut: true,
|
||||
validateInput: (value: string) => {
|
||||
if (!value) {
|
||||
return 'Please enter a name for the content type';
|
||||
return l10n.t(
|
||||
LocalizationKey.helpersContentTypeGenerateContentTypeInputValidationEnterName
|
||||
);
|
||||
}
|
||||
|
||||
const contentTypes = ContentType.getAll();
|
||||
@@ -204,7 +211,9 @@ export class ContentType {
|
||||
contentTypes &&
|
||||
contentTypes.find((ct) => ct.name.toLowerCase() === value.toLowerCase())
|
||||
) {
|
||||
return 'A content type with this name already exists';
|
||||
return l10n.t(
|
||||
LocalizationKey.helpersContentTypeGenerateContentTypeInputValidationNameExists
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -212,7 +221,9 @@ export class ContentType {
|
||||
});
|
||||
|
||||
if (!contentTypeName) {
|
||||
Notifications.warning(`You didn't specify a name for the content type.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersContentTypeGenerateNoContentTypeNameWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -221,12 +232,17 @@ export class ContentType {
|
||||
let pageBundle = false;
|
||||
const fileName = filePath ? basename(filePath) : undefined;
|
||||
if (fileName?.startsWith(`index.`)) {
|
||||
const pageBundleAnswer = await window.showQuickPick(['Yes', 'No'], {
|
||||
title: 'Use as page bundle',
|
||||
placeHolder: 'Do you want to use this content type as a page bundle?',
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
pageBundle = pageBundleAnswer === 'Yes';
|
||||
const pageBundleAnswer = await window.showQuickPick(
|
||||
[l10n.t(LocalizationKey.commonYes), l10n.t(LocalizationKey.commonNo)],
|
||||
{
|
||||
title: l10n.t(LocalizationKey.helpersContentTypeGeneratePageBundleQuickPickTitle),
|
||||
placeHolder: l10n.t(
|
||||
LocalizationKey.helpersContentTypeGeneratePageBundleQuickPickPlaceHolder
|
||||
),
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
pageBundle = pageBundleAnswer === l10n.t(LocalizationKey.commonYes);
|
||||
}
|
||||
|
||||
const fields = ContentType.generateFields(content.data);
|
||||
@@ -256,11 +272,19 @@ export class ContentType {
|
||||
|
||||
const configPath = await Settings.projectConfigPath();
|
||||
const notificationAction = await Notifications.info(
|
||||
`Content type ${contentTypeName} has been ${overrideBool ? `updated` : `generated`}.`,
|
||||
configPath && (await existsAsync(configPath)) ? `Open settings` : undefined
|
||||
overrideBool
|
||||
? l10n.t(LocalizationKey.helpersContentTypeGenerateUpdatedSuccess)
|
||||
: l10n.t(LocalizationKey.helpersContentTypeGenerateGeneratedSuccess),
|
||||
configPath && (await existsAsync(configPath))
|
||||
? l10n.t(LocalizationKey.commonOpenSettings)
|
||||
: undefined
|
||||
);
|
||||
|
||||
if (notificationAction === 'Open settings' && configPath && (await existsAsync(configPath))) {
|
||||
if (
|
||||
notificationAction === l10n.t(LocalizationKey.commonOpenSettings) &&
|
||||
configPath &&
|
||||
(await existsAsync(configPath))
|
||||
) {
|
||||
commands.executeCommand('vscode.open', Uri.file(configPath));
|
||||
}
|
||||
}
|
||||
@@ -278,7 +302,9 @@ export class ContentType {
|
||||
const content = ArticleHelper.getCurrent();
|
||||
|
||||
if (!content || !content.data) {
|
||||
Notifications.warning(`No front matter data found to add missing fields.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersContentTypeAddMissingFieldsNoFrontMatterWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -293,11 +319,17 @@ export class ContentType {
|
||||
|
||||
const configPath = await Settings.projectConfigPath();
|
||||
const notificationAction = await Notifications.info(
|
||||
`Content type ${contentType.name} has been updated.`,
|
||||
configPath && (await existsAsync(configPath)) ? `Open settings` : undefined
|
||||
l10n.t(LocalizationKey.helpersContentTypeAddMissingFieldsUpdatedSuccess, contentType.name),
|
||||
configPath && (await existsAsync(configPath))
|
||||
? l10n.t(LocalizationKey.commonOpenSettings)
|
||||
: undefined
|
||||
);
|
||||
|
||||
if (notificationAction === 'Open settings' && configPath && (await existsAsync(configPath))) {
|
||||
if (
|
||||
notificationAction === l10n.t(LocalizationKey.commonOpenSettings) &&
|
||||
configPath &&
|
||||
(await existsAsync(configPath))
|
||||
) {
|
||||
commands.executeCommand('vscode.open', Uri.file(configPath));
|
||||
}
|
||||
}
|
||||
@@ -316,16 +348,18 @@ export class ContentType {
|
||||
const contentTypes = ContentType.getAll() || [];
|
||||
|
||||
if (!content || !content.data) {
|
||||
Notifications.warning(`No front matter data found to set the content type.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersContentTypeSetContentTypeNoFrontMatterWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const ctAnswer = await window.showQuickPick(
|
||||
contentTypes.map((ct) => ct.name),
|
||||
{
|
||||
title: 'Select the content type',
|
||||
ignoreFocusOut: true,
|
||||
placeHolder: 'Which content type would you like to use?'
|
||||
title: l10n.t(LocalizationKey.helpersContentTypeSetContentTypeQuickPickTitle),
|
||||
placeHolder: l10n.t(LocalizationKey.helpersContentTypeSetContentTypeQuickPickPlaceholder),
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
|
||||
@@ -739,6 +773,20 @@ export class ContentType {
|
||||
name: field,
|
||||
type: 'number'
|
||||
} as Field);
|
||||
} else if (typeof fieldData === 'boolean') {
|
||||
if (field.toLowerCase() === 'draft') {
|
||||
fields.push({
|
||||
title: field,
|
||||
name: field,
|
||||
type: 'draft'
|
||||
} as Field);
|
||||
} else {
|
||||
fields.push({
|
||||
title: field,
|
||||
name: field,
|
||||
type: 'boolean'
|
||||
} as Field);
|
||||
}
|
||||
} else if (!isNaN(new Date(fieldData).getDate())) {
|
||||
fields.push({
|
||||
title: field,
|
||||
@@ -776,10 +824,66 @@ export class ContentType {
|
||||
window.withProgress(
|
||||
{
|
||||
location: ProgressLocation.Notification,
|
||||
title: 'Front Matter: Creating content...',
|
||||
title: l10n.t(LocalizationKey.helpersContentTypeCreateProgressTitle, EXTENSION_NAME),
|
||||
cancellable: false
|
||||
},
|
||||
async () => {
|
||||
if (contentType.isSubContent || contentType.allowAsSubContent) {
|
||||
let showDialog = true;
|
||||
|
||||
if (contentType.allowAsSubContent) {
|
||||
const subContentAnswer = await window.showQuickPick(
|
||||
[l10n.t(LocalizationKey.commonNo), l10n.t(LocalizationKey.commonYes)],
|
||||
{
|
||||
title: l10n.t(LocalizationKey.helpersContentTypeCreateAllowSubContentTitle),
|
||||
placeHolder: l10n.t(
|
||||
LocalizationKey.helpersContentTypeCreateAllowSubContentPlaceHolder
|
||||
),
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
showDialog = subContentAnswer === l10n.t(LocalizationKey.commonYes);
|
||||
}
|
||||
|
||||
if (showDialog) {
|
||||
const folderLocation = await window.showOpenDialog({
|
||||
canSelectFiles: false,
|
||||
canSelectFolders: true,
|
||||
canSelectMany: false,
|
||||
defaultUri: Uri.file(folderPath),
|
||||
openLabel: l10n.t(
|
||||
LocalizationKey.helpersContentTypeCreateAllowSubContentShowOpenDialogOpenLabel
|
||||
),
|
||||
title: l10n.t(
|
||||
LocalizationKey.helpersContentTypeCreateAllowSubContentShowOpenDialogTitle
|
||||
)
|
||||
});
|
||||
|
||||
if (!folderLocation || folderLocation.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
folderPath = folderLocation[0].fsPath;
|
||||
|
||||
if (contentType.pageBundle) {
|
||||
const createAsPageBundle = await window.showQuickPick(
|
||||
[l10n.t(LocalizationKey.commonNo), l10n.t(LocalizationKey.commonYes)],
|
||||
{
|
||||
title: l10n.t(LocalizationKey.helpersContentTypeCreatePageBundleTitle),
|
||||
placeHolder: l10n.t(
|
||||
LocalizationKey.helpersContentTypeCreatePageBundlePlaceHolder
|
||||
),
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
|
||||
if (createAsPageBundle === l10n.t(LocalizationKey.commonNo)) {
|
||||
contentType.pageBundle = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let titleValue = await Questions.ContentTitle();
|
||||
if (!titleValue) {
|
||||
return;
|
||||
@@ -826,7 +930,13 @@ export class ContentType {
|
||||
!!contentType.clearEmpty
|
||||
);
|
||||
|
||||
data = ArticleHelper.updateDates(Object.assign({}, data));
|
||||
const article: ParsedFrontMatter = {
|
||||
content: '',
|
||||
data: Object.assign({}, data),
|
||||
path: newFilePath
|
||||
};
|
||||
|
||||
data = ArticleHelper.updateDates(article);
|
||||
|
||||
if (contentType.name !== DEFAULT_CONTENT_TYPE_NAME) {
|
||||
data['type'] = contentType.name;
|
||||
@@ -851,7 +961,7 @@ export class ContentType {
|
||||
|
||||
await commands.executeCommand('vscode.open', Uri.file(newFilePath));
|
||||
|
||||
Notifications.info(`Your new content has been created.`);
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersContentTypeCreateSuccess));
|
||||
|
||||
Telemetry.send(TelemetryEvent.createContentFromContentType);
|
||||
|
||||
@@ -878,6 +988,11 @@ export class ContentType {
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
|
||||
for (const field of obj.fields) {
|
||||
if (!fieldWhenClause(field, data, obj.fields)) {
|
||||
Logger.info(`Field ${field.name} not added because of when clause`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field.name === 'title') {
|
||||
if (field.default) {
|
||||
data[field.name] = processKnownPlaceholders(
|
||||
@@ -992,7 +1107,7 @@ export class ContentType {
|
||||
private static async verify() {
|
||||
const hasFeature = await ModeListener.hasFeature(FEATURE_FLAG.panel.contentType);
|
||||
if (!hasFeature) {
|
||||
Notifications.warning(`The content type actions are not available in this mode.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.helpersContentTypeVerifyWarning));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ import { ParsedFrontMatter } from '../parsers';
|
||||
import { TelemetryEvent } from '../constants/TelemetryEvent';
|
||||
import { SETTING_CUSTOM_SCRIPTS } from '../constants';
|
||||
import { existsAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class CustomScript {
|
||||
/**
|
||||
@@ -101,7 +103,9 @@ export class CustomScript {
|
||||
}
|
||||
);
|
||||
} else {
|
||||
Notifications.warning(`${script.title}: Article couldn't be retrieved.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersCustomScriptSingleRunArticleWarning, script.title)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +119,9 @@ export class CustomScript {
|
||||
const folders = await Folders.getInfo();
|
||||
|
||||
if (!folders || folders.length === 0) {
|
||||
Notifications.warning(`${script.title}: No files found.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersCustomScriptBulkRunNoFilesWarning, script.title)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -124,7 +130,7 @@ export class CustomScript {
|
||||
window.withProgress(
|
||||
{
|
||||
location: ProgressLocation.Notification,
|
||||
title: `Executing: ${script.title}`,
|
||||
title: l10n.t(LocalizationKey.helpersCustomScriptExecuting, script.title),
|
||||
cancellable: false
|
||||
},
|
||||
async (progress, token) => {
|
||||
@@ -169,7 +175,9 @@ export class CustomScript {
|
||||
script: ICustomScript
|
||||
): Promise<void> {
|
||||
if (!path) {
|
||||
Notifications.error(`${script.title}: There was no folder or media path specified.`);
|
||||
Notifications.error(
|
||||
l10n.t(LocalizationKey.helpersCustomScriptRunMediaScriptNoFolderWarning, script.title)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -177,7 +185,7 @@ export class CustomScript {
|
||||
window.withProgress(
|
||||
{
|
||||
location: ProgressLocation.Notification,
|
||||
title: `Executing: ${script.title}`,
|
||||
title: l10n.t(LocalizationKey.helpersCustomScriptExecuting, script.title),
|
||||
cancellable: false
|
||||
},
|
||||
async () => {
|
||||
@@ -196,7 +204,7 @@ export class CustomScript {
|
||||
|
||||
return;
|
||||
} catch (e) {
|
||||
Notifications.error(`${script.title}: ${(e as Error).message}`);
|
||||
Notifications.errorWithOutput(`${script.title} -`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -286,11 +294,15 @@ export class CustomScript {
|
||||
} else if (editor) {
|
||||
await ArticleHelper.update(editor, article);
|
||||
} else {
|
||||
Logger.error(`Couldn't update article.`);
|
||||
throw new Error(`Couldn't update article.`);
|
||||
}
|
||||
Notifications.info(`${script.title}: front matter updated.`);
|
||||
Notifications.info(
|
||||
l10n.t(LocalizationKey.helpersCustomScriptShowOutputFrontMatterSuccess, script.title)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Logger.error(`No frontmatter found.`);
|
||||
throw new Error(`No frontmatter found.`);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -298,16 +310,21 @@ export class CustomScript {
|
||||
ContentProvider.show(output, script.title, script.outputType || 'text');
|
||||
} else {
|
||||
window
|
||||
.showInformationMessage(`${script.title}: ${output}`, 'Copy output')
|
||||
.showInformationMessage(
|
||||
`${script.title}: ${output}`,
|
||||
l10n.t(LocalizationKey.helpersCustomScriptShowOutputCopyOutputAction)
|
||||
)
|
||||
.then((value) => {
|
||||
if (value === 'Copy output') {
|
||||
if (value === l10n.t(LocalizationKey.helpersCustomScriptShowOutputCopyOutputAction)) {
|
||||
vscodeEnv.clipboard.writeText(output);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Notifications.info(`${script.title}: Executed your custom script.`);
|
||||
Notifications.info(
|
||||
l10n.t(LocalizationKey.helpersCustomScriptShowOutputSuccess, script.title)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,6 +377,7 @@ export class CustomScript {
|
||||
}
|
||||
|
||||
if (!(await existsAsync(scriptPath))) {
|
||||
Logger.error(`Script not found: ${scriptPath}`);
|
||||
throw new Error(`Script not found: ${scriptPath}`);
|
||||
}
|
||||
|
||||
@@ -368,7 +386,7 @@ export class CustomScript {
|
||||
}
|
||||
|
||||
const fullScript = `${command} "${scriptPath}" ${args}`;
|
||||
Logger.info(`Executing: ${fullScript}`);
|
||||
Logger.info(l10n.t(LocalizationKey.helpersCustomScriptExecuting, fullScript));
|
||||
|
||||
const output: string = await CustomScript.executeScriptAsync(fullScript, wsPath);
|
||||
|
||||
@@ -416,6 +434,7 @@ export class CustomScript {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
exec(fullScript, { cwd: wsPath }, (error, stdout) => {
|
||||
if (error) {
|
||||
Logger.error(error.message);
|
||||
reject(error.message);
|
||||
return;
|
||||
}
|
||||
@@ -441,7 +460,7 @@ export class CustomScript {
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
Logger.error(`Invalid command: ${command}`);
|
||||
Logger.error(l10n.t(LocalizationKey.helpersCustomScriptValidateCommandError, command));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import { commands } from 'vscode';
|
||||
import { COMMAND_NAME, SETTING_DATA_FILES } from '../constants';
|
||||
import { Settings } from './SettingsHelper';
|
||||
import { existsAsync, readFileAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class DataFileHelper {
|
||||
/**
|
||||
@@ -54,21 +56,13 @@ export class DataFileHelper {
|
||||
const dataFile = await DataFileHelper.get(file);
|
||||
|
||||
if (fileType === 'yaml') {
|
||||
return yaml.safeLoad(dataFile || '');
|
||||
return yaml.load(dataFile || '');
|
||||
} else {
|
||||
return dataFile ? JSON.parse(dataFile) : undefined;
|
||||
}
|
||||
} catch (ex) {
|
||||
Logger.error(`DataFileHelper::process: ${(ex as Error).message}`);
|
||||
const btnClick = await Notifications.error(
|
||||
`Something went wrong while processing the data file. Check your file and output log for more information.`,
|
||||
'Open output'
|
||||
);
|
||||
|
||||
if (btnClick && btnClick === 'Open output') {
|
||||
commands.executeCommand(COMMAND_NAME.showOutputChannel);
|
||||
}
|
||||
|
||||
Notifications.errorWithOutput(l10n.t(LocalizationKey.helpersDataFileHelperProcessError));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ import { Notifications } from './Notifications';
|
||||
import { Settings } from './SettingsHelper';
|
||||
import { TaxonomyHelper } from './TaxonomyHelper';
|
||||
import { Cache } from '../commands/Cache';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Extension {
|
||||
private static instance: Extension;
|
||||
@@ -72,8 +74,8 @@ export class Extension {
|
||||
}
|
||||
|
||||
if (usedVersion !== installedVersion) {
|
||||
const whatIsNewTitle = `Check the changelog`;
|
||||
const githubTitle = `Give it a ⭐️`;
|
||||
const whatIsNewTitle = l10n.t(LocalizationKey.helpersExtensionGetVersionChangelog);
|
||||
const githubTitle = l10n.t(LocalizationKey.helpersExtensionGetVersionStarIt);
|
||||
|
||||
const whatIsNew = {
|
||||
title: whatIsNewTitle,
|
||||
@@ -94,7 +96,11 @@ export class Extension {
|
||||
|
||||
window
|
||||
.showInformationMessage(
|
||||
`${EXTENSION_NAME} has been updated to v${installedVersion} — check out what's new!`,
|
||||
l10n.t(
|
||||
LocalizationKey.helpersExtensionGetVersionUpdateNotification,
|
||||
EXTENSION_NAME,
|
||||
installedVersion
|
||||
),
|
||||
starGitHub,
|
||||
whatIsNew
|
||||
)
|
||||
@@ -215,11 +221,18 @@ export class Extension {
|
||||
modifiedField?.teamValue
|
||||
) {
|
||||
Notifications.warning(
|
||||
`The "${CONFIG_KEY}.${SETTING_DATE_FIELD}" and "${CONFIG_KEY}.${SETTING_MODIFIED_FIELD}" settings have been deprecated. Please use the "isPublishDate" and "isModifiedDate" datetime field properties instead.`,
|
||||
'Hide',
|
||||
'See migration guide'
|
||||
l10n.t(
|
||||
LocalizationKey.helpersExtensionMigrateSettingsDeprecatedWarning,
|
||||
`${CONFIG_KEY}.${SETTING_DATE_FIELD}`,
|
||||
`${CONFIG_KEY}.${SETTING_MODIFIED_FIELD}`
|
||||
),
|
||||
l10n.t(LocalizationKey.helpersExtensionMigrateSettingsDeprecatedWarningHide),
|
||||
l10n.t(LocalizationKey.helpersExtensionMigrateSettingsDeprecatedWarningSeeGuide)
|
||||
).then(async (value) => {
|
||||
if (value === 'See migration guide') {
|
||||
if (
|
||||
value ===
|
||||
l10n.t(LocalizationKey.helpersExtensionMigrateSettingsDeprecatedWarningSeeGuide)
|
||||
) {
|
||||
const isProd = this.isProductionMode;
|
||||
commands.executeCommand(
|
||||
'vscode.open',
|
||||
@@ -234,7 +247,9 @@ export class Extension {
|
||||
true,
|
||||
'workspace'
|
||||
);
|
||||
} else if (value === 'Hide') {
|
||||
} else if (
|
||||
value === l10n.t(LocalizationKey.helpersExtensionMigrateSettingsDeprecatedWarningHide)
|
||||
) {
|
||||
await Extension.getInstance().setState<boolean>(
|
||||
ExtensionState.Updates.v7_0_0.dateFields,
|
||||
true,
|
||||
@@ -291,15 +306,23 @@ export class Extension {
|
||||
|
||||
const templates = await Template.getTemplates();
|
||||
if (templates && templates.length > 0) {
|
||||
const answer = await window.showQuickPick(['Yes', 'No'], {
|
||||
title: 'Front Matter - Templates',
|
||||
placeHolder: 'Do you want to keep on using the template functionality?',
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
const answer = await window.showQuickPick(
|
||||
[l10n.t(LocalizationKey.commonYes), l10n.t(LocalizationKey.commonNo)],
|
||||
{
|
||||
title: l10n.t(
|
||||
LocalizationKey.helpersExtensionMigrateSettingsTemplatesQuickPickTitle,
|
||||
EXTENSION_NAME
|
||||
),
|
||||
placeHolder: l10n.t(
|
||||
LocalizationKey.helpersExtensionMigrateSettingsTemplatesQuickPickPlaceholder
|
||||
),
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
|
||||
await Settings.update(
|
||||
SETTING_TEMPLATES_ENABLED,
|
||||
answer?.toLocaleLowerCase() === 'yes',
|
||||
answer?.toLocaleLowerCase() === l10n.t(LocalizationKey.commonYes),
|
||||
true
|
||||
);
|
||||
}
|
||||
@@ -410,9 +433,7 @@ export class Extension {
|
||||
const mainVersionInstalled = extensions.getExtension(EXTENSION_ID);
|
||||
|
||||
if (mainVersionInstalled) {
|
||||
Notifications.error(
|
||||
`Front Matter BETA cannot be used while the main version is installed. Please ensure that you have only over version installed.`
|
||||
);
|
||||
Notifications.error(l10n.t(LocalizationKey.helpersExtensionCheckIfExtensionCanRunWarning));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import { MediaListener as DashboardMediaListener } from '../listeners/dashboard'
|
||||
import { ArticleHelper } from './ArticleHelper';
|
||||
import { lookup } from 'mime-types';
|
||||
import { existsAsync, readdirAsync, unlinkAsync, writeFileAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class MediaHelpers {
|
||||
private static media: MediaInfo[] = [];
|
||||
@@ -308,7 +310,7 @@ export class MediaHelpers {
|
||||
}
|
||||
|
||||
if (!(await existsAsync(absFolderPath))) {
|
||||
Notifications.error(`We couldn't find your selected folder.`);
|
||||
Notifications.error(l10n.t(LocalizationKey.helpersMediaHelperSaveFileFolderError));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -317,12 +319,22 @@ export class MediaHelpers {
|
||||
|
||||
if (imgData) {
|
||||
await writeFileAsync(staticPath, imgData.data);
|
||||
Notifications.info(`File ${fileName} uploaded to: ${folder}`);
|
||||
Notifications.info(
|
||||
l10n.t(
|
||||
LocalizationKey.helpersMediaHelperSaveFileFileUploadedSuccess,
|
||||
fileName,
|
||||
folder || ''
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
Notifications.error(`Something went wrong uploading ${fileName}`);
|
||||
throw new Error(`Something went wrong uploading ${fileName}`);
|
||||
Notifications.error(
|
||||
l10n.t(LocalizationKey.helpersMediaHelperSaveFileFileUploadedFailed, fileName)
|
||||
);
|
||||
throw new Error(
|
||||
l10n.t(LocalizationKey.helpersMediaHelperSaveFileFileUploadedFailed, fileName)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,8 +367,12 @@ export class MediaHelpers {
|
||||
MediaHelpers.media = [];
|
||||
return true;
|
||||
} catch (err: any) {
|
||||
Notifications.error(`Something went wrong deleting ${basename(file)}`);
|
||||
throw new Error(`Something went wrong deleting ${basename(file)}`);
|
||||
Notifications.error(
|
||||
l10n.t(LocalizationKey.helpersMediaHelperDeleteFileFileDeletionFailed, basename(file))
|
||||
);
|
||||
throw new Error(
|
||||
l10n.t(LocalizationKey.helpersMediaHelperDeleteFileFileDeletionFailed, basename(file))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import { LocalStore } from '../constants';
|
||||
import { existsAsync, renameAsync } from '../utils';
|
||||
import { existsSync, mkdirSync, renameSync } from 'fs';
|
||||
import { lookup } from 'mime-types';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
interface MediaRecord {
|
||||
description: string;
|
||||
@@ -160,14 +162,14 @@ export class MediaLibrary {
|
||||
const newPath = join(dirname(filePath), `${newFileInfo.name}${oldFileInfo.ext}`);
|
||||
|
||||
if (await existsAsync(newPath)) {
|
||||
Notifications.warning(`The name "${filename}" already exists at the file location.`);
|
||||
Notifications.warning(LocalizationKey.helpersMediaLibraryRemoveWarning, filename);
|
||||
} else {
|
||||
await renameAsync(filePath, newPath);
|
||||
await this.rename(filePath, newPath);
|
||||
MediaHelpers.resetMedia();
|
||||
}
|
||||
} catch (err) {
|
||||
Notifications.error(`Something went wrong updating "${name}" to "${filename}".`);
|
||||
Notifications.error(l10n.t(LocalizationKey.helpersMediaLibraryRemoveError, name, filename));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { SETTING_GLOBAL_NOTIFICATIONS_DISABLED } from './../constants/settings';
|
||||
import { window } from 'vscode';
|
||||
import { EXTENSION_NAME, SETTING_GLOBAL_NOTIFICATIONS } from '../constants';
|
||||
import { COMMAND_NAME, EXTENSION_NAME, SETTING_GLOBAL_NOTIFICATIONS } from '../constants';
|
||||
import { Logger } from './Logger';
|
||||
import { Settings } from './SettingsHelper';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
type NotificationType = 'INFO' | 'WARNING' | 'ERROR' | 'ERROR_ONCE';
|
||||
|
||||
@@ -57,6 +59,30 @@ export class Notifications {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an error notification to the user with a link to the output channel
|
||||
* @param message
|
||||
* @param items
|
||||
* @returns
|
||||
*/
|
||||
public static errorWithOutput(message: string, ...items: any): Thenable<string | undefined> {
|
||||
Logger.info(`${EXTENSION_NAME}: ${message}`, 'ERROR');
|
||||
|
||||
if (this.shouldShow('ERROR')) {
|
||||
return window.showErrorMessage(
|
||||
`${EXTENSION_NAME}: ${message} ${l10n.t(
|
||||
LocalizationKey.notificationsOutputChannelDescription,
|
||||
`[${l10n.t(LocalizationKey.notificationsOutputChannelLink)}](command:${
|
||||
COMMAND_NAME.showOutputChannel
|
||||
})`
|
||||
)}`,
|
||||
...items
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an error notification to the user only once
|
||||
* @param message
|
||||
|
||||
@@ -29,7 +29,6 @@ import {
|
||||
SETTING_SLUG_PREFIX,
|
||||
SETTING_SLUG_SUFFIX,
|
||||
SETTING_SLUG_UPDATE_FILE_NAME,
|
||||
SETTING_TAXONOMY_CONTENT_TYPES,
|
||||
SETTING_TAXONOMY_CUSTOM,
|
||||
SETTING_TAXONOMY_FIELD_GROUPS,
|
||||
SETTING_GIT_ENABLED,
|
||||
|
||||
@@ -6,6 +6,8 @@ import { Notifications } from './Notifications';
|
||||
import { Settings } from './SettingsHelper';
|
||||
import { Logger } from './Logger';
|
||||
import { SponsorAi } from '../services/SponsorAI';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Questions {
|
||||
/**
|
||||
@@ -14,12 +16,15 @@ export class Questions {
|
||||
* @returns
|
||||
*/
|
||||
public static async yesOrNo(placeholder: string) {
|
||||
const answer = await window.showQuickPick(['yes', 'no'], {
|
||||
placeHolder: placeholder,
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
return answer === 'yes';
|
||||
const answer = await window.showQuickPick(
|
||||
[l10n.t(LocalizationKey.commonYes), l10n.t(LocalizationKey.commonNo)],
|
||||
{
|
||||
placeHolder: placeholder,
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
return answer === l10n.t(LocalizationKey.commonYes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,9 +41,9 @@ export class Questions {
|
||||
|
||||
if (githubAuth && githubAuth.account.label) {
|
||||
title = await window.showInputBox({
|
||||
title: 'Title or description',
|
||||
prompt: `What would you like to write about?`,
|
||||
placeHolder: `Content title or description`,
|
||||
title: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputTitle),
|
||||
prompt: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputPrompt),
|
||||
placeHolder: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputPlaceholder),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
@@ -49,14 +54,18 @@ export class Questions {
|
||||
if (aiTitles && aiTitles.length > 0) {
|
||||
const options: QuickPickItem[] = [
|
||||
{
|
||||
label: `✏️ your title/description`,
|
||||
label: `✏️ ${l10n.t(
|
||||
LocalizationKey.helpersQuestionsContentTitleAiInputQuickPickTitleSeparator
|
||||
)}`,
|
||||
kind: QuickPickItemKind.Separator
|
||||
},
|
||||
{
|
||||
label: title
|
||||
},
|
||||
{
|
||||
label: `🤖 AI generated title`,
|
||||
label: `🤖 ${l10n.t(
|
||||
LocalizationKey.helpersQuestionsContentTitleAiInputQuickPickAiSeparator
|
||||
)}`,
|
||||
kind: QuickPickItemKind.Separator
|
||||
},
|
||||
...aiTitles.map((d: string) => ({
|
||||
@@ -65,8 +74,10 @@ export class Questions {
|
||||
];
|
||||
|
||||
const selectedTitle = await window.showQuickPick(options, {
|
||||
title: 'Select a title',
|
||||
placeHolder: `Select a title for your content`,
|
||||
title: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputSelectTitle),
|
||||
placeHolder: l10n.t(
|
||||
LocalizationKey.helpersQuestionsContentTitleAiInputSelectPlaceholder
|
||||
),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
@@ -79,13 +90,11 @@ export class Questions {
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.error((e as Error).message);
|
||||
Notifications.error(
|
||||
`Failed fetching the AI title. Please try to use your own title or try again later.`
|
||||
);
|
||||
Notifications.error(l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputFailed));
|
||||
title = undefined;
|
||||
}
|
||||
} else if (!title && showWarning) {
|
||||
Notifications.warning(`You did not specify a title for your content.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputWarning));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -93,15 +102,15 @@ export class Questions {
|
||||
|
||||
if (!title) {
|
||||
title = await window.showInputBox({
|
||||
title: 'Title',
|
||||
prompt: `What would you like to use as a title for the content to create?`,
|
||||
placeHolder: `Content title`,
|
||||
title: l10n.t(LocalizationKey.helpersQuestionsContentTitleTitleInputTitle),
|
||||
prompt: l10n.t(LocalizationKey.helpersQuestionsContentTitleTitleInputPrompt),
|
||||
placeHolder: l10n.t(LocalizationKey.helpersQuestionsContentTitleTitleInputPlaceholder),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
}
|
||||
|
||||
if (!title && showWarning) {
|
||||
Notifications.warning(`You did not specify a title for your content.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.helpersQuestionsContentTitleTitleInputWarning));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -123,20 +132,26 @@ export class Questions {
|
||||
selectedFolder = await window.showQuickPick(
|
||||
folders.map((f) => f.title),
|
||||
{
|
||||
title: `Select a folder`,
|
||||
placeHolder: `Select where you want to create your content`,
|
||||
title: l10n.t(LocalizationKey.helpersQuestionsSelectContentFolderQuickPickTitle),
|
||||
placeHolder: l10n.t(
|
||||
LocalizationKey.helpersQuestionsSelectContentFolderQuickPickPlaceholder
|
||||
),
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
} else if (folders.length === 1) {
|
||||
selectedFolder = folders[0].title;
|
||||
} else {
|
||||
Notifications.warning(`No page folders were configures.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersQuestionsSelectContentFolderQuickPickNoFoldersWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedFolder && showWarning) {
|
||||
Notifications.warning(`You didn't select a place where you wanted to create your content.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersQuestionsSelectContentFolderQuickPickNoSelectionWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -155,7 +170,9 @@ export class Questions {
|
||||
): Promise<string | undefined> {
|
||||
let contentTypes = ContentType.getAll();
|
||||
if (!contentTypes || contentTypes.length === 0) {
|
||||
Notifications.warning('No content types found. Please create a content type first.');
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersQuestionsSelectContentTypeNoContentTypeWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -175,14 +192,16 @@ export class Questions {
|
||||
}));
|
||||
|
||||
const selectedOption = await window.showQuickPick(options, {
|
||||
title: `Content type`,
|
||||
placeHolder: `Select the content type to create your new content`,
|
||||
title: l10n.t(LocalizationKey.helpersQuestionsSelectContentTypeQuickPickTitle),
|
||||
placeHolder: l10n.t(LocalizationKey.helpersQuestionsSelectContentTypeQuickPickPlaceholder),
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!selectedOption && showWarning) {
|
||||
Notifications.warning('No content type was selected.');
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.helpersQuestionsSelectContentTypeNoSelectionWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { ArticleHelper } from '.';
|
||||
import { ParsedFrontMatter } from '../parsers';
|
||||
import { EXTENSION_NAME } from '../constants';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class SeoHelper {
|
||||
public static checkLength(
|
||||
@@ -23,10 +26,15 @@ export class SeoHelper {
|
||||
|
||||
const diagnostic: vscode.Diagnostic = {
|
||||
code: '',
|
||||
message: `Article ${fieldName} is longer than ${length} characters (current length: ${value.length}). For SEO reasons, it would be better to make it less than ${length} characters.`,
|
||||
message: l10n.t(
|
||||
LocalizationKey.helpersSeoHelperCheckLengthDiagnosticMessage,
|
||||
fieldName,
|
||||
length,
|
||||
value.length
|
||||
),
|
||||
range: new vscode.Range(posStart, posEnd),
|
||||
severity: vscode.DiagnosticSeverity.Warning,
|
||||
source: 'Front Matter'
|
||||
source: EXTENSION_NAME
|
||||
};
|
||||
|
||||
if (collection.has(editor.document.uri)) {
|
||||
|
||||
@@ -51,6 +51,8 @@ import { GitListener } from '../listeners/general';
|
||||
import { DataListener } from '../listeners/panel';
|
||||
import { MarkdownFoldingProvider } from '../providers/MarkdownFoldingProvider';
|
||||
import { ModeSwitch } from '../services/ModeSwitch';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class Settings {
|
||||
public static globalFile = 'frontmatter.json';
|
||||
@@ -181,16 +183,19 @@ export class Settings {
|
||||
if (Settings.hasSettings()) {
|
||||
window
|
||||
.showInformationMessage(
|
||||
`You have local settings. Would you like to promote them to the global settings ("frontmatter.json")?`,
|
||||
'Yes',
|
||||
'No'
|
||||
l10n.t(LocalizationKey.helpersSettingsHelperCheckToPromoteMessage),
|
||||
l10n.t(LocalizationKey.commonYes),
|
||||
l10n.t(LocalizationKey.commonNo)
|
||||
)
|
||||
.then(async (result) => {
|
||||
if (result === 'Yes') {
|
||||
if (result === l10n.t(LocalizationKey.commonYes)) {
|
||||
Settings.promote();
|
||||
}
|
||||
|
||||
if (result === 'No' || result === 'Yes') {
|
||||
if (
|
||||
result === l10n.t(LocalizationKey.commonNo) ||
|
||||
result === l10n.t(LocalizationKey.commonYes)
|
||||
) {
|
||||
Extension.getInstance().setState(ExtensionState.SettingPromoted, true, 'workspace');
|
||||
}
|
||||
});
|
||||
@@ -529,7 +534,7 @@ export class Settings {
|
||||
}
|
||||
}
|
||||
|
||||
Notifications.info(`All settings promoted to team level.`);
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersSettingsHelperPromoteSuccess));
|
||||
|
||||
Telemetry.send(TelemetryEvent.promoteSettings);
|
||||
}
|
||||
@@ -663,7 +668,10 @@ export class Settings {
|
||||
await window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: `${EXTENSION_NAME}: Reading dynamic config file...`
|
||||
title: l10n.t(
|
||||
LocalizationKey.helpersSettingsHelperReadConfigProgressTitle,
|
||||
EXTENSION_NAME
|
||||
)
|
||||
},
|
||||
async () => {
|
||||
const absFilePath = Folders.getAbsFilePath(dynamicConfigPath);
|
||||
@@ -691,9 +699,7 @@ export class Settings {
|
||||
}
|
||||
} catch (e) {
|
||||
Settings.globalConfig = undefined;
|
||||
Notifications.error(
|
||||
`Error reading "frontmatter.json" config file. Check [output window](command:${COMMAND_NAME.showOutputChannel}) for more details.`
|
||||
);
|
||||
Notifications.errorWithOutput(l10n.t(LocalizationKey.helpersSettingsHelperReadConfigError));
|
||||
Logger.error((e as Error).message);
|
||||
}
|
||||
|
||||
@@ -1103,7 +1109,7 @@ export class Settings {
|
||||
*/
|
||||
private static async refreshConfig() {
|
||||
await Settings.reloadConfig();
|
||||
Notifications.info(`Settings have been refreshed.`);
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersSettingsHelperRefreshConfigSuccess));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,6 +64,6 @@ export class SlugHelper {
|
||||
*/
|
||||
private static replaceCharacters(value: string) {
|
||||
const characters = [...value];
|
||||
return characters.map((c) => charMap[c] || c).join('');
|
||||
return characters.map((c) => (typeof charMap[c] === 'string' ? charMap[c] : c)).join('');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import { Folders } from '../commands';
|
||||
import { join } from 'path';
|
||||
import { SettingsListener as PanelSettingsListener } from '../listeners/panel';
|
||||
import { SettingsListener as DashboardSettingsListener } from '../listeners/dashboard';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class TaxonomyHelper {
|
||||
private static db: JsonDB;
|
||||
@@ -126,15 +128,15 @@ export class TaxonomyHelper {
|
||||
const { type, value } = data;
|
||||
|
||||
const answer = await window.showInputBox({
|
||||
title: `Rename the "${value}"`,
|
||||
title: l10n.t(LocalizationKey.helpersTaxonomyHelperRenameInputTitle, value),
|
||||
value,
|
||||
validateInput: (text) => {
|
||||
if (text === value) {
|
||||
return 'The new value must be different from the old one.';
|
||||
return l10n.t(LocalizationKey.helpersTaxonomyHelperRenameValidateEqualValue);
|
||||
}
|
||||
|
||||
if (!text) {
|
||||
return 'A new value must be provided.';
|
||||
return l10n.t(LocalizationKey.helpersTaxonomyHelperRenameValidateNoValue);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -168,8 +170,8 @@ export class TaxonomyHelper {
|
||||
const answer = await window.showQuickPick(
|
||||
options.filter((o) => o !== value),
|
||||
{
|
||||
title: `Merge the "${value}" with another ${type} value`,
|
||||
placeHolder: `Select the ${type} value to merge with`,
|
||||
title: l10n.t(LocalizationKey.helpersTaxonomyHelperMergeQuickPickTitle, value, type),
|
||||
placeHolder: l10n.t(LocalizationKey.helpersTaxonomyHelperMergeQuickPickPlaceholder, type),
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
@@ -188,13 +190,20 @@ export class TaxonomyHelper {
|
||||
public static async delete(data: { type: string; value: string }) {
|
||||
const { type, value } = data;
|
||||
|
||||
const answer = await window.showQuickPick(['Yes', 'No'], {
|
||||
title: `Delete the "${value}" ${type} value`,
|
||||
placeHolder: `Are you sure you want to delete the "${value}" ${type} value?`,
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
const answer = await window.showQuickPick(
|
||||
[l10n.t(LocalizationKey.commonYes), l10n.t(LocalizationKey.commonNo)],
|
||||
{
|
||||
title: l10n.t(LocalizationKey.helpersTaxonomyHelperDeleteQuickPickTitle, value, type),
|
||||
placeHolder: l10n.t(
|
||||
LocalizationKey.helpersTaxonomyHelperDeleteQuickPickPlaceholder,
|
||||
value,
|
||||
type
|
||||
),
|
||||
ignoreFocusOut: true
|
||||
}
|
||||
);
|
||||
|
||||
if (!answer || answer === 'No') {
|
||||
if (!answer || answer === l10n.t(LocalizationKey.commonNo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -221,16 +230,16 @@ export class TaxonomyHelper {
|
||||
const options = await this.getTaxonomyOptions(taxonomyType);
|
||||
|
||||
const newOption = await window.showInputBox({
|
||||
title: `Create a new ${type} value`,
|
||||
placeHolder: `The value you want to add`,
|
||||
title: l10n.t(LocalizationKey.helpersTaxonomyHelperCreateNewInputTitle, type),
|
||||
placeHolder: l10n.t(LocalizationKey.helpersTaxonomyHelperCreateNewInputPlaceholder),
|
||||
ignoreFocusOut: true,
|
||||
validateInput: (text) => {
|
||||
if (!text) {
|
||||
return 'A value must be provided.';
|
||||
return l10n.t(LocalizationKey.helpersTaxonomyHelperCreateNewInputValidateNoValue);
|
||||
}
|
||||
|
||||
if (options.includes(text)) {
|
||||
return 'The value already exists.';
|
||||
return l10n.t(LocalizationKey.helpersTaxonomyHelperCreateNewInputValidateExists);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -276,11 +285,28 @@ export class TaxonomyHelper {
|
||||
let progressText = ``;
|
||||
|
||||
if (type === 'edit') {
|
||||
progressText = `${EXTENSION_NAME}: Renaming "${oldValue}" from ${taxonomyName} to "${newValue}".`;
|
||||
progressText = l10n.t(
|
||||
LocalizationKey.helpersTaxonomyHelperProcessEdit,
|
||||
EXTENSION_NAME,
|
||||
oldValue,
|
||||
taxonomyName,
|
||||
newValue || ''
|
||||
);
|
||||
} else if (type === 'merge') {
|
||||
progressText = `${EXTENSION_NAME}: Merging "${oldValue}" from "${taxonomyName}" to "${newValue}".`;
|
||||
progressText = l10n.t(
|
||||
LocalizationKey.helpersTaxonomyHelperProcessMerge,
|
||||
EXTENSION_NAME,
|
||||
oldValue,
|
||||
taxonomyName,
|
||||
newValue || ''
|
||||
);
|
||||
} else if (type === 'delete') {
|
||||
progressText = `${EXTENSION_NAME}: Deleting "${oldValue}" from "${taxonomyName}".`;
|
||||
progressText = l10n.t(
|
||||
LocalizationKey.helpersTaxonomyHelperProcessDelete,
|
||||
EXTENSION_NAME,
|
||||
oldValue,
|
||||
taxonomyName
|
||||
);
|
||||
}
|
||||
|
||||
window.withProgress(
|
||||
@@ -350,11 +376,11 @@ export class TaxonomyHelper {
|
||||
await this.addToSettings(taxonomyType, oldValue, newValue);
|
||||
|
||||
if (type === 'edit') {
|
||||
Notifications.info(`Edit completed.`);
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersTaxonomyHelperProcessEditSuccess));
|
||||
} else if (type === 'merge') {
|
||||
Notifications.info(`Merge completed.`);
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersTaxonomyHelperProcessMergeSuccess));
|
||||
} else if (type === 'delete') {
|
||||
Notifications.info(`Deletion completed.`);
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersTaxonomyHelperProcessDeleteSuccess));
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -375,8 +401,8 @@ export class TaxonomyHelper {
|
||||
options = options.filter((o) => o !== type);
|
||||
|
||||
const answer = await window.showQuickPick(options, {
|
||||
title: `Move the "${value}" to another type`,
|
||||
placeHolder: `Select the type to move to`,
|
||||
title: l10n.t(LocalizationKey.helpersTaxonomyHelperMoveQuickPickTitle, value),
|
||||
placeHolder: l10n.t(LocalizationKey.helpersTaxonomyHelperMoveQuickPickPlaceholder),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
@@ -390,7 +416,13 @@ export class TaxonomyHelper {
|
||||
window.withProgress(
|
||||
{
|
||||
location: ProgressLocation.Notification,
|
||||
title: `${EXTENSION_NAME}: Moving "${value}" from ${type} to "${answer}".`,
|
||||
title: l10n.t(
|
||||
LocalizationKey.helpersTaxonomyHelperMoveProgressTitle,
|
||||
EXTENSION_NAME,
|
||||
value,
|
||||
type,
|
||||
answer
|
||||
),
|
||||
cancellable: false
|
||||
},
|
||||
async (progress) => {
|
||||
@@ -465,7 +497,7 @@ export class TaxonomyHelper {
|
||||
|
||||
await this.process('delete', oldType, value);
|
||||
|
||||
Notifications.info(`Move completed.`);
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersTaxonomyHelperMoveSuccess));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Uri, workspace, window } from 'vscode';
|
||||
import { Logger } from './Logger';
|
||||
import { Notifications } from './Notifications';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export const openFileInEditor = async (filePath: string) => {
|
||||
if (filePath) {
|
||||
@@ -8,7 +10,7 @@ export const openFileInEditor = async (filePath: string) => {
|
||||
const doc = await workspace.openTextDocument(Uri.file(filePath));
|
||||
await window.showTextDocument(doc, 1, false);
|
||||
} catch (e) {
|
||||
Notifications.error(`Couldn't open the file.`);
|
||||
Notifications.error(l10n.t(LocalizationKey.helpersOpenFileInEditorError));
|
||||
Logger.error(`${filePath}: ${(e as Error).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { dirname, relative } from 'path';
|
||||
import { ContentFolder } from '../models';
|
||||
|
||||
export const processPathPlaceholders = (
|
||||
@@ -7,6 +8,13 @@ export const processPathPlaceholders = (
|
||||
contentFolder: ContentFolder | null | undefined
|
||||
) => {
|
||||
if (value && value.includes('{{pathToken.')) {
|
||||
const relPathToken = '{{pathToken.relPath}}';
|
||||
if (value.includes(relPathToken) && contentFolder?.path) {
|
||||
const dirName = dirname(filePath);
|
||||
let relPath = relative(contentFolder.path, dirName);
|
||||
value = value.replace(relPathToken, relPath);
|
||||
}
|
||||
|
||||
const regex = /{{pathToken.(\d+|relPath)}}/g;
|
||||
const matches = value.match(regex);
|
||||
if (matches) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Dashboard } from '../../commands/Dashboard';
|
||||
import { DashboardCommand } from '../../dashboardWebView/DashboardCommand';
|
||||
import { DashboardMessage } from '../../dashboardWebView/DashboardMessage';
|
||||
import { Logger } from '../../helpers/Logger';
|
||||
import { PostMessageData } from '../../models';
|
||||
|
||||
|
||||
@@ -2,10 +2,14 @@ import { Dashboard } from '../../commands/Dashboard';
|
||||
import { ExtensionState } from '../../constants';
|
||||
import { DashboardCommand } from '../../dashboardWebView/DashboardCommand';
|
||||
import { DashboardMessage } from '../../dashboardWebView/DashboardMessage';
|
||||
import { Extension, Notifications } from '../../helpers';
|
||||
import { Extension, Notifications, Settings } from '../../helpers';
|
||||
import { PostMessageData } from '../../models';
|
||||
import { PinnedItems } from '../../services';
|
||||
import { BaseListener } from './BaseListener';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../localization';
|
||||
import { Uri, commands } from 'vscode';
|
||||
import { existsAsync } from '../../utils';
|
||||
|
||||
export class DashboardListener extends BaseListener {
|
||||
/**
|
||||
@@ -27,6 +31,9 @@ export class DashboardListener extends BaseListener {
|
||||
case DashboardMessage.setPageViewType:
|
||||
Extension.getInstance().setState(ExtensionState.PagesView, msg.payload, 'workspace');
|
||||
break;
|
||||
case DashboardMessage.openConfig:
|
||||
this.openConfig();
|
||||
break;
|
||||
case DashboardMessage.showWarning:
|
||||
Notifications.warning(msg.payload);
|
||||
break;
|
||||
@@ -42,6 +49,21 @@ export class DashboardListener extends BaseListener {
|
||||
}
|
||||
}
|
||||
|
||||
private static async openConfig() {
|
||||
const answer = await Notifications.info(
|
||||
l10n.t(LocalizationKey.listenersDashboardDashboardListenerOpenConfigNotification),
|
||||
l10n.t(LocalizationKey.commonOpenSettings)
|
||||
);
|
||||
|
||||
if (answer && answer === l10n.t(LocalizationKey.commonOpenSettings)) {
|
||||
const configPath = await Settings.projectConfigPath();
|
||||
|
||||
if (configPath && (await existsAsync(configPath))) {
|
||||
commands.executeCommand('vscode.open', Uri.file(configPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pinned items
|
||||
* @param msg
|
||||
@@ -66,14 +88,22 @@ export class DashboardListener extends BaseListener {
|
||||
|
||||
const path = payload;
|
||||
if (!path) {
|
||||
this.sendError(command as any, requestId, 'No path provided.');
|
||||
this.sendError(
|
||||
command as any,
|
||||
requestId,
|
||||
l10n.t(LocalizationKey.listenersDashboardDashboardListenerPinItemNoPathError)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const allPinned = await PinnedItems.pin(path);
|
||||
|
||||
if (!allPinned) {
|
||||
this.sendError(command as any, requestId, 'Could not pin item.');
|
||||
this.sendError(
|
||||
command as any,
|
||||
requestId,
|
||||
l10n.t(LocalizationKey.listenersDashboardDashboardListenerPinItemCoundNotPinError)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,14 +122,22 @@ export class DashboardListener extends BaseListener {
|
||||
|
||||
const path = payload;
|
||||
if (!path) {
|
||||
this.sendError(command as any, requestId, 'No path provided.');
|
||||
this.sendError(
|
||||
command as any,
|
||||
requestId,
|
||||
l10n.t(LocalizationKey.listenersDashboardDashboardListenerPinItemNoPathError)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedPinned = await PinnedItems.remove(path);
|
||||
|
||||
if (!updatedPinned) {
|
||||
this.sendError(command as any, requestId, 'Could not unpin item.');
|
||||
this.sendError(
|
||||
command as any,
|
||||
requestId,
|
||||
l10n.t(LocalizationKey.listenersDashboardDashboardListenerPinItemCoundNotUnPinError)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,9 @@ export class SettingsListener extends BaseListener {
|
||||
await window.withProgress(
|
||||
{
|
||||
location: ProgressLocation.Notification,
|
||||
title: 'Downloading and initializing the template...',
|
||||
title: l10n.t(
|
||||
LocalizationKey.listenersDashboardSettingsListenerTriggerTemplateProgressTitle
|
||||
),
|
||||
cancellable: false
|
||||
},
|
||||
async (progress) => {
|
||||
@@ -209,7 +211,11 @@ export class SettingsListener extends BaseListener {
|
||||
const ghFolder = await download(template.url, wsFolder.fsPath);
|
||||
|
||||
if (!ghFolder.downloaded) {
|
||||
Notifications.error('Failed to download the template.');
|
||||
Notifications.error(
|
||||
l10n.t(
|
||||
LocalizationKey.listenersDashboardSettingsListenerTriggerTemplateDownloadError
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -225,7 +231,9 @@ export class SettingsListener extends BaseListener {
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
Notifications.error(`Failed to initialize the template.`);
|
||||
Notifications.error(
|
||||
l10n.t(LocalizationKey.listenersDashboardSettingsListenerTriggerTemplateInitError)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -7,6 +7,8 @@ import { Notifications, Settings, Telemetry } from '../../helpers';
|
||||
import { PostMessageData, Snippets } from '../../models';
|
||||
import { BaseListener } from './BaseListener';
|
||||
import { SettingsListener } from './SettingsListener';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../localization';
|
||||
|
||||
export class SnippetListener extends BaseListener {
|
||||
public static process(msg: PostMessageData) {
|
||||
@@ -30,13 +32,17 @@ export class SnippetListener extends BaseListener {
|
||||
const { title, description, body, fields, isMediaSnippet } = data;
|
||||
|
||||
if (!title || !body) {
|
||||
Notifications.warning('Snippet missing title or body');
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.listenersDashboardSnippetListenerAddSnippetMissingFieldsWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const snippets = Settings.get<any>(SETTING_CONTENT_SNIPPETS);
|
||||
if (snippets && snippets[title]) {
|
||||
Notifications.warning('Snippet with the same title already exists');
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.listenersDashboardSnippetListenerAddSnippetExistsWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,7 +69,9 @@ export class SnippetListener extends BaseListener {
|
||||
const { snippets } = data;
|
||||
|
||||
if (!snippets) {
|
||||
Notifications.warning('No snippets to update');
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.listenersDashboardSnippetListenerUpdateSnippetNoSnippetsWarning)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,15 @@ import { BaseListener } from './BaseListener';
|
||||
import { exec } from 'child_process';
|
||||
import { Extension, Logger, Settings } from '../../helpers';
|
||||
import { Folders } from '../../commands';
|
||||
import { SETTING_TAXONOMY_CONTENT_TYPES, SsgScripts } from '../../constants';
|
||||
import {
|
||||
DEFAULT_CONTENT_TYPE_NAME,
|
||||
SETTING_TAXONOMY_CONTENT_TYPES,
|
||||
SsgScripts
|
||||
} from '../../constants';
|
||||
import { SettingsListener } from './SettingsListener';
|
||||
import { Terminal } from '../../services';
|
||||
import { existsAsync, readFileAsync } from '../../utils';
|
||||
import { join } from 'path';
|
||||
|
||||
export class SsgListener extends BaseListener {
|
||||
/**
|
||||
@@ -57,7 +62,16 @@ export class SsgListener extends BaseListener {
|
||||
}
|
||||
}
|
||||
|
||||
const contentTypes = Settings.get<ContentType[]>(SETTING_TAXONOMY_CONTENT_TYPES) || [];
|
||||
// Set the preview image on the first found image of the content type
|
||||
const images = contentType.fields.filter((f) => f.type === 'image');
|
||||
if (images.length > 0) {
|
||||
images[0].isPreviewImage = true;
|
||||
}
|
||||
|
||||
let contentTypes = Settings.get<ContentType[]>(SETTING_TAXONOMY_CONTENT_TYPES) || [];
|
||||
|
||||
// Filter out the default content type
|
||||
contentTypes = contentTypes.filter((ct) => ct.name !== DEFAULT_CONTENT_TYPE_NAME);
|
||||
|
||||
if (contentTypes.find((ct) => ct.name === collection.name)) {
|
||||
SsgListener.sendRequest(command as any, requestId, {});
|
||||
@@ -133,7 +147,28 @@ export class SsgListener extends BaseListener {
|
||||
const tempLocation = Uri.joinPath(wsFolder, '/.frontmatter/temp');
|
||||
const tempScriptPath = Uri.joinPath(tempLocation, SsgScripts.astroContentCollectionScript);
|
||||
await workspace.fs.createDirectory(tempLocation);
|
||||
workspace.fs.copy(scriptPath, tempScriptPath, { overwrite: true });
|
||||
|
||||
// Check if the workspace uses pnpm
|
||||
if (await existsAsync(Uri.joinPath(wsFolder, 'node_modules/.pnpm').fsPath)) {
|
||||
const vitePackageFiles = await workspace.findFiles(
|
||||
`**/node_modules/.pnpm/vite@*/node_modules/vite/package.json`
|
||||
);
|
||||
if (vitePackageFiles.length > 0) {
|
||||
const vitePackageFile = vitePackageFiles[0];
|
||||
const vitePackage = JSON.parse(await readFileAsync(vitePackageFile.fsPath, 'utf8')) as {
|
||||
main: string;
|
||||
};
|
||||
const viteFolder = vitePackageFile.fsPath.replace('/package.json', '');
|
||||
const vitePath = join(viteFolder, vitePackage.main).replace(wsFolder.fsPath, '../..');
|
||||
|
||||
// Update the vite reference, as it is not a direct dependency of the project
|
||||
let scriptContents = await readFileAsync(scriptPath.fsPath, 'utf8');
|
||||
scriptContents = scriptContents.replace(`'vite'`, `'${vitePath}'`);
|
||||
await workspace.fs.writeFile(tempScriptPath, Buffer.from(scriptContents, 'utf8'));
|
||||
}
|
||||
} else {
|
||||
workspace.fs.copy(scriptPath, tempScriptPath, { overwrite: true });
|
||||
}
|
||||
|
||||
const fullScript = `node "${tempScriptPath.fsPath}" "${contentConfigFile.fsPath}"`;
|
||||
|
||||
@@ -187,16 +222,35 @@ export class SsgListener extends BaseListener {
|
||||
} as Field;
|
||||
break;
|
||||
case 'ZodBoolean':
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'boolean'
|
||||
} as Field;
|
||||
if (field.name === 'draft') {
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'draft'
|
||||
} as Field;
|
||||
} else {
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'boolean'
|
||||
} as Field;
|
||||
}
|
||||
break;
|
||||
case 'ZodArray':
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'list'
|
||||
} as Field;
|
||||
if (field.name === 'tags') {
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'tags'
|
||||
} as Field;
|
||||
} else if (field.name === 'categories') {
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'categories'
|
||||
} as Field;
|
||||
} else {
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'list'
|
||||
} as Field;
|
||||
}
|
||||
break;
|
||||
case 'ZodEnum':
|
||||
ctField = {
|
||||
@@ -205,12 +259,23 @@ export class SsgListener extends BaseListener {
|
||||
choices: field.options || []
|
||||
} as Field;
|
||||
break;
|
||||
case 'datetime':
|
||||
case 'ZodDate':
|
||||
ctField = {
|
||||
name: field.name,
|
||||
type: 'datetime',
|
||||
default: '{{now}}'
|
||||
} as Field;
|
||||
|
||||
if (field.name.toLowerCase() === 'published') {
|
||||
ctField.isPublishDate = true;
|
||||
} else if (
|
||||
field.name.toLowerCase() === 'modified' ||
|
||||
field.name.toLowerCase() === 'updated'
|
||||
) {
|
||||
ctField.isModifiedDate = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'image':
|
||||
ctField = {
|
||||
|
||||
@@ -28,6 +28,8 @@ import {
|
||||
import { Folders } from '../../commands/Folders';
|
||||
import { commands } from 'vscode';
|
||||
import { PostMessageData } from '../../models';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../localization';
|
||||
|
||||
export class GitListener {
|
||||
private static isRegistered: boolean = false;
|
||||
@@ -177,7 +179,9 @@ export class GitListener {
|
||||
}
|
||||
await subGit.push();
|
||||
} catch (e) {
|
||||
Notifications.error(`Failed to push submodules. Please check the logs for more details.`);
|
||||
Notifications.errorWithOutput(
|
||||
l10n.t(LocalizationKey.listenersGeneralGitListenerPushError)
|
||||
);
|
||||
Logger.error((e as Error).message);
|
||||
return;
|
||||
}
|
||||
@@ -203,7 +207,9 @@ export class GitListener {
|
||||
await git.subModule(['foreach', 'git', 'push']);
|
||||
}
|
||||
} catch (e) {
|
||||
Notifications.error(`Failed to push submodules. Please check the logs for more details.`);
|
||||
Notifications.errorWithOutput(
|
||||
l10n.t(LocalizationKey.listenersGeneralGitListenerPushError)
|
||||
);
|
||||
Logger.error((e as Error).message);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -19,11 +19,13 @@ import { Article, Preview } from '../../commands';
|
||||
import { ParsedFrontMatter } from '../../parsers';
|
||||
import { processKnownPlaceholders } from '../../helpers/PlaceholderHelper';
|
||||
import { Field, PostMessageData } from '../../models';
|
||||
import { encodeEmoji } from '../../utils';
|
||||
import { encodeEmoji, fieldWhenClause } from '../../utils';
|
||||
import { PanelProvider } from '../../panelWebView/PanelProvider';
|
||||
import { MessageHandlerData } from '@estruyf/vscode';
|
||||
import { SponsorAi } from '../../services/SponsorAI';
|
||||
import { Terminal } from '../../services';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../localization';
|
||||
|
||||
const FILE_LIMIT = 10;
|
||||
|
||||
@@ -94,7 +96,7 @@ export class DataListener extends BaseListener {
|
||||
panel.getWebview()?.postMessage({
|
||||
command,
|
||||
requestId,
|
||||
error: 'No active editor'
|
||||
error: l10n.t(LocalizationKey.listenersPanelDataListenerAiSuggestTaxonomyNoEditorError)
|
||||
} as MessageHandlerData<string>);
|
||||
return;
|
||||
}
|
||||
@@ -104,7 +106,7 @@ export class DataListener extends BaseListener {
|
||||
panel.getWebview()?.postMessage({
|
||||
command,
|
||||
requestId,
|
||||
error: 'No article data'
|
||||
error: l10n.t(LocalizationKey.listenersPanelDataListenerAiSuggestTaxonomyNoDataError)
|
||||
} as MessageHandlerData<string>);
|
||||
return;
|
||||
}
|
||||
@@ -126,7 +128,7 @@ export class DataListener extends BaseListener {
|
||||
panel.getWebview()?.postMessage({
|
||||
command,
|
||||
requestId,
|
||||
error: 'No article data'
|
||||
error: l10n.t(LocalizationKey.listenersPanelDataListenerAiSuggestTaxonomyNoDataError)
|
||||
} as MessageHandlerData<string>);
|
||||
return;
|
||||
}
|
||||
@@ -255,9 +257,18 @@ export class DataListener extends BaseListener {
|
||||
}
|
||||
|
||||
const contentType = ArticleHelper.getContentType(article);
|
||||
const sourceField = ContentType.findFieldByName(contentType.fields, field);
|
||||
|
||||
if (!value && field !== titleField && contentType.clearEmpty) {
|
||||
value = undefined;
|
||||
// Check if the draft or boolean field needs to be cleared
|
||||
// This is only required when the default value is not set to true
|
||||
if (sourceField && (sourceField.type === 'draft' || sourceField.type === 'boolean')) {
|
||||
if (!sourceField.default) {
|
||||
value = undefined;
|
||||
}
|
||||
} else {
|
||||
value = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const dateFields = ContentType.findFieldsByTypeDeep(contentType.fields, 'datetime');
|
||||
@@ -337,6 +348,29 @@ export class DataListener extends BaseListener {
|
||||
}
|
||||
}
|
||||
|
||||
// Verify if there are fields to be cleared due to the when clause
|
||||
const allFieldNames = Object.keys(parentObj);
|
||||
let ctFields = contentType.fields;
|
||||
if (parents && parents.length > 0) {
|
||||
for (const parent of parents) {
|
||||
const crntField = ctFields.find((f) => f.name === parent);
|
||||
if (crntField) {
|
||||
ctFields = crntField.fields || [];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ctFields && ctFields.length > 0) {
|
||||
for (const field of allFieldNames) {
|
||||
const crntField = ctFields.find((f) => f.name === field);
|
||||
if (crntField && crntField.when) {
|
||||
const renderField = fieldWhenClause(crntField, parentObj, ctFields);
|
||||
if (!renderField) {
|
||||
delete parentObj[field];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the field if it is empty
|
||||
if (
|
||||
value === undefined ||
|
||||
@@ -499,7 +533,11 @@ export class DataListener extends BaseListener {
|
||||
if (entries) {
|
||||
this.sendRequest(command, requestId, entries);
|
||||
} else {
|
||||
this.sendRequestError(command, requestId, "Couldn't find data file entries");
|
||||
this.sendRequestError(
|
||||
command,
|
||||
requestId,
|
||||
l10n.t(LocalizationKey.listenersPanelDataListenerGetDataFileEntriesNoDataFilesError)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
import { SponsorAi } from '../../services/SponsorAI';
|
||||
import { PanelProvider } from '../../panelWebView/PanelProvider';
|
||||
import { MessageHandlerData } from '@estruyf/vscode';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../localization';
|
||||
|
||||
export class TaxonomyListener extends BaseListener {
|
||||
/**
|
||||
@@ -80,7 +82,7 @@ export class TaxonomyListener extends BaseListener {
|
||||
panel.getWebview()?.postMessage({
|
||||
command,
|
||||
requestId,
|
||||
error: 'No active editor'
|
||||
error: l10n.t(LocalizationKey.listenersPanelTaxonomyListenerAiSuggestTaxonomyNoDataError)
|
||||
} as MessageHandlerData<string>);
|
||||
return;
|
||||
}
|
||||
@@ -90,7 +92,7 @@ export class TaxonomyListener extends BaseListener {
|
||||
panel.getWebview()?.postMessage({
|
||||
command,
|
||||
requestId,
|
||||
error: 'No article data'
|
||||
error: l10n.t(LocalizationKey.listenersPanelTaxonomyListenerAiSuggestTaxonomyNoEditorError)
|
||||
} as MessageHandlerData<string>);
|
||||
return;
|
||||
}
|
||||
@@ -115,7 +117,7 @@ export class TaxonomyListener extends BaseListener {
|
||||
panel.getWebview()?.postMessage({
|
||||
command,
|
||||
requestId,
|
||||
error: 'No article data'
|
||||
error: l10n.t(LocalizationKey.listenersPanelTaxonomyListenerAiSuggestTaxonomyNoDataError)
|
||||
} as MessageHandlerData<string>);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,6 +115,30 @@ export enum LocalizationKey {
|
||||
* No results
|
||||
*/
|
||||
commonNoResults = 'common.noResults',
|
||||
/**
|
||||
* Sorry, something went wrong.
|
||||
*/
|
||||
commonError = 'common.error',
|
||||
/**
|
||||
* yes
|
||||
*/
|
||||
commonYes = 'common.yes',
|
||||
/**
|
||||
* no
|
||||
*/
|
||||
commonNo = 'common.no',
|
||||
/**
|
||||
* Open settings
|
||||
*/
|
||||
commonOpenSettings = 'common.openSettings',
|
||||
/**
|
||||
* output window
|
||||
*/
|
||||
notificationsOutputChannelLink = 'notifications.outputChannel.link',
|
||||
/**
|
||||
* Check the {0} for more details.
|
||||
*/
|
||||
notificationsOutputChannelDescription = 'notifications.outputChannel.description',
|
||||
/**
|
||||
* Common
|
||||
*/
|
||||
@@ -891,6 +915,10 @@ export enum LocalizationKey {
|
||||
* Select a template to prefill the frontmatter.json file with the recommended settings.
|
||||
*/
|
||||
dashboardStepsStepsToGetStartedTemplateDescription = 'dashboard.steps.stepsToGetStarted.template.description',
|
||||
/**
|
||||
* Selecting a template applies a whole configuration to your project and closes this configuration view.
|
||||
*/
|
||||
dashboardStepsStepsToGetStartedTemplateWarning = 'dashboard.steps.stepsToGetStarted.template.warning',
|
||||
/**
|
||||
* Create Content-Types for your Astro Content Collections
|
||||
*/
|
||||
@@ -1032,7 +1060,7 @@ export enum LocalizationKey {
|
||||
*/
|
||||
dashboardConfigurationAstroAstroContentTypesEmpty = 'dashboard.configuration.astro.astroContentTypes.empty',
|
||||
/**
|
||||
* The following Astro Content Collections and can be used to generate a content-type.
|
||||
* The following Astro Content Collections can be used to generate a content-type.
|
||||
*/
|
||||
dashboardConfigurationAstroAstroContentTypesDescription = 'dashboard.configuration.astro.astroContentTypes.description',
|
||||
/**
|
||||
@@ -1452,8 +1480,852 @@ export enum LocalizationKey {
|
||||
* Continue in the media dashboard to select the image you want to insert.
|
||||
*/
|
||||
panelViewPanelMediaInsert = 'panel.viewPanel.mediaInsert',
|
||||
/**
|
||||
* No {0} configured.
|
||||
*/
|
||||
commandsArticleNotificationNoTaxonomy = 'commands.article.notification.noTaxonomy',
|
||||
/**
|
||||
* Select your {0} to insert.
|
||||
*/
|
||||
commandsArticleQuickPickPlaceholder = 'commands.article.quickPick.placeholder',
|
||||
/**
|
||||
* Something failed while parsing the date format. Check your "{0}" setting.
|
||||
*/
|
||||
commandsArticleSetDateError = 'commands.article.setDate.error',
|
||||
/**
|
||||
* Failed to rename file: {0}
|
||||
*/
|
||||
commandsArticleUpdateSlugError = 'commands.article.updateSlug.error',
|
||||
/**
|
||||
* Cache cleared
|
||||
*/
|
||||
commandsCacheCleared = 'commands.cache.cleared',
|
||||
/**
|
||||
* Ask me anything
|
||||
*/
|
||||
commandsChatbotTitle = 'commands.chatbot.title',
|
||||
/**
|
||||
* Create content by content type
|
||||
*/
|
||||
commandsContentOptionContentTypeLabel = 'commands.content.option.contentType.label',
|
||||
/**
|
||||
* Select if you want to create new content by the available content type(s)
|
||||
*/
|
||||
commandsContentOptionContentTypeDescription = 'commands.content.option.contentType.description',
|
||||
/**
|
||||
* Create content by template
|
||||
*/
|
||||
commandsContentOptionTemplateLabel = 'commands.content.option.template.label',
|
||||
/**
|
||||
* Select if you want to create new content by the available template(s)
|
||||
*/
|
||||
commandsContentOptionTemplateDescription = 'commands.content.option.template.description',
|
||||
/**
|
||||
* Create content
|
||||
*/
|
||||
commandsContentQuickPickTitle = 'commands.content.quickPick.title',
|
||||
/**
|
||||
* Select how you want to create your new content
|
||||
*/
|
||||
commandsContentQuickPickPlaceholder = 'commands.content.quickPick.placeholder',
|
||||
/**
|
||||
* Dashboard
|
||||
*/
|
||||
commandsDashboardTitle = 'commands.dashboard.title',
|
||||
/**
|
||||
* Add media folder
|
||||
*/
|
||||
commandsFoldersAddMediaFolderInputBoxTitle = 'commands.folders.addMediaFolder.inputBox.title',
|
||||
/**
|
||||
* Which name would you like to give to your folder (use "/" to create multi-level folders)?
|
||||
*/
|
||||
commandsFoldersAddMediaFolderInputBoxPrompt = 'commands.folders.addMediaFolder.inputBox.prompt',
|
||||
/**
|
||||
* No folder name was specified.
|
||||
*/
|
||||
commandsFoldersAddMediaFolderNoFolderWarning = 'commands.folders.addMediaFolder.noFolder.warning',
|
||||
/**
|
||||
* Folder is already registered
|
||||
*/
|
||||
commandsFoldersCreateFolderExistsWarning = 'commands.folders.create.folderExists.warning',
|
||||
/**
|
||||
* Register folder
|
||||
*/
|
||||
commandsFoldersCreateInputTitle = 'commands.folders.create.input.title',
|
||||
/**
|
||||
* Which name would you like to specify for this folder?
|
||||
*/
|
||||
commandsFoldersCreateInputPrompt = 'commands.folders.create.input.prompt',
|
||||
/**
|
||||
* Folder name
|
||||
*/
|
||||
commandsFoldersCreateInputPlaceholder = 'commands.folders.create.input.placeholder',
|
||||
/**
|
||||
* Folder registered
|
||||
*/
|
||||
commandsFoldersCreateSuccess = 'commands.folders.create.success',
|
||||
/**
|
||||
* Please select the main workspace folder for Front Matter to use.
|
||||
*/
|
||||
commandsFoldersGetWorkspaceFolderWorkspaceFolderPickPlaceholder = 'commands.folders.getWorkspaceFolder.workspaceFolderPick.placeholder',
|
||||
/**
|
||||
* Folder "{0}" does not exist. Please remove it from the settings.
|
||||
*/
|
||||
commandsFoldersGetNotificationErrorTitle = 'commands.folders.get.notificationError.title',
|
||||
/**
|
||||
* Remove folder
|
||||
*/
|
||||
commandsFoldersGetNotificationErrorRemoveAction = 'commands.folders.get.notificationError.remove.action',
|
||||
/**
|
||||
* Create folder
|
||||
*/
|
||||
commandsFoldersGetNotificationErrorCreateAction = 'commands.folders.get.notificationError.create.action',
|
||||
/**
|
||||
* Preview: {0}
|
||||
*/
|
||||
commandsPreviewPanelTitle = 'commands.preview.panel.title',
|
||||
/**
|
||||
* Select the folder of the article to preview
|
||||
*/
|
||||
commandsPreviewAskUserToPickFolderTitle = 'commands.preview.askUserToPickFolder.title',
|
||||
/**
|
||||
* Project initialized successfully.
|
||||
*/
|
||||
commandsProjectInitializeSuccess = 'commands.project.initialize.success',
|
||||
/**
|
||||
* To which project do you want to switch?
|
||||
*/
|
||||
commandsProjectSwitchProjectTitle = 'commands.project.switchProject.title',
|
||||
/**
|
||||
* Sample template created.
|
||||
*/
|
||||
commandsProjectCreateSampleTemplateInfo = 'commands.project.createSampleTemplate.info',
|
||||
/**
|
||||
* Insert the value of the {0} that you want to add to your configuration.
|
||||
*/
|
||||
commandsSettingsCreateInputPrompt = 'commands.settings.create.input.prompt',
|
||||
/**
|
||||
* Name of the {0}
|
||||
*/
|
||||
commandsSettingsCreateInputPlaceholder = 'commands.settings.create.input.placeholder',
|
||||
/**
|
||||
* The provided {0} already exists.
|
||||
*/
|
||||
commandsSettingsCreateWarning = 'commands.settings.create.warning',
|
||||
/**
|
||||
* Do you want to add the new {0} to the page?
|
||||
*/
|
||||
commandsSettingsCreateQuickPickPlaceholder = 'commands.settings.create.quickPick.placeholder',
|
||||
/**
|
||||
* {0}: exporting tags and categories
|
||||
*/
|
||||
commandsSettingsExportProgressTitle = 'commands.settings.export.progress.title',
|
||||
/**
|
||||
* Export completed. Tags: {0} - Categories: {1}.
|
||||
*/
|
||||
commandsSettingsExportProgressSuccess = 'commands.settings.export.progress.success',
|
||||
/**
|
||||
* Remap
|
||||
*/
|
||||
commandsSettingsRemapQuickpickTitle = 'commands.settings.remap.quickpick.title',
|
||||
/**
|
||||
* What do you want to remap?
|
||||
*/
|
||||
commandsSettingsRemapQuickpickPlaceholder = 'commands.settings.remap.quickpick.placeholder',
|
||||
/**
|
||||
* No {0} configured.
|
||||
*/
|
||||
commandsSettingsRemapNoTaxonomyWarning = 'commands.settings.remap.noTaxonomy.warning',
|
||||
/**
|
||||
* Select your {0} to insert.
|
||||
*/
|
||||
commandsSettingsRemapSelectTaxonomyPlaceholder = 'commands.settings.remap.selectTaxonomy.placeholder',
|
||||
/**
|
||||
* Specify the value of the {0} with which you want to remap "{1}". Leave the input <blank> if you want to remove the {0} from all articles.
|
||||
*/
|
||||
commandsSettingsRemapNewOptionInputPrompt = 'commands.settings.remap.newOption.input.prompt',
|
||||
/**
|
||||
* Name of the {0}
|
||||
*/
|
||||
commandsSettingsRemapNewOptionInputPlaceholder = 'commands.settings.remap.newOption.input.placeholder',
|
||||
/**
|
||||
* Delete {0} {1}?
|
||||
*/
|
||||
commandsSettingsRemapDeletePlaceholder = 'commands.settings.remap.delete.placeholder',
|
||||
/**
|
||||
* The {0} field is required. Please define a value for the field.
|
||||
*/
|
||||
commandsStatusListenerVerifyRequiredFieldsDiagnosticEmptyField = 'commands.statusListener.verifyRequiredFields.diagnostic.emptyField',
|
||||
/**
|
||||
* The following fields are required to contain a value: {0}
|
||||
*/
|
||||
commandsStatusListenerVerifyRequiredFieldsNotificationError = 'commands.statusListener.verifyRequiredFields.notification.error',
|
||||
/**
|
||||
* Template title
|
||||
*/
|
||||
commandsTemplateGenerateInputTitle = 'commands.template.generate.input.title',
|
||||
/**
|
||||
* Which name would you like to give your template?
|
||||
*/
|
||||
commandsTemplateGenerateInputPrompt = 'commands.template.generate.input.prompt',
|
||||
/**
|
||||
* article
|
||||
*/
|
||||
commandsTemplateGenerateInputPlaceholder = 'commands.template.generate.input.placeholder',
|
||||
/**
|
||||
* You did not specify a template title.
|
||||
*/
|
||||
commandsTemplateGenerateNoTitleWarning = 'commands.template.generate.noTitle.warning',
|
||||
/**
|
||||
* Keep content
|
||||
*/
|
||||
commandsTemplateGenerateKeepContentsTitle = 'commands.template.generate.keepContents.title',
|
||||
/**
|
||||
* Do you want to keep the contents for the template?
|
||||
*/
|
||||
commandsTemplateGenerateKeepContentsPlaceholder = 'commands.template.generate.keepContents.placeholder',
|
||||
/**
|
||||
* You did not pick any of the options for keeping the template its content.
|
||||
*/
|
||||
commandsTemplateGenerateKeepContentsNoOptionWarning = 'commands.template.generate.keepContents.noOption.warning',
|
||||
/**
|
||||
* Template created and is now available in your {0} folder.
|
||||
*/
|
||||
commandsTemplateGenerateKeepContentsSuccess = 'commands.template.generate.keepContents.success',
|
||||
/**
|
||||
* No templates found.
|
||||
*/
|
||||
commandsTemplateGetTemplatesWarning = 'commands.template.getTemplates.warning',
|
||||
/**
|
||||
* Incorrect project folder path retrieved.
|
||||
*/
|
||||
commandsTemplateCreateFolderPathWarning = 'commands.template.create.folderPath.warning',
|
||||
/**
|
||||
* No templates found.
|
||||
*/
|
||||
commandsTemplateCreateNoTemplatesWarning = 'commands.template.create.noTemplates.warning',
|
||||
/**
|
||||
* Select a template
|
||||
*/
|
||||
commandsTemplateCreateSelectTemplateTitle = 'commands.template.create.selectTemplate.title',
|
||||
/**
|
||||
* Select the content template to use
|
||||
*/
|
||||
commandsTemplateCreateSelectTemplatePlaceholder = 'commands.template.create.selectTemplate.placeholder',
|
||||
/**
|
||||
* No template selected.
|
||||
*/
|
||||
commandsTemplateCreateSelectTemplateNoTemplateWarning = 'commands.template.create.selectTemplate.noTemplate.warning',
|
||||
/**
|
||||
* Content template could not be found.
|
||||
*/
|
||||
commandsTemplateCreateSelectTemplateNotFoundWarning = 'commands.template.create.selectTemplate.notFound.warning',
|
||||
/**
|
||||
* Your new content is now available.
|
||||
*/
|
||||
commandsTemplateCreateSuccess = 'commands.template.create.success',
|
||||
/**
|
||||
* Unordered list
|
||||
*/
|
||||
commandsWysiwygCommandUnorderedListLabel = 'commands.wysiwyg.command.unorderedList.label',
|
||||
/**
|
||||
* Add an unordered list
|
||||
*/
|
||||
commandsWysiwygCommandUnorderedListDetail = 'commands.wysiwyg.command.unorderedList.detail',
|
||||
/**
|
||||
* Ordered list
|
||||
*/
|
||||
commandsWysiwygCommandOrderedListLabel = 'commands.wysiwyg.command.orderedList.label',
|
||||
/**
|
||||
* Add an ordered list
|
||||
*/
|
||||
commandsWysiwygCommandOrderedListDetail = 'commands.wysiwyg.command.orderedList.detail',
|
||||
/**
|
||||
* Task list
|
||||
*/
|
||||
commandsWysiwygCommandTaskListLabel = 'commands.wysiwyg.command.taskList.label',
|
||||
/**
|
||||
* Add a task list
|
||||
*/
|
||||
commandsWysiwygCommandTaskListDetail = 'commands.wysiwyg.command.taskList.detail',
|
||||
/**
|
||||
* Code
|
||||
*/
|
||||
commandsWysiwygCommandCodeLabel = 'commands.wysiwyg.command.code.label',
|
||||
/**
|
||||
* Add inline code snippet
|
||||
*/
|
||||
commandsWysiwygCommandCodeDetail = 'commands.wysiwyg.command.code.detail',
|
||||
/**
|
||||
* Code block
|
||||
*/
|
||||
commandsWysiwygCommandCodeblockLabel = 'commands.wysiwyg.command.codeblock.label',
|
||||
/**
|
||||
* Add a code block
|
||||
*/
|
||||
commandsWysiwygCommandCodeblockDetail = 'commands.wysiwyg.command.codeblock.detail',
|
||||
/**
|
||||
* Blockquote
|
||||
*/
|
||||
commandsWysiwygCommandBlockquoteLabel = 'commands.wysiwyg.command.blockquote.label',
|
||||
/**
|
||||
* Add a blockquote
|
||||
*/
|
||||
commandsWysiwygCommandBlockquoteDetail = 'commands.wysiwyg.command.blockquote.detail',
|
||||
/**
|
||||
* Strikethrough
|
||||
*/
|
||||
commandsWysiwygCommandStrikethroughLabel = 'commands.wysiwyg.command.strikethrough.label',
|
||||
/**
|
||||
* Add strikethrough text
|
||||
*/
|
||||
commandsWysiwygCommandStrikethroughDetail = 'commands.wysiwyg.command.strikethrough.detail',
|
||||
/**
|
||||
* WYSIWYG Options
|
||||
*/
|
||||
commandsWysiwygQuickPickTitle = 'commands.wysiwyg.quickPick.title',
|
||||
/**
|
||||
* Which type of markup would you like to insert?
|
||||
*/
|
||||
commandsWysiwygQuickPickPlaceholder = 'commands.wysiwyg.quickPick.placeholder',
|
||||
/**
|
||||
* WYSIWYG Hyperlink
|
||||
*/
|
||||
commandsWysiwygAddHyperlinkHyperlinkInputTitle = 'commands.wysiwyg.addHyperlink.hyperlinkInput.title',
|
||||
/**
|
||||
* Enter the URL
|
||||
*/
|
||||
commandsWysiwygAddHyperlinkHyperlinkInputPrompt = 'commands.wysiwyg.addHyperlink.hyperlinkInput.prompt',
|
||||
/**
|
||||
* WYSIWYG Text
|
||||
*/
|
||||
commandsWysiwygAddHyperlinkTextInputTitle = 'commands.wysiwyg.addHyperlink.textInput.title',
|
||||
/**
|
||||
* Enter the text for the hyperlink
|
||||
*/
|
||||
commandsWysiwygAddHyperlinkTextInputPrompt = 'commands.wysiwyg.addHyperlink.textInput.prompt',
|
||||
/**
|
||||
* Heading level
|
||||
*/
|
||||
commandsWysiwygInsertTextHeadingInputTitle = 'commands.wysiwyg.insertText.heading.input.title',
|
||||
/**
|
||||
* Which heading level do you want to insert?
|
||||
*/
|
||||
commandsWysiwygInsertTextHeadingInputPlaceholder = 'commands.wysiwyg.insertText.heading.input.placeholder',
|
||||
/**
|
||||
* A page bundle with the name {0} already exists in {1}.
|
||||
*/
|
||||
helpersArticleHelperCreateContentPageBundleError = 'helpers.articleHelper.createContent.pageBundle.error',
|
||||
/**
|
||||
* Content with the title already exists. Please specify a new title.
|
||||
*/
|
||||
helpersArticleHelperCreateContentContentExistsWarning = 'helpers.articleHelper.createContent.contentExists.warning',
|
||||
/**
|
||||
* Error while processing the {0} placeholder.
|
||||
*/
|
||||
helpersArticleHelperProcessCustomPlaceholdersPlaceholderError = 'helpers.articleHelper.processCustomPlaceholders.placeholder.error',
|
||||
/**
|
||||
* Error parsing the front matter of {0}.
|
||||
*/
|
||||
helpersArticleHelperParseFileDiagnosticError = 'helpers.articleHelper.parseFile.diagnostic.error',
|
||||
/**
|
||||
* No front matter data found to generate a content type.
|
||||
*/
|
||||
helpersContentTypeGenerateNoFrontMatterError = 'helpers.contentType.generate.noFrontMatter.error',
|
||||
/**
|
||||
* Override the default content type
|
||||
*/
|
||||
helpersContentTypeGenerateOverrideQuickPickTitle = 'helpers.contentType.generate.override.quickPick.title',
|
||||
/**
|
||||
* Do you want to overwrite the default content type configuration with the fields used in the current field?
|
||||
*/
|
||||
helpersContentTypeGenerateOverrideQuickPickPlaceholder = 'helpers.contentType.generate.override.quickPick.placeholder',
|
||||
/**
|
||||
* Generate Content Type
|
||||
*/
|
||||
helpersContentTypeGenerateContentTypeInputTitle = 'helpers.contentType.generate.contentTypeInput.title',
|
||||
/**
|
||||
* Enter the name of the content type to generate
|
||||
*/
|
||||
helpersContentTypeGenerateContentTypeInputPrompt = 'helpers.contentType.generate.contentTypeInput.prompt',
|
||||
/**
|
||||
* Please enter a name for the content type.
|
||||
*/
|
||||
helpersContentTypeGenerateContentTypeInputValidationEnterName = 'helpers.contentType.generate.contentTypeInput.validation.enterName',
|
||||
/**
|
||||
* A content type with this name already exists.
|
||||
*/
|
||||
helpersContentTypeGenerateContentTypeInputValidationNameExists = 'helpers.contentType.generate.contentTypeInput.validation.nameExists',
|
||||
/**
|
||||
* You didn't specify a name for the content type.
|
||||
*/
|
||||
helpersContentTypeGenerateNoContentTypeNameWarning = 'helpers.contentType.generate.noContentTypeName.warning',
|
||||
/**
|
||||
* Use as a page bundle
|
||||
*/
|
||||
helpersContentTypeGeneratePageBundleQuickPickTitle = 'helpers.contentType.generate.pageBundle.quickPick.title',
|
||||
/**
|
||||
* Do you want to use this content type as a page bundle?
|
||||
*/
|
||||
helpersContentTypeGeneratePageBundleQuickPickPlaceHolder = 'helpers.contentType.generate.pageBundle.quickPick.placeHolder',
|
||||
/**
|
||||
* Content type {0} has been updated.
|
||||
*/
|
||||
helpersContentTypeGenerateUpdatedSuccess = 'helpers.contentType.generate.updated.success',
|
||||
/**
|
||||
* Content type {0} has been generated.
|
||||
*/
|
||||
helpersContentTypeGenerateGeneratedSuccess = 'helpers.contentType.generate.generated.success',
|
||||
/**
|
||||
* No front matter data found to add missing fields.
|
||||
*/
|
||||
helpersContentTypeAddMissingFieldsNoFrontMatterWarning = 'helpers.contentType.addMissingFields.noFrontMatter.warning',
|
||||
/**
|
||||
* Content type {0} has been updated.
|
||||
*/
|
||||
helpersContentTypeAddMissingFieldsUpdatedSuccess = 'helpers.contentType.addMissingFields.updated.success',
|
||||
/**
|
||||
* No front matter data found to set the content type.
|
||||
*/
|
||||
helpersContentTypeSetContentTypeNoFrontMatterWarning = 'helpers.contentType.setContentType.noFrontMatter.warning',
|
||||
/**
|
||||
* Select the content type
|
||||
*/
|
||||
helpersContentTypeSetContentTypeQuickPickTitle = 'helpers.contentType.setContentType.quickPick.title',
|
||||
/**
|
||||
* Which content type would you like to use?
|
||||
*/
|
||||
helpersContentTypeSetContentTypeQuickPickPlaceholder = 'helpers.contentType.setContentType.quickPick.placeholder',
|
||||
/**
|
||||
* Do you want to create it as sub-content?
|
||||
*/
|
||||
helpersContentTypeCreateAllowSubContentTitle = 'helpers.contentType.create.allowSubContent.title',
|
||||
/**
|
||||
* Do you want to create it as sub-content?
|
||||
*/
|
||||
helpersContentTypeCreateAllowSubContentPlaceHolder = 'helpers.contentType.create.allowSubContent.placeHolder',
|
||||
/**
|
||||
* Select folder
|
||||
*/
|
||||
helpersContentTypeCreateAllowSubContentShowOpenDialogOpenLabel = 'helpers.contentType.create.allowSubContent.showOpenDialog.openLabel',
|
||||
/**
|
||||
* Select folder to create the content
|
||||
*/
|
||||
helpersContentTypeCreateAllowSubContentShowOpenDialogTitle = 'helpers.contentType.create.allowSubContent.showOpenDialog.title',
|
||||
/**
|
||||
* Create as a page bundle?
|
||||
*/
|
||||
helpersContentTypeCreatePageBundleTitle = 'helpers.contentType.create.pageBundle.title',
|
||||
/**
|
||||
* Do you want to create the sub-content as a page bundle?
|
||||
*/
|
||||
helpersContentTypeCreatePageBundlePlaceHolder = 'helpers.contentType.create.pageBundle.placeHolder',
|
||||
/**
|
||||
* {0}: Creating content...
|
||||
*/
|
||||
helpersContentTypeCreateProgressTitle = 'helpers.contentType.create.progress.title',
|
||||
/**
|
||||
* Your new content has been created.
|
||||
*/
|
||||
helpersContentTypeCreateSuccess = 'helpers.contentType.create.success',
|
||||
/**
|
||||
* The content type actions are not available in this mode.
|
||||
*/
|
||||
helpersContentTypeVerifyWarning = 'helpers.contentType.verify.warning',
|
||||
/**
|
||||
* Executing: {0}
|
||||
*/
|
||||
helpersCustomScriptExecuting = 'helpers.customScript.executing',
|
||||
/**
|
||||
* {0}: Article couldn't be retrieved.
|
||||
*/
|
||||
helpersCustomScriptSingleRunArticleWarning = 'helpers.customScript.singleRun.article.warning',
|
||||
/**
|
||||
* {0}: No files found
|
||||
*/
|
||||
helpersCustomScriptBulkRunNoFilesWarning = 'helpers.customScript.bulkRun.noFiles.warning',
|
||||
/**
|
||||
* {0}: There was no folder or media path specified.
|
||||
*/
|
||||
helpersCustomScriptRunMediaScriptNoFolderWarning = 'helpers.customScript.runMediaScript.noFolder.warning',
|
||||
/**
|
||||
* {0}: front matter updated.
|
||||
*/
|
||||
helpersCustomScriptShowOutputFrontMatterSuccess = 'helpers.customScript.showOutput.frontMatter.success',
|
||||
/**
|
||||
* Copy output
|
||||
*/
|
||||
helpersCustomScriptShowOutputCopyOutputAction = 'helpers.customScript.showOutput.copyOutput.action',
|
||||
/**
|
||||
* {0}: Executed your custom script.
|
||||
*/
|
||||
helpersCustomScriptShowOutputSuccess = 'helpers.customScript.showOutput.success',
|
||||
/**
|
||||
* Invalid command: {0}
|
||||
*/
|
||||
helpersCustomScriptValidateCommandError = 'helpers.customScript.validateCommand.error',
|
||||
/**
|
||||
* Something went wrong while processing the data file.
|
||||
*/
|
||||
helpersDataFileHelperProcessError = 'helpers.dataFileHelper.process.error',
|
||||
/**
|
||||
* Check the changelog
|
||||
*/
|
||||
helpersExtensionGetVersionChangelog = 'helpers.extension.getVersion.changelog',
|
||||
/**
|
||||
* Give it a ⭐️
|
||||
*/
|
||||
helpersExtensionGetVersionStarIt = 'helpers.extension.getVersion.starIt',
|
||||
/**
|
||||
* {0} has been updated to v{1} — check out what's new!
|
||||
*/
|
||||
helpersExtensionGetVersionUpdateNotification = 'helpers.extension.getVersion.update.notification',
|
||||
/**
|
||||
* The "{0}" and "{1}" settings have been deprecated. Please use the "isPublishDate" and "isModifiedDate" datetime field properties instead.
|
||||
*/
|
||||
helpersExtensionMigrateSettingsDeprecatedWarning = 'helpers.extension.migrateSettings.deprecated.warning',
|
||||
/**
|
||||
* Hide
|
||||
*/
|
||||
helpersExtensionMigrateSettingsDeprecatedWarningHide = 'helpers.extension.migrateSettings.deprecated.warning.hide',
|
||||
/**
|
||||
* See migration guide
|
||||
*/
|
||||
helpersExtensionMigrateSettingsDeprecatedWarningSeeGuide = 'helpers.extension.migrateSettings.deprecated.warning.seeGuide',
|
||||
/**
|
||||
* {0} - Templates
|
||||
*/
|
||||
helpersExtensionMigrateSettingsTemplatesQuickPickTitle = 'helpers.extension.migrateSettings.templates.quickPick.title',
|
||||
/**
|
||||
* Do you want to keep on using the template functionality?
|
||||
*/
|
||||
helpersExtensionMigrateSettingsTemplatesQuickPickPlaceholder = 'helpers.extension.migrateSettings.templates.quickPick.placeholder',
|
||||
/**
|
||||
* Front Matter BETA cannot be used while the stable version is installed. Please ensure that you have only over version installed.
|
||||
*/
|
||||
helpersExtensionCheckIfExtensionCanRunWarning = 'helpers.extension.checkIfExtensionCanRun.warning',
|
||||
/**
|
||||
* We couldn't find your selected folder.
|
||||
*/
|
||||
helpersMediaHelperSaveFileFolderError = 'helpers.mediaHelper.saveFile.folder.error',
|
||||
/**
|
||||
* File {0} uploaded to: {1}
|
||||
*/
|
||||
helpersMediaHelperSaveFileFileUploadedSuccess = 'helpers.mediaHelper.saveFile.file.uploaded.success',
|
||||
/**
|
||||
* Sorry, something went wrong uploading {0}
|
||||
*/
|
||||
helpersMediaHelperSaveFileFileUploadedFailed = 'helpers.mediaHelper.saveFile.file.uploaded.failed',
|
||||
/**
|
||||
* Sorry, something went wrong deleting {0}
|
||||
*/
|
||||
helpersMediaHelperDeleteFileFileDeletionFailed = 'helpers.mediaHelper.deleteFile.file.deletion.failed',
|
||||
/**
|
||||
* The name "{0}" already exists at the file location.
|
||||
*/
|
||||
helpersMediaLibraryRemoveWarning = 'helpers.mediaLibrary.remove.warning',
|
||||
/**
|
||||
* Sorry, something went wrong updating "{0}" to "{1}".
|
||||
*/
|
||||
helpersMediaLibraryRemoveError = 'helpers.mediaLibrary.remove.error',
|
||||
/**
|
||||
* Couldn't open the file.
|
||||
*/
|
||||
helpersOpenFileInEditorError = 'helpers.openFileInEditor.error',
|
||||
/**
|
||||
* Title or description
|
||||
*/
|
||||
helpersQuestionsContentTitleAiInputTitle = 'helpers.questions.contentTitle.aiInput.title',
|
||||
/**
|
||||
* What would you like to write about?
|
||||
*/
|
||||
helpersQuestionsContentTitleAiInputPrompt = 'helpers.questions.contentTitle.aiInput.prompt',
|
||||
/**
|
||||
* What would you like to write about?
|
||||
*/
|
||||
helpersQuestionsContentTitleAiInputPlaceholder = 'helpers.questions.contentTitle.aiInput.placeholder',
|
||||
/**
|
||||
* your title/description
|
||||
*/
|
||||
helpersQuestionsContentTitleAiInputQuickPickTitleSeparator = 'helpers.questions.contentTitle.aiInput.quickPick.title.separator',
|
||||
/**
|
||||
* AI generated title
|
||||
*/
|
||||
helpersQuestionsContentTitleAiInputQuickPickAiSeparator = 'helpers.questions.contentTitle.aiInput.quickPick.ai.separator',
|
||||
/**
|
||||
* Select a title
|
||||
*/
|
||||
helpersQuestionsContentTitleAiInputSelectTitle = 'helpers.questions.contentTitle.aiInput.select.title',
|
||||
/**
|
||||
* Select a title for your content
|
||||
*/
|
||||
helpersQuestionsContentTitleAiInputSelectPlaceholder = 'helpers.questions.contentTitle.aiInput.select.placeholder',
|
||||
/**
|
||||
* Failed fetching the AI title. Please try to use your own title or try again later.
|
||||
*/
|
||||
helpersQuestionsContentTitleAiInputFailed = 'helpers.questions.contentTitle.aiInput.failed',
|
||||
/**
|
||||
* You did not specify a title for your content.
|
||||
*/
|
||||
helpersQuestionsContentTitleAiInputWarning = 'helpers.questions.contentTitle.aiInput.warning',
|
||||
/**
|
||||
* Content title
|
||||
*/
|
||||
helpersQuestionsContentTitleTitleInputTitle = 'helpers.questions.contentTitle.titleInput.title',
|
||||
/**
|
||||
* What would you like to use as a title for the content to create?
|
||||
*/
|
||||
helpersQuestionsContentTitleTitleInputPrompt = 'helpers.questions.contentTitle.titleInput.prompt',
|
||||
/**
|
||||
* Content title
|
||||
*/
|
||||
helpersQuestionsContentTitleTitleInputPlaceholder = 'helpers.questions.contentTitle.titleInput.placeholder',
|
||||
/**
|
||||
* You did not specify a title for your content.
|
||||
*/
|
||||
helpersQuestionsContentTitleTitleInputWarning = 'helpers.questions.contentTitle.titleInput.warning',
|
||||
/**
|
||||
* Select a folder
|
||||
*/
|
||||
helpersQuestionsSelectContentFolderQuickPickTitle = 'helpers.questions.selectContentFolder.quickPick.title',
|
||||
/**
|
||||
* Select where you want to create your content
|
||||
*/
|
||||
helpersQuestionsSelectContentFolderQuickPickPlaceholder = 'helpers.questions.selectContentFolder.quickPick.placeholder',
|
||||
/**
|
||||
* No page folders were configured.
|
||||
*/
|
||||
helpersQuestionsSelectContentFolderQuickPickNoFoldersWarning = 'helpers.questions.selectContentFolder.quickPick.noFolders.warning',
|
||||
/**
|
||||
* You didn't select a place where you wanted to create your content.
|
||||
*/
|
||||
helpersQuestionsSelectContentFolderQuickPickNoSelectionWarning = 'helpers.questions.selectContentFolder.quickPick.noSelection.warning',
|
||||
/**
|
||||
* No content types found. Please create a content type first.
|
||||
*/
|
||||
helpersQuestionsSelectContentTypeNoContentTypeWarning = 'helpers.questions.selectContentType.noContentType.warning',
|
||||
/**
|
||||
* Content type
|
||||
*/
|
||||
helpersQuestionsSelectContentTypeQuickPickTitle = 'helpers.questions.selectContentType.quickPick.title',
|
||||
/**
|
||||
* Select the content type to create your new content
|
||||
*/
|
||||
helpersQuestionsSelectContentTypeQuickPickPlaceholder = 'helpers.questions.selectContentType.quickPick.placeholder',
|
||||
/**
|
||||
* No content type was selected.
|
||||
*/
|
||||
helpersQuestionsSelectContentTypeNoSelectionWarning = 'helpers.questions.selectContentType.noSelection.warning',
|
||||
/**
|
||||
* Article {0} is longer than {1} characters (current length: {2}). For SEO reasons, it would be better to make it less than {1} characters.
|
||||
*/
|
||||
helpersSeoHelperCheckLengthDiagnosticMessage = 'helpers.seoHelper.checkLength.diagnostic.message',
|
||||
/**
|
||||
* You have local settings. Would you like to promote them to the global settings ("frontmatter.json")?
|
||||
*/
|
||||
helpersSettingsHelperCheckToPromoteMessage = 'helpers.settingsHelper.checkToPromote.message',
|
||||
/**
|
||||
* All settings promoted to team level.
|
||||
*/
|
||||
helpersSettingsHelperPromoteSuccess = 'helpers.settingsHelper.promote.success',
|
||||
/**
|
||||
* {0}: Reading dynamic config file...
|
||||
*/
|
||||
helpersSettingsHelperReadConfigProgressTitle = 'helpers.settingsHelper.readConfig.progress.title',
|
||||
/**
|
||||
* Error reading your configuration.
|
||||
*/
|
||||
helpersSettingsHelperReadConfigError = 'helpers.settingsHelper.readConfig.error',
|
||||
/**
|
||||
* Settings have been refreshed.
|
||||
*/
|
||||
helpersSettingsHelperRefreshConfigSuccess = 'helpers.settingsHelper.refreshConfig.success',
|
||||
/**
|
||||
* Rename the {0}
|
||||
*/
|
||||
helpersTaxonomyHelperRenameInputTitle = 'helpers.taxonomyHelper.rename.input.title',
|
||||
/**
|
||||
* The new value must be different from the old one.
|
||||
*/
|
||||
helpersTaxonomyHelperRenameValidateEqualValue = 'helpers.taxonomyHelper.rename.validate.equalValue',
|
||||
/**
|
||||
* A new value must be provided.
|
||||
*/
|
||||
helpersTaxonomyHelperRenameValidateNoValue = 'helpers.taxonomyHelper.rename.validate.noValue',
|
||||
/**
|
||||
* Merge the "{0}" with another {1} value
|
||||
*/
|
||||
helpersTaxonomyHelperMergeQuickPickTitle = 'helpers.taxonomyHelper.merge.quickPick.title',
|
||||
/**
|
||||
* Select the {0} value to merge with
|
||||
*/
|
||||
helpersTaxonomyHelperMergeQuickPickPlaceholder = 'helpers.taxonomyHelper.merge.quickPick.placeholder',
|
||||
/**
|
||||
* Delete the "{0}" {1} value
|
||||
*/
|
||||
helpersTaxonomyHelperDeleteQuickPickTitle = 'helpers.taxonomyHelper.delete.quickPick.title',
|
||||
/**
|
||||
* Are you sure you want to delete the "{0}" {1} value?
|
||||
*/
|
||||
helpersTaxonomyHelperDeleteQuickPickPlaceholder = 'helpers.taxonomyHelper.delete.quickPick.placeholder',
|
||||
/**
|
||||
* Create a new {0} value
|
||||
*/
|
||||
helpersTaxonomyHelperCreateNewInputTitle = 'helpers.taxonomyHelper.createNew.input.title',
|
||||
/**
|
||||
* Enter the value you want to add
|
||||
*/
|
||||
helpersTaxonomyHelperCreateNewInputPlaceholder = 'helpers.taxonomyHelper.createNew.input.placeholder',
|
||||
/**
|
||||
* A value must be provided.
|
||||
*/
|
||||
helpersTaxonomyHelperCreateNewInputValidateNoValue = 'helpers.taxonomyHelper.createNew.input.validate.noValue',
|
||||
/**
|
||||
* The value already exists.
|
||||
*/
|
||||
helpersTaxonomyHelperCreateNewInputValidateExists = 'helpers.taxonomyHelper.createNew.input.validate.exists',
|
||||
/**
|
||||
* {0}: Renaming "{1}" from {2} to {3}.
|
||||
*/
|
||||
helpersTaxonomyHelperProcessEdit = 'helpers.taxonomyHelper.process.edit',
|
||||
/**
|
||||
* {0}: Merging "{1}" from {2} to {3}.
|
||||
*/
|
||||
helpersTaxonomyHelperProcessMerge = 'helpers.taxonomyHelper.process.merge',
|
||||
/**
|
||||
* {0}: Deleting "{1}" from {2}.
|
||||
*/
|
||||
helpersTaxonomyHelperProcessDelete = 'helpers.taxonomyHelper.process.delete',
|
||||
/**
|
||||
* Edit completed.
|
||||
*/
|
||||
helpersTaxonomyHelperProcessEditSuccess = 'helpers.taxonomyHelper.process.edit.success',
|
||||
/**
|
||||
* Merge completed.
|
||||
*/
|
||||
helpersTaxonomyHelperProcessMergeSuccess = 'helpers.taxonomyHelper.process.merge.success',
|
||||
/**
|
||||
* Deletion completed.
|
||||
*/
|
||||
helpersTaxonomyHelperProcessDeleteSuccess = 'helpers.taxonomyHelper.process.delete.success',
|
||||
/**
|
||||
* Move the "{0}" to another type
|
||||
*/
|
||||
helpersTaxonomyHelperMoveQuickPickTitle = 'helpers.taxonomyHelper.move.quickPick.title',
|
||||
/**
|
||||
* Select the type to move to
|
||||
*/
|
||||
helpersTaxonomyHelperMoveQuickPickPlaceholder = 'helpers.taxonomyHelper.move.quickPick.placeholder',
|
||||
/**
|
||||
* {0}: Moving "{1}" from {2} to "${3}".
|
||||
*/
|
||||
helpersTaxonomyHelperMoveProgressTitle = 'helpers.taxonomyHelper.move.progress.title',
|
||||
/**
|
||||
* Move completed.
|
||||
*/
|
||||
helpersTaxonomyHelperMoveSuccess = 'helpers.taxonomyHelper.move.success',
|
||||
/**
|
||||
* Open the "frontmatter.json" file if you want to review the configuration.
|
||||
*/
|
||||
listenersDashboardDashboardListenerOpenConfigNotification = 'listeners.dashboard.dashboardListener.openConfig.notification',
|
||||
/**
|
||||
* No path provided.
|
||||
*/
|
||||
listenersDashboardDashboardListenerPinItemNoPathError = 'listeners.dashboard.dashboardListener.pinItem.noPath.error',
|
||||
/**
|
||||
* Could not pin item.
|
||||
*/
|
||||
listenersDashboardDashboardListenerPinItemCoundNotPinError = 'listeners.dashboard.dashboardListener.pinItem.coundNotPin.error',
|
||||
/**
|
||||
* Could not unpin item.
|
||||
*/
|
||||
listenersDashboardDashboardListenerPinItemCoundNotUnPinError = 'listeners.dashboard.dashboardListener.pinItem.coundNotUnPin.error',
|
||||
/**
|
||||
* Template files copied.
|
||||
*/
|
||||
listenersDashboardSettingsListenerTriggerTemplateNotification = 'listeners.dashboard.settingsListener.triggerTemplate.notification'
|
||||
listenersDashboardSettingsListenerTriggerTemplateNotification = 'listeners.dashboard.settingsListener.triggerTemplate.notification',
|
||||
/**
|
||||
* Downloading and initializing the template...
|
||||
*/
|
||||
listenersDashboardSettingsListenerTriggerTemplateProgressTitle = 'listeners.dashboard.settingsListener.triggerTemplate.progress.title',
|
||||
/**
|
||||
* Failed to download the template.
|
||||
*/
|
||||
listenersDashboardSettingsListenerTriggerTemplateDownloadError = 'listeners.dashboard.settingsListener.triggerTemplate.download.error',
|
||||
/**
|
||||
* Failed to initialize the template.
|
||||
*/
|
||||
listenersDashboardSettingsListenerTriggerTemplateInitError = 'listeners.dashboard.settingsListener.triggerTemplate.init.error',
|
||||
/**
|
||||
* Snippet missing title or body
|
||||
*/
|
||||
listenersDashboardSnippetListenerAddSnippetMissingFieldsWarning = 'listeners.dashboard.snippetListener.addSnippet.missingFields.warning',
|
||||
/**
|
||||
* Snippet with the same title already exists
|
||||
*/
|
||||
listenersDashboardSnippetListenerAddSnippetExistsWarning = 'listeners.dashboard.snippetListener.addSnippet.exists.warning',
|
||||
/**
|
||||
* No snippets to update
|
||||
*/
|
||||
listenersDashboardSnippetListenerUpdateSnippetNoSnippetsWarning = 'listeners.dashboard.snippetListener.updateSnippet.noSnippets.warning',
|
||||
/**
|
||||
* Failed to push submodules.
|
||||
*/
|
||||
listenersGeneralGitListenerPushError = 'listeners.general.gitListener.push.error',
|
||||
/**
|
||||
* No active editor
|
||||
*/
|
||||
listenersPanelDataListenerAiSuggestTaxonomyNoEditorError = 'listeners.panel.dataListener.aiSuggestTaxonomy.noEditor.error',
|
||||
/**
|
||||
* No article data
|
||||
*/
|
||||
listenersPanelDataListenerAiSuggestTaxonomyNoDataError = 'listeners.panel.dataListener.aiSuggestTaxonomy.noData.error',
|
||||
/**
|
||||
* Couldn't find data file entries
|
||||
*/
|
||||
listenersPanelDataListenerGetDataFileEntriesNoDataFilesError = 'listeners.panel.dataListener.getDataFileEntries.noDataFiles.error',
|
||||
/**
|
||||
* No active editor
|
||||
*/
|
||||
listenersPanelTaxonomyListenerAiSuggestTaxonomyNoEditorError = 'listeners.panel.taxonomyListener.aiSuggestTaxonomy.noEditor.error',
|
||||
/**
|
||||
* No article data
|
||||
*/
|
||||
listenersPanelTaxonomyListenerAiSuggestTaxonomyNoDataError = 'listeners.panel.taxonomyListener.aiSuggestTaxonomy.noData.error',
|
||||
/**
|
||||
* Select the mode you want to use
|
||||
*/
|
||||
servicesModeSwitchSwitchModeQuickPickPlaceholder = 'services.modeSwitch.switchMode.quickPick.placeholder',
|
||||
/**
|
||||
* {0}: Mode selection
|
||||
*/
|
||||
servicesModeSwitchSwitchModeQuickPickTitle = 'services.modeSwitch.switchMode.quickPick.title',
|
||||
/**
|
||||
* Mode: {0}
|
||||
*/
|
||||
servicesModeSwitchSetTextMode = 'services.modeSwitch.setText.mode',
|
||||
/**
|
||||
* Processing...
|
||||
*/
|
||||
servicesPagesParserParsePagesStatusBarText = 'services.pagesParser.parsePages.statusBar.text',
|
||||
/**
|
||||
* File error: {0}
|
||||
*/
|
||||
servicesPagesParserParsePagesFileError = 'services.pagesParser.parsePages.file.error',
|
||||
/**
|
||||
* The AI title generation took too long. Please try again later.
|
||||
*/
|
||||
servicesSponsorAiGetTitlesWarning = 'services.sponsorAi.getTitles.warning',
|
||||
/**
|
||||
* The AI description generation took too long. Please try again later.
|
||||
*/
|
||||
servicesSponsorAiGetDescriptionWarning = 'services.sponsorAi.getDescription.warning',
|
||||
/**
|
||||
* The AI taxonomy generation took too long. Please try again later.
|
||||
*/
|
||||
servicesSponsorAiGetTaxonomySuggestionsWarning = 'services.sponsorAi.getTaxonomySuggestions.warning',
|
||||
/**
|
||||
* Starting local server
|
||||
*/
|
||||
servicesTerminalOpenLocalServerTerminalTerminalOptionMessage = 'services.terminal.openLocalServerTerminal.terminalOption.message'
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface AstroField {
|
||||
| 'ZodEnum'
|
||||
| 'ZodDate'
|
||||
| 'ZodObject'
|
||||
| 'datetime'
|
||||
| 'email'
|
||||
| 'url'
|
||||
| 'image';
|
||||
|
||||
@@ -65,6 +65,8 @@ export interface ContentType {
|
||||
postScript?: string;
|
||||
filePrefix?: string;
|
||||
clearEmpty?: boolean;
|
||||
isSubContent?: boolean;
|
||||
allowAsSubContent?: boolean;
|
||||
}
|
||||
|
||||
export type FieldType =
|
||||
|
||||
@@ -114,7 +114,7 @@ const Actions: React.FunctionComponent<IActionsProps> = ({
|
||||
|
||||
{customActions?.length > 0 && (
|
||||
<>
|
||||
{actions?.length > 0 && <div className="divider py-4 w-full" style={{ height: `1px` }}></div>}
|
||||
{actions?.length > 0 && <div className="divider w-full" style={{ height: `1px` }}></div>}
|
||||
|
||||
{...customActions}
|
||||
</>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import * as React from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { DateHelper } from '../../../helpers/DateHelper';
|
||||
import { BlockFieldData, CustomPanelViewResult, Field, PanelSettings, WhenOperator } from '../../../models';
|
||||
import { BlockFieldData, CustomPanelViewResult, Field, PanelSettings } from '../../../models';
|
||||
import { Command } from '../../Command';
|
||||
import { CommandToCode } from '../../CommandToCode';
|
||||
import { TagType } from '../../TagType';
|
||||
@@ -36,6 +36,7 @@ import { LocalizationKey } from '../../../localization';
|
||||
|
||||
export interface IWrapperFieldProps {
|
||||
field: Field;
|
||||
allFields: Field[];
|
||||
parent: IMetadata;
|
||||
parentFields: string[];
|
||||
metadata: IMetadata;
|
||||
@@ -57,6 +58,7 @@ export interface IWrapperFieldProps {
|
||||
|
||||
export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
field,
|
||||
allFields,
|
||||
parent,
|
||||
parentFields,
|
||||
metadata,
|
||||
@@ -158,7 +160,7 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
|
||||
// Conditional fields
|
||||
if (typeof field.when !== 'undefined') {
|
||||
const shouldRender = fieldWhenClause(field, parent);
|
||||
const shouldRender = fieldWhenClause(field, parent, allFields);
|
||||
|
||||
if (!shouldRender) {
|
||||
return null;
|
||||
|
||||
@@ -74,6 +74,7 @@ const Metadata: React.FunctionComponent<IMetadataProps> = ({
|
||||
<WrapperField
|
||||
key={field.name}
|
||||
field={field}
|
||||
allFields={ctFields}
|
||||
parent={parent}
|
||||
parentFields={parentFields}
|
||||
metadata={metadata}
|
||||
|
||||
@@ -158,7 +158,8 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
value = item;
|
||||
}
|
||||
|
||||
const uniqValues = Array.from(new Set([...selected, value]));
|
||||
const safeSelected = selected instanceof Array ? selected : [];
|
||||
const uniqValues = Array.from(new Set([...safeSelected, value]));
|
||||
setSelected(uniqValues);
|
||||
sendUpdate(uniqValues);
|
||||
setInputValue('');
|
||||
@@ -181,15 +182,19 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
* @param option
|
||||
* @param inputValue
|
||||
*/
|
||||
const filterList = (option: string, inputValue: string | null) => {
|
||||
const filterList = useCallback((option: string, inputValue: string | null) => {
|
||||
if (typeof option !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(selected instanceof Array)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (
|
||||
option && !selected.includes(option) && option.toLowerCase().includes((inputValue || '').toLowerCase())
|
||||
);
|
||||
};
|
||||
}, [selected]);
|
||||
|
||||
/**
|
||||
* Add the new item to the data
|
||||
@@ -295,12 +300,18 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
}, [settings?.aiEnabled, label, type]);
|
||||
|
||||
const sortedSelectedTags = useMemo(() => {
|
||||
return (selected || []).sort((a: string, b: string) => {
|
||||
const aString = typeof a === 'string' ? a : `${a}`;
|
||||
const bString = typeof b === 'string' ? b : `${b}`;
|
||||
const safeSelected = selected || [];
|
||||
|
||||
return aString?.toLowerCase() < bString?.toLowerCase() ? -1 : 1;
|
||||
});
|
||||
if (safeSelected instanceof Array && safeSelected.length > 0) {
|
||||
return (selected || []).sort((a: string, b: string) => {
|
||||
const aString = typeof a === 'string' ? a : `${a}`;
|
||||
const bString = typeof b === 'string' ? b : `${b}`;
|
||||
|
||||
return aString?.toLowerCase() < bString?.toLowerCase() ? -1 : 1;
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}, [selected]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as yaml from 'yaml';
|
||||
import * as toml from '@iarna/toml';
|
||||
import { Format, FrontMatterParser } from '.';
|
||||
import { SETTING_QUOTE_STRINGS } from '../constants';
|
||||
import { Settings } from '../helpers';
|
||||
|
||||
export const getFormatOpts = (format: string): Format => {
|
||||
const formats: { [prop: string]: Format } = {
|
||||
@@ -83,9 +85,12 @@ export const Engines = {
|
||||
|
||||
let updatedValue = docYaml.toJSON();
|
||||
|
||||
const quoteStrings = Settings.get(SETTING_QUOTE_STRINGS);
|
||||
|
||||
return yaml.stringify(updatedValue, {
|
||||
lineWidth: options?.lineWidth || 5000,
|
||||
defaultStringType: 'PLAIN',
|
||||
defaultStringType: quoteStrings ? 'QUOTE_DOUBLE' : 'PLAIN',
|
||||
defaultKeyType: 'PLAIN',
|
||||
keepUndefined: false,
|
||||
indent: options?.indent || 2,
|
||||
indentSeq: options?.noArrayIndent ? false : true
|
||||
|
||||
@@ -18,8 +18,7 @@ import {
|
||||
} from 'vscode';
|
||||
import {
|
||||
SETTING_CONTENT_FRONTMATTER_HIGHLIGHT,
|
||||
SETTING_CONTENT_SUPPORTED_FILETYPES,
|
||||
SETTING_FRONTMATTER_TYPE
|
||||
SETTING_CONTENT_SUPPORTED_FILETYPES
|
||||
} from '../constants';
|
||||
import { Settings } from '../helpers';
|
||||
import { FrontMatterDecorationProvider } from './FrontMatterDecorationProvider';
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import { ModeListener } from './../listeners/general/ModeListener';
|
||||
import { SETTING_GLOBAL_ACTIVE_MODE, SETTING_GLOBAL_MODES } from './../constants/settings';
|
||||
import { commands, StatusBarAlignment, StatusBarItem, ThemeColor, window } from 'vscode';
|
||||
import {
|
||||
EXTENSION_NAME,
|
||||
SETTING_GLOBAL_ACTIVE_MODE,
|
||||
SETTING_GLOBAL_MODES
|
||||
} from './../constants/settings';
|
||||
import { commands, StatusBarAlignment, StatusBarItem, window } from 'vscode';
|
||||
import { Settings } from '../helpers/SettingsHelper';
|
||||
import { COMMAND_NAME, CONTEXT } from '../constants';
|
||||
import { Mode } from '../models';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class ModeSwitch {
|
||||
private static isInit: boolean = false;
|
||||
@@ -56,9 +62,9 @@ export class ModeSwitch {
|
||||
const modePicks = ['Default', ...modes.map((m) => m.id)];
|
||||
|
||||
const mode = await window.showQuickPick(modePicks, {
|
||||
placeHolder: `Select the mode you want to use`,
|
||||
ignoreFocusOut: true,
|
||||
title: `Front Matter: Mode selection`
|
||||
title: l10n.t(LocalizationKey.servicesModeSwitchSwitchModeQuickPickTitle, EXTENSION_NAME),
|
||||
placeHolder: l10n.t(LocalizationKey.servicesModeSwitchSwitchModeQuickPickPlaceholder),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (mode) {
|
||||
@@ -70,9 +76,10 @@ export class ModeSwitch {
|
||||
}
|
||||
|
||||
private static setText() {
|
||||
ModeSwitch.statusBarElm.text = `$(preview) Mode: ${
|
||||
ModeSwitch.statusBarElm.text = `$(preview) ${l10n.t(
|
||||
LocalizationKey.servicesModeSwitchSetTextMode,
|
||||
ModeSwitch.currentMode ? ModeSwitch.currentMode : 'Default'
|
||||
}`;
|
||||
)}`;
|
||||
ModeSwitch.statusBarElm.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ import {
|
||||
} from '../helpers';
|
||||
import { existsAsync } from '../utils';
|
||||
import { Article, Cache } from '../commands';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
export class PagesParser {
|
||||
public static allPages: Page[] = [];
|
||||
@@ -81,7 +83,9 @@ export class PagesParser {
|
||||
const pages: Page[] = [];
|
||||
|
||||
if (folderInfo) {
|
||||
PagesParser.pagesStatusBar.text = '$(sync~spin) Processing pages...';
|
||||
PagesParser.pagesStatusBar.text = `$(sync~spin) ${l10n.t(
|
||||
LocalizationKey.servicesPagesParserParsePagesStatusBarText
|
||||
)}`;
|
||||
PagesParser.pagesStatusBar.show();
|
||||
|
||||
for (const folder of folderInfo) {
|
||||
@@ -108,7 +112,12 @@ export class PagesParser {
|
||||
}
|
||||
|
||||
Logger.error(`PagesParser::parsePages: ${file.filePath} - ${error.message}`);
|
||||
Notifications.error(`File error: ${file.filePath} - ${error?.message || error}`);
|
||||
Notifications.error(
|
||||
l10n.t(
|
||||
LocalizationKey.servicesPagesParserParsePagesFileError,
|
||||
`${file.filePath} - ${error?.message || error}`
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ import { Logger, Notifications, Settings, TaxonomyHelper } from '../helpers';
|
||||
import fetch from 'node-fetch';
|
||||
import { TagType } from '../panelWebView/TagType';
|
||||
import { TaxonomyType } from '../models';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
const AI_URL = 'https://frontmatter.codes/api/ai';
|
||||
// const AI_URL = 'http://localhost:3000/api/ai';
|
||||
@@ -18,7 +20,7 @@ export class SponsorAi {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => {
|
||||
Notifications.warning(`The AI title generation took too long. Please try again later.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.servicesSponsorAiGetTitlesWarning));
|
||||
controller.abort();
|
||||
}, 10000);
|
||||
const signal = controller.signal;
|
||||
@@ -51,7 +53,7 @@ export class SponsorAi {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => {
|
||||
Notifications.warning(`The AI title generation took too long. Please try again later.`);
|
||||
Notifications.warning(l10n.t(LocalizationKey.servicesSponsorAiGetDescriptionWarning));
|
||||
controller.abort();
|
||||
}, 10000);
|
||||
const signal = controller.signal;
|
||||
@@ -103,7 +105,9 @@ export class SponsorAi {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => {
|
||||
Notifications.warning(`The AI taxonomy generation took too long. Please try again later.`);
|
||||
Notifications.warning(
|
||||
l10n.t(LocalizationKey.servicesSponsorAiGetTaxonomySuggestionsWarning)
|
||||
);
|
||||
controller.abort();
|
||||
}, 10000);
|
||||
const signal = controller.signal;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { workspace, window, ThemeIcon, TerminalOptions } from 'vscode';
|
||||
import * as os from 'os';
|
||||
import { Folders } from '../commands';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
interface ShellSetting {
|
||||
path: string;
|
||||
@@ -45,7 +47,9 @@ export class Terminal {
|
||||
const terminalOptions: TerminalOptions = {
|
||||
name: Terminal.terminalName,
|
||||
iconPath: new ThemeIcon('server-environment'),
|
||||
message: `Starting local server`
|
||||
message: l10n.t(
|
||||
LocalizationKey.servicesTerminalOpenLocalServerTerminalTerminalOptionMessage
|
||||
)
|
||||
};
|
||||
|
||||
// Check if workspace
|
||||
|
||||
@@ -3,17 +3,25 @@ import { Field, WhenOperator } from '../models';
|
||||
import { IMetadata } from '../panelWebView/components/Metadata';
|
||||
|
||||
/**
|
||||
* Validate the field its "when" clause
|
||||
* @param field
|
||||
* @param parent
|
||||
* @returns
|
||||
* Determines whether a field should be displayed based on its "when" clause.
|
||||
* @param field - The field to check.
|
||||
* @param parent - The parent metadata object.
|
||||
* @returns A boolean indicating whether the field should be displayed.
|
||||
*/
|
||||
export const fieldWhenClause = (field: Field, parent: IMetadata): boolean => {
|
||||
export const fieldWhenClause = (field: Field, parent: IMetadata, allFields?: Field[]): boolean => {
|
||||
const when = field.when;
|
||||
if (!when) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let parentField = allFields?.find((f) => f.name === when.fieldRef);
|
||||
if (parentField && parentField.when) {
|
||||
const renderParent = fieldWhenClause(parentField, parent, allFields);
|
||||
if (!renderParent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let whenValue = parent[when.fieldRef];
|
||||
if (when.caseSensitive || typeof when.caseSensitive === 'undefined') {
|
||||
return caseSensitive(when, field, whenValue);
|
||||
@@ -23,11 +31,11 @@ export const fieldWhenClause = (field: Field, parent: IMetadata): boolean => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Case sensitive checks
|
||||
* @param when
|
||||
* @param field
|
||||
* @param whenValue
|
||||
* @returns
|
||||
* Returns a boolean indicating whether the given `when` clause matches the given `field` and `whenValue`, ignoring case sensitivity.
|
||||
* @param when - The `WhenClause` to match against.
|
||||
* @param field - The `Field` to match against.
|
||||
* @param whenValue - The value to match against the `when` clause.
|
||||
* @returns A boolean indicating whether the `when` clause matches the `field` and `whenValue`, ignoring case sensitivity.
|
||||
*/
|
||||
const caseInsensitive = (
|
||||
when: WhenClause,
|
||||
@@ -43,11 +51,11 @@ const caseInsensitive = (
|
||||
};
|
||||
|
||||
/**
|
||||
* Case insensitive checks
|
||||
* @param when
|
||||
* @param field
|
||||
* @param whenValue
|
||||
* @returns
|
||||
* Determines if a given field matches a when clause with case sensitivity.
|
||||
* @param when - The when clause to match against.
|
||||
* @param field - The field to match.
|
||||
* @param whenValue - The value to match against the when clause.
|
||||
* @returns True if the field matches the when clause, false otherwise.
|
||||
*/
|
||||
const caseSensitive = (
|
||||
when: WhenClause,
|
||||
@@ -119,9 +127,9 @@ const caseSensitive = (
|
||||
};
|
||||
|
||||
/**
|
||||
* Lower the value(s)
|
||||
* @param value
|
||||
* @returns
|
||||
* Converts the given string or array of strings to lowercase.
|
||||
* @param value - The string or array of strings to convert to lowercase.
|
||||
* @returns The converted string or array of strings.
|
||||
*/
|
||||
const lowerValue = (value: string | string[] | any) => {
|
||||
if (typeof value === 'string') {
|
||||
|
||||
@@ -1,32 +1,35 @@
|
||||
import { writeFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { createServer } from "vite";
|
||||
import zod from "zod";
|
||||
import { writeFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { createServer } from 'vite';
|
||||
import zod from 'astro/zod';
|
||||
|
||||
const {
|
||||
ZodDefault,
|
||||
ZodObject,
|
||||
ZodOptional,
|
||||
ZodString,
|
||||
ZodEffects,
|
||||
ZodEnum
|
||||
} = zod;
|
||||
const { ZodDefault, ZodObject, ZodOptional, ZodString, ZodEffects, ZodEnum, ZodUnion } = zod;
|
||||
|
||||
/**
|
||||
* Process the Zod field
|
||||
* @param {ZodTypeAny} field
|
||||
* @param {string} defaultValue
|
||||
* @returns
|
||||
* @param {ZodTypeAny} field
|
||||
* @param {boolean} isOptional
|
||||
* @param {string} defaultValue
|
||||
* @returns
|
||||
*/
|
||||
function getField(field, defaultValue = undefined) {
|
||||
let isOptional = false;
|
||||
|
||||
function getField(field, isOptional = false, defaultValue = undefined) {
|
||||
// Handle various type transformations and assignments
|
||||
if (field instanceof ZodOptional) {
|
||||
isOptional = true;
|
||||
const type = field.unwrap();
|
||||
|
||||
return getField(type, isOptional, defaultValue)
|
||||
return getField(type, isOptional, defaultValue);
|
||||
}
|
||||
|
||||
if (field instanceof ZodEffects) {
|
||||
const type = field.sourceType();
|
||||
return getField(type, isOptional, defaultValue);
|
||||
}
|
||||
|
||||
if (field instanceof ZodUnion) {
|
||||
const types = field._def.options;
|
||||
const type = types[0];
|
||||
return getField(type, isOptional, defaultValue);
|
||||
}
|
||||
|
||||
if (field instanceof ZodDefault) {
|
||||
@@ -35,43 +38,43 @@ function getField(field, defaultValue = undefined) {
|
||||
defaultValue = field.parse(undefined);
|
||||
// https://github.com/sachinraja/zod-to-ts/blob/main/src/index.ts
|
||||
const type = field._def.innerType;
|
||||
return getField(type, isOptional, defaultValue)
|
||||
return getField(type, isOptional, defaultValue);
|
||||
}
|
||||
|
||||
return {
|
||||
type: field,
|
||||
isOptional,
|
||||
defaultValue
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the field information
|
||||
* @param {string} name
|
||||
* @param {ZodTypeAny} type
|
||||
* @returns
|
||||
* @param {string} name
|
||||
* @param {ZodTypeAny} type
|
||||
* @returns
|
||||
*/
|
||||
function generateFieldInfo(name, type) {
|
||||
let description = type.description;
|
||||
let defaultValue = undefined;
|
||||
|
||||
const {
|
||||
type: fieldType,
|
||||
isOptional: isFieldOptional,
|
||||
defaultValue: fieldDefaultValue
|
||||
} = getField(type, defaultValue);
|
||||
const {
|
||||
type: fieldType,
|
||||
isOptional: isFieldOptional,
|
||||
defaultValue: fieldDefaultValue
|
||||
} = getField(type, false, defaultValue);
|
||||
|
||||
const fieldInfo = {
|
||||
name: name,
|
||||
description: description,
|
||||
defaultValue: fieldDefaultValue,
|
||||
type: fieldType._def.typeName,
|
||||
required: !isFieldOptional,
|
||||
required: !isFieldOptional
|
||||
};
|
||||
|
||||
if (fieldType instanceof ZodObject) {
|
||||
const subFields = extractFieldInfoFromShape(fieldType);
|
||||
|
||||
|
||||
fieldInfo.fields = subFields;
|
||||
}
|
||||
|
||||
@@ -79,6 +82,10 @@ function generateFieldInfo(name, type) {
|
||||
fieldInfo.type = fieldType.sourceType().fmFieldType;
|
||||
}
|
||||
|
||||
if (fieldInfo.name.toLowerCase().includes('image')) {
|
||||
fieldInfo.type = 'image';
|
||||
}
|
||||
|
||||
if (fieldType instanceof ZodEnum) {
|
||||
fieldInfo.options = fieldType.options;
|
||||
}
|
||||
@@ -96,8 +103,8 @@ function generateFieldInfo(name, type) {
|
||||
|
||||
/**
|
||||
* Parse the scheme into an array of fields
|
||||
* @param {ZodTypeAny} type
|
||||
* @returns
|
||||
* @param {ZodTypeAny} type
|
||||
* @returns
|
||||
*/
|
||||
function extractFieldInfoFromShape(type) {
|
||||
if (type instanceof ZodOptional) {
|
||||
@@ -106,7 +113,7 @@ function extractFieldInfoFromShape(type) {
|
||||
|
||||
if (!(type instanceof ZodObject)) {
|
||||
// Return an empty array if the type is not of the expected type
|
||||
return [];
|
||||
return [];
|
||||
}
|
||||
|
||||
// Iterate through the shape properties
|
||||
@@ -121,8 +128,8 @@ function extractFieldInfoFromShape(type) {
|
||||
|
||||
/**
|
||||
* Process each content collection
|
||||
* @param {*} collections
|
||||
* @returns
|
||||
* @param {*} collections
|
||||
* @returns
|
||||
*/
|
||||
function processCollection(collections) {
|
||||
if (!Array.isArray(collections)) {
|
||||
@@ -130,32 +137,35 @@ function processCollection(collections) {
|
||||
}
|
||||
|
||||
return collections.map(([name, collection]) => {
|
||||
const schema = typeof collection.schema === "function" ? collection.schema({
|
||||
image() {
|
||||
const field = zod.string();
|
||||
field.fmFieldType = "image";
|
||||
return field;
|
||||
}
|
||||
}) : collection.schema;
|
||||
const schema =
|
||||
typeof collection.schema === 'function'
|
||||
? collection.schema({
|
||||
image() {
|
||||
const field = zod.string();
|
||||
field.fmFieldType = 'image';
|
||||
return field;
|
||||
}
|
||||
})
|
||||
: collection.schema;
|
||||
|
||||
return {
|
||||
name,
|
||||
type: collection.type || "content",
|
||||
fields: extractFieldInfoFromShape(schema),
|
||||
type: collection.type || 'content',
|
||||
fields: extractFieldInfoFromShape(schema)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* More info: https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
const astroContentModulePlugin = () => {
|
||||
const astroContent = "astro:content";
|
||||
const astroContent = 'astro:content';
|
||||
const astroContentMarker = `\0${astroContent}`;
|
||||
|
||||
return {
|
||||
name: "astro-content-collections",
|
||||
name: 'astro-content-collections',
|
||||
resolveId(importee) {
|
||||
if (importee === astroContent) {
|
||||
return astroContentMarker;
|
||||
@@ -174,7 +184,7 @@ const astroContentModulePlugin = () => {
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -182,8 +192,8 @@ const astroContentModulePlugin = () => {
|
||||
*/
|
||||
(async () => {
|
||||
const configPath = process.argv[2];
|
||||
if (!configPath || typeof configPath !== "string") {
|
||||
console.log("No config path provided");
|
||||
if (!configPath || typeof configPath !== 'string') {
|
||||
console.log('No config path provided');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -195,22 +205,25 @@ const astroContentModulePlugin = () => {
|
||||
hmr: false
|
||||
},
|
||||
optimizeDeps: {
|
||||
disabled: true,
|
||||
disabled: true
|
||||
},
|
||||
appType: "custom",
|
||||
appType: 'custom',
|
||||
plugins: [astroContentModulePlugin()]
|
||||
});
|
||||
|
||||
try {
|
||||
// https://github.dev/withastro/astro/blob/defab70cb2a0c67d5e9153542490d2749046b151/packages/astro/src/content/utils.ts#L334
|
||||
const contentModule = await server.ssrLoadModule(configPath)
|
||||
const contentModule = await server.ssrLoadModule(configPath);
|
||||
|
||||
const collections = Object.entries(contentModule.collections ?? {});
|
||||
const processedCollections = processCollection(collections);
|
||||
|
||||
writeFileSync(join(process.cwd(), `./.frontmatter/temp/astro.collections.json`), JSON.stringify(processedCollections));
|
||||
|
||||
console.log("Collections generated successfully");
|
||||
writeFileSync(
|
||||
join(process.cwd(), `./.frontmatter/temp/astro.collections.json`),
|
||||
JSON.stringify(processedCollections, null, 2)
|
||||
);
|
||||
|
||||
console.log('Collections generated successfully');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
@@ -218,4 +231,4 @@ const astroContentModulePlugin = () => {
|
||||
} finally {
|
||||
await server.close();
|
||||
}
|
||||
})();
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user