Use responsive grid for templates dialog (#2791)

This commit is contained in:
bymyself
2025-03-01 15:08:41 -07:00
committed by GitHub
parent 09ab14ac81
commit e58fab92d1
12 changed files with 280 additions and 126 deletions

View File

@@ -1,56 +1,75 @@
<template>
<div
class="flex h-96 overflow-y-hidden"
class="flex flex-col h-[83vh] w-[90vw] relative"
data-testid="template-workflows-content"
>
<div class="relative">
<ProgressSpinner
v-if="!workflowTemplatesStore.isLoaded"
class="absolute w-8 h-full inset-0"
/>
<Listbox
:model-value="selectedTab"
@update:model-value="handleTabSelection"
:options="tabs"
option-group-label="label"
option-label="title"
option-group-children="modules"
scroll-height="auto"
class="overflow-y-auto w-64 h-full"
listStyle="max-height:unset"
/>
</div>
<Carousel
class="carousel justify-center"
:value="selectedTab.templates"
:responsive-options="responsiveOptions"
:num-visible="4"
:num-scroll="3"
:key="`${selectedTab.moduleName}${selectedTab.title}`"
>
<template #item="slotProps">
<div class="p-2 justify-items-center">
<TemplateWorkflowCard
:sourceModule="selectedTab.moduleName"
:template="slotProps.data"
:loading="slotProps.data.name === workflowLoading"
:categoryTitle="selectedTab.title"
@loadWorkflow="loadWorkflow"
/>
<Button
v-if="isSmallScreen"
:icon="isSideNavOpen ? 'pi pi-chevron-left' : 'pi pi-chevron-right'"
text
class="absolute top-1/2 -translate-y-1/2 z-10"
:class="isSideNavOpen ? 'left-[19rem]' : 'left-2'"
@click="toggleSideNav"
/>
<Divider
class="m-0 [&::before]:border-surface-border/70 [&::before]:border-t-2"
/>
<div class="flex flex-1 relative overflow-hidden">
<aside
v-if="isSideNavOpen"
class="absolute translate-x-0 top-0 left-0 h-full w-80 shadow-md z-5 transition-transform duration-300 ease-in-out"
>
<ProgressSpinner
v-if="!workflowTemplatesStore.isLoaded"
class="absolute w-8 h-full inset-0"
/>
<TemplateWorkflowsSideNav
:tabs="tabs"
:selected-tab="selectedTab"
@update:selected-tab="handleTabSelection"
/>
</aside>
<div
class="flex-1 overflow-auto transition-all duration-300"
:class="{
'pl-80': isSideNavOpen || !isSmallScreen,
'pl-8': !isSideNavOpen && isSmallScreen
}"
>
<div v-if="selectedTab" class="flex flex-col px-12 pb-4">
<div class="py-3 text-left">
<h2 class="text-lg">{{ selectedTab.title }}</h2>
</div>
<div
class="grid grid-cols-[repeat(auto-fill,minmax(16rem,1fr))] gap-8 justify-items-center"
>
<div v-for="template in selectedTab.templates" :key="template.name">
<TemplateWorkflowCard
:sourceModule="selectedTab.moduleName"
:template="template"
:loading="template.name === workflowLoading"
:categoryTitle="selectedTab.title"
@loadWorkflow="loadWorkflow"
/>
</div>
</div>
</div>
</template>
</Carousel>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Carousel from 'primevue/carousel'
import Listbox from 'primevue/listbox'
import { useBreakpoints } from '@vueuse/core'
import { useAsyncState } from '@vueuse/core'
import Button from 'primevue/button'
import Divider from 'primevue/divider'
import ProgressSpinner from 'primevue/progressspinner'
import { computed, onMounted, ref } from 'vue'
import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import TemplateWorkflowCard from '@/components/templates/TemplateWorkflowCard.vue'
import TemplateWorkflowsSideNav from '@/components/templates/TemplateWorkflowsSideNav.vue'
import { api } from '@/scripts/api'
import { app } from '@/scripts/app'
import { useDialogStore } from '@/stores/dialogStore'
@@ -59,43 +78,46 @@ import type { WorkflowTemplates } from '@/types/workflowTemplateTypes'
const { t } = useI18n()
const responsiveOptions = ref([
{
breakpoint: '1660px',
numVisible: 3,
numScroll: 2
},
{
breakpoint: '1360px',
numVisible: 2,
numScroll: 1
},
{
breakpoint: '960px',
numVisible: 1,
numScroll: 1
}
])
const breakpoints = useBreakpoints({
mobile: 0,
tablet: 768,
desktop: 1024
})
const isSmallScreen = breakpoints.between('mobile', 'desktop')
const isSideNavOpen = ref(!isSmallScreen.value)
const toggleSideNav = () => {
isSideNavOpen.value = !isSideNavOpen.value
}
watch(isSmallScreen, toggleSideNav)
const workflowTemplatesStore = useWorkflowTemplatesStore()
const { isReady } = useAsyncState(
workflowTemplatesStore.loadWorkflowTemplates,
null
)
const selectedTab = ref<WorkflowTemplates | null>(
workflowTemplatesStore?.defaultTemplate
workflowTemplatesStore.defaultTemplate
)
const workflowLoading = ref<string | null>(null)
const tabs = computed(() => workflowTemplatesStore.groupedTemplates)
onMounted(async () => {
await workflowTemplatesStore.loadWorkflowTemplates()
})
const handleTabSelection = (selection: WorkflowTemplates | null) => {
//Listbox allows deselecting so this special case is ignored here
if (selection !== selectedTab.value && selection !== null)
if (selection !== selectedTab.value && selection !== null) {
selectedTab.value = selection
// On small screens, close the sidebar when a category is selected
if (isSmallScreen.value) {
isSideNavOpen.value = false
}
}
}
const loadWorkflow = async (id: string) => {
if (!isReady.value) return
workflowLoading.value = id
let json
if (selectedTab.value.moduleName === 'default') {
@@ -120,9 +142,3 @@ const loadWorkflow = async (id: string) => {
return false
}
</script>
<style lang="css" scoped>
.carousel {
width: 66vw;
}
</style>