Storybook: ํ•˜์œ„ ์Šคํ† ๋ฆฌ/๊ณ„์ธต ๊ตฌ์กฐ

์— ๋งŒ๋“  2016๋…„ 04์›” 28์ผ  ยท  79์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: storybookjs/storybook

"ํ•˜์œ„ ์ด์•ผ๊ธฐ" ๋˜๋Š” ์ด์•ผ๊ธฐ์˜ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด ๊ฒฝ์šฐ์—๋Š” ๋™์ผํ•œ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ํฌํ•จ๋œ ๋‹ค์–‘ํ•œ ๋ฏธ๋‹ˆ "์•ฑ"์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ์†”๋ฃจ์…˜์€ ui.core.foo ๋ฐ ui.core.bar ์™€ ๊ฐ™์€ ์ด๋ฆ„์˜ ์ƒ์ ์„ ํ‘œ์‹œํ•˜๋Š” ์˜ต์…˜์ž…๋‹ˆ๋‹ค.

โ””โ”€โ”€ core
    โ”œโ”€โ”€ bar
    โ””โ”€โ”€ foo

๋…ธ๋“œ ํ™•์žฅ ๋ฐ ์ถ•์†Œ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

stories feature request merged ui

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์–˜๋“ค ์•„!

์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์ด ๊ฐ€๊นŒ์šด ์žฅ๋ž˜์— ๊ณ„ํš๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์‚ฌ์‹ค์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ด๊ฒƒ์ด Storybook Addons API๋ฅผ ํ†ตํ•ด ๊ทธ๋Ÿฌํ•œ ๋™์ž‘์„ ์–ป์„ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๊ทธ๋Ÿฌํ•œ ์• ๋“œ์˜จ์ž…๋‹ˆ๋‹ค.



์Šคํ† ๋ฆฌ๋ถ ์ฑ•ํ„ฐ

์Šคํ† ๋ฆฌ๋ถ ์ฑ•ํ„ฐ

(ํ•˜์œ„) ์Šคํ† ๋ฆฌ์— ๋Œ€ํ•œ ๋ฌด์ œํ•œ ์ˆ˜์ค€์˜ ์ค‘์ฒฉ ์ถ”๊ฐ€

preview

์ค‘์ฒฉ ์ˆ˜์ค€์„ ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ์Šคํ† ๋ฆฌ์— .chapter(name) ๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

// stories.js:

storiesOf('React App', module)
    .chapter('Left panel')
        .add('Button 1', fn(1))
        .add('Button 2', fn(2))
        .chapter('Bottom Panel')
            .add('Input 3', fn(3))
            .add('Input 4', fn(4))
            .endOfChapter()
        .chapter('Header Panel')
            .add('Input 5', fn(5))
            .add('Input 6', fn(6))
            .endOfChapter()
        .endOfChapter()
    .chapter('Right panel')
        .add('Button 7', fn(7))
        .add('Button 8', fn(8))
        .endOfChapter()

ํŠน์ง•

  • ์„œ๋ธŒ ์Šคํ† ๋ฆฌ์˜ ๊ณ„์ธต ๊ตฌ์กฐ
  • Knobs , addWithInfo ๋ฐ ๊ธฐํƒ€ ์• ๋“œ์˜จ๊ณผ ํ˜ธํ™˜
  • storyDecorator ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ์žฅ์„ ๋ž˜ํ•‘ํ•˜์‹ญ์‹œ์˜ค.

๋ฐ๋ชจ ํŽ˜์ด์ง€

ํ”„๋กœ์ ํŠธ

์˜ˆ์‹œ


๋ชจ๋“  ํ”ผ๋“œ๋ฐฑ์€ ๋งค์šฐ ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค! :)

๋ชจ๋“  79 ๋Œ“๊ธ€

ํ˜„์žฌ๋กœ์„œ๋Š” ์ด๋ฅผ ๊ตฌํ˜„ํ•  ๊ณ„ํš์ด ์—†์Šต๋‹ˆ๋‹ค. ํƒ์ƒ‰์„ ์–ด๋ ต๊ฒŒ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. "ui.core", "ui.app"๊ณผ ๊ฐ™์€ ์ ์œผ๋กœ ์Šคํ† ๋ฆฌ ์ข…๋ฅ˜์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ํ•„์š”์— ๋”ฐ๋ผ ํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์•ผ๊ธฐ๊ฐ€ ๋งŽ์€ ๊ฒฝ์šฐ ๋ช‡ ๊ฐ€์ง€ ์ด์•ผ๊ธฐ์ฑ… ์ธ์Šคํ„ด์Šค๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘ ๊ฐœ์˜ ์Šคํ† ๋ฆฌ๋ถ ๊ตฌ์„ฑ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์–ด์จŒ๋“  ๊ทธ๊ฒƒ์€ ๊ทน๋‹จ์  ์ธ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

์ด ์ ์„ ๊ธฐ๊บผ์ด ์ธ์ •ํ•˜๊ณ  ๋‹ค๋ฅธ ๊ตฌ์„ฑ์„ ๋งŒ๋“ค๊ณ  ๋‹ค๋ฅธ ํฌํŠธ์—์„œ ์‹คํ–‰ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์Šคํ† ๋ฆฌ๋ถ์ด ์—ฌ๋Ÿฌ ๊ตฌ์„ฑ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ—ˆ์šฉํ•œ ๋‹ค์Œ ๋ช…๋ช…๋œ ๊ตฌ์„ฑ ํŒŒ์ผ ๊ฐ„์— ์ „ํ™˜ํ•˜๊ฑฐ๋‚˜ ๋‹ค์‹œ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๋” ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ตฌ์„ฑ์„ ์ „ํ™˜ํ•˜๋Š” UI์˜ ๊ฒฝ์šฐ ๊ตฌ์„ฑ ํŒŒ์ผ์ด ๋‹ค๋ฅธ ๊ตฌ์„ฑ ํŒŒ์ผ์„ "๋กœ๋“œ"ํ•œ ๊ฒฝ์šฐ์—๋งŒ ๋‚˜ํƒ€๋‚˜๋ฉฐ ์‚ฌ์ด๋“œ๋ฐ” ํƒ์ƒ‰์˜ ์ƒ๋‹จ ๋˜๋Š” ํ•˜๋‹จ์— ์žˆ๋Š” ์‚ฌ์ด๋“œ๋ฐ” ํ•ญ๋ชฉ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์–ด์จŒ๋“  - ๋” ํฐ ์•ฑ์˜ ๊ฒฝ์šฐ ๊ตฌ์„ฑ์„ ๋ถ„ํ• ํ•  ์ˆ˜ ์—†๊ฑฐ๋‚˜ ๋ถ„ํ• ํ•˜์ง€ ์•Š์œผ๋ฉด ์ข€ ๋ฏธ์นœ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ถ”๊ฐ€ ๊ตฌ์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ์ง€๋‚˜์น˜๊ฒŒ ๋ณต์žกํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํด๋ž˜์‹/๊ณ„์ธต ๋ณด๊ธฐ์— ๋Œ€ํ•œ ํ† ๊ธ€์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ? ์•ž์œผ๋กœ ๋ฉฐ์น  ๋™์•ˆ ๊ตฌํ˜„์„ ์‹œ์ž‘ํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ๋„ ๋งค์šฐ ๊ท€์ค‘ํ•œ ๊ธฐ๋Šฅ์ด์ง€๋งŒ ์—ฌ๋Ÿฌ ์•ฑ์ด ์•„๋‹Œ ๋‹จ์ผ ์•ฑ ๋‚ด์—์„œ ๊ตฌ์„ฑ ์š”์†Œ ์œ ํ˜•์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์•ž์œผ๋กœ ๋‚˜์•„๊ฐˆ ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋‘ ์‚ฌ์šฉ ์‚ฌ๋ก€ ๋ชจ๋‘์—์„œ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌํ˜„์„ ํ˜•์„ฑํ•˜๋Š” ๋ฐ ๋„์›€์„ ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

