mirror of
https://github.com/sergeyyarkov/yarkov.tech.git
synced 2026-10-11 10:29:21 +03:00
graphql codegen
This commit is contained in:
parent
a4576db438
commit
e03cd19a78
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -1,3 +1,5 @@
|
|||||||
{
|
{
|
||||||
"githubPullRequests.ignoredPullRequestBranches": ["develop"]
|
"githubPullRequests.ignoredPullRequestBranches": ["develop"],
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
|
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||||
}
|
}
|
||||||
|
|||||||
31
codegen.ts
Normal file
31
codegen.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import type { CodegenConfig } from "@graphql-codegen/cli";
|
||||||
|
|
||||||
|
const config: CodegenConfig = {
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
[`${process.env.DIRECTUS_URL}/graphql`]: {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${process.env.DIRECTUS_TOKEN}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
documents: ["src/**/*.ts"],
|
||||||
|
ignoreNoDocuments: true,
|
||||||
|
generates: {
|
||||||
|
"./src/graphql/": {
|
||||||
|
preset: "client",
|
||||||
|
config: {
|
||||||
|
documentMode: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"./schema.graphql": {
|
||||||
|
plugins: ["schema-ast"],
|
||||||
|
config: {
|
||||||
|
includeDirectives: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
6648
package-lock.json
generated
6648
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@ -16,7 +16,8 @@
|
|||||||
"start": "node --env-file=.env ./dist/server/entry.mjs",
|
"start": "node --env-file=.env ./dist/server/entry.mjs",
|
||||||
"preview": "astro preview",
|
"preview": "astro preview",
|
||||||
"astro": "astro",
|
"astro": "astro",
|
||||||
"directus:gen-types": "node --env-file=.env ./scripts/gen-types.js"
|
"directus:gen-types": "node --env-file=.env ./scripts/gen-types.js",
|
||||||
|
"codegen": "graphql-codegen --require dotenv/config --config codegen.ts --watch"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/check": "^0.9.5",
|
"@astrojs/check": "^0.9.5",
|
||||||
@ -28,6 +29,7 @@
|
|||||||
"@iconify-json/mdi": "^1.2.3",
|
"@iconify-json/mdi": "^1.2.3",
|
||||||
"astro": "^5.15.8",
|
"astro": "^5.15.8",
|
||||||
"astro-icon": "^1.1.5",
|
"astro-icon": "^1.1.5",
|
||||||
|
"graphql": "^16.12.0",
|
||||||
"hast-util-select": "^6.0.4",
|
"hast-util-select": "^6.0.4",
|
||||||
"hast-util-to-string": "^3.0.0",
|
"hast-util-to-string": "^3.0.0",
|
||||||
"hastscript": "^8.0.0",
|
"hastscript": "^8.0.0",
|
||||||
@ -43,14 +45,19 @@
|
|||||||
"remark-toc": "^9.0.0",
|
"remark-toc": "^9.0.0",
|
||||||
"sharp": "^0.32.6",
|
"sharp": "^0.32.6",
|
||||||
"solid-js": "^1.7.12",
|
"solid-js": "^1.7.12",
|
||||||
"typescript": "^5.8.3",
|
|
||||||
"unified": "^11.0.5"
|
"unified": "^11.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@0no-co/graphqlsp": "^1.15.1",
|
||||||
|
"@graphql-codegen/cli": "^6.1.0",
|
||||||
|
"@graphql-codegen/schema-ast": "^5.0.0",
|
||||||
|
"@parcel/watcher": "^2.5.1",
|
||||||
"@types/html-escaper": "^3.0.4",
|
"@types/html-escaper": "^3.0.4",
|
||||||
"@types/mime-types": "^2.1.4",
|
"@types/mime-types": "^2.1.4",
|
||||||
"@types/remark-prism": "^1.3.7",
|
"@types/remark-prism": "^1.3.7",
|
||||||
"directus-sdk-typegen": "^0.2.1",
|
"directus-sdk-typegen": "^0.2.1",
|
||||||
"sass": "^1.68.0"
|
"dotenv": "^17.2.3",
|
||||||
|
"sass": "^1.68.0",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2394
schema.graphql
Normal file
2394
schema.graphql
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,10 +6,11 @@ import TagsList from "./TagsList";
|
|||||||
import ArticleItem from "@components/ArticleItem";
|
import ArticleItem from "@components/ArticleItem";
|
||||||
import "./ArticlesList.scss";
|
import "./ArticlesList.scss";
|
||||||
import type { ArticleTranslation } from "@/directus-schema";
|
import type { ArticleTranslation } from "@/directus-schema";
|
||||||
|
import { ArticleQuery } from "@/src/graphql/graphql";
|
||||||
|
|
||||||
type UiStringsType = { "articles.empty": string; "input.search": string };
|
type UiStringsType = { "articles.empty": string; "input.search": string };
|
||||||
|
|
||||||
type ArticlesBlockType = Record<string, ArticleTranslation[]>;
|
type ArticlesBlockType = Record<string, ArticleQuery["article"][0]["translations"]>;
|
||||||
|
|
||||||
type ArticlesListProps = {
|
type ArticlesListProps = {
|
||||||
articles: ArticlesBlockType;
|
articles: ArticlesBlockType;
|
||||||
|
|||||||
27
src/graphql/execute.ts
Normal file
27
src/graphql/execute.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import type { ExecutionResult } from "graphql";
|
||||||
|
import type { TypedDocumentString } from "./graphql";
|
||||||
|
import { DIRECTUS_URL, DIRECTUS_TOKEN } from "astro:env/server";
|
||||||
|
|
||||||
|
export default async function execute<TResult, TVariables>(
|
||||||
|
query: TypedDocumentString<TResult, TVariables>,
|
||||||
|
...[variables]: TVariables extends Record<string, never> ? [] : [TVariables]
|
||||||
|
) {
|
||||||
|
const response = await fetch(DIRECTUS_URL + "/graphql", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/graphql-response+json",
|
||||||
|
Authorization: `Bearer ${DIRECTUS_TOKEN}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
query,
|
||||||
|
variables,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Network response was not ok. ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json() as ExecutionResult<TResult>;
|
||||||
|
}
|
||||||
83
src/graphql/fragment-masking.ts
Normal file
83
src/graphql/fragment-masking.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
import { ResultOf, DocumentTypeDecoration } from '@graphql-typed-document-node/core';
|
||||||
|
import { Incremental, TypedDocumentString } from './graphql';
|
||||||
|
|
||||||
|
|
||||||
|
export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<
|
||||||
|
infer TType,
|
||||||
|
any
|
||||||
|
>
|
||||||
|
? [TType] extends [{ ' $fragmentName'?: infer TKey }]
|
||||||
|
? TKey extends string
|
||||||
|
? { ' $fragmentRefs'?: { [key in TKey]: TType } }
|
||||||
|
: never
|
||||||
|
: never
|
||||||
|
: never;
|
||||||
|
|
||||||
|
// return non-nullable if `fragmentType` is non-nullable
|
||||||
|
export function useFragment<TType>(
|
||||||
|
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||||
|
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>
|
||||||
|
): TType;
|
||||||
|
// return nullable if `fragmentType` is undefined
|
||||||
|
export function useFragment<TType>(
|
||||||
|
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||||
|
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | undefined
|
||||||
|
): TType | undefined;
|
||||||
|
// return nullable if `fragmentType` is nullable
|
||||||
|
export function useFragment<TType>(
|
||||||
|
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||||
|
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null
|
||||||
|
): TType | null;
|
||||||
|
// return nullable if `fragmentType` is nullable or undefined
|
||||||
|
export function useFragment<TType>(
|
||||||
|
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||||
|
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null | undefined
|
||||||
|
): TType | null | undefined;
|
||||||
|
// return array of non-nullable if `fragmentType` is array of non-nullable
|
||||||
|
export function useFragment<TType>(
|
||||||
|
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||||
|
fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>>
|
||||||
|
): Array<TType>;
|
||||||
|
// return array of nullable if `fragmentType` is array of nullable
|
||||||
|
export function useFragment<TType>(
|
||||||
|
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||||
|
fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
|
||||||
|
): Array<TType> | null | undefined;
|
||||||
|
// return readonly array of non-nullable if `fragmentType` is array of non-nullable
|
||||||
|
export function useFragment<TType>(
|
||||||
|
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||||
|
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
|
||||||
|
): ReadonlyArray<TType>;
|
||||||
|
// return readonly array of nullable if `fragmentType` is array of nullable
|
||||||
|
export function useFragment<TType>(
|
||||||
|
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||||
|
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
|
||||||
|
): ReadonlyArray<TType> | null | undefined;
|
||||||
|
export function useFragment<TType>(
|
||||||
|
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||||
|
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | Array<FragmentType<DocumentTypeDecoration<TType, any>>> | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
|
||||||
|
): TType | Array<TType> | ReadonlyArray<TType> | null | undefined {
|
||||||
|
return fragmentType as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function makeFragmentData<
|
||||||
|
F extends DocumentTypeDecoration<any, any>,
|
||||||
|
FT extends ResultOf<F>
|
||||||
|
>(data: FT, _fragment: F): FragmentType<F> {
|
||||||
|
return data as FragmentType<F>;
|
||||||
|
}
|
||||||
|
export function isFragmentReady<TQuery, TFrag>(
|
||||||
|
queryNode: TypedDocumentString<TQuery, any>,
|
||||||
|
fragmentNode: TypedDocumentString<TFrag, any>,
|
||||||
|
data: FragmentType<TypedDocumentString<Incremental<TFrag>, any>> | null | undefined
|
||||||
|
): data is FragmentType<typeof fragmentNode> {
|
||||||
|
const deferredFields = queryNode.__meta__?.deferredFields as Record<string, (keyof TFrag)[]>;
|
||||||
|
const fragName = fragmentNode.__meta__?.fragmentName as string | undefined;
|
||||||
|
|
||||||
|
if (!deferredFields || !fragName) return true;
|
||||||
|
|
||||||
|
const fields = deferredFields[fragName] ?? [];
|
||||||
|
return fields.length > 0 && fields.every(field => data && field in data);
|
||||||
|
}
|
||||||
38
src/graphql/gql.ts
Normal file
38
src/graphql/gql.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
import * as types from './graphql';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of all GraphQL operations in the project.
|
||||||
|
*
|
||||||
|
* This map has several performance disadvantages:
|
||||||
|
* 1. It is not tree-shakeable, so it will include all operations in the project.
|
||||||
|
* 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.
|
||||||
|
* 3. It does not support dead code elimination, so it will add unused operations.
|
||||||
|
*
|
||||||
|
* Therefore it is highly recommended to use the babel or swc plugin for production.
|
||||||
|
* Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size
|
||||||
|
*/
|
||||||
|
type Documents = {
|
||||||
|
"\n\t\tquery Article {\n\t\t\tarticle {\n\t\t\t\ttranslations(filter: { status: { _eq: \"published\" } }) {\n\t\t\t\t\tid\n\t\t\t\t\ttitle\n\t\t\t\t\ttags {\n\t\t\t\t\t\ttag_id {\n\t\t\t\t\t\t\ttitle\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdescription\n\t\t\t\t\tslug\n\t\t\t\t\tpub_date\n\t\t\t\t\tlanguages_code {\n\t\t\t\t\t\tcode\n\t\t\t\t\t\tname\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t": typeof types.ArticleDocument,
|
||||||
|
"\n\t\tquery Tag {\n\t\t\ttag {\n\t\t\t\tid\n\t\t\t\ttitle\n\t\t\t}\n\t\t}\n\t": typeof types.TagDocument,
|
||||||
|
};
|
||||||
|
const documents: Documents = {
|
||||||
|
"\n\t\tquery Article {\n\t\t\tarticle {\n\t\t\t\ttranslations(filter: { status: { _eq: \"published\" } }) {\n\t\t\t\t\tid\n\t\t\t\t\ttitle\n\t\t\t\t\ttags {\n\t\t\t\t\t\ttag_id {\n\t\t\t\t\t\t\ttitle\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdescription\n\t\t\t\t\tslug\n\t\t\t\t\tpub_date\n\t\t\t\t\tlanguages_code {\n\t\t\t\t\t\tcode\n\t\t\t\t\t\tname\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t": types.ArticleDocument,
|
||||||
|
"\n\t\tquery Tag {\n\t\t\ttag {\n\t\t\t\tid\n\t\t\t\ttitle\n\t\t\t}\n\t\t}\n\t": types.TagDocument,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
|
*/
|
||||||
|
export function graphql(source: "\n\t\tquery Article {\n\t\t\tarticle {\n\t\t\t\ttranslations(filter: { status: { _eq: \"published\" } }) {\n\t\t\t\t\tid\n\t\t\t\t\ttitle\n\t\t\t\t\ttags {\n\t\t\t\t\t\ttag_id {\n\t\t\t\t\t\t\ttitle\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdescription\n\t\t\t\t\tslug\n\t\t\t\t\tpub_date\n\t\t\t\t\tlanguages_code {\n\t\t\t\t\t\tcode\n\t\t\t\t\t\tname\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t"): typeof import('./graphql').ArticleDocument;
|
||||||
|
/**
|
||||||
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
|
*/
|
||||||
|
export function graphql(source: "\n\t\tquery Tag {\n\t\t\ttag {\n\t\t\t\tid\n\t\t\t\ttitle\n\t\t\t}\n\t\t}\n\t"): typeof import('./graphql').TagDocument;
|
||||||
|
|
||||||
|
|
||||||
|
export function graphql(source: string) {
|
||||||
|
return (documents as any)[source] ?? {};
|
||||||
|
}
|
||||||
4358
src/graphql/graphql.ts
Normal file
4358
src/graphql/graphql.ts
Normal file
File diff suppressed because it is too large
Load Diff
2
src/graphql/index.ts
Normal file
2
src/graphql/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./fragment-masking";
|
||||||
|
export * from "./gql";
|
||||||
33
src/queries/article.ts
Normal file
33
src/queries/article.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { graphql } from "../graphql";
|
||||||
|
import execute from "../graphql/execute";
|
||||||
|
|
||||||
|
export async function getArticleList() {
|
||||||
|
const ArticleQuery = graphql(`
|
||||||
|
query Article {
|
||||||
|
article {
|
||||||
|
translations(filter: { status: { _eq: "published" } }) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
tags {
|
||||||
|
tag_id {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
description
|
||||||
|
slug
|
||||||
|
pub_date
|
||||||
|
languages_code {
|
||||||
|
code
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
const result = await execute(ArticleQuery);
|
||||||
|
|
||||||
|
if (!result.data) return [];
|
||||||
|
|
||||||
|
return result.data.article;
|
||||||
|
}
|
||||||
2
src/queries/index.ts
Normal file
2
src/queries/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./tag";
|
||||||
|
export * from "./article";
|
||||||
19
src/queries/tag.ts
Normal file
19
src/queries/tag.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { graphql } from "../graphql";
|
||||||
|
import execute from "../graphql/execute";
|
||||||
|
|
||||||
|
export async function getTagList() {
|
||||||
|
const TagsQuery = graphql(`
|
||||||
|
query Tag {
|
||||||
|
tag {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
const result = await execute(TagsQuery);
|
||||||
|
|
||||||
|
if (!result.data) return [];
|
||||||
|
|
||||||
|
return result.data.tag;
|
||||||
|
}
|
||||||
@ -1,19 +1,20 @@
|
|||||||
---
|
---
|
||||||
import { useTranslation, getLanguageFromURL } from "@i18n/utils";
|
import { useTranslation, getLanguageFromURL } from "@i18n/utils";
|
||||||
import * as utils from "@utils/index";
|
import { removeArticleDuplicates, formatToArticleBlocks } from "@utils/article";
|
||||||
import PageLayout from "@layouts/default.astro";
|
import PageLayout from "@layouts/default.astro";
|
||||||
import PageHeading from "@components/PageHeading.astro";
|
import PageHeading from "@components/PageHeading.astro";
|
||||||
import ArticlesList from "@root/components/ArticlesList";
|
import ArticlesList from "@root/components/ArticlesList";
|
||||||
import { fetchTags, fetchArticles } from "@/directus";
|
import { getTagList } from "@root/queries/tag";
|
||||||
|
import { getArticleList } from "@root/queries/article";
|
||||||
|
|
||||||
const t = useTranslation(Astro);
|
const t = useTranslation(Astro);
|
||||||
const pageLang = getLanguageFromURL(Astro.url.pathname);
|
const pageLang = getLanguageFromURL(Astro.url.pathname);
|
||||||
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
|
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
|
||||||
const tags = (await fetchTags()).map((t) => t.title);
|
const tags = (await getTagList()).map((t) => t.title);
|
||||||
const articles = (await fetchArticles()).flatMap((a) =>
|
const articles = (await getArticleList()).flatMap((a) =>
|
||||||
utils.removeArticleDuplicates(a.translations, pageLang)
|
removeArticleDuplicates(a.translations, pageLang)
|
||||||
);
|
);
|
||||||
const articleBlocks = utils.formatToArticleBlocks(articles);
|
const articleBlocks = formatToArticleBlocks(articles);
|
||||||
---
|
---
|
||||||
|
|
||||||
<PageLayout
|
<PageLayout
|
||||||
|
|||||||
@ -1,26 +1,25 @@
|
|||||||
import type { MarkdownHeading } from "astro";
|
import type { MarkdownHeading } from "astro";
|
||||||
import { DEFAULT_LANGUAGE } from "@root/constants";
|
import { DEFAULT_LANGUAGE } from "@root/constants";
|
||||||
import type { ArticleTranslation } from "@/directus-schema";
|
import type { ArticleTranslation } from "@/directus-schema";
|
||||||
|
import { ArticleQuery } from "../graphql/graphql";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If there is a translation of an article in the current language of the page,
|
* If there is a translation of an article in the current language of the page,
|
||||||
* the remaining articles with other translations should be removed.
|
* the remaining articles with other translations should be removed.
|
||||||
*/
|
*/
|
||||||
export function removeArticleDuplicates(
|
export function removeArticleDuplicates(
|
||||||
articleTranslations: ArticleTranslation[] | null,
|
articles: ArticleQuery["article"][0]["translations"],
|
||||||
pageLang: LanguageKeys
|
pageLang: LanguageKeys
|
||||||
): ArticleTranslation[] {
|
) {
|
||||||
if (!articleTranslations) return [];
|
if (!articles) return [];
|
||||||
if (articleTranslations && articleTranslations.length >= 2) {
|
if (articles && articles.length >= 2) {
|
||||||
const pageLangArticles = articleTranslations.filter((a) => {
|
const pageLangArticles = articles.filter(
|
||||||
return (
|
(a) => a?.languages_code?.code.split("-")[0] === pageLang
|
||||||
typeof a.languages_code === "object" && a.languages_code.code.split("-")[0] === pageLang
|
);
|
||||||
);
|
|
||||||
});
|
|
||||||
if (pageLangArticles.length !== 0) return pageLangArticles;
|
if (pageLangArticles.length !== 0) return pageLangArticles;
|
||||||
return articleTranslations;
|
return articles;
|
||||||
}
|
}
|
||||||
return articleTranslations;
|
return articles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,20 +36,17 @@ export function createRelativeArticleUrl(
|
|||||||
return `${lang}/${prefix}/${date}/${slug}`;
|
return `${lang}/${prefix}/${date}/${slug}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatToArticleBlocks(articles: ArticleTranslation[]) {
|
export function formatToArticleBlocks(articles: ArticleQuery["article"][0]["translations"]) {
|
||||||
const blocks: Record<string, ArticleTranslation[]> = {};
|
const blocks: Record<string, ArticleQuery["article"][0]["translations"]> = {};
|
||||||
|
|
||||||
|
if (!articles) return {};
|
||||||
|
|
||||||
articles.forEach((a) => {
|
articles.forEach((a) => {
|
||||||
const year = new Date(a.pub_date).getFullYear();
|
const year = new Date(a?.pub_date).getFullYear();
|
||||||
if (!blocks[year]) blocks[year] = [];
|
if (!blocks[year]) blocks[year] = [];
|
||||||
blocks[year].push({
|
blocks[year].push(a);
|
||||||
id: a.id,
|
|
||||||
title: a.title,
|
|
||||||
tags: a.tags,
|
|
||||||
slug: a.slug,
|
|
||||||
pub_date: a.pub_date,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
"exclude": ["dist"],
|
"exclude": ["dist"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
|
"target": "esnext",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./*"],
|
"@/*": ["./*"],
|
||||||
@ -17,6 +18,13 @@
|
|||||||
"@hooks/*": ["./src/hooks/*"],
|
"@hooks/*": ["./src/hooks/*"],
|
||||||
"@i18n/*": ["./src/i18n/*"]
|
"@i18n/*": ["./src/i18n/*"]
|
||||||
},
|
},
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "@0no-co/graphqlsp",
|
||||||
|
"schema": "./schema.graphql"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"verbatimModuleSyntax": false,
|
||||||
"typeRoots": ["./node_modules/@types", "./src/types"],
|
"typeRoots": ["./node_modules/@types", "./src/types"],
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"jsxImportSource": "solid-js"
|
"jsxImportSource": "solid-js"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user