Display the news articles

This commit is contained in:
DrMint 2022-03-17 17:05:34 +01:00
parent 1f1c17a3a8
commit 151ae0b126
10 changed files with 517 additions and 27 deletions

View File

@ -167,7 +167,7 @@ export default function Markdawn(props: ScenBreakProps): JSX.Element {
},
InsetBox: {
component: (props) => {
return <InsetBox>{props.children}</InsetBox>;
return <InsetBox className="my-12">{props.children}</InsetBox>;
},
},
li: {

View File

@ -0,0 +1,64 @@
import Link from "next/link";
import { prettyDate, prettySlug } from "queries/helpers";
import Chip from "components/Chip";
import Img, { ImageQuality } from "components/Img";
import { GetPostsPreviewQuery } from "graphql/operations-types";
export type PostPreviewProps = {
post: {
slug: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["slug"];
thumbnail: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["thumbnail"];
translations: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["translations"];
categories: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["categories"];
date: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["date"];
};
};
export default function PostPreview(props: PostPreviewProps): JSX.Element {
const post = props.post;
return (
<Link href={"/news/" + post.slug} passHref>
<div className="drop-shadow-shade-xl cursor-pointer grid items-end hover:scale-[1.02] transition-transform">
{post.thumbnail.data ? (
<Img
className="rounded-md rounded-b-none"
image={post.thumbnail.data.attributes}
quality={ImageQuality.Medium}
/>
) : (
<div className="w-full aspect-[3/2] bg-light rounded-lg"></div>
)}
<div className="linearbg-obi fine:drop-shadow-shade-lg rounded-b-md top-full transition-opacity z-20 grid p-4 gap-2">
<div className="grid grid-flow-col w-full">
{post.date && (
<p className="mobile:text-xs text-sm">
<span className="material-icons !text-base translate-y-[.15em] mr-1">
event
</span>
{prettyDate(post.date)}
</p>
)}
</div>
<div>
{post.translations.length > 0 ? (
<>
<h1 className="text-xl">{post.translations[0].title}</h1>
<p>{post.translations[0].excerpt}</p>
</>
) : (
<h1 className="text-lg">{prettySlug(post.slug)}</h1>
)}
</div>
<div className="grid grid-flow-col gap-1 overflow-x-scroll webkit-scrollbar:w-0 [scrollbar-width:none] place-content-start">
{post.categories.data.map((category) => (
<Chip key={category.id} className="text-sm">
{category.attributes.short}
</Chip>
))}
</div>
</div>
</div>
</Link>
);
}

View File

@ -1155,8 +1155,12 @@ query getPost($slug: String, $language_code: String) {
id
attributes {
slug
publishedAt
updatedAt
date {
year
month
day
}
authors {
data {
id
@ -1200,8 +1204,20 @@ query getPost($slug: String, $language_code: String) {
}
}
hidden
thumbnail {
data {
attributes {
name
alternativeText
caption
width
height
url
}
}
}
translations(filters: { language: { code: { eq: $language_code } } }) {
Status
status
title
excerpt
thumbnail {
@ -1222,3 +1238,66 @@ query getPost($slug: String, $language_code: String) {
}
}
}
query getPostsSlugs {
posts(filters: { hidden: { eq: false } }) {
data {
id
attributes {
slug
}
}
}
}
query getPostsPreview($language_code: String) {
posts(filters: { hidden: { eq: false } }) {
data {
id
attributes {
slug
date {
year
month
day
}
categories {
data {
id
attributes {
short
}
}
}
thumbnail {
data {
attributes {
name
alternativeText
caption
width
height
url
}
}
}
translations(filters: { language: { code: { eq: $language_code } } }) {
title
excerpt
thumbnail {
data {
attributes {
name
alternativeText
caption
width
height
url
}
}
}
}
}
}
}
}

View File

@ -1554,8 +1554,13 @@ export type GetPostQuery = {
attributes: {
__typename: "Post";
slug: string;
publishedAt: any;
updatedAt: any;
date: {
__typename: "ComponentBasicsDatepicker";
year: number;
month: number;
day: number;
};
hidden: boolean;
authors: {
__typename: "RecorderRelationResponseCollection";
@ -1609,9 +1614,24 @@ export type GetPostQuery = {
};
}>;
};
thumbnail: {
__typename: "UploadFileEntityResponse";
data: {
__typename: "UploadFileEntity";
attributes: {
__typename: "UploadFile";
name: string;
alternativeText: string;
caption: string;
width: number;
height: number;
url: string;
};
};
};
translations: Array<{
__typename: "ComponentTranslationsPosts";
Status: Enum_Componenttranslationsposts_Status;
status: Enum_Componenttranslationsposts_Status;
title: string;
excerpt: string;
body: string;
@ -1635,3 +1655,85 @@ export type GetPostQuery = {
}>;
};
};
export type GetPostsSlugsQueryVariables = Exact<{ [key: string]: never }>;
export type GetPostsSlugsQuery = {
__typename: "Query";
posts: {
__typename: "PostEntityResponseCollection";
data: Array<{
__typename: "PostEntity";
id: string;
attributes: { __typename: "Post"; slug: string };
}>;
};
};
export type GetPostsPreviewQueryVariables = Exact<{
language_code: InputMaybe<Scalars["String"]>;
}>;
export type GetPostsPreviewQuery = {
__typename: "Query";
posts: {
__typename: "PostEntityResponseCollection";
data: Array<{
__typename: "PostEntity";
id: string;
attributes: {
__typename: "Post";
slug: string;
date: {
__typename: "ComponentBasicsDatepicker";
year: number;
month: number;
day: number;
};
categories: {
__typename: "CategoryRelationResponseCollection";
data: Array<{
__typename: "CategoryEntity";
id: string;
attributes: { __typename: "Category"; short: string };
}>;
};
thumbnail: {
__typename: "UploadFileEntityResponse";
data: {
__typename: "UploadFileEntity";
attributes: {
__typename: "UploadFile";
name: string;
alternativeText: string;
caption: string;
width: number;
height: number;
url: string;
};
};
};
translations: Array<{
__typename: "ComponentTranslationsPosts";
title: string;
excerpt: string;
thumbnail: {
__typename: "UploadFileEntityResponse";
data: {
__typename: "UploadFileEntity";
attributes: {
__typename: "UploadFile";
name: string;
alternativeText: string;
caption: string;
width: number;
height: number;
url: string;
};
};
};
}>;
};
}>;
};
};

View File

@ -25,6 +25,10 @@ import {
GetLibraryItemsSlugsQueryVariables,
GetPostQuery,
GetPostQueryVariables,
GetPostsPreviewQuery,
GetPostsPreviewQueryVariables,
GetPostsSlugsQuery,
GetPostsSlugsQueryVariables,
GetWebsiteInterfaceQuery,
GetWebsiteInterfaceQueryVariables,
} from "graphql/operations-types";
@ -150,3 +154,17 @@ export async function getPost(
const query = getQueryFromOperations("getPost");
return await graphQL(query, JSON.stringify(variables));
}
export async function getPostsSlugs(
variables: GetPostsSlugsQueryVariables
): Promise<GetPostsSlugsQuery> {
const query = getQueryFromOperations("getPostsSlugs");
return await graphQL(query, JSON.stringify(variables));
}
export async function getPostsPreview(
variables: GetPostsPreviewQueryVariables
): Promise<GetPostsPreviewQuery> {
const query = getQueryFromOperations("getPostsPreview");
return await graphQL(query, JSON.stringify(variables));
}

View File

@ -26,11 +26,6 @@ type ResponseCollectionMeta {
pagination: Pagination!
}
enum PublicationState {
LIVE
PREVIEW
}
input IDFilterInput {
and: [ID]
or: [ID]
@ -387,6 +382,8 @@ input ComponentCollectionsComponentLibraryObiBeltInput {
back: ID
full: ID
inside_full: ID
flap_front: ID
flap_back: ID
}
type ComponentCollectionsComponentLibraryObiBelt {
@ -396,6 +393,8 @@ type ComponentCollectionsComponentLibraryObiBelt {
back: UploadFileEntityResponse
full: UploadFileEntityResponse
inside_full: UploadFileEntityResponse
flap_front: UploadFileEntityResponse
flap_back: UploadFileEntityResponse
}
input ComponentCollectionsComponentTitlesFiltersInput {
@ -1057,11 +1056,11 @@ enum ENUM_COMPONENTTRANSLATIONSPOSTS_STATUS {
}
input ComponentTranslationsPostsFiltersInput {
Status: StringFilterInput
title: StringFilterInput
excerpt: StringFilterInput
body: StringFilterInput
language: LanguageFiltersInput
status: StringFilterInput
and: [ComponentTranslationsPostsFiltersInput]
or: [ComponentTranslationsPostsFiltersInput]
not: ComponentTranslationsPostsFiltersInput
@ -1069,22 +1068,22 @@ input ComponentTranslationsPostsFiltersInput {
input ComponentTranslationsPostsInput {
id: ID
Status: ENUM_COMPONENTTRANSLATIONSPOSTS_STATUS
title: String
excerpt: String
thumbnail: ID
body: String
language: ID
status: ENUM_COMPONENTTRANSLATIONSPOSTS_STATUS
}
type ComponentTranslationsPosts {
id: ID!
Status: ENUM_COMPONENTTRANSLATIONSPOSTS_STATUS!
title: String!
excerpt: String
thumbnail: UploadFileEntityResponse
body: String
language: LanguageEntityResponse
status: ENUM_COMPONENTTRANSLATIONSPOSTS_STATUS!
}
enum ENUM_COMPONENTTRANSLATIONSSCANSET_STATUS {
@ -2126,7 +2125,6 @@ input PostFiltersInput {
hidden: BooleanFilterInput
createdAt: DateTimeFilterInput
updatedAt: DateTimeFilterInput
publishedAt: DateTimeFilterInput
and: [PostFiltersInput]
or: [PostFiltersInput]
not: PostFiltersInput
@ -2138,7 +2136,7 @@ input PostInput {
categories: [ID]
translations: [ComponentTranslationsPostsInput]
hidden: Boolean
publishedAt: DateTime
thumbnail: ID
}
type Post {
@ -2159,9 +2157,9 @@ type Post {
sort: [String] = []
): [ComponentTranslationsPosts]
hidden: Boolean!
thumbnail: UploadFileEntityResponse
createdAt: DateTime
updatedAt: DateTime
publishedAt: DateTime
}
type PostEntity {
@ -3206,7 +3204,6 @@ type Query {
filters: PostFiltersInput
pagination: PaginationArg = {}
sort: [String] = []
publicationState: PublicationState = LIVE
): PostEntityResponseCollection
rangedContent(id: ID): RangedContentEntityResponse
rangedContents(

View File

@ -40,7 +40,28 @@ export default function ContentIndex(props: ContentIndexProps): JSX.Element {
className="mb-10"
/>
<div className="grid place-items-center">
<ThumbnailHeader content={content} langui={langui} />
<ThumbnailHeader
thumbnail={content.thumbnail}
pre_title={
content.titles.length > 0 ? content.titles[0].pre_title : undefined
}
title={
content.titles.length > 0
? content.titles[0].title
: prettySlug(content.slug)
}
subtitle={
content.titles.length > 0 ? content.titles[0].subtitle : undefined
}
description={
content.titles.length > 0
? content.titles[0].description
: undefined
}
type={content.type}
categories={content.categories}
langui={langui}
/>
<HorizontalLine />

View File

@ -1,9 +1,6 @@
import { GetStaticPaths, GetStaticProps } from "next";
import { getContentsSlugs, getContentText } from "graphql/operations";
import {
Enum_Componentsetstextset_Status,
GetContentTextQuery,
} from "graphql/operations-types";
import { GetContentTextQuery } from "graphql/operations-types";
import ContentPanel from "components/Panels/ContentPanel";
import HorizontalLine from "components/HorizontalLine";
import SubPanel from "components/Panels/SubPanel";
@ -158,13 +155,34 @@ export default function ContentRead(props: ContentReadProps): JSX.Element {
<ContentPanel>
<ReturnButton
href={`/contents/${content.slug}`}
title={"Content"}
title={langui.content}
langui={langui}
displayOn={ReturnButtonType.Mobile}
className="mb-10"
/>
<div className="grid place-items-center">
<ThumbnailHeader content={content} langui={langui} />
<ThumbnailHeader
thumbnail={content.thumbnail}
pre_title={
content.titles.length > 0 ? content.titles[0].pre_title : undefined
}
title={
content.titles.length > 0
? content.titles[0].title
: prettySlug(content.slug)
}
subtitle={
content.titles.length > 0 ? content.titles[0].subtitle : undefined
}
description={
content.titles.length > 0
? content.titles[0].description
: undefined
}
type={content.type}
categories={content.categories}
langui={langui}
/>
<HorizontalLine />

165
src/pages/news/[slug].tsx Normal file
View File

@ -0,0 +1,165 @@
import AppLayout from "components/AppLayout";
import Chip from "components/Chip";
import ThumbnailHeader from "components/Content/ThumbnailHeader";
import HorizontalLine from "components/HorizontalLine";
import Markdawn from "components/Markdown/Markdawn";
import TOC from "components/Markdown/TOC";
import ReturnButton, {
ReturnButtonType,
} from "components/PanelComponents/ReturnButton";
import ContentPanel from "components/Panels/ContentPanel";
import SubPanel from "components/Panels/SubPanel";
import RecorderChip from "components/RecorderChip";
import ToolTip from "components/ToolTip";
import { getPost, getPostsSlugs } from "graphql/operations";
import { GetPostQuery } from "graphql/operations-types";
import { GetStaticPaths, GetStaticProps } from "next";
import { useRouter } from "next/router";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
import { prettySlug, getStatusDescription } from "queries/helpers";
interface PostProps extends AppStaticProps {
post: GetPostQuery["posts"]["data"][number]["attributes"];
postId: GetPostQuery["posts"]["data"][number]["id"];
}
export default function LibrarySlug(props: PostProps): JSX.Element {
const { post, postId, langui } = props;
const router = useRouter();
const subPanel = (
<SubPanel>
<ReturnButton
href="/news"
title={langui.news}
langui={langui}
displayOn={ReturnButtonType.Desktop}
horizontalLine
/>
{post.translations.length > 0 && (
<div className="grid grid-flow-col place-items-center place-content-center gap-2">
<p className="font-headers">{langui.status}:</p>
<ToolTip
content={getStatusDescription(post.translations[0].status, langui)}
maxWidth={"20rem"}
>
<Chip>{post.translations[0].status}</Chip>
</ToolTip>
</div>
)}
{post.authors.data.length > 0 && (
<div>
<p className="font-headers">{"Authors"}:</p>
<div className="grid place-items-center place-content-center gap-2">
{post.authors.data.map((author) => (
<RecorderChip key={author.id} langui={langui} recorder={author} />
))}
</div>
</div>
)}
<HorizontalLine />
{post.translations.length > 0 && post.translations[0].body && (
<TOC
text={post.translations[0].body}
router={router}
title={post.translations[0].title}
/>
)}
</SubPanel>
);
const contentPanel = (
<ContentPanel>
<ReturnButton
href="/news"
title={langui.news}
langui={langui}
displayOn={ReturnButtonType.Mobile}
className="mb-10"
/>
<ThumbnailHeader
thumbnail={
post.translations.length > 0 && post.translations[0].thumbnail.data
? post.translations[0].thumbnail
: post.thumbnail
}
title={
post.translations.length > 0
? post.translations[0].title
: prettySlug(post.slug)
}
description={
post.translations.length > 0
? post.translations[0].excerpt
: undefined
}
langui={langui}
categories={post.categories}
/>
<HorizontalLine />
{post.translations.length > 0 && post.translations[0].body && (
<Markdawn text={post.translations[0].body} />
)}
</ContentPanel>
);
return (
<AppLayout
navTitle={langui.news}
title={
post.translations.length > 0
? post.translations[0].title
: prettySlug(post.slug)
}
contentPanel={contentPanel}
subPanel={subPanel}
thumbnail={post.translations[0].thumbnail.data?.attributes}
{...props}
/>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
const post = (
await getPost({
slug: context.params?.slug?.toString() || "",
language_code: context.locale || "en",
})
).posts.data[0];
const props: PostProps = {
...(await getAppStaticProps(context)),
post: post.attributes,
postId: post.id,
};
return {
props: props,
};
};
export const getStaticPaths: GetStaticPaths = async (context) => {
type Path = {
params: {
slug: string;
};
locale: string;
};
const data = await getPostsSlugs({});
const paths: Path[] = [];
data.posts.data.map((item) => {
context.locales?.map((local) => {
paths.push({ params: { slug: item.attributes.slug }, locale: local });
});
});
return {
paths,
fallback: false,
};
};

View File

@ -3,11 +3,17 @@ import PanelHeader from "components/PanelComponents/PanelHeader";
import { GetStaticProps } from "next";
import AppLayout from "components/AppLayout";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
import { GetPostsPreviewQuery } from "graphql/operations-types";
import { getPostsPreview } from "graphql/operations";
import ContentPanel, { ContentPanelWidthSizes } from "components/Panels/ContentPanel";
import PostsPreview from "components/News/PostsPreview";
interface NewsProps extends AppStaticProps {}
interface NewsProps extends AppStaticProps {
posts: GetPostsPreviewQuery["posts"]["data"];
}
export default function News(props: NewsProps): JSX.Element {
const { langui } = props;
const { langui, posts } = props;
const subPanel = (
<SubPanel>
<PanelHeader
@ -18,12 +24,32 @@ export default function News(props: NewsProps): JSX.Element {
</SubPanel>
);
return <AppLayout navTitle={langui.news} subPanel={subPanel} {...props} />;
const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.large}>
<div className="grid gap-8 items-end grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(20rem,1fr))]">
{posts.map((post) => (
<PostsPreview key={post.id} post={post.attributes} />
))}
</div>
</ContentPanel>
);
return (
<AppLayout
navTitle={langui.news}
subPanel={subPanel}
contentPanel={contentPanel}
{...props}
/>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
const props: NewsProps = {
...(await getAppStaticProps(context)),
posts: await (
await getPostsPreview({ language_code: context.locale || "en" })
).posts.data,
};
return {
props: props,