@travi ์šฐ๋ฆฌ์˜ ๋˜ ๋‹ค๋ฅธ ์•„์ด๋””์–ด ์ค‘ ํ•˜๋‚˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์„ ํƒํ•˜๊ธฐ ์œ„ํ•ด ํ•„ํ„ฐ ์ƒ์ž ๋ฐ”๋กœ ์•„๋ž˜์— ๋“œ๋กญ๋‹ค์šด ๋ฉ”๋‰ด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ๋Š” config.js ๋ฐ ๋‹ค๋ฅธ ํŒŒ์ผ ์„ธํŠธ์— ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ทธ๋ฃนํ™”์˜ ๋˜ ๋‹ค๋ฅธ ๊ณ„์ธต์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌํ•œ ์œ ํ˜•์˜ ์†”๋ฃจ์…˜์ด ํ˜„ ์‹œ์ ์—์„œ ์ œ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๊ธฐ์— ์ถฉ๋ถ„ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๊ทœ์น™์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋“œ๋กญ๋‹ค์šด์—์„œ ์„ ํƒ ํ•ญ๋ชฉ์œผ๋กœ ํ•ด์„๋  ์ˆ˜ ์žˆ๋Š” ๋ฒ”์ฃผ๋ฅผ ํ• ๋‹นํ•˜๋Š” ํ•ฉ๋ฆฌ์ ์ธ ๋ฐฉ๋ฒ•์ผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฒ”์ฃผ ๊ฐ„ ์—ฐ๊ฒฐ์ด ์—ฌ์ „ํžˆ ๊ฐ„๋‹จํ•˜๊ฒŒ ์œ ์ง€๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋งŒ๋“ค๊ณ  ์žˆ๋Š” ์•ฑ(๋Š์Šจํ•œ "๊ธฐ๋‘ฅ" ์˜์—ญ ์•ˆ์— ๊ตฌ์„ฑ๋œ ์ˆ˜๋ฐฑ ๊ฐœ์˜ ๊ตฌ์„ฑ ์š”์†Œ)์—์„œ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํ˜„์žฌ ์ž‘์—… ์ค‘์ธ ์˜์—ญ์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๋ฅผ ๋™์ ์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

find.file(
  /\.story\.js/,
  path.resolve(__dirname, '../src/app/components', targetComponentPath),
  function(files) {
    var requires = files.map(function(file) {
      return "require('" + path.relative(__dirname, file) + "');";
    });
    fs.writeFileSync(path.resolve(__dirname, '../.storybook/stories.js'), requires.join("\n"));
  }
);

์ฆ‰, Storybook์€ ๋‹ค๋ฅธ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋งŒ๋“ค ํ•„์š”์กฐ์ฐจ ์—†์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์ œ๊ณต ์˜ต์…˜์œผ๋กœ ์ด์— ๋Œ€ํ•œ ์ผ์ • ์ˆ˜์ค€์˜ ์ง€์›์„ ์›ํ•ฉ๋‹ˆ๋‹ค.

201์ด ์ด์— ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์— ๋Œ€ํ•œ ์–ด๋–ค ์—…๋ฐ์ดํŠธ?

+1

๋งค์šฐ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค!

+1

+1

+1

+1

+1

+1

@arunoda๋‹˜ , ์นดํ…Œ๊ณ ๋ฆฌ ๊ตฌํ˜„์— ์ง„์ „์ด ์žˆ์—ˆ๋‚˜์š”?

๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๋‘ ๊ฐœ์˜ ์Šคํ† ๋ฆฌ๋ถ ๊ตฌ์„ฑ ๊ฐ„์— ์ „ํ™˜ํ•˜๋Š” ์˜ˆ์ œ ์•ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

+1 ํ•œ ๋‹จ๊ณ„์˜ ์ถ”๊ฐ€ ์ค‘์ฒฉ์ด ์ ˆ๋Œ€์ ์œผ๋กœ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค./

+1

+1

+1

+1

+1

+1

์•ฑ์ด ์„ฑ์žฅํ•˜๋Š” ๋™์•ˆ ๊ตฌ์„ฑ ์š”์†Œ ๋ชฉ๋ก๋„ ์ปค์ง€๊ณ  ์ค‘์ฒฉ์ด ๋” ํ•„์š”ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. 1๊ฐœ ์ด์ƒ์˜ ๋ ˆ๋ฒจ์€ ์ด๋ฏธ ๋งŽ์€ ๊ฒฝ์šฐ๋ฅผ ์ปค๋ฒ„ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

+1

์–˜๋“ค ์•„!

์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์ด ๊ฐ€๊นŒ์šด ์žฅ๋ž˜์— ๊ณ„ํš๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์‚ฌ์‹ค์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ด๊ฒƒ์ด Storybook Addons API๋ฅผ ํ†ตํ•ด ๊ทธ๋Ÿฌํ•œ ๋™์ž‘์„ ์–ป์„ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๊ทธ๋Ÿฌํ•œ ์• ๋“œ์˜จ์ž…๋‹ˆ๋‹ค.



์Šคํ† ๋ฆฌ๋ถ ์ฑ•ํ„ฐ

์Šคํ† ๋ฆฌ๋ถ ์ฑ•ํ„ฐ

(ํ•˜์œ„) ์Šคํ† ๋ฆฌ์— ๋Œ€ํ•œ ๋ฌด์ œํ•œ ์ˆ˜์ค€์˜ ์ค‘์ฒฉ ์ถ”๊ฐ€

preview

์ค‘์ฒฉ ์ˆ˜์ค€์„ ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ์Šคํ† ๋ฆฌ์— .chapter(name) ๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

// stories.js:

storiesOf('React App', module)
    .chapter('Left panel')
        .add('Button 1', fn(1))
        .add('Button 2', fn(2))
        .chapter('Bottom Panel')
            .add('Input 3', fn(3))
            .add('Input 4', fn(4))
            .endOfChapter()
        .chapter('Header Panel')
            .add('Input 5', fn(5))
            .add('Input 6', fn(6))
            .endOfChapter()
        .endOfChapter()
    .chapter('Right panel')
        .add('Button 7', fn(7))
        .add('Button 8', fn(8))
        .endOfChapter()

ํŠน์ง•

  • ์„œ๋ธŒ ์Šคํ† ๋ฆฌ์˜ ๊ณ„์ธต ๊ตฌ์กฐ
  • Knobs , addWithInfo ๋ฐ ๊ธฐํƒ€ ์• ๋“œ์˜จ๊ณผ ํ˜ธํ™˜
  • storyDecorator ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ์žฅ์„ ๋ž˜ํ•‘ํ•˜์‹ญ์‹œ์˜ค.

๋ฐ๋ชจ ํŽ˜์ด์ง€

ํ”„๋กœ์ ํŠธ

์˜ˆ์‹œ


๋ชจ๋“  ํ”ผ๋“œ๋ฐฑ์€ ๋งค์šฐ ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค! :)

@UsulPro ๋ฐ˜๊ฐ‘์Šต๋‹ˆ๋‹ค!

@UsulPro Storybook Chapters๋Š” ํ›Œ๋ฅญํ•œ ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”!

@UsulPro๊ฐ€ ์ •ํ™•ํžˆ ์ œ๊ฐ€

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„! @UsulPro ( storybook-chapters ๋กœ ๋ฉ‹์ง„ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ)์™€ ๊ฒฝ์Ÿํ•˜๋ ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ preview ์ฐฝ. ์ด๊ฒƒ์€ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๋ฌธ์„œ์™€ detailed components view ์‚ฌ์ด์—์„œ ์‰ฝ๊ฒŒ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค related components view ๋ณด์—ฌ์ค„ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ์Šคํ† ๋ฆฌ๋ถ ์ธ์Šคํ„ด์Šค๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒฝ๋Ÿ‰ ๋ฒ„์ „์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์œ ์šฉํ•˜๋‹ค๋ฉด ์—ฌ๊ธฐ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค - https://github.com/majapw/storybook-addon-toggle

๋‚˜๋Š” @UsulPro ์˜ ๋ฉ‹์ง„ storybook-chapters ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ ํŒŒ์ผ ๊ณ„์ธต์„ ์Šคํ† ๋ฆฌ๋ถ ์ฑ•ํ„ฐ๋กœ ๋ฏธ๋Ÿฌ๋งํ•  ์Šคํ† ๋ฆฌ๋ถ ๋กœ๋”๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค: storybook-filepath-chapters

์ด๋ฅผ ํ†ตํ•ด ๋‚ด ์Šคํ† ๋ฆฌ๋ฅผ ๊ตฌ์„ฑ ์š”์†Œ์™€ ํ•จ๊ป˜ ์ธ๋ผ์ธ์œผ๋กœ _stories ํŒŒ์ผ์ด๋‚˜ ํด๋”์— ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋กœ๋”๋Š” ๋ชจ๋“  ์Šคํ† ๋ฆฌ ํŒŒ์ผ์„ ์ฐพ์•„ ํ•ด๋‹น ํƒ์ƒ‰ ๊ตฌ์กฐ์— ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋œปํ•œ ํ”ผ๋“œ๋ฐฑ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค, ์—ฌ๋Ÿฌ๋ถ„!

@hadfieldn ์˜ storybook-filepath-chapters ๋ฅผ ๋ณด๋‹ˆ ์ •๋ง ๋ฉ‹์ง€๋„ค์š” ! ๐Ÿ‘

