From 0e42e1ea00dcd895aed5334e0d7e58481707c9ff Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Thu, 3 Mar 2022 16:26:36 +0100 Subject: [PATCH] Code snippets changes: add, update, delete, and more --- CHANGELOG.md | 7 +- assets/empty.svg | 2 + assets/icons/scissors-dark.svg | 3 + assets/icons/scissors-light.svg | 3 + assets/walkthrough/documentation.md | 3 + assets/walkthrough/get-started.md | 11 ++ assets/walkthrough/support-the-project.md | 8 ++ package.json | 77 ++++++++-- src/commands/Article.ts | 24 ++++ src/commands/Project.ts | 3 + src/commands/Template.ts | 4 + src/commands/Wysiwyg.ts | 3 + src/constants/Extension.ts | 6 +- src/constants/TelemetryEvent.ts | 1 + src/constants/context.ts | 1 + src/dashboardWebView/DashboardMessage.ts | 2 + .../components/Contents/Item.tsx | 2 +- .../components/Header/Header.tsx | 7 +- .../components/Header/Tabs.tsx | 4 +- .../components/Layout/PageLayout.tsx | 4 +- .../components/Media/Item.tsx | 2 +- .../components/Modals/FormDialog.tsx | 7 +- .../components/SnippetsView/Item.tsx | 136 +++++++++++++++--- .../components/SnippetsView/NewForm.tsx | 108 ++++++++++++++ .../components/SnippetsView/SnippetForm.tsx | 122 +++++++++++++--- .../components/SnippetsView/Snippets.tsx | 76 +++++++++- src/dashboardWebView/hooks/useMessages.tsx | 2 + src/extension.ts | 15 +- src/helpers/SnippetParser.ts | 4 +- src/listeners/dashboard/SnippetListener.ts | 41 ++++++ src/models/DashboardData.ts | 4 +- 31 files changed, 630 insertions(+), 62 deletions(-) create mode 100644 assets/empty.svg create mode 100644 assets/icons/scissors-dark.svg create mode 100644 assets/icons/scissors-light.svg create mode 100644 assets/walkthrough/documentation.md create mode 100644 assets/walkthrough/get-started.md create mode 100644 assets/walkthrough/support-the-project.md create mode 100644 src/dashboardWebView/components/SnippetsView/NewForm.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bb4f8d3..31340439 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,17 @@ # Change Log -## [6.2.0] - 2022-03-xx +## [7.0.0] - 2022-03-xx + +### ✨ Features + +- [#175](https://github.com/estruyf/vscode-front-matter/issues/175): New snippet support + dashboard ### 🎨 Enhancements - Light color theme enhancements to media cards - Light color theme enhancements to folder cards - [#272](https://github.com/estruyf/vscode-front-matter/issues/272): New slide over panel for showing details of media files +- [#276](https://github.com/estruyf/vscode-front-matter/issues/276): Add a Front Matter walkthrough for VS Code ## [6.1.0] - 2022-02-28 - [Release notes](https://beta.frontmatter.codes/updates/v6.1.0) diff --git a/assets/empty.svg b/assets/empty.svg new file mode 100644 index 00000000..8872d161 --- /dev/null +++ b/assets/empty.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/assets/icons/scissors-dark.svg b/assets/icons/scissors-dark.svg new file mode 100644 index 00000000..514110d3 --- /dev/null +++ b/assets/icons/scissors-dark.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/assets/icons/scissors-light.svg b/assets/icons/scissors-light.svg new file mode 100644 index 00000000..780b674e --- /dev/null +++ b/assets/icons/scissors-light.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/assets/walkthrough/documentation.md b/assets/walkthrough/documentation.md new file mode 100644 index 00000000..d5751e00 --- /dev/null +++ b/assets/walkthrough/documentation.md @@ -0,0 +1,3 @@ +## Documentation + +Our documentation can be found at: [https://frontmatter.codes/docs](https://frontmatter.codes/docs) \ No newline at end of file diff --git a/assets/walkthrough/get-started.md b/assets/walkthrough/get-started.md new file mode 100644 index 00000000..9cfcfb31 --- /dev/null +++ b/assets/walkthrough/get-started.md @@ -0,0 +1,11 @@ +## Getting started + +Thanks for installing Front Matter! + +To get started, open our dashboard which will guide you through the initialization process of your project. + +When you haven't initialized your project yet, you will see the Front Matter's welcome screen on which you will have to perform the following steps: + +- Project initialization +- Content folders registration +- Framework initialization diff --git a/assets/walkthrough/support-the-project.md b/assets/walkthrough/support-the-project.md new file mode 100644 index 00000000..5b9362cd --- /dev/null +++ b/assets/walkthrough/support-the-project.md @@ -0,0 +1,8 @@ +## Support the project + +Front Matter is an open source project and we are always looking for new contributors, supporters, and partners. If you are interested in backing the project, please consider supporting it by donating. You can donate at via the following links: + +- [GitHub Sponsors](https://github.com/sponsors/estruyf) +- [Open Collective](https://opencollective.com/frontmatter) + +> Each sponsor/backer will be mentioned on the [Front Matter](https://frontmatter.codes) website and on the [GitHub repository](https://github.com/estruyf/vscode-front-matter). \ No newline at end of file diff --git a/package.json b/package.json index db0eb1aa..c36b4970 100644 --- a/package.json +++ b/package.json @@ -1089,7 +1089,7 @@ }, { "command": "frontMatter.markup.blockquote", - "title": "Codeblock", + "title": "Blockquote", "category": "Front matter", "icon": { "light": "assets/icons/blockquote-light.svg", @@ -1180,6 +1180,15 @@ "light": "/assets/icons/media-light.svg" } }, + { + "command": "frontMatter.insertSnippet", + "title": "Insert snippet into your content", + "category": "Front matter", + "icon": { + "dark": "/assets/icons/scissors-dark.svg", + "light": "/assets/icons/scissors-light.svg" + } + }, { "command": "frontMatter.insertTags", "title": "Insert tags", @@ -1212,6 +1221,15 @@ "light": "/assets/icons/frontmatter-small-light.svg" } }, + { + "command": "frontMatter.dashboard.snippets", + "title": "Open snippets dashboard", + "category": "Front matter", + "icon": { + "dark": "/assets/icons/frontmatter-small-dark.svg", + "light": "/assets/icons/frontmatter-small-light.svg" + } + }, { "command": "frontMatter.dashboard.media", "title": "Open media dashboard", @@ -1287,32 +1305,32 @@ "editor/title": [ { "command": "frontMatter.markup.heading", - "group": "navigation@-132", + "group": "navigation@-133", "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" }, { "command": "frontMatter.markup.bold", - "group": "navigation@-131", + "group": "navigation@-132", "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" }, { "command": "frontMatter.markup.italic", - "group": "navigation@-130", + "group": "navigation@-131", "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" }, { "command": "frontMatter.markup.strikethrough", - "group": "navigation@-129", + "group": "navigation@-130", "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" }, { - "command": "frontMatter.markup.blockquote", - "group": "navigation@-128", - "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" + "command": "frontMatter.insertSnippet", + "group": "navigation@-129", + "when": "resourceLangId == markdown" }, { "command": "frontMatter.insertImage", - "group": "navigation@-127", + "group": "navigation@-128", "when": "resourceLangId == markdown" }, { @@ -1345,6 +1363,11 @@ "group": "1_markup@5", "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" }, + { + "command": "frontMatter.markup.blockquote", + "group": "1_markup@6", + "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" + }, { "command": "frontMatter.dashboard", "group": "navigation@-98", @@ -1466,6 +1489,42 @@ "text.html.markdown" ] } + ], + "walkthroughs": [ + { + "id": "frontmatter.welcome", + "title": "Get started with Front Matter", + "description": "Discover the features of Front Matter and learn how to use the CMS for your SSG or static site.", + "steps": [ + { + "id": "frontmatter.welcome.init", + "title": "Get started", + "description": "Initial steps to get started.\n[Open dashboard](command:frontMatter.dashboard)", + "media": { + "markdown": "assets/walkthrough/get-started.md" + }, + "completionEvents": ["onContext:frontMatterInitialized"] + }, + { + "id": "frontmatter.welcome.documentation", + "title": "Documentation", + "description": "Check out the documentation for Front Matter.\n[View our documentation](https://frontmatter.codes/docs)", + "media": { + "markdown": "assets/walkthrough/documentation.md" + }, + "completionEvents": ["onLink:https://frontmatter.codes/docs"] + }, + { + "id": "frontmatter.welcome.supporter", + "title": "Support the project", + "description": "Become a supporter.\n[Support the project](https://github.com/sponsors/estruyf)", + "media": { + "markdown": "assets/walkthrough/support-the-project.md" + }, + "completionEvents": ["onLink:https://github.com/sponsors/estruyf"] + } + ] + } ] }, "scripts": { diff --git a/src/commands/Article.ts b/src/commands/Article.ts index cc55675e..a7afe679 100644 --- a/src/commands/Article.ts +++ b/src/commands/Article.ts @@ -13,6 +13,7 @@ import { parseWinPath } from '../helpers/parseWinPath'; import { Telemetry } from '../helpers/Telemetry'; import { ParsedFrontMatter } from '../parsers'; import { MediaListener } from '../listeners/panel'; +import { NavigationType } from '../dashboardWebView/models'; export class Article { @@ -340,6 +341,29 @@ export class Article { MediaListener.getMediaSelection(); } + /** + * Insert a snippet into the article + */ + public static async insertSnippet() { + let editor = vscode.window.activeTextEditor; + if (!editor) { + return; + } + + const position = editor.selection.active; + const selectionText = editor.document.getText(editor.selection); + + await vscode.commands.executeCommand(COMMAND_NAME.dashboard, { + type: NavigationType.Snippets, + data: { + filePath: editor.document.uri.fsPath, + fieldName: basename(editor.document.uri.fsPath), + position, + selection: selectionText + } + } as DashboardData); + } + /** * Get the current article */ diff --git a/src/commands/Project.ts b/src/commands/Project.ts index 5595c207..0fbc2fb2 100644 --- a/src/commands/Project.ts +++ b/src/commands/Project.ts @@ -7,6 +7,7 @@ import { Template } from "./Template"; import { Folders } from "./Folders"; import { Settings } from "../helpers"; import { SETTING_CONTENT_DEFAULT_FILETYPE, TelemetryEvent } from "../constants"; +import { SettingsListener } from '../listeners/dashboard'; export class Project { @@ -50,6 +51,8 @@ categories: [] } Telemetry.send(TelemetryEvent.initialization) + + SettingsListener.getSettings(); } catch (err: any) { Notifications.error(`Sorry, something went wrong - ${err?.message || err}`); } diff --git a/src/commands/Template.ts b/src/commands/Template.ts index fa5659b0..d164ed0f 100644 --- a/src/commands/Template.ts +++ b/src/commands/Template.ts @@ -23,6 +23,10 @@ export class Template { public static async init() { const isInitialized = await Template.isInitialized(); await vscode.commands.executeCommand('setContext', CONTEXT.canInit, !isInitialized); + + if (isInitialized) { + await vscode.commands.executeCommand('setContext', CONTEXT.initialized, true); + } } /** diff --git a/src/commands/Wysiwyg.ts b/src/commands/Wysiwyg.ts index 70201ce0..657335d2 100644 --- a/src/commands/Wysiwyg.ts +++ b/src/commands/Wysiwyg.ts @@ -54,6 +54,7 @@ export class Wysiwyg { { label: "$(tasklist) Task list", detail: "Add a task list", alwaysShow: true }, { label: "$(code) Code", detail: "Add inline code snippet", alwaysShow: true }, { label: "$(symbol-namespace) Code block", detail: "Add a code block", alwaysShow: true }, + { label: "$(quote) Blockquote", detail: "Add a blockquote", alwaysShow: true }, ] const option = await window.showQuickPick([ ...qpItems ], { @@ -73,6 +74,8 @@ export class Wysiwyg { await this.addMarkup(MarkupType.code); } else if (option.label === qpItems[4].label) { await this.addMarkup(MarkupType.codeblock); + } else if (option.label === qpItems[5].label) { + await this.addMarkup(MarkupType.blockquote); } } })); diff --git a/src/constants/Extension.ts b/src/constants/Extension.ts index 561a0541..e0446325 100644 --- a/src/constants/Extension.ts +++ b/src/constants/Extension.ts @@ -29,13 +29,17 @@ export const COMMAND_NAME = { preview: getCommandName("preview"), dashboard: getCommandName("dashboard"), dashboardMedia: getCommandName("dashboard.media"), + dashboardSnippets: getCommandName("dashboard.snippets"), dashboardData: getCommandName("dashboard.data"), dashboardClose: getCommandName("dashboard.close"), promote: getCommandName("promoteSettings"), - insertImage: getCommandName("insertImage"), createFolder: getCommandName("createFolder"), diagnostics: getCommandName("diagnostics"), + // Insert dashboards + insertImage: getCommandName("insertImage"), + insertSnippet: getCommandName("insertSnippet"), + // WYSIWYG bold: getCommandName("markup.bold"), italic: getCommandName("markup.italic"), diff --git a/src/constants/TelemetryEvent.ts b/src/constants/TelemetryEvent.ts index dfca5182..56a0aae5 100644 --- a/src/constants/TelemetryEvent.ts +++ b/src/constants/TelemetryEvent.ts @@ -4,6 +4,7 @@ export const TelemetryEvent = { openContentDashboard: 'openContentDashboard', openMediaDashboard: 'openMediaDashboard', openDataDashboard: 'openDataDashboard', + openSnippetsDashboard: 'openSnippetsDashboard', closeDashboard: 'closeDashboard', generateSlug: 'generateSlug', createContentFromTemplate: 'createContentFromTemplate', diff --git a/src/constants/context.ts b/src/constants/context.ts index 8f029de2..6f5b7689 100644 --- a/src/constants/context.ts +++ b/src/constants/context.ts @@ -1,5 +1,6 @@ export const CONTEXT = { canInit: "frontMatterCanInit", + initialized: "frontMatterInitialized", canOpenPreview: "frontMatterCanOpenPreview", canOpenDashboard: "frontMatterCanOpenDashboard", isEnabled: "frontMatter:enabled", diff --git a/src/dashboardWebView/DashboardMessage.ts b/src/dashboardWebView/DashboardMessage.ts index ad5ccb61..305bbda4 100644 --- a/src/dashboardWebView/DashboardMessage.ts +++ b/src/dashboardWebView/DashboardMessage.ts @@ -26,4 +26,6 @@ export enum DashboardMessage { putDataEntries = 'putDataEntries', sendTelemetry = 'sendTelemetry', insertSnippet = 'insertSnippet', + addSnippet = 'addSnippet', + updateSnippet = 'updateSnippet', } \ No newline at end of file diff --git a/src/dashboardWebView/components/Contents/Item.tsx b/src/dashboardWebView/components/Contents/Item.tsx index 29d62e18..05b8b6d4 100644 --- a/src/dashboardWebView/components/Contents/Item.tsx +++ b/src/dashboardWebView/components/Contents/Item.tsx @@ -23,7 +23,7 @@ export const Item: React.FunctionComponent = ({ fmFilePath, date, ti if (view === DashboardViewType.Grid) { return (
  • -
  • { diff --git a/src/dashboardWebView/components/Layout/PageLayout.tsx b/src/dashboardWebView/components/Layout/PageLayout.tsx index c2083d48..634bf70e 100644 --- a/src/dashboardWebView/components/Layout/PageLayout.tsx +++ b/src/dashboardWebView/components/Layout/PageLayout.tsx @@ -4,16 +4,18 @@ import { SettingsSelector } from '../../state'; import { Header } from '../Header'; export interface IPageLayoutProps { + header?: React.ReactNode; folders?: string[] | undefined totalPages?: number | undefined } -export const PageLayout: React.FunctionComponent = ({ folders, totalPages, children }: React.PropsWithChildren) => { +export const PageLayout: React.FunctionComponent = ({ header, folders, totalPages, children }: React.PropsWithChildren) => { const settings = useRecoilValue(SettingsSelector); return (
    diff --git a/src/dashboardWebView/components/Media/Item.tsx b/src/dashboardWebView/components/Media/Item.tsx index 4d46bc75..ba79099c 100644 --- a/src/dashboardWebView/components/Media/Item.tsx +++ b/src/dashboardWebView/components/Media/Item.tsx @@ -205,7 +205,7 @@ export const Item: React.FunctionComponent = ({media}: React.PropsWi return ( <> -
  • +
  • - ) : ( -
    Edit
    ) } + + + +
  • -

    {snippet.description}

    +

    {snippet.description}

    { @@ -70,11 +135,48 @@ export const Item: React.FunctionComponent = ({ title, snippet }: Re cancelBtnText='Cancel'> + ref={formRef} + snippet={snippet} + selection={viewData?.data?.selection} /> ) } + + { + showEditDialog && ( + + + setSnippetTitle(value)} + onDescriptionUpdate={(value: string) => setSnippetDescription(value)} + onBodyUpdate={(value: string) => setSnippetOriginalBody(value)} /> + + + ) + } + + { + showAlert && ( + setShowAlert(false)} + trigger={onDelete} /> + ) + } ); }; \ No newline at end of file diff --git a/src/dashboardWebView/components/SnippetsView/NewForm.tsx b/src/dashboardWebView/components/SnippetsView/NewForm.tsx new file mode 100644 index 00000000..fc319203 --- /dev/null +++ b/src/dashboardWebView/components/SnippetsView/NewForm.tsx @@ -0,0 +1,108 @@ +import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/outline'; +import * as React from 'react'; + +export interface INewFormProps { + title: string; + description: string; + body: string; + + onTitleUpdate: (value: string) => void; + onDescriptionUpdate: (value: string) => void; + onBodyUpdate: (value: string) => void; +} + +export const NewForm: React.FunctionComponent = ({ title, description, body, onTitleUpdate, onDescriptionUpdate, onBodyUpdate }: React.PropsWithChildren) => { + const [ showDetails, setShowDetails ] = React.useState(false); + + return ( +
    +
    + +
    + onTitleUpdate(e.currentTarget.value)} + /> +
    +
    + +
    + +
    + onDescriptionUpdate(e.currentTarget.value)} + /> +
    +
    + +
    + +
    +