Skip to content

Commit

Permalink
v3 - customer case detail and landing page (#793)
Browse files Browse the repository at this point in the history
* feat: remove global :focus

* feat: update color palette

* feat(SanityImage): alternatives to useNextSanityGlobalImage

If the project is known, the image url should be used directly without the existence check

* feat(SanityImage): blurDataURL

* feat(customerCase): remove root rich text field

* feat: initial customer case detail page

* feat(customerCases): initial customer cases landing page
  • Loading branch information
mathiazom authored Oct 18, 2024
1 parent 3bef07f commit 7bb5a84
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 58 deletions.
8 changes: 2 additions & 6 deletions src/app/(main)/[lang]/[...path]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Metadata } from "next";

import Compensations from "src/components/compensations/Compensations";
import CompensationsPreview from "src/components/compensations/CompensationsPreview";
import CustomerCase from "src/components/customerCases/customerCase/CustomerCase";
import CustomerCases from "src/components/customerCases/CustomerCases";
import CustomerCasesPreview from "src/components/customerCases/CustomerCasesPreview";
import CustomErrorMessage from "src/components/customErrorMessage/CustomErrorMessage";
Expand Down Expand Up @@ -122,12 +123,7 @@ async function Page({ params }: Props) {
<CustomerCases customerCasesPage={queryResponse.data} />
);
case "customerCase":
return (
// TODO: implement customer case detail page
<pre style={{ background: "hotpink", marginTop: "8rem" }}>
{JSON.stringify(pageData, null, 2)}
</pre>
);
return <CustomerCase customerCase={queryResponse.data} />;
case "legalDocument":
return isDraftMode ? (
<LegalPreview initialDocument={queryResponse} />
Expand Down
48 changes: 28 additions & 20 deletions src/components/customerCases/CustomerCases.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Link from "next/link";

import { SanitySharedImage } from "src/components/image/SanityImage";
import LinkButton from "src/components/linkButton/LinkButton";
import Text from "src/components/text/Text";
import { sharedCustomerCasesLink } from "src/components/utils/linkTypes";
Expand Down Expand Up @@ -28,27 +29,34 @@ const CustomerCases = async ({ customerCasesPage }: CustomerCasesProps) => {

return (
<div className={styles.wrapper}>
<Text type="h1"> {customerCasesPage.basicTitle} </Text>
{sharedCustomerCases && sharedCustomerCases.data.length > 0 ? (
sharedCustomerCases.data.map((customerCase) => (
<div key={customerCase._id}>
<Link href={`${customerCasesPage.slug}/${customerCase.slug}`}>
<Text type="h2">{customerCase.basicTitle}</Text>
</Link>
{customerCase.description && (
<Text>{customerCase.description}</Text>
)}
<div className={styles.content}>
<Text type="h1"> {customerCasesPage.basicTitle} </Text>
{sharedCustomerCases && sharedCustomerCases.data.length > 0 ? (
sharedCustomerCases.data.map((customerCase) => (
<div key={customerCase._id} className={styles.caseWrapper}>
<div className={styles.caseImageWrapper}>
<SanitySharedImage image={customerCase.image} />
</div>
<div>
<Link href={`${customerCasesPage.slug}/${customerCase.slug}`}>
<Text type="h2">{customerCase.basicTitle}</Text>
</Link>
{customerCase.description && (
<Text>{customerCase.description}</Text>
)}
</div>
</div>
))
) : (
<div className={styles.section}>
<Text>
It looks like you haven&apos;t created any customer cases yet.
Please visit the shared studio to add some.
</Text>
<LinkButton link={sharedCustomerCasesLink} />
</div>
))
) : (
<div className={styles.section}>
<Text>
It looks like you haven&apos;t created any customer cases yet.
Please visit the shared studio to add some.
</Text>
<LinkButton link={sharedCustomerCasesLink} />
</div>
)}
)}
</div>
</div>
);
};
Expand Down
90 changes: 90 additions & 0 deletions src/components/customerCases/customerCase/CustomerCase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { SanitySharedImage } from "src/components/image/SanityImage";
import { RichText } from "src/components/richText/RichText";
import Text from "src/components/text/Text";
import { CustomerCase as CustomerCaseDocument } from "studioShared/lib/interfaces/customerCases";

import styles from "./customerCase.module.css";

export interface CustomerCaseProps {
customerCase: CustomerCaseDocument;
}

export default function CustomerCase({ customerCase }: CustomerCaseProps) {
return (
<div className={styles.wrapper}>
<div className={styles.content}>
<Text type={"h1"} className={styles.mainTitle}>
{customerCase.basicTitle}
</Text>
<div className={styles.mainImageWrapper}>
<SanitySharedImage image={customerCase.image} />
</div>
<div className={styles.ingress}>
<Text type={"bodyLarge"}>{customerCase.description}</Text>
<div className={styles.projectInfo}>
<div className={styles.projectInfoItem}>
<Text>Kunde</Text>
<Text className={styles.projectInfoItemValue}>
{customerCase.projectInfo.customer}
</Text>
</div>
<div className={styles.projectInfoItem}>
<Text>Prosjekt</Text>
<Text className={styles.projectInfoItemValue}>
{customerCase.projectInfo.name}
</Text>
</div>
<div className={styles.projectInfoItem}>
<Text>Varighet</Text>
<Text className={styles.projectInfoItemValue}>
{customerCase.projectInfo.duration}
</Text>
</div>
</div>
<div className={styles.projectInfo}>
<div className={styles.projectInfoItem}>
<Text>Bransje</Text>
<Text className={styles.projectInfoItemValue}>
{customerCase.projectInfo.sector}
</Text>
</div>
<div className={styles.projectInfoItem}>
<Text>Leveranse</Text>
<Text className={styles.projectInfoItemValue}>
{customerCase.projectInfo.delivery}
</Text>
</div>
<div className={styles.projectInfoItem}>
<Text>Konsulenter</Text>
<Text className={styles.projectInfoItemValue}>
{customerCase.projectInfo.consultants.join(", ")}
</Text>
</div>
</div>
</div>
<div className={styles.sectionsWrapper}>
{customerCase.sections.map((section) => (
<div key={section._key}>
{section._type === "richTextBlock" ? (
<RichText value={section.richText} />
) : (
<div className={styles.imageBlockWrapper}>
{section.images.map((image) => (
<div
key={image._key}
className={styles.imageBlockImageWrapper}
>
<div className={styles.imageBlockImageContent}>
<SanitySharedImage image={image} />
</div>
</div>
))}
</div>
)}
</div>
))}
</div>
</div>
</div>
);
}
70 changes: 70 additions & 0 deletions src/components/customerCases/customerCase/customerCase.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
.wrapper {
display: flex;
flex-direction: column;
margin: 8rem 0;
align-items: center;
}

.content {
display: flex;
flex-direction: column;
max-width: 1200px;
gap: 2rem;
padding: 1rem;
}

.mainTitle {
font-weight: 600;
}

.mainImageWrapper img {
border-radius: 12px;
}

.ingress {
display: flex;
flex-direction: column;
gap: 1.5rem;
}

.projectInfo {
display: flex;
gap: 1rem;
flex-grow: 1;
}

.projectInfoItem {
display: flex;
gap: 1rem;
}

.projectInfoItemValue {
font-weight: 300;
white-space: nowrap;
}

.sectionsWrapper {
display: flex;
flex-direction: column;
gap: 2rem;
}

.imageBlockWrapper {
display: flex;
flex-direction: column;
gap: 1rem;
}

.imageBlockImageWrapper {
display: flex;
flex-direction: column;
align-items: center;
}

.imageBlockImageContent {
max-width: 800px;
}

.imageBlockImageContent img {
border-radius: 12px;
}
24 changes: 23 additions & 1 deletion src/components/customerCases/customerCases.module.css
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
.wrapper {
display: flex;
flex-direction: column;
padding: 10rem 5rem;
margin: 8rem 0;
align-items: center;
}

.content {
display: flex;
flex-direction: column;
gap: 5rem;
max-width: 1200px;
padding: 1rem;
}

.section {
display: flex;
flex-direction: column;
gap: 5rem;
}

.caseWrapper {
display: flex;
gap: 3rem;
}

.caseImageWrapper {
min-width: 20rem;
max-width: 20rem;
}

.caseImageWrapper img {
border-radius: 12px;
}
29 changes: 26 additions & 3 deletions src/components/image/SanityImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,13 @@ const useNextSanityGlobalImage = (
return globalImage;
};

const SanityAssetImage = ({ image }: { image: IImage }) => {
const imageProps = useNextSanityGlobalImage(image);
const SanityAssetImage = ({
image,
imageProps,
}: {
image: IImage;
imageProps?: UseNextSanityImageProps;
}) => {
const objectPosition = image.hotspot
? `${image.hotspot.x * 100}% ${image.hotspot.y * 100}%`
: "50% 50%"; // Default to center if no hotspot is defined
Expand All @@ -50,6 +55,7 @@ const SanityAssetImage = ({ image }: { image: IImage }) => {
{...imageProps}
width={imageProps.width}
height={imageProps.height}
blurDataURL={image.metadata?.lqip}
style={{
objectFit: "cover",
objectPosition,
Expand All @@ -62,6 +68,23 @@ const SanityAssetImage = ({ image }: { image: IImage }) => {
);
};

export function SanityStudioImage({ image }: { image: IImage }) {
const imageProps = useNextSanityImage(client, image);
return <SanityAssetImage image={image} imageProps={imageProps} />;
}

export function SanitySharedImage({ image }: { image: IImage }) {
const imageProps = useNextSanityImage(sharedClient, image);
return <SanityAssetImage image={image} imageProps={imageProps} />;
}

function SanityGlobalImage({ image }: { image: IImage }) {
const imageProps = useNextSanityGlobalImage(image);
return (
<SanityAssetImage image={image} imageProps={imageProps ?? undefined} />
);
}

export function SanityImage({ image }: { image: IImage }) {
if (image?.src) {
return (
Expand All @@ -74,5 +97,5 @@ export function SanityImage({ image }: { image: IImage }) {
/>
);
}
return <SanityAssetImage image={image} />;
return <SanityGlobalImage image={image} />;
}
11 changes: 3 additions & 8 deletions src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ html {
--primary-dark: #e61a6b;
--primary-darker: #8b0f40;
--primary-light: #f5a4c4;
--primary-bg: #f4f1e7;
--primary-bg-dark: #fad2e2;
--primary-bg: #f2f2f2;
--primary-bg-dark: #d9d9d9;

--primary-white-bright: #ffffff;
--primary-white: #faf8f5;
--primary-black: #1f1f1f;
--primary-black: #2d2d2d;

--secondary-off-white1: #f4efe8;
--secondary-off-white2: #ece1d3;
Expand All @@ -37,11 +37,6 @@ html {
--max-content-width-small: 1000px;
}

:focus {
outline: 2px solid var(--focus-color);
border-radius: 4px;
}

body {
margin: 0;
padding: 0;
Expand Down
3 changes: 3 additions & 0 deletions studio/lib/interfaces/media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export interface IImage {
alt?: string;
crop?: ICrop;
hotspot?: IHotspot;
metadata?: {
lqip: string;
};
}

export interface ImageExtendedProps extends IImage {
Expand Down
Loading

0 comments on commit 7bb5a84

Please sign in to comment.