๋‚˜๋Š” storybook-addon-toggle ๋ฅผ ์˜ˆ๋กœ ๋“ค์ž๋ฉด, ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์‹ฌ์ธต์ ์œผ๋กœ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ƒ์œ„์—์„œ๋„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์„ ๊ฐ–๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์‹ค ๊ธฐ์ˆ ์ ์œผ๋กœ๋Š” ๊ฐ€๋Šฅํ•˜์ง€๋งŒ (์• ๋“œ์˜จ API ๋‚ด์—์„œ ์œ ์ง€) ์ตœ์„ ์˜ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•˜๊ธฐ๋Š” ์–ด๋ ต๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ์ด๊ฒƒ์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ(@majapw์™€ ๊ฐ™์€)๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์• ๋“œ์˜จ ํŒจ๋„์„ ํ†ตํ•ด ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„์ง ์Šคํ† ๋ฆฌ ์œ„์— ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์ถ”๊ฐ€ํ•  ๊ณ„ํš์€ ์—†์ง€๋งŒ storybook-chapters ์• ๋“œ์˜จ์—๋Š” ์ด์ œ API ๊ฐ€ ์žˆ์œผ๋ฉฐ ์ด๋Ÿฌํ•œ ๊ณ„์ธต ๊ตฌ์กฐ์˜ ๊ตฌ์„ฑ์„ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

enable / disable ์Šคํ† ๋ฆฌ ํ‘œ์‹œ/์ˆจ๊ธฐ๊ธฐ



๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.


-

์Šคํ† ๋ฆฌ์— enable() / disable() ๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”. ์ธ์ˆ˜๋กœ ์ œ์–ด ๊ธฐ๋Šฅ์„ ์ „๋‹ฌํ•  ์ฝœ๋ฐฑ์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

let toLight = () => {};
let toDark = () => {};

storiesOf('Heroes Lightside', module)
    .enable((en) => { toLight = en; })
    .add('Yoda', info('Yoda'))
    .add('Mace Windu', info('Mace Windu'));

storiesOf('Heroes Darkside', module)
    .disable((en) => { toDark = en; })
    .add('Darth Sidious', info('Darth Sidious'))
    .add('Darth Maul', info('Darth Maul'));

๋‹น์‹ ์€ ์‚ฌ์šฉํ•  ์ˆ˜์žˆ๋Š” toLight(false) ์ˆจ๊ธธ Heroes Lightside ๋ฐ toDark(true) ๋ณด์—ฌ Heroes Darkside ์ด์•ผ๊ธฐ๋ฅผ. toLight ๋ฐ toDark ๋ฅผ ์ผ๋ถ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ๋„ฃ๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์Šคํ† ๋ฆฌ์—์„œ ์ฝœ๋ฐฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ์˜ˆ๋ฅผ ๋ณด์—ฌ ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

storiesOf('Choose Your Side', module)
    .add('Lightside', () => {
        toLight();
        toDark(false);
        return (<div>{'Lightside selected'}</div>);
    })
    .add('Darkside', () => {
        toDark();
        toLight(false);
        return (<div>{'Darkside selected'}</div>);
    });

์ด์ œ Choose Your Side , Heroes Lightside ๋ฐ Heroes Darkside 3๊ฐ€์ง€ ์Šคํ† ๋ฆฌ ์„ธํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰ ๋‘ ๊ฐœ ์ค‘ ํ•˜๋‚˜๋งŒ ๋ณผ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ฒซ ๋ฒˆ์งธ๋Š” ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ๋ฆด๋ฆฌ์Šค ์—์„œ๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ๊ฐ€๋Šฅํ•œ ์• ๋“œ์˜จ ํŒจ๋„์„ ํ†ตํ•ด ์Šคํ† ๋ฆฌ์˜ ๊ฐ€์‹œ์„ฑ์„ ์ œ์–ดํ•˜๋Š” โ€‹โ€‹๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๊ณ„ํš์ž…๋‹ˆ๋‹ค.

-

ํ™œ์„ฑํ™”/๋น„ํ™œ์„ฑํ™” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ์„ ํ˜ธํ•˜๋Š” ๋กœ์ง์œผ๋กœ ์‚ฌ์šฉ์ž ์ •์˜ ํƒ์ƒ‰์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ์™„์ „ํ•œ ์˜ˆ

์šฐ๋ฆฌ๋Š” ๊ณ„์ธต ๊ตฌ์กฐ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๊ตฌํ˜„ํ•  ๊ฒƒ์ด์ง€๋งŒ ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๊ฐœ๋…์„ ์ข‹์•„ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • UX ํ˜„๋ช…ํ•œ
  • ๊ทธ๋ฃน์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•

UX ํ˜„๋ช…ํ•œ, ๋‚˜๋Š” ์ด ์•„์ด๋””์–ด๋ฅผ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค: http://multi-level-push-menu.make.rs/demo/basichtml/basichtml.html

๊ตฌ์„ฑ์„ ์•„์ง ๋ชจ๋ฆ…๋‹ˆ๋‹ค. ํŒŒ์ผ ํƒ์ƒ‰์„ ์‚ฌ์šฉํ•˜๊ณ  ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ๋ฏธ๋Ÿฌ๋งํ•˜๊ฑฐ๋‚˜ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. https://github.com/sm-react/storybook-chapters/issues/1#issue -215446017

@ndelangen ์Šคํ† ๋ฆฌ ์™ธ๋ถ€์—์„œ ํƒ์ƒ‰์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋„๋ก (์ ์–ด๋„ ์„ ํƒ์ ์œผ๋กœ?) ์ƒ๊ฐ์„

@jackmccloy ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌด์Šจ ๋ง์ธ์ง€ ์ž์„ธํžˆ ๋ง์”€ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

๋‹ค๋ฅธ ๋ฌธ์ œ์—์„œ ์–ธ๊ธ‰ํ–ˆ์ง€๋งŒ ๋ฒ”์ฃผ์— ๋Œ€ํ•œ ๋‚ด ๋ชฉํ‘œ๋Š” ๋Œ€๋ถ€๋ถ„ ์›์ž ์„ค๊ณ„ ์™€ ์ •๋ ฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŒจํ„ด ๋žฉ ์€ ์•„ํ† ๋ฏน ๋””์ž์ธ์„ ์œ„ํ•œ ๊ณต์‹ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ ์ ‘๊ทผ ๋ฐฉ์‹์ด์ง€๋งŒ ์Šคํ† ๋ฆฌ๋ถ์— ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋งˆ์ง€๋ง‰ ๋‚จ์€ ๊ณต๋ฐฑ์„ ์ฑ„์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ํ•ด๋‹น ๋ฒ”์ฃผ์˜ ์ตœ์ƒ์œ„ ํด๋”์— ์ •๋ ฌํ•˜๋ฏ€๋กœ ์ตœ์ƒ์œ„ ํด๋”๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋ฒ”์ฃผ์— ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋„ ์ดฌ์˜์— ์ข‹์€ ์ผ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@travi ํด๋” ๋ ˆ์ด์•„์›ƒ์„ ์ธ์‡„ํ•ด ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ด ์ •ํ™•ํ•œ ๋ชฉ์ ์„ ์œ„ํ•ด ์Šคํ† ๋ฆฌ๋ถ์„ ๊ฐœ์„ ํ•˜๋Š” ๋ฐ ํ™•์‹คํžˆ ๊ด€์‹ฌ์ด ์žˆ์ง€๋งŒ ํด๋” ๊ตฌ์กฐ์—์„œ ์ด ๋ถ„๋ฅ˜๋ฅผ ์ฝ๋Š” ๋ฐ ๊ธฐ์ˆ ์ ์œผ๋กœ ํ•„์š”ํ•œ ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€ ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ณธ์งˆ์ ์œผ๋กœ

project root
|
+--
|  +-- atoms
|  |  +-- foo
|  |    +-- index.js // the component
|  |    +-- stories.js
...
|  +-- molecules
|  |  +-- bar
|  |    +-- index.js
|  |    +-- stories.js
...
|  +-- organisms
|  |  +-- baz
|  |    +-- index.js
|  |    +-- stories.js

๊ทธ๊ฒŒ ๋„์›€์ด ๋˜๋‚˜์š”? ๊ฐ ์ตœ์ƒ์œ„ ํด๋” ์•„๋ž˜์— ์—ฌ๋Ÿฌ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ์œผ๋ฉฐ ๋•Œ๋กœ๋Š” ๋‹ค๋ฅธ ํด๋” ์ˆ˜์ค€์œผ๋กœ ๊ทธ๋ฃนํ™”๋ฉ๋‹ˆ๋‹ค. ๋„์›€์ด๋œ๋‹ค๋ฉด ๋” ์ž์„ธํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๊ฒŒ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

