/
StoryVariantGridItem.vue
149 lines (131 loc) · 4.2 KB
/
StoryVariantGridItem.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
<script lang="ts" setup>
import { PropType, ref, toRefs } from 'vue'
import { Icon } from '@iconify/vue'
import { useRouter } from 'vue-router'
import { useResizeObserver } from '@vueuse/core'
import { useCurrentVariantRoute } from '../../util/variant'
import type { Story, Variant } from '../../types'
import { useScrollOnActive } from '../../util/scroll'
import { usePreviewSettingsStore } from '../../stores/preview-settings'
import GenericRenderStory from './GenericRenderStory.vue'
import ToolbarNewTab from '../toolbar/ToolbarNewTab.vue'
import CheckerboardPattern from '../misc/CheckerboardPattern.vue'
import { getContrastColor } from '../../util/preview-settings'
const props = defineProps({
variant: {
type: Object as PropType<Variant>,
required: true,
},
story: {
type: Object as PropType<Story>,
required: true,
},
})
const emit = defineEmits({
// eslint-disable-next-line @typescript-eslint/no-unused-vars
resize: (width: number, height: number) => true,
})
const { variant } = toRefs(props)
const { isActive, targetRoute } = useCurrentVariantRoute(variant)
Object.assign(props.variant, {
previewReady: false,
})
function onReady () {
Object.assign(props.variant, {
previewReady: true,
})
}
const router = useRouter()
function selectVariant () {
router.push(targetRoute.value)
}
const el = ref<HTMLDivElement>()
const { autoScroll } = useScrollOnActive(isActive, el)
useResizeObserver(el, () => {
if (props.variant.previewReady) {
emit('resize', el.value!.clientWidth, el.value!.clientHeight)
if (isActive.value) {
autoScroll()
}
}
})
const settings = usePreviewSettingsStore().currentSettings
</script>
<template>
<div
ref="el"
class="histoire-story-variant-grid-item htw-cursor-default htw-flex htw-flex-col htw-gap-y-1 htw-group"
>
<!-- Header -->
<div class="htw-flex-none htw-flex htw-items-center">
<RouterLink
v-tooltip="variant.title"
:to="targetRoute"
class="htw-rounded htw-w-max htw-px-2 htw-py-0.5 htw-min-w-16 htw-cursor-pointer htw-flex htw-items-center htw-gap-1 htw-flex-shrink"
:class="{
'hover:htw-bg-gray-200 htw-text-gray-500 dark:hover:htw-bg-gray-800': !isActive,
'htw-bg-primary-200 hover:htw-bg-primary-300 htw-text-primary-800 dark:htw-bg-primary-700 dark:hover:htw-bg-primary-800 dark:htw-text-primary-200': isActive,
}"
>
<Icon
:icon="variant.icon ?? 'carbon:cube'"
class="htw-w-4 htw-h-4 htw-opacity-50"
:class="{
'htw-text-gray-500': !isActive && !variant.iconColor,
'bind-icon-color': !isActive && variant.iconColor,
}"
/>
<span class="htw-truncate htw-flex-1">{{ variant.title }}</span>
</RouterLink>
<!-- Toolbar -->
<div class="htw-flex-none htw-ml-auto htw-hidden group-hover:htw-flex htw-items-center">
<ToolbarNewTab
:variant="variant"
:story="story"
/>
</div>
</div>
<!-- Body -->
<div
class="htw-border htw-bg-white dark:htw-bg-gray-700 htw-rounded htw-flex-1 htw-p-4 htw-relative"
:class="{
'htw-border-gray-100 dark:htw-border-gray-800': !isActive,
'htw-border-primary-200 dark:htw-border-primary-900': isActive,
}"
data-test-id="sandbox-render"
@click.stop="selectVariant()"
@keyup="selectVariant()"
>
<div
class="htw-absolute htw-inset-0 htw-rounded bind-preview-bg"
data-test-id="responsive-preview-bg"
/>
<CheckerboardPattern
v-if="settings.checkerboard"
class="htw-absolute htw-inset-0 htw-w-full htw-h-full htw-text-gray-500/20"
/>
<div
class="htw-relative htw-h-full"
:style="{
'--histoire-contrast-color': getContrastColor(settings),
}"
>
<GenericRenderStory
:key="`${story.id}-${variant.id}`"
:variant="variant"
:story="story"
:dir="settings.textDirection"
@ready="onReady"
/>
</div>
</div>
</div>
</template>
<style scoped>
.bind-icon-color {
color: v-bind('variant.iconColor');
}
.bind-preview-bg {
background-color: v-bind('settings.backgroundColor');
}
</style>