@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,75 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import { logEvent } from "histoire/client"
|
|
4
|
+
import RangeSlider from "../src/components/RangeSlider.vue"
|
|
5
|
+
|
|
6
|
+
const opacity = ref(50)
|
|
7
|
+
const volume = ref(75)
|
|
8
|
+
const temperature = ref(0.7)
|
|
9
|
+
const rotation = ref(0)
|
|
10
|
+
|
|
11
|
+
function handleUpdate(name, value) {
|
|
12
|
+
logEvent("update:modelValue", { name, value })
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<Story title="RangeSlider">
|
|
18
|
+
<Variant title="Basic">
|
|
19
|
+
<div class="flex flex-col gap-3 w-[300px]">
|
|
20
|
+
<RangeSlider
|
|
21
|
+
v-model="opacity"
|
|
22
|
+
:min="0"
|
|
23
|
+
:max="100"
|
|
24
|
+
label="Opacity"
|
|
25
|
+
@update:model-value="v => handleUpdate('opacity', v)"
|
|
26
|
+
/>
|
|
27
|
+
<RangeSlider
|
|
28
|
+
v-model="volume"
|
|
29
|
+
:min="0"
|
|
30
|
+
:max="100"
|
|
31
|
+
label="Volume"
|
|
32
|
+
@update:model-value="v => handleUpdate('volume', v)"
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
<template #controls>
|
|
36
|
+
<div class="text-xs text-fg-2 p-2">
|
|
37
|
+
opacity: {{ opacity }}, volume: {{ volume }}
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
40
|
+
</Variant>
|
|
41
|
+
<Variant title="Float Precision">
|
|
42
|
+
<div class="w-[300px]">
|
|
43
|
+
<RangeSlider
|
|
44
|
+
v-model="temperature"
|
|
45
|
+
:min="0"
|
|
46
|
+
:max="2"
|
|
47
|
+
:step="0.01"
|
|
48
|
+
label="Temperature"
|
|
49
|
+
@update:model-value="v => handleUpdate('temperature', v)"
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
52
|
+
</Variant>
|
|
53
|
+
<Variant title="Negative Range">
|
|
54
|
+
<div class="w-[300px]">
|
|
55
|
+
<RangeSlider
|
|
56
|
+
v-model="rotation"
|
|
57
|
+
:min="-180"
|
|
58
|
+
:max="180"
|
|
59
|
+
label="Rotation"
|
|
60
|
+
@update:model-value="v => handleUpdate('rotation', v)"
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
</Variant>
|
|
64
|
+
<Variant title="No Label">
|
|
65
|
+
<div class="w-[300px]">
|
|
66
|
+
<RangeSlider
|
|
67
|
+
v-model="opacity"
|
|
68
|
+
:min="0"
|
|
69
|
+
:max="100"
|
|
70
|
+
@update:model-value="v => handleUpdate('opacity', v)"
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
</Variant>
|
|
74
|
+
</Story>
|
|
75
|
+
</template>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import ScrollBox from "../src/components/ScrollBox.vue"
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<Story title="ScrollBox">
|
|
7
|
+
<Variant title="Vertical">
|
|
8
|
+
<ScrollBox style="height: 200px" class="p-3 bg-1 border border-line rounded-sm">
|
|
9
|
+
<p class="text-base text-fg-1 mb-3">
|
|
10
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
|
11
|
+
tempor incididunt ut labore et dolore magna aliqua. Sed vulputate odio
|
|
12
|
+
ut enim. Magnis dis parturient montes nascetur ridiculus mus. Ultricies
|
|
13
|
+
mi eget mauris pharetra et. Massa sapien faucibus et molestie ac feugiat
|
|
14
|
+
sed lectus. Tempus imperdiet nulla malesuada pellentesque elit. Sit amet
|
|
15
|
+
aliquam id diam. Aliquam ultrices sagittis orci a. Urna nec tincidunt
|
|
16
|
+
praesent semper feugiat nibh sed pulvinar. Sit amet mauris commodo quis
|
|
17
|
+
imperdiet. Aliquet enim facilisis gravida neque convallis a cras semper.
|
|
18
|
+
</p>
|
|
19
|
+
<p class="text-base text-fg-1 mb-3">
|
|
20
|
+
Vitae nunc sed velit dignissim sodales ut eu. Pretium quam vulputate
|
|
21
|
+
dignissim suspendisse in est. Duis ut diam quam nulla porttitor massa id
|
|
22
|
+
neque aliquam. Volutpat ac tincidunt vitae semper quis lectus nulla at.
|
|
23
|
+
Ac tincidunt vitae semper quis lectus nulla at. Quis hendrerit dolor
|
|
24
|
+
magna egest est. Feugiat in ante metus dictum at tempor commodo
|
|
25
|
+
ullamcorper a. Quis auctor elit sed vulputate mi sit.
|
|
26
|
+
</p>
|
|
27
|
+
<p class="text-base text-fg-1">
|
|
28
|
+
Egestas dui id ornare arcu odio ut sem nulla. Potenti nullam ac tortor
|
|
29
|
+
vitae purus faucibus ornare suspendisse sed. Sagittis id consectetur
|
|
30
|
+
purus ut faucibus pulvinar elementum integer. Amet venenatis urna cursus
|
|
31
|
+
eget nunc scelerisque viverra mauris. Morbi tempus iaculis urna id
|
|
32
|
+
volutpat lacus laoreet non.
|
|
33
|
+
</p>
|
|
34
|
+
</ScrollBox>
|
|
35
|
+
</Variant>
|
|
36
|
+
<Variant title="Horizontal">
|
|
37
|
+
<ScrollBox horizontal style="height: 100px; width: 300px" class="p-3 bg-1 border border-line rounded-sm">
|
|
38
|
+
<div style="width: 800px">
|
|
39
|
+
<p class="text-base text-fg-1 whitespace-nowrap">
|
|
40
|
+
This content is wider than the container and scrolls horizontally.
|
|
41
|
+
Keep going to the right to see more content that overflows the scroll box.
|
|
42
|
+
</p>
|
|
43
|
+
</div>
|
|
44
|
+
</ScrollBox>
|
|
45
|
+
</Variant>
|
|
46
|
+
<Variant title="Max Height List">
|
|
47
|
+
<ScrollBox style="max-height: 150px" class="bg-1 border border-line rounded-sm">
|
|
48
|
+
<div v-for="i in 20" :key="i" class="px-3 py-1 text-base text-fg-1 border-b border-line-subtle">
|
|
49
|
+
Item {{ i }}
|
|
50
|
+
</div>
|
|
51
|
+
</ScrollBox>
|
|
52
|
+
</Variant>
|
|
53
|
+
</Story>
|
|
54
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import SectionHeader from "../src/components/SectionHeader.vue"
|
|
3
|
+
import Button from "../src/components/Button.vue"
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<Story title="SectionHeader">
|
|
8
|
+
<Variant title="Label Only">
|
|
9
|
+
<SectionHeader label="Assertions" />
|
|
10
|
+
</Variant>
|
|
11
|
+
<Variant title="With Description">
|
|
12
|
+
<SectionHeader label="Assertions" description="conditions that must pass for this test case to succeed" />
|
|
13
|
+
</Variant>
|
|
14
|
+
<Variant title="With Actions">
|
|
15
|
+
<SectionHeader label="Assertions" description="conditions that must pass for this test case to succeed">
|
|
16
|
+
<template #actions>
|
|
17
|
+
<Button>+ add assertion</Button>
|
|
18
|
+
</template>
|
|
19
|
+
</SectionHeader>
|
|
20
|
+
</Variant>
|
|
21
|
+
</Story>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import Select from "../src/components/Select.vue"
|
|
4
|
+
|
|
5
|
+
const simple = ref(null)
|
|
6
|
+
const withObjects = ref("b")
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<Story title="Select">
|
|
11
|
+
<Variant title="String Options">
|
|
12
|
+
<Select v-model="simple" :options="['apple', 'banana', 'cherry', 'dragonfruit']" />
|
|
13
|
+
<template #controls>
|
|
14
|
+
<div class="text-xs text-fg-2 p-2">value: {{ simple }}</div>
|
|
15
|
+
</template>
|
|
16
|
+
</Variant>
|
|
17
|
+
<Variant title="Object Options">
|
|
18
|
+
<Select
|
|
19
|
+
v-model="withObjects"
|
|
20
|
+
:options="[
|
|
21
|
+
{ value: 'a', label: 'Option A' },
|
|
22
|
+
{ value: 'b', label: 'Option B' },
|
|
23
|
+
{ value: 'c', label: 'Option C' }
|
|
24
|
+
]"
|
|
25
|
+
/>
|
|
26
|
+
<template #controls>
|
|
27
|
+
<div class="text-xs text-fg-2 p-2">value: {{ withObjects }}</div>
|
|
28
|
+
</template>
|
|
29
|
+
</Variant>
|
|
30
|
+
<Variant title="Custom Placeholder">
|
|
31
|
+
<Select v-model="simple" :options="['one', 'two', 'three']" placeholder="pick one..." />
|
|
32
|
+
</Variant>
|
|
33
|
+
</Story>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import Switch from "../src/components/Switch.vue"
|
|
4
|
+
|
|
5
|
+
const on = ref(false)
|
|
6
|
+
const features = ref({ darkMode: true, notifications: false, autoSave: true })
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<Story title="Switch">
|
|
11
|
+
<Variant title="Default">
|
|
12
|
+
<Switch v-model="on" />
|
|
13
|
+
<template #controls>
|
|
14
|
+
<div class="text-xs text-fg-2 p-2">value: {{ on }}</div>
|
|
15
|
+
</template>
|
|
16
|
+
</Variant>
|
|
17
|
+
<Variant title="States">
|
|
18
|
+
<div class="flex items-center gap-4">
|
|
19
|
+
<Switch :model-value="false" />
|
|
20
|
+
<Switch :model-value="true" />
|
|
21
|
+
<Switch :model-value="false" disabled />
|
|
22
|
+
<Switch :model-value="true" disabled />
|
|
23
|
+
</div>
|
|
24
|
+
</Variant>
|
|
25
|
+
<Variant title="Settings List">
|
|
26
|
+
<div class="flex flex-col gap-2 max-w-xs">
|
|
27
|
+
<label class="flex items-center justify-between px-2 py-1 rounded-sm hover:bg-2 cursor-pointer">
|
|
28
|
+
<span class="text-base text-fg-0">Dark mode</span>
|
|
29
|
+
<Switch v-model="features.darkMode" />
|
|
30
|
+
</label>
|
|
31
|
+
<label class="flex items-center justify-between px-2 py-1 rounded-sm hover:bg-2 cursor-pointer">
|
|
32
|
+
<span class="text-base text-fg-0">Notifications</span>
|
|
33
|
+
<Switch v-model="features.notifications" />
|
|
34
|
+
</label>
|
|
35
|
+
<label class="flex items-center justify-between px-2 py-1 rounded-sm hover:bg-2 cursor-pointer">
|
|
36
|
+
<span class="text-base text-fg-0">Auto save</span>
|
|
37
|
+
<Switch v-model="features.autoSave" />
|
|
38
|
+
</label>
|
|
39
|
+
</div>
|
|
40
|
+
</Variant>
|
|
41
|
+
</Story>
|
|
42
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import Tabs from "../src/components/Tabs.vue"
|
|
4
|
+
|
|
5
|
+
const active = ref("all")
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<Story title="Tabs">
|
|
10
|
+
<Variant title="Basic">
|
|
11
|
+
<Tabs
|
|
12
|
+
v-model="active"
|
|
13
|
+
:tabs="[
|
|
14
|
+
{ key: 'all', label: 'All' },
|
|
15
|
+
{ key: 'active', label: 'Active' },
|
|
16
|
+
{ key: 'archived', label: 'Archived' }
|
|
17
|
+
]"
|
|
18
|
+
/>
|
|
19
|
+
<template #controls>
|
|
20
|
+
<div class="text-xs text-fg-2 p-2">active: {{ active }}</div>
|
|
21
|
+
</template>
|
|
22
|
+
</Variant>
|
|
23
|
+
<Variant title="With Icons and Counts">
|
|
24
|
+
<Tabs
|
|
25
|
+
v-model="active"
|
|
26
|
+
:tabs="[
|
|
27
|
+
{ key: 'all', icon: 'material-symbols:list', label: 'All', count: 42 },
|
|
28
|
+
{ key: 'active', icon: 'material-symbols:check-circle', label: 'Active', count: 12 },
|
|
29
|
+
{ key: 'archived', icon: 'material-symbols:archive', label: 'Archived', count: 30 }
|
|
30
|
+
]"
|
|
31
|
+
/>
|
|
32
|
+
</Variant>
|
|
33
|
+
</Story>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import { logEvent } from "histoire/client"
|
|
4
|
+
import TagInput from "../src/components/TagInput.vue"
|
|
5
|
+
|
|
6
|
+
const colors = ref(["red", "blue", "green"])
|
|
7
|
+
const empty = ref([])
|
|
8
|
+
const sentiments = ref(["positive", "neutral", "negative"])
|
|
9
|
+
|
|
10
|
+
function handleUpdate(name, value) {
|
|
11
|
+
logEvent("update:modelValue", { name, value })
|
|
12
|
+
}
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<Story title="TagInput">
|
|
17
|
+
<Variant title="With Tags">
|
|
18
|
+
<div class="w-[300px]">
|
|
19
|
+
<TagInput
|
|
20
|
+
v-model="colors"
|
|
21
|
+
placeholder="type and press enter..."
|
|
22
|
+
@update:model-value="v => handleUpdate('colors', v)"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
<template #controls>
|
|
26
|
+
<div class="text-xs text-fg-2 p-2">tags: {{ colors.join(', ') }}</div>
|
|
27
|
+
</template>
|
|
28
|
+
</Variant>
|
|
29
|
+
<Variant title="Empty">
|
|
30
|
+
<div class="w-[300px]">
|
|
31
|
+
<TagInput
|
|
32
|
+
v-model="empty"
|
|
33
|
+
placeholder="add tags..."
|
|
34
|
+
@update:model-value="v => handleUpdate('empty', v)"
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
37
|
+
<template #controls>
|
|
38
|
+
<div class="text-xs text-fg-2 p-2">tags: {{ empty.length ? empty.join(', ') : 'none' }}</div>
|
|
39
|
+
</template>
|
|
40
|
+
</Variant>
|
|
41
|
+
<Variant title="Enum Options">
|
|
42
|
+
<div class="w-[300px]">
|
|
43
|
+
<TagInput
|
|
44
|
+
v-model="sentiments"
|
|
45
|
+
placeholder="type option, enter to add"
|
|
46
|
+
@update:model-value="v => handleUpdate('sentiments', v)"
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
<template #controls>
|
|
50
|
+
<div class="text-xs text-fg-2 p-2">options: {{ sentiments.join(', ') }}</div>
|
|
51
|
+
</template>
|
|
52
|
+
</Variant>
|
|
53
|
+
</Story>
|
|
54
|
+
</template>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import Textarea from "../src/components/Textarea.vue"
|
|
4
|
+
|
|
5
|
+
const basic = ref("")
|
|
6
|
+
const prefilled = ref("This textarea has some initial content that was set before mount. It should auto-grow to fit this text without any scrollbar appearing.")
|
|
7
|
+
const growing = ref("")
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<Story title="Textarea">
|
|
12
|
+
<Variant title="Default">
|
|
13
|
+
<Textarea v-model="basic" placeholder="Placeholder" />
|
|
14
|
+
<template #controls>
|
|
15
|
+
<div class="text-xs text-fg-2 p-2">{{ basic.length }} chars</div>
|
|
16
|
+
</template>
|
|
17
|
+
</Variant>
|
|
18
|
+
<Variant title="Auto Grow (empty)">
|
|
19
|
+
<Textarea v-model="growing" auto-grow placeholder="Start typing, I grow..." />
|
|
20
|
+
</Variant>
|
|
21
|
+
<Variant title="Auto Grow (prefilled)">
|
|
22
|
+
<Textarea v-model="prefilled" auto-grow />
|
|
23
|
+
</Variant>
|
|
24
|
+
<Variant title="Fixed Rows">
|
|
25
|
+
<Textarea v-model="basic" :rows="6" placeholder="6 rows tall..." />
|
|
26
|
+
</Variant>
|
|
27
|
+
</Story>
|
|
28
|
+
</template>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { toast } from "../src/composables/toast.js"
|
|
3
|
+
import ToastContainer from "../src/components/ToastContainer.vue"
|
|
4
|
+
import Button from "../src/components/Button.vue"
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<Story title="Toast">
|
|
9
|
+
<Variant title="All Variants">
|
|
10
|
+
<ToastContainer />
|
|
11
|
+
<div class="flex flex-wrap gap-2">
|
|
12
|
+
<Button @click="toast('Something happened')">Neutral</Button>
|
|
13
|
+
<Button variant="primary" @click="toast.success('Changes saved')">Success</Button>
|
|
14
|
+
<Button @click="toast.warning('Careful with that')">Warning</Button>
|
|
15
|
+
<Button variant="danger" @click="toast.error('Something broke')">Error</Button>
|
|
16
|
+
<Button variant="outline" @click="toast.info('New version available')">Info</Button>
|
|
17
|
+
</div>
|
|
18
|
+
</Variant>
|
|
19
|
+
<Variant title="Long Duration">
|
|
20
|
+
<ToastContainer />
|
|
21
|
+
<Button @click="toast('This stays for 10 seconds', { duration: 10000 })">Long Toast</Button>
|
|
22
|
+
</Variant>
|
|
23
|
+
<Variant title="Persistent">
|
|
24
|
+
<ToastContainer />
|
|
25
|
+
<Button @click="toast.error('Connection lost. Click X to dismiss.', { duration: 0 })">Persistent</Button>
|
|
26
|
+
</Variant>
|
|
27
|
+
</Story>
|
|
28
|
+
</template>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import { logEvent } from "histoire/client"
|
|
4
|
+
import ToggleButtons from "../src/components/ToggleButtons.vue"
|
|
5
|
+
|
|
6
|
+
const axes = ref(["x", "y"])
|
|
7
|
+
const formats = ref(["bold"])
|
|
8
|
+
const layers = ref([])
|
|
9
|
+
|
|
10
|
+
function handleUpdate(name, value) {
|
|
11
|
+
logEvent("update:modelValue", { name, value })
|
|
12
|
+
}
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<Story title="ToggleButtons">
|
|
17
|
+
<Variant title="Axes (with label)">
|
|
18
|
+
<ToggleButtons
|
|
19
|
+
v-model="axes"
|
|
20
|
+
label="Axes"
|
|
21
|
+
:options="['X', 'Y', 'Z']"
|
|
22
|
+
@update:model-value="v => handleUpdate('axes', v)"
|
|
23
|
+
/>
|
|
24
|
+
<template #controls>
|
|
25
|
+
<div class="text-xs text-fg-2 p-2">selected: {{ axes.join(', ') || 'none' }}</div>
|
|
26
|
+
</template>
|
|
27
|
+
</Variant>
|
|
28
|
+
<Variant title="Text Formatting">
|
|
29
|
+
<ToggleButtons
|
|
30
|
+
v-model="formats"
|
|
31
|
+
:options="[
|
|
32
|
+
{ value: 'bold', icon: 'material-symbols:format-bold' },
|
|
33
|
+
{ value: 'italic', icon: 'material-symbols:format-italic' },
|
|
34
|
+
{ value: 'underline', icon: 'material-symbols:format-underlined' },
|
|
35
|
+
{ value: 'strike', icon: 'material-symbols:strikethrough-s' }
|
|
36
|
+
]"
|
|
37
|
+
@update:model-value="v => handleUpdate('formats', v)"
|
|
38
|
+
/>
|
|
39
|
+
<template #controls>
|
|
40
|
+
<div class="text-xs text-fg-2 p-2">selected: {{ formats.join(', ') || 'none' }}</div>
|
|
41
|
+
</template>
|
|
42
|
+
</Variant>
|
|
43
|
+
<Variant title="Layers (none selected)">
|
|
44
|
+
<ToggleButtons
|
|
45
|
+
v-model="layers"
|
|
46
|
+
label="Layers"
|
|
47
|
+
:options="[
|
|
48
|
+
{ value: 'bg', label: 'BG' },
|
|
49
|
+
{ value: 'fg', label: 'FG' },
|
|
50
|
+
{ value: 'ui', label: 'UI' },
|
|
51
|
+
{ value: 'fx', label: 'FX' }
|
|
52
|
+
]"
|
|
53
|
+
@update:model-value="v => handleUpdate('layers', v)"
|
|
54
|
+
/>
|
|
55
|
+
</Variant>
|
|
56
|
+
</Story>
|
|
57
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import ToggleGroup from "../src/components/ToggleGroup.vue"
|
|
4
|
+
|
|
5
|
+
const view = ref("grid")
|
|
6
|
+
const align = ref("left")
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<Story title="ToggleGroup">
|
|
11
|
+
<Variant title="View Switcher">
|
|
12
|
+
<ToggleGroup
|
|
13
|
+
v-model="view"
|
|
14
|
+
:options="[
|
|
15
|
+
{ value: 'grid', icon: 'material-symbols:grid-view' },
|
|
16
|
+
{ value: 'list', icon: 'material-symbols:view-list' }
|
|
17
|
+
]"
|
|
18
|
+
/>
|
|
19
|
+
<template #controls>
|
|
20
|
+
<div class="text-xs text-fg-2 p-2">view: {{ view }}</div>
|
|
21
|
+
</template>
|
|
22
|
+
</Variant>
|
|
23
|
+
<Variant title="Text Alignment">
|
|
24
|
+
<ToggleGroup
|
|
25
|
+
v-model="align"
|
|
26
|
+
:options="[
|
|
27
|
+
{ value: 'left', icon: 'material-symbols:format-align-left' },
|
|
28
|
+
{ value: 'center', icon: 'material-symbols:format-align-center' },
|
|
29
|
+
{ value: 'right', icon: 'material-symbols:format-align-right' }
|
|
30
|
+
]"
|
|
31
|
+
/>
|
|
32
|
+
</Variant>
|
|
33
|
+
</Story>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { Icon } from "@iconify/vue"
|
|
3
|
+
import Tooltip from "../src/components/Tooltip.vue"
|
|
4
|
+
import Button from "../src/components/Button.vue"
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<Story title="Tooltip">
|
|
9
|
+
<Variant title="Basic">
|
|
10
|
+
<div class="flex items-center gap-4 p-8">
|
|
11
|
+
<Tooltip text="Edit this item">
|
|
12
|
+
<Button variant="icon"><Icon icon="material-symbols:edit-outline" class="text-base" /></Button>
|
|
13
|
+
</Tooltip>
|
|
14
|
+
<Tooltip text="Delete permanently">
|
|
15
|
+
<Button variant="icon"><Icon icon="material-symbols:delete-outline" class="text-base" /></Button>
|
|
16
|
+
</Tooltip>
|
|
17
|
+
<Tooltip text="Copy to clipboard">
|
|
18
|
+
<Button variant="icon"><Icon icon="material-symbols:content-copy" class="text-base" /></Button>
|
|
19
|
+
</Tooltip>
|
|
20
|
+
</div>
|
|
21
|
+
</Variant>
|
|
22
|
+
<Variant title="Placements">
|
|
23
|
+
<div class="flex items-center justify-center gap-6 p-16">
|
|
24
|
+
<Tooltip text="Top (default)" placement="top">
|
|
25
|
+
<Button>Top</Button>
|
|
26
|
+
</Tooltip>
|
|
27
|
+
<Tooltip text="Bottom tooltip" placement="bottom">
|
|
28
|
+
<Button>Bottom</Button>
|
|
29
|
+
</Tooltip>
|
|
30
|
+
<Tooltip text="Left tooltip" placement="left">
|
|
31
|
+
<Button>Left</Button>
|
|
32
|
+
</Tooltip>
|
|
33
|
+
<Tooltip text="Right tooltip" placement="right">
|
|
34
|
+
<Button>Right</Button>
|
|
35
|
+
</Tooltip>
|
|
36
|
+
</div>
|
|
37
|
+
</Variant>
|
|
38
|
+
<Variant title="No Delay">
|
|
39
|
+
<div class="p-8">
|
|
40
|
+
<Tooltip text="Instant tooltip" :delay="0">
|
|
41
|
+
<Button>Hover me (no delay)</Button>
|
|
42
|
+
</Tooltip>
|
|
43
|
+
</div>
|
|
44
|
+
</Variant>
|
|
45
|
+
<Variant title="On Text">
|
|
46
|
+
<div class="p-8 flex items-center gap-1">
|
|
47
|
+
<span class="text-base text-fg-1">Hover the</span>
|
|
48
|
+
<Tooltip text="This is an explanation">
|
|
49
|
+
<span class="text-base text-accent cursor-default underline decoration-dotted underline-offset-2">underlined text</span>
|
|
50
|
+
</Tooltip>
|
|
51
|
+
<span class="text-base text-fg-1">for more info</span>
|
|
52
|
+
</div>
|
|
53
|
+
</Variant>
|
|
54
|
+
</Story>
|
|
55
|
+
</template>
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from "vue"
|
|
3
|
+
import Tree from "../src/components/Tree.vue"
|
|
4
|
+
|
|
5
|
+
const selected = ref(null)
|
|
6
|
+
const filterSelected = ref(null)
|
|
7
|
+
|
|
8
|
+
const fileTree = [
|
|
9
|
+
{
|
|
10
|
+
key: "src",
|
|
11
|
+
label: "src",
|
|
12
|
+
icon: "material-symbols:folder-outline",
|
|
13
|
+
children: [
|
|
14
|
+
{
|
|
15
|
+
key: "src/components",
|
|
16
|
+
label: "components",
|
|
17
|
+
icon: "material-symbols:folder-outline",
|
|
18
|
+
children: [
|
|
19
|
+
{ key: "src/components/Button.vue", label: "Button.vue", icon: "material-symbols:description-outline" },
|
|
20
|
+
{ key: "src/components/Input.vue", label: "Input.vue", icon: "material-symbols:description-outline" },
|
|
21
|
+
{ key: "src/components/Select.vue", label: "Select.vue", icon: "material-symbols:description-outline" },
|
|
22
|
+
{ key: "src/components/Modal.vue", label: "Modal.vue", icon: "material-symbols:description-outline" }
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
key: "src/composables",
|
|
27
|
+
label: "composables",
|
|
28
|
+
icon: "material-symbols:folder-outline",
|
|
29
|
+
children: [
|
|
30
|
+
{ key: "src/composables/useClickOutside.js", label: "useClickOutside.js", icon: "material-symbols:description-outline" },
|
|
31
|
+
{ key: "src/composables/usePointerDrag.js", label: "usePointerDrag.js", icon: "material-symbols:description-outline" }
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{ key: "src/index.js", label: "index.js", icon: "material-symbols:description-outline" },
|
|
35
|
+
{ key: "src/style.css", label: "style.css", icon: "material-symbols:description-outline" }
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
key: "stories",
|
|
40
|
+
label: "stories",
|
|
41
|
+
icon: "material-symbols:folder-outline",
|
|
42
|
+
children: [
|
|
43
|
+
{ key: "stories/Button.story.vue", label: "Button.story.vue", icon: "material-symbols:description-outline" },
|
|
44
|
+
{ key: "stories/Input.story.vue", label: "Input.story.vue", icon: "material-symbols:description-outline" },
|
|
45
|
+
{ key: "stories/Overview.story.vue", label: "Overview.story.vue", icon: "material-symbols:description-outline" }
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
{ key: "package.json", label: "package.json", icon: "material-symbols:settings-outline" },
|
|
49
|
+
{ key: "tailwind.config.js", label: "tailwind.config.js", icon: "material-symbols:settings-outline" },
|
|
50
|
+
{ key: "README.md", label: "README.md", icon: "material-symbols:description-outline" }
|
|
51
|
+
]
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<template>
|
|
55
|
+
<Story title="Tree">
|
|
56
|
+
<Variant title="Basic">
|
|
57
|
+
<div class="w-64 h-80 border border-line rounded-sm overflow-hidden">
|
|
58
|
+
<Tree
|
|
59
|
+
v-model="selected"
|
|
60
|
+
:items="fileTree"
|
|
61
|
+
:default-expanded="['src', 'src/components']"
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
<template #controls>
|
|
65
|
+
<div class="text-xs text-fg-2 p-2">selected: {{ selected ?? 'null' }}</div>
|
|
66
|
+
</template>
|
|
67
|
+
</Variant>
|
|
68
|
+
<Variant title="All Expanded">
|
|
69
|
+
<div class="w-64 h-80 border border-line rounded-sm overflow-hidden">
|
|
70
|
+
<Tree
|
|
71
|
+
v-model="selected"
|
|
72
|
+
:items="fileTree"
|
|
73
|
+
:default-expanded="true"
|
|
74
|
+
/>
|
|
75
|
+
</div>
|
|
76
|
+
</Variant>
|
|
77
|
+
<Variant title="With Filter">
|
|
78
|
+
<div class="w-64 h-80 border border-line rounded-sm overflow-hidden">
|
|
79
|
+
<Tree
|
|
80
|
+
v-model="filterSelected"
|
|
81
|
+
:items="fileTree"
|
|
82
|
+
filterable
|
|
83
|
+
filter-placeholder="find file..."
|
|
84
|
+
:default-expanded="['src']"
|
|
85
|
+
/>
|
|
86
|
+
</div>
|
|
87
|
+
<template #controls>
|
|
88
|
+
<div class="text-xs text-fg-2 p-2">selected: {{ filterSelected ?? 'null' }}</div>
|
|
89
|
+
</template>
|
|
90
|
+
</Variant>
|
|
91
|
+
<Variant title="No Icons">
|
|
92
|
+
<div class="w-64 h-80 border border-line rounded-sm overflow-hidden">
|
|
93
|
+
<Tree
|
|
94
|
+
v-model="selected"
|
|
95
|
+
:items="[
|
|
96
|
+
{ key: 'a', label: 'Animals', children: [
|
|
97
|
+
{ key: 'a1', label: 'Cat' },
|
|
98
|
+
{ key: 'a2', label: 'Dog' },
|
|
99
|
+
{ key: 'a3', label: 'Fish', children: [
|
|
100
|
+
{ key: 'a3a', label: 'Goldfish' },
|
|
101
|
+
{ key: 'a3b', label: 'Salmon' }
|
|
102
|
+
]}
|
|
103
|
+
]},
|
|
104
|
+
{ key: 'b', label: 'Plants', children: [
|
|
105
|
+
{ key: 'b1', label: 'Oak' },
|
|
106
|
+
{ key: 'b2', label: 'Pine' }
|
|
107
|
+
]},
|
|
108
|
+
{ key: 'c', label: 'Minerals' }
|
|
109
|
+
]"
|
|
110
|
+
:default-expanded="['a']"
|
|
111
|
+
/>
|
|
112
|
+
</div>
|
|
113
|
+
</Variant>
|
|
114
|
+
</Story>
|
|
115
|
+
</template>
|