diff --git a/backend/api/project/models/project.settings.json b/backend/api/project/models/project.settings.json index f76104e..2697ae4 100644 --- a/backend/api/project/models/project.settings.json +++ b/backend/api/project/models/project.settings.json @@ -51,10 +51,10 @@ "blocks": { "type": "dynamiczone", "components": [ - "project.title-block", "project.blockquote-block", "project.image-block", - "project.paragraph-block" + "project.paragraph-block", + "project.list-block" ], "pluginOptions": { "i18n": { diff --git a/backend/components/blocks/list-item.json b/backend/components/blocks/list-item.json new file mode 100644 index 0000000..524687d --- /dev/null +++ b/backend/components/blocks/list-item.json @@ -0,0 +1,13 @@ +{ + "collectionName": "components_blocks_list_items", + "info": { + "name": "listItem", + "icon": "ban" + }, + "options": {}, + "attributes": { + "text": { + "type": "string" + } + } +} diff --git a/backend/components/project/list-block.json b/backend/components/project/list-block.json new file mode 100644 index 0000000..a749d21 --- /dev/null +++ b/backend/components/project/list-block.json @@ -0,0 +1,15 @@ +{ + "collectionName": "components_project_list_blocks", + "info": { + "name": "listBlock", + "icon": "list-ul" + }, + "options": {}, + "attributes": { + "items": { + "type": "component", + "repeatable": true, + "component": "blocks.list-item" + } + } +} diff --git a/backend/components/project/title-block.json b/backend/components/project/title-block.json deleted file mode 100644 index 5b22e50..0000000 --- a/backend/components/project/title-block.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "collectionName": "components_project_title_blocks", - "info": { - "name": "titleBlock", - "icon": "angle-up" - }, - "options": {}, - "attributes": { - "title": { - "type": "string" - } - } -} diff --git a/frontend/features/project/blocks/ListBlock.tsx b/frontend/features/project/blocks/ListBlock.tsx new file mode 100644 index 0000000..c430639 --- /dev/null +++ b/frontend/features/project/blocks/ListBlock.tsx @@ -0,0 +1,57 @@ +import React from "react"; +import { + Block, + BlockComponentProps, + BlocksControls, + InlineBlocks, +} from "react-tinacms-inline"; + +import { Box } from "@chakra-ui/react"; +import { listItemBlock } from "./ListItemBlock"; + +export type ListBlockData = BlockTemplateData< + "listBlock", + { + id: string; + items: { + text: Nullable[]; + }; + } +>; + +export default function ListBlock() { + return ( + + + + ); +} + +function BlockComponent({ index, data }: BlockComponentProps) { + return ( + + + + ); +} + +export const listBlock: Block = { + Component: BlockComponent, + template: { + label: "List block", + defaultItem: { + blocks: [], + }, + fields: [], + }, +}; diff --git a/frontend/features/project/blocks/ListItemBlock.tsx b/frontend/features/project/blocks/ListItemBlock.tsx new file mode 100644 index 0000000..a90f6cd --- /dev/null +++ b/frontend/features/project/blocks/ListItemBlock.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { + Block, + BlockComponentProps, + BlocksControls, + InlineText, +} from "react-tinacms-inline"; + +import { Box } from "@chakra-ui/react"; + +export type ListItemBlockData = BlockTemplateData< + "listItemBlock", + { + id: string; + text: string; + } +>; + +export default function ListItemBlock() { + return ( + + + + ); +} + +function BlockComponent({ index, data }: BlockComponentProps) { + return ( + + + + ); +} + +export const listItemBlock: Block = { + Component: BlockComponent, + template: { + label: "List item block", + defaultItem: { + text: "Default item text", + }, + fields: [], + }, +}; diff --git a/frontend/graphql.schema.json b/frontend/graphql.schema.json index ea85a05..cdb37ae 100644 --- a/frontend/graphql.schema.json +++ b/frontend/graphql.schema.json @@ -265,7 +265,69 @@ }, { "kind": "OBJECT", - "name": "ComponentBlocksLink", + "name": "ComponentBlocksListItem", + "description": null, + "fields": [ + { + "name": "id", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "text", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "ComponentBlocksListItemInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "text", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "ComponentBlocksNavigationBlock", "description": null, "fields": [ { @@ -861,7 +923,17 @@ "defaultValue": null, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "ComponentProjectListBlock", + "description": null, + "fields": [ { "name": "legalCompanyName", "description": null, @@ -891,24 +963,44 @@ "deprecationReason": null }, { - "name": "primaryEmail", + "name": "items", "description": null, "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "ComponentBlocksListItem", + "ofType": null + } }, "defaultValue": null, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "ComponentProjectListBlockInput", + "description": null, + "fields": null, + "inputFields": [ { - "name": "vatId", + "name": "items", "description": null, "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "ComponentBlocksListItemInput", + "ofType": null + } }, "defaultValue": null, "isDeprecated": false, @@ -921,7 +1013,7 @@ }, { "kind": "OBJECT", - "name": "ComponentGlobalFooter", + "name": "ComponentProjectParagraphBlock", "description": null, "fields": [ { @@ -937,7 +1029,7 @@ "deprecationReason": null }, { - "name": "id", + "name": "text", "description": null, "args": [], "type": { @@ -960,12 +1052,12 @@ }, { "kind": "INPUT_OBJECT", - "name": "ComponentGlobalFooterInput", + "name": "ComponentProjectParagraphBlockInput", "description": null, "fields": null, "inputFields": [ { - "name": "description", + "name": "text", "description": null, "type": { "kind": "SCALAR", @@ -4794,7 +4886,12 @@ }, { "kind": "OBJECT", - "name": "deleteGlobalPayload", + "name": "ComponentBlocksListItem", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "ComponentBlocksNavigationBlock", "ofType": null }, { @@ -4824,12 +4921,12 @@ }, { "kind": "OBJECT", - "name": "updateFormMessagePayload", + "name": "ComponentProjectListBlock", "ofType": null }, { "kind": "OBJECT", - "name": "updateGlobalPayload", + "name": "ComponentProjectParagraphBlock", "ofType": null }, { @@ -7358,6 +7455,47 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "UNION", + "name": "ProjectBlocksDynamicZone", + "description": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "ComponentProjectBlockquoteBlock", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "ComponentProjectImageBlock", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "ComponentProjectParagraphBlock", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "ComponentProjectListBlock", + "ofType": null + } + ] + }, + { + "kind": "SCALAR", + "name": "ProjectBlocksDynamicZoneInput", + "description": "Input type for dynamic zone blocks of Project", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "ProjectConnectionPath", @@ -13769,7 +13907,172 @@ }, { "kind": "INPUT_OBJECT", - "name": "createRoleInput", + "name": "editComponentBlocksCardInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "id", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "title", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "image", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "url", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "label", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "editComponentBlocksListItemInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "id", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "text", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "editComponentBlocksNavigationBlockInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "id", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "label", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "url", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "editComponentBlocksSingleFeatureInput", "description": null, "fields": null, "inputFields": [ @@ -14114,7 +14417,7 @@ }, { "kind": "INPUT_OBJECT", - "name": "deleteRoleInput", + "name": "editComponentProjectListBlockInput", "description": null, "fields": null, "inputFields": [ @@ -14141,13 +14444,17 @@ "description": null, "fields": [ { - "name": "role", + "name": "items", "description": null, "args": [], "type": { - "kind": "OBJECT", - "name": "UsersPermissionsRole", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "editComponentBlocksListItemInput", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null @@ -14160,7 +14467,7 @@ }, { "kind": "INPUT_OBJECT", - "name": "deleteUserInput", + "name": "editComponentProjectParagraphBlockInput", "description": null, "fields": null, "inputFields": [ @@ -14187,7 +14494,7 @@ "description": null, "fields": [ { - "name": "user", + "name": "text", "description": null, "args": [], "type": { diff --git a/frontend/graphql/generated.ts b/frontend/graphql/generated.ts index dcd8671..174786f 100644 --- a/frontend/graphql/generated.ts +++ b/frontend/graphql/generated.ts @@ -53,8 +53,18 @@ export type ComponentBlocksCardInput = { url: Scalars['String']; }; -export type ComponentBlocksLink = { - __typename?: 'ComponentBlocksLink'; +export type ComponentBlocksListItem = { + __typename?: 'ComponentBlocksListItem'; + id: Scalars['ID']; + text?: Maybe; +}; + +export type ComponentBlocksListItemInput = { + text?: Maybe; +}; + +export type ComponentBlocksNavigationBlock = { + __typename?: 'ComponentBlocksNavigationBlock'; id: Scalars['ID']; label?: Maybe; url?: Maybe; @@ -185,6 +195,16 @@ export type ComponentProjectImageBlockInput = { image?: Maybe; }; +export type ComponentProjectListBlock = { + __typename?: 'ComponentProjectListBlock'; + id: Scalars['ID']; + items?: Maybe>>; +}; + +export type ComponentProjectListBlockInput = { + items?: Maybe>>; +}; + export type ComponentProjectParagraphBlock = { __typename?: 'ComponentProjectParagraphBlock'; id: Scalars['ID']; @@ -520,7 +540,7 @@ export type MenuInput = { updated_by?: Maybe; }; -export type Morph = ComponentBlocksCard | ComponentBlocksLink | ComponentBlocksSingleFeature | ComponentBlocksSocialBubble | ComponentGlobalCompanyData | ComponentGlobalFooter | ComponentGlobalHeadquarter | ComponentGlobalTopbar | ComponentProjectBlockquoteBlock | ComponentProjectImageBlock | ComponentProjectParagraphBlock | ComponentSectionCardSection | ComponentSectionContactsSection | ComponentSectionHeroSection | ComponentSectionSimpleSection | ComponentSectionSingleFeatureSection | FormMessages | FormMessagesAggregator | FormMessagesConnection | FormMessagesConnectionCreated_At | FormMessagesConnectionEmail | FormMessagesConnectionId | FormMessagesConnectionMessage | FormMessagesConnectionName | FormMessagesConnectionPublished_At | FormMessagesConnectionUpdated_At | FormMessagesGroupBy | Global | I18NLocale | Menu | MenuAggregator | MenuConnection | MenuConnectionCreated_At | MenuConnectionId | MenuConnectionLocale | MenuConnectionPublished_At | MenuConnectionTitle | MenuConnectionUpdated_At | MenuGroupBy | Page | PageAggregator | PageConnection | PageConnectionCreated_At | PageConnectionId | PageConnectionLocale | PageConnectionPath | PageConnectionPublished_At | PageConnectionTitle | PageConnectionUpdated_At | PageGroupBy | Project | ProjectAggregator | ProjectConnection | ProjectConnectionCompanyName | ProjectConnectionCreated_At | ProjectConnectionDescription | ProjectConnectionId | ProjectConnectionImage | ProjectConnectionLinkLabel | ProjectConnectionLinkPath | ProjectConnectionLocale | ProjectConnectionPath | ProjectConnectionProjectType | ProjectConnectionPublished_At | ProjectConnectionUpdated_At | ProjectGroupBy | UploadFile | UploadFileAggregator | UploadFileAggregatorAvg | UploadFileAggregatorMax | UploadFileAggregatorMin | UploadFileAggregatorSum | UploadFileConnection | UploadFileConnectionAlternativeText | UploadFileConnectionCaption | UploadFileConnectionCreated_At | UploadFileConnectionExt | UploadFileConnectionFormats | UploadFileConnectionHash | UploadFileConnectionHeight | UploadFileConnectionId | UploadFileConnectionMime | UploadFileConnectionName | UploadFileConnectionPreviewUrl | UploadFileConnectionProvider | UploadFileConnectionProvider_Metadata | UploadFileConnectionSize | UploadFileConnectionUpdated_At | UploadFileConnectionUrl | UploadFileConnectionWidth | UploadFileGroupBy | UserPermissionsPasswordPayload | UsersPermissionsLoginPayload | UsersPermissionsMe | UsersPermissionsMeRole | UsersPermissionsPermission | UsersPermissionsRole | UsersPermissionsRoleAggregator | UsersPermissionsRoleConnection | UsersPermissionsRoleConnectionDescription | UsersPermissionsRoleConnectionId | UsersPermissionsRoleConnectionName | UsersPermissionsRoleConnectionType | UsersPermissionsRoleGroupBy | UsersPermissionsUser | UsersPermissionsUserAggregator | UsersPermissionsUserConnection | UsersPermissionsUserConnectionBlocked | UsersPermissionsUserConnectionConfirmed | UsersPermissionsUserConnectionCreated_At | UsersPermissionsUserConnectionEmail | UsersPermissionsUserConnectionId | UsersPermissionsUserConnectionProvider | UsersPermissionsUserConnectionRole | UsersPermissionsUserConnectionUpdated_At | UsersPermissionsUserConnectionUsername | UsersPermissionsUserGroupBy | CreateFormMessagePayload | CreateMenuPayload | CreatePagePayload | CreateProjectPayload | CreateRolePayload | CreateUserPayload | DeleteFilePayload | DeleteFormMessagePayload | DeleteGlobalPayload | DeleteMenuPayload | DeletePagePayload | DeleteProjectPayload | DeleteRolePayload | DeleteUserPayload | UpdateFormMessagePayload | UpdateGlobalPayload | UpdateMenuPayload | UpdatePagePayload | UpdateProjectPayload | UpdateRolePayload | UpdateUserPayload; +export type Morph = UsersPermissionsMe | UsersPermissionsMeRole | UsersPermissionsLoginPayload | UserPermissionsPasswordPayload | Global | UpdateGlobalPayload | DeleteGlobalPayload | Menu | MenuConnection | MenuAggregator | MenuGroupBy | MenuConnectionId | MenuConnectionCreated_At | MenuConnectionUpdated_At | MenuConnectionTitle | MenuConnectionPublished_At | CreateMenuPayload | UpdateMenuPayload | DeleteMenuPayload | Pages | PagesConnection | PagesAggregator | PagesGroupBy | PagesConnectionId | PagesConnectionCreated_At | PagesConnectionUpdated_At | PagesConnectionTitle | PagesConnectionPath | PagesConnectionLocale | PagesConnectionPublished_At | CreatePagePayload | UpdatePagePayload | DeletePagePayload | Project | ProjectConnection | ProjectAggregator | ProjectGroupBy | ProjectConnectionId | ProjectConnectionCreated_At | ProjectConnectionUpdated_At | ProjectConnectionProjectType | ProjectConnectionLinkPath | ProjectConnectionLinkLabel | ProjectConnectionDescription | ProjectConnectionPath | ProjectConnectionCompanyName | ProjectConnectionImage | ProjectConnectionLocale | ProjectConnectionPublished_At | CreateProjectPayload | UpdateProjectPayload | DeleteProjectPayload | I18NLocale | UploadFile | UploadFileConnection | UploadFileAggregator | UploadFileAggregatorSum | UploadFileAggregatorAvg | UploadFileAggregatorMin | UploadFileAggregatorMax | UploadFileGroupBy | UploadFileConnectionId | UploadFileConnectionCreated_At | UploadFileConnectionUpdated_At | UploadFileConnectionName | UploadFileConnectionAlternativeText | UploadFileConnectionCaption | UploadFileConnectionWidth | UploadFileConnectionHeight | UploadFileConnectionFormats | UploadFileConnectionHash | UploadFileConnectionExt | UploadFileConnectionMime | UploadFileConnectionSize | UploadFileConnectionUrl | UploadFileConnectionPreviewUrl | UploadFileConnectionProvider | UploadFileConnectionProvider_Metadata | DeleteFilePayload | UsersPermissionsPermission | UsersPermissionsRole | UsersPermissionsRoleConnection | UsersPermissionsRoleAggregator | UsersPermissionsRoleGroupBy | UsersPermissionsRoleConnectionId | UsersPermissionsRoleConnectionName | UsersPermissionsRoleConnectionDescription | UsersPermissionsRoleConnectionType | CreateRolePayload | UpdateRolePayload | DeleteRolePayload | UsersPermissionsUser | UsersPermissionsUserConnection | UsersPermissionsUserAggregator | UsersPermissionsUserGroupBy | UsersPermissionsUserConnectionId | UsersPermissionsUserConnectionCreated_At | UsersPermissionsUserConnectionUpdated_At | UsersPermissionsUserConnectionUsername | UsersPermissionsUserConnectionEmail | UsersPermissionsUserConnectionProvider | UsersPermissionsUserConnectionConfirmed | UsersPermissionsUserConnectionBlocked | UsersPermissionsUserConnectionRole | CreateUserPayload | UpdateUserPayload | DeleteUserPayload | ComponentBlocksCard | ComponentBlocksListItem | ComponentBlocksNavigationBlock | ComponentBlocksSingleFeature | ComponentGlobalTopbar | ComponentMenuPageLink | ComponentProjectBlockquoteBlock | ComponentProjectImageBlock | ComponentProjectListBlock | ComponentProjectParagraphBlock | ComponentSectionCardSection | ComponentSectionFooterSection | ComponentSectionHeroSection | ComponentSectionProjectsSection | ComponentSectionSimpleSection | ComponentSectionSingleFeatureSection; export type Mutation = { __typename?: 'Mutation'; @@ -865,7 +885,7 @@ export type ProjectAggregator = { totalCount?: Maybe; }; -export type ProjectBlocksDynamicZone = ComponentProjectBlockquoteBlock | ComponentProjectImageBlock | ComponentProjectParagraphBlock; +export type ProjectBlocksDynamicZone = ComponentProjectBlockquoteBlock | ComponentProjectImageBlock | ComponentProjectParagraphBlock | ComponentProjectListBlock; export type ProjectConnection = { @@ -1748,7 +1768,12 @@ export type EditComponentBlocksCardInput = { url?: Maybe; }; -export type EditComponentBlocksLinkInput = { +export type EditComponentBlocksListItemInput = { + id?: Maybe; + text?: Maybe; +}; + +export type EditComponentBlocksNavigationBlockInput = { id?: Maybe; label?: Maybe; url?: Maybe; @@ -1814,6 +1839,11 @@ export type EditComponentProjectImageBlockInput = { image?: Maybe; }; +export type EditComponentProjectListBlockInput = { + id?: Maybe; + items?: Maybe>>; +}; + export type EditComponentProjectParagraphBlockInput = { id?: Maybe; text?: Maybe; @@ -2062,11 +2092,45 @@ export type GetGlobalQueryVariables = Exact<{ [key: string]: never; }>; export type GetGlobalQuery = { __typename?: 'Query', global?: Maybe<{ __typename?: 'Global', id: string, topbar?: Maybe<{ __typename?: 'ComponentGlobalTopbar', id: string, menu?: Maybe<{ __typename?: 'Menu', id: string, title: string, links?: Maybe, url?: Maybe }>>> }> }>, companyData?: Maybe<{ __typename?: 'ComponentGlobalCompanyData', id: string, primaryEmail?: Maybe, companyName?: Maybe, copyright?: Maybe, vatId?: Maybe, capital?: Maybe, additionalLegalInfo?: Maybe, locations?: Maybe, provinceInitials?: Maybe, type?: Maybe, street?: Maybe, city?: Maybe, cap?: Maybe }>>> }>, footer?: Maybe<{ __typename?: 'ComponentGlobalFooter', id: string, description?: Maybe }> }> }; export type GetProjectsQueryVariables = Exact<{ + where?: Maybe; locale?: Maybe; }>; -export type GetProjectsQuery = { __typename?: 'Query', projects?: Maybe, linkLabel?: Maybe, projectType?: Maybe, companyName?: Maybe, description?: Maybe, path?: Maybe, locale?: Maybe, localizations?: Maybe, locale?: Maybe }>>>, image?: Maybe<{ __typename?: 'UploadFile', id: string, url: string, alternativeText?: Maybe }>, blocks?: Maybe } | { __typename: 'ComponentProjectImageBlock', id: string, image?: Maybe<{ __typename?: 'UploadFile', id: string, url: string, alternativeText?: Maybe }> } | { __typename: 'ComponentProjectParagraphBlock', id: string, text?: Maybe }>>> }>>> }; +export type GetProjectsQuery = ( + { __typename?: 'Query' } + & { projects?: Maybe + & { localizations?: Maybe + )>>>, image?: Maybe<( + { __typename?: 'UploadFile' } + & Pick + )>, blocks?: Maybe + ) | ( + { __typename: 'ComponentProjectImageBlock' } + & Pick + & { image?: Maybe<( + { __typename?: 'UploadFile' } + & Pick + )> } + ) | ( + { __typename: 'ComponentProjectParagraphBlock' } + & Pick + ) | ( + { __typename?: 'ComponentProjectListBlock' } + & Pick + & { items?: Maybe + )>>> } + )>>> } + )>>> } +); export type SaveChangesMutationVariables = Exact<{ pageInput?: Maybe; @@ -2084,6 +2148,29 @@ export type UpdateMenuMutationVariables = Exact<{ export type UpdateMenuMutation = { __typename?: 'Mutation', updateMenu?: Maybe<{ __typename?: 'updateMenuPayload', menu?: Maybe<{ __typename?: 'Menu', id: string }> }> }; +export type UpdateProjectMutationVariables = Exact<{ + projectInput?: Maybe; + menuInput?: Maybe; +}>; + + +export type UpdateProjectMutation = ( + { __typename?: 'Mutation' } + & { updateProject?: Maybe<( + { __typename?: 'updateProjectPayload' } + & { project?: Maybe<( + { __typename?: 'Project' } + & Pick + )> } + )>, updateMenu?: Maybe<( + { __typename?: 'updateMenuPayload' } + & { menu?: Maybe<( + { __typename?: 'Menu' } + & Pick + )> } + )> } +); + export const GetPages = ` query GetPages($where: JSON, $locale: String) { @@ -2233,8 +2320,8 @@ export const GetGlobal = ` } `; export const GetProjects = ` - query getProjects($locale: String) { - projects(locale: $locale) { + query getProjects($where: JSON, $locale: String) { + projects(where: $where, locale: $locale) { id linkPath linkLabel @@ -2273,6 +2360,13 @@ export const GetProjects = ` id text } + ... on ComponentProjectListBlock { + id + items { + id + text + } + } } } } @@ -2314,5 +2408,19 @@ export const UpdateMenu = ` id } } +} + `; +export const UpdateProject = ` + mutation updateProject($projectInput: updateProjectInput, $menuInput: updateMenuInput) { + updateProject(input: $projectInput) { + project { + id + } + } + updateMenu(input: $menuInput) { + menu { + id + } + } } `; \ No newline at end of file diff --git a/frontend/graphql/getProjects.graphql b/frontend/graphql/getProjects.graphql index 8f3902d..3f64146 100644 --- a/frontend/graphql/getProjects.graphql +++ b/frontend/graphql/getProjects.graphql @@ -1,5 +1,5 @@ -query getProjects($locale: String) { - projects(locale: $locale) { +query getProjects($where: JSON, $locale: String) { + projects(where: $where, locale: $locale) { id linkPath linkLabel @@ -38,6 +38,13 @@ query getProjects($locale: String) { id text } + ... on ComponentProjectListBlock { + id + items { + id + text + } + } } } } diff --git a/frontend/graphql/updateProject.graphql b/frontend/graphql/updateProject.graphql new file mode 100644 index 0000000..d93f966 --- /dev/null +++ b/frontend/graphql/updateProject.graphql @@ -0,0 +1,16 @@ +mutation updateProject( + $projectInput: updateProjectInput + $menuInput: updateMenuInput +) { + updateProject(input: $projectInput) { + project { + id + } + } + + updateMenu(input: $menuInput) { + menu { + id + } + } +} diff --git a/frontend/pages/[[...slug]].tsx b/frontend/pages/[[...slug]].tsx index f7ecb79..ee336ea 100644 --- a/frontend/pages/[[...slug]].tsx +++ b/frontend/pages/[[...slug]].tsx @@ -73,7 +73,6 @@ const StyledInlineBlocks = chakra(InlineBlocks); export default function DynamicPage({ data, preview }: DynamicPageProps) { const { colorMode } = useColorMode(); - const itemProps = React.useMemo(() => { return { isPreview: preview, @@ -214,7 +213,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { return { paths, fallback: false }; }; -function wrap(value: T | T[]): T[] { +export function wrap(value: T | T[]): T[] { if (Array.isArray(value)) { return value; } @@ -504,7 +503,7 @@ function getPageData( path: page.path ? page.path : undefined, localizations: page.localizations ? filterListNullableItems( - page.localizations?.map((localization) => { + page.localizations.map((localization) => { return { id: localization?.id, locale: localization?.locale, diff --git a/frontend/pages/projects/[...handle].tsx b/frontend/pages/projects/[...handle].tsx new file mode 100644 index 0000000..8947a7f --- /dev/null +++ b/frontend/pages/projects/[...handle].tsx @@ -0,0 +1,443 @@ +import { Box, Img, Text } from "@chakra-ui/react"; +import { + LocaleMenu, + LocaleMenuButton, + LocaleMenuList, + LocaleMenuLink, +} from "@components/LocaleMenu"; +import { MobileNavDrawer } from "@components/MobileNavDrawer"; +import { WordmarkLogo } from "@components/WordmarkLogo"; +import { + NavBar, + NavMenuMobile, + NavMenuDesktop, +} from "@features/mainNavigation"; +import { + GetGlobal, + GetGlobalQuery, + GetGlobalQueryVariables, + GetProjects, + GetProjectsQuery, + GetProjectsQueryVariables, + UpdateMenuInput, + UpdateProject, + UpdateProjectInput, +} from "@graphql/generated"; +import { fetchGraphQL } from "@graphql/utils"; +import { SiteLayout } from "@layouts/siteLayout"; +import { + GlobalData, + LocalizationsData, + MenuData, +} from "@plugins/usePagePlugin"; +import { filterListNullableItems } from "@utils"; +import { GetStaticPaths, GetStaticProps } from "next"; +import { useRouter } from "next/router"; +import { wrap } from "pages/[[...slug]]"; +import React from "react"; +import { InlineForm, InlineText } from "react-tinacms-inline"; +import { useCMS, useForm, usePlugin } from "tinacms"; +import { FormOptions } from "tinacms"; +import { Form } from "tinacms"; +import { getGlobalData } from "."; +import NextLink from "next/link"; +import { STRAPI_URL } from "@config/env"; + +interface ProjectData { + id: string; + path: string; + linkPath: Nullable; + linkLabel: Nullable; + description: Nullable; + locale: Nullable; + companyName: Nullable; + projectType: Nullable; + image: Nullable; + localizations?: LocalizationsData[]; + blocks: string; +} + +interface ProjectImage { + id: string; + url: string; + alternativeText: Nullable; +} + +interface DynamicPageProps { + locale: string; + preview: boolean; + data: { + global: GlobalData; + project: ProjectData; + }; +} + +export default function DynamicPage({ data: data }: DynamicPageProps) { + const [_, form] = useProjectPlugin(data); + const router = useRouter(); + + return ( + + + + + + + + + + + + + + + + {router.locale!.toUpperCase()} + + + + {router.locale?.toUpperCase()} + + {data ? ( + data.project.localizations?.map((pageLocale) => { + return ( + + {pageLocale.locale?.toUpperCase()} + + ); + }) + ) : ( + + )} + + + + + + + + + + + + + + + + + + + + + + + Blocks + + + + + + ); +} + +export const getStaticPaths: GetStaticPaths = async (context) => { + if (context.locales == null) { + throw new Error("No locale has been defined!"); + } + const allProjectsRequests = context.locales.map(async (locale) => { + const localeProjects = await fetchGraphQL< + GetProjectsQuery, + GetProjectsQueryVariables + >(GetProjects, { + locale, + }); + + if (localeProjects.projects) { + return filterListNullableItems(localeProjects.projects); + } + return []; + }); + + const allProjects = await Promise.all(allProjectsRequests); + const projects = allProjects.flat(); + + const paths = projects.map((page) => { + const pagePath = page.path?.replace(/^\/+/, "") || ""; + + const slugArray: any = + pagePath.length > 0 ? pagePath.split("/") : undefined; + + return { + params: { handle: slugArray }, + locale: page.locale!, + }; + }); + + return { paths, fallback: "blocking" }; +}; + +export const getStaticProps: GetStaticProps< + DynamicPageProps | { notFound: boolean } +> = async (context) => { + const pathParts = wrap(context.params?.handle || []); + const path = `/projects/${pathParts.join("/")}`; + const locale = context.locale; + if (locale == null) { + throw new Error(`Path "${pathParts.join("/")}" has no locale!`); + } + const preview = context.preview === true; + + const availableProjects = await fetchGraphQL< + GetProjectsQuery, + GetProjectsQueryVariables + >(GetProjects, { + locale, + where: { + path, + }, + }); + + if (availableProjects.projects == null) { + return { + notFound: true, + }; + } + + const availableGlobal = await fetchGraphQL< + GetGlobalQuery, + GetGlobalQueryVariables + >(GetGlobal); + + if (availableGlobal.global == null) { + return { + notFound: true, + }; + } + + const projectData = getProjectData(availableProjects.projects, locale); + + const globalData = getGlobalData(availableGlobal.global); + + if (projectData == null) { + return { + notFound: true, + }; + } + + if (globalData == null) { + return { + notFound: true, + }; + } + + if (preview) { + return { + props: { + path: pathParts, + locale, + preview, + previewData: context.previewData, + data: { + global: globalData, + project: projectData, + }, + }, + }; + } + + return { + props: { + path: pathParts, + locale, + preview, + data: { + global: globalData, + project: projectData, + }, + }, + }; +}; + +function getProjectData( + projects: GetProjectsQuery["projects"], + locale: string +): ProjectData | undefined { + const project = projects?.find((project) => project?.locale === locale); + if (project == null) { + return undefined; + } + return { + id: project.id, + companyName: project.companyName || null, + description: project.description || null, + projectType: project.projectType || null, + linkLabel: project.linkLabel || null, + linkPath: project.linkPath || null, + path: project.path, + locale: project.locale || null, + blocks: "aa", + image: project.image + ? { + id: project.image.id, + url: project.image.url, + alternativeText: project.image.alternativeText || null, + } + : null, + localizations: project.localizations + ? filterListNullableItems(project.localizations).map( + (localization) => { + return { + id: localization.id, + locale: localization.locale || null, + path: localization.path || null, + }; + } + ) + : [], + }; +} + +function getProjectInput(data: ProjectData): UpdateProjectInput { + return { + where: { id: data.id }, + data: { + companyName: data.companyName, + description: data.description, + projectType: data.projectType?.toUpperCase(), + linkLabel: data.linkLabel, + linkPath: data.linkPath, + path: data.path, + locale: data.locale, + blocks: undefined, + image: data.image ? data.image.id : null, + }, + }; +} + +interface Data { + project: ProjectData; + global: GlobalData; +} + +function useProjectPlugin(data: Data): [Data, Form] { + const cms = useCMS(); + const formConfig: FormOptions = { + id: data.project.id, + label: "Project settings", + initialValues: data, + onSubmit: async (data) => { + const projectInput = getProjectInput(data.project); + const menuInput = getMenuInput(data.global.topbar.menu); + try { + const response = await cms.api.strapi.fetchGraphql(UpdateProject, { + projectInput: projectInput, + menuInput: menuInput, + }); + + if (response.errors != null) { + cms.alerts.error("Error while saving data", 10000); + } else { + if (response.data) { + cms.alerts.success("Changes saved!"); + } else { + cms.alerts.error("Error while saving changes"); + } + } + } catch (error) { + console.log(error); + cms.alerts.error("Error while saving changes"); + } + }, + fields: [], + }; + + const [formData, form] = useForm(formConfig, { values: data }); + usePlugin(form); + + return [formData, form]; +} + +function getMenuInput(data: MenuData): UpdateMenuInput { + return { + where: { id: data.id }, + data: { + title: data.title, + links: data.links.map((link) => { + return { + id: link.id, + label: link.label || null, + url: link.url || null, + }; + }), + }, + }; +} diff --git a/frontend/pages/projects/index.tsx b/frontend/pages/projects/index.tsx index 0f6ae6b..d225642 100644 --- a/frontend/pages/projects/index.tsx +++ b/frontend/pages/projects/index.tsx @@ -498,7 +498,7 @@ function getMenuInput(data: GlobalData): UpdateMenuInput { }; } -function getGlobalData( +export function getGlobalData( global: GetGlobalQuery["global"] ): GlobalData | undefined { if (global == null) { diff --git a/frontend/theme/index.ts b/frontend/theme/index.ts index 4923ea0..d5e329d 100644 --- a/frontend/theme/index.ts +++ b/frontend/theme/index.ts @@ -57,6 +57,14 @@ const overrides: ThemeOverride = { }, }, }, + styles: { + global: { + body: { + fontSize: "sm", + letterSpacing: "0.02em", + }, + }, + }, }; const customTheme = extendTheme(overrides);