Feat resize model card (#104)
* feat: Use setting definition card size * refactor: Optimize computed value of the list items - Add useContainerResize hooks - Remove v-resize - Change cols to computed * refactor(ModelCard): Optimize style - Control the display of button or name in difference sizes - Add name tooltip when hiding name * feat: Add i18n * pref: optimize style code structure * feat: add quick resize card size * feat: add custom size tooltip * feat: optimize card tool button display judgment
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
:style="$content_lg(contentStyle)"
|
||||
>
|
||||
<div ref="toolbarContainer" class="col-span-full">
|
||||
<div class="flex flex-col gap-4" :style="$toolbar_2xl(toolbarStyle)">
|
||||
<div :class="['flex gap-4', $toolbar_2xl('flex-row', 'flex-col')]">
|
||||
<ResponseInput
|
||||
v-model="searchContent"
|
||||
:placeholder="$t('searchModels')"
|
||||
@@ -26,6 +26,10 @@
|
||||
v-model="sortOrder"
|
||||
:items="sortOrderOptions"
|
||||
></ResponseSelect>
|
||||
<ResponseSelect
|
||||
v-model="currentCardSize"
|
||||
:items="cardSizeOptions"
|
||||
></ResponseSelect>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -72,7 +76,7 @@ import { genModelKey } from 'utils/model'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { isMobile, cardWidth, gutter, aspect } = useConfig()
|
||||
const { isMobile, gutter, cardSize } = useConfig()
|
||||
|
||||
const { data, folders } = useModels()
|
||||
const { t } = useI18n()
|
||||
@@ -126,14 +130,14 @@ const sortOrderOptions = ref(
|
||||
)
|
||||
|
||||
const itemSize = computed(() => {
|
||||
let itemWidth = cardWidth
|
||||
let itemHeight = cardSize.value.height
|
||||
let itemGutter = gutter
|
||||
if (isMobile.value) {
|
||||
const baseSize = 16
|
||||
itemWidth = window.innerWidth - baseSize * 2 * 2
|
||||
itemHeight = window.innerWidth - baseSize * 2 * 2
|
||||
itemGutter = baseSize * 2
|
||||
}
|
||||
return itemWidth / aspect + itemGutter
|
||||
return itemHeight + itemGutter
|
||||
})
|
||||
|
||||
const { width } = useElementSize(contentContainer)
|
||||
@@ -142,9 +146,9 @@ const cols = computed(() => {
|
||||
if (isMobile.value) {
|
||||
return 1
|
||||
}
|
||||
|
||||
const containerWidth = width.value
|
||||
return Math.floor((containerWidth - gutter) / (cardWidth + gutter))
|
||||
const itemWidth = cardSize.value.width
|
||||
return Math.floor((containerWidth - gutter) / (itemWidth + gutter))
|
||||
})
|
||||
|
||||
const list = computed(() => {
|
||||
@@ -187,13 +191,56 @@ const list = computed(() => {
|
||||
})
|
||||
|
||||
const contentStyle = computed(() => ({
|
||||
gridTemplateColumns: `repeat(auto-fit, ${cardWidth}px)`,
|
||||
gridTemplateColumns: `repeat(auto-fit, ${cardSize.value.width}px)`,
|
||||
gap: `${gutter}px`,
|
||||
paddingLeft: `1rem`,
|
||||
paddingRight: `1rem`,
|
||||
}))
|
||||
|
||||
const toolbarStyle = computed(() => ({
|
||||
flexDirection: 'row',
|
||||
}))
|
||||
const currentCardSize = computed({
|
||||
get: () => {
|
||||
const options = cardSizeOptions.value.map((item) => item.value)
|
||||
const current = [cardSize.value.width, cardSize.value.height].join('x')
|
||||
if (options.includes(current)) {
|
||||
return current
|
||||
}
|
||||
return 'custom'
|
||||
},
|
||||
set: (val) => {
|
||||
if (val === 'custom') {
|
||||
app.ui?.settings.show(t('size.customTip'))
|
||||
return
|
||||
}
|
||||
|
||||
const [width, height] = val.split('x')
|
||||
app.ui?.settings.setSettingValue(
|
||||
'ModelManager.UI.CardWidth',
|
||||
parseInt(width),
|
||||
)
|
||||
app.ui?.settings.setSettingValue(
|
||||
'ModelManager.UI.CardHeight',
|
||||
parseInt(height),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
const cardSizeOptions = computed(() => {
|
||||
const defineOptions = {
|
||||
extraLarge: '240x320',
|
||||
large: '180x240',
|
||||
medium: '120x160',
|
||||
small: '80x120',
|
||||
custom: 'custom',
|
||||
}
|
||||
|
||||
return Object.entries(defineOptions).map(([key, value]) => {
|
||||
return {
|
||||
label: t(`size.${key}`),
|
||||
value,
|
||||
command() {
|
||||
currentCardSize.value = value
|
||||
},
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div
|
||||
class="group/card relative w-full cursor-pointer select-none preview-aspect"
|
||||
class="group/card relative cursor-pointer select-none"
|
||||
:style="{ width: `${cardSize.width}px`, height: `${cardSize.height}px` }"
|
||||
v-tooltip.top="{ value: model.basename, disabled: showModelName }"
|
||||
@click.stop="openDetailDialog"
|
||||
>
|
||||
<div class="h-full overflow-hidden rounded-lg">
|
||||
@@ -18,7 +20,7 @@
|
||||
|
||||
<div class="pointer-events-none absolute left-0 top-0 h-full w-full p-4">
|
||||
<div class="relative h-full w-full text-white">
|
||||
<div class="absolute bottom-0 left-0">
|
||||
<div v-show="showModelName" class="absolute bottom-0 left-0">
|
||||
<div class="drop-shadow-[0px_2px_2px_rgba(0,0,0,0.75)]">
|
||||
<div
|
||||
:class="[
|
||||
@@ -33,13 +35,19 @@
|
||||
|
||||
<div class="absolute left-0 top-0 w-full">
|
||||
<div class="flex flex-row items-start justify-between">
|
||||
<div class="flex items-center rounded-full bg-black/30 px-3 py-2">
|
||||
<div
|
||||
v-show="showModelType"
|
||||
class="flex items-center rounded-full bg-black/30 px-3 py-2"
|
||||
>
|
||||
<div :class="['font-bold', $lg('text-xs')]">
|
||||
{{ model.type }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="opacity-0 duration-300 group-hover/card:opacity-100">
|
||||
<div
|
||||
v-show="showToolButton"
|
||||
class="opacity-0 duration-300 group-hover/card:opacity-100"
|
||||
>
|
||||
<div class="flex flex-col gap-4 *:pointer-events-auto">
|
||||
<Button
|
||||
icon="pi pi-plus"
|
||||
@@ -71,6 +79,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import DialogModelDetail from 'components/DialogModelDetail.vue'
|
||||
import { useConfig } from 'hooks/config'
|
||||
import { useContainerQueries } from 'hooks/container'
|
||||
import { useDialog } from 'hooks/dialog'
|
||||
import { useModelNodeAction } from 'hooks/model'
|
||||
@@ -85,6 +94,8 @@ interface Props {
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const { cardSize } = useConfig()
|
||||
|
||||
const dialog = useDialog()
|
||||
|
||||
const openDetailDialog = () => {
|
||||
@@ -105,6 +116,18 @@ const preview = computed(() =>
|
||||
: props.model.preview,
|
||||
)
|
||||
|
||||
const showToolButton = computed(() => {
|
||||
return cardSize.value.width >= 180 && cardSize.value.height >= 240
|
||||
})
|
||||
|
||||
const showModelName = computed(() => {
|
||||
return cardSize.value.width >= 160 && cardSize.value.height >= 120
|
||||
})
|
||||
|
||||
const showModelType = computed(() => {
|
||||
return cardSize.value.width >= 120
|
||||
})
|
||||
|
||||
const { addModelNode, dragToAddModelNode, copyModelNode, loadPreviewWorkflow } =
|
||||
useModelNodeAction(props.model)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user