Skip to content

Commit

Permalink
📝 스토리북에서 사이드바를 업데이트한다
Browse files Browse the repository at this point in the history
- Storybook에서 position: fixed가 제대로 되지 않는 현상이 발생하고 있다.
- 따라서 absolute로 임시방편 후 주석을 달아놓았다.
- 참고: storybookjs/storybook#8011
  • Loading branch information
JengYoung committed Nov 23, 2022
1 parent 8b3cdf7 commit df5c929
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 32 deletions.
11 changes: 11 additions & 0 deletions .storybook/preview-head.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<style>
html,
body {
margin: 0;
padding: 0;
}
.sb-show-main.sb-main-padded {
margin: 0 !important;
padding: 0 !important;
}
</style>
16 changes: 9 additions & 7 deletions src/components/Base/Button/Hamburger/Hamburger.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
'hamburger--active': !isActive,
'hamburger--fixed': fixed,
}"
@click="onClick"
@click.stop="onClick"
>
<HamburgerLine
:width="width"
Expand All @@ -26,7 +26,7 @@
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';
import { computed, defineComponent } from 'vue';
import { defaultHamburgerProps } from './defaultProps';
import HamburgerLine from './HamburgerLine.vue';
export default defineComponent({
Expand Down Expand Up @@ -56,17 +56,19 @@ export default defineComponent({
},
fixed: {
type: Boolean,
default: true,
default: defaultHamburgerProps.fixed,
},
actived: {
type: Boolean,
deafult: defaultHamburgerProps.actived,
},
},
setup(props, { emit }) {
const isActive = ref(false);
const isActive = computed(() => props.actived);
const onClick = () => {
isActive.value = !isActive.value;
console.log(isActive.value);
emit('update:hamburger', isActive.value);
emit('update:hamburger', !isActive.value);
};
return {
Expand Down
2 changes: 2 additions & 0 deletions src/components/Base/Button/Hamburger/defaultProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ export const defaultHamburgerProps = {
margin: '1rem',
lineHeight: '2px',
strokeColor: globalCSS.color.sub700,
actived: false,
fixed: false,
};
25 changes: 18 additions & 7 deletions src/components/Layout/Sidebar/Sidebar.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
<template>
<aside class="sidebar" :class="sidebarClosed ? 'sidebar--closed' : ''">
<aside
ref="sidebarRef"
class="sidebar"
:class="isActive ? 'sidebar--closed' : ''"
>
<slot></slot>
</aside>
</template>

<script lang="ts">
import { computed, defineComponent, onMounted, onUnmounted } from 'vue';
import { computed, defineComponent, onMounted, onUnmounted, ref } from 'vue';
import { defaultSidebarProps } from './defaultProps';
export default defineComponent({
Expand Down Expand Up @@ -46,29 +50,36 @@ export default defineComponent({
},
emits: ['update:closed'],
setup(props, { emit }) {
const handleBodyClick = (e: Event) => {
const $sidebar = (e.target as HTMLElement).closest('.sidebar');
if (!$sidebar && props.isClickAway && !props.sidebarClosed) {
const sidebarRef = ref(null);
const isActive = computed(() => props.sidebarClosed);
const onClickAway = (e: Event) => {
if (!props.isClickAway || !sidebarRef.value) return;
if (!props.sidebarClosed) {
emit('update:closed', true);
} else {
emit('update:closed', props.sidebarClosed);
}
};
onMounted(() => {
if (props.isClickAway) {
document.body.addEventListener('click', handleBodyClick);
document.body.addEventListener('click', onClickAway);
}
});
onUnmounted(() => {
if (props.isClickAway) {
document.body.removeEventListener('click', handleBodyClick);
document.body.removeEventListener('click', onClickAway);
}
});
const transitionDuration = computed(() => props.duration + 's');
return {
isActive,
sidebarRef,
transitionDuration,
};
},
Expand Down
78 changes: 60 additions & 18 deletions src/stories/Sidebar.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,94 @@ import Hamburger from '@components/Base/Button/Hamburger/Hamburger.vue';
import { computed, ref } from 'vue';
import { Meta, StoryFn } from '@storybook/vue3';
import { defaultSidebarProps } from '@/components/Layout/Sidebar/defaultProps';
import { action } from '@storybook/addon-actions';

export default {
title: 'Layout/Sidebar',
component: { Sidebar, Hamburger },
component: { Sidebar },
subcomponents: { Hamburger },

argTypes: {
width: { control: { type: 'text' } },
padding: { control: { type: 'text' } },
backgroundColor: { control: 'color' },
border: { control: { type: 'text' } },
headerHeight: { control: { type: 'text' } },
delay: { control: { type: 'number', min: 0.1, max: 1, step: 0.1 } },
isClickAway: { control: { type: 'boolean' } },
width: {
controls: { type: 'text' },
description: '너비를 설정할 수 있어요.',
},
padding: {
controls: { type: 'text' },
description: '패딩을 설정할 수 있어요.',
},
bgColor: {
controls: { type: 'color' },
description: '사이드바의 색상을 설정할 수 있어요.',
},
sidebarClosed: {
controls: { type: 'boolean' },
description: '햄버거 버튼과 사이드바가 닫힐지를 결정할 수 있어요.',
},
border: {
controls: { type: 'text' },
description:
'**오른쪽의 선 굵기**를 설정할 수 있어요. 형식은 `1px solid {{색상}}`입니다.',
},
headerHeight: {
controls: { type: 'text' },
description: '헤더의 높이만큼 사이드바의 크기를 줄여요.',
},
duration: {
controls: { type: 'number', min: 0.1, max: 1, step: 0.1 },
description: '사이드바가 닫히는 속도를 조절해요.',
},
isClickAway: {
controls: { type: 'boolean' },
description: '바깥을 눌러도 사이드바가 닫힐지를 결정해요.',
},
'update:closed': {
description:
'emit으로 사이드바의 상태를 관찰할 수 있어요. 이를 통해 `sidebarClosed`를 조정합니다.',
},
},
} as Meta<typeof Sidebar>;

const Template = (args) => ({
components: { Sidebar, Hamburger },
setup() {
const sidebarClosed = ref(false);
const onClickHamburger = (value) => {
const sidebarClosed = ref(args.sidebarClosed);
const updateClosed = action('update:closed');

const updateCloseSidebar = (value) => {
sidebarClosed.value = value;
updateClosed(value);
};

return {
sidebarClosed,
onClickHamburger,
updateCloseSidebar,
args: computed(() => ({ ...args, sidebarClosed: sidebarClosed.value })),
};
},
/**
* @throws
* 스토리북에서는 fixed가 적용이 잘 되지 않습니다.
* 따라서 이를 style로 absolute로 임시방편으로 설정합니다.
*/
template: `
<div>
<div style=" position: relative; width: 100vw;height: 100vh;">
<Hamburger
fixed
@update:hamburger="onClickHamburger"
style="position: absolute; z-index: 20;"
:actived="sidebarClosed"
@update:hamburger="updateCloseSidebar"
/>
<Sidebar
style="position: absolute; z-index: 10;"
v-bind="args"
@update:closed="(value) => {
sidebarClosed = value
args.sidebarClosed = value
}"
@update:closed="updateCloseSidebar"
>
내용을 입력할 수 있어요. 🙇🏻‍♂️
</>
</div>
`,
methods: { action },
});

export const SidebarComponent: StoryFn<typeof Sidebar> = Template.bind({});
Expand Down

0 comments on commit df5c929

Please sign in to comment.