Skip to content

Commit

Permalink
feat: add service introduction menu
Browse files Browse the repository at this point in the history
  • Loading branch information
Najeong-Kim committed Jan 1, 2025
1 parent 1da73c9 commit 8bc71ab
Show file tree
Hide file tree
Showing 9 changed files with 399 additions and 3 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-popover": "^1.1.1",
"@react-spring/web": "^9.7.4",
"@tanstack/react-query": "^5.51.21",
Expand Down
48 changes: 48 additions & 0 deletions src/features/resort-detail/ui/share-dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use client';

import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
import React from 'react';
import { cn } from '@/shared/lib';

const DropdownMenu = DropdownMenuPrimitive.Root;

const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;

const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-[10px] border bg-popover p-1 text-popover-foreground shadow-md',
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className
)}
{...props}
/>
</DropdownMenuPrimitive.Portal>
));
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;

const DropdownMenuItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0',
inset && 'pl-8',
className
)}
{...props}
/>
));
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;

export { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem };
3 changes: 3 additions & 0 deletions src/shared/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ export { default as SunIcon } from './weather/sun';
export { default as SnowRainIcon } from './weather/snow-rain';
export { default as FogIcon } from './weather/fog';
export { default as VoteIcon } from './vote';
export { default as MenuIcon } from './menu';
export { default as MessageIcon } from './message';
export { default as MailIcon } from './mail';
34 changes: 34 additions & 0 deletions src/shared/icons/mail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { SVGProps } from 'react';

interface MailIconProps extends SVGProps<SVGSVGElement> {
className?: string;
}

const MailIcon = ({ className, ...props }: MailIconProps) => {
return (
<svg
width="15"
height="17"
viewBox="0 0 15 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1.25 5.99572C1.25 4.61198 2.36929 3.49023 3.75 3.49023H11.25C12.6307 3.49023 13.75 4.61198 13.75 5.99572V11.0067C13.75 12.3904 12.6307 13.5122 11.25 13.5122H3.75C2.36929 13.5122 1.25 12.3904 1.25 11.0067V5.99572ZM3.75 4.74298C3.05964 4.74298 2.5 5.30385 2.5 5.99572V11.0067C2.5 11.6986 3.05964 12.2594 3.75 12.2594H11.25C11.9404 12.2594 12.5 11.6986 12.5 11.0067V5.99572C12.5 5.30385 11.9404 4.74298 11.25 4.74298H3.75Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.88698 6.2312C4.10261 5.96107 4.49592 5.91727 4.76546 6.13337L7.50002 8.32582L10.2346 6.13337C10.5041 5.91727 10.8974 5.96107 11.1131 6.2312C11.3287 6.50133 11.285 6.8955 11.0155 7.1116L7.50002 9.93012L3.98459 7.1116C3.71505 6.8955 3.67135 6.50133 3.88698 6.2312Z"
fill="currentColor"
/>
</svg>
);
};

export default MailIcon;
25 changes: 25 additions & 0 deletions src/shared/icons/menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { SVGProps } from 'react';

interface MenuIconProps extends SVGProps<SVGSVGElement> {
className?: string;
}

const MenuIcon = ({ className, ...props }: MenuIconProps) => {
return (
<svg
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
{...props}
>
<circle cx="16" cy="16" r="2" fill="currentColor" />
<circle cx="8" cy="16" r="2" fill="currentColor" />
<circle cx="24" cy="16" r="2" fill="currentColor" />
</svg>
);
};

export default MenuIcon;
46 changes: 46 additions & 0 deletions src/shared/icons/message.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { SVGProps } from 'react';

interface MessageIconProps extends SVGProps<SVGSVGElement> {
className?: string;
}

