From aaae161044c62ede3b1c73e9bf7eff45f6308326 Mon Sep 17 00:00:00 2001 From: Truls Henrik Jakobsen Date: Wed, 27 Nov 2024 15:14:38 +0100 Subject: [PATCH 1/2] feat: Color Picker for Customer Cases --- package-lock.json | 88 +++++++++++++++++++ package.json | 1 + .../customerCase/CustomerCase.tsx | 45 +++++++++- .../projectInfo/CustomerCaseProjectInfo.tsx | 11 ++- studioShared/lib/interfaces/customerCases.ts | 8 ++ studioShared/lib/queries/customerCases.ts | 8 +- .../schemas/documents/customerCase.ts | 27 ++++++ studioShared/studioConfig.tsx | 2 + 8 files changed, 184 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 37f1fb773..fc2984528 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "sankitty", "version": "0.1.0", "dependencies": { + "@sanity/color-input": "^4.0.1", "@sanity/document-internationalization": "^3.0.1", "@sanity/image-url": "^1.0.2", "@sanity/preview-url-secret": "^1.6.11", @@ -3056,6 +3057,15 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@icons/material": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", + "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, "node_modules/@img/sharp-darwin-arm64": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", @@ -5021,6 +5031,39 @@ "node": ">=18.0.0" } }, + "node_modules/@sanity/color-input": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sanity/color-input/-/color-input-4.0.1.tgz", + "integrity": "sha512-Ra/IZO7j5vsx5VIF1OGIoeVfgwZu74tii8qOLuLQIRYbd6Av8si1mQFl6MOBu/kzWKWURE6JEN8+Ac1K2fi8Ww==", + "license": "MIT", + "dependencies": { + "@sanity/icons": "^3.4.0", + "@sanity/incompatible-plugin": "^1.0.4", + "@sanity/ui": "^2.8.9", + "react-color": "^2.19.3", + "use-effect-event": "^1.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18.3", + "sanity": "^3.23.0", + "styled-components": "^6.1" + } + }, + "node_modules/@sanity/color-input/node_modules/@sanity/icons": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@sanity/icons/-/icons-3.4.0.tgz", + "integrity": "sha512-X8BMM68w3y5cuCLpPwV7jGhVNGgAL/FA3UI6JaRCsyVOahA6aBOeKdjFs5MHtKi8cmrKwq1a98h/HbrK56kszA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^18.3 || >=19.0.0-rc" + } + }, "node_modules/@sanity/core-loader": { "version": "1.6.23", "resolved": "https://registry.npmjs.org/@sanity/core-loader/-/core-loader-1.6.23.tgz", @@ -19286,6 +19329,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -19449,6 +19498,12 @@ "react": ">= 0.14.0" } }, + "node_modules/material-colors": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", + "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==", + "license": "ISC" + }, "node_modules/md5-o-matic": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", @@ -22481,6 +22536,24 @@ "react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-color": { + "version": "2.19.3", + "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", + "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==", + "license": "MIT", + "dependencies": { + "@icons/material": "^0.2.4", + "lodash": "^4.17.15", + "lodash-es": "^4.17.15", + "material-colors": "^1.2.1", + "prop-types": "^15.5.10", + "reactcss": "^1.2.0", + "tinycolor2": "^1.4.1" + }, + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-colorful": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", @@ -22916,6 +22989,15 @@ "react-dom": ">=16 || >=17 || >= 18" } }, + "node_modules/reactcss": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", + "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", + "license": "MIT", + "dependencies": { + "lodash": "^4.0.1" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -26085,6 +26167,12 @@ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", "license": "MIT" }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" + }, "node_modules/tinyrainbow": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", diff --git a/package.json b/package.json index ef184eafd..31822d41e 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "test-storybook": "test-storybook" }, "dependencies": { + "@sanity/color-input": "^4.0.1", "@sanity/document-internationalization": "^3.0.1", "@sanity/image-url": "^1.0.2", "@sanity/preview-url-secret": "^1.6.11", diff --git a/src/components/customerCases/customerCase/CustomerCase.tsx b/src/components/customerCases/customerCase/CustomerCase.tsx index 1b499ca35..521cb7f01 100644 --- a/src/components/customerCases/customerCase/CustomerCase.tsx +++ b/src/components/customerCases/customerCase/CustomerCase.tsx @@ -26,13 +26,18 @@ export default async function CustomerCase({ return (
- - {customerCase.basicTitle} - +
{consultantsResult.ok && (
- +
)}
@@ -61,3 +66,35 @@ export default async function CustomerCase({
); } + +function ColoredTitle({ + title, + colorPart, + color, +}: { + title: string; + colorPart?: string; + color?: string; +}) { + if (colorPart === undefined || colorPart === "") + return ( + + {title} + + ); + + const startColorIndex = title.indexOf(colorPart); + const endColorIndex = startColorIndex + colorPart.length; + + const preColorText = title.slice(0, startColorIndex); + const colorText = title.slice(startColorIndex, endColorIndex); + const postColorText = title.slice(endColorIndex); + + return ( + + {preColorText} + {colorText} + {postColorText} + + ); +} diff --git a/src/components/customerCases/customerCase/projectInfo/CustomerCaseProjectInfo.tsx b/src/components/customerCases/customerCase/projectInfo/CustomerCaseProjectInfo.tsx index 3a9561cd3..e597d50d3 100644 --- a/src/components/customerCases/customerCase/projectInfo/CustomerCaseProjectInfo.tsx +++ b/src/components/customerCases/customerCase/projectInfo/CustomerCaseProjectInfo.tsx @@ -6,6 +6,7 @@ import Text from "src/components/text/Text"; import { LinkType } from "studio/lib/interfaces/navigation"; import { CustomerCaseProjectInfo as CustomerCaseCaseProjectInfoObject, + CustomerCaseClientColors, CustomerSector, } from "studioShared/lib/interfaces/customerCases"; @@ -13,10 +14,12 @@ import styles from "./customerCaseProjectInfo.module.css"; interface CustomerCaseProjectInfoProps { projectInfo: CustomerCaseCaseProjectInfoObject; + clientColors: CustomerCaseClientColors; } export default async function CustomerCaseProjectInfo({ projectInfo, + clientColors, }: CustomerCaseProjectInfoProps) { const t = await getTranslations("customer_case"); @@ -35,7 +38,13 @@ export default async function CustomerCaseProjectInfo({
{projectInfo.customerSectors.map((sector: CustomerSector) => ( - {sector.customerSector} + + {sector.customerSector} + ))}
diff --git a/studioShared/lib/interfaces/customerCases.ts b/studioShared/lib/interfaces/customerCases.ts index ec320c9c1..16cd36f94 100644 --- a/studioShared/lib/interfaces/customerCases.ts +++ b/studioShared/lib/interfaces/customerCases.ts @@ -54,8 +54,16 @@ export interface CustomerCaseBase { slug: string; domains: string[]; basicTitle: string; + basicTitleColorPart: string; description: string; image: IImage; + clientColors: CustomerCaseClientColors; +} + +export interface CustomerCaseClientColors { + title?: string; + badge?: string; + badgeText?: string; } export type CustomerCaseSection = diff --git a/studioShared/lib/queries/customerCases.ts b/studioShared/lib/queries/customerCases.ts index fd9055f6b..5b8dacf55 100644 --- a/studioShared/lib/queries/customerCases.ts +++ b/studioShared/lib/queries/customerCases.ts @@ -17,9 +17,15 @@ const CUSTOMER_CASE_BASE_FRAGMENT = groq` ${LANGUAGE_FIELD_FRAGMENT}, "slug": ${translatedFieldFragment("slug")}, "basicTitle": ${translatedFieldFragment("basicTitle")}, + "basicTitleColorPart": ${translatedFieldFragment("basicTitleColorPart")}, "description": ${translatedFieldFragment("description")}, "image": image { ${INTERNATIONALIZED_IMAGE_FRAGMENT} + }, + "clientColors": { + "title": clientColorTitle.hex, + "badge": clientColorBadge.hex, + "badgeText": clientColorBadgeText.hex } `; @@ -66,7 +72,7 @@ export const CUSTOMER_CASE_QUERY = groq` }, collaborators, "consultants": consultants[] { - _key, + _key, employeeEmail, employeeFirstName, } diff --git a/studioShared/schemas/documents/customerCase.ts b/studioShared/schemas/documents/customerCase.ts index 2b37f1df4..ed6429bed 100644 --- a/studioShared/schemas/documents/customerCase.ts +++ b/studioShared/schemas/documents/customerCase.ts @@ -39,7 +39,34 @@ const customerCase = defineType({ type: "internationalizedArrayString", title: "Title", }), + defineField({ + name: `${titleID.basic}ColorPart`, + type: "internationalizedArrayString", + title: "Title Color Part", + description: "Which part of the title should be colored", + }), defineField({ ...domainsField, validation: (rule) => rule.required() }), + defineField({ + name: "clientColorTitle", + type: "color", + title: "Client Color (Title)", + description: "This color will be used for parts of the title", + options: { disableAlpha: true }, + }), + defineField({ + name: "clientColorBadge", + type: "color", + title: "Client Color (Badge)", + description: "This color will be used for the badges under project info", + options: { disableAlpha: true }, + }), + defineField({ + name: "clientColorBadgeText", + type: "color", + title: "Client Color (Badge Text)", + description: "This color will be used for the text on the badges", + options: { disableAlpha: true }, + }), defineField({ name: "description", type: "internationalizedArrayText", diff --git a/studioShared/studioConfig.tsx b/studioShared/studioConfig.tsx index 23ced8911..4c3a3d859 100644 --- a/studioShared/studioConfig.tsx +++ b/studioShared/studioConfig.tsx @@ -1,3 +1,4 @@ +import { colorInput } from "@sanity/color-input"; import { visionTool } from "@sanity/vision"; import { WorkspaceOptions } from "sanity"; import { structureTool } from "sanity/structure"; @@ -32,6 +33,7 @@ const config: WorkspaceOptions = { languages: supportedLanguages, fieldTypes: ["string", "richText", "text"], }), + colorInput(), ], }; From b1e638b5bc97cac9afe66c737419e962240d6ef2 Mon Sep 17 00:00:00 2001 From: Truls Henrik Jakobsen Date: Wed, 27 Nov 2024 15:58:58 +0100 Subject: [PATCH 2/2] use same input for badge color & text color --- .../customerCase/CustomerCase.tsx | 2 +- .../projectInfo/CustomerCaseProjectInfo.tsx | 2 +- studioShared/lib/interfaces/customerCases.ts | 3 +-- studioShared/lib/queries/customerCases.ts | 3 +-- .../schemas/documents/customerCase.ts | 21 ++++++++----------- 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/components/customerCases/customerCase/CustomerCase.tsx b/src/components/customerCases/customerCase/CustomerCase.tsx index 521cb7f01..5a495d814 100644 --- a/src/components/customerCases/customerCase/CustomerCase.tsx +++ b/src/components/customerCases/customerCase/CustomerCase.tsx @@ -29,7 +29,7 @@ export default async function CustomerCase({
{consultantsResult.ok && ( diff --git a/src/components/customerCases/customerCase/projectInfo/CustomerCaseProjectInfo.tsx b/src/components/customerCases/customerCase/projectInfo/CustomerCaseProjectInfo.tsx index e597d50d3..9475d3dd2 100644 --- a/src/components/customerCases/customerCase/projectInfo/CustomerCaseProjectInfo.tsx +++ b/src/components/customerCases/customerCase/projectInfo/CustomerCaseProjectInfo.tsx @@ -40,7 +40,7 @@ export default async function CustomerCaseProjectInfo({ {projectInfo.customerSectors.map((sector: CustomerSector) => ( {sector.customerSector} diff --git a/studioShared/lib/interfaces/customerCases.ts b/studioShared/lib/interfaces/customerCases.ts index 16cd36f94..20d165266 100644 --- a/studioShared/lib/interfaces/customerCases.ts +++ b/studioShared/lib/interfaces/customerCases.ts @@ -61,8 +61,7 @@ export interface CustomerCaseBase { } export interface CustomerCaseClientColors { - title?: string; - badge?: string; + color?: string; badgeText?: string; } diff --git a/studioShared/lib/queries/customerCases.ts b/studioShared/lib/queries/customerCases.ts index 5b8dacf55..024976b4e 100644 --- a/studioShared/lib/queries/customerCases.ts +++ b/studioShared/lib/queries/customerCases.ts @@ -23,8 +23,7 @@ const CUSTOMER_CASE_BASE_FRAGMENT = groq` ${INTERNATIONALIZED_IMAGE_FRAGMENT} }, "clientColors": { - "title": clientColorTitle.hex, - "badge": clientColorBadge.hex, + "color": clientColor.hex, "badgeText": clientColorBadgeText.hex } `; diff --git a/studioShared/schemas/documents/customerCase.ts b/studioShared/schemas/documents/customerCase.ts index ed6429bed..43d2499e5 100644 --- a/studioShared/schemas/documents/customerCase.ts +++ b/studioShared/schemas/documents/customerCase.ts @@ -47,25 +47,22 @@ const customerCase = defineType({ }), defineField({ ...domainsField, validation: (rule) => rule.required() }), defineField({ - name: "clientColorTitle", + name: "clientColor", type: "color", - title: "Client Color (Title)", - description: "This color will be used for parts of the title", - options: { disableAlpha: true }, - }), - defineField({ - name: "clientColorBadge", - type: "color", - title: "Client Color (Badge)", - description: "This color will be used for the badges under project info", + title: "Client Color (Title & Badges)", + description: "This color will be used for parts of the title and badges", options: { disableAlpha: true }, }), defineField({ name: "clientColorBadgeText", type: "color", title: "Client Color (Badge Text)", - description: "This color will be used for the text on the badges", - options: { disableAlpha: true }, + description: + "This color will be used for the text on the badges. There are predefined colors for text in the component", + options: { + disableAlpha: true, + colorList: ["#222424", "#faf8f5"], + }, }), defineField({ name: "description",