์ข‹์•„์š”, ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ config.js ํ”Œ๋ž˜๊ทธ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. autoDiscoverStories ์ •๋„. ์ฆ‰, ์Šคํ† ๋ฆฌ๋ฅผ ์ˆ˜๋™์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ํŒŒ์ผ ์‹œ์Šคํ…œ ํด๋”๊ฐ€ ๋ฒ”์ฃผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

@ndelangen ์ œ๊ฐ€ ์ƒ๊ฐํ•˜๋Š”

ํ•œ ๊ฐ€์ง€ ๊ฐ€๋Šฅ์„ฑ:
ํ˜„์žฌ ๊ฐ ์Šคํ† ๋ฆฌ๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ํ• ๋‹น๋˜๋Š” ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„์™€ ์ œ๋ชฉ์ด ํ• ๋‹น๋˜๋Š” ๋‘ ๋ฒˆ์งธ ๋‹จ๊ณ„์˜ ๋‘ ๋‹จ๊ณ„๋กœ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

storiesOf('storyCategory', module).add('storyTitle', () => <Component />)

์—ฌ๋Ÿฌ ์Šคํ† ๋ฆฌ๋ฅผ ๋™์ผํ•œ ์นดํ…Œ๊ณ ๋ฆฌ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ตฌ์กฐ๋Š” ์œ ์—ฐ์„ฑ์„ ์–ด๋Š ์ •๋„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์Šคํ† ๋ฆฌ์—๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์™€ ์ œ๋ชฉ์ด ์žˆ์–ด์•ผ ํ•˜๋ฉฐ ์นดํ…Œ๊ณ ๋ฆฌ๋Š” ์ œ๋ชฉ๋ณด๋‹ค "์ƒ์œ„ ์ˆ˜์ค€"์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ด์•ผ๊ธฐ๋ฅผ ์•ฝ๊ฐ„ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์ฆ‰

const storyData = {
  category: "category",
  title: "storyTitle",
}
stories.add(() => <Component />, storyData)

๋‹ค์–‘ํ•œ ํƒ์ƒ‰ ์˜ต์…˜์„ ๋” ์‰ฝ๊ฒŒ ์‹คํ—˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ํƒ์ƒ‰์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ •์ƒ์ ์ธ ๊ธฐ๋ณธ๊ฐ’์ด๋ฉฐ ์•„๋งˆ๋„ ์šฐ๋ฆฌ ๋Œ€๋ถ€๋ถ„์—๊ฒŒ ์ถฉ๋ถ„ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. storyData ๋Š” ์„ ํƒ ์‚ฌํ•ญ์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์—†๋Š” ์Šคํ† ๋ฆฌ๋Š” ์ตœ์ƒ์œ„ ์ˆ˜์ค€์— ํ‘œ์‹œ๋  ์ˆ˜ ์žˆ๊ณ , ์ œ๋ชฉ์ด ์—†๋Š” ์Šคํ† ๋ฆฌ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ์˜ displayName ์— ํ‘œ์‹œ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ปค๋ฎค๋‹ˆํ‹ฐ๋Š” (a) stroyData ์ถ”๊ฐ€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ (b) ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ•„๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํƒ์ƒ‰ ํŒจ๋„์ด ๋ Œ๋”๋ง๋˜๋Š” ๋ฐฉ์‹์„ ๋ณ€๊ฒฝํ•˜์—ฌ ์Šคํ† ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์„ ์‹คํ—˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ช‡ ๊ฐ€์ง€ ์•„์ด๋””์–ด:

// add an additional level to the hierarchy called subCategory
const stroyData = {
  category: "Buttons",
  subCategory: "Blue",
  title: "BlueButton",
}
stories.add(() => <BlueButton />, storyData)

// add tags to a story that you could then filter by
const stroyData = {
  category: "Buttons",
  tags: ["button", "homepage"],
  title: "HomepageButton",
}
stories.add(() => <HomepageButton />, storyData)

// have a story to appear in multiple categories
const stroyData = {
  categories: ["Buttons", "Homepage Elements"],
  title: "HomepageButton",
}
stories.add(() => <HomepageButton />, storyData)

๋ฉ‹์ง„! ๊ทธ๊ฒƒ์€ ์•„์ฃผ ๊ธฐ๋ณธ์ด๋ฉฐ ์‹ค์ œ๋กœ ํ™•์žฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์— ๋Œ€ํ•ด ์ž ์‹œ ์ƒ๊ฐํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿค”

์—„์ฒญ๋‚œ. ๊ฒฐ์ •ํ•œ ์‚ฌํ•ญ์„ ์•Œ๋ ค์ฃผ์„ธ์š”. ์–ด๋–ค ๋ฐฉํ–ฅ์„ ์„ ํƒํ•˜์‹œ๋“  ์ œ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ณณ์—์„œ ์ œ์•ˆํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. - ํ”„๋กœ์ ํŠธ์˜ ์—ด๋ ฌํ•œ ํŒฌ

@jackmccloy ์˜ ์ œ์•ˆ์€ ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค. ๋ฉ‹์ง„ ์•„์ด๋””์–ด์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

๊ทธ๋Ÿฌ๋‚˜ UI๋ฅผ ์ผ๋ จ์˜ "์‹œ๊ฐ์  ํ…Œ์ŠคํŠธ ์‚ฌ๋ก€"๋กœ ์ƒ๊ฐํ•˜๊ณ  ์ƒํƒœ๋‹น add() ํ˜ธ์ถœ์„ ์‚ฌ์šฉํ•˜์—ฌ UI ์ƒํƒœ๋ฅผ ๊ฐœ๋ณ„ ์Šคํ† ๋ฆฌ๋กœ ์‰ฝ๊ฒŒ ์ •์˜ํ•˜๋Š” Storybooks์˜ ๊ฐ•๋ ฅํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

add() ํ˜ธ์ถœ์— ์Šคํ† ๋ฆฌ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๊ฒƒ์€ ์ž˜๋ชป๋œ ์ˆ˜์ค€์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค. ๋™์ผํ•œ ์ œ์•ˆ์„ ๋ณด๊ณ  ์‹ถ์ง€๋งŒ storiesOf() ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ:

storiesOf({
  title: Component,
  category: "My Category"
}, module)
  .add("when empty", () => <List items=[] />)
  .add("with items", () => <List items=["one", "two", "three"] />)
  .add("etc.", () => <List items={etc} />);

Component.displayName ์—์„œ ์ œ๋ชฉ์„ ๊ฐ€์ ธ๊ฐˆ ์ˆ˜ ์žˆ๊ณ  ํ•˜์œ„ ๋ฒ”์ฃผ์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ๋ชจ๋“  ์•„์ด๋””์–ด๋‚˜ ์—ฌ๋Ÿฌ ๋ฒ”์ฃผ์— ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์•„์ด๋””์–ด๊ฐ€ ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค. ์ƒํƒœ ์ถ”๊ฐ€์˜ ๋‹จ์ˆœ์„ฑ์„ ์œ ์ง€ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

๋ฒ”์ฃผ๊ฐ€ ์ •์˜๋œ ์œ„์น˜์— ๊ด€๊ณ„์—†์ด ๋ช…์‹ฌํ•ด์•ผ ํ•  ํ•œ ๊ฐ€์ง€๋Š” ๋‹ค๋ฅธ ํŒŒ์ผ์ด ๋ฒ”์ฃผ์— ์ถ”๊ฐ€๋  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ๋‹จ์ผ ํŒŒ์ผ์—์„œ๋งŒ ์ •์˜๋  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋งค์šฐ ์ œํ•œ์ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@travi์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ๋ฌธ์ž์—ด(์ผ๋ถ€ ์‚ฌ์ „ ํ‚ค์— ๋งคํ•‘๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ์ƒํ•จ)์ด ๋งค๋ ฅ์ ์ธ ์ด์œ ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜คํƒ€๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋‚ด ๋ฒ”์ฃผ๋ฅผ ํ•œ ๊ณณ์—์„œ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

// categories.js
export const Layouts = "Layouts";
export const Components = "Components";
export const Styles =  "Styles";

// DashboardLayout.story.js
import { Layouts } from "../categories";
import DashboardLayout from "./DashboardLayout";

storiesOf({
  title: DashboardLayout,
  category: Layouts
}, module)
  .add("default", () => <DashboardLayout />);

๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ๋‚ด ์•ฑ์— ๋‚จ๊ฒจ์ง„ ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@theinterned @jackmccloy ๊ท€ํ•˜์˜ ์ œ์•ˆ์ด ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค .

