@luna-park/design 1.0.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.
Files changed (130) hide show
  1. package/eslint.config.js +9 -0
  2. package/histoire.config.ts +60 -0
  3. package/package.json +71 -0
  4. package/public/favicon_rc.png +0 -0
  5. package/src/app.ts +9 -0
  6. package/src/assets/controls/mouse.svg +54 -0
  7. package/src/assets/logo_neon.svg +18 -0
  8. package/src/assets/logo_rc_color.svg +54 -0
  9. package/src/assets/logo_rc_square_blue.svg +16 -0
  10. package/src/assets/logo_square_blue.svg +17 -0
  11. package/src/assets/logo_square_white.svg +17 -0
  12. package/src/assets/logo_text_white.svg +32 -0
  13. package/src/assets/stars.svg +66 -0
  14. package/src/components/breadcrumb/LBreadLink.vue +40 -0
  15. package/src/components/breadcrumb/LBreadcrumb.story.vue +29 -0
  16. package/src/components/breadcrumb/LBreadcrumb.vue +54 -0
  17. package/src/components/breadcrumb/type.ts +6 -0
  18. package/src/components/context/LContextMenu.story.vue +73 -0
  19. package/src/components/context/LContextMenu.vue +24 -0
  20. package/src/components/context/LContextMenuElement.vue +54 -0
  21. package/src/components/context/LContextMenuWrapper.vue +55 -0
  22. package/src/components/context/LContextOption.story.vue +18 -0
  23. package/src/components/context/LContextOption.vue +160 -0
  24. package/src/components/context/LContextWrapper.story.vue +11 -0
  25. package/src/components/context/LContextWrapper.vue +60 -0
  26. package/src/components/context/store.ts +62 -0
  27. package/src/components/context/type.ts +27 -0
  28. package/src/components/dialog/LDialogAlert.vue +38 -0
  29. package/src/components/dialog/LDialogConfirm.vue +45 -0
  30. package/src/components/dialog/LDialogInjector.story.vue +41 -0
  31. package/src/components/dialog/LDialogInjector.vue +40 -0
  32. package/src/components/dialog/LDialogPrompt.vue +67 -0
  33. package/src/components/dialog/LDialogWrapper.vue +66 -0
  34. package/src/components/dialog/lib.ts +50 -0
  35. package/src/components/dialog/store.ts +32 -0
  36. package/src/components/floating/LFloating.story.vue +35 -0
  37. package/src/components/floating/LFloating.vue +362 -0
  38. package/src/components/form/LAutoComplete.vue +13 -0
  39. package/src/components/form/LAutoInput.story.vue +43 -0
  40. package/src/components/form/LAutoInput.vue +101 -0
  41. package/src/components/form/LButton.story.vue +147 -0
  42. package/src/components/form/LButton.vue +227 -0
  43. package/src/components/form/LCheckbox.story.vue +13 -0
  44. package/src/components/form/LCheckbox.vue +70 -0
  45. package/src/components/form/LColorInput.story.vue +28 -0
  46. package/src/components/form/LColorInput.vue +101 -0
  47. package/src/components/form/LImageInput.story.vue +28 -0
  48. package/src/components/form/LImageInput.vue +75 -0
  49. package/src/components/form/LInfo.story.vue +22 -0
  50. package/src/components/form/LInfo.vue +44 -0
  51. package/src/components/form/LInput.story.vue +150 -0
  52. package/src/components/form/LInput.vue +493 -0
  53. package/src/components/form/LInputDateFloating.vue +61 -0
  54. package/src/components/form/LInputNumber.story.vue +58 -0
  55. package/src/components/form/LProgress.story.vue +49 -0
  56. package/src/components/form/LProgress.vue +77 -0
  57. package/src/components/form/LSelect.story.vue +67 -0
  58. package/src/components/form/LSelect.vue +142 -0
  59. package/src/components/form/LSwitch.story.vue +15 -0
  60. package/src/components/form/LSwitch.vue +79 -0
  61. package/src/components/form/LTextarea.story.vue +29 -0
  62. package/src/components/form/LTextarea.vue +151 -0
  63. package/src/components/form/color-picker/LColorAlpha.vue +129 -0
  64. package/src/components/form/color-picker/LColorHue.vue +109 -0
  65. package/src/components/form/color-picker/LColorModels.vue +223 -0
  66. package/src/components/form/color-picker/LColorPicker.story.vue +44 -0
  67. package/src/components/form/color-picker/LColorPicker.vue +105 -0
  68. package/src/components/form/color-picker/LColorShade.vue +114 -0
  69. package/src/components/form/color-picker/LImagePicker.vue +477 -0
  70. package/src/components/form/dropdown/LDropdown.story.vue +123 -0
  71. package/src/components/form/dropdown/LDropdown.vue +483 -0
  72. package/src/components/form/dropdown/LDropdownOption.vue +224 -0
  73. package/src/components/form/dropdown/LDropdownSelection.vue +76 -0
  74. package/src/components/form/dropdown/types.ts +15 -0
  75. package/src/components/form/emoji-picker/LEmojiList.vue +54 -0
  76. package/src/components/form/emoji-picker/LEmojiListCategory.vue +92 -0
  77. package/src/components/form/emoji-picker/LEmojiPicker.story.vue +32 -0
  78. package/src/components/form/emoji-picker/LEmojiPicker.vue +55 -0
  79. package/src/components/form/emoji-picker/LEmojiSelect.story.vue +22 -0
  80. package/src/components/form/emoji-picker/LEmojiSelect.vue +51 -0
  81. package/src/components/form/icon-picker/LIconList.vue +100 -0
  82. package/src/components/form/icon-picker/LIconMaterial.vue +43 -0
  83. package/src/components/form/icon-picker/LIconPicker.story.vue +39 -0
  84. package/src/components/form/icon-picker/LIconPicker.vue +92 -0
  85. package/src/components/form/icon-picker/LIconSelect.story.vue +25 -0
  86. package/src/components/form/icon-picker/LIconSelect.vue +91 -0
  87. package/src/components/icons/LControls.story.vue +92 -0
  88. package/src/components/icons/LKeyIcon.vue +66 -0
  89. package/src/components/icons/LMouseIcon.vue +85 -0
  90. package/src/components/icons/LShortcut.story.vue +12 -0
  91. package/src/components/icons/LShortcut.vue +45 -0
  92. package/src/components/layout/LResizer.story.vue +89 -0
  93. package/src/components/layout/LResizer.vue +138 -0
  94. package/src/components/misc/LIcon.vue +34 -0
  95. package/src/components/misc/LLineLoader.story.vue +18 -0
  96. package/src/components/misc/LLineLoader.vue +52 -0
  97. package/src/components/misc/LLoading.story.vue +14 -0
  98. package/src/components/misc/LLoading.vue +28 -0
  99. package/src/components/misc/LStarsBackground.story.vue +16 -0
  100. package/src/components/misc/LStarsBackground.vue +121 -0
  101. package/src/components/navigation/LElementsPagination.vue +75 -0
  102. package/src/components/navigation/LPagination.story.vue +57 -0
  103. package/src/components/navigation/LPagination.vue +125 -0
  104. package/src/components/table/LCell.vue +37 -0
  105. package/src/components/table/LLine.vue +24 -0
  106. package/src/components/table/LTable.story.vue +35 -0
  107. package/src/components/table/LTable.vue +21 -0
  108. package/src/components/toasts/LContainer.story.vue +47 -0
  109. package/src/components/toasts/LContainer.vue +140 -0
  110. package/src/components/toasts/LToast.story.vue +47 -0
  111. package/src/components/toasts/LToast.vue +30 -0
  112. package/src/components/toasts/LToastInjector.vue +54 -0
  113. package/src/components/toasts/requests.ts +46 -0
  114. package/src/components/toasts/store.ts +45 -0
  115. package/src/components/utils/LVirtualElement.vue +36 -0
  116. package/src/components/utils/LVirtualScroller.story.vue +62 -0
  117. package/src/components/utils/LVirtualScroller.vue +105 -0
  118. package/src/components/utils/virtual.ts +6 -0
  119. package/src/env.d.ts +9 -0
  120. package/src/histoire.setup.ts +8 -0
  121. package/src/icons.ts +8 -0
  122. package/src/index.ts +58 -0
  123. package/src/style/colors.scss +152 -0
  124. package/src/style/fonts.scss +45 -0
  125. package/src/style/index.scss +64 -0
  126. package/src/style/layout.scss +3 -0
  127. package/src/style/lengths.scss +21 -0
  128. package/src/style/scrollbar.scss +27 -0
  129. package/tsconfig.json +34 -0
  130. package/vite.config.ts +68 -0
