mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-08-06 08:52:47 +02:00
Merge branch 'release/v7.2.0' into dev
This commit is contained in:
@@ -1,5 +1,17 @@
|
||||
# Change Log
|
||||
|
||||
## [7.2.0] - 2022-04-xx
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- [#263](https://github.com/estruyf/vscode-front-matter/issues/263): WYSIWYG string field option
|
||||
- [#314](https://github.com/estruyf/vscode-front-matter/issues/314): New preview actions to open the page in the browser and refresh the preview
|
||||
- [#322](https://github.com/estruyf/vscode-front-matter/issues/322): Show parent folder name when file is an index page (`index.md` / `_index.md`)
|
||||
|
||||
### ⚡️ Optimizations
|
||||
|
||||
- [#316](https://github.com/estruyf/vscode-front-matter/issues/316): Surpress file parsing errors when closing the dashboard
|
||||
|
||||
## [7.1.2] - 2022-04-11
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
Generated
+78
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vscode-front-matter-beta",
|
||||
"version": "7.1.2",
|
||||
"version": "7.2.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -642,6 +642,15 @@
|
||||
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/quill": {
|
||||
"version": "1.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz",
|
||||
"integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"parchment": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"@types/range-parser": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
|
||||
@@ -1432,6 +1441,12 @@
|
||||
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
|
||||
"dev": true
|
||||
},
|
||||
"clone": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
|
||||
"dev": true
|
||||
},
|
||||
"clone-deep": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
|
||||
@@ -2286,6 +2301,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||
"dev": true
|
||||
},
|
||||
"extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
@@ -2301,6 +2322,12 @@
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-diff": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
|
||||
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-glob": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz",
|
||||
@@ -4224,6 +4251,12 @@
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"parchment": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz",
|
||||
"integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==",
|
||||
"dev": true
|
||||
},
|
||||
"parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
@@ -4606,6 +4639,39 @@
|
||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
|
||||
"dev": true
|
||||
},
|
||||
"quill": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz",
|
||||
"integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"clone": "^2.1.1",
|
||||
"deep-equal": "^1.0.1",
|
||||
"eventemitter3": "^2.0.3",
|
||||
"extend": "^3.0.2",
|
||||
"parchment": "^1.1.4",
|
||||
"quill-delta": "^3.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"eventemitter3": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
|
||||
"integrity": "sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"quill-delta": {
|
||||
"version": "3.6.3",
|
||||
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz",
|
||||
"integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"deep-equal": "^1.0.1",
|
||||
"extend": "^3.0.2",
|
||||
"fast-diff": "1.1.2"
|
||||
}
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
@@ -4707,6 +4773,17 @@
|
||||
"warning": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"react-quill": {
|
||||
"version": "2.0.0-beta.4",
|
||||
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0-beta.4.tgz",
|
||||
"integrity": "sha512-KyAHvAlPjP4xLElKZJefMth91Z6FbbXRvq9OSu6xN3KBaoasLP9p+3dcxg4Ywr4tBlpMGXcPszYSAgd5CpJ45Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/quill": "^1.3.10",
|
||||
"lodash": "^4.17.4",
|
||||
"quill": "^1.3.7"
|
||||
}
|
||||
},
|
||||
"react-sortable-hoc": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-sortable-hoc/-/react-sortable-hoc-2.0.0.tgz",
|
||||
|
||||
+7
-1
@@ -3,7 +3,7 @@
|
||||
"displayName": "Front Matter",
|
||||
"description": "Front Matter is a CMS that runs within Visual Studio Code. It gives you the power and control of a full-blown CMS while also providing you the flexibility and speed of the static site generator of your choice like: Hugo, Jekyll, Hexo, NextJs, Gatsby, and many more...",
|
||||
"icon": "assets/frontmatter-teal-128x128.png",
|
||||
"version": "7.1.2",
|
||||
"version": "7.2.0",
|
||||
"preview": false,
|
||||
"publisher": "eliostruyf",
|
||||
"galleryBanner": {
|
||||
@@ -802,6 +802,11 @@
|
||||
"default": false,
|
||||
"description": "Is a single line field"
|
||||
},
|
||||
"wysiwyg": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Is a WYSIWYG field (HTML output)"
|
||||
},
|
||||
"multiple": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
@@ -1802,6 +1807,7 @@
|
||||
"react-datepicker": "4.2.1",
|
||||
"react-dom": "17.0.1",
|
||||
"react-dropzone": "^11.3.4",
|
||||
"react-quill": "^2.0.0-beta.4",
|
||||
"react-sortable-hoc": "^2.0.0",
|
||||
"react-toastify": "^8.1.0",
|
||||
"recoil": "^0.4.1",
|
||||
|
||||
+55
-51
@@ -1,14 +1,15 @@
|
||||
import { Telemetry } from './../helpers/Telemetry';
|
||||
import { SETTING_PREVIEW_HOST, SETTING_PREVIEW_PATHNAME, CONTEXT, TelemetryEvent } from './../constants';
|
||||
import { SETTING_PREVIEW_HOST, SETTING_PREVIEW_PATHNAME, CONTEXT, TelemetryEvent, PreviewCommands } from './../constants';
|
||||
import { ArticleHelper } from './../helpers/ArticleHelper';
|
||||
import { join } from "path";
|
||||
import { commands, env, Uri, ViewColumn, window } from "vscode";
|
||||
import { Settings } from '../helpers';
|
||||
import { Extension, Settings } from '../helpers';
|
||||
import { PreviewSettings } from '../models';
|
||||
import { format } from 'date-fns';
|
||||
import { DateHelper } from '../helpers/DateHelper';
|
||||
import { Article } from '.';
|
||||
import { urlJoin } from 'url-join-ts';
|
||||
import { WebviewHelper } from '@estruyf/vscode';
|
||||
|
||||
|
||||
export class Preview {
|
||||
@@ -81,59 +82,62 @@ export class Preview {
|
||||
|
||||
const cspSource = webView.webview.cspSource;
|
||||
|
||||
webView.webview.html = `<!DOCTYPE html>
|
||||
<head>
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'none'; frame-src ${localhostUrl} ${cspSource} http: https:; img-src ${localhostUrl} ${cspSource} http: https:; script-src ${localhostUrl} ${cspSource} 'unsafe-inline'; style-src ${localhostUrl} ${cspSource} 'self' 'unsafe-inline' http: https:;"
|
||||
/>
|
||||
<style>
|
||||
html,body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: white;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
webView.webview.onDidReceiveMessage(message => {
|
||||
switch (message.command) {
|
||||
case PreviewCommands.toVSCode.open:
|
||||
if (message.data) {
|
||||
commands.executeCommand('vscode.open', message.data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: calc(100% - 30px);
|
||||
border: 0;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.slug {
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: var(--vscode-editor-background);
|
||||
border-bottom: 1px solid var(--vscode-focusBorder);
|
||||
}
|
||||
const dashboardFile = "dashboardWebView.js";
|
||||
const localPort = `9000`;
|
||||
const localServerUrl = `localhost:${localPort}`;
|
||||
|
||||
input {
|
||||
color: var(--vscode-editor-foreground);
|
||||
padding: 0.25rem 0.5rem;
|
||||
background: none;
|
||||
border: 0;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="slug">
|
||||
<input type="text" value="${urlJoin(localhostUrl.toString(), slug || '')}" disabled />
|
||||
</div>
|
||||
<iframe src="${urlJoin(localhostUrl.toString(), slug || '')}" >
|
||||
</body>
|
||||
</html>`;
|
||||
const nonce = WebviewHelper.getNonce();
|
||||
|
||||
const ext = Extension.getInstance();
|
||||
const isProd = ext.isProductionMode;
|
||||
const version = ext.getVersion();
|
||||
const isBeta = ext.isBetaVersion();
|
||||
const extensionUri = ext.extensionPath;
|
||||
|
||||
const csp = [
|
||||
`default-src 'none';`,
|
||||
`img-src ${localhostUrl} ${cspSource} http: https:;`,
|
||||
`script-src ${isProd ? `'nonce-${nonce}'` : `http://${localServerUrl} http://0.0.0.0:${localPort}`} 'unsafe-eval'`,
|
||||
`style-src ${cspSource} 'self' 'unsafe-inline' http: https:`,
|
||||
`connect-src https://o1022172.ingest.sentry.io ${isProd ? `` : `ws://${localServerUrl} ws://0.0.0.0:${localPort} http://${localServerUrl} http://0.0.0.0:${localPort}`}`,
|
||||
`frame-src ${localhostUrl} ${cspSource} http: https:;`,
|
||||
];
|
||||
|
||||
let scriptUri = "";
|
||||
if (isProd) {
|
||||
scriptUri = webView.webview.asWebviewUri(Uri.joinPath(extensionUri, 'dist', dashboardFile)).toString();
|
||||
} else {
|
||||
scriptUri = `http://${localServerUrl}/${dashboardFile}`;
|
||||
}
|
||||
|
||||
webView.webview.html = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="width:100%;height:100%;margin:0;padding:0;">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="${csp.join('; ')}">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Front Matter Preview</title>
|
||||
</head>
|
||||
<body style="width:100%;height:100%;margin:0;padding:0;overflow:hidden">
|
||||
<div id="app" data-type="preview" data-url="${urlJoin(localhostUrl.toString(), slug || '')}" data-isProd="${isProd}" data-environment="${isBeta ? "BETA" : "main"}" data-version="${version.usedVersion}" style="width:100%;height:100%;margin:0;padding:0;"></div>
|
||||
|
||||
<script ${isProd ? `nonce="${nonce}"` : ""} src="${scriptUri}"></script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
Telemetry.send(TelemetryEvent.openPreview);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
export const PreviewCommands = {
|
||||
toVSCode: {
|
||||
open: `preview.open`
|
||||
},
|
||||
fromVSCode: {}
|
||||
};
|
||||
@@ -9,6 +9,7 @@ export * from './GeneralCommands';
|
||||
export * from './Links';
|
||||
export * from './LocalStore';
|
||||
export * from './Navigation';
|
||||
export * from './PreviewCommands';
|
||||
export * from './TelemetryEvent';
|
||||
export * from './charCode';
|
||||
export * from './charMap';
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { ExternalLinkIcon, RefreshIcon } from '@heroicons/react/outline';
|
||||
import * as React from 'react';
|
||||
import { useRef } from 'react';
|
||||
import { PreviewCommands } from '../../../constants';
|
||||
|
||||
export interface IPreviewProps {
|
||||
url: string | null;
|
||||
}
|
||||
|
||||
export const Preview: React.FunctionComponent<IPreviewProps> = ({url}: React.PropsWithChildren<IPreviewProps>) => {
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
|
||||
const onRefresh = () => {
|
||||
if (iframeRef.current?.src) {
|
||||
iframeRef.current.src = iframeRef.current.src;
|
||||
}
|
||||
};
|
||||
|
||||
const openInBrowser = () => {
|
||||
Messenger.send(PreviewCommands.toVSCode.open, url);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='w-full h-full bg-white'>
|
||||
<div
|
||||
className="slug fixed w-full top-0 flex items-center"
|
||||
style={{
|
||||
height: "30px",
|
||||
background: "var(--vscode-editor-background)",
|
||||
borderBottom: "1px solid var(--vscode-focusBorder)"
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value={url || ""}
|
||||
className="w-full h-full border-0 bg-transparent text-xs py-1 px-2"
|
||||
style={{
|
||||
color: "var(--vscode-editor-foreground)"
|
||||
}}
|
||||
disabled />
|
||||
|
||||
<div
|
||||
className="actions absolute right-0 top-0 bottom-0 flex items-center space-x-2 px-2"
|
||||
style={{
|
||||
background: "var(--vscode-editor-background)",
|
||||
}}
|
||||
>
|
||||
<button title="Refresh" onClick={onRefresh}>
|
||||
<RefreshIcon className='w-4 h-4' aria-hidden="true" />
|
||||
</button>
|
||||
|
||||
<button title="Open" onClick={openInBrowser} className="mr-2">
|
||||
<ExternalLinkIcon className='w-4 h-4' aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
src={url || ""}
|
||||
className={`w-full border-0`}
|
||||
style={{
|
||||
height: "calc(100% - 30px)",
|
||||
marginTop: "30px"
|
||||
}}></iframe>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './Preview';
|
||||
@@ -6,6 +6,7 @@ import * as Sentry from "@sentry/react";
|
||||
import { Integrations } from "@sentry/tracing";
|
||||
import { SENTRY_LINK } from "../constants";
|
||||
import './styles.css';
|
||||
import { Preview } from "./components/Preview";
|
||||
|
||||
declare const acquireVsCodeApi: <T = unknown>() => {
|
||||
getState: () => T;
|
||||
@@ -19,6 +20,8 @@ if (elm) {
|
||||
const version = elm?.getAttribute("data-version");
|
||||
const environment = elm?.getAttribute("data-environment");
|
||||
const isProd = elm?.getAttribute("data-isProd");
|
||||
const type = elm?.getAttribute("data-type");
|
||||
const url = elm?.getAttribute("data-url");
|
||||
|
||||
if (isProd === "true") {
|
||||
Sentry.init({
|
||||
@@ -31,7 +34,11 @@ if (elm) {
|
||||
});
|
||||
}
|
||||
|
||||
render(<RecoilRoot><Dashboard showWelcome={!!welcome} /></RecoilRoot>, elm);
|
||||
if (type === "preview") {
|
||||
render(<Preview url={url} />, elm);
|
||||
} else {
|
||||
render(<RecoilRoot><Dashboard showWelcome={!!welcome} /></RecoilRoot>, elm);
|
||||
}
|
||||
}
|
||||
|
||||
// Webpack HMR
|
||||
|
||||
@@ -174,6 +174,10 @@ export class PagesListener extends BaseListener {
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
if ((error as Error)?.message.toLowerCase() === "webview is disposed") {
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger.error(`PagesListener::getPagesData: ${file.filePath} - ${error.message}`);
|
||||
Notifications.error(`File error: ${file.filePath} - ${error?.message || error}`);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ export interface Field {
|
||||
type: FieldType;
|
||||
choices?: string[] | Choice[];
|
||||
single?: boolean;
|
||||
wysiwyg?: boolean;
|
||||
multiple?: boolean;
|
||||
isPreviewImage?: boolean;
|
||||
hidden?: boolean;
|
||||
|
||||
@@ -6,12 +6,15 @@ export interface ITextFieldProps {
|
||||
label: string;
|
||||
value: string | null;
|
||||
singleLine: boolean | undefined;
|
||||
wysiwyg: boolean | undefined;
|
||||
limit: number | undefined;
|
||||
rows?: number;
|
||||
onChange: (txtValue: string) => void;
|
||||
}
|
||||
|
||||
export const TextField: React.FunctionComponent<ITextFieldProps> = ({singleLine, limit, label, value, rows, onChange}: React.PropsWithChildren<ITextFieldProps>) => {
|
||||
const WysiwygField = React.lazy(() => import('./WysiwygField'));
|
||||
|
||||
export const TextField: React.FunctionComponent<ITextFieldProps> = ({singleLine, wysiwyg, limit, label, value, rows, onChange}: React.PropsWithChildren<ITextFieldProps>) => {
|
||||
const [ text, setText ] = React.useState<string | null>(value);
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -37,25 +40,31 @@ export const TextField: React.FunctionComponent<ITextFieldProps> = ({singleLine,
|
||||
<PencilIcon style={{ width: "16px", height: "16px" }} /> <span style={{ lineHeight: "16px"}}>{label}</span>
|
||||
</div>
|
||||
</VsLabel>
|
||||
|
||||
|
||||
{
|
||||
singleLine ? (
|
||||
<input
|
||||
className={`metadata_field__input`}
|
||||
value={text || ""}
|
||||
onChange={(e) => onTextChange(e.currentTarget.value)}
|
||||
style={{
|
||||
border: isValid ? "1px solid var(--vscode-inputValidation-infoBorder)" : "1px solid var(--vscode-inputValidation-warningBorder)"
|
||||
}} />
|
||||
wysiwyg ? (
|
||||
<React.Suspense fallback={(<div>Loading field</div>)}>
|
||||
<WysiwygField text={text || ""} onChange={onTextChange} />
|
||||
</React.Suspense>
|
||||
) : (
|
||||
<textarea
|
||||
className={`metadata_field__textarea`}
|
||||
rows={rows || 2}
|
||||
value={text || ""}
|
||||
onChange={(e) => onTextChange(e.currentTarget.value)}
|
||||
style={{
|
||||
border: isValid ? "1px solid var(--vscode-inputValidation-infoBorder)" : "1px solid var(--vscode-inputValidation-warningBorder)"
|
||||
}} />
|
||||
singleLine ? (
|
||||
<input
|
||||
className={`metadata_field__input`}
|
||||
value={text || ""}
|
||||
onChange={(e) => onTextChange(e.currentTarget.value)}
|
||||
style={{
|
||||
border: isValid ? "1px solid var(--vscode-inputValidation-infoBorder)" : "1px solid var(--vscode-inputValidation-warningBorder)"
|
||||
}} />
|
||||
) : (
|
||||
<textarea
|
||||
className={`metadata_field__textarea`}
|
||||
rows={rows || 2}
|
||||
value={text || ""}
|
||||
onChange={(e) => onTextChange(e.currentTarget.value)}
|
||||
style={{
|
||||
border: isValid ? "1px solid var(--vscode-inputValidation-infoBorder)" : "1px solid var(--vscode-inputValidation-warningBorder)"
|
||||
}} />
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -153,6 +153,7 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
label={field.title || field.name}
|
||||
singleLine={field.single}
|
||||
limit={limit}
|
||||
wysiwyg={field.wysiwyg}
|
||||
rows={3}
|
||||
onChange={(value) => onSendUpdate(field.name, value, parentFields)}
|
||||
value={fieldValue as string || null} />
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import * as React from 'react';
|
||||
const ReactQuill = require('react-quill');
|
||||
import 'react-quill/dist/quill.snow.css';
|
||||
|
||||
export interface IWysiwygFieldProps {
|
||||
text: string;
|
||||
onChange: (txtValue: string) => void;
|
||||
}
|
||||
|
||||
const WysiwygField: React.FunctionComponent<IWysiwygFieldProps> = ({ text, onChange }: React.PropsWithChildren<IWysiwygFieldProps>) => {
|
||||
const modules = {
|
||||
toolbar: [
|
||||
[{ 'header': [1, 2, 3, false] }],
|
||||
['bold', 'italic', 'underline', 'strike'],
|
||||
[{'list': 'ordered'}, {'list': 'bullet'}],
|
||||
['clean']
|
||||
]
|
||||
};
|
||||
|
||||
return (
|
||||
<ReactQuill
|
||||
modules={modules}
|
||||
value={text || ""}
|
||||
onChange={onChange} />
|
||||
);
|
||||
};
|
||||
|
||||
export default WysiwygField;
|
||||
@@ -19,7 +19,7 @@ const FileItem: React.FunctionComponent<IFileItemProps> = ({ name, folderName, p
|
||||
};
|
||||
|
||||
const itemName = useMemo(() => {
|
||||
if (folderName && name === 'index.md') {
|
||||
if (folderName && name.includes("index.")) {
|
||||
return folderName;
|
||||
}
|
||||
|
||||
|
||||
@@ -251,4 +251,66 @@
|
||||
|
||||
.sr-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Quill changes */
|
||||
.ql-toolbar.ql-snow,
|
||||
.ql-container.ql-snow {
|
||||
border-color: var(--vscode-inputValidation-infoBorder) !important;
|
||||
}
|
||||
|
||||
.ql-toolbar.ql-snow {
|
||||
padding: var(--input-padding-vertical) var(--input-padding-horizontal) !important;
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker {
|
||||
color: var(--vscode-settings-headerForeground) !important;
|
||||
}
|
||||
|
||||
.ql-snow .ql-fill {
|
||||
fill: var(--vscode-settings-headerForeground) !important;
|
||||
}
|
||||
|
||||
.ql-snow .ql-stroke {
|
||||
stroke: var(--vscode-settings-headerForeground) !important;
|
||||
}
|
||||
|
||||
.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label {
|
||||
border-color: var(--vscode-inputValidation-infoBorder) !important;
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker-options {
|
||||
background: var(--vscode-input-background) !important;
|
||||
color: var(--vscode-input-foreground) !important;
|
||||
border-color: var(--vscode-inputValidation-infoBorder) !important;
|
||||
}
|
||||
|
||||
.ql-editor {
|
||||
background-color: var(--vscode-input-background) !important;
|
||||
padding: var(--input-padding-vertical) var(--input-padding-horizontal) !important;
|
||||
}
|
||||
|
||||
.ql-snow.ql-toolbar button:hover,
|
||||
.ql-snow .ql-toolbar button:hover,
|
||||
.ql-snow.ql-toolbar button:focus,
|
||||
.ql-snow .ql-toolbar button:focus,
|
||||
.ql-snow.ql-toolbar button.ql-active,
|
||||
.ql-snow .ql-toolbar button.ql-active,
|
||||
.ql-snow.ql-toolbar .ql-picker-label:hover,
|
||||
.ql-snow .ql-toolbar .ql-picker-label:hover,
|
||||
.ql-snow.ql-toolbar .ql-picker-label.ql-active,
|
||||
.ql-snow .ql-toolbar .ql-picker-label.ql-active,
|
||||
.ql-snow.ql-toolbar .ql-picker-item:hover,
|
||||
.ql-snow .ql-toolbar .ql-picker-item:hover,
|
||||
.ql-snow.ql-toolbar .ql-picker-item.ql-selected,
|
||||
.ql-snow .ql-toolbar .ql-picker-item.ql-selected {
|
||||
color: var(--vscode-button-background) !important;
|
||||
}
|
||||
|
||||
.ql-snow.ql-toolbar button:hover .ql-stroke, .ql-snow .ql-toolbar button:hover .ql-stroke, .ql-snow.ql-toolbar button:focus .ql-stroke, .ql-snow .ql-toolbar button:focus .ql-stroke, .ql-snow.ql-toolbar button.ql-active .ql-stroke, .ql-snow .ql-toolbar button.ql-active .ql-stroke, .ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke, .ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke, .ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke, .ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke, .ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke, .ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke, .ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke, .ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke, .ql-snow.ql-toolbar button:hover .ql-stroke-miter, .ql-snow .ql-toolbar button:hover .ql-stroke-miter, .ql-snow.ql-toolbar button:focus .ql-stroke-miter, .ql-snow .ql-toolbar button:focus .ql-stroke-miter, .ql-snow.ql-toolbar button.ql-active .ql-stroke-miter, .ql-snow .ql-toolbar button.ql-active .ql-stroke-miter, .ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter, .ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter, .ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter, .ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter, .ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter, .ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter, .ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter, .ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter {
|
||||
stroke: var(--vscode-button-background) !important;
|
||||
}
|
||||
|
||||
.ql-snow.ql-toolbar button:hover .ql-fill, .ql-snow .ql-toolbar button:hover .ql-fill, .ql-snow.ql-toolbar button:focus .ql-fill, .ql-snow .ql-toolbar button:focus .ql-fill, .ql-snow.ql-toolbar button.ql-active .ql-fill, .ql-snow .ql-toolbar button.ql-active .ql-fill, .ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill, .ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill, .ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill, .ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill, .ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill, .ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill, .ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill, .ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill, .ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill, .ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill, .ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill, .ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill, .ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill, .ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill, .ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill, .ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill, .ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill, .ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill, .ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill, .ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill, .ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill, .ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill {
|
||||
fill: var(--vscode-button-background) !important;
|
||||
}
|
||||
Reference in New Issue
Block a user