@geckou/ui-vue 0.3.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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +253 -0
  3. package/dist/assets/scss/functions.scss +6 -0
  4. package/dist/assets/scss/mixin.scss +33 -0
  5. package/dist/components/ArticleList/Card/Artistic.vue +310 -0
  6. package/dist/components/ArticleList/Card/Entertainment.vue +244 -0
  7. package/dist/components/ArticleList/Card/Gallery.vue +254 -0
  8. package/dist/components/ArticleList/Card/Grid.vue +247 -0
  9. package/dist/components/ArticleList/Card/News.vue +150 -0
  10. package/dist/components/ArticleList/Card/Rounded.vue +154 -0
  11. package/dist/components/ArticleList/Card/Row.vue +167 -0
  12. package/dist/components/ArticleList/Card/Simple.vue +232 -0
  13. package/dist/components/ArticleList/Card/Standard.vue +187 -0
  14. package/dist/components/ArticleList/Card/Tile.vue +171 -0
  15. package/dist/components/ArticleList/GenericArticleList.vue +143 -0
  16. package/dist/components/ArticleList/List/Artistic.vue +24 -0
  17. package/dist/components/ArticleList/List/Entertainment.vue +24 -0
  18. package/dist/components/ArticleList/List/Gallery.vue +24 -0
  19. package/dist/components/ArticleList/List/Grid.vue +216 -0
  20. package/dist/components/ArticleList/List/News.vue +24 -0
  21. package/dist/components/ArticleList/List/Rounded.vue +24 -0
  22. package/dist/components/ArticleList/List/Row.vue +24 -0
  23. package/dist/components/ArticleList/List/Simple.vue +24 -0
  24. package/dist/components/ArticleList/List/Standard.vue +24 -0
  25. package/dist/components/ArticleList/List/Tile.vue +24 -0
  26. package/dist/components/ArticleList/Parts/AuthorInfo.vue +100 -0
  27. package/dist/components/ArticleList/Parts/CardContainer.vue +23 -0
  28. package/dist/components/ArticleList/Parts/CardHeading.vue +43 -0
  29. package/dist/components/ArticleList/Parts/CategoryList.vue +41 -0
  30. package/dist/components/ArticleList/Parts/ExcerptText.vue +43 -0
  31. package/dist/components/ArticleList/Parts/MetadataList.vue +120 -0
  32. package/dist/components/ArticleList/Parts/NoImage.vue +36 -0
  33. package/dist/components/ArticleList/Parts/PostedDate.vue +41 -0
  34. package/dist/components/ArticleList/Parts/TagList.vue +41 -0
  35. package/dist/components/ArticleList/Parts/ThumbnailImage.vue +85 -0
  36. package/dist/components/BasicButton.vue +143 -0
  37. package/dist/components/CheckBox.vue +140 -0
  38. package/dist/components/CheckBoxes.vue +100 -0
  39. package/dist/components/CheckButton.vue +127 -0
  40. package/dist/components/DatePicker.vue +234 -0
  41. package/dist/components/DateRangePicker.vue +85 -0
  42. package/dist/components/DateSelector.vue +273 -0
  43. package/dist/components/DropdownUi.vue +118 -0
  44. package/dist/components/ErrorMessage.vue +61 -0
  45. package/dist/components/Icon/CalendarIcon.vue +8 -0
  46. package/dist/components/Icon/CheckIcon.vue +8 -0
  47. package/dist/components/Icon/CloseIcon.vue +8 -0
  48. package/dist/components/Icon/Folder.vue +8 -0
  49. package/dist/components/Icon/Image.vue +14 -0
  50. package/dist/components/Icon/KeyboardArrowDownIcon.vue +8 -0
  51. package/dist/components/Icon/Tag.vue +8 -0
  52. package/dist/components/InputBox.vue +134 -0
  53. package/dist/components/InputGroup.vue +41 -0
  54. package/dist/components/LabeledCheckbox.vue +82 -0
  55. package/dist/components/LabeledFieldset.vue +41 -0
  56. package/dist/components/LoadingSpinner.vue +56 -0
  57. package/dist/components/ModalBox.vue +192 -0
  58. package/dist/components/PopupBox.vue +93 -0
  59. package/dist/components/RadioButtons.vue +163 -0
  60. package/dist/components/SelectBox.vue +166 -0
  61. package/dist/components/SlideDownUi.vue +123 -0
  62. package/dist/components/TabUI.vue +123 -0
  63. package/dist/components/TextArea.vue +115 -0
  64. package/dist/components/TextBox.vue +111 -0
  65. package/dist/components/TextButton.vue +47 -0
  66. package/dist/components/ToggleButton.vue +179 -0
  67. package/dist/const/index.ts +2 -0
  68. package/dist/const/list-theme.ts +62 -0
  69. package/dist/index.ts +126 -0
  70. package/dist/scripts/form-validation-manager.ts +63 -0
  71. package/dist/scripts/utils.ts +36 -0
  72. package/dist/types/custom.d.ts +1 -0
  73. package/dist/types/index.d.ts +93 -0
  74. package/dist/types/vue-shim.d.ts +5 -0
  75. package/package.json +44 -0
