fix: Container queries occasionally fail (#88)

- Use js dynamic calculation instead of container query
- Remove @tailwindcss/container-queries
This commit is contained in:
Hayden
2025-01-10 16:04:49 +08:00
committed by GitHub
parent c1e89eb177
commit e75275dfff
11 changed files with 123 additions and 51 deletions

View File

@@ -10,7 +10,6 @@
"prepare": "husky"
},
"devDependencies": {
"@tailwindcss/container-queries": "^0.1.1",
"@types/lodash": "^4.17.9",
"@types/markdown-it": "^14.1.2",
"@types/node": "^22.5.5",

12
pnpm-lock.yaml generated
View File

@@ -36,9 +36,6 @@ importers:
specifier: ^2.6.0
version: 2.6.0
devDependencies:
'@tailwindcss/container-queries':
specifier: ^0.1.1
version: 0.1.1(tailwindcss@3.4.12)
'@types/lodash':
specifier: ^4.17.9
version: 4.17.9
@@ -470,11 +467,6 @@ packages:
cpu: [x64]
os: [win32]
'@tailwindcss/container-queries@0.1.1':
resolution: {integrity: sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==}
peerDependencies:
tailwindcss: '>=3.2.0'
'@types/estree@1.0.5':
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
@@ -2000,10 +1992,6 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.22.0':
optional: true
'@tailwindcss/container-queries@0.1.1(tailwindcss@3.4.12)':
dependencies:
tailwindcss: 3.4.12
'@types/estree@1.0.5': {}
'@types/linkify-it@5.0.0': {}

View File

@@ -1,9 +1,9 @@
<template>
<div class="flex h-full flex-col gap-4">
<div class="whitespace-nowrap px-4 @container">
<div class="flex gap-4 @sm:justify-end">
<div class="whitespace-nowrap px-4" v-container="container">
<div :class="['flex gap-4', $sm('justify-end')]">
<Button
class="w-full @sm:w-auto"
:class="[$sm('w-auto', 'w-full')]"
:label="$t('createDownloadTask')"
@click="openCreateTask"
></Button>
@@ -73,6 +73,7 @@
<script setup lang="ts">
import DialogCreateTask from 'components/DialogCreateTask.vue'
import ResponseScroll from 'components/ResponseScroll.vue'
import { useContainerQueries } from 'hooks/container'
import { useDialog } from 'hooks/dialog'
import { useDownload } from 'hooks/download'
import Button from 'primevue/button'
@@ -90,4 +91,7 @@ const openCreateTask = () => {
content: DialogCreateTask,
})
}
const container = Symbol('container')
const { $sm } = useContainerQueries(container)
</script>

View File

