@reni-corp/reni-2c-ui 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/helpers/assert-contract.d.ts +9 -0
- package/dist/__tests__/helpers/assert-contract.d.ts.map +1 -0
- package/dist/__tests__/helpers/contract-helpers.d.ts +45 -0
- package/dist/__tests__/helpers/contract-helpers.d.ts.map +1 -0
- package/dist/__tests__/setup.d.ts +1 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/components/elements/Label.vue.d.ts +2 -2
- package/dist/components/elements/Label.vue.d.ts.map +1 -1
- package/dist/components/features/AnnounceBarCollection.vue.d.ts.map +1 -1
- package/dist/components/features/ProductList.vue.d.ts.map +1 -1
- package/dist/components/features/ProductListItem.vue.d.ts.map +1 -1
- package/dist/components/interactive/Slider.vue.d.ts.map +1 -1
- package/dist/components/interactive/TabGroup.vue.d.ts +4 -6
- package/dist/components/interactive/TabGroup.vue.d.ts.map +1 -1
- package/dist/components/interactive/TabPanels.vue.d.ts +8 -4
- package/dist/components/interactive/TabPanels.vue.d.ts.map +1 -1
- package/dist/components/interactive/Tabs.vue.d.ts +9 -3
- package/dist/components/interactive/Tabs.vue.d.ts.map +1 -1
- package/dist/components/layouts/List.vue.d.ts.map +1 -1
- package/dist/components/layouts/Section.vue.d.ts +2 -0
- package/dist/components/layouts/Section.vue.d.ts.map +1 -1
- package/dist/components/renderless/Form.vue.d.ts +4 -2
- package/dist/components/renderless/Form.vue.d.ts.map +1 -1
- package/dist/composables.es.js +1 -1
- package/dist/index.es.js +2138 -2119
- package/dist/script.es.js +2079 -2060
- package/dist/script.umd.js +26 -26
- package/dist/style.css +1 -1
- package/dist/{useAppDialogGuidance-BhYqv41n.js → useAppDialogGuidance-Bs1h3YmP.js} +95 -95
- package/package.json +10 -6
- package/src/stories/Label.stories.ts +13 -1
- package/src/stories/Text.stories.ts +23 -0
- package/src/stories/compositions/EventPage.stories.ts +184 -0
- package/src/stories/compositions/FormPage.stories.ts +222 -0
- package/src/stories/compositions/TopPage.stories.ts +164 -0
|
@@ -28,7 +28,7 @@ const meta: Meta<typeof Label> = {
|
|
|
28
28
|
},
|
|
29
29
|
variant: {
|
|
30
30
|
control: 'select',
|
|
31
|
-
options: ['filled', 'outline'],
|
|
31
|
+
options: ['solid', 'filled', 'outline'],
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
34
|
args: {
|
|
@@ -92,6 +92,18 @@ export const カラー一覧: OverridesStory = {
|
|
|
92
92
|
},
|
|
93
93
|
template: /* html */ `
|
|
94
94
|
<div class='sb-canvas'>
|
|
95
|
+
<h3>Solid</h3>
|
|
96
|
+
<rn-stack direction="horizontal" gap="sm" style="flex-wrap: wrap; margin-bottom: 24px;">
|
|
97
|
+
<rn-label
|
|
98
|
+
v-for="color in allColors"
|
|
99
|
+
:key="'solid-' + color"
|
|
100
|
+
:color="color"
|
|
101
|
+
variant="solid"
|
|
102
|
+
>
|
|
103
|
+
{{ color }}
|
|
104
|
+
</rn-label>
|
|
105
|
+
</rn-stack>
|
|
106
|
+
|
|
95
107
|
<h3>Filled</h3>
|
|
96
108
|
<rn-stack direction="horizontal" gap="sm" style="flex-wrap: wrap; margin-bottom: 24px;">
|
|
97
109
|
<rn-label
|
|
@@ -67,3 +67,26 @@ export const 基本: OverridesStory = {
|
|
|
67
67
|
`,
|
|
68
68
|
}),
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
export const Nl2br: OverridesStory = {
|
|
72
|
+
args: {
|
|
73
|
+
nl2br: true,
|
|
74
|
+
slotText: '1行目のテキスト\n2行目のテキスト\n3行目のテキスト',
|
|
75
|
+
},
|
|
76
|
+
argTypes: {
|
|
77
|
+
default: { table: { disable: true } },
|
|
78
|
+
},
|
|
79
|
+
render: (args: StoryArgs) => ({
|
|
80
|
+
components: { 'rn-text': Text },
|
|
81
|
+
setup() {
|
|
82
|
+
return { args }
|
|
83
|
+
},
|
|
84
|
+
template: /* html */ `
|
|
85
|
+
<div class='sb-canvas'>
|
|
86
|
+
<rn-text :size=args.size :color=args.color :weight=args.weight :nl2br=args.nl2br>
|
|
87
|
+
{{ args.slotText }}
|
|
88
|
+
</rn-text>
|
|
89
|
+
</div>
|
|
90
|
+
`,
|
|
91
|
+
}),
|
|
92
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composition Story: イベントページ
|
|
3
|
+
*
|
|
4
|
+
* イベント・スケジュール一覧画面を模した構成。
|
|
5
|
+
* Tabs, Disclosure, Section, Stack, Card, Text を組み合わせ、
|
|
6
|
+
* タブ切り替え + アコーディオン開閉を含む画面をテストする。
|
|
7
|
+
*/
|
|
8
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
9
|
+
import { ref } from 'vue'
|
|
10
|
+
import Tabs from '@/components/interactive/Tabs.vue'
|
|
11
|
+
import Tab from '@/components/interactive/Tab.vue'
|
|
12
|
+
import Disclosure from '@/components/interactive/Disclosure.vue'
|
|
13
|
+
import Section from '@/components/layouts/Section.vue'
|
|
14
|
+
import Stack from '@/components/layouts/Stack.vue'
|
|
15
|
+
import Card from '@/components/layouts/Card.vue'
|
|
16
|
+
import Text from '@/components/elements/Text.vue'
|
|
17
|
+
import Button from '@/components/elements/Button.vue'
|
|
18
|
+
import Divider from '@/components/elements/Divider.vue'
|
|
19
|
+
import Icon from '@/components/elements/Icon.vue'
|
|
20
|
+
|
|
21
|
+
const meta: Meta = {
|
|
22
|
+
title: 'Example/イベントページ',
|
|
23
|
+
parameters: {
|
|
24
|
+
layout: 'padded',
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default meta
|
|
29
|
+
type Story = StoryObj
|
|
30
|
+
|
|
31
|
+
const mockEvents = [
|
|
32
|
+
{
|
|
33
|
+
id: 1,
|
|
34
|
+
title: '新作お披露目会',
|
|
35
|
+
date: '2025/04/20 14:00',
|
|
36
|
+
location: '東京・渋谷',
|
|
37
|
+
description:
|
|
38
|
+
'新作アイテムをいち早くお披露目します。限定グッズの先行販売もあります。',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 2,
|
|
42
|
+
title: 'ファンミーティング',
|
|
43
|
+
date: '2025/05/10 13:00',
|
|
44
|
+
location: '大阪・梅田',
|
|
45
|
+
description:
|
|
46
|
+
'クリエイターとファンが直接交流できるイベントです。サイン会も予定しています。',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 3,
|
|
50
|
+
title: 'ポップアップストア',
|
|
51
|
+
date: '2025/06/01 〜 06/07',
|
|
52
|
+
location: '名古屋・栄',
|
|
53
|
+
description: '期間限定ショップをオープン。イベント限定商品を販売します。',
|
|
54
|
+
},
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
const mockFaqItems = [
|
|
58
|
+
{
|
|
59
|
+
question: '参加には予約が必要ですか?',
|
|
60
|
+
answer:
|
|
61
|
+
'はい、全てのイベントは事前予約制です。各イベントの申し込みページからご予約ください。',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
question: 'キャンセルはできますか?',
|
|
65
|
+
answer:
|
|
66
|
+
'イベント開催日の3日前までキャンセル可能です。それ以降のキャンセルはお受けできません。',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
question: '物販はありますか?',
|
|
70
|
+
answer:
|
|
71
|
+
'イベントによって異なります。各イベントの詳細ページをご確認ください。',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
question: '未成年でも参加できますか?',
|
|
75
|
+
answer:
|
|
76
|
+
'全てのイベントで年齢制限はありません。ただし、中学生以下のお子様は保護者の同伴が必要です。',
|
|
77
|
+
},
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
export const イベント一覧: Story = {
|
|
81
|
+
render: () => ({
|
|
82
|
+
components: {
|
|
83
|
+
'rn-tabs': Tabs,
|
|
84
|
+
'rn-tab': Tab,
|
|
85
|
+
'rn-disclosure': Disclosure,
|
|
86
|
+
'rn-section': Section,
|
|
87
|
+
'rn-stack': Stack,
|
|
88
|
+
'rn-card': Card,
|
|
89
|
+
'rn-text': Text,
|
|
90
|
+
'rn-button': Button,
|
|
91
|
+
'rn-divider': Divider,
|
|
92
|
+
'rn-icon': Icon,
|
|
93
|
+
},
|
|
94
|
+
setup() {
|
|
95
|
+
const currentTab = ref(0)
|
|
96
|
+
|
|
97
|
+
const handleTabChange = (index: number) => {
|
|
98
|
+
currentTab.value = index
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
currentTab,
|
|
103
|
+
handleTabChange,
|
|
104
|
+
mockEvents,
|
|
105
|
+
mockFaqItems,
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
template: /* html */ `
|
|
109
|
+
<div style="width: 100%;">
|
|
110
|
+
<rn-stack direction="vertical" gap="xl" horizontalReSize="fill">
|
|
111
|
+
|
|
112
|
+
<rn-section title="イベント情報" description="今後のイベント・スケジュール">
|
|
113
|
+
<template #body>
|
|
114
|
+
<rn-tabs :modelValue="currentTab" v-slot="slotProps">
|
|
115
|
+
<rn-tab
|
|
116
|
+
:active="slotProps.currentIndex === 0"
|
|
117
|
+
@click="handleTabChange(0)"
|
|
118
|
+
>
|
|
119
|
+
<rn-icon icon="calendar" />
|
|
120
|
+
開催予定
|
|
121
|
+
</rn-tab>
|
|
122
|
+
<rn-tab
|
|
123
|
+
:active="slotProps.currentIndex === 1"
|
|
124
|
+
@click="handleTabChange(1)"
|
|
125
|
+
>
|
|
126
|
+
<rn-icon icon="check-circle" />
|
|
127
|
+
開催済み
|
|
128
|
+
</rn-tab>
|
|
129
|
+
</rn-tabs>
|
|
130
|
+
|
|
131
|
+
<rn-stack direction="vertical" gap="md" style="margin-top: 16px;">
|
|
132
|
+
<template v-if="currentTab === 0">
|
|
133
|
+
<rn-card v-for="event in mockEvents" :key="event.id">
|
|
134
|
+
<rn-stack direction="vertical" gap="sm" padding="md">
|
|
135
|
+
<rn-text variant="title-sm">{{ event.title }}</rn-text>
|
|
136
|
+
<rn-stack direction="horizontal" gap="md">
|
|
137
|
+
<rn-text variant="body-sm" color="secondary">
|
|
138
|
+
{{ event.date }}
|
|
139
|
+
</rn-text>
|
|
140
|
+
<rn-text variant="body-sm" color="secondary">
|
|
141
|
+
{{ event.location }}
|
|
142
|
+
</rn-text>
|
|
143
|
+
</rn-stack>
|
|
144
|
+
<rn-text variant="body-sm">{{ event.description }}</rn-text>
|
|
145
|
+
<rn-button variant="outlined" size="sm">
|
|
146
|
+
詳細を見る
|
|
147
|
+
</rn-button>
|
|
148
|
+
</rn-stack>
|
|
149
|
+
</rn-card>
|
|
150
|
+
</template>
|
|
151
|
+
<template v-else>
|
|
152
|
+
<rn-card>
|
|
153
|
+
<rn-stack direction="vertical" gap="sm" padding="md" horizontalAlign="center">
|
|
154
|
+
<rn-text variant="body-sm" color="secondary">
|
|
155
|
+
過去のイベントはありません
|
|
156
|
+
</rn-text>
|
|
157
|
+
</rn-stack>
|
|
158
|
+
</rn-card>
|
|
159
|
+
</template>
|
|
160
|
+
</rn-stack>
|
|
161
|
+
</template>
|
|
162
|
+
</rn-section>
|
|
163
|
+
|
|
164
|
+
<rn-divider />
|
|
165
|
+
|
|
166
|
+
<rn-section title="よくある質問">
|
|
167
|
+
<template #body>
|
|
168
|
+
<rn-stack direction="vertical" gap="sm">
|
|
169
|
+
<rn-disclosure
|
|
170
|
+
v-for="(faq, index) in mockFaqItems"
|
|
171
|
+
:key="index"
|
|
172
|
+
:title="faq.question"
|
|
173
|
+
>
|
|
174
|
+
<rn-text variant="body-sm">{{ faq.answer }}</rn-text>
|
|
175
|
+
</rn-disclosure>
|
|
176
|
+
</rn-stack>
|
|
177
|
+
</template>
|
|
178
|
+
</rn-section>
|
|
179
|
+
|
|
180
|
+
</rn-stack>
|
|
181
|
+
</div>
|
|
182
|
+
`,
|
|
183
|
+
}),
|
|
184
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composition Story: フォームページ
|
|
3
|
+
*
|
|
4
|
+
* お届け先入力フォームを模した画面構成。
|
|
5
|
+
* TextField, SelectBox, CheckBox, Radio, TextArea, Button, Form を組み合わせ、
|
|
6
|
+
* バリデーション連携を含むリアルなフォーム画面をテストする。
|
|
7
|
+
*/
|
|
8
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
9
|
+
import { ref } from 'vue'
|
|
10
|
+
import Form from '@/components/renderless/Form.vue'
|
|
11
|
+
import TextField from '@/components/elements/TextField.vue'
|
|
12
|
+
import SelectBox from '@/components/elements/SelectBox.vue'
|
|
13
|
+
import TextArea from '@/components/elements/TextArea.vue'
|
|
14
|
+
import CheckBox from '@/components/elements/CheckBox.vue'
|
|
15
|
+
import Radio from '@/components/elements/Radio.vue'
|
|
16
|
+
import Button from '@/components/elements/Button.vue'
|
|
17
|
+
import Text from '@/components/elements/Text.vue'
|
|
18
|
+
import Stack from '@/components/layouts/Stack.vue'
|
|
19
|
+
import Section from '@/components/layouts/Section.vue'
|
|
20
|
+
import Card from '@/components/layouts/Card.vue'
|
|
21
|
+
import Divider from '@/components/elements/Divider.vue'
|
|
22
|
+
|
|
23
|
+
const meta: Meta = {
|
|
24
|
+
title: 'Example/フォームページ',
|
|
25
|
+
parameters: {
|
|
26
|
+
layout: 'padded',
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default meta
|
|
31
|
+
type Story = StoryObj
|
|
32
|
+
|
|
33
|
+
const prefectureItems = [
|
|
34
|
+
{ label: '東京都', value: 'tokyo' },
|
|
35
|
+
{ label: '神奈川県', value: 'kanagawa' },
|
|
36
|
+
{ label: '大阪府', value: 'osaka' },
|
|
37
|
+
{ label: '愛知県', value: 'aichi' },
|
|
38
|
+
{ label: '福岡県', value: 'fukuoka' },
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
const paymentMethods = [
|
|
42
|
+
{ label: 'クレジットカード', value: 'credit' },
|
|
43
|
+
{ label: 'コンビニ払い', value: 'convenience' },
|
|
44
|
+
{ label: '銀行振込', value: 'bank' },
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
export const お届け先入力: Story = {
|
|
48
|
+
render: () => ({
|
|
49
|
+
components: {
|
|
50
|
+
'rn-form': Form,
|
|
51
|
+
'rn-text-field': TextField,
|
|
52
|
+
'rn-select-box': SelectBox,
|
|
53
|
+
'rn-text-area': TextArea,
|
|
54
|
+
'rn-checkbox': CheckBox,
|
|
55
|
+
'rn-radio': Radio,
|
|
56
|
+
'rn-button': Button,
|
|
57
|
+
'rn-text': Text,
|
|
58
|
+
'rn-stack': Stack,
|
|
59
|
+
'rn-section': Section,
|
|
60
|
+
'rn-card': Card,
|
|
61
|
+
'rn-divider': Divider,
|
|
62
|
+
},
|
|
63
|
+
setup() {
|
|
64
|
+
const name = ref('')
|
|
65
|
+
const email = ref('')
|
|
66
|
+
const phone = ref('')
|
|
67
|
+
const postalCode = ref('')
|
|
68
|
+
const prefecture = ref(null)
|
|
69
|
+
const address = ref('')
|
|
70
|
+
const building = ref('')
|
|
71
|
+
const payment = ref('credit')
|
|
72
|
+
const notes = ref('')
|
|
73
|
+
const agreed = ref(false)
|
|
74
|
+
|
|
75
|
+
const handleSubmit = () => {
|
|
76
|
+
console.log('送信:', {
|
|
77
|
+
name: name.value,
|
|
78
|
+
email: email.value,
|
|
79
|
+
phone: phone.value,
|
|
80
|
+
postalCode: postalCode.value,
|
|
81
|
+
prefecture: prefecture.value,
|
|
82
|
+
address: address.value,
|
|
83
|
+
building: building.value,
|
|
84
|
+
payment: payment.value,
|
|
85
|
+
notes: notes.value,
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
name,
|
|
91
|
+
email,
|
|
92
|
+
phone,
|
|
93
|
+
postalCode,
|
|
94
|
+
prefecture,
|
|
95
|
+
address,
|
|
96
|
+
building,
|
|
97
|
+
payment,
|
|
98
|
+
notes,
|
|
99
|
+
agreed,
|
|
100
|
+
prefectureItems,
|
|
101
|
+
paymentMethods,
|
|
102
|
+
handleSubmit,
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
template: /* html */ `
|
|
106
|
+
<div style="width: 100%;">
|
|
107
|
+
<rn-section title="お届け先情報">
|
|
108
|
+
<template #body>
|
|
109
|
+
<rn-form v-slot="{ canSubmit }">
|
|
110
|
+
<rn-stack direction="vertical" gap="lg" horizontalReSize="fill">
|
|
111
|
+
|
|
112
|
+
<rn-card>
|
|
113
|
+
<rn-stack direction="vertical" gap="md" padding="md">
|
|
114
|
+
<rn-text variant="title-sm">お届け先</rn-text>
|
|
115
|
+
<rn-text-field
|
|
116
|
+
v-model="name"
|
|
117
|
+
label="お名前"
|
|
118
|
+
name="name"
|
|
119
|
+
rules="required"
|
|
120
|
+
placeholder="山田 太郎"
|
|
121
|
+
/>
|
|
122
|
+
<rn-text-field
|
|
123
|
+
v-model="email"
|
|
124
|
+
label="メールアドレス"
|
|
125
|
+
name="email"
|
|
126
|
+
type="email"
|
|
127
|
+
rules="required|email"
|
|
128
|
+
placeholder="example@email.com"
|
|
129
|
+
/>
|
|
130
|
+
<rn-text-field
|
|
131
|
+
v-model="phone"
|
|
132
|
+
label="電話番号"
|
|
133
|
+
name="phone"
|
|
134
|
+
type="tel"
|
|
135
|
+
rules="required"
|
|
136
|
+
placeholder="090-1234-5678"
|
|
137
|
+
/>
|
|
138
|
+
<rn-divider />
|
|
139
|
+
<rn-text-field
|
|
140
|
+
v-model="postalCode"
|
|
141
|
+
label="郵便番号"
|
|
142
|
+
name="postalCode"
|
|
143
|
+
rules="required"
|
|
144
|
+
placeholder="123-4567"
|
|
145
|
+
/>
|
|
146
|
+
<rn-select-box
|
|
147
|
+
v-model="prefecture"
|
|
148
|
+
label="都道府県"
|
|
149
|
+
name="prefecture"
|
|
150
|
+
:items="prefectureItems"
|
|
151
|
+
rules="required"
|
|
152
|
+
placeholder="選択してください"
|
|
153
|
+
/>
|
|
154
|
+
<rn-text-field
|
|
155
|
+
v-model="address"
|
|
156
|
+
label="市区町村・番地"
|
|
157
|
+
name="address"
|
|
158
|
+
rules="required"
|
|
159
|
+
placeholder="渋谷区神南1-2-3"
|
|
160
|
+
/>
|
|
161
|
+
<rn-text-field
|
|
162
|
+
v-model="building"
|
|
163
|
+
label="建物名・部屋番号"
|
|
164
|
+
name="building"
|
|
165
|
+
placeholder="○○マンション 101号室"
|
|
166
|
+
/>
|
|
167
|
+
</rn-stack>
|
|
168
|
+
</rn-card>
|
|
169
|
+
|
|
170
|
+
<rn-card>
|
|
171
|
+
<rn-stack direction="vertical" gap="md" padding="md">
|
|
172
|
+
<rn-text variant="title-sm">お支払い方法</rn-text>
|
|
173
|
+
<rn-radio
|
|
174
|
+
v-model="payment"
|
|
175
|
+
name="payment"
|
|
176
|
+
:items="paymentMethods"
|
|
177
|
+
direction="vertical"
|
|
178
|
+
variant="default"
|
|
179
|
+
color="default"
|
|
180
|
+
/>
|
|
181
|
+
</rn-stack>
|
|
182
|
+
</rn-card>
|
|
183
|
+
|
|
184
|
+
<rn-card>
|
|
185
|
+
<rn-stack direction="vertical" gap="md" padding="md">
|
|
186
|
+
<rn-text variant="title-sm">備考</rn-text>
|
|
187
|
+
<rn-text-area
|
|
188
|
+
v-model="notes"
|
|
189
|
+
label="配送に関するご要望"
|
|
190
|
+
name="notes"
|
|
191
|
+
placeholder="置き配希望など"
|
|
192
|
+
:rows="3"
|
|
193
|
+
/>
|
|
194
|
+
</rn-stack>
|
|
195
|
+
</rn-card>
|
|
196
|
+
|
|
197
|
+
<rn-stack direction="vertical" gap="md" horizontalAlign="center">
|
|
198
|
+
<rn-checkbox
|
|
199
|
+
v-model="agreed"
|
|
200
|
+
label="利用規約に同意する"
|
|
201
|
+
name="agreement"
|
|
202
|
+
:required="true"
|
|
203
|
+
/>
|
|
204
|
+
<rn-button
|
|
205
|
+
variant="fill"
|
|
206
|
+
size="lg"
|
|
207
|
+
block
|
|
208
|
+
:disabled="!canSubmit || !agreed"
|
|
209
|
+
@click="handleSubmit"
|
|
210
|
+
>
|
|
211
|
+
注文を確定する
|
|
212
|
+
</rn-button>
|
|
213
|
+
</rn-stack>
|
|
214
|
+
|
|
215
|
+
</rn-stack>
|
|
216
|
+
</rn-form>
|
|
217
|
+
</template>
|
|
218
|
+
</rn-section>
|
|
219
|
+
</div>
|
|
220
|
+
`,
|
|
221
|
+
}),
|
|
222
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composition Story: ストアトップページ
|
|
3
|
+
*
|
|
4
|
+
* 2C ストアの典型的なファーストビューを模した画面構成。
|
|
5
|
+
* AppFrame をルートに、AnnounceBar / Hero は全幅、
|
|
6
|
+
* Section 内コンテンツは max-width 制約で表示する。
|
|
7
|
+
*
|
|
8
|
+
* ※ Slider は Swiper 依存のため happy-dom で動作しない可能性あり。
|
|
9
|
+
* このストーリーでは ProductList(list) で代替テストする。
|
|
10
|
+
*/
|
|
11
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
12
|
+
import AppFrame from '@/components/foundation/AppFrame.vue'
|
|
13
|
+
import AnnounceBar from '@/components/features/AnnounceBar.vue'
|
|
14
|
+
import Hero from '@/components/features/Hero.vue'
|
|
15
|
+
import Banner from '@/components/features/Banner.vue'
|
|
16
|
+
import ProductList from '@/components/features/ProductList.vue'
|
|
17
|
+
import Section from '@/components/layouts/Section.vue'
|
|
18
|
+
import Stack from '@/components/layouts/Stack.vue'
|
|
19
|
+
import Button from '@/components/elements/Button.vue'
|
|
20
|
+
|
|
21
|
+
const meta: Meta = {
|
|
22
|
+
title: 'Example/ストアトップページ',
|
|
23
|
+
parameters: {
|
|
24
|
+
layout: 'fullscreen',
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default meta
|
|
29
|
+
type Story = StoryObj
|
|
30
|
+
|
|
31
|
+
const mockProducts = [
|
|
32
|
+
{
|
|
33
|
+
product_id: '1',
|
|
34
|
+
title: 'オリジナルTシャツ',
|
|
35
|
+
price_sale: 3980,
|
|
36
|
+
img_urls: ['https://placehold.co/400x400?text=T-shirt'],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
product_id: '2',
|
|
40
|
+
title: 'アクリルキーホルダー',
|
|
41
|
+
price_sale: 1200,
|
|
42
|
+
img_urls: ['https://placehold.co/400x400?text=Keychain'],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
product_id: '3',
|
|
46
|
+
title: 'トートバッグ',
|
|
47
|
+
price_sale: 2500,
|
|
48
|
+
img_urls: ['https://placehold.co/400x400?text=Tote+Bag'],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
product_id: '4',
|
|
52
|
+
title: 'ステッカーセット',
|
|
53
|
+
price_sale: 800,
|
|
54
|
+
img_urls: ['https://placehold.co/400x400?text=Stickers'],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
product_id: '5',
|
|
58
|
+
title: 'マグカップ',
|
|
59
|
+
price_sale: 1800,
|
|
60
|
+
img_urls: ['https://placehold.co/400x400?text=Mug'],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
product_id: '6',
|
|
64
|
+
title: 'ポスター A2',
|
|
65
|
+
price_sale: 1500,
|
|
66
|
+
img_urls: ['https://placehold.co/400x400?text=Poster'],
|
|
67
|
+
},
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
export const トップページ: Story = {
|
|
71
|
+
render: () => ({
|
|
72
|
+
components: {
|
|
73
|
+
'rn-app-frame': AppFrame,
|
|
74
|
+
'rn-announce-bar': AnnounceBar,
|
|
75
|
+
'rn-hero': Hero,
|
|
76
|
+
'rn-banner': Banner,
|
|
77
|
+
'rn-product-list': ProductList,
|
|
78
|
+
'rn-section': Section,
|
|
79
|
+
'rn-stack': Stack,
|
|
80
|
+
'rn-button': Button,
|
|
81
|
+
},
|
|
82
|
+
setup() {
|
|
83
|
+
return { mockProducts }
|
|
84
|
+
},
|
|
85
|
+
template: /* html */ `
|
|
86
|
+
<rn-app-frame style="--rn-app-frame-min-height: auto;">
|
|
87
|
+
|
|
88
|
+
<rn-announce-bar
|
|
89
|
+
title="期間限定セール開催中!"
|
|
90
|
+
subtitle="全品10%OFF"
|
|
91
|
+
color="primary"
|
|
92
|
+
colorStyle="gradient"
|
|
93
|
+
/>
|
|
94
|
+
|
|
95
|
+
<rn-hero
|
|
96
|
+
layout="overlay"
|
|
97
|
+
media="https://placehold.co/1200x600?text=Hero+Image"
|
|
98
|
+
eyebrow="NEW ARRIVAL"
|
|
99
|
+
title="Spring Collection 2025"
|
|
100
|
+
subtitle="新作アイテムが続々入荷"
|
|
101
|
+
description="お気に入りのクリエイターの最新グッズをチェック"
|
|
102
|
+
contentAlign="center"
|
|
103
|
+
contentVerticalAlign="center"
|
|
104
|
+
overlayColor="rgba(0, 0, 0, 0.4)"
|
|
105
|
+
/>
|
|
106
|
+
|
|
107
|
+
<div style="max-width: 1280px; margin: 0 auto; padding: 32px 24px; width: 100%; box-sizing: border-box;">
|
|
108
|
+
<rn-section
|
|
109
|
+
title="新着商品"
|
|
110
|
+
description="最新のアイテムをチェック"
|
|
111
|
+
headerAlign="center"
|
|
112
|
+
>
|
|
113
|
+
<template #body>
|
|
114
|
+
<rn-product-list
|
|
115
|
+
displayMode="list"
|
|
116
|
+
:pcColumns="3"
|
|
117
|
+
:spColumns="2"
|
|
118
|
+
:pcRows="1"
|
|
119
|
+
:spRows="1"
|
|
120
|
+
:data="mockProducts"
|
|
121
|
+
/>
|
|
122
|
+
<rn-stack horizontalAlign="center" style="margin-top: 16px;">
|
|
123
|
+
<rn-button variant="outlined" withArrow>
|
|
124
|
+
すべての商品を見る
|
|
125
|
+
</rn-button>
|
|
126
|
+
</rn-stack>
|
|
127
|
+
</template>
|
|
128
|
+
</rn-section>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<rn-banner
|
|
132
|
+
imageUrl="https://placehold.co/1200x400?text=Campaign+Banner"
|
|
133
|
+
title="コラボレーション企画"
|
|
134
|
+
description="人気クリエイター × ブランドの限定コラボアイテム"
|
|
135
|
+
variant="overlay"
|
|
136
|
+
overlayColor="rgba(0, 0, 0, 0.3)"
|
|
137
|
+
contentHorizontalAlign="center"
|
|
138
|
+
contentVerticalAlign="center"
|
|
139
|
+
aspectRatio="3/1"
|
|
140
|
+
/>
|
|
141
|
+
|
|
142
|
+
<div style="max-width: 1280px; margin: 0 auto; padding: 32px 24px; width: 100%; box-sizing: border-box;">
|
|
143
|
+
<rn-section
|
|
144
|
+
title="人気ランキング"
|
|
145
|
+
description="今週の売れ筋トップ6"
|
|
146
|
+
headerAlign="center"
|
|
147
|
+
>
|
|
148
|
+
<template #body>
|
|
149
|
+
<rn-product-list
|
|
150
|
+
displayMode="list"
|
|
151
|
+
:pcColumns="3"
|
|
152
|
+
:spColumns="2"
|
|
153
|
+
:pcRows="1"
|
|
154
|
+
:spRows="1"
|
|
155
|
+
:data="mockProducts"
|
|
156
|
+
/>
|
|
157
|
+
</template>
|
|
158
|
+
</rn-section>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
</rn-app-frame>
|
|
162
|
+
`,
|
|
163
|
+
}),
|
|
164
|
+
}
|