const MessageIcon = ({ className, ...props }: MessageIconProps) => {
return (
<svg
width="15"
height="17"
viewBox="0 0 15 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.5 3.49102C4.73858 3.49102 2.5 5.73451 2.5 8.50199C2.5 9.56189 2.82765 10.5432 3.38698 11.3522C3.57208 11.6199 3.61671 11.9773 3.47008 12.2935L2.90456 13.513H7.5C10.2614 13.513 12.5 11.2695 12.5 8.50199C12.5 5.73451 10.2614 3.49102 7.5 3.49102ZM1.25 8.50199C1.25 5.04264 4.04822 2.23828 7.5 2.23828C10.9518 2.23828 13.75 5.04264 13.75 8.50199C13.75 11.9613 10.9518 14.7657 7.5 14.7657H2.41349C1.7046 14.7657 1.25616 14.0099 1.58378 13.3887L2.2636 11.9228C1.62263 10.9391 1.25 9.7633 1.25 8.50199Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5 9.31606C5.44873 9.31606 5.8125 8.9515 5.8125 8.50178C5.8125 8.05207 5.44873 7.6875 5 7.6875C4.55127 7.6875 4.1875 8.05207 4.1875 8.50178C4.1875 8.9515 4.55127 9.31606 5 9.31606Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10 9.31606C10.4487 9.31606 10.8125 8.9515 10.8125 8.50178C10.8125 8.05207 10.4487 7.6875 10 7.6875C9.55127 7.6875 9.1875 8.05207 9.1875 8.50178C9.1875 8.9515 9.55127 9.31606 10 9.31606Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.5 9.31606C7.94873 9.31606 8.3125 8.9515 8.3125 8.50178C8.3125 8.05207 7.94873 7.6875 7.5 7.6875C7.05127 7.6875 6.6875 8.05207 6.6875 8.50178C6.6875 8.9515 7.05127 9.31606 7.5 9.31606Z"
fill="currentColor"
/>
</svg>
);
};

export default MessageIcon;
2 changes: 1 addition & 1 deletion src/views/resort-list/ui/resort-list-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const ResortListPage = () => {

return (
<div className={cn('size-full bg-gradient-to-b from-[rgba(141,163,221,0.2)] to-transparent')}>
<Header />
<Header hasMenuButton />
<ResortList resorts={resorts} />
</div>
);
Expand Down
49 changes: 47 additions & 2 deletions src/widgets/header/ui/header.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
import Image from 'next/image';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import logo from '@public/assets/logo.svg';
import ShareDialog from '@/features/resort-detail/ui/share-dialog';
import { ChevronLeftIcon, ShareIcon } from '@/shared/icons';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/features/resort-detail/ui/share-dropdown';
import { ChevronLeftIcon, MailIcon, MenuIcon, MessageIcon, ShareIcon } from '@/shared/icons';
import { cn } from '@/shared/lib';

interface HeaderProps {
resortId?: number;
resortName?: string;
hasBackButton?: boolean;
hasShareButton?: boolean;
hasMenuButton?: boolean;
}

const Header = ({ resortId, resortName, hasBackButton, hasShareButton }: HeaderProps) => {
const Header = ({
resortId,
resortName,
hasBackButton,
hasShareButton,
hasMenuButton,
}: HeaderProps) => {
const router = useRouter();

return (
Expand Down Expand Up @@ -41,6 +55,37 @@ const Header = ({ resortId, resortName, hasBackButton, hasShareButton }: HeaderP
name={resortName}
/>
)}
{hasMenuButton && (
<div className={cn('absolute right-7 top-1/2 -translate-y-1/2')}>
<DropdownMenu>
<DropdownMenuTrigger>
<MenuIcon />
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>
<Link
href="https://lizzie00.notion.site/weski?pvs=4"
target="_blank"
className={cn('flex items-center gap-1')}
>
<MessageIcon />
<p className={cn('py-1')}>서비스 소개보기</p>
</Link>
</DropdownMenuItem>
<DropdownMenuItem>
<Link
href="https://joey.team/block?block_id=oPWTFUezsWA61tdpDRoD&id=SoD0lftsYVQBUT65Hcpgp9mIBzj2"
target="_blank"
className={cn('flex items-center gap-1')}
>
<MailIcon />
<p className={cn('py-1')}>버그 제보하기</p>
</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
)}
</div>
);
};
Expand Down
Loading

0 comments on commit 8bc71ab

Please sign in to comment.