@@ -0,0 +1,143 @@
1
+ <script setup lang="ts">
2
+
3
+ import type {
4
+ Article,
5
+ Category,
6
+ ListSettings,
7
+ } from '../../types'
8
+ import { computed } from 'vue'
9
+ import { returnArticlePath, normalizePostConfig } from '../../scripts/utils'
10
+ import { LIST_THEME } from '../../const/list-theme'
11
+ import StandardCard from '../../components/ArticleList/Card/Standard.vue'
12
+ import RoundedCard from '../../components/ArticleList/Card/Rounded.vue'
13
+ import ArtisticCard from '../../components/ArticleList/Card/Artistic.vue'
14
+ import TileCard from '../../components/ArticleList/Card/Tile.vue'
15
+ import SimpleCard from '../../components/ArticleList/Card/Simple.vue'
16
+ import RowCard from '../../components/ArticleList/Card/Row.vue'
17
+ import NewsCard from '../../components/ArticleList/Card/News.vue'
18
+ import EntertainmentCard from '../../components/ArticleList/Card/Entertainment.vue'
19
+ import GalleryCard from '../../components/ArticleList/Card/Gallery.vue'
20
+
21
+ const props = defineProps<{
22
+ articles: Article[]
23
+ theme: keyof typeof LIST_THEME
24
+ categories: Category[]
25
+ columnNumber: number
26
+ settings: ListSettings
27
+ }>()
28
+
29
+ // settings は親から動的に差し替えられるため computed で参照する
30
+ const domainToUse = computed(() => props.settings.domainToUse)
31
+ const isEnabledPickUp = computed(() => props.settings.isEnabledPickUp)
32
+ const postConfig = computed(() => normalizePostConfig(props.settings.postConfig))
33
+
34
+ const listItem = computed(() => {
35
+ switch (props.theme) {
36
+ case 'standard':
37
+ return StandardCard
38
+ case 'rounded':
39
+ return RoundedCard
40
+ case 'artistic':
41
+ return ArtisticCard
42
+ case 'tile':
43
+ return TileCard
44
+ case 'simple':
45
+ return SimpleCard
46
+ case 'row':
47
+ return RowCard
48
+ case 'news':
49
+ return NewsCard
50
+ case 'gallery':
51
+ return GalleryCard
52
+ case 'entertainment':
53
+ return EntertainmentCard
54
+ default:
55
+ return StandardCard
56
+ }
57
+ })
58
+ </script>
59
+
60
+ <template>
61
+ <ul
62
+ :style="{
63
+ ['--column-number']: columnNumber,
64
+ ['--tablet-column-number']: columnNumber - 1 ? columnNumber - 1 : 1,
65
+ }"
66
+ :class="[$style.list, {[$style.pickup]: isEnabledPickUp}]"
67
+ >
68
+ <li
69
+ v-for="(article, index) in articles"
70
+ :key="article.id"
71
+ :style="{animationDelay: `${Number(index) * .1}s`}"
72
+ >
73
+ <component
74
+ :is="listItem"
75
+ :path="returnArticlePath(postConfig, domainToUse, article.id)"
76
+ :article="article"
77
+ :isPickUpItem="Number(index) === 0 && isEnabledPickUp"
78
+ :postConfig="postConfig"
79
+ :categories="categories"
80
+ />
81
+ </li>
82
+ </ul>
83
+ </template>
84
+
85
+ <style lang="scss" module>
86
+ @use '../../assets/scss/mixin' as *;
87
+
88
+ .list {
89
+ --list-gap : var(--sp-large);
90
+ display : grid;
91
+ grid-template-rows: 1fr;
92
+ gap : var(--list-gap);
93
+ width : 100%;
94
+
95
+ @keyframes fadeIn {
96
+ from {
97
+ opacity: 0;
98
+ }
99
+
100
+ to {
101
+ opacity: 1;
102
+ }
103
+ }
104
+
105
+ @include media('mobile') {
106
+ grid-template-columns : repeat(auto-fit, 100%);
107
+ }
108
+
109
+ @include media('tablet') {
110
+ grid-template-columns : repeat(auto-fit, calc((100% - var(--list-gap) * (var(--tablet-column-number) - 1)) / var(--tablet-column-number)));
111
+ }
112
+
113
+ @include media('desktop') {
114
+ grid-template-columns : repeat(auto-fit, calc((100% - var(--list-gap) * (var(--column-number) - 1)) / var(--column-number)));
115
+ }
116
+
117
+ > li {
118
+ opacity : 0;
119
+ animation-name : fadeIn;
120
+ animation-duration : 1s;
121
+ animation-timing-function: ease-out;
122
+ animation-fill-mode : forwards;
123
+ }
124
+
125
+ &.pickup {
126
+ > li {
127
+ &:first-child {
128
+ @include media('mobile') {
129
+ grid-column: 1;
130
+ }
131
+
132
+ @include media('tablet') {
133
+ grid-column: span var(--tablet-column-number);
134
+ }
135
+
136
+ @include media('desktop') {
137
+ grid-column: span var(--column-number);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
143
+ </style>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ Article,
4
+ Category,
5
+ ListSettings,
6
+ } from '../../../types'
7
+ import GenericArticleList from '../../../components/ArticleList/GenericArticleList.vue'
8
+
9
+ defineProps<{
10
+ articles: Article[]
11
+ categories: Category[]
12
+ settings: ListSettings
13
+ }>()
14
+ </script>
15
+
16
+ <template>
17
+ <GenericArticleList
18
+ theme="artistic"
19
+ :columnNumber="3"
20
+ :articles="articles"
21
+ :categories="categories"
22
+ :settings="settings"
23
+ />
24
+ </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ Article,
4
+ Category,
5
+ ListSettings,
6
+ } from '../../../types'
7
+ import GenericArticleList from '../../../components/ArticleList/GenericArticleList.vue'
8
+
9
+ defineProps<{
10
+ articles: Article[]
11
+ categories: Category[]
12
+ settings: ListSettings
13
+ }>()
14
+ </script>
15
+
16
+ <template>
17
+ <GenericArticleList
18
+ theme="entertainment"
19
+ :columnNumber="3"
20
+ :articles="articles"
21
+ :categories="categories"
22
+ :settings="settings"
23
+ />
24
+ </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ Article,
4
+ Category,
5
+ ListSettings,
6
+ } from '../../../types'
7
+ import GenericArticleList from '../../../components/ArticleList/GenericArticleList.vue'
8
+
9
+ defineProps<{
10
+ articles: Article[]
11
+ categories: Category[]
12
+ settings: ListSettings
13
+ }>()
14
+ </script>
15
+
16
+ <template>
17
+ <GenericArticleList
18
+ theme="gallery"
19
+ :columnNumber="3"
20
+ :articles="articles"
21
+ :categories="categories"
22
+ :settings="settings"
23
+ />
24
+ </template>
@@ -0,0 +1,216 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ Article,
4
+ Category,
5
+ ListSettings,
6
+ } from '../../../types'
7
+ import { ref, computed, onMounted, onUnmounted } from 'vue'
8
+ import { returnArticlePath, normalizePostConfig } from '../../../scripts/utils'
9
+ import GridCard from '../../../components/ArticleList/Card/Grid.vue'
10
+
11
+ const props = defineProps<{
12
+ articles: Article[]
13
+ categories: Category[]
14
+ columnNumber: number
15
+ settings: ListSettings
16
+ }>()
17
+
18
+ // settings は親から動的に差し替えられるため computed で参照する
19
+ const domainToUse = computed(() => props.settings.domainToUse)
20
+ const isEnabledPickUp = computed(() => props.settings.isEnabledPickUp)
21
+ const postConfig = computed(() => normalizePostConfig(props.settings.postConfig))
22
+
23
+ const listElement = ref<HTMLElement | null>(null)
24
+ const listWidth = ref(0)
25
+ const resizeTimeout = ref<number | null>(null)
26
+
27
+ const deviceColumnNumber = computed(() => {
28
+ if (listWidth.value > 992) return props.columnNumber
29
+ else if (listWidth.value >= 576 && listWidth.value <= 992) return props.columnNumber - 1
30
+ else return 1
31
+ })
32
+
33
+ const returnRowNumber = (index: number): number => {
34
+ const itemNum = index + 1
35
+ const actualColumnNumber = Number(deviceColumnNumber.value) - 1
36
+ return Math.ceil(itemNum / actualColumnNumber)
37
+ }
38
+
39
+ const returnColumnNumber = (index: number): number => {
40
+ const itemNum = index + 1
41
+ const columns = Number(deviceColumnNumber.value)
42
+ if (itemNum < columns) return itemNum
43
+ if (columns === 1) return 1
44
+ const remainder = itemNum % (columns - 1)
45
+ return remainder === 0 ? columns - 1 : remainder
46
+ }
47
+
48
+ const calcGridRowValue = (index: number): string | undefined => {
49
+ if (deviceColumnNumber.value === 4) {
50
+ const rowNum = returnRowNumber(index)
51
+ const actualRowNumber = Array.from({ length: 49 }, (_, i) => i + 1)
52
+ .find(n => rowNum <= n * 2) || 0
53
+ const adjustedRowNum = rowNum - 1 + actualRowNumber
54
+
55
+ return returnItemDirection(index) === 'vertical'
56
+ ? `${Number(adjustedRowNum)}/${Number(adjustedRowNum) + 2}`
57
+ : rowNum % 2
58
+ ? `${Number(adjustedRowNum)}/${Number(adjustedRowNum) + 1}`
59
+ : `${Number(adjustedRowNum) + 1}/${Number(adjustedRowNum) + 2}`
60
+ } else if (deviceColumnNumber.value === 3) {
61
+ const itemNum = index + 1
62
+ const division = itemNum % 3
63
+ const count = Math.floor(itemNum / 3)
64
+ const actualRowNumber = division ? count * 2 + 1 : count * 2
65
+
66
+ return returnItemDirection(index) === 'horizontal'
67
+ ? `${Number(actualRowNumber)}/${Number(actualRowNumber) + 1}`
68
+ : `${Number(actualRowNumber)}/${Number(actualRowNumber) + 2}`
69
+ }
70
+ }
71
+
72
+ const calcGridColumnValue = (index: number): string => {
73
+ const division = (index + 1) % 6
74
+
75
+ const columns = Number(deviceColumnNumber.value)
76
+
77
+ if (columns === 4) {
78
+ const colNum = returnColumnNumber(index)
79
+ switch (true) {
80
+ case !index || division === 1:
81
+ return '1/3'
82
+ case !division:
83
+ return '3/5'
84
+ default:
85
+ return returnRowNumber(index) % 2
86
+ ? `${colNum + 1}/${colNum + 2}`
87
+ : `${colNum}/${colNum + 1}`
88
+ }
89
+ } else if (columns === 3) {
90
+ const endCount = returnItemDirection(index) === 'horizontal' ? 2 : 1
91
+ switch (division) {
92
+ case 1:
93
+ case 3:
94
+ case 4:
95
+ return `1/${1 + endCount}`
96
+ case 5:
97
+ case 0:
98
+ return `2/${2 + endCount}`
99
+ case 2:
100
+ return `3/${3 + endCount}`
101
+ default:
102
+ return ''
103
+ }
104
+ }
105
+
106
+ return ''
107
+ }
108
+
109
+ const returnItemDirection = (index: number): 'horizontal' | 'vertical' => {
110
+ if (deviceColumnNumber.value === 1) {
111
+ return 'vertical'
112
+ } else if (deviceColumnNumber.value === 3) {
113
+ const itemNum = index + 1
114
+ const division = itemNum % 6
115
+ return division !== 2 && division !== 4 ? 'horizontal' : 'vertical'
116
+ } else {
117
+ const gridValue = calcGridColumnValue(index)
118
+ if (!gridValue.includes('/')) return 'horizontal'
119
+ const values = gridValue.split('/').map(Number)
120
+ return values[1] - values[0] >= 2 ? 'horizontal' : 'vertical'
121
+ }
122
+ }
123
+
124
+ onMounted(() => {
125
+ const resizeObserver = new ResizeObserver(entries => {
126
+ if (resizeTimeout.value) clearTimeout(resizeTimeout.value)
127
+ resizeTimeout.value = setTimeout(() => {
128
+ listWidth.value = entries[0].contentRect.width
129
+ }, 100) as unknown as number
130
+ })
131
+
132
+ if (listElement.value) resizeObserver.observe(listElement.value)
133
+
134
+ onUnmounted(() => {
135
+ if (listElement.value) resizeObserver.unobserve(listElement.value)
136
+ resizeObserver.disconnect()
137
+ if (resizeTimeout.value) clearTimeout(resizeTimeout.value)
138
+ })
139
+ })
140
+ </script>
141
+
142
+ <template>
143
+ <ul
144
+ ref="listElement"
145
+ :style="{
146
+ ['--column-number']: columnNumber,
147
+ ['--tablet-column-number']: columnNumber - 1 ? columnNumber - 1 : 1,
148
+ }"
149
+ :class="$style.list"
150
+ >
151
+ <li
152
+ v-for="(article, index) in articles"
153
+ :key="article.id"
154
+ :class="$style.item"
155
+ :style="{
156
+ animationDelay: `${Number(index) * .1}s`,
157
+ gridRow: calcGridRowValue(Number(index)) || 'auto',
158
+ gridColumn: calcGridColumnValue(Number(index)) || 'auto',
159
+ }"
160
+ >
161
+ <GridCard
162
+ :path="returnArticlePath(postConfig, domainToUse, article.id)"
163
+ :article="article"
164
+ :isPickUpItem="Number(index) === 0 && isEnabledPickUp"
165
+ :postConfig="postConfig"
166
+ :categories="categories"
167
+ :direction="returnItemDirection(Number(index))"
168
+ />
169
+ </li>
170
+ </ul>
171
+ </template>
172
+
173
+ <style lang="scss" module>
174
+ @use '../../../assets/scss/mixin' as *;
175
+
176
+ .list {
177
+ --list-gap : var(--sp-medium);
178
+ display : grid;
179
+ gap : var(--list-gap);
180
+ grid-template-rows: 1fr;
181
+ width : 100%;
182
+ list-style : none;
183
+ grid-auto-flow : dense;
184
+
185
+ @keyframes fadeIn {
186
+ from {
187
+ opacity: 0;
188
+ }
189
+
190
+ to {
191
+ opacity: 1;
192
+ }
193
+ }
194
+
195
+ @include media('mobile') {
196
+ display : flex;
197
+ flex-direction: column;
198
+ gap : var(--sp-large);
199
+ }
200
+
201
+ @include media('tablet') {
202
+ grid-template-columns : repeat(auto-fit, calc((100% - var(--list-gap) * (var(--tablet-column-number) - 1)) / var(--tablet-column-number)));
203
+ }
204
+
205
+ @include media('desktop') {
206
+ grid-template-columns : repeat(auto-fit, calc((100% - var(--list-gap) * (var(--column-number) - 1)) / var(--column-number)));
207
+ }
208
+
209
+ > li {
210
+ animation-name : fadeIn;
211
+ animation-duration : 1s;
212
+ animation-timing-function: ease-out;
213
+ animation-fill-mode : backwards;
214
+ }
215
+ }
216
+ </style>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ Article,
4
+ Category,
5
+ ListSettings,
6
+ } from '../../../types'
7
+ import GenericArticleList from '../../../components/ArticleList/GenericArticleList.vue'
8
+
9
+ defineProps<{
10
+ articles: Article[]
11
+ categories: Category[]
12
+ settings: ListSettings
13
+ }>()
14
+ </script>
15
+
16
+ <template>
17
+ <GenericArticleList
18
+ theme="news"
19
+ :columnNumber="1"
20
+ :articles="articles"
21
+ :categories="categories"
22
+ :settings="settings"
23
+ />
24
+ </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ Article,
4
+ Category,
5
+ ListSettings,
6
+ } from '../../../types'
7
+ import GenericArticleList from '../../../components/ArticleList/GenericArticleList.vue'
8
+
9
+ defineProps<{
10
+ articles: Article[]
11
+ categories: Category[]
12
+ settings: ListSettings
13
+ }>()
14
+ </script>
15
+
16
+ <template>
17
+ <GenericArticleList
18
+ theme="rounded"
19
+ :columnNumber="3"
20
+ :articles="articles"
21
+ :categories="categories"
22
+ :settings="settings"
23
+ />
24
+ </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ Article,
4
+ Category,
5
+ ListSettings,
6
+ } from '../../../types'
7
+ import GenericArticleList from '../../../components/ArticleList/GenericArticleList.vue'
8
+
9
+ defineProps<{
10
+ articles: Article[]
11
+ categories: Category[]
12
+ settings: ListSettings
13
+ }>()
14
+ </script>
15
+
16
+ <template>
17
+ <GenericArticleList
18
+ theme="row"
19
+ :columnNumber="1"
20
+ :articles="articles"
21
+ :categories="categories"
22
+ :settings="settings"
23
+ />
24
+ </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ Article,
4
+ Category,
5
+ ListSettings,
6
+ } from '../../../types'
7
+ import GenericArticleList from '../../../components/ArticleList/GenericArticleList.vue'
8
+
9
+ defineProps<{
10
+ articles: Article[]
11
+ categories: Category[]
12
+ settings: ListSettings
13
+ }>()
14
+ </script>
15
+
16
+ <template>
17
+ <GenericArticleList
18
+ theme="simple"
19
+ :columnNumber="3"
20
+ :articles="articles"
21
+ :categories="categories"
22
+ :settings="settings"
23
+ />
24
+ </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ Article,
4
+ Category,
5
+ ListSettings,
6
+ } from '../../../types'
7
+ import GenericArticleList from '../../../components/ArticleList/GenericArticleList.vue'
8
+
9
+ defineProps<{
10
+ articles: Article[]
11
+ categories: Category[]
12
+ settings: ListSettings
13
+ }>()
14
+ </script>
15
+
16
+ <template>
17
+ <GenericArticleList
18
+ theme="standard"
19
+ :columnNumber="3"
20
+ :articles="articles"
21
+ :categories="categories"
22
+ :settings="settings"
23
+ />
24
+ </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ Article,
4
+ Category,
5
+ ListSettings,
6
+ } from '../../../types'
7
+ import GenericArticleList from '../../../components/ArticleList/GenericArticleList.vue'
8
+
9
+ defineProps<{
10
+ articles: Article[]
11
+ categories: Category[]
12
+ settings: ListSettings
13
+ }>()
14
+ </script>
15
+
16
+ <template>
17
+ <GenericArticleList
18
+ theme="tile"
19
+ :columnNumber="3"
20
+ :articles="articles"
21
+ :categories="categories"
22
+ :settings="settings"
23
+ />
24
+ </template>
@@ -0,0 +1,100 @@
1
+ <script setup lang="ts">
2
+ withDefaults(defineProps<{
3
+ avatarUrls?: Record<string, string> | null
4
+ name?: string
5
+ direction?: 'row' | 'row-reverse'
6
+ thumbnail?: {
7
+ size?: 'small' | 'medium' | 'large'
8
+ shape?: 'square' | 'circle'
9
+ }
10
+ text?: {
11
+ color?: string
12
+ fontSize?: string
13
+ fontWeight?: string
14
+ preposition?: string
15
+ }
16
+ }>(), {
17
+ avatarUrls: null,
18
+ name : '',
19
+ direction : 'row',
20
+ thumbnail : () => ({
21
+ size : 'medium',
22
+ shape: 'square',
23
+ }),
24
+ text: () => ({
25
+ color : 'var(--gray)',
26
+ fontSize : 'medium',
27
+ fontWeight : 'normal',
28
+ preposition: '',
29
+ }),
30
+ })
31
+ </script>
32
+
33
+ <template>
34
+ <div
35
+ :class="$style.author_info"
36
+ :style="{
37
+ '--author-info-direction': direction,
38
+ '--author-name-color': text.color,
39
+ '--author-name-font-size': text.fontSize,
40
+ '--author-name-font-weight': text.fontWeight,
41
+ }"
42
+ >
43
+ <img
44
+ v-if="avatarUrls"
45
+ :src="avatarUrls['96']"
46
+ :srcset="
47
+ `${avatarUrls['96']} 1024w,
48
+ ${['48']} 640w`"
49
+ :alt="`${name} thumbnail`"
50
+ loading="lazy"
51
+ :class="[$style.thumbnail, $style[thumbnail.shape ?? 'square']]"
52
+ :style="{
53
+ '--thumbnail-size': thumbnail.size === 'small'
54
+ ? 'calc(var(--bv) * 3)'
55
+ : thumbnail.size === 'large'
56
+ ? 'calc(var(--bv) * 6)'
57
+ : 'calc(var(--bv) * 4)',
58
+ }"
59
+ >
60
+ <span
61
+ v-if="name"
62
+ :data-preposition="text.preposition"
63
+ >
64
+ {{ name }}
65
+ </span>
66
+ </div>
67
+ </template>
68
+
69
+ <style lang="scss" module>
70
+ .author_info {
71
+ display : inline-flex;
72
+ flex-direction: var(--author-info-direction);
73
+ align-items : center;
74
+ word-wrap : normal;
75
+ gap : var(--sp-small);
76
+
77
+ .thumbnail {
78
+ width : var(--thumbnail-size);
79
+ height : var(--thumbnail-size);
80
+ object-fit: cover;
81
+
82
+ &.circle {
83
+ border-radius: 50%;
84
+ }
85
+ }
86
+
87
+ > span {
88
+ margin : 0;
89
+ padding : 0;
90
+ color : var(--author-name-color);
91
+ font-size : var(--author-name-font-size);
92
+ font-weight: var(--author-name-font-weight);
93
+
94
+ &::before {
95
+ content : attr(data-preposition);
96
+ margin-inline-end: var(--sp-min);
97
+ }
98
+ }
99
+ }
100
+ </style>