๋‚˜๋Š” ๋‹น์‹ ์ด ์ž„์˜์˜ ๊นŠ์ด์˜ ๊ณ„์ธต์—์„œ ๋‹น์‹ ์˜ ์ œ์•ˆ์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„์ง€ ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. category / subCategory ๊ฒฝ๋กœ ๊ตฌ์„ฑ ์š”์†Œ์˜ ๋ฐฐ์—ด์ด ์žˆ๋Š” path ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (๋‹น์‹ ์ด ๊ฑฐ๊ธฐ์— ๊ตฌ์ฒด์ ์ธ ๋‚ด์šฉ์„ ์˜๋„ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ ๋‹น์‹ ์˜ ์•„์ด๋””์–ด๋ฅผ ์ธ์šฉํ–ˆ์„ ๋ฟ์ž…๋‹ˆ๋‹ค.)

๋˜ํ•œ ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜์—ฌ ํƒ์ƒ‰ ๊ณ„์ธต์„ ์ƒ์„ฑํ•˜๋Š” ๊ตฌ์„ฑ ์˜ต์…˜์˜ ์•„์ด๋””์–ด๊ฐ€ ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค. ์ด ์˜ต์…˜์ด ํ™œ์„ฑํ™”๋˜๋ฉด path ์ธ์ˆ˜๋Š” ์„ ํƒ ์‚ฌํ•ญ์ด ๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ํ™•์žฅ ๋ชฉํ‘œ์— ๊ฐ€๊น์ง€๋งŒ ๊ณ„์ธต ๊ตฌ์กฐ์˜ ๊ฐ ์Šคํ† ๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ๋ณ„๋„์˜ ์ฒญํฌ๋กœ ๋กœ๋“œํ•˜์—ฌ ์Šคํ† ๋ฆฌ๋ถ์ด ์ปค์งˆ์ˆ˜๋ก ๊ฐ€๋ณ๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์Šคํ† ๋ฆฌ๋ถ ๋กœ๋”๊ฐ€ ํŠน์ • ํŒŒ์ผ ์‹œ์Šคํ…œ ํด๋”๋ฅผ ๋ฃจํŠธ ์ปจํ…์ŠคํŠธ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์‹คํ–‰ํ•˜๋„๋ก ํ—ˆ์šฉํ•˜์—ฌ ์ „์ฒด ํ”„๋กœ์ ํŠธ์˜ ๋ชจ๋“  ์Šคํ† ๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ผ ํ•ด๋‹น ํด๋”์— ์ •์˜๋œ ์Šคํ† ๋ฆฌ๋งŒ์œผ๋กœ ์Šคํ† ๋ฆฌ๋ถ์„ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์Šต๋‹ˆ๋‹ค.

์‚ฌ๋žŒ๋“ค์€ ๊ตฌ์„ฑ์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋ฏธ๋ฆฌ ์ •์˜/๋“ฑ๋กํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๊นŒ?

// config.js
import { configure, addCategory } from '@kadira/storybook';

function init() {
  require('../src/stories');
  addCategory({
    id: 'atom',
    name: 'Atoms',
    index: 0
  });
  addCategory({
    id: 'molecule',
    name: 'Molecules',
    index: 1
  })
}

configure(init, module);
// component.story.js
import Component from "./Component";

storiesOf({
  title: Component,
  category: 'atom'
}, module)
  .add("default", () => <DashboardLayout />);

category: ['atom', 'deprecated'] ๋ฐฐ์—ด์„ ์ง€์›ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์™œ ์•ˆ ๋ ๊นŒ์š”?

์ด๊ฒƒ์€ ์›์ž ์„ค๊ณ„์—์„œ ์ค‘์š”ํ•œ ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ์ˆœ์„œ๋กœ ๋ฐฐ์น˜๋˜๋„๋ก ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๊ตฌ์„ฑ์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ฒƒ์€ ์ข‹์ง€๋งŒ ๋งค์ง ๋ฌธ์ž์—ด์€ ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค ๐Ÿ‘Ž

๊ทธ๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ๋ฌธ์ž์—ด๊ณผ ์ผ์น˜ํ•˜๊ธฐ๋ฅผ ํฌ๋งํ•˜์ง€ ์•Š๊ณ  ๊ตฌ์„ฑ์— ์ •์˜๋œ ๊ฒƒ์—์„œ ์Šคํ† ๋ฆฌ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒฝ์šฐ +1

@ndelangen์ด ๋ฒ”์ฃผ๋ฅผ

Storybook์—์„œ ๋‚ด๊ฐ€ ์ข‹์•„ํ•˜๋Š” ํ•œ ๊ฐ€์ง€๋Š” ๊ตฌ์„ฑ ์š”์†Œ์™€ ๊ฐ™์€ ์œ„์น˜์— story.jsx ํŒŒ์ผ์ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ Storybook์— ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ ๋ณด์ฆ -
story.jsx ํŒŒ์ผ์ด ์กด์žฌํ•˜๋ฉด ์Šคํ† ๋ฆฌ๊ฐ€ ์กด์žฌํ•œ๋‹ค๋Š” ๊ฒƒ - ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋ฏธ๋ฆฌ ์ •์˜ํ•˜์—ฌ ์ทจ์†Œํ•ด์„œ๋Š” ์•ˆ ๋˜๋Š” ์ค‘์š”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•ด๋‹น ๋ณด๊ธฐ์—์„œ ๊ตฌ์„ฑ์˜ ๋ฒ”์ฃผ์— ๋Œ€ํ•ด id ๋ฐ index ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์™€ ๊ฐ™์€ ๊ฒƒ(์˜ต์…˜ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๊ฐ€์ •)์ด ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

