#69 - Welcome screen integration

This commit is contained in:
Elio Struyf
2021-08-27 11:30:25 +02:00
parent 918a33b45e
commit 7716d98868
22 changed files with 342 additions and 27 deletions
+1
View File
@@ -6,6 +6,7 @@
- [#64](https://github.com/estruyf/vscode-front-matter/issues/64): Publish toggle for easier publishing an article
- [#65](https://github.com/estruyf/vscode-front-matter/issues/65): Aggregate articles in draft
- [#66](https://github.com/estruyf/vscode-front-matter/issues/66): New dashboard webview on which you can manage all your content
- [#69](https://github.com/estruyf/vscode-front-matter/issues/69): Welcome screen for getting started
## [2.5.1] - 2020-08-23
+3 -6
View File
@@ -267,18 +267,15 @@
},
{
"command": "frontMatter.createFromTemplate",
"title": "New article from template",
"category": "Front matter"
"title": "Front Matter: New article from template"
},
{
"command": "frontMatter.registerFolder",
"title": "Register folder",
"category": "Front matter"
"title": "Front Matter: Register folder"
},
{
"command": "frontMatter.unregisterFolder",
"title": "Unregister folder",
"category": "Front matter"
"title": "Front Matter: Unregister folder"
},
{
"command": "frontMatter.createContent",
+23 -2
View File
@@ -14,6 +14,7 @@ import { COMMAND_NAME } from '../constants/Extension';
import { Template } from './Template';
import { Notifications } from '../helpers/Notifications';
import { Settings } from '../pagesView/models/Settings';
import { Extension } from '../helpers/Extension';
export class Dashboard {
@@ -92,6 +93,10 @@ export class Dashboard {
Dashboard.isDisposed = true;
});
workspace.onDidChangeConfiguration(() => {
Dashboard.getSettings();
});
Dashboard.webview.webview.onDidReceiveMessage(async (msg) => {
switch(msg.command) {
case DashboardMessage.getData:
@@ -107,6 +112,19 @@ export class Dashboard {
case DashboardMessage.updateSetting:
Dashboard.updateSetting(msg.data);
break;
case DashboardMessage.InitializeProject:
await commands.executeCommand(COMMAND_NAME.init);
// Delay to allow the project to be initialized
setTimeout(() => {
Dashboard.getSettings();
}, 1000);
break;
case DashboardMessage.Reload:
Dashboard.webview?.dispose();
setTimeout(() => {
Dashboard.open(Extension.getInstance().extensionPath);
}, 100);
break;
}
});
}
@@ -122,7 +140,8 @@ export class Dashboard {
initialized: await Template.isInitialized(),
tags: SettingsHelper.getTaxonomy(TaxonomyType.Tag),
categories: SettingsHelper.getTaxonomy(TaxonomyType.Category),
openOnStart: SettingsHelper.getConfig().get(SETTINGS_DASHBOARD_OPENONSTART)
openOnStart: SettingsHelper.getConfig().get(SETTINGS_DASHBOARD_OPENONSTART),
versionInfo: Extension.getInstance().getVersion()
} as Settings
});
}
@@ -213,6 +232,8 @@ export class Dashboard {
const nonce = getNonce();
const version = Extension.getInstance().getVersion();
return `
<!DOCTYPE html>
<html lang="en" style="width:100%;height:100%;margin:0;padding:0;">
@@ -223,7 +244,7 @@ export class Dashboard {
<title>Front Matter Dashboard</title>
</head>
<body style="width:100%;height:100%;margin:0;padding:0;overflow:hidden" class="bg-gray-100 text-vulcan-500 dark:bg-vulcan-500 dark:text-whisper-500">
<div id="app" style="width:100%;height:100%;margin:0;padding:0;"></div>
<div id="app" style="width:100%;height:100%;margin:0;padding:0;" ${version.usedVersion ? "" : `data-showWelcome="true"`}></div>
<img style="display:none" src="https://api.visitorbadge.io/api/combined?user=estruyf&repo=frontmatter-usage&countColor=%23263759" alt="Daily usage" />
+4
View File
@@ -0,0 +1,4 @@
export const GITHUB_LINK = "https://github.com/sponsors/estruyf";
export const ISSUE_LINK = "https://github.com/estruyf/vscode-front-matter/issues";
export const SPONSOR_LINK = "https://github.com/estruyf/vscode-front-matter";
export const REVIEW_LINK = "https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter&ssr=false#review-details";
+5 -7
View File
@@ -5,12 +5,12 @@ import { Folders } from './commands/Folders';
import { Preview } from './commands/Preview';
import { Project } from './commands/Project';
import { Template } from './commands/Template';
import { COMMAND_NAME, EXTENSION_ID, EXTENSION_STATE_VERSION } from './constants/Extension';
import { COMMAND_NAME } from './constants/Extension';
import { TaxonomyType } from './models';
import { MarkdownFoldingProvider } from './providers/MarkdownFoldingProvider';
import { TagType } from './viewpanel/TagType';
import { ExplorerView } from './webview/ExplorerView';
import { Notifications } from './helpers/Notifications';
import { Extension } from './helpers/Extension';
let frontMatterStatusBar: vscode.StatusBarItem;
let statusDebouncer: { (fnc: any, time: number): void; };
@@ -20,11 +20,9 @@ let collection: vscode.DiagnosticCollection;
const mdSelector: vscode.DocumentSelector = { language: 'markdown', scheme: 'file' };
export async function activate({ subscriptions, extensionUri, extensionPath, globalState }: vscode.ExtensionContext) {
collection = vscode.languages.createDiagnosticCollection('frontMatter');
const extension = Extension.getInstance(globalState, extensionPath);
const frontMatter = vscode.extensions.getExtension(EXTENSION_ID)!;
const frontMatterVersoin = frontMatter.packageJSON.version;
const crntVersion = globalState.get<string>(EXTENSION_STATE_VERSION);
collection = vscode.languages.createDiagnosticCollection('frontMatter');
// Pages dashboard
Dashboard.init(extensionPath);
@@ -32,7 +30,7 @@ export async function activate({ subscriptions, extensionUri, extensionPath, glo
Dashboard.open(extensionPath);
}));
if (!crntVersion) {
if (!extension.getVersion().usedVersion) {
vscode.commands.executeCommand(COMMAND_NAME.dashboard);
}
+44
View File
@@ -0,0 +1,44 @@
import { Memento, extensions } from "vscode";
import { EXTENSION_ID, EXTENSION_STATE_VERSION } from "../constants/Extension";
export class Extension {
private static instance: Extension;
private constructor(private globalState: Memento, private extPath: string) {}
/**
* Creates the singleton instance for the panel
* @param extPath
*/
public static getInstance(globalState?: Memento, extPath?: string): Extension {
if (!Extension.instance && globalState && extPath) {
Extension.instance = new Extension(globalState, extPath);
}
return Extension.instance;
}
public getVersion(): { usedVersion: string | undefined, installedVersion: string } {
const frontMatter = extensions.getExtension(EXTENSION_ID)!;
const installedVersion = frontMatter.packageJSON.version;
const usedVersion = this.globalState.get<string>(EXTENSION_STATE_VERSION);
if (!usedVersion) {
this.setVersion(installedVersion);
};
return {
usedVersion,
installedVersion
};
}
public setVersion(installedVersion: string): void {
this.globalState.update(EXTENSION_STATE_VERSION, installedVersion);
}
public get extensionPath(): string {
return this.extPath;
}
}
+6
View File
@@ -0,0 +1,6 @@
export interface VersionInfo {
usedVersion: string | undefined;
installedVersion: string;
}
+2
View File
@@ -4,4 +4,6 @@ export enum DashboardMessage {
getTheme = 'getTheme',
createContent = 'createContent',
updateSetting = 'updateSetting',
InitializeProject = 'InitializeProject',
Reload = 'Reload',
}
+19 -3
View File
@@ -7,10 +7,14 @@ import { Tab } from '../constants/Tab';
import { SortOption } from '../constants/SortOption';
import useDarkMode from '../../hooks/useDarkMode';
import usePages from '../hooks/usePages';
import { SponsorMsg } from './SponsorMsg';
import { WelcomeScreen } from './WelcomeScreen';
export interface IDashboardProps {}
export interface IDashboardProps {
showWelcome: boolean;
}
export const Dashboard: React.FunctionComponent<IDashboardProps> = ({}: React.PropsWithChildren<IDashboardProps>) => {
export const Dashboard: React.FunctionComponent<IDashboardProps> = ({showWelcome}: React.PropsWithChildren<IDashboardProps>) => {
const { loading, pages, settings } = useMessages();
const [ tab, setTab ] = React.useState(Tab.All);
const [ sorting, setSorting ] = React.useState(SortOption.LastModified);
@@ -22,6 +26,18 @@ export const Dashboard: React.FunctionComponent<IDashboardProps> = ({}: React.Pr
useDarkMode();
const pageGroups = [...new Set(pages.map(page => page.fmGroup))];
if (!settings) {
return <Spinner />;
}
if (showWelcome) {
return <WelcomeScreen settings={settings} />;
}
if (!settings.initialized || settings.folders?.length === 0) {
return <WelcomeScreen settings={settings} />;
}
return (
<main className={`h-full w-full`}>
@@ -46,7 +62,7 @@ export const Dashboard: React.FunctionComponent<IDashboardProps> = ({}: React.Pr
{ loading ? <Spinner /> : <Overview pages={pageItems} settings={settings} /> }
</div>
<p className={`text-vulcan-50 dark:text-whisper-900 py-2 text-center`}>If you find FrontMatter useful, please consider <a className={`text-vulcan-500 dark:text-whisper-500 hover:text-vulcan-600 dark:hover:text-whisper-300`} href="https://github.com/sponsors/estruyf" title="Sponsor Front Matter">sponsoring</a> it, or if you use FrontMatter for work, please encourage your employer to <a className={`text-vulcan-500 dark:text-whisper-500 hover:text-vulcan-600 dark:hover:text-whisper-300`} href="https://github.com/sponsors/estruyf" title="Sponsor Front Matter">sponsoring</a> it.</p>
<SponsorMsg />
</div>
</main>
);
+1 -3
View File
@@ -1,6 +1,5 @@
import * as React from 'react';
import { FrontMatterIcon } from '../../viewpanel/components/Icons/FrontMatterIcon';
import { MarkdownIcon } from '../../viewpanel/components/Icons/MarkdownIcon';
import { Page } from '../models/Page';
import { Settings } from '../models/Settings';
import { Item } from './Item';
@@ -18,13 +17,12 @@ export const Overview: React.FunctionComponent<IOverviewProps> = ({pages, settin
return (
<div className={`flex items-center justify-center h-full`}>
<div className={`max-w-xl text-center`}>
<FrontMatterIcon className={`text-vulcan-300 dark:text-whisper-800 h-32 mx-auto opacity-10 mb-8`} />
<FrontMatterIcon className={`text-vulcan-300 dark:text-whisper-800 h-32 mx-auto opacity-90 mb-8`} />
{
settings?.folders?.length > 0 ? (
<p className={`text-xl font-medium`}>No Markdown to show</p>
) : (
<>
<p className={`text-lg font-medium`}>Hi, this might be the first time you opened the dashboard, or recently started using Front Matter.</p>
<p className={`text-lg font-medium`}>Make sure you registered a content folder in your project to let Front Matter find the contents.</p>
</>
)
+19
View File
@@ -0,0 +1,19 @@
import { HeartIcon, StarIcon } from '@heroicons/react/outline';
import * as React from 'react';
import { REVIEW_LINK, SPONSOR_LINK } from '../../constants/Links';
export interface ISponsorMsgProps {}
export const SponsorMsg: React.FunctionComponent<ISponsorMsgProps> = (props: React.PropsWithChildren<ISponsorMsgProps>) => {
return (
<p className={`w-full max-w-7xl mx-auto px-4 text-vulcan-50 dark:text-whisper-900 py-2 text-center space-x-8 flex items-center justify-between`}>
<a className={`group inline-flex justify-center items-center space-x-2 text-vulcan-500 dark:text-whisper-500 hover:text-vulcan-600 dark:hover:text-whisper-300 opacity-50 hover:opacity-100`} href={SPONSOR_LINK} title="Sponsor Front Matter">
<span>Sponsor</span> <HeartIcon className={`h-5 w-5 group-hover:fill-current`} />
</a>
<span>FrontMatter</span>
<a className={`group inline-flex justify-center items-center space-x-2 text-vulcan-500 dark:text-whisper-500 hover:text-vulcan-600 dark:hover:text-whisper-300 opacity-50 hover:opacity-100`} href={REVIEW_LINK} title="Review Front Matter">
<StarIcon className={`h-5 w-5 group-hover:fill-current`} /> <span>Review</span>
</a>
</p>
);
};
+60
View File
@@ -0,0 +1,60 @@
import { CheckIcon } from '@heroicons/react/outline';
import * as React from 'react';
import { Status } from '../../models/Status';
export interface IStepProps {
name: string;
description: string;
status: Status;
showLine: boolean;
onClick?: () => void;
}
export const Step: React.FunctionComponent<IStepProps> = ({name, description, status, showLine, onClick}: React.PropsWithChildren<IStepProps>) => {
return (
<>
{
showLine ? (
<div className={`-ml-px absolute mt-0.5 top-4 left-4 w-0.5 h-full ${status === Status.Completed ? "bg-teal-600" : "bg-gray-300"}`} aria-hidden="true" />
) : null
}
<button className={`relative flex items-start group text-left ${onClick ? "" : "cursor-default"}`} onClick={() => { if (onClick) { onClick(); } }} disabled={!onClick}>
{
status === Status.NotStarted && (
<span className="h-9 flex items-center" aria-hidden="true">
<span className={`relative z-10 w-8 h-8 flex items-center justify-center bg-white border-2 border-gray-300 rounded-full ${onClick ? "group-hover:text-gray-400" : ""}`}>
<span className={`h-2.5 w-2.5 bg-transparent rounded-full ${onClick ? "group-hover:bg-gray-300" : ""}`} />
</span>
</span>
)
}
{
status === Status.Active && (
<span className="h-9 flex items-center" aria-hidden="true">
<span className="relative z-10 w-8 h-8 flex items-center justify-center bg-white border-2 border-teal-600 rounded-full">
<span className="h-2.5 w-2.5 bg-teal-600 rounded-full" />
</span>
</span>
)
}
{
status === Status.Completed && (
<span className="h-9 flex items-center">
<span className="relative z-10 w-8 h-8 flex items-center justify-center bg-teal-600 rounded-full group-hover:bg-teal-800">
<CheckIcon className="w-5 h-5 text-white" aria-hidden="true" />
</span>
</span>
)
}
<span className="ml-4 min-w-0 flex flex-col">
<span className="text-xs font-semibold tracking-wide uppercase text-vulcan-500 dark:text-whisper-500">{name}</span>
<span className="text-sm text-vulcan-400 dark:text-whisper-600" dangerouslySetInnerHTML={{__html: description}} />
</span>
</button>
</>
);
};
@@ -0,0 +1,45 @@
import * as React from 'react';
import { MessageHelper } from '../../../helpers/MessageHelper';
import { DashboardMessage } from '../../DashboardMessage';
import { Settings } from '../../models/Settings';
import { Status } from '../../models/Status';
import { Step } from './Step';
export interface IStepsToGetStartedProps {
settings: Settings;
}
export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps> = ({settings}: React.PropsWithChildren<IStepsToGetStartedProps>) => {
const steps = [
{
name: 'Initialize project',
description: 'Initialize the project with a template folder and sample markdown file. The template folder can be used to define your own templates. <b>Start by clicking on this action</b>.',
status: settings.initialized ? Status.Completed : Status.NotStarted,
onClick: settings.initialized ? undefined : () => { MessageHelper.sendMessage(DashboardMessage.InitializeProject); }
},
{
name: 'Register content folders (manual action)',
description: 'Register your content folder(s). You can perform this action by right-clicking on the folder in the explorer view, and selecting <b>register folder</b>. Once a folder is set, Front Matter can be used to list all contents and allow you to create content.',
status: settings.folders && settings.folders.length > 0 ? Status.Completed : Status.NotStarted
},
{
name: 'Show the dashboard',
description: 'Once both actions are completed, click on this action to load the dashboard.',
status: (settings.initialized && settings.folders && settings.folders.length > 0) ? Status.Active : Status.NotStarted,
onClick: (settings.initialized && settings.folders && settings.folders.length > 0) ? () => { MessageHelper.sendMessage(DashboardMessage.Reload); } : undefined
}
];
return (
<nav aria-label="Progress">
<ol role="list" className="overflow-hidden">
{steps.map((step, stepIdx) => (
<li key={step.name} className={`${stepIdx !== steps.length - 1 ? 'pb-10' : ''} relative`}>
<Step name={step.name} description={step.description} status={step.status} showLine={stepIdx !== steps.length - 1} onClick={step.onClick} />
</li>
))}
</ol>
</nav>
);
};
@@ -0,0 +1,82 @@
import { HeartIcon, StarIcon } from '@heroicons/react/outline';
import * as React from 'react';
import { GITHUB_LINK, REVIEW_LINK, SPONSOR_LINK } from '../../constants/Links';
import { FrontMatterIcon } from '../../viewpanel/components/Icons/FrontMatterIcon';
import { GitHubIcon } from '../../viewpanel/components/Icons/GitHubIcon';
import { Settings } from '../models/Settings';
import { StepsToGetStarted } from './Steps/StepsToGetStarted';
export interface IWelcomeScreenProps {
settings: Settings;
}
export const WelcomeScreen: React.FunctionComponent<IWelcomeScreenProps> = ({settings}: React.PropsWithChildren<IWelcomeScreenProps>) => {
return (
<main className="mt-24">
<div className="mx-auto max-w-7xl">
<div className="grid grid-cols-12 gap-8">
<div className="px-6 col-span-8 text-left flex items-center">
<div>
<h1 className="mt-4 text-4xl tracking-tight font-extrabold sm:mt-5 sm:leading-none lg:mt-6 lg:text-5xl xl:text-6xl">
<span className="md:block">Manage your static site with</span>{' '}
<span className="text-teal-500 md:block">Front Matter</span>
</h1>
<p className="mt-3 text-base text-vulcan-300 dark:text-whisper-700 sm:mt-5 sm:text-xl lg:text-lg xl:text-xl">
Thank you for taking the time to test out Front Matter!
</p>
<p className="mt-3 text-base text-vulcan-300 dark:text-whisper-700 sm:mt-5 sm:text-xl lg:text-lg xl:text-xl">
We try to aim to make Front Matter as easy to use as possible, but if you have any questions, please don't hesitate to reach out to us on GitHub.
</p>
<div className="mt-5 w-full sm:mx-auto sm:max-w-lg lg:ml-0">
<div className="flex flex-wrap items-start justify-between">
<a href={GITHUB_LINK} title={`GitHub`} className="flex items-center px-1 text-vulcan-300 hover:text-vulcan-500 dark:text-whisper-500 dark:hover:text-teal-500">
<GitHubIcon className="w-8 h-8" />
<span className={`text-lg ml-2`}>GitHub / Documentation</span>
</a>
<a href={SPONSOR_LINK} title={`Become a sponsor`} className="flex items-center px-1 text-vulcan-300 hover:text-vulcan-500 dark:text-whisper-500 dark:hover:text-teal-500">
<HeartIcon className="w-8 h-8" />
<span className={`text-lg ml-2`}>Sponsor</span>
</a>
<a href={REVIEW_LINK} title={`Write a quick review`} className="flex items-center px-1 text-vulcan-300 hover:text-vulcan-500 dark:text-whisper-500 dark:hover:text-teal-500">
<StarIcon className="w-8 h-8" />
<span className={`text-lg ml-2`}>Review</span>
</a>
</div>
</div>
</div>
</div>
<div className="col-span-4 flex justify-center items-center">
<FrontMatterIcon className={`h-64 w-64 text-vulcan-500 dark:text-whisper-500`} />
</div>
</div>
</div>
<div className="mx-auto max-w-7xl mt-12 px-6">
<h2 className="text-xl tracking-tight font-extrabold sm:leading-none">
Perform the next steps to get you started with the extension
</h2>
<div className={`grid grid-cols-12 gap-8 mt-5`}>
<div className={`col-span-8`}>
<StepsToGetStarted settings={settings} />
<p className="mt-5 text-sm text-vulcan-300 dark:text-whisper-700">
Once you completed both actions, the dashboard will show its full potential. You can also use the extension from the <b>Front Matter</b> side panel. There you will find the actions you can perform specifically for your pages.
</p>
</div>
</div>
<h2 className="mt-5 text-lg tracking-tight font-extrabold sm:leading-none">
We hope you enjoy Front Matter!
</h2>
</div>
</main>
);
};
+1 -2
View File
@@ -1,6 +1,5 @@
import { useState, useEffect } from 'react';
import { MessageHelper } from '../../helpers/MessageHelper';
import { ContentFolder } from '../../models';
import { DashboardCommand } from '../DashboardCommand';
import { DashboardMessage } from '../DashboardMessage';
import { Page } from '../models/Page';
@@ -11,7 +10,7 @@ const vscode = MessageHelper.getVsCodeAPI();
export default function useMessages(options?: any) {
const [loading, setLoading] = useState<boolean>(false);
const [pages, setPages] = useState<Page[]>([]);
const [settings, setSettings] = useState<Settings>({} as any);
const [settings, setSettings] = useState<Settings | undefined>(undefined);
window.addEventListener('message', event => {
const message = event.data;
+2 -1
View File
@@ -11,4 +11,5 @@ declare const acquireVsCodeApi: <T = unknown>() => {
};
const elm = document.querySelector("#app");
render(<Dashboard />, elm);
const welcome = elm?.getAttribute("data-showWelcome");
render(<Dashboard showWelcome={!!welcome} />, elm);
+2
View File
@@ -1,3 +1,4 @@
import { VersionInfo } from '../../models/VersionInfo';
import { ContentFolder } from './../../models/ContentFolder';
export interface Settings {
@@ -6,4 +7,5 @@ export interface Settings {
tags: string[];
categories: string[];
openOnStart: boolean | null;
versionInfo: VersionInfo;
}
+7
View File
@@ -0,0 +1,7 @@
export enum Status {
Active = 1,
Completed,
NotStarted
}
@@ -6,6 +6,6 @@ export interface IFrontMatterIconProps {
export const FrontMatterIcon: React.FunctionComponent<IFrontMatterIconProps> = ({className}: React.PropsWithChildren<IFrontMatterIconProps>) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" className={className || ""} viewBox="0 0 30 30"><path d="M4,11.4H2.2V2.9H5.4v2H4V6.1H5.3V8H4Z" transform="translate(1 1)" fill="currentcolor"/><path d="M10.9,11.4H9l-.9-3V8.2C8,8.1,8,8,7.9,7.8v3.6H6.1V2.9H8a2.88,2.88,0,0,1,1.9.6,3.11,3.11,0,0,1,.8,2.2A2.25,2.25,0,0,1,9.6,7.8ZM8,6.8h.1a.55.55,0,0,0,.5-.3,1.88,1.88,0,0,0,.2-.8c0-.6-.3-1-.8-1H8Z" transform="translate(1 1)" fill="currentcolor"/><path d="M16.5,7.2a6.08,6.08,0,0,1-.7,3.2A2.14,2.14,0,0,1,14,11.6a2.09,2.09,0,0,1-1.7-.9,5.84,5.84,0,0,1-.9-3.5,5.84,5.84,0,0,1,.9-3.5A2.09,2.09,0,0,1,14,2.8,2.16,2.16,0,0,1,15.9,4,8.24,8.24,0,0,1,16.5,7.2Zm-1.9,0c0-1.5-.2-2.3-.7-2.3-.2,0-.4.2-.5.6a6.53,6.53,0,0,0-.2,1.7,7.18,7.18,0,0,0,.2,1.7c.1.4.3.6.5.6s.4-.2.5-.6A7.93,7.93,0,0,0,14.6,7.2Z" transform="translate(1 1)" fill="currentcolor"/><path d="M17.2,11.4V2.9H19l.9,3c.1.1.1.3.2.6s.1.5.2.8l.2.7c-.1-.7-.1-1.4-.2-1.9a6.64,6.64,0,0,1-.1-1.3V2.9H22v8.5H20.3l-.9-3.1-.3-.9c-.1-.3-.1-.6-.2-.8,0,.6.1,1.1.1,1.6v3.4H17.2Z" transform="translate(1 1)" fill="currentcolor"/><path d="M25.3,11.4H23.5V4.9h-1v-2h3.9v2H25.3Z" transform="translate(1 1)" fill="currentcolor"/><rect x="1" y="1" width="28" height="28" fill="none" stroke="currentcolor" stroke-miterlimit="10" stroke-width="2"/><path d="M2.9,17h.9l.6,3a5,5,0,0,1,.2,1.2c.1.4.1.8.2,1.2v-.2l.2-.9.1-.8.1-.5.6-3h.9l.7,7.5h-1l-.2-2.6V19.5h0v.1a.9.9,0,0,1-.1.5c-.1.2,0,.2-.1.3l-.1.7v.3l-.6,3.3H4.5l-.6-2.8a5.16,5.16,0,0,1-.2-1.1c-.1-.4-.1-.8-.2-1.2l-.3,5.2h-1Z" transform="translate(1 1)" fill="currentcolor"/><path d="M9.3,17h.8l1.6,7.5h-1L10.4,23H8.9l-.3,1.5h-1Zm1,5.2L10,21c-.1-.8-.3-1.7-.4-2.6a6.75,6.75,0,0,1-.2,1.4l-.3,1.5-.2,1h1.4Z" transform="translate(1 1)" fill="currentcolor"/><path d="M11.5,17h3.3v.9H13.7v6.7h-1V17.9H11.5Z" transform="translate(1 1)" fill="currentcolor"/><path d="M14.8,17h3.3v.9H17v6.7H16V17.9H14.8Z" transform="translate(1 1)" fill="currentcolor"/><path d="M18.7,17h2.7v.9H19.7v2.4h1.5v.9H19.7v2.6h1.7v.9H18.7Z" transform="translate(1 1)" fill="currentcolor"/><path d="M22.3,17h1.3c.6,0,1,.1,1.2.4a2.35,2.35,0,0,1,.5,1.6,2.5,2.5,0,0,1-.3,1.3,1.24,1.24,0,0,1-.8.6l1.4,3.7h-1l-1.4-3.7v3.7h-1V17Zm1,3.3c.4,0,.7-.1.8-.3s.2-.5.2-.9a1.27,1.27,0,0,0-.1-.6c-.1-.2-.1-.3-.2-.4s-.2-.2-.3-.2-.3-.1-.4-.1h-.2v2.5Z" transform="translate(1 1)" fill="currentcolor"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" className={className || ""} viewBox="0 0 30 30"><path d="M4,11.4H2.2V2.9H5.4v2H4V6.1H5.3V8H4Z" transform="translate(1 1)" fill="currentcolor"/><path d="M10.9,11.4H9l-.9-3V8.2C8,8.1,8,8,7.9,7.8v3.6H6.1V2.9H8a2.88,2.88,0,0,1,1.9.6,3.11,3.11,0,0,1,.8,2.2A2.25,2.25,0,0,1,9.6,7.8ZM8,6.8h.1a.55.55,0,0,0,.5-.3,1.88,1.88,0,0,0,.2-.8c0-.6-.3-1-.8-1H8Z" transform="translate(1 1)" fill="currentcolor"/><path d="M16.5,7.2a6.08,6.08,0,0,1-.7,3.2A2.14,2.14,0,0,1,14,11.6a2.09,2.09,0,0,1-1.7-.9,5.84,5.84,0,0,1-.9-3.5,5.84,5.84,0,0,1,.9-3.5A2.09,2.09,0,0,1,14,2.8,2.16,2.16,0,0,1,15.9,4,8.24,8.24,0,0,1,16.5,7.2Zm-1.9,0c0-1.5-.2-2.3-.7-2.3-.2,0-.4.2-.5.6a6.53,6.53,0,0,0-.2,1.7,7.18,7.18,0,0,0,.2,1.7c.1.4.3.6.5.6s.4-.2.5-.6A7.93,7.93,0,0,0,14.6,7.2Z" transform="translate(1 1)" fill="currentcolor"/><path d="M17.2,11.4V2.9H19l.9,3c.1.1.1.3.2.6s.1.5.2.8l.2.7c-.1-.7-.1-1.4-.2-1.9a6.64,6.64,0,0,1-.1-1.3V2.9H22v8.5H20.3l-.9-3.1-.3-.9c-.1-.3-.1-.6-.2-.8,0,.6.1,1.1.1,1.6v3.4H17.2Z" transform="translate(1 1)" fill="currentcolor"/><path d="M25.3,11.4H23.5V4.9h-1v-2h3.9v2H25.3Z" transform="translate(1 1)" fill="currentcolor"/><rect x="1" y="1" width="28" height="28" fill="none" stroke="currentcolor" strokeMiterlimit="10" strokeWidth="2"/><path d="M2.9,17h.9l.6,3a5,5,0,0,1,.2,1.2c.1.4.1.8.2,1.2v-.2l.2-.9.1-.8.1-.5.6-3h.9l.7,7.5h-1l-.2-2.6V19.5h0v.1a.9.9,0,0,1-.1.5c-.1.2,0,.2-.1.3l-.1.7v.3l-.6,3.3H4.5l-.6-2.8a5.16,5.16,0,0,1-.2-1.1c-.1-.4-.1-.8-.2-1.2l-.3,5.2h-1Z" transform="translate(1 1)" fill="currentcolor"/><path d="M9.3,17h.8l1.6,7.5h-1L10.4,23H8.9l-.3,1.5h-1Zm1,5.2L10,21c-.1-.8-.3-1.7-.4-2.6a6.75,6.75,0,0,1-.2,1.4l-.3,1.5-.2,1h1.4Z" transform="translate(1 1)" fill="currentcolor"/><path d="M11.5,17h3.3v.9H13.7v6.7h-1V17.9H11.5Z" transform="translate(1 1)" fill="currentcolor"/><path d="M14.8,17h3.3v.9H17v6.7H16V17.9H14.8Z" transform="translate(1 1)" fill="currentcolor"/><path d="M18.7,17h2.7v.9H19.7v2.4h1.5v.9H19.7v2.6h1.7v.9H18.7Z" transform="translate(1 1)" fill="currentcolor"/><path d="M22.3,17h1.3c.6,0,1,.1,1.2.4a2.35,2.35,0,0,1,.5,1.6,2.5,2.5,0,0,1-.3,1.3,1.24,1.24,0,0,1-.8.6l1.4,3.7h-1l-1.4-3.7v3.7h-1V17Zm1,3.3c.4,0,.7-.1.8-.3s.2-.5.2-.9a1.27,1.27,0,0,0-.1-.6c-.1-.2-.1-.3-.2-.4s-.2-.2-.3-.2-.3-.1-.4-.1h-.2v2.5Z" transform="translate(1 1)" fill="currentcolor"/></svg>
);
};
@@ -0,0 +1,11 @@
import * as React from 'react';
export interface IGitHubIconProps {
className: string;
}
export const GitHubIcon: React.FunctionComponent<IGitHubIconProps> = ({className}: React.PropsWithChildren<IGitHubIconProps>) => {
return (
<svg className={className || ""} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M12 0a12 12 0 1 0 0 24 12 12 0 0 0 0-24zm3.163 21.783h-.093a.513.513 0 0 1-.382-.14.513.513 0 0 1-.14-.372v-1.406c.006-.467.01-.94.01-1.416a3.693 3.693 0 0 0-.151-1.028 1.832 1.832 0 0 0-.542-.875 8.014 8.014 0 0 0 2.038-.471 4.051 4.051 0 0 0 1.466-.964c.407-.427.71-.943.885-1.506a6.77 6.77 0 0 0 .3-2.13 4.138 4.138 0 0 0-.26-1.476 3.892 3.892 0 0 0-.795-1.284 2.81 2.81 0 0 0 .162-.582c.033-.2.05-.402.05-.604 0-.26-.03-.52-.09-.773a5.309 5.309 0 0 0-.221-.763.293.293 0 0 0-.111-.02h-.11c-.23.002-.456.04-.674.111a5.34 5.34 0 0 0-.703.26 6.503 6.503 0 0 0-.661.343c-.215.127-.405.249-.573.362a9.578 9.578 0 0 0-5.143 0 13.507 13.507 0 0 0-.572-.362 6.022 6.022 0 0 0-.672-.342 4.516 4.516 0 0 0-.705-.261 2.203 2.203 0 0 0-.662-.111h-.11a.29.29 0 0 0-.11.02 5.844 5.844 0 0 0-.23.763c-.054.254-.08.513-.081.773 0 .202.017.404.051.604.033.199.086.394.16.582A3.888 3.888 0 0 0 5.702 10a4.142 4.142 0 0 0-.263 1.476 6.871 6.871 0 0 0 .292 2.12c.181.563.483 1.08.884 1.516.415.422.915.75 1.466.964.653.25 1.337.41 2.033.476a1.828 1.828 0 0 0-.452.633 2.99 2.99 0 0 0-.2.744 2.754 2.754 0 0 1-1.175.27 1.788 1.788 0 0 1-1.065-.3 2.904 2.904 0 0 1-.752-.824 3.1 3.1 0 0 0-.292-.382 2.693 2.693 0 0 0-.372-.343 1.841 1.841 0 0 0-.432-.24 1.2 1.2 0 0 0-.481-.101c-.04.001-.08.005-.12.01a.649.649 0 0 0-.162.02.408.408 0 0 0-.13.06.116.116 0 0 0-.06.1.33.33 0 0 0 .14.242c.093.074.17.131.232.171l.03.021c.133.103.261.214.382.333.112.098.213.209.3.33.09.119.168.246.231.381.073.134.15.288.231.463.188.474.522.875.954 1.145.453.243.961.364 1.476.351.174 0 .349-.01.522-.03.172-.028.343-.057.515-.091v1.743a.5.5 0 0 1-.533.521h-.062a10.286 10.286 0 1 1 6.324 0v.005z"/></svg>
);
};
+2 -1
View File
@@ -11,6 +11,7 @@ import { SettingsIcon } from './Icons/SettingsIcon';
import { TemplateIcon } from './Icons/TemplateIcon';
import { WritingIcon } from './Icons/WritingIcon';
import { OtherActionButton } from './OtherActionButton';
import { ISSUE_LINK } from '../../constants/Links';
export interface IOtherActionsProps {
isFile: boolean;
@@ -58,7 +59,7 @@ export const OtherActions: React.FunctionComponent<IOtherActionsProps> = ({isFil
<OtherActionButton onClick={openProject}><FolderOpenedIcon /> <span>Reveal project folder</span></OtherActionButton>
<div className="ext_link_block">
<a href="https://github.com/estruyf/vscode-front-matter/issues" title="Open an issue on GitHub"><BugIcon /> <span>Report an issue</span></a>
<a href={ISSUE_LINK} title="Open an issue on GitHub"><BugIcon /> <span>Report an issue</span></a>
</div>
</Collapsible>
</>
+2 -1
View File
@@ -1,4 +1,5 @@
import * as React from 'react';
import { SPONSOR_LINK } from '../../constants/Links';
import { HeartIcon } from './Icons/HeartIcon';
export interface ISponsorMsgProps {}
@@ -6,7 +7,7 @@ export interface ISponsorMsgProps {}
export const SponsorMsg: React.FunctionComponent<ISponsorMsgProps> = (props: React.PropsWithChildren<ISponsorMsgProps>) => {
return (
<p className={`sponsor`}>
<a href="https://github.com/sponsors/estruyf" title="Sponsor Front Matter">
<a href={SPONSOR_LINK} title="Sponsor Front Matter">
<span>Sponsor</span> <HeartIcon className={`h-5 w-5 mr-2`} /> <span>FrontMatter</span>
</a>
</p>