@prsm/mono-components 0.1.0
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/.claude/settings.local.json +13 -0
- package/.lore +83 -0
- package/histoire.config.js +43 -0
- package/package.json +39 -0
- package/postcss.config.js +6 -0
- package/src/components/Badge.vue +36 -0
- package/src/components/Button.vue +44 -0
- package/src/components/Checkbox.vue +51 -0
- package/src/components/CheckboxCards.vue +61 -0
- package/src/components/CodeEditor.vue +299 -0
- package/src/components/Collapsible.vue +69 -0
- package/src/components/CollapsibleGroup.vue +38 -0
- package/src/components/Combobox.vue +179 -0
- package/src/components/ContextMenu.vue +65 -0
- package/src/components/ContextMenuPanel.vue +115 -0
- package/src/components/DataTable.vue +326 -0
- package/src/components/Dropdown.vue +127 -0
- package/src/components/GhostInput.vue +29 -0
- package/src/components/Input.vue +23 -0
- package/src/components/KeyValue.vue +149 -0
- package/src/components/LabeledTextarea.vue +64 -0
- package/src/components/LabeledTextareaGroup.vue +14 -0
- package/src/components/Mention.vue +79 -0
- package/src/components/Modal.vue +109 -0
- package/src/components/MultiCombobox.vue +209 -0
- package/src/components/NavTree.vue +98 -0
- package/src/components/NumberInput.vue +128 -0
- package/src/components/PopConfirm.vue +94 -0
- package/src/components/Popover.vue +53 -0
- package/src/components/RadioCards.vue +37 -0
- package/src/components/RadioGroup.vue +57 -0
- package/src/components/RangeSlider.vue +165 -0
- package/src/components/ScrollBox.vue +78 -0
- package/src/components/SectionHeader.vue +18 -0
- package/src/components/Select.vue +187 -0
- package/src/components/Switch.vue +85 -0
- package/src/components/Tabs.vue +34 -0
- package/src/components/TagInput.vue +80 -0
- package/src/components/Textarea.vue +97 -0
- package/src/components/ToastContainer.vue +104 -0
- package/src/components/ToggleButtons.vue +45 -0
- package/src/components/ToggleGroup.vue +30 -0
- package/src/components/Tooltip.vue +56 -0
- package/src/components/Tree.vue +188 -0
- package/src/composables/toast.js +54 -0
- package/src/composables/useClickOutside.js +23 -0
- package/src/composables/useMention.js +291 -0
- package/src/composables/usePointerDrag.js +39 -0
- package/src/histoire-setup.js +1 -0
- package/src/index.js +43 -0
- package/src/style.css +96 -0
- package/stories/Badge.story.vue +24 -0
- package/stories/Button.story.vue +45 -0
- package/stories/Checkbox.story.vue +31 -0
- package/stories/CheckboxCards.story.vue +51 -0
- package/stories/CodeEditor.story.vue +71 -0
- package/stories/Collapsible.story.vue +84 -0
- package/stories/Combobox.story.vue +44 -0
- package/stories/ContextMenu.story.vue +59 -0
- package/stories/DataTable.story.vue +185 -0
- package/stories/Dropdown.story.vue +49 -0
- package/stories/GhostInput.story.vue +24 -0
- package/stories/Input.story.vue +23 -0
- package/stories/KeyValue.story.vue +104 -0
- package/stories/LabeledTextarea.story.vue +44 -0
- package/stories/Mention.story.vue +166 -0
- package/stories/Modal.story.vue +86 -0
- package/stories/MultiCombobox.story.vue +76 -0
- package/stories/NavTree.story.vue +184 -0
- package/stories/NumberInput.story.vue +31 -0
- package/stories/Overview.story.vue +85 -0
- package/stories/PopConfirm.story.vue +39 -0
- package/stories/RadioCards.story.vue +66 -0
- package/stories/RadioGroup.story.vue +52 -0
- package/stories/RangeSlider.story.vue +75 -0
- package/stories/ScrollBox.story.vue +54 -0
- package/stories/SectionHeader.story.vue +22 -0
- package/stories/Select.story.vue +34 -0
- package/stories/Switch.story.vue +42 -0
- package/stories/Tabs.story.vue +34 -0
- package/stories/TagInput.story.vue +54 -0
- package/stories/Textarea.story.vue +28 -0
- package/stories/Toast.story.vue +28 -0
- package/stories/ToggleButtons.story.vue +57 -0
- package/stories/ToggleGroup.story.vue +34 -0
- package/stories/Tooltip.story.vue +55 -0
- package/stories/Tree.story.vue +115 -0
- package/tailwind.config.js +9 -0
- package/tailwind.preset.js +79 -0
- package/vite.config.js +6 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import Modal from "../src/components/Modal.vue"
|
|
4
|
+
import Button from "../src/components/Button.vue"
|
|
5
|
+
import Input from "../src/components/Input.vue"
|
|
6
|
+
|
|
7
|
+
const basic = ref(false)
|
|
8
|
+
const form = ref(false)
|
|
9
|
+
const scrollable = ref(false)
|
|
10
|
+
const persistent = ref(false)
|
|
11
|
+
const nameVal = ref("")
|
|
12
|
+
const emailVal = ref("")
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<Story title="Modal">
|
|
17
|
+
<Variant title="Basic">
|
|
18
|
+
<Button @click="basic = true">Open Modal</Button>
|
|
19
|
+
<Modal v-model:open="basic">
|
|
20
|
+
<div class="p-4 flex flex-col gap-3 min-w-[300px]">
|
|
21
|
+
<span class="text-lg text-fg-0">Confirm action</span>
|
|
22
|
+
<span class="text-base text-fg-2">Are you sure you want to proceed?</span>
|
|
23
|
+
<div class="flex justify-end gap-2 mt-2">
|
|
24
|
+
<Button variant="outline" @click="basic = false">Cancel</Button>
|
|
25
|
+
<Button variant="primary" @click="basic = false">Confirm</Button>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</Modal>
|
|
29
|
+
</Variant>
|
|
30
|
+
<Variant title="Form">
|
|
31
|
+
<Button @click="form = true">Edit Profile</Button>
|
|
32
|
+
<Modal v-model:open="form">
|
|
33
|
+
<div class="p-4 flex flex-col gap-3 min-w-[360px]">
|
|
34
|
+
<span class="text-lg text-fg-0">Edit profile</span>
|
|
35
|
+
<div class="flex flex-col gap-2">
|
|
36
|
+
<div class="flex flex-col gap-1">
|
|
37
|
+
<label class="text-base text-fg-2">Name</label>
|
|
38
|
+
<Input v-model="nameVal" placeholder="Your name..." autofocus />
|
|
39
|
+
</div>
|
|
40
|
+
<div class="flex flex-col gap-1">
|
|
41
|
+
<label class="text-base text-fg-2">Email</label>
|
|
42
|
+
<Input v-model="emailVal" placeholder="you@example.com" />
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="flex justify-end gap-2 mt-2">
|
|
46
|
+
<Button variant="outline" @click="form = false">Cancel</Button>
|
|
47
|
+
<Button variant="primary" @click="form = false">Save</Button>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</Modal>
|
|
51
|
+
</Variant>
|
|
52
|
+
<Variant title="Scrollable Content">
|
|
53
|
+
<Button @click="scrollable = true">Long Content</Button>
|
|
54
|
+
<Modal v-model:open="scrollable">
|
|
55
|
+
<template #header>
|
|
56
|
+
<div class="p-4 min-w-[360px]">
|
|
57
|
+
<span class="text-lg text-fg-0">Terms of service</span>
|
|
58
|
+
</div>
|
|
59
|
+
</template>
|
|
60
|
+
<div class="p-4 flex flex-col gap-2 text-base text-fg-1 min-w-[360px]">
|
|
61
|
+
<p v-for="i in 20" :key="i">
|
|
62
|
+
Paragraph {{ i }} - Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
63
|
+
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
|
64
|
+
</p>
|
|
65
|
+
</div>
|
|
66
|
+
<template #footer>
|
|
67
|
+
<div class="p-4 flex justify-end gap-2">
|
|
68
|
+
<Button variant="primary" @click="scrollable = false">Accept</Button>
|
|
69
|
+
</div>
|
|
70
|
+
</template>
|
|
71
|
+
</Modal>
|
|
72
|
+
</Variant>
|
|
73
|
+
<Variant title="Persistent (no backdrop close)">
|
|
74
|
+
<Button @click="persistent = true">Persistent Modal</Button>
|
|
75
|
+
<Modal v-model:open="persistent" :close-on-backdrop="false" :close-on-escape="false">
|
|
76
|
+
<div class="p-4 flex flex-col gap-3 min-w-[300px]">
|
|
77
|
+
<span class="text-lg text-fg-0">Required action</span>
|
|
78
|
+
<span class="text-base text-fg-2">You must explicitly close this modal.</span>
|
|
79
|
+
<div class="flex justify-end gap-2 mt-2">
|
|
80
|
+
<Button variant="primary" @click="persistent = false">Got it</Button>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</Modal>
|
|
84
|
+
</Variant>
|
|
85
|
+
</Story>
|
|
86
|
+
</template>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import { logEvent } from "histoire/client"
|
|
4
|
+
import MultiCombobox from "../src/components/MultiCombobox.vue"
|
|
5
|
+
|
|
6
|
+
const fruits = ref(["apple", "banana"])
|
|
7
|
+
const fruitOptions = [
|
|
8
|
+
"apple", "banana", "cherry", "date", "elderberry",
|
|
9
|
+
"fig", "grape", "honeydew", "kiwi", "lemon",
|
|
10
|
+
"mango", "nectarine", "orange", "papaya", "quince"
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
const roles = ref(["admin"])
|
|
14
|
+
const roleOptions = [
|
|
15
|
+
{ value: "admin", label: "Admin" },
|
|
16
|
+
{ value: "editor", label: "Editor" },
|
|
17
|
+
{ value: "viewer", label: "Viewer" },
|
|
18
|
+
{ value: "billing", label: "Billing" },
|
|
19
|
+
{ value: "support", label: "Support" }
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
const tags = ref([])
|
|
23
|
+
const tagOptions = [
|
|
24
|
+
"bug", "feature", "enhancement", "documentation",
|
|
25
|
+
"help wanted", "good first issue", "priority: high",
|
|
26
|
+
"priority: medium", "priority: low", "wontfix"
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
function handleUpdate(name, value) {
|
|
30
|
+
logEvent("update:modelValue", { name, value })
|
|
31
|
+
}
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<Story title="MultiCombobox">
|
|
36
|
+
<Variant title="Basic">
|
|
37
|
+
<div class="w-[300px]">
|
|
38
|
+
<MultiCombobox
|
|
39
|
+
v-model="fruits"
|
|
40
|
+
:options="fruitOptions"
|
|
41
|
+
placeholder="pick fruits..."
|
|
42
|
+
@update:model-value="v => handleUpdate('fruits', v)"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
<template #controls>
|
|
46
|
+
<div class="text-xs text-fg-2 p-2">selected: {{ fruits.join(', ') }}</div>
|
|
47
|
+
</template>
|
|
48
|
+
</Variant>
|
|
49
|
+
<Variant title="Object Options">
|
|
50
|
+
<div class="w-[300px]">
|
|
51
|
+
<MultiCombobox
|
|
52
|
+
v-model="roles"
|
|
53
|
+
:options="roleOptions"
|
|
54
|
+
placeholder="assign roles..."
|
|
55
|
+
@update:model-value="v => handleUpdate('roles', v)"
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
<template #controls>
|
|
59
|
+
<div class="text-xs text-fg-2 p-2">selected: {{ roles.join(', ') }}</div>
|
|
60
|
+
</template>
|
|
61
|
+
</Variant>
|
|
62
|
+
<Variant title="Empty">
|
|
63
|
+
<div class="w-[300px]">
|
|
64
|
+
<MultiCombobox
|
|
65
|
+
v-model="tags"
|
|
66
|
+
:options="tagOptions"
|
|
67
|
+
placeholder="add labels..."
|
|
68
|
+
@update:model-value="v => handleUpdate('tags', v)"
|
|
69
|
+
/>
|
|
70
|
+
</div>
|
|
71
|
+
<template #controls>
|
|
72
|
+
<div class="text-xs text-fg-2 p-2">selected: {{ tags.length ? tags.join(', ') : 'none' }}</div>
|
|
73
|
+
</template>
|
|
74
|
+
</Variant>
|
|
75
|
+
</Story>
|
|
76
|
+
</template>
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import { logEvent } from "histoire/client"
|
|
4
|
+
import NavTree from "../src/components/NavTree.vue"
|
|
5
|
+
import ScrollBox from "../src/components/ScrollBox.vue"
|
|
6
|
+
import Badge from "../src/components/Badge.vue"
|
|
7
|
+
|
|
8
|
+
const active = ref("overview")
|
|
9
|
+
|
|
10
|
+
const sidebarItems = [
|
|
11
|
+
{
|
|
12
|
+
key: "general",
|
|
13
|
+
label: "General",
|
|
14
|
+
children: [
|
|
15
|
+
{ key: "overview", label: "Overview", icon: "material-symbols:dashboard-outline" },
|
|
16
|
+
{ key: "settings", label: "Settings", icon: "material-symbols:settings-outline" },
|
|
17
|
+
{ key: "members", label: "Members", icon: "material-symbols:group-outline", badge: 5 }
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
key: "content",
|
|
22
|
+
label: "Content",
|
|
23
|
+
children: [
|
|
24
|
+
{ key: "pages", label: "Pages", icon: "material-symbols:description-outline" },
|
|
25
|
+
{ key: "media", label: "Media", icon: "material-symbols:image-outline" },
|
|
26
|
+
{ key: "create-page", label: "New page", icon: "material-symbols:add" }
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
key: "system",
|
|
31
|
+
label: "System",
|
|
32
|
+
children: [
|
|
33
|
+
{ key: "logs", label: "Logs", icon: "material-symbols:receipt-long-outline" },
|
|
34
|
+
{ key: "api-keys", label: "API keys", icon: "material-symbols:key-outline" }
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
const projectItems = [
|
|
40
|
+
{
|
|
41
|
+
key: "projects",
|
|
42
|
+
label: "Projects",
|
|
43
|
+
children: [
|
|
44
|
+
{ key: "proj-1", label: "mono-components" },
|
|
45
|
+
{ key: "proj-2", label: "axiom" },
|
|
46
|
+
{ key: "proj-3", label: "prose-preact" },
|
|
47
|
+
{ key: "create-project", label: "New project", icon: "material-symbols:add" }
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
key: "recent",
|
|
52
|
+
label: "Recent",
|
|
53
|
+
children: [
|
|
54
|
+
{ key: "proj-1", label: "mono-components" },
|
|
55
|
+
{ key: "proj-3", label: "prose-preact" }
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
const projectActive = ref("proj-1")
|
|
61
|
+
|
|
62
|
+
const nestedItems = [
|
|
63
|
+
{
|
|
64
|
+
key: "org",
|
|
65
|
+
label: "Acme Corp",
|
|
66
|
+
children: [
|
|
67
|
+
{
|
|
68
|
+
key: "engineering",
|
|
69
|
+
label: "Engineering",
|
|
70
|
+
children: [
|
|
71
|
+
{
|
|
72
|
+
key: "frontend",
|
|
73
|
+
label: "Frontend",
|
|
74
|
+
children: [
|
|
75
|
+
{ key: "react-app", label: "react-app" },
|
|
76
|
+
{ key: "vue-app", label: "vue-app" },
|
|
77
|
+
{ key: "design-system", label: "design-system" }
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
key: "backend",
|
|
82
|
+
label: "Backend",
|
|
83
|
+
children: [
|
|
84
|
+
{ key: "api-gateway", label: "api-gateway" },
|
|
85
|
+
{ key: "auth-service", label: "auth-service" },
|
|
86
|
+
{ key: "worker", label: "worker" }
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
{ key: "infra", label: "Infrastructure" }
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
key: "design",
|
|
94
|
+
label: "Design",
|
|
95
|
+
children: [
|
|
96
|
+
{ key: "brand", label: "Brand guidelines" },
|
|
97
|
+
{ key: "figma", label: "Figma files" }
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
{ key: "org-settings", label: "Settings", icon: "material-symbols:settings-outline" }
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
const nestedActive = ref("vue-app")
|
|
106
|
+
|
|
107
|
+
const flatItems = [
|
|
108
|
+
{ key: "inbox", label: "Inbox", icon: "material-symbols:inbox", badge: 12 },
|
|
109
|
+
{ key: "drafts", label: "Drafts", icon: "material-symbols:edit-outline", badge: 3 },
|
|
110
|
+
{ key: "sent", label: "Sent", icon: "material-symbols:send" },
|
|
111
|
+
{ key: "archive", label: "Archive", icon: "material-symbols:archive-outline" },
|
|
112
|
+
{ key: "trash", label: "Trash", icon: "material-symbols:delete-outline" }
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
const mailActive = ref("inbox")
|
|
116
|
+
|
|
117
|
+
function handleSelect(key) {
|
|
118
|
+
logEvent("select", { key })
|
|
119
|
+
}
|
|
120
|
+
</script>
|
|
121
|
+
|
|
122
|
+
<template>
|
|
123
|
+
<Story title="NavTree">
|
|
124
|
+
<Variant title="Sidebar Navigation">
|
|
125
|
+
<div class="w-56 h-80 bg-1 border border-line rounded-sm overflow-hidden">
|
|
126
|
+
<NavTree
|
|
127
|
+
v-model="active"
|
|
128
|
+
:items="sidebarItems"
|
|
129
|
+
:default-expanded="['general', 'content']"
|
|
130
|
+
@select="handleSelect"
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
<template #controls>
|
|
134
|
+
<div class="text-xs text-fg-2 p-2">active: {{ active }}</div>
|
|
135
|
+
</template>
|
|
136
|
+
</Variant>
|
|
137
|
+
<Variant title="Project List">
|
|
138
|
+
<div class="w-56 h-64 bg-1 border border-line rounded-sm overflow-hidden">
|
|
139
|
+
<NavTree
|
|
140
|
+
v-model="projectActive"
|
|
141
|
+
:items="projectItems"
|
|
142
|
+
:default-expanded="true"
|
|
143
|
+
@select="handleSelect"
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
</Variant>
|
|
147
|
+
<Variant title="Deeply Nested">
|
|
148
|
+
<ScrollBox class="h-[256px] bg-1 border border-line rounded-sm">
|
|
149
|
+
<NavTree
|
|
150
|
+
v-model="nestedActive"
|
|
151
|
+
:items="nestedItems"
|
|
152
|
+
:default-expanded="['org', 'engineering', 'frontend', 'backend', 'design']"
|
|
153
|
+
@select="handleSelect"
|
|
154
|
+
/>
|
|
155
|
+
</ScrollBox>
|
|
156
|
+
<template #controls>
|
|
157
|
+
<div class="text-xs text-fg-2 p-2">active: {{ nestedActive }}</div>
|
|
158
|
+
</template>
|
|
159
|
+
</Variant>
|
|
160
|
+
<Variant title="Flat (no groups)">
|
|
161
|
+
<div class="w-48 h-64 bg-1 border border-line rounded-sm overflow-hidden">
|
|
162
|
+
<NavTree
|
|
163
|
+
v-model="mailActive"
|
|
164
|
+
:items="flatItems"
|
|
165
|
+
@select="handleSelect"
|
|
166
|
+
/>
|
|
167
|
+
</div>
|
|
168
|
+
</Variant>
|
|
169
|
+
<Variant title="With Trailing Slot">
|
|
170
|
+
<div class="w-56 h-80 bg-1 border border-line rounded-sm overflow-hidden">
|
|
171
|
+
<NavTree
|
|
172
|
+
v-model="active"
|
|
173
|
+
:items="sidebarItems"
|
|
174
|
+
:default-expanded="['general', 'content']"
|
|
175
|
+
@select="handleSelect"
|
|
176
|
+
>
|
|
177
|
+
<template #trailing-members="{ node }">
|
|
178
|
+
<Badge variant="warning">{{ node.badge }}</Badge>
|
|
179
|
+
</template>
|
|
180
|
+
</NavTree>
|
|
181
|
+
</div>
|
|
182
|
+
</Variant>
|
|
183
|
+
</Story>
|
|
184
|
+
</template>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import NumberInput from "../src/components/NumberInput.vue"
|
|
4
|
+
|
|
5
|
+
const integer = ref(50)
|
|
6
|
+
const decimal = ref(0.5)
|
|
7
|
+
const constrained = ref(5)
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<Story title="NumberInput">
|
|
12
|
+
<Variant title="Default">
|
|
13
|
+
<NumberInput v-model="integer" />
|
|
14
|
+
<template #controls>
|
|
15
|
+
<div class="text-xs text-fg-2 p-2">value: {{ integer }}</div>
|
|
16
|
+
</template>
|
|
17
|
+
</Variant>
|
|
18
|
+
<Variant title="Decimal (step 0.1)">
|
|
19
|
+
<NumberInput v-model="decimal" :step="0.1" :precision="2" />
|
|
20
|
+
<template #controls>
|
|
21
|
+
<div class="text-xs text-fg-2 p-2">value: {{ decimal }}</div>
|
|
22
|
+
</template>
|
|
23
|
+
</Variant>
|
|
24
|
+
<Variant title="Constrained (0-10)">
|
|
25
|
+
<NumberInput v-model="constrained" :min="0" :max="10" />
|
|
26
|
+
<template #controls>
|
|
27
|
+
<div class="text-xs text-fg-2 p-2">value: {{ constrained }}</div>
|
|
28
|
+
</template>
|
|
29
|
+
</Variant>
|
|
30
|
+
</Story>
|
|
31
|
+
</template>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import { Icon } from "@iconify/vue"
|
|
4
|
+
import Button from "../src/components/Button.vue"
|
|
5
|
+
import Input from "../src/components/Input.vue"
|
|
6
|
+
import NumberInput from "../src/components/NumberInput.vue"
|
|
7
|
+
import Select from "../src/components/Select.vue"
|
|
8
|
+
import Dropdown from "../src/components/Dropdown.vue"
|
|
9
|
+
import Checkbox from "../src/components/Checkbox.vue"
|
|
10
|
+
import Badge from "../src/components/Badge.vue"
|
|
11
|
+
import Tabs from "../src/components/Tabs.vue"
|
|
12
|
+
import ToggleGroup from "../src/components/ToggleGroup.vue"
|
|
13
|
+
import ToggleButtons from "../src/components/ToggleButtons.vue"
|
|
14
|
+
import RangeSlider from "../src/components/RangeSlider.vue"
|
|
15
|
+
import RadioGroup from "../src/components/RadioGroup.vue"
|
|
16
|
+
|
|
17
|
+
const inputVal = ref("")
|
|
18
|
+
const numberVal = ref(42)
|
|
19
|
+
const selectVal = ref("a")
|
|
20
|
+
const dropdownVal = ref("grid")
|
|
21
|
+
const checkVal = ref(true)
|
|
22
|
+
const tabVal = ref("all")
|
|
23
|
+
const toggleVal = ref("grid")
|
|
24
|
+
const radioVal = ref("a")
|
|
25
|
+
const toggleBtns = ref(["x", "y"])
|
|
26
|
+
const rangeVal = ref(50)
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<Story title="Overview" icon="material-symbols:dashboard">
|
|
31
|
+
<Variant title="Height Consistency">
|
|
32
|
+
<p class="text-xs text-fg-3 mb-3">all control-height elements should align vertically</p>
|
|
33
|
+
<div class="flex items-center gap-2 flex-wrap">
|
|
34
|
+
<Button>Button</Button>
|
|
35
|
+
<Button variant="primary">Primary</Button>
|
|
36
|
+
<Button variant="outline">Outline</Button>
|
|
37
|
+
<Button variant="icon"><Icon icon="material-symbols:settings" class="text-base" /></Button>
|
|
38
|
+
<Button variant="ghost">Ghost</Button>
|
|
39
|
+
<Input v-model="inputVal" placeholder="input..." style="width: 120px" />
|
|
40
|
+
<NumberInput v-model="numberVal" style="width: 100px" />
|
|
41
|
+
<Select v-model="selectVal" :options="[{ value: 'a', label: 'Select' }]" />
|
|
42
|
+
<Dropdown v-model="dropdownVal" label="Dropdown" :options="[{ value: 'grid', label: 'Grid' }]" />
|
|
43
|
+
<Checkbox v-model="checkVal" label="Checkbox" />
|
|
44
|
+
<Badge variant="info">Badge</Badge>
|
|
45
|
+
<ToggleGroup v-model="toggleVal" :options="[{ value: 'grid', icon: 'material-symbols:grid-view' }, { value: 'list', icon: 'material-symbols:view-list' }]" />
|
|
46
|
+
<ToggleButtons v-model="toggleBtns" :options="['X', 'Y', 'Z']" />
|
|
47
|
+
<RangeSlider v-model="rangeVal" :min="0" :max="100" style="width: 120px" />
|
|
48
|
+
<RadioGroup v-model="radioVal" :options="[{ value: 'a', label: 'Radio A' }, { value: 'b', label: 'Radio B' }]" direction="horizontal" />
|
|
49
|
+
</div>
|
|
50
|
+
</Variant>
|
|
51
|
+
<Variant title="Tabs Height">
|
|
52
|
+
<div class="flex items-center gap-2">
|
|
53
|
+
<Tabs
|
|
54
|
+
v-model="tabVal"
|
|
55
|
+
:tabs="[
|
|
56
|
+
{ key: 'all', label: 'All', count: 10 },
|
|
57
|
+
{ key: 'active', label: 'Active' }
|
|
58
|
+
]"
|
|
59
|
+
/>
|
|
60
|
+
<Button variant="outline">Action</Button>
|
|
61
|
+
<Input v-model="inputVal" placeholder="search..." style="width: 120px" />
|
|
62
|
+
</div>
|
|
63
|
+
</Variant>
|
|
64
|
+
<Variant title="Form Layout">
|
|
65
|
+
<div class="flex flex-col gap-2 max-w-xs">
|
|
66
|
+
<div class="flex items-center gap-2">
|
|
67
|
+
<label class="text-base text-fg-2 w-16 shrink-0">Name</label>
|
|
68
|
+
<Input v-model="inputVal" placeholder="enter name..." />
|
|
69
|
+
</div>
|
|
70
|
+
<div class="flex items-center gap-2">
|
|
71
|
+
<label class="text-base text-fg-2 w-16 shrink-0">Count</label>
|
|
72
|
+
<NumberInput v-model="numberVal" :min="0" :max="100" />
|
|
73
|
+
</div>
|
|
74
|
+
<div class="flex items-center gap-2">
|
|
75
|
+
<label class="text-base text-fg-2 w-16 shrink-0">Type</label>
|
|
76
|
+
<Select v-model="selectVal" :options="['a', 'b', 'c']" />
|
|
77
|
+
</div>
|
|
78
|
+
<div class="flex items-center gap-2">
|
|
79
|
+
<label class="text-base text-fg-2 w-16 shrink-0">Active</label>
|
|
80
|
+
<Checkbox v-model="checkVal" />
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</Variant>
|
|
84
|
+
</Story>
|
|
85
|
+
</template>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import PopConfirm from "../src/components/PopConfirm.vue"
|
|
4
|
+
import Button from "../src/components/Button.vue"
|
|
5
|
+
|
|
6
|
+
const lastAction = ref("none")
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<Story title="PopConfirm">
|
|
11
|
+
<Variant title="Default">
|
|
12
|
+
<PopConfirm @confirm="lastAction = 'confirmed'" @cancel="lastAction = 'cancelled'">
|
|
13
|
+
<Button>Click here</Button>
|
|
14
|
+
</PopConfirm>
|
|
15
|
+
<template #controls>
|
|
16
|
+
<div class="text-xs text-fg-2 p-2">last action: {{ lastAction }}</div>
|
|
17
|
+
</template>
|
|
18
|
+
</Variant>
|
|
19
|
+
<Variant title="Custom Message">
|
|
20
|
+
<PopConfirm
|
|
21
|
+
message="Delete this item?"
|
|
22
|
+
confirm-label="Delete"
|
|
23
|
+
cancel-label="Nope"
|
|
24
|
+
icon="material-symbols:delete-outline"
|
|
25
|
+
@confirm="lastAction = 'deleted'"
|
|
26
|
+
@cancel="lastAction = 'cancelled'"
|
|
27
|
+
>
|
|
28
|
+
<Button variant="danger">Delete</Button>
|
|
29
|
+
</PopConfirm>
|
|
30
|
+
</Variant>
|
|
31
|
+
<Variant title="Placement Top">
|
|
32
|
+
<div class="pt-24">
|
|
33
|
+
<PopConfirm placement="top-start" @confirm="lastAction = 'confirmed'">
|
|
34
|
+
<Button variant="outline">Confirm above</Button>
|
|
35
|
+
</PopConfirm>
|
|
36
|
+
</div>
|
|
37
|
+
</Variant>
|
|
38
|
+
</Story>
|
|
39
|
+
</template>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import { logEvent } from "histoire/client"
|
|
4
|
+
import RadioCards from "../src/components/RadioCards.vue"
|
|
5
|
+
|
|
6
|
+
const plan = ref("pro")
|
|
7
|
+
const planOptions = [
|
|
8
|
+
{ value: "free", label: "Free", description: "5 projects, 1 GB storage, community support" },
|
|
9
|
+
{ value: "pro", label: "Pro", description: "Unlimited projects, 100 GB storage, priority support" },
|
|
10
|
+
{ value: "enterprise", label: "Enterprise", description: "Custom limits, dedicated infrastructure, SLA guarantee" }
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
const deploy = ref("docker")
|
|
14
|
+
const deployOptions = [
|
|
15
|
+
{ value: "docker", label: "Docker", description: "Container-based deployment with full control over the runtime environment" },
|
|
16
|
+
{ value: "nixpacks", label: "Nixpacks", description: "Auto-detected buildpacks, zero config for most frameworks" },
|
|
17
|
+
{ value: "static", label: "Static", description: "Pre-built assets served via CDN, no server required" }
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
const priority = ref(null)
|
|
21
|
+
const priorityOptions = [
|
|
22
|
+
{ value: "low", label: "Low" },
|
|
23
|
+
{ value: "medium", label: "Medium" },
|
|
24
|
+
{ value: "high", label: "High" },
|
|
25
|
+
{ value: "critical", label: "Critical" }
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
function handleUpdate(name, value) {
|
|
29
|
+
logEvent("update:modelValue", { name, value })
|
|
30
|
+
}
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<template>
|
|
34
|
+
<Story title="RadioCards">
|
|
35
|
+
<Variant title="Pricing Plans">
|
|
36
|
+
<div class="w-[320px]">
|
|
37
|
+
<RadioCards
|
|
38
|
+
v-model="plan"
|
|
39
|
+
:options="planOptions"
|
|
40
|
+
@update:model-value="v => handleUpdate('plan', v)"
|
|
41
|
+
/>
|
|
42
|
+
</div>
|
|
43
|
+
<template #controls>
|
|
44
|
+
<div class="text-xs text-fg-2 p-2">selected: {{ plan }}</div>
|
|
45
|
+
</template>
|
|
46
|
+
</Variant>
|
|
47
|
+
<Variant title="Deploy Target">
|
|
48
|
+
<div class="w-[320px]">
|
|
49
|
+
<RadioCards
|
|
50
|
+
v-model="deploy"
|
|
51
|
+
:options="deployOptions"
|
|
52
|
+
@update:model-value="v => handleUpdate('deploy', v)"
|
|
53
|
+
/>
|
|
54
|
+
</div>
|
|
55
|
+
</Variant>
|
|
56
|
+
<Variant title="No Descriptions">
|
|
57
|
+
<div class="w-[240px]">
|
|
58
|
+
<RadioCards
|
|
59
|
+
v-model="priority"
|
|
60
|
+
:options="priorityOptions"
|
|
61
|
+
@update:model-value="v => handleUpdate('priority', v)"
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
</Variant>
|
|
65
|
+
</Story>
|
|
66
|
+
</template>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import RadioGroup from "../src/components/RadioGroup.vue"
|
|
4
|
+
|
|
5
|
+
const selected = ref("a")
|
|
6
|
+
const iconSelected = ref("grid")
|
|
7
|
+
const dirSelected = ref("one")
|
|
8
|
+
|
|
9
|
+
const basicOptions = [
|
|
10
|
+
{ value: "a", label: "Option A" },
|
|
11
|
+
{ value: "b", label: "Option B" },
|
|
12
|
+
{ value: "c", label: "Option C" }
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
const iconOptions = [
|
|
16
|
+
{ value: "grid", label: "Grid", icon: "material-symbols:grid-view" },
|
|
17
|
+
{ value: "list", label: "List", icon: "material-symbols:view-list" },
|
|
18
|
+
{ value: "board", label: "Board", icon: "material-symbols:view-kanban" }
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
const dirOptions = [
|
|
22
|
+
{ value: "one", label: "First" },
|
|
23
|
+
{ value: "two", label: "Second" },
|
|
24
|
+
{ value: "three", label: "Third" }
|
|
25
|
+
]
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<Story title="RadioGroup">
|
|
30
|
+
<Variant title="Vertical (default)">
|
|
31
|
+
<RadioGroup v-model="selected" :options="basicOptions" />
|
|
32
|
+
<template #controls>
|
|
33
|
+
<div class="text-xs text-fg-2 p-2">selected: {{ selected }}</div>
|
|
34
|
+
</template>
|
|
35
|
+
</Variant>
|
|
36
|
+
<Variant title="Horizontal">
|
|
37
|
+
<RadioGroup v-model="dirSelected" :options="dirOptions" direction="horizontal" />
|
|
38
|
+
<template #controls>
|
|
39
|
+
<div class="text-xs text-fg-2 p-2">selected: {{ dirSelected }}</div>
|
|
40
|
+
</template>
|
|
41
|
+
</Variant>
|
|
42
|
+
<Variant title="With Icons">
|
|
43
|
+
<RadioGroup v-model="iconSelected" :options="iconOptions" />
|
|
44
|
+
<template #controls>
|
|
45
|
+
<div class="text-xs text-fg-2 p-2">selected: {{ iconSelected }}</div>
|
|
46
|
+
</template>
|
|
47
|
+
</Variant>
|
|
48
|
+
<Variant title="With Icons (Horizontal)">
|
|
49
|
+
<RadioGroup v-model="iconSelected" :options="iconOptions" direction="horizontal" />
|
|
50
|
+
</Variant>
|
|
51
|
+
</Story>
|
|
52
|
+
</template>
|