setOptions({
  categoryOrder: [
    "First Category",
    "Second Category",
    "Third Category",
});

์—ฌ๊ธฐ์„œ First Category , Second Category , Third Category ๋Š” ๋ฐ˜๋“œ์‹œ ์ฒซ ๋ฒˆ์งธ, ๋‘ ๋ฒˆ์งธ, ์„ธ ๋ฒˆ์งธ๋กœ ํ‘œ์‹œ๋˜๋ฉฐ ์Šคํ† ๋ฆฌ์— ์„ ์–ธ๋œ ๋‹ค๋ฅธ ์นดํ…Œ๊ณ ๋ฆฌ๋Š” ์ด ์„ธ ๊ฐœ ๋’ค์— ์•ŒํŒŒ๋ฒณ์ˆœ์œผ๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž„์˜ ๊นŠ์ด ์ค‘์ฒฉ์„ ์ œ์–ดํ•˜๋Š” โ€‹โ€‹ํ˜„๋ช…ํ•œ ๋ฐฉ๋ฒ•์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

categoryOrder: [
  {
    "Atoms": [
      {
        "Buttons": []
      }
    ],
  }, {
    "Molecules": [],
}],

์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ "๋ฒ„ํŠผ"์ธ ์Šคํ† ๋ฆฌ๋Š” Atoms -> Buttons ์•ˆ์— ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. "Atoms" ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์Šคํ† ๋ฆฌ๋Š” Atoms , Buttons (๊ทธ๋Ÿฌ๋‚˜ ๋‚ด๋ถ€๋Š” ์•„๋‹˜) ๋“ฑ์— ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๋Š” ๊ตฌ์„ฑ ์—†์ด ํ•œ ์ˆ˜์ค€์˜ ๊นŠ์ด(์ง€๊ธˆ๊ณผ ๊ฐ™์ด)์™€ ์ตœ์†Œํ•œ์˜ ๊ตฌ์„ฑ์œผ๋กœ ์ž„์˜ ์ˆ˜์ค€์˜ ๊นŠ์ด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ ๊ฒƒ์€ ์Šคํ† ๋ฆฌ ์ž์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ ๊นŠ์ด๊ฐ€ ์žˆ๋Š” ์นดํ…Œ๊ณ ๋ฆฌ(๊ตฌ์„ฑ ์ˆ˜์ค€์—์„œ ์„ค์ •)๊ฐ€ ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค(์ฆ‰, ์Šคํ† ๋ฆฌ๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋งŒ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ๊ณ„์ธต ๊ตฌ์กฐ์—์„œ ๋‚˜ํƒ€๋‚˜๋Š” ์œ„์น˜๋ฅผ ์ •์˜ํ•˜์ง€ ์•Š์Œ).

@theinterned ์ƒํƒœ ์ถ”๊ฐ€์˜ ๋‹จ์ˆœ์„ฑ์„ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์— ๋‹ค์‹œ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ b/c๋Š” ๋…ธ๋ธŒ ์• ๋“œ์˜จ์„ ๋งŽ์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ €๋Š” ๊ตฌ์„ฑ ์š”์†Œ์™€ ์Šคํ† ๋ฆฌ ์‚ฌ์ด์— 1-1 ๊ด€๊ณ„๋ฅผ ์œ ์ง€ํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๊ณ  ์Šคํ† ๋ฆฌ ์ œ๋ชฉ์€ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์ƒํƒœ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

๋‘ ์‚ฌ์šฉ ์‚ฌ๋ก€ ๋ชจ๋‘์—์„œ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ ๊ฐ€์ง€ ์ž ์žฌ์ ์ธ ์†”๋ฃจ์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

const storyData = {
  category: "category",
  title: "first item",
}
stories.add(() => <Component />, storyData)
  .add(() => <Component />, {title: "second item"})
  .add(() => <Component />, {title: "third item"})

์—ฌ๊ธฐ์„œ (a) ์Šคํ† ๋ฆฌ์˜ ์ˆœ์„œ๋Š” ์„ ์–ธ๋œ ์œ„์น˜์—์„œ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ณ (์™ธ๋ถ€ ๊ตฌ์„ฑ์ด ํ•„์š”ํ•˜์ง€ ์•Š์Œ) (b) storyData ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ์ด์ „ ๊ฐ์ฒด๋ฅผ ๋ณด์กดํ•˜์—ฌ ๋‹ค์Œ ๊ฐ’๋งŒ ๋ฎ์–ด์”๋‹ˆ๋‹ค. ๋ช…์‹œ์ ์œผ๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ƒฅ ์ƒ๊ฐ.

์ตœ์ƒ์œ„ ์นดํ…Œ๊ณ ๋ฆฌ๋งŒ์œผ๋กœ๋„ ํฅ๋ถ„๋˜์ง€๋งŒ, ์ค‘์ฒฉ๋œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ง€์›ํ•  ๋งŒํผ ์ถฉ๋ถ„ํžˆ ์ง„ํ–‰๋œ๋‹ค๋ฉด ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„์ด ๋‹ค๋ฅธ ์นดํ…Œ๊ณ ๋ฆฌ ๊ฐ„์— ๊ณ ์œ ํ•  ๊ฒƒ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•˜์ง€ ์•Š๋‹ค๋Š” ์ ์€ ์ฃผ๋ชฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์›์ž ์„ค๊ณ„ ์˜ˆ๋ฅผ ๊ณ„์†ํ•˜๋ฉด ์›์ž, ๋ถ„์ž ๋ฐ ์œ ๊ธฐ์ฒด์˜ ์ตœ์ƒ์œ„ ๋ฒ”์ฃผ ๊ฐ๊ฐ์— ๋Œ€ํ•ด ๋™์ผํ•œ ์ด๋ฆ„์˜ ํ•˜์œ„ ๋ฒ”์ฃผ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ํŒจํ„ด ๋žฉ ๋ฐ๋ชจ ์—์„œ ์–‘์‹์ด ์ด์— ๋Œ€ํ•œ ์ข‹์€ ์˜ˆ์ž…๋‹ˆ๋‹ค. ๊ฐœ๋ณ„ ํ•„๋“œ ์š”์†Œ๋Š” ์›์ž ์•„๋ž˜์— ๋‚˜์—ด๋˜๊ณ  ํ•„๋“œ์™€ ๋ ˆ์ด๋ธ”์˜ ์กฐํ•ฉ์€ ๋ถ„์ž ์•„๋ž˜์— ๋‚˜์—ด๋˜๋ฉฐ ์™„์ „ํ•œ ํ˜•ํƒœ๋กœ ๊ทธ๋ฃนํ™”๋œ ์—ฌ๋Ÿฌ ํ•„๋“œ๋Š” ์œ ๊ธฐ์ฒด ์•„๋ž˜์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

ํฅ๋ฏธ๋กœ์šด ์ƒ๊ฐ์€ ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์ œ๋ชฉ, ์Šคํ† ๋ฆฌ ๋ฐ ์Šคํ† ๋ฆฌ ํŒŒ์ผ์˜ ๊ฒฝ๋กœ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ฝœ๋ฐฑ์œผ๋กœ ์ •์˜๋  ์ˆ˜ ์žˆ๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ์ฝœ๋ฐฑ์„ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š” ์ผ๋ถ€ ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

storyData = {
  title: Component,
  category: ({ title, story, storyPath, meta }) => someCategoryPath,
  meta: { ..whateverMeta }
}

์œ ์ผํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์€ ์ฝœ๋ฐฑ์ด ์Šคํ† ๋ฆฌ์— ๋Œ€ํ•œ ๋ฒ”์ฃผ ๊ฒฝ๋กœ๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

storyData.category() //=> returns the below array

// a simple category path might look like:
[ "One category" ];

// The path for a story nested three categories deep would look like:
[ "Parent Category",  "Child Category", "Grandchild category where the story lives" ];

์ด๊ฒƒ์€ ์‚ฌ๋žŒ๋“ค์ด ์›ํ•˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ ์‹œ์Šคํ…œ์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

์ „์—ญ ๊ตฌ์„ฑ์„ ์›ํ•˜๋ฉด ์ฝœ๋ฐฑ ๋‚ด์—์„œ ๋“ฑ๋กํ•˜๊ณ  ์‚ฌ์šฉ์ž ์ •์˜ ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํ† ๋ฆฌ๋ฅผ ๋“ฑ๋กํ•  ๋ฒ”์ฃผ/ํ•˜์œ„ ๋ฒ”์ฃผ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

categories: [
  {
    "Atoms": [
      {
        "Buttons": []
      }
    ],
  }, {
    "Molecules": [],
}];

function setCategory({ meta }) {
  const { categroyPath } = meta; // maybe a dot path string like "Atoms.Buttons" ?
  const category = categroyPath.split('.'); // [ "Atoms", "Buttons" ]
  return validatePath(category, categories); // categories["Atoms"]["Buttons"] is a valid path
}

ํŒŒ์ผ ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์นดํ…Œ๊ณ ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์„ค์ •ํ•˜๋ ค๋ฉด ๊ฒฝ๋กœ ์ •๋ณด๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

function setCategory({ storyPath }) {
  // for story path `src/components/Atoms/MyComponent.story.js`
  let folders =storyPath.split('/'); // [ "src", "components", "Atoms", "MyComponent.story.js" ];
  folders = without(folders, 'src'); // ["components", "Atoms", "MyComponent.story.js" ];
  folders.pop(); // [ "components", "Atoms" ]
  return folders;
}

๊ฐ„๋‹จํ•œ ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ํ•˜๋‚˜๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค! (๊ทธ๋ฆฌ๊ณ  ์นดํ…Œ๊ณ ๋ฆฌ๋Š” ๋‹จ์ˆœํ•œ ๋ฌธ์ž์—ด, ์นดํ…Œ๊ณ ๋ฆฌ ๊ฒฝ๋กœ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๋ฐฐ์—ด ๋˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ ๊ฒฝ๋กœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฝœ๋ฐฑ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

์ด์ œ ํ•˜๋Š˜์ด ํ•œ๊ณ„์ž…๋‹ˆ๋‹ค!

๋น„์Šทํ•œ ์ฐธ๊ณ ๋กœ ์ •๋ ฌ ์ˆœ์„œ๋ฅผ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋Š” addCategorySort ํ•จ์ˆ˜๋ฅผ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋ชจ๋“  ์Šคํ† ๋ฆฌ๋ฅผ ๋กœ๋“œํ•˜๊ณ  ์ •๋ ฌํ•˜์—ฌ ์ƒ์„ฑ๋œ ํŠธ๋ฆฌ ๋ฒ”์ฃผ ๊ตฌ์กฐ๋ฅผ ์ทจํ•ฉ๋‹ˆ๋‹ค.

import { configure, addCategorySort } from "@kadira/storybook";

addCategorySort( categories => /* sort logic here */ );

configure(loadStories, module);

@travi ์ด๋ฆ„์ด ์ค‘๋ณต๋œ ๋ฒ”์ฃผ์˜ ํ•„์š”์„ฑ์„ ๊ณ ๋ คํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ์ค‘์š”ํ•˜๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ํ•ด๊ฒฐ์ฑ…์— ๋Œ€ํ•œ ์ƒ๊ฐ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ด๊ฒƒ์ด ๋‚˜์—๊ฒŒ ๋– ์˜ค๋ฅด๋Š” ๊ฒƒ์ด์ง€๋งŒ ๋” ๋‚˜์€ ํ•ด๊ฒฐ์ฑ…์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const storyData = {
  categories: ["Buttons"],  // any category with the title "buttons"
}

const storyData = {
  categories: ["Atoms.Buttons"],  // any category with the title "buttons" that also has the parent category "atoms"
}

@interterned ๋‚˜๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์„ ํŒŒ๊ณ  ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž˜ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์„ ํ•„์š”๋กœํ•˜๊ฑฐ๋‚˜ ์›ํ•˜๋Š”)๊ฐ€ ๊ณ ๊ธ‰ ์‚ฌ์šฉ์ž(์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์„ ์›ํ•˜๋Š” ์•ฝ๊ฐ„์˜ ๋…ธ๋ ฅ).

@jackmccloy ์˜ˆ ... ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๋ชจ๋“  ์‚ฌ๋žŒ์—๊ฒŒ ์š”๊ตฌ ์‚ฌํ•ญ์ด๋˜์–ด์„œ๋Š” ์•ˆ๋œ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ๋žŒ๋“ค์ด ์ง€์›ํ•˜๊ธฐ๋ฅผ ์›ํ•˜๋Š” ๋‹ค์–‘ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์œผ๋ฏ€๋กœ ์ฝœ๋ฐฑ ์‹œ์Šคํ…œ์€ ๋ชจ๋“  ์‚ฌ๋žŒ์ด ์ž์‹ ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์‚ฌ์šฉ์ž ์ •์˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ™•์žฅ์„ฑ์„ ์ œ๊ณตํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์ด "ํ–‰๋ณตํ•œ ๊ธธ"์„ ๋” ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค์ง€ ์•Š์„๊นŒ ํ•˜๋Š” ๊ฑฑ์ •์„ ๋œ์–ด์ฃผ๊ธฐ ์œ„ํ•ด ๋‹ค์Œ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

  1. storydData.category ๊ฐ€ ๋ฌธ์ž์—ด์„ ํ—ˆ์šฉํ•˜๋„๋ก ํ•˜๋ฉด ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์ตœ์ƒ์œ„ ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
  2. storydData.category ๊ฐ€ ๋ฐฐ์—ด์˜ ์š”์†Œ๊ฐ€ ๋ฒ”์ฃผ์— ๋Œ€ํ•œ ๊ฒฝ๋กœ์ธ ๋ฐฐ์—ด์„ ํ—ˆ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
// given
storydData.category = ["grand parent", "parent", "story category"];
// category tree would look like:
categories = {
  "grand parent": {
    "parent": {
      "story category": /* the story lives here */
    }
  }
};
  1. ์Šคํ† ๋ฆฌ ๋ฐ์ดํ„ฐ๊ฐ€ ์œ„์—์„œ ์„ค๋ช…ํ•œ ๋Œ€๋กœ ๊ธฐ๋Šฅ์„ ํ—ˆ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค(https://github.com/storybooks/react-storybook/issues/151#issuecomment-292689536).
  2. ์—ฌ๊ธฐ์— ์žˆ๋Š” ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€(Atomic ๋””์ž์ธ, ํด๋” ๊ธฐ๋ฐ˜ ...) ์ค‘ ์ผ๋ถ€๋ฅผ ๋‹ค๋ฃจ๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ฒ”์ฃผ ์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์‹ค์ œ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ ์‚ฌํ•˜๊ฒŒ ์ •๋ ฌ์˜ ๊ฒฝ์šฐ ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ธฐ๋ณธ ์ „๋žต(์•ŒํŒŒ)์„ ์ง€์›ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‚ฌ์ „ ๊ตฌ์ถ•๋œ ๋‹ค๋ฅธ ์ •๋ ฌ ์ „๋žต(๊ฐ์ฒด ๋ชจ์–‘์— ๋”ฐ๋ฅธ ์ •๋ ฌ, ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ์˜ ์ธ๋ฑ์Šค ์ •๋ ฌ ๋“ฑ...)์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@ndelangen ์•ž์œผ๋กœ ๋‚˜์•„๊ฐˆ ๋ณด์‹ญ๋‹ˆ๊นŒ ? ์ž‘์—… ์ค‘์ธ ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ฃผ๋ง์— ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ž‘์—…์„ ์‹œ์ž‘ํ–ˆ๊ณ  ๊ทธ๋“ค์˜ ์†”๋ฃจ์…˜์ด ์‹คํ–‰ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์•Œ๋ฆผ์„ ๋ฐ›์œผ๋ฉด PR needed ๋ ˆ์ด๋ธ”์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๊ฒƒ์€ ํ˜„์žฌ ๋กœ๋“œ๋งต์— ์žˆ์ง€๋งŒ ์•„์ง ์ž‘์—…์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์‹œ์ž‘ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋งค์šฐ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค!

@jackmccloy ๊ดœ์ฐฎ์œผ์‹œ๋‹ค๋ฉด ์ €๋„ ์ด ์ž‘์—…์— ์ฐธ์—ฌํ•ด์„œ ์ฐธ์—ฌํ•ด๋„ ๋ ๊นŒ์š”?

@UsulPro 100%, ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ํฅ๋ถ„ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ผ์š”์ผ ์˜คํ›„(NYC ์‹œ๊ฐ„)์— ๋ณธ๊ฒฉ์ ์œผ๋กœ ์‚ดํŽด๋ณด๊ธฐ ์‹œ์ž‘ํ•  ๊ณ„ํš์ž…๋‹ˆ๋‹ค. ๋™์‹œ์— ์˜จ๋ผ์ธ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด lmk์™€ ์šฐ๋ฆฌ๊ฐ€ ๋Œ€ํ™”๋ฅผ slack์œผ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋‚˜๋Š” ์กฐ๊ธˆ ํŒŒ๊ณ  ๋‚œ ํ›„ ๋ช‡ ๊ฐ€์ง€ ์ƒ๊ฐ๊ณผ ํ•จ๊ป˜ ์—ฌ๊ธฐ์— ๊ฒŒ์‹œ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@jackmccloy @usulpro ์ €๋„ ์ด ์ž‘์—…์— ํ™•์‹คํžˆ ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

@interned ์ •๋ง ์ข‹์„ ๊ฒƒ

@UsulPro ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์‹ฌํ•œ ์œ„์žฅ ๋…๊ฐ์ด ์šฐ๋ฆฌ ๊ฐ€์ •์„ ๊ฐ•ํƒ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ธˆ์š”์ผ์— ์ง์žฅ์— ํ•ดํ‚น ๋‚ ์ด ์žˆ๊ณ  ๊ทธ ๋•Œ ์ผํ•  ๊ณ„ํš์ž…๋‹ˆ๋‹ค. ์‹œ์ž‘ํ•  ๊ธฐํšŒ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๊นŒ? Slack๊ณผ ๋™๊ธฐํ™”ํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค. ์ €๋Š” SB ์ฑ„๋„์— ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•œ ์ˆ˜์ค€์˜ ์ค‘์ฒฉ๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ React Storybook Addon Chapters ๊ฐ€ ํ•„์š”์— ๋งž์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ €๋Š” @igor-dv ์˜ ๋›ฐ์–ด๋‚œ ์Šคํ† ๋ฆฌ ๊ณ„์ธต ๊ตฌํ˜„์˜ ์ฒซ ๋ฒˆ์งธ ๋ฒ„์ „์„ ์ถœ์‹œํ–ˆ์œผ๋ฉฐ ๋” ๋„“์€ ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์ถœ์‹œํ•˜๊ธฐ ์ „์— ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์•ŒํŒŒ์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

https://gist.github.com/shilman/947a3d1d4cfdf5c3a8bb06d3d4eb84cf

@ 1i1it @andrubot @arunoda @atnovember @danielbartsch @franzihubrick @hadfieldn @iaanvn @imsnif @isuvorov @jackmccloy @joeruello @johnnyghost @lnmunhoz @majapw @markopavlovic @mystetskyivlad @mzedeler @ndelangen @nirhart @ noahprince22 @revolunet @sethkinast @theinterned @thesisb @travi @usulpro @yangshun @zeroasterisk @zvictor

์Šคํ† ๋ฆฌ ๊ณ„์ธต ๊ตฌ์กฐ์—์„œ ๋ฐœ๊ฒฌํ•œ ์ž‘์€ ๋‹จ์ :
๋””๋ ‰ํ† ๋ฆฌ์— ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ํด๋ฆญํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.
ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ํด๋”๊ฐ€ ํ™•์žฅ๋˜์ง€๋งŒ ์Šคํ† ๋ฆฌ ์ˆ˜์ค€์— ์žˆ๋Š” ๊ฒฝ์šฐ ์Šคํ† ๋ฆฌ๊ฐ€ ์ž๋™์œผ๋กœ ์„ ํƒ๋ฉ๋‹ˆ๋‹ค.
์‚ฌ์šฉ์ž๋Š” ๋‚ด๋ถ€์˜ ์Šคํ† ๋ฆฌ๋ฅผ ์„ ํƒํ•˜์ง€ ์•Š๊ณ  dir์˜ ๋‚ด์šฉ์„ ๋ณด๊ณ  ์‹ถ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
autoselectdir

์—…๋ฐ์ดํŠธ:

react-treebeard ์—์„œ ์ด ๋ฌธ์ œ์™€ ๊ด€๋ จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
https://github.com/alexcurtis/react-treebeard/issues/33
storybooks/react-treebeard ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ๋Œ€ํ•œ PR์„ ํƒ์ƒ‰ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ „ ๊ตฌํ˜„์—์„œ kind ์„ ํƒํ•  ๋•Œ ์ฒซ ๋ฒˆ์งธ ์Šคํ† ๋ฆฌ๊ฐ€ ์ž๋™ ์„ ํƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด ๊ธฐ๋Šฅ์„ ๋ณด์กดํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋ฏธ ๋ฒ„๊ทธ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

image

๊ทธ๋ฆผ์—์„œ Component 5 ๋Š” ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ผ kind ์ž…๋‹ˆ๋‹ค.

์‚ฌ์‹ค ๋‚˜๋„ ์ด๋Ÿฐ ํ–‰๋™์ด ์‹ซ๋‹ค...

๊ธด ์ด์•ผ๊ธฐ์˜ ์ด๋ฆ„์ด ์ด์ƒํ•˜๊ฒŒ ํฌ์žฅ๋ฉ๋‹ˆ๋‹ค.
image

์‚ฌ์ด๋“œ๋ฐ”์˜ ํฌ๊ธฐ๋ฅผ ์ •๋ง ์ž‘๊ฒŒ ์กฐ์ •ํ•˜๋ฉด ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ฐฝ์ด ์‚ฌ์ด๋“œ๋ฐ”์— ๋„˜์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
shrunk

๊ณ„์ธต ํด๋”๋ฅผ ๊ฐœ๋ณ„ ์Šคํ† ๋ฆฌ์™€ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์ตœ์ƒ์œ„ ์ˆ˜์ค€์—์„œ ์›ํ•˜๋Š” ์Šคํ† ๋ฆฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋‹จ์ผ ํ•ญ๋ชฉ์ด ์žˆ๋Š” ํด๋”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด

storiesOf('Something', module).add('top story');
storiesOf('Something.Chapter', module).add('substory');

๊ทธ๋Ÿฐ ๋‹ค์Œ ํด๋”๊ฐ€ ์žˆ๋Š” ํ•ญ๋ชฉ๊ณผ ํ•ญ๋ชฉ์ด ์žˆ๋Š” ํ•ญ๋ชฉ์ธ 'Something'์— ๋Œ€ํ•ด 2๊ฐœ์˜ ํ•ญ๋ชฉ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

@TheSisb ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ณต์‹ ๋ฆด๋ฆฌ์Šค์—์„œ ์ˆ˜์ •๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@psimyn , ํ˜„์žฌ ๊ตฌํ˜„์—์„œ๋Š” ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.. ํ•˜์ง€๋งŒ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.. @UsulPro ๋Š” ์ดˆ๊ธฐ PR์—์„œ๋„ ์ด๊ฒƒ์„ ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค.
IMO ์ด๊ฒƒ์€ ์ข‹์€ ๋™์ž‘์ด ์•„๋‹ˆ๋ฉฐ ๋” ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  IDE์™€ ๋น„๊ตํ•˜๋ฉด ๋„ค์ž„์ŠคํŽ˜์ด์Šค(dirs/folders/packages)๊ฐ€ ์žˆ์œผ๋ฉฐ ํ•ด๋‹น ๋„ค์ž„์ŠคํŽ˜์ด์Šค(๋˜๋Š” ๊ทผ์ฒ˜)์— ๊ฐ™์€ ์ด๋ฆ„์„ ๊ฐ€์ง„ ์ผ๋ถ€ ํ•ญ๋ชฉ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์–ด์จŒ๋“  ์ด๊ฒŒ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๋ฐ”๋ผ๋Š” ํ–‰๋™์ด๋ผ๋ฉด ๋ฐ”๊ฟ”์•ผ ํ•˜๊ฒ ์ง€๋งŒ ์ถœ์‹œ๋ฅผ ์œ„ํ•œ ๋งˆ๊ฐœ๋Š” ์‹ซ๋‹ค =)

์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ํ•„์š”ํ–ˆ๋˜ ์ •ํ™•ํ•œ ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค !!! ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค +1

@psimyn ๊ธฐ๋Šฅ์„ ์„ค๋ช…ํ•˜๋Š” ์ƒˆ ๋ฌธ์ œ๋ฅผ ์—ฌ์‹ญ์‹œ์˜ค. ์ด ๋ฌธ์ œ๋Š” 3.2.0 ์˜ ์ถœ์‹œ์™€ ํ•จ๊ป˜ ๊ณง ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

์ด์ œ ์ƒˆ๋กœ์šด CSF ํ˜•์‹์œผ๋กœ ์—ฌ๋Ÿฌ ์ˆ˜์ค€์˜ ์ค‘์ฒฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๊นŒ?

@gaurav5430 ์–ผ๋งˆ ๋™์•ˆ์€ ๊ฐ€๋Šฅํ–ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ์šฐ๋ฆฌ์˜ ์˜ˆ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

๋‡Œ์ฒ™์ˆ˜์•ก:

import React from 'react';
import { linkTo } from '@storybook/addon-links';
import { Welcome } from '@storybook/react/demo';

export default {
  title: 'Other/Demo/Welcome',
  component: Welcome,
};

export const ToStorybook = () => <Welcome showApp={linkTo('Other/Demo/Button')} />;
ToStorybook.storyName = 'to Storybook';

์•ˆ๋…•ํ•˜์„ธ์š” @ndelangen
๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค: https://storybook.js.org/docs/basics/writing-stories/#story -hierarchy

๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ ๊ธฐ๋ณธ ๋‚ด๋ณด๋‚ด๊ธฐ ์ œ๋ชฉ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ story.name ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜์œ„ ํด๋”๋ฅผ ๋งŒ๋“œ๋Š” ๊ธฐ๋Šฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

export default {
  title: 'Other/Demo/Welcome',
  component: Welcome,
};

export const ToStorybook = () => <Welcome showApp={linkTo('Other/Demo/Button')} />;
ToStorybook.story = { name: 'to/Storybook' };

Other/Demo/Welcome/To/Storybook

์œ„์˜ ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ์Šคํ† ๋ฆฌ ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ๊ฐ๊ฐ์˜ ์˜ฌ๋ฐ”๋ฅธ ๊ณ„์ธต ๊ตฌ์กฐ๋กœ ๊ธฐ๋ณธ๊ฐ’์„ ๋‚ด๋ณด๋‚ด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

one.stories.js ์—์„œ์™€ ๊ฐ™์ด :

export default {
  title: 'Other/Demo/Welcome/One',
  component: Welcome,
};

export const ToStorybookOne = () => <Welcome showApp={linkTo('Other/Demo/Button')} />;

๊ทธ๋ฆฌ๊ณ  two.stories.js

export default {
  title: 'Other/Demo/Welcome/Two',
  component: Welcome,
};

export const ToStorybookTwo = () => <Welcome showApp={linkTo('Other/Demo/Button')} />;

๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‘ ์ด์•ผ๊ธฐ๊ฐ€ ์Šคํ† ๋ฆฌ๋ถ ํด๋” ๊ตฌ์กฐ์— ์˜ˆ์ƒ๋Œ€๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

@gaurav5430 ๊ถŒ์žฅ ์‚ฌ์šฉ๋ฒ•์ด๋ฉฐ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์•„๋‹™๋‹ˆ๋‹ค. ๐Ÿ˜„

@gaurav5430 ๊ถŒ์žฅ ์‚ฌ์šฉ๋ฒ•์ด๋ฉฐ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์•„๋‹™๋‹ˆ๋‹ค. ๐Ÿ˜„

์˜ˆ, ์ด ๋‘ ํŒŒ์ผ์€ ๋™์ผํ•œ ๊ตฌ์„ฑ ์š”์†Œ์˜ ๋‹ค๋ฅธ ์ƒํƒœ์— ๋Œ€ํ•œ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ธฐ๋ฅผ ์ฃผ์ €ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•„์ž์˜ ๊ฒฝ์šฐ ๊ตฌ์„ฑ ์š”์†Œ์—๋Š” 2๊ฐœ์˜ ๊ธฐ๋ณธ ์ƒํƒœ์™€ ์ด๋Ÿฌํ•œ 2๊ฐœ์˜ ๊ธฐ๋ณธ ์ƒํƒœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ์—ฌ๋Ÿฌ ํ•˜์œ„ ์ƒํƒœ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ์˜ ๋ชจ๋“  ์ƒํƒœ๋ฅผ ๋™์ผํ•œ ํŒŒ์ผ์— ์œ ์ง€ํ•˜์ง€๋งŒ ์ด ๊ฒฝ์šฐ ์Šคํ† ๋ฆฌ์˜ ๊ณ„์ธต ๊ตฌ์กฐ์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ํŒŒ์ผ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