@@ -1,22 +1,15 @@
<template>
<div
class="flex h-full flex-col gap-4 overflow-hidden @container/content"
:style="{
['--card-width']: `${cardWidth}px`,
['--gutter']: `${gutter}px`,
}"
class="flex h-full flex-col gap-4 overflow-hidden"
v-resize="onContainerResize"
v-container="contentContainer"
>
<div
:class="[
'grid grid-cols-1 justify-center gap-4 px-8',
'@lg/content:grid-cols-[repeat(auto-fit,var(--card-width))]',
'@lg/content:gap-[var(--gutter)]',
'@lg/content:px-4',
]"
class="grid grid-cols-1 justify-center gap-4 px-8"
:style="$content_lg(contentStyle)"
>
<div class="col-span-full @container/toolbar">
<div :class="['flex flex-col gap-4', '@2xl/toolbar:flex-row']">
<div class="col-span-full" v-container="toolbarContainer">
<div class="flex flex-col gap-4" :style="$toolbar_2xl(toolbarStyle)">
<ResponseInput
v-model="searchContent"
:placeholder="$t('searchModels')"
@@ -48,12 +41,8 @@
>
<template #item="{ item }">
<div
:class="[
'grid grid-cols-1 justify-center gap-8 px-8',
'@lg/content:grid-cols-[repeat(auto-fit,var(--card-width))]',
'@lg/content:gap-[var(--gutter)]',
'@lg/content:px-4',
]"
class="grid grid-cols-1 justify-center gap-8 px-8"
:style="contentStyle"
>
<ModelCard
v-for="model in item"
@@ -80,6 +69,7 @@ import ResponseInput from 'components/ResponseInput.vue'
import ResponseScroll from 'components/ResponseScroll.vue'
import ResponseSelect from 'components/ResponseSelect.vue'
import { useConfig } from 'hooks/config'
import { useContainerQueries } from 'hooks/container'
import { useModels } from 'hooks/model'
import { defineResizeCallback } from 'hooks/resize'
import { chunk } from 'lodash'
@@ -179,6 +169,22 @@ const list = computed(() => {
return chunk(sortedList, colSpan.value)
})
const toolbarContainer = Symbol('toolbar')
const { $2xl: $toolbar_2xl } = useContainerQueries(toolbarContainer)
const contentContainer = Symbol('content')
const { $lg: $content_lg } = useContainerQueries(contentContainer)
const contentStyle = {
gridTemplateColumns: `repeat(auto-fit, ${cardWidth}px)`,
gap: `${gutter}px`,
paddingLeft: `1rem`,
paddingRight: `1rem`,
}
const toolbarStyle = {
flexDirection: 'row',
}
const onContainerResize = defineResizeCallback((entries) => {
const entry = entries[0]
if (isMobile.value) {

View File

@@ -20,7 +20,12 @@
<div class="relative h-full w-full text-white">
<div class="absolute bottom-0 left-0">
<div class="drop-shadow-[0px_2px_2px_rgba(0,0,0,0.75)]">
<div class="line-clamp-3 break-all text-2xl font-bold @lg:text-lg">
<div
:class="[
'line-clamp-3 break-all font-bold',
$lg('text-lg', 'text-2xl'),
]"
>
{{ model.basename }}
</div>
</div>
@@ -29,7 +34,7 @@
<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 class="font-bold @lg:text-xs">
<div :class="['font-bold', $lg('text-xs')]">
{{ model.type }}
</div>
</div>
@@ -66,6 +71,7 @@
<script setup lang="ts">
import DialogModelDetail from 'components/DialogModelDetail.vue'
import { useContainerQueries } from 'hooks/container'
import { useDialog } from 'hooks/dialog'
import { useModelNodeAction } from 'hooks/model'
import Button from 'primevue/button'
@@ -101,4 +107,6 @@ const preview = computed(() =>
const { addModelNode, dragToAddModelNode, copyModelNode, loadPreviewWorkflow } =
useModelNodeAction(props.model)
const { $lg } = useContainerQueries()
</script>

View File

@@ -1,11 +1,16 @@
<template>
<form
class="@container"
@submit.prevent="handleSubmit"
@reset.prevent="handleReset"
v-container="container"
>
<div class="mx-auto w-full max-w-[50rem]">
<div class="relative flex flex-col gap-4 overflow-hidden @xl:flex-row">
<div
:class="[
'relative flex gap-4 overflow-hidden',
$xl('flex-row', 'flex-col'),
]"
>
<ModelPreview
class="shrink-0"
v-model:editable="editable"
@@ -43,6 +48,7 @@ import ModelBaseInfo from 'components/ModelBaseInfo.vue'
import ModelDescription from 'components/ModelDescription.vue'
import ModelMetadata from 'components/ModelMetadata.vue'
import ModelPreview from 'components/ModelPreview.vue'
import { useContainerQueries } from 'hooks/container'
import {
useModelBaseInfoEditor,
useModelDescriptionEditor,
@@ -94,4 +100,7 @@ watch(
handleReset()
},
)
const container = Symbol('container')
const { $xl } = useContainerQueries(container)
</script>

View File

@@ -1,15 +1,9 @@
<template>
<div
class="flex flex-col gap-4"
:style="{ ['--preview-width']: `${cardWidth}px` }"
>
<div class="flex flex-col gap-4">
<div>
<div
:class="[
'relative mx-auto w-full',
'@sm:w-[var(--preview-width)]',
'overflow-hidden rounded-lg preview-aspect',
]"
class="relative mx-auto w-full overflow-hidden rounded-lg preview-aspect"
:style="$sm({ width: `${cardWidth}px` })"
>
<ResponseImage :src="preview" :error="noPreviewContent"></ResponseImage>
@@ -52,7 +46,7 @@
:class="[
'flex h-10 items-center gap-4',
'absolute left-1/2 -translate-x-1/2',
'@xl:left-0 @xl:translate-x-0',
$xl('left-0 translate-x-0'),
]"
>
<Button
@@ -92,6 +86,7 @@ import ResponseFileUpload from 'components/ResponseFileUpload.vue'
import ResponseImage from 'components/ResponseImage.vue'
import ResponseInput from 'components/ResponseInput.vue'
import { useConfig } from 'hooks/config'
import { useContainerQueries } from 'hooks/container'
import { useModelPreview } from 'hooks/model'
import Button from 'primevue/button'
import Carousel from 'primevue/carousel'
@@ -109,4 +104,6 @@ const {
updateLocalContent,
noPreviewContent,
} = useModelPreview()
const { $sm, $xl } = useContainerQueries()
</script>

