Skip to content

Commit

Permalink
feat: ๐Ÿ ๊ณต์œ ํ•˜๊ธฐ
Browse files Browse the repository at this point in the history
  • Loading branch information
bepyan committed Aug 23, 2024
1 parent dd67b0d commit 45f3311
Show file tree
Hide file tree
Showing 16 changed files with 303 additions and 3 deletions.
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Script from "next/script";
import KakaoShareScript from "~/components/kakao-share-script";
import { env } from "~/lib/env";

export default function KakaoMapScriptLayout({
Expand All @@ -18,6 +19,7 @@ export default function KakaoMapScriptLayout({
type="text/javascript"
src={`${env.KAKAO_MAP_BASE_URL}?appkey=${env.KAKAO_MAP_API_KEY}&libraries=services&autoload=false`}
/>
<KakaoShareScript />
{children}
</>
);
Expand Down
11 changes: 11 additions & 0 deletions src/components/editor/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,16 @@ export const accordionElement: InferEditorElement<"accordion"> = {
},
};

export const shareElement: InferEditorElement<"share"> = {
id: "__share",
type: "share",
styles: {
color: "#222",
height: "50px",
},
content: {},
};

/**
* mapper for element types
*/
Expand All @@ -193,6 +203,7 @@ export const elementNameMap: Record<EditorElementType, string> = {
navigation: "๊ธธ์ฐพ๊ธฐ",
logoBanner: "์ธ๋น„ ๋กœ๊ณ ",
accordion: "ํŽผ์นจ/์ ‘ํž˜",
share: "๊ณต์œ ํ•˜๊ธฐ",
empty: "",
};

Expand Down
3 changes: 3 additions & 0 deletions src/components/editor/elements/recursive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ImageElement from "~/components/editor/elements/image-element";
import KakaoMap from "~/components/editor/elements/kakao-map";
import LogoBannerElement from "~/components/editor/elements/logo-banner-element";
import NavigationElement from "~/components/editor/elements/navigation-element";
import ShareElement from "~/components/editor/elements/share-element";
import Text from "~/components/editor/elements/text";
import type { EditorElement } from "~/components/editor/type";

Expand All @@ -28,6 +29,8 @@ export default function Recursive({ element }: { element: EditorElement }) {
return <LogoBannerElement element={element} />;
case "accordion":
return <AccordionElement element={element} />;
case "share":
return <ShareElement element={element} />;
default:
return null;
}
Expand Down
106 changes: 106 additions & 0 deletions src/components/editor/elements/share-element.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"use client";

import { PopoverArrow, PopoverClose } from "@radix-ui/react-popover";
import { LinkIcon } from "lucide-react";
import { toast } from "sonner";
import ElementWrapper from "~/components/editor/elements/element-wrapper";
import { useEditor } from "~/components/editor/provider";
import type { InferEditorElement } from "~/components/editor/type";
import { KakaoIcon, ShareIcon } from "~/components/ui/icons";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "~/components/ui/popover";

type Props = {
element: InferEditorElement<"share">;
};

export default function ShareElement({ element }: Props) {
const { editor } = useEditor();

const handleCopyLink = async () => {
const link = `https://${editor.config.invitationSubdomain}.invi.my`;

try {
await navigator.clipboard.writeText(link);
toast("๋งํฌ๊ฐ€ ๋ณต์‚ฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.", {
description: link,
position: "top-center",
duration: 2000,
style: {
backgroundColor: "black",
opacity: 0.9,
height: "56px",
color: "white",
border: 0,
},
});
} catch (e) {
console.error(e);
toast.error("๋งํฌ ๋ณต์‚ฌ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.");
}
};

const handleKakaoShare = () => {
// ์นด์นด์˜ค ์ •์ฑ… ์ƒ ์„œ๋ธŒ๋„๋ฉ”์ธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ
const link = `https://invi.my/i/${editor.config.invitationSubdomain}`;

window.Kakao.Share.sendDefault({
objectType: "feed",
content: {
imageUrl: editor.config.invitationThumbnail,
imageWidth: 600,
imageHeight: 450,
title: editor.config.invitationTitle,
description: editor.config.invitationDesc,
link: {
mobileWebUrl: link,
webUrl: link,
},
},
buttons: [
{
title: "์ดˆ๋Œ€์žฅ ์—ด๊ธฐ",
link: {
mobileWebUrl: link,
webUrl: link,
},
},
],
});
};

return (
<ElementWrapper
element={element}
className="flex items-center justify-center"
>
<Popover>
<PopoverTrigger className="">
<ShareIcon className="size-6" />
</PopoverTrigger>
<PopoverContent sideOffset={5} className="w-auto border-none p-2">
<PopoverClose
className="flex w-full items-center gap-2 rounded-lg p-2 text-xs transition-colors focus:outline-none active:bg-gray-100"
onClick={handleCopyLink}
>
<div className="flex h-4 w-4 items-center justify-center">
<LinkIcon />
</div>
๋งํฌ ๋ณต์‚ฌํ•˜๊ธฐ
</PopoverClose>
<PopoverClose
onClick={handleKakaoShare}
className="flex w-full items-center gap-2 rounded-lg p-2 text-xs transition-colors focus:outline-none active:bg-gray-100"
>
<KakaoIcon className="h-4 w-4" />
<span>๊ณต์œ ํ•˜๊ธฐ</span>
</PopoverClose>
<PopoverArrow className="fill-white" />
</PopoverContent>
</Popover>
</ElementWrapper>
);
}
10 changes: 9 additions & 1 deletion src/components/editor/placeholders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from "lucide-react";
import { useEditor } from "~/components/editor/provider";
import type { EditorElementType } from "~/components/editor/type";
import { ImageSolidIcon, LogoTextIcon } from "~/components/ui/icons";
import { ImageSolidIcon, LogoTextIcon, ShareIcon } from "~/components/ui/icons";
import { cn } from "~/lib/utils";

type PlaceholderProps = {
Expand Down Expand Up @@ -120,3 +120,11 @@ export function AccordionPlaceholder() {
</Placeholder>
);
}

export function SharePlaceholder() {
return (
<Placeholder type="share">
<ShareIcon className="size-6" />
</Placeholder>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import KakaoMapSetting from "~/components/editor/sidebar/sidebar-element-setting
import LayoutSetting from "~/components/editor/sidebar/sidebar-element-settings-tab/layout-setting";
import LogoBannerSetting from "~/components/editor/sidebar/sidebar-element-settings-tab/logo-banner-setting";
import MapSetting from "~/components/editor/sidebar/sidebar-element-settings-tab/map-setting";
import ShareSetting from "~/components/editor/sidebar/sidebar-element-settings-tab/share-setting";
import TextSetting from "~/components/editor/sidebar/sidebar-element-settings-tab/text-setting";
import { getElementName } from "~/components/editor/util";
import { SheetHeader, SheetTitle } from "~/components/ui/sheet";
Expand Down Expand Up @@ -79,6 +80,12 @@ export default function SidebarElementSettingsTab(props: Props) {
<AccordionSetting />
</>
)}

{selectedElement.type === "share" && (
<>
<ShareSetting />
</>
)}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"use client";

import { HeightIcon } from "@radix-ui/react-icons";
import { useEditor } from "~/components/editor/provider";
import { EditorInput } from "~/components/editor/ui/input";

export default function ShareSetting() {
const { editor, dispatch } = useEditor();
const element = editor.state.selectedElement;

return (
<div className="space-y-1 border-t p-6 pt-4">
<div className="flex h-10 items-center">
<h4 className="text-sm font-medium">๋ ˆ์ด์•„์›ƒ ์„ค์ •</h4>
</div>

<div className="grid w-full grid-cols-9 gap-1">
<div className="col-span-4">
<EditorInput
id="height_input"
defaultValue={element.styles.height}
onDebounceChange={(e) =>
dispatch({
type: "UPDATE_ELEMENT_STYLE",
payload: { height: e.target.value },
})
}
componentPrefix={<HeightIcon />}
/>
</div>
<div className="col-span-4">
<EditorInput
id="color"
defaultValue={element.styles.color ?? "transparent"}
onDebounceChange={(e) => {
dispatch({
type: "UPDATE_ELEMENT_STYLE",
payload: { color: e.target.value },
});
}}
componentPrefix={
<div
className="h-3.5 w-3.5 rounded ring-1 ring-border"
style={{ backgroundColor: element.styles.color }}
/>
}
/>
</div>
</div>
</div>
);
}
6 changes: 6 additions & 0 deletions src/components/editor/sidebar/sidebar-elements-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
KakaoMapPlaceholder,
LogoBannerPlaceholder,
NavigationPlaceholder,
SharePlaceholder,
TextPlaceholder,
TwoColumnsPlaceholder,
} from "~/components/editor/placeholders";
Expand Down Expand Up @@ -77,6 +78,11 @@ export default function SidebarElementsTab(props: Props) {
Component: <LogoBannerPlaceholder />,
group: "elements",
},
{
type: "share",
Component: <SharePlaceholder />,
group: "elements",
},
];

return (
Expand Down
1 change: 1 addition & 0 deletions src/components/editor/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type EditorElementContentMap = {
contentStyle?: React.CSSProperties;
innerContainer: InferEditorElement<"container">;
};
share: {};
};

export type EditorElementType = keyof EditorElementContentMap;
Expand Down
2 changes: 2 additions & 0 deletions src/components/editor/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
kakaoMapElement,
logoBannerElement,
navigationElement,
shareElement,
textElement,
twoColumnElement,
} from "~/components/editor/constant";
Expand Down Expand Up @@ -47,6 +48,7 @@ export const getDefaultElement = <T extends EditorElementType>(
navigation: navigationElement,
logoBanner: logoBannerElement,
accordion: accordionElement,
share: shareElement,
__body: bodyElement,
empty: emptyElement,
};
Expand Down
27 changes: 27 additions & 0 deletions src/components/kakao-share-script.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client";

