#586 - Allow to specify the content card fields

This commit is contained in:
Elio Struyf
2023-05-23 15:35:58 +02:00
parent 9515b74182
commit a29d2a86e0
7 changed files with 128 additions and 31 deletions
+2 -1
View File
@@ -9,9 +9,10 @@
### 🎨 Enhancements
- [#558](https://github.com/estruyf/vscode-front-matter/issues/558): Moved the tags and categories to a `.frontmatter/database/taxonomyDb.json` file
- [#566](https://github.com/estruyf/vscode-front-matter/issues/566): Keep the panel context on the live preview
- [#568](https://github.com/estruyf/vscode-front-matter/issues/568): Update the preview URL if the slug changes
- [#558](https://github.com/estruyf/vscode-front-matter/issues/558): Moved the tags and categories to a `.frontmatter/database/taxonomyDb.json` file
- [#586](https://github.com/estruyf/vscode-front-matter/issues/586): Allow to specify the content card fields
### ⚡️ Optimizations
+20
View File
@@ -573,6 +573,26 @@
"markdownDescription": "Specify the name of the metadata field that will be used to show the tags on the content card. When empty or null, it will hide the tags from the card. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontMatter.dashboard.content.cardTags)",
"scope": "Dashboard"
},
"frontMatter.dashboard.content.card.fields.state": {
"type": "boolean",
"default": true,
"markdownDescription": "Specify if you want to show the state/draft status on the content card view. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontMatter.dashboard.content.card.fields.state)"
},
"frontMatter.dashboard.content.card.fields.date": {
"type": "boolean",
"default": true,
"markdownDescription": "Specify if you want to show the date on the content card view. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontMatter.dashboard.content.card.fields.date)"
},
"frontMatter.dashboard.content.card.fields.description": {
"type": ["null", "string"],
"default": "",
"markdownDescription": "Specify the name of the metadata field that will be used to show the description on the content card. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontMatter.dashboard.content.card.fields.description)"
},
"frontMatter.dashboard.content.card.fields.title": {
"type": ["null", "string"],
"default": "",
"markdownDescription": "Specify the name of the metadata field that will be used to show the title on the content card. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontMatter.dashboard.content.card.fields.title)"
},
"frontMatter.dashboard.mediaSnippet": {
"type": "array",
"default": [],
+7
View File
@@ -76,6 +76,13 @@ export const SETTING_DASHBOARD_OPENONSTART = 'dashboard.openOnStart';
export const SETTING_DASHBOARD_CONTENT_TAGS = 'dashboard.content.cardTags';
export const SETTING_DASHBOARD_CONTENT_PAGINATION = 'dashboard.content.pagination';
// Content cards
export const SETTING_DASHBOARD_CONTENT_CARD_STATE = 'dashboard.content.card.fields.state';
export const SETTING_DASHBOARD_CONTENT_CARD_DATE = 'dashboard.content.card.fields.date';
export const SETTING_DASHBOARD_CONTENT_CARD_TITLE = 'dashboard.content.card.fields.title';
export const SETTING_DASHBOARD_CONTENT_CARD_DESCRIPTION =
'dashboard.content.card.fields.description';
export const SETTING_DATA_FILES = 'data.files';
export const SETTING_DATA_FOLDERS = 'data.folders';
export const SETTING_DATA_TYPES = 'data.types';
@@ -11,7 +11,6 @@ import { useEffect, useMemo, useState } from 'react';
import useThemeColors from '../../hooks/useThemeColors';
import { Status } from './Status';
import * as React from 'react';
import { messageHandler } from '@estruyf/vscode/dist/client';
export interface IItemProps extends Page { }
@@ -28,25 +27,51 @@ export const Item: React.FunctionComponent<IItemProps> = ({
const view = useRecoilValue(ViewSelector);
const settings = useRecoilValue(SettingsSelector);
const draftField = useMemo(() => settings?.draftField, [settings]);
const cardFields = useMemo(() => settings?.dashboardState?.contents?.cardFields, [settings?.dashboardState?.contents?.cardFields]);
const [imageHtml, setImageHtml] = useState<string | undefined>(undefined);
const [footerHtml, setFooterHtml] = useState<string | undefined>(undefined);
const { getColors } = useThemeColors();
const escapedTitle = useMemo(() => {
if (title && typeof title !== 'string') {
console.log('escapedTitle', title, cardFields?.title, pageData);
let value = title;
if (cardFields?.title) {
if (cardFields.title === "description") {
value = description;
} else if (cardFields?.title !== "title") {
value = pageData[cardFields?.title] || title;
}
} else if (cardFields?.title === null) {
return null;
}
if (value && typeof value !== 'string') {
return '<invalid title>';
}
return title;
}, [title]);
return value;
}, [title, description, cardFields?.title, pageData]);
const escapedDescription = useMemo(() => {
if (description && typeof description !== 'string') {
let value = description;
if (cardFields?.description) {
if (cardFields.description === "title") {
value = title;
} else if (cardFields?.description !== "description") {
value = pageData[cardFields?.description] || description;
}
} else if (cardFields?.description === null) {
return null;
}
if (value && typeof value !== 'string') {
return '<invalid description>';
}
return description;
}, [description]);
return value;
}, [description, title, cardFields?.description, pageData]);
const openFile = () => {
Messenger.send(DashboardMessage.openFile, fmFilePath);
@@ -77,6 +102,10 @@ export const Item: React.FunctionComponent<IItemProps> = ({
return [];
}, [settings, pageData]);
const hasDraftOrDate = useMemo(() => {
return cardFields && (cardFields.state || cardFields.date);
}, [cardFields]);
useEffect(() => {
if (window.fmExternal && window.fmExternal.getCardFooter) {
window.fmExternal.getCardFooter(fmFilePath, {
@@ -137,7 +166,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
pageData[PREVIEW_IMAGE_FIELD] ? (
<img
src={`${pageData[PREVIEW_IMAGE_FIELD]}`}
alt={escapedTitle}
alt={escapedTitle || ""}
className="absolute inset-0 h-full w-full object-cover group-hover:brightness-75"
loading="lazy"
/>
@@ -160,21 +189,27 @@ export const Item: React.FunctionComponent<IItemProps> = ({
</button>
<div className="relative p-4 w-full grow">
<div className={`flex justify-between items-center`}>
{draftField && draftField.name && <Status draft={pageData[draftField.name]} />}
<div className={`flex justify-between items-center ${hasDraftOrDate ? `mb-2` : ``}`}>
{
cardFields?.state && draftField && draftField.name && <Status draft={pageData[draftField.name]} />
}
<DateField className={`mr-4`} value={date} />
<ContentActions
title={title}
path={fmFilePath}
scripts={settings?.scripts}
onOpen={openFile}
/>
{
cardFields?.date && <DateField className={`mr-4`} value={date} />
}
</div>
<ContentActions
title={title}
path={fmFilePath}
scripts={settings?.scripts}
onOpen={openFile}
/>
<button onClick={openFile} className={`text-left block`}>
<h2 className="mt-2 mb-2 font-bold">{escapedTitle}</h2>
<h2 className="mb-2 font-bold">
{escapedTitle}
</h2>
</button>
<button onClick={openFile} className={`text-left block`}>
@@ -226,7 +261,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
</button>
<ContentActions
title={escapedTitle}
title={escapedTitle || ""}
path={fmFilePath}
scripts={settings?.scripts}
onOpen={openFile}
+8
View File
@@ -58,6 +58,14 @@ export interface ContentsViewState {
tags: string | null | undefined;
templatesEnabled: boolean | null | undefined;
pagination: boolean | number | null | undefined;
cardFields: CardFields;
}
export interface CardFields {
state: boolean | undefined;
date: boolean | undefined;
title: string | null | undefined;
description: string | null | undefined;
}
export interface MediaViewState extends ContentsViewState {
+12 -2
View File
@@ -25,7 +25,11 @@ import {
SETTING_TEMPLATES_ENABLED,
SETTING_GIT_ENABLED,
SETTING_DASHBOARD_CONTENT_PAGINATION,
SETTING_SNIPPETS_WRAPPER
SETTING_SNIPPETS_WRAPPER,
SETTING_DASHBOARD_CONTENT_CARD_DATE,
SETTING_DASHBOARD_CONTENT_CARD_TITLE,
SETTING_DASHBOARD_CONTENT_CARD_STATE,
SETTING_DASHBOARD_CONTENT_CARD_DESCRIPTION
} from '../constants';
import {
DashboardViewType,
@@ -99,7 +103,13 @@ export class DashboardSettings {
defaultSorting: Settings.get<string>(SETTING_CONTENT_SORTING_DEFAULT),
tags: Settings.get<string>(SETTING_DASHBOARD_CONTENT_TAGS),
templatesEnabled: Settings.get<boolean>(SETTING_TEMPLATES_ENABLED),
pagination: pagination !== undefined ? pagination : true
pagination: pagination !== undefined ? pagination : true,
cardFields: {
state: Settings.get<string>(SETTING_DASHBOARD_CONTENT_CARD_STATE),
date: Settings.get<string>(SETTING_DASHBOARD_CONTENT_CARD_DATE),
title: Settings.get<string>(SETTING_DASHBOARD_CONTENT_CARD_TITLE),
description: Settings.get<string>(SETTING_DASHBOARD_CONTENT_CARD_DESCRIPTION)
}
},
media: {
sorting: await ext.getState<SortingOption | undefined>(
+24 -8
View File
@@ -3,11 +3,16 @@ import { basename } from 'path';
import { commands, FileSystemWatcher, RelativePattern, TextDocument, Uri, workspace } from 'vscode';
import { Dashboard } from '../../commands/Dashboard';
import { Folders } from '../../commands/Folders';
import { COMMAND_NAME, ExtensionState } from '../../constants';
import {
COMMAND_NAME,
ExtensionState,
SETTING_DASHBOARD_CONTENT_CARD_DESCRIPTION,
SETTING_DASHBOARD_CONTENT_CARD_TITLE
} from '../../constants';
import { DashboardCommand } from '../../dashboardWebView/DashboardCommand';
import { DashboardMessage } from '../../dashboardWebView/DashboardMessage';
import { Page } from '../../dashboardWebView/models';
import { ArticleHelper, Extension, Logger } from '../../helpers';
import { ArticleHelper, Extension, Logger, Settings } from '../../helpers';
import { BaseListener } from './BaseListener';
import { DataListener } from '../panel';
import Fuse from 'fuse.js';
@@ -219,13 +224,24 @@ export class PagesListener extends BaseListener {
* Search the pages
*/
private static async searchPages(data: { query: string }) {
const fieldKeys = [
{ name: 'title', weight: 1 },
{ name: 'fmBody', weight: 1 },
{ name: 'slug', weight: 0.5 },
{ name: 'description', weight: 0.5 }
];
const cardTitle = Settings.get(SETTING_DASHBOARD_CONTENT_CARD_TITLE);
if (cardTitle) {
fieldKeys.push({ name: cardTitle as string, weight: 1 });
}
const cardDescription = Settings.get(SETTING_DASHBOARD_CONTENT_CARD_DESCRIPTION);
if (cardTitle) {
fieldKeys.push({ name: cardDescription as string, weight: 0.5 });
}
const fuseOptions: Fuse.IFuseOptions<Page> = {
keys: [
{ name: 'title', weight: 1 },
{ name: 'fmBody', weight: 1 },
{ name: 'slug', weight: 0.5 },
{ name: 'description', weight: 0.5 }
],
keys: fieldKeys,
includeScore: true,
ignoreLocation: true,
threshold: 0.1