60
src/hooks/container.ts Normal file
View File

@@ -0,0 +1,60 @@
import { defineResizeCallback } from 'hooks/resize'
import { computed, Directive, inject, InjectionKey, provide, ref } from 'vue'
const globalContainerSize = ref<Record<symbol, number>>({})
const containerNameKey = Symbol('containerName') as InjectionKey<symbol>
export const containerDirective: Directive<HTMLElement, symbol> = {
mounted: (el, binding) => {
const containerName = binding.value || Symbol('container')
const resizeCallback = defineResizeCallback((entries) => {
const entry = entries[0]
globalContainerSize.value[containerName] = entry.contentRect.width
})
const observer = new ResizeObserver(resizeCallback)
observer.observe(el)
el['_containerObserver'] = observer
},
unmounted: (el) => {
const observer = el['_containerObserver']
observer.disconnect()
},
}
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize)
export const useContainerQueries = (containerName?: symbol) => {
const parentContainer = inject(containerNameKey, Symbol('unknown'))
const name = containerName ?? parentContainer
provide(containerNameKey, name)
const currentContainerSize = computed(() => {
return globalContainerSize.value[name] ?? 0
})
/**
* @param size unit rem
*/
const generator = (size: number) => {
return (content: any, defaultContent: any = undefined) => {
return currentContainerSize.value > size * rem ? content : defaultContent
}
}
return {
$xs: generator(20),
$sm: generator(24),
$md: generator(28),
$lg: generator(32),
$xl: generator(36),
$2xl: generator(42),
$3xl: generator(48),
$4xl: generator(54),
$5xl: generator(60),
$6xl: generator(66),
$7xl: generator(72),
}
}

View File

@@ -1,5 +1,6 @@
import { definePreset } from '@primevue/themes'
import Aura from '@primevue/themes/aura'
import { containerDirective } from 'hooks/container'
import { resizeDirective } from 'hooks/resize'
import PrimeVue from 'primevue/config'
import ConfirmationService from 'primevue/confirmationservice'
@@ -21,6 +22,7 @@ function createVueApp(rootContainer: string | HTMLElement) {
const app = createApp(App)
app.directive('tooltip', Tooltip)
app.directive('resize', resizeDirective)
app.directive('container', containerDirective)
app
.use(PrimeVue, {
theme: {

View File

@@ -3,6 +3,7 @@ export {}
declare module 'vue' {
interface ComponentCustomProperties {
vResize: (typeof import('hooks/resize'))['resizeDirective']
vContainer: (typeof import('hooks/container'))['containerDirective']
}
}

View File

@@ -1,4 +1,3 @@
import container from '@tailwindcss/container-queries'
import plugin from 'tailwindcss/plugin'
/** @type {import('tailwindcss').Config} */
@@ -8,7 +7,6 @@ export default {
darkMode: ['selector', '.dark-theme'],
plugins: [
container,
plugin(({ addUtilities }) => {
addUtilities({
'.scrollbar-none': {