Improved handling of null values when entering tags frontmatter
This commit is contained in:
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@@ -2,6 +2,7 @@
|
|||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"alipay",
|
"alipay",
|
||||||
"frontmatter",
|
"frontmatter",
|
||||||
|
"Frontmatters",
|
||||||
"giscus",
|
"giscus",
|
||||||
"github",
|
"github",
|
||||||
"micromessenger",
|
"micromessenger",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { TPostListItem, TTagSubPostSet } from "@/types/post-list";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { serialize } from "next-mdx-remote/serialize";
|
import { serialize } from "next-mdx-remote/serialize";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { capitalizeFirstLetter, nullifyEmptyString } from "./utils";
|
import { isEmptyString, nullifyEmptyArray, nullifyEmptyString } from "./utils";
|
||||||
|
|
||||||
async function getFrontmatters(filepath: string): Promise<TFrontmatter> {
|
async function getFrontmatters(filepath: string): Promise<TFrontmatter> {
|
||||||
const source = fs.readFileSync(filepath, "utf-8");
|
const source = fs.readFileSync(filepath, "utf-8");
|
||||||
@@ -45,7 +45,10 @@ const sortOutPostLists = async (): Promise<{
|
|||||||
for (let i = 0; i < postFilePaths.length; i++) {
|
for (let i = 0; i < postFilePaths.length; i++) {
|
||||||
const frontmatter = await getFrontmatters(postFilePaths[i]);
|
const frontmatter = await getFrontmatters(postFilePaths[i]);
|
||||||
const postId = path.parse(postFilePaths[i]).name;
|
const postId = path.parse(postFilePaths[i]).name;
|
||||||
const normalizedTags = frontmatter.tags?.map((tagname) => tagname.toUpperCase());
|
|
||||||
|
const normalizedTags = frontmatter.tags
|
||||||
|
?.filter((tagname) => !isEmptyString(tagname))
|
||||||
|
.map((tagname) => tagname.toUpperCase());
|
||||||
|
|
||||||
const postListItem: TPostListItem = {
|
const postListItem: TPostListItem = {
|
||||||
id: postId,
|
id: postId,
|
||||||
@@ -53,7 +56,7 @@ const sortOutPostLists = async (): Promise<{
|
|||||||
title: frontmatter.title,
|
title: frontmatter.title,
|
||||||
subtitle: nullifyEmptyString(frontmatter.subtitle),
|
subtitle: nullifyEmptyString(frontmatter.subtitle),
|
||||||
coverURL: nullifyEmptyString(frontmatter.coverURL),
|
coverURL: nullifyEmptyString(frontmatter.coverURL),
|
||||||
tags: normalizedTags ?? [],
|
tags: nullifyEmptyArray(normalizedTags),
|
||||||
summary: nullifyEmptyString(frontmatter.summary),
|
summary: nullifyEmptyString(frontmatter.summary),
|
||||||
time: frontmatter.time,
|
time: frontmatter.time,
|
||||||
pin: frontmatter.pin ?? false,
|
pin: frontmatter.pin ?? false,
|
||||||
|
|||||||
46
lib/utils.ts
46
lib/utils.ts
@@ -1,3 +1,4 @@
|
|||||||
|
import { NonEmptyArray } from "@/types/utils.type";
|
||||||
import { clsx, type ClassValue } from "clsx";
|
import { clsx, type ClassValue } from "clsx";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
@@ -33,13 +34,10 @@ export function paginateArray<T = any>(array: T[], pageSize: number, pageNumber:
|
|||||||
* @returns return `null` if the input belongs to "", undefined and null.
|
* @returns return `null` if the input belongs to "", undefined and null.
|
||||||
*/
|
*/
|
||||||
export function nullifyEmptyString(value: string | null | undefined): string | null {
|
export function nullifyEmptyString(value: string | null | undefined): string | null {
|
||||||
if (value == null) {
|
if (isEmptyString(value)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (value.trim() === "") {
|
return value!;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,7 +46,7 @@ export function nullifyEmptyString(value: string | null | undefined): string | n
|
|||||||
* @returns return `true` if the input belongs to "", undefined and null.
|
* @returns return `true` if the input belongs to "", undefined and null.
|
||||||
*/
|
*/
|
||||||
export function isEmptyString(value: string | null | undefined): boolean {
|
export function isEmptyString(value: string | null | undefined): boolean {
|
||||||
if (value == null) {
|
if (value === null || value === undefined) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (value.trim() === "") {
|
if (value.trim() === "") {
|
||||||
@@ -57,6 +55,42 @@ export function isEmptyString(value: string | null | undefined): boolean {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes empty values from an array.
|
||||||
|
* @param value - The array to remove empty values from.
|
||||||
|
* @returns The array without empty values.
|
||||||
|
* @template T - The type of the array elements.
|
||||||
|
*/
|
||||||
|
export function removeEmptyValuesFromArray<T = any>(value: any[]): T[] {
|
||||||
|
return value.filter((item) => item != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an array is empty.
|
||||||
|
* @param value - The array to check.
|
||||||
|
* @returns True if the array is empty, false otherwise.
|
||||||
|
*/
|
||||||
|
export function isEmptyArray(value: any[] | null | undefined): boolean {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return removeEmptyValuesFromArray(value).length !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nullifies an empty array.
|
||||||
|
*
|
||||||
|
* @template T - The type of the array elements.
|
||||||
|
* @param value - The array value to be nullified if empty.
|
||||||
|
* @returns The nullified array if it is empty, otherwise returns the original array.
|
||||||
|
*/
|
||||||
|
export function nullifyEmptyArray<T>(value: T[] | null | undefined): NonEmptyArray<T> | null {
|
||||||
|
if (isEmptyArray(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return value as NonEmptyArray<T>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Capitalizes the first letter of each word in a string.
|
* Capitalizes the first letter of each word in a string.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export default function PostsPage(props: PostsPageProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChangePageNumber = (event: ChangeEvent<HTMLInputElement>) => {
|
const handleInputPageNumber = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
setPageNumber(event.target.value);
|
setPageNumber(event.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ export default function PostsPage(props: PostsPageProps) {
|
|||||||
<div className="my-auto font-bold flex justify-center">
|
<div className="my-auto font-bold flex justify-center">
|
||||||
<Input
|
<Input
|
||||||
onKeyDown={handleEnterKeyJump}
|
onKeyDown={handleEnterKeyJump}
|
||||||
onChange={handleChangePageNumber}
|
onChange={handleInputPageNumber}
|
||||||
className="my-auto mx-2 w-11 h-6"
|
className="my-auto mx-2 w-11 h-6"
|
||||||
value={pageNumber}
|
value={pageNumber}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Footer } from "@/components/utils/Footer";
|
|||||||
import { NavBar } from "@/components/utils/NavBar";
|
import { NavBar } from "@/components/utils/NavBar";
|
||||||
import { SEO } from "@/components/utils/SEO";
|
import { SEO } from "@/components/utils/SEO";
|
||||||
import { Config } from "@/data/config";
|
import { Config } from "@/data/config";
|
||||||
|
import { isEmptyString } from "@/lib/utils";
|
||||||
import { fontFangZhengXiaoBiaoSongCN, fontSourceSerifScreenCN } from "@/styles/font";
|
import { fontFangZhengXiaoBiaoSongCN, fontSourceSerifScreenCN } from "@/styles/font";
|
||||||
import { TSearchResultItem } from "@/types/search-result";
|
import { TSearchResultItem } from "@/types/search-result";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
@@ -30,7 +31,7 @@ export default function SearchPage() {
|
|||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
setSearchResult(data);
|
setSearchResult(data);
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
toast({ title: "Empty Result", description: "Change the keyword please." });
|
toast({ title: "Empty Result", description: "No results were found for this keyword. Try another keyword." });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
@@ -47,6 +48,10 @@ export default function SearchPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleMakeSearch = () => {
|
const handleMakeSearch = () => {
|
||||||
|
if (isEmptyString(searchText)) {
|
||||||
|
toast({ title: "Enter a Keyword", description: "Please enter one keyword at least." });
|
||||||
|
return;
|
||||||
|
}
|
||||||
querySearch.refetch();
|
querySearch.refetch();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export default function TagsContentPage(props: TagsContentPageProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChangePageNumber = (event: ChangeEvent<HTMLInputElement>) => {
|
const handleInputPageNumber = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
setPageNumber(event.target.value);
|
setPageNumber(event.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ export default function TagsContentPage(props: TagsContentPageProps) {
|
|||||||
<div className="my-auto font-bold flex justify-center">
|
<div className="my-auto font-bold flex justify-center">
|
||||||
<Input
|
<Input
|
||||||
onKeyDown={handleEnterKeyJump}
|
onKeyDown={handleEnterKeyJump}
|
||||||
onChange={handleChangePageNumber}
|
onChange={handleInputPageNumber}
|
||||||
className="my-auto mx-2 w-11 h-6"
|
className="my-auto mx-2 w-11 h-6"
|
||||||
value={pageNumber}
|
value={pageNumber}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import { NonEmptyArray } from "./utils.type";
|
||||||
|
|
||||||
export type TFrontmatter = {
|
export type TFrontmatter = {
|
||||||
title: string;
|
title: string;
|
||||||
time: string;
|
time: string;
|
||||||
tags: string[] | null;
|
tags: NonEmptyArray<string> | null;
|
||||||
subtitle: string | null;
|
subtitle: string | null;
|
||||||
summary: string | null;
|
summary: string | null;
|
||||||
coverURL: string | null;
|
coverURL: string | null;
|
||||||
|
|||||||
1
types/utils.type.ts
Normal file
1
types/utils.type.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export type NonEmptyArray<T> = [T, ...T[]];
|
||||||
Reference in New Issue
Block a user