Skip to content

Commit 66529ca

Browse files
committed
feat(sanity): 이미지, 텍스트 반반 컴포넌트 추가
1 parent 888ed78 commit 66529ca

File tree

4 files changed

+144
-10
lines changed

4 files changed

+144
-10
lines changed

docs/components/sanity/sanity-content.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useEffect, useState } from "react";
88
import ErrorBoundary from "../error-boundary";
99
import { PortableImage } from "./image";
1010
import { Table } from "./table";
11+
import { ImageWithTextPreview } from "@/sanity/components/ImageWithTextPreview";
1112

1213
interface SanityGuidelineProps {
1314
title: string;
@@ -49,6 +50,7 @@ export const PortableContent = ({ content }: { content: any }) => {
4950
types: {
5051
image: (props) => <PortableImage {...props} />,
5152
tabelContainer: Table,
53+
imageWithText: ImageWithTextPreview,
5254
},
5355
block: {
5456
normal: (props) => <p className="min-h-4 m-0" {...props} />,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { PortableText, PortableTextBlock } from "@portabletext/react";
2+
import { SanityImageAsset } from "@sanity/asset-utils";
3+
import imageUrlBuilder from "@sanity/image-url";
4+
import { useCallback } from "react";
5+
import { client } from "./client";
6+
7+
const builder = imageUrlBuilder(client);
8+
9+
interface SanityImage {
10+
_type: "image";
11+
asset: SanityImageAsset;
12+
hotspot?: {
13+
x: number;
14+
y: number;
15+
height: number;
16+
width: number;
17+
};
18+
crop?: {
19+
top: number;
20+
bottom: number;
21+
left: number;
22+
right: number;
23+
};
24+
}
25+
26+
interface ImageWithTextPreviewProps {
27+
value: {
28+
image: SanityImage;
29+
text: PortableTextBlock[];
30+
imagePosition: "left" | "right";
31+
};
32+
}
33+
34+
export function ImageWithTextPreview({ value }: ImageWithTextPreviewProps) {
35+
const { image, text, imagePosition } = value;
36+
37+
console.log("value", value);
38+
39+
const imageUrl = useCallback(() => builder.image(image).width(800).url(), [image]);
40+
41+
return (
42+
<div
43+
style={{
44+
display: "flex",
45+
flexDirection: imagePosition === "right" ? "row-reverse" : "row",
46+
gap: 8,
47+
}}
48+
>
49+
<div style={{ flex: 1, maxWidth: "50%" }}>
50+
<img
51+
src={imageUrl()}
52+
alt=""
53+
style={{
54+
width: "100%",
55+
height: "auto",
56+
objectFit: "cover",
57+
}}
58+
/>
59+
</div>
60+
61+
<div style={{ flex: 1, padding: 4 }}>
62+
<PortableText value={text} />
63+
</div>
64+
</div>
65+
);
66+
}

docs/sanity/components/client.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { createClient } from "@sanity/client";
2+
3+
import { projectId, dataset } from "../env";
4+
5+
export const client = createClient({
6+
projectId,
7+
dataset,
8+
apiVersion: "2023-05-03", // 현재 날짜 사용
9+
useCdn: true, // 프로덕션에서는 true로 설정
10+
});

docs/sanity/schemaTypes/blockContent.tsx

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,71 @@
11
import { ImageIcon } from "@sanity/icons";
22
import { defineArrayMember, defineType } from "sanity";
33

4-
/**
5-
* This is the schema type for block content used in the post document type
6-
* Importing this type into the studio configuration's `schema` property
7-
* lets you reuse it in other document types with:
8-
* {
9-
* name: 'someName',
10-
* title: 'Some title',
11-
* type: 'blockContent'
12-
* }
13-
*/
4+
// imageWithText를 defineArrayMember로 정의
5+
export const imageWithTextType = defineArrayMember({
6+
name: "imageWithText",
7+
title: "이미지 텍스트 조합",
8+
type: "object",
9+
fields: [
10+
{
11+
name: "image",
12+
title: "이미지",
13+
type: "image",
14+
options: {
15+
hotspot: true,
16+
},
17+
},
18+
{
19+
name: "text",
20+
title: "텍스트",
21+
type: "array",
22+
of: [
23+
{
24+
type: "block",
25+
styles: [
26+
{ title: "본문", value: "normal" },
27+
{ title: "제목", value: "h3" },
28+
{ title: "부제목", value: "h4" },
29+
],
30+
marks: {
31+
decorators: [
32+
{ title: "굵게", value: "strong" },
33+
{ title: "기울임", value: "em" },
34+
{ title: "밑줄", value: "underline" },
35+
],
36+
},
37+
},
38+
],
39+
},
40+
{
41+
name: "imagePosition",
42+
title: "이미지 위치",
43+
type: "string",
44+
options: {
45+
list: [
46+
{ title: "왼쪽", value: "left" },
47+
{ title: "오른쪽", value: "right" },
48+
],
49+
layout: "radio",
50+
},
51+
initialValue: "left",
52+
},
53+
],
54+
preview: {
55+
select: {
56+
title: "text",
57+
media: "image",
58+
imagePosition: "imagePosition",
59+
},
60+
prepare({ title, media, imagePosition }) {
61+
return {
62+
title: title?.[0]?.children?.[0]?.text || "이미지 텍스트 블록",
63+
subtitle: `이미지 위치: ${imagePosition === "left" ? "왼쪽" : "오른쪽"}`,
64+
media,
65+
};
66+
},
67+
},
68+
});
1469

1570
// You can add additional types here. Note that you can't use
1671
// primitive types such as 'string' and 'number' in the same array
@@ -90,5 +145,6 @@ export default defineType({
90145
}),
91146
imageType,
92147
tableType,
148+
imageWithTextType,
93149
],
94150
});

0 commit comments

Comments
 (0)