diff --git a/src/components/customerCases/customerCase/sections/text/TextSection.tsx b/src/components/customerCases/customerCase/sections/text/TextSection.tsx
index 44d0caf17..148408288 100644
--- a/src/components/customerCases/customerCase/sections/text/TextSection.tsx
+++ b/src/components/customerCases/customerCase/sections/text/TextSection.tsx
@@ -1,4 +1,6 @@
+import CustomLink from "src/components/link/CustomLink";
import Text from "src/components/text/Text";
+import { LinkType } from "studio/lib/interfaces/navigation";
import { TextBlock } from "studioShared/lib/interfaces/textBlock";
import styles from "./textSection.module.css";
@@ -12,11 +14,36 @@ export default function TextSection({ section }: TextSectionProps) {
-
{section.text}
+
+ {section.sectionTitle && (
+
+ {section.sectionTitle}
+
+ )}
+ {section.text}
+
+
+ {section.url && (
+
+ )}
+
diff --git a/src/components/customerCases/customerCase/sections/text/textSection.module.css b/src/components/customerCases/customerCase/sections/text/textSection.module.css
index bfdc18925..94a3608ee 100644
--- a/src/components/customerCases/customerCase/sections/text/textSection.module.css
+++ b/src/components/customerCases/customerCase/sections/text/textSection.module.css
@@ -2,6 +2,7 @@
display: flex;
flex-direction: column;
align-items: center;
+ gap: 2rem;
}
.content {
@@ -14,8 +15,24 @@
background-color: var(--primary-yellow-warning);
}
+.innerContent {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+}
+
.highlighted .innerContent {
background-color: var(--primary-bg);
border-radius: 1.25rem;
padding: 1rem;
+ height: fit-content;
+}
+.header {
+ margin-bottom: 16px;
+}
+
+.link {
+ margin-top: 2rem;
+ text-decoration: none;
+ color: var(--primary-black-darker);
}
diff --git a/src/components/text/Text.tsx b/src/components/text/Text.tsx
index 24e32a9ce..d233234db 100644
--- a/src/components/text/Text.tsx
+++ b/src/components/text/Text.tsx
@@ -8,6 +8,7 @@ export type TextType =
| "h5"
| "h6"
| "desktopLink"
+ | "desktopLinkBig"
| "labelSmall"
| "labelLight"
| "labelRegular"
@@ -32,6 +33,7 @@ const elementMap: { [key in TextType]: keyof JSX.IntrinsicElements } = {
h5: "h5",
h6: "h6",
desktopLink: "p",
+ desktopLinkBig: "p",
labelSmall: "p",
labelLight: "p",
labelRegular: "p",
@@ -56,6 +58,7 @@ const classMap: { [key in TextType]?: string } = {
h5: styles.h5,
h6: styles.h6,
desktopLink: styles.desktopLink,
+ desktopLinkBig: styles.desktopLinkBig,
labelSmall: styles.labelSmall,
labelLight: styles.labelLight,
labelRegular: styles.labelRegular,
diff --git a/src/components/text/text.module.css b/src/components/text/text.module.css
index 9be875174..82e24402e 100644
--- a/src/components/text/text.module.css
+++ b/src/components/text/text.module.css
@@ -45,8 +45,14 @@
line-height: 120%; /* 1.8rem */
}
+.h5 {
+ font-size: 1.25rem;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 120%;
+}
+
/* TODO: add font variables */
-/* .h5 */
/* .h6 */
.desktopLink {
@@ -56,6 +62,14 @@
line-height: 110%;
}
+.desktopLinkBig {
+ font-size: 1.25rem;
+ font-style: normal;
+ font-weight: 300;
+ line-height: 120%;
+ text-decoration-line: underline;
+}
+
.bodyXl {
font-size: 2.125rem;
font-weight: 500;
diff --git a/studioShared/lib/interfaces/textBlock.ts b/studioShared/lib/interfaces/textBlock.ts
index 2c5a60491..f72a44d95 100644
--- a/studioShared/lib/interfaces/textBlock.ts
+++ b/studioShared/lib/interfaces/textBlock.ts
@@ -1,6 +1,8 @@
export interface TextBlock {
_key: string;
_type: "textBlock";
+ sectionTitle?: string;
text: string;
- highlighted?: boolean;
+ url?: string;
+ textBlockType?: string;
}
diff --git a/studioShared/lib/queries/customerCases.ts b/studioShared/lib/queries/customerCases.ts
index 17abdf681..bd04ded3c 100644
--- a/studioShared/lib/queries/customerCases.ts
+++ b/studioShared/lib/queries/customerCases.ts
@@ -30,8 +30,10 @@ export const CUSTOMER_CASES_QUERY = groq`
export const BASE_SECTIONS_FRAGMENT = groq`
_type == "textBlock" => {
+ "sectionTitle": ${translatedFieldFragment("sectionTitle")},
"text": ${translatedFieldFragment("text")},
- highlighted
+ url,
+ textBlockType,
},
_type == "imageBlock" => {
"images": images[] {
diff --git a/studioShared/schemas/fields/customerCaseProjectInfo.ts b/studioShared/schemas/fields/customerCaseProjectInfo.ts
index 709c83746..c89c2d620 100644
--- a/studioShared/schemas/fields/customerCaseProjectInfo.ts
+++ b/studioShared/schemas/fields/customerCaseProjectInfo.ts
@@ -49,7 +49,7 @@ export const customerCaseProjectInfo = defineField({
],
preview: {
select: {
- item: "delivery",
+ delivery: "delivery",
},
prepare({ delivery }) {
if (!isInternationalizedString(delivery)) {
diff --git a/studioShared/schemas/objects/richTextBlock.ts b/studioShared/schemas/objects/richTextBlock.ts
new file mode 100644
index 000000000..109995dbe
--- /dev/null
+++ b/studioShared/schemas/objects/richTextBlock.ts
@@ -0,0 +1,56 @@
+import { defineField } from "sanity";
+
+import { isInternationalizedRichText } from "studio/lib/interfaces/global";
+import { firstTranslation } from "studio/utils/i18n";
+import { richTextPreview } from "studio/utils/preview";
+
+const richTextBlock = defineField({
+ name: "richTextBlock",
+ title: "Rich Text Block",
+ type: "object",
+ fields: [
+ {
+ name: "title",
+ title: "Section Title",
+ type: "internationalizedArrayString",
+ },
+ {
+ name: "richText",
+ title: "Rich Text",
+ type: "internationalizedArrayRichText",
+ },
+ {
+ name: "highlighted",
+ title: "Highlighted",
+ type: "boolean",
+ description: "Display the rich text with a highlight frame",
+ initialValue: false,
+ },
+ ],
+ preview: {
+ select: {
+ richText: "richText",
+ highlighted: "highlighted",
+ },
+ prepare({ richText, highlighted }) {
+ if (!isInternationalizedRichText(richText)) {
+ throw new TypeError(
+ `Expected 'richText' to be InternationalizedRichText, was ${typeof richText}`,
+ );
+ }
+ const translatedRichText = firstTranslation(richText);
+ return {
+ title:
+ translatedRichText !== null
+ ? richTextPreview(translatedRichText)
+ : undefined,
+ subtitle:
+ typeof highlighted === "boolean" && highlighted
+ ? "Highlighted"
+ : undefined,
+ };
+ },
+ },
+});
+
+export default richTextBlock;
diff --git a/studioShared/schemas/objects/textBlock.ts b/studioShared/schemas/objects/textBlock.ts
index b3576d8b2..b4988b0dc 100644
--- a/studioShared/schemas/objects/textBlock.ts
+++ b/studioShared/schemas/objects/textBlock.ts
@@ -7,31 +7,98 @@ const textBlock = defineField({
title: "Text Block",
type: "object",
fields: [
+ {
+ name: "sectionTitle",
+ title: "Section Title",
+ type: "internationalizedArrayString",
+ description:
+ "Section title is optional, and cannot be more than 50 characters.",
+ validation: (rule) =>
+ rule.custom<{ value: string; _type: string; _key: string }[]>(
+ (value) => {
+ if (!value) return true;
+
+ const invalidItems = value.filter(
+ (item) =>
+ typeof item.value === "string" && item.value.length > 50,
+ );
+
+ if (invalidItems.length > 0) {
+ return invalidItems.map((item) => ({
+ message: "Title cannot be more than 50 characters long.",
+ path: [{ _key: item._key }, "value"],
+ }));
+ }
+
+ return true;
+ },
+ ),
+ },
{
name: "text",
- title: "Text",
+ title: "Block text content",
type: "internationalizedArrayText",
+ description:
+ "Please type the text content for the block. This field is required, and cannot be more than 300 characters.",
+ validation: (rule) =>
+ rule.custom<{ value: string; _type: string; _key: string }[]>(
+ (value) => {
+ if (!value || value.length === 0) {
+ return { message: "This field is required." };
+ }
+ const invalidItems = value.filter(
+ (item) =>
+ typeof item.value === "string" && item.value.length > 300,
+ );
+
+ if (invalidItems.length > 0) {
+ return invalidItems.map((item) => ({
+ message: "Title cannot be more than 50 characters long.",
+ path: [{ _key: item._key }, "value"],
+ }));
+ }
+ return true;
+ },
+ ),
+ },
+ {
+ name: "url",
+ title: "Enter an external link",
+ type: "url",
+ description:
+ "If the text block should include a URL, please enter the full URL, including 'https://'. For example, 'https://www.example.com'.",
+ validation: (rule) =>
+ rule.uri({
+ scheme: ["http", "https"],
+ allowRelative: false,
+ }),
},
{
- name: "highlighted",
- title: "Highlighted",
- type: "boolean",
- description: "Display the text with a highlight frame",
- initialValue: false,
+ name: "textBlockType",
+ title: "Text Block Type",
+ type: "string",
+ description: "Please choose the style you want for the text box.",
+ options: {
+ list: [
+ { title: "Normal", value: "normal" },
+ { title: "Highlighted", value: "highlighted" },
+ { title: "Framed", value: "framed" },
+ ],
+ layout: "radio",
+ direction: "vertical",
+ },
+ initialValue: "normal",
},
],
preview: {
select: {
text: "text",
- highlighted: "highlighted",
+ textBlockType: "textBlockType",
},
- prepare({ text, highlighted }) {
+ prepare({ text, textBlockType }) {
return {
title: firstTranslation(text) ?? undefined,
- subtitle:
- typeof highlighted === "boolean" && highlighted
- ? "Highlighted"
- : undefined,
+ subtitle: textBlockType ? textBlockType : undefined,
};
},
},