import Script from "next/script";
import { env } from "~/lib/env";

export default function KakaoShareScript() {
const kakaoInit = () => {
try {
if (!window.Kakao.isInitialized()) {
window.Kakao.init(env.NEXT_PUBLIC_KAKAO_JS_KEY);
}
} catch (error) {
console.error(error);
}
};

return (
<>
<Script
src="https://t1.kakaocdn.net/kakao_js_sdk/2.7.2/kakao.min.js"
integrity="sha384-TiCUE00h649CAMonG018J2ujOgDKW/kVWlChEuu4jK2vxfAAD0eZxzCKakxg55G4"
crossOrigin="anonymous"
onLoad={kakaoInit}
/>
</>
);
}
37 changes: 37 additions & 0 deletions src/components/ui/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,40 @@ export function ImageSolidIcon(props: React.ComponentProps<"svg">) {
</svg>
);
}

export function KakaoIcon(props: React.ComponentProps<"svg">) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
fill="currentColor"
{...props}
>
<path d="M12 3c5.8 0 10.501 3.664 10.501 8.185c0 4.52-4.701 8.184-10.5 8.184a13.51 13.51 0 0 1-1.727-.11l-4.408 2.883c-.501.265-.678.236-.472-.413l.892-3.678c-2.88-1.46-4.785-3.99-4.785-6.866c0-4.52 4.7-8.185 10.5-8.185Zm5.908 8.06l1.47-1.424a.472.472 0 0 0-.656-.678l-1.928 1.866V9.282a.472.472 0 0 0-.944 0v2.557a.472.472 0 0 0 0 .222V13.5a.472.472 0 0 0 .944 0v-1.363l.427-.413l1.428 2.033a.472.472 0 1 0 .773-.543l-1.514-2.155Zm-2.958 1.924h-1.46V9.297a.472.472 0 0 0-.943 0v4.159c0 .26.21.472.471.472h1.932a.472.472 0 1 0 0-.944Zm-5.857-1.091l.696-1.708l.638 1.707H9.093Zm2.523.487l.002-.016a.469.469 0 0 0-.127-.32l-1.046-2.8a.69.69 0 0 0-.627-.474a.696.696 0 0 0-.653.447l-1.662 4.075a.472.472 0 0 0 .874.357l.332-.813h2.07l.298.8a.472.472 0 1 0 .884-.33l-.345-.926ZM8.294 9.302a.472.472 0 0 0-.471-.472H4.578a.472.472 0 1 0 0 .944h1.16v3.736a.472.472 0 0 0 .944 0V9.774h1.14a.472.472 0 0 0 .472-.472Z"></path>
</svg>
);
}

export function ShareIcon(props: React.ComponentProps<"svg">) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
{...props}
>
<g fill="none" stroke="currentColor" strokeWidth="1.5">
<path d="M9 11.5a2.5 2.5 0 1 1-5 0a2.5 2.5 0 0 1 5 0Z"></path>
<path
strokeLinecap="round"
d="M14.32 16.802L9 13.29m5.42-6.45L9.1 10.35"
opacity=".5"
/>
<path d="M19 18.5a2.5 2.5 0 1 1-5 0a2.5 2.5 0 0 1 5 0Zm0-13a2.5 2.5 0 1 1-5 0a2.5 2.5 0 0 1 5 0Z"></path>
</g>
</svg>
);
}
Loading

0 comments on commit 45f3311

Please sign in to comment.