Skip to content

Commit

Permalink
feat: [LINKER-110] 프로필 헤더 수정 (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
useonglee authored Feb 11, 2024
1 parent 171db5e commit 35a053d
Show file tree
Hide file tree
Showing 54 changed files with 591 additions and 221 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/chromatic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ on:
pull_request:
branches:
- develop
types: [opened, reopened]
paths:
- '**.stories.tsx'
types: [opened, edited, reopened]

jobs:
chromatic:
Expand Down
4 changes: 3 additions & 1 deletion packages/lds/src/Dialog/DialogBase.css.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { colors } from '@linker/styles';
import { recipe } from '@vanilla-extract/recipes';

import { DIALOG_Z_INDEX } from '../constants';

export const dialogOverlay = recipe({
base: {
position: 'fixed',
top: 0,
left: 0,
zIndex: 'auto',
zIndex: DIALOG_Z_INDEX,
width: '100vw',
height: '100vh',
minHeight: '100%',
Expand Down
21 changes: 21 additions & 0 deletions packages/lds/src/Header/FixedHeader.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createThemeContract, style } from '@vanilla-extract/css';

import { HEADER_Z_INDEX } from '../constants';

export const styleVar = createThemeContract({
display: null,
background: null,
});

export const container = style({
position: 'fixed',
top: 0,
zIndex: HEADER_Z_INDEX,
display: `${styleVar.display}`,
width: '100%',
background: `${styleVar.background}`,
});

export const headerContainer = style({
padding: '0.8rem 2rem !important',
});
46 changes: 46 additions & 0 deletions packages/lds/src/Header/FixedHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use client';

import { useIsScrollOver } from '@linker/react';
import { colors } from '@linker/styles';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx';
import { ReactNode, forwardRef } from 'react';

import { container, styleVar, headerContainer } from './FixedHeader.css';
import Header from './Header';
import { HEADER_HEIGHT_NUMBER, TAB_HEIGHT_NUMBER } from '../constants';

interface HeaderProps {
children: ReactNode;
leftAddon?: ReactNode;
rightAddon?: ReactNode;
className?: string;
bgColor?: string;
scrollOver?: number;
}

const MINIMIZE_SCROLL = HEADER_HEIGHT_NUMBER + TAB_HEIGHT_NUMBER + 15;

const FixedHeader = forwardRef<HTMLDivElement, HeaderProps>(
({ children, leftAddon, rightAddon, className, bgColor, scrollOver = 0 }: HeaderProps, ref) => {
const isScrollOver = useIsScrollOver(MINIMIZE_SCROLL + scrollOver ?? MINIMIZE_SCROLL);

return (
<div
ref={ref}
aria-hidden
className={clsx(container, className)}
style={assignInlineVars(styleVar, {
display: isScrollOver ? 'block' : 'none',
background: bgColor ?? colors.gradationBlue,
})}
>
<Header leftAddon={leftAddon} rightAddon={rightAddon} className={headerContainer} />

{children}
</div>
);
},
);

export default FixedHeader;
18 changes: 18 additions & 0 deletions packages/lds/src/Header/Header.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { style } from '@vanilla-extract/css';

import { HEADER_HEIGHT } from '../constants';

export const headerContainer = style({
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
maxWidth: '72rem',
height: HEADER_HEIGHT,
margin: '0 auto',
padding: '1.4rem 2rem',
});

export const rightItem = style({
display: 'flex',
gap: '1rem',
});
32 changes: 32 additions & 0 deletions packages/lds/src/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use client';

import clsx from 'clsx';
import Link from 'next/link';

import { Logo } from '@linker/lds';

import { headerContainer, rightItem } from './Header.css';

interface Props {
leftAddon?: React.ReactNode;
rightAddon?: React.ReactNode;
className?: string;
}

const Header = ({ leftAddon, rightAddon, className }: Props) => {
return (
<header className={clsx(headerContainer, className)}>
{leftAddon ? (
<>{leftAddon}</>
) : (
<Link href="/my/feed">
<Logo />
</Link>
)}

<div className={rightItem}>{rightAddon}</div>
</header>
);
};

export default Header;
2 changes: 2 additions & 0 deletions packages/lds/src/Header/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as Header } from './Header';
export { default as HeaderFixed } from './FixedHeader';
15 changes: 15 additions & 0 deletions packages/lds/src/Icon/Icon.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@ export const Template: Story = {
<Icon name="user" />
<Txt typography="p1">user</Txt>
</div>

<div className={iconWrapper}>
<Icon name="share-white" />
<Txt typography="p1">share-white</Txt>
</div>

<div className={iconWrapper}>
<Icon name="list-white" />
<Txt typography="p1">list-white</Txt>
</div>
</div>

<br />
Expand Down Expand Up @@ -144,6 +154,11 @@ export const Template: Story = {
<Icon name="question-fill-purple" />
<Txt typography="p1">question-fill-purple</Txt>
</div>

<div className={iconWrapper}>
<Icon name="logo" />
<Txt typography="p1">logo</Txt>
</div>
</div>
</>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/lds/src/Icon/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Image, { ImageProps } from 'next/image';

const bucket = 'https://static.im-linker.com';

interface Props extends Omit<ImageProps, 'src' | 'alt' | 'width' | 'height'> {
interface Props extends Omit<ImageProps, 'src' | 'alt' | 'width'> {
name: string;
size?: number;
}
Expand Down
17 changes: 17 additions & 0 deletions packages/lds/src/Logo/Logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Image from 'next/image';

const Logo = () => {
return (
<Image
src="https://static.im-linker.com/icons/logo.svg"
blurDataURL="https://static.im-linker.com/icons/logo.svg"
alt="Linker ogo"
width={72}
height={24}
priority
placeholder="blur"
/>
);
};

export default Logo;
File renamed without changes.
33 changes: 29 additions & 4 deletions packages/lds/src/Profile/Profile.css.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
import { style } from '@vanilla-extract/css';
import { recipe } from '@vanilla-extract/recipes';

export const profile = style({
objectFit: 'contain',
borderRadius: '2.4rem',
export const profile = recipe({
base: {
objectFit: 'contain',
},

variants: {
size: {
small: {
borderRadius: '1.2rem',
},
medium: {
borderRadius: '1.2rem',
},
large: {
borderRadius: '2.4rem',
},
xLarge: {
borderRadius: '2.4rem',
},
xxLarge: {
borderRadius: '2.4rem',
},
},
},

defaultVariants: {
size: 'large',
},
});
6 changes: 3 additions & 3 deletions packages/lds/src/Profile/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Image, { ImageProps } from 'next/image';
import { profile } from './Profile.css';

const PROFILE_SIZE = {
xxLarge: 90,
xLarge: 64,
large: 56,
medium: 48,
Expand All @@ -15,7 +16,7 @@ const PROFILE_SIZE = {
type ProfileSize = keyof typeof PROFILE_SIZE;

interface Props extends Omit<ImageProps, 'src' | 'alt'> {
imageUrl?: string;
imageUrl?: string | null;
alt?: string;
className?: string;
size?: ProfileSize;
Expand All @@ -31,8 +32,7 @@ const Profile = ({ imageUrl, alt = '', className, size = 'large', ...props }: Pr
alt={alt === '' ? '기본 프로필 이미지' : alt}
width={PROFILE_SIZE[size]}
height={PROFILE_SIZE[size]}
placeholder="blur"
className={clsx(profile, className)}
className={clsx(profile({ size }), className)}
{...props}
/>
);
Expand Down
9 changes: 5 additions & 4 deletions packages/lds/src/Tabs/Tabs.css.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { colors } from '@linker/styles';
import { style } from '@vanilla-extract/css';

import { TAB_HEIGHT } from '../constants';

export const tabs = style({
position: 'sticky',
top: 0,
width: '100%',
maxWidth: '72rem',
margin: '0 auto',
});

export const tapList = style({
Expand All @@ -24,7 +25,7 @@ export const link = style({
justifyContent: 'center',
alignItems: 'center',
width: '94px',
height: '48px',
height: TAB_HEIGHT,
fontSize: '1.6rem',
color: 'rgba(255, 255, 255, 0.3)',
fontWeight: 'bold',
Expand Down
9 changes: 9 additions & 0 deletions packages/lds/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
/** z-index */
export const HEADER_Z_INDEX = 1;
export const DIALOG_Z_INDEX = 10;
export const MODAL_Z_INDEX = 1000;
export const FAB_Z_INDEX = 100;

/** height */
export const HEADER_HEIGHT = '5.2rem';
export const HEADER_HEIGHT_NUMBER = 52;
export const TAB_HEIGHT = '3.6rem';
export const TAB_HEIGHT_NUMBER = 36;
2 changes: 2 additions & 0 deletions packages/lds/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ export * from './Calendar';
export * from './Carousel';
export * from './Chip';
export * from './Dialog';
export * from './Header';
export * from './HorizonScroller';
export * from './Icon';
export * from './Layout';
export * from './List';
export * from './Logo';
export * from './Modal';
export * from './Profile';
export * from './SearchInput';
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { createContext } from './createContext';
export { useBodyScrollLock } from './useBodyScrollLock';
export { useIsClient } from './useIsClient';
export { useIsScrollOver } from './useIsScrollOver';
1 change: 1 addition & 0 deletions packages/react/src/useIsScrollOver/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as useIsScrollOver } from './useIsScrollOver';
48 changes: 48 additions & 0 deletions packages/react/src/useIsScrollOver/useIsScorllOver.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { fireEvent } from '@testing-library/dom';
import { renderHook } from '@testing-library/react-hooks';

import useIsScrollOver from './useIsScrollOver';

describe('useIsScrollOver', () => {
test('스크롤을 하면 true를 반환한다.', () => {
const { result } = renderHook(() => useIsScrollOver());

fireEvent.scroll(window, { target: { scrollY: 100 } });

expect(result.current).toBe(true);
});

test('스크롤 위치가 인수값을 넘지 않으면 false를 반환한다.', () => {
const { result } = renderHook(() => useIsScrollOver(50));

fireEvent.scroll(window, { target: { scrollY: 37 } });

expect(result.current).toBe(false);
});

test('스크롤 위치가 인수값을 넘으면 true를 반환한다.', () => {
const { result } = renderHook(() => useIsScrollOver(50));

fireEvent.scroll(window, { target: { scrollY: 328 } });

expect(result.current).toBe(true);
});

test('true를 반환한 이후에 인수값보다 스크롤 위치가 작아지지 않으면 호출하지 않는다.', () => {
const { result, unmount } = renderHook(() => useIsScrollOver(50));

const spyAdd = jest.spyOn(window, 'addEventListener');
const spyRemove = jest.spyOn(window, 'removeEventListener');

fireEvent.scroll(window, { target: { scrollY: 328 } });

unmount();

expect(result.current).toBe(true);
expect(spyRemove).toHaveBeenCalledWith('scroll', expect.any(Function));

fireEvent.scroll(window, { target: { scrollY: 167 } });

expect(spyAdd).not.toHaveBeenCalled();
});
});
Loading

0 comments on commit 35a053d

Please sign in to comment.