@@ -0,0 +1,76 @@
1
+ <template>
2
+ <ul
3
+ ref="options"
4
+ class="options"
5
+ :class="{'max-height': maxHeight, big}"
6
+ >
7
+ <template
8
+ v-for="option in options"
9
+ :key="option.id"
10
+ >
11
+ <LDropdownOption
12
+ :big="big"
13
+ :container="container"
14
+ :depth="depth"
15
+ :hover="hover"
16
+ :max-height="maxHeight"
17
+ :option="option"
18
+ :selected="selected"
19
+ @select="select"
20
+ />
21
+ </template>
22
+ <li
23
+ v-if="!options.length"
24
+ class="option disabled"
25
+ >
26
+ No options...
27
+ </li>
28
+ </ul>
29
+ </template>
30
+
31
+ <script setup lang="ts">
32
+ import { TOption } from "@/components/form/dropdown/types";
33
+ import { onMounted, useTemplateRef } from "vue";
34
+ import LDropdownOption from "@/components/form/dropdown/LDropdownOption.vue";
35
+
36
+ const props = withDefaults(defineProps<{
37
+ big?: boolean;
38
+ container?: string;
39
+ depth?: number;
40
+ hover: Array<string>;
41
+ maxHeight?: boolean;
42
+ options: Array<TOption>;
43
+ selected?: string | number
44
+ }>(), {
45
+ depth: 0
46
+ });
47
+
48
+ const emits = defineEmits<(e: "select", value: TOption) => void>();
49
+ const optionsTemplate = useTemplateRef("options");
50
+
51
+ onMounted(() => {
52
+ if (optionsTemplate.value) {
53
+ optionsTemplate.value.querySelector(".selected")?.scrollIntoView({ block: "center" });
54
+ }
55
+ });
56
+
57
+ async function select(option: TOption) {
58
+ emits("select", option);
59
+ }
60
+ </script>
61
+
62
+ <style scoped>
63
+ .options {
64
+ overflow: hidden;
65
+ font-size: 0.8rem;
66
+
67
+ &.big {
68
+ font-size: .9rem;
69
+ }
70
+
71
+ &.max-height {
72
+ max-height: 240px;
73
+ overflow-y: auto;
74
+ }
75
+ }
76
+ </style>
@@ -0,0 +1,15 @@
1
+ import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
2
+
3
+ export type TOptions = Array<string | number | TOption> | Record<string, string>;
4
+
5
+ export type TOption = {
6
+ action?: () => Promise<void> | void;
7
+ children?: Array<TOption>;
8
+ disabled?: boolean;
9
+ icon?: {
10
+ color?: string;
11
+ icon: IconDefinition | string;
12
+ };
13
+ id: string;
14
+ value: string;
15
+ };
@@ -0,0 +1,54 @@
1
+ <template>
2
+ <div class="emoji-list">
3
+ <LEmojiListCategory
4
+ v-if="filter"
5
+ :big="big"
6
+ :category="result"
7
+ @select="$emit('select', $event)"
8
+ />
9
+ <template v-else>
10
+ <LEmojiListCategory
11
+ v-for="category in emojiCategories"
12
+ :key="category.name"
13
+ :big="big"
14
+ :category="category"
15
+ @select="$emit('select', $event)"
16
+ />
17
+ </template>
18
+ </div>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import { computed } from "vue";
23
+ import { computedAsync } from "@vueuse/core";
24
+ import LEmojiListCategory from "@/components/form/emoji-picker/LEmojiListCategory.vue";
25
+
26
+ const props = defineProps<{
27
+ big?: boolean;
28
+ filter: string;
29
+ }>();
30
+
31
+ const emits = defineEmits<(e: "select", value: string) => void>();
32
+
33
+ const emojiCategories = computedAsync(async () => {
34
+ const { emojiCategories } = await import("symbol-db/emoji");
35
+ return emojiCategories;
36
+ }, {});
37
+
38
+ const allEmojis = computed(() => Object.values(emojiCategories.value).flatMap((category) => category.emojis));
39
+
40
+ const result = computed(() => ({
41
+ emojis: allEmojis.value.filter((emoji) => {
42
+ const searchWords = props.filter.split(" ");
43
+ return searchWords.every((searchWord) => emoji.search.includes(searchWord));
44
+ }).slice(0, 128)
45
+ }));
46
+ </script>
47
+
48
+ <style scoped>
49
+ .emoji-list {
50
+ display: flex;
51
+ flex-direction: column;
52
+ gap: var(--length-m);
53
+ }
54
+ </style>
@@ -0,0 +1,92 @@
1
+ <template>
2
+ <div
3
+ class="emoji-category"
4
+ :class="{big}"
5
+ >
6
+ <h2 v-if="category.name">
7
+ {{ category.name }}
8
+ </h2>
9
+ <div class="list">
10
+ <div
11
+ v-for="emoji in category.emojis"
12
+ :key="emoji.name"
13
+ class="emoji"
14
+ tabindex="0"
15
+ :title="emoji.name"
16
+ @click="$emit('select', emoji.emoji)"
17
+ @keydown.enter="$emit('select', emoji.emoji)"
18
+ >
19
+ {{ emoji.emoji }}
20
+ </div>
21
+ </div>
22
+ </div>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ import { TEmojiCategory } from "symbol-db/emoji";
27
+
28
+ const props = defineProps<{
29
+ big?: boolean;
30
+ category: TEmojiCategory;
31
+ }>();
32
+
33
+ const emits = defineEmits<(e: "select", value: string) => void>();
34
+
35
+ </script>
36
+
37
+ <style scoped>
38
+ .emoji-category {
39
+ display: flex;
40
+ flex-direction: column;
41
+ gap: var(--length-xxs);
42
+
43
+ h2 {
44
+ font-weight: 600;
45
+ font-size: 0.8rem;
46
+ padding: 0;
47
+ margin: 0;
48
+ }
49
+
50
+ &.big h2 {
51
+ font-size: 1.2rem;
52
+ color: var(--color-content-lite);
53
+ }
54
+
55
+ .list {
56
+ display: grid;
57
+ grid-template-columns: repeat(auto-fill, minmax(24px, 1fr));
58
+ font-size: 1rem;
59
+ grid-gap: var(--length-xxxs);
60
+
61
+ .emoji {
62
+ display: flex;
63
+ justify-content: center;
64
+ align-items: center;
65
+ cursor: pointer;
66
+ border-radius: var(--length-radius-m);
67
+ border: 2px solid transparent;
68
+ width: 24px;
69
+ height: 24px;
70
+ overflow: hidden;
71
+
72
+ &:hover {
73
+ background: var(--color-primary-dark);
74
+ }
75
+
76
+ &:focus {
77
+ border: 2px dashed var(--color-primary);
78
+ }
79
+ }
80
+ }
81
+
82
+ &.big .list {
83
+ grid-template-columns: repeat(auto-fill, minmax(32px, 1fr));
84
+ font-size: 1.5rem;
85
+
86
+ .emoji {
87
+ width: 32px;
88
+ height: 32px;
89
+ }
90
+ }
91
+ }
92
+ </style>
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <Story
3
+ :layout="{
4
+ type: 'grid',
5
+ width: '320',
6
+ }"
7
+ >
8
+ <Variant title="big">
9
+ <LEmojiPicker
10
+ v-model="emoji"
11
+ big
12
+ />
13
+ </Variant>
14
+ <Variant title="Small">
15
+ <LEmojiPicker
16
+ v-model="emoji"
17
+ small
18
+ />
19
+ </Variant>
20
+ </Story>
21
+ </template>
22
+
23
+ <script setup lang="ts">
24
+ import { ref } from "vue";
25
+ import LEmojiPicker from "@/components/form/emoji-picker/LEmojiPicker.vue";
26
+
27
+ const emoji = ref("");
28
+ </script>
29
+
30
+ <style scoped>
31
+
32
+ </style>
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <LFloating @show="focusSearch">
3
+ <LButton
4
+ :big="big"
5
+ class="button"
6
+ :class="{big}"
7
+ square
8
+ >
9
+ {{ modelValue }}
10
+ </LButton>
11
+ <template #popper>
12
+ <div class="popper-wrapper">
13
+ <LEmojiSelect
14
+ :big="big"
15
+ @select="$emit('update:modelValue', $event)"
16
+ />
17
+ </div>
18
+ </template>
19
+ </LFloating>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { nextTick } from "vue";
24
+ import LFloating from "@/components/floating/LFloating.vue";
25
+ import LEmojiSelect from "@/components/form/emoji-picker/LEmojiSelect.vue";
26
+ import LButton from "@/components/form/LButton.vue";
27
+
28
+ const props = defineProps<{
29
+ big?: boolean;
30
+ modelValue: string;
31
+ }>();
32
+
33
+ const emits = defineEmits<(e: "update:modelValue", value: string) => void>();
34
+
35
+ async function focusSearch() {
36
+ await nextTick();
37
+ const input = document.querySelector(".popper-wrapper input") as HTMLInputElement;
38
+ input?.focus();
39
+ }
40
+ </script>
41
+
42
+ <style scoped>
43
+ .button {
44
+ font-size: 1rem;
45
+
46
+ &.big {
47
+ font-size: 1.5rem;
48
+ }
49
+ }
50
+
51
+ .popper-wrapper {
52
+ padding: var(--length-s);
53
+ color: var(--color-content);
54
+ }
55
+ </style>
@@ -0,0 +1,22 @@
1
+ <template>
2
+ <Story
3
+ :layout="{
4
+ type: 'grid',
5
+ width: '320',
6
+ }"
7
+ >
8
+ <Variant title="big">
9
+ <LEmojiSelect big />
10
+ </Variant>
11
+ <Variant title="Small">
12
+ <LEmojiSelect />
13
+ </Variant>
14
+ </Story>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import LEmojiSelect from "@/components/form/emoji-picker/LEmojiSelect.vue";
19
+ </script>
20
+
21
+ <style scoped>
22
+ </style>
@@ -0,0 +1,51 @@
1
+ <template>
2
+ <div
3
+ class="emoji-select"
4
+ :class="{big}"
5
+ >
6
+ <LInput
7
+ v-model="filter"
8
+ :big="big"
9
+ placeholder="Search emoji..."
10
+ />
11
+ <LEmojiList
12
+ :big="big"
13
+ class="list"
14
+ :filter="filter"
15
+ @select="$emit('select', $event)"
16
+ />
17
+ </div>
18
+ </template>
19
+
20
+ <script setup lang="ts">
21
+ import { ref } from "vue";
22
+ import LInput from "@/components/form/LInput.vue";
23
+ import LEmojiList from "@/components/form/emoji-picker/LEmojiList.vue";
24
+
25
+ const filter = ref("");
26
+
27
+ const props = defineProps<{
28
+ big?: boolean;
29
+ }>();
30
+
31
+ const emits = defineEmits<(e: "select", value: string) => void>();
32
+ </script>
33
+
34
+ <style scoped>
35
+ .emoji-select {
36
+ display: flex;
37
+ flex-direction: column;
38
+ gap: var(--length-xs);
39
+
40
+ .list {
41
+ max-height: 200px;
42
+ overflow: auto;
43
+ }
44
+
45
+ &.big {
46
+ .list {
47
+ max-height: 280px;
48
+ }
49
+ }
50
+ }
51
+ </style>
@@ -0,0 +1,100 @@
1
+ <template>
2
+ <div
3
+ class="icon-list"
4
+ :class="{big}"
5
+ >
6
+ <div
7
+ v-for="icon in filteredIcons"
8
+ :key="icon.name"
9
+ class="icon-wrapper"
10
+ tabindex="0"
11
+ :title="icon.name"
12
+ @click="$emit('select', icon.name)"
13
+ @keydown.enter="$emit('select', icon.name)"
14
+ >
15
+ <LIconMaterial
16
+ class="icon"
17
+ :icon="icon.name"
18
+ />
19
+ </div>
20
+ </div>
21
+ </template>
22
+
23
+ <script setup lang="ts">
24
+ import { computedAsync } from "@vueuse/core";
25
+ import { computed } from "vue";
26
+
27
+ import LIconMaterial from "@/components/form/icon-picker/LIconMaterial.vue";
28
+
29
+ const props = withDefaults(defineProps<{
30
+ big?: boolean;
31
+ filter: string;
32
+ }>(), {
33
+ filter: ""
34
+ });
35
+
36
+ const emits = defineEmits<(e: "select", value: string) => void>();
37
+
38
+ const iconDb = computedAsync(async () => {
39
+ const { icons } = await import("symbol-db/material");
40
+ return icons;
41
+ }, []);
42
+
43
+ const filteredIcons = computed(() => {
44
+ return iconDb.value.filter((icon) => {
45
+ const searchWords = props.filter.split(" ");
46
+ return searchWords.every((searchWord) => icon.search.includes(searchWord));
47
+ }).slice(0, 128);
48
+ });
49
+ </script>
50
+
51
+ <style scoped>
52
+ .icon-list {
53
+ display: grid;
54
+ grid-template-columns: repeat(auto-fill, minmax(24px, 1fr));
55
+ grid-gap: var(--length-xxxs);
56
+
57
+ .icon-wrapper {
58
+ display: flex;
59
+ align-items: center;
60
+ justify-content: center;
61
+ padding: var(--length-xxxs);
62
+ border-radius: var(--length-radius-m);
63
+ cursor: pointer;
64
+ border: 2px solid transparent;
65
+ width: 24px;
66
+ height: 24px;
67
+ overflow: hidden;
68
+
69
+ .icon {
70
+ font-size: 16px;
71
+ width: 16px;
72
+ height: 16px;
73
+ }
74
+
75
+ &:focus {
76
+ border: 2px dashed var(--color-primary);
77
+ }
78
+
79
+ &:hover {
80
+ background-color: var(--color-primary-dark);
81
+ }
82
+ }
83
+
84
+ &.big {
85
+ grid-template-columns: repeat(auto-fill, minmax(32px, 1fr));
86
+ padding: var(--length-xxs);
87
+
88
+ .icon-wrapper{
89
+ width: 32px;
90
+ height: 32px;
91
+
92
+ .icon {
93
+ font-size: 24px;
94
+ width: 24px;
95
+ height: 24px;
96
+ }
97
+ }
98
+ }
99
+ }
100
+ </style>
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <span
3
+ class="icon"
4
+ :class="{spin}"
5
+ >
6
+ {{ icon }}
7
+ </span>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ const props = defineProps<{
12
+ icon: string;
13
+ spin?: boolean;
14
+ }>();
15
+ </script>
16
+
17
+ <style scoped>
18
+ @import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20,400,1,-25');
19
+
20
+ .icon {
21
+ font-family: 'Material Symbols Rounded', sans-serif;
22
+ text-rendering: optimizelegibility;
23
+ font-feature-settings: "liga";
24
+ user-select: none;
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+
29
+ &.spin {
30
+ animation: spin 2s linear infinite;
31
+ }
32
+ }
33
+
34
+ @keyframes spin {
35
+ 0% {
36
+ transform: rotate(0deg);
37
+ }
38
+
39
+ 100% {
40
+ transform: rotate(360deg);
41
+ }
42
+ }
43
+ </style>
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <Story
3
+ :layout="{
4
+ type: 'grid',
5
+ width: '320',
6
+ }"
7
+ >
8
+ <Variant title="big">
9
+ <LIconPicker
10
+ v-model="icon"
11
+ big
12
+ />
13
+ </Variant>
14
+ <Variant title="Small">
15
+ <LIconPicker
16
+ v-model="icon"
17
+ small
18
+ />
19
+ </Variant>
20
+ <Variant title="Small with-emoji">
21
+ <LIconPicker
22
+ v-model="icon"
23
+ small
24
+ with-emoji
25
+ />
26
+ </Variant>
27
+ </Story>
28
+ </template>
29
+
30
+ <script setup lang="ts">
31
+ import { ref } from "vue";
32
+ import LIconPicker from "@/components/form/icon-picker/LIconPicker.vue";
33
+
34
+ const icon = ref("");
35
+ </script>
36
+
37
+ <style scoped>
38
+
39
+ </style>
@@ -0,0 +1,92 @@
1
+ <template>
2
+ <LFloating @show="focusSearch">
3
+ <LButton
4
+ :big="big"
5
+ :borderless="borderless"
6
+ class="button"
7
+ :class="{big}"
8
+ :small="small"
9
+ square
10
+ :title="value"
11
+ >
12
+ <div class="icon-wrapper">
13
+ <LIconMaterial
14
+ class="icon"
15
+ :icon="value"
16
+ />
17
+ </div>
18
+ </LButton>
19
+ <template #popper>
20
+ <div class="popper-wrapper">
21
+ <LIconSelect
22
+ :big="big"
23
+ :with-emoji="withEmoji"
24
+ @select="value = $event"
25
+ />
26
+ </div>
27
+ </template>
28
+ </LFloating>
29
+ </template>
30
+
31
+ <script setup lang="ts">
32
+ import { nextTick } from "vue";
33
+ import LFloating from "@/components/floating/LFloating.vue";
34
+ import LButton from "@/components/form/LButton.vue";
35
+ import LIconSelect from "@/components/form/icon-picker/LIconSelect.vue";
36
+ import LIconMaterial from "@/components/form/icon-picker/LIconMaterial.vue";
37
+
38
+ const props = defineProps<{
39
+ big?: boolean;
40
+ borderless?: boolean;
41
+ small?: boolean;
42
+ withEmoji?: boolean;
43
+ }>();
44
+
45
+ const value = defineModel<string>({ default: "" });
46
+
47
+ async function focusSearch() {
48
+ await nextTick();
49
+ const input = document.querySelector(".popper-wrapper input") as HTMLInputElement;
50
+ input?.focus();
51
+ }
52
+ </script>
53
+
54
+ <style scoped>
55
+ .button {
56
+ .icon-wrapper {
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ .icon {
61
+ font-size: 1rem;
62
+ width: 1rem;
63
+ height: 1rem;
64
+ }
65
+ }
66
+
67
+ &.big {
68
+ .icon-wrapper {
69
+ .icon {
70
+ font-size: 1.5rem;
71
+ width: 1.5rem;
72
+ height: 1.5rem;
73
+ }
74
+ }
75
+ }
76
+
77
+ &.small {
78
+ .icon-wrapper {
79
+ .icon {
80
+ font-size: 0.8rem;
81
+ width: 0.8rem;
82
+ height: 0.8rem;
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ .popper-wrapper {
89
+ padding: var(--length-s);
90
+ color: var(--color-content);
91
+ }
92
+ </style>
@@ -0,0 +1,25 @@
1
+ <template>
2
+ <Story
3
+ :layout="{
4
+ type: 'grid',
5
+ width: '320',
6
+ }"
7
+ >
8
+ <Variant title="big">
9
+ <LIconSelect big />
10
+ </Variant>
11
+ <Variant title="Small">
12
+ <LIconSelect />
13
+ </Variant>
14
+ <Variant title="Small with emoji">
15
+ <LIconSelect with-emoji />
16
+ </Variant>
17
+ </Story>
18
+ </template>
19
+
20
+ <script setup lang="ts">
21
+ import LIconSelect from "@/components/form/icon-picker/LIconSelect.vue";
22
+ </script>
23
+
24
+ <style scoped>
25
+ </style>