chore(deps): bump tailwindcss to v4

This commit is contained in:
2026-02-10 10:29:50 +08:00
parent 2c4951ff9b
commit d0bca215c1
35 changed files with 117 additions and 88 deletions

View File

@@ -30,7 +30,7 @@ const props = defineProps({
</h1>
<h1
class="text-xl font-bold text-neutral-700 dark:text-neutral-300 leading-none relative z-[1]"
class="text-xl font-bold text-neutral-700 dark:text-neutral-300 leading-none relative z-1"
>
{{ title }}
</h1>
@@ -43,7 +43,7 @@ const props = defineProps({
<div
v-if="bubble"
:class="`bg-${bubbleColor}/50`"
class="absolute -left-1.5 -bottom-1.5 w-4 h-4 rounded-full z-[0]"
class="absolute -left-1.5 -bottom-1.5 w-4 h-4 rounded-full z-0"
></div>
</div>
</template>

View File

@@ -477,7 +477,7 @@ const showAuthModal = ref(false)
<div class="flex items-center gap-2">
<UIcon
name="i-heroicons-sun"
class="h-4 w-4 text-amber-500 mt-0.5 flex-shrink-0"
class="h-4 w-4 text-amber-500 mt-0.5 shrink-0"
/>
<span class="text-xs text-gray-600 dark:text-gray-300">
确保光线充足避免背光
@@ -486,7 +486,7 @@ const showAuthModal = ref(false)
<div class="flex items-center gap-2">
<UIcon
name="i-heroicons-speaker-wave"
class="h-4 w-4 text-green-500 mt-0.5 flex-shrink-0"
class="h-4 w-4 text-green-500 mt-0.5 shrink-0"
/>
<span class="text-xs text-gray-600 dark:text-gray-300">
选择安静环境减少噪音干扰
@@ -495,7 +495,7 @@ const showAuthModal = ref(false)
<div class="flex items-center gap-2">
<UIcon
name="i-heroicons-viewfinder-circle"
class="h-4 w-4 text-blue-500 mt-0.5 flex-shrink-0"
class="h-4 w-4 text-blue-500 mt-0.5 shrink-0"
/>
<span class="text-xs text-gray-600 dark:text-gray-300">
人脸占画面比例控制在 1/4 以内
@@ -504,7 +504,7 @@ const showAuthModal = ref(false)
<div class="flex items-center gap-2">
<UIcon
name="i-heroicons-face-smile"
class="h-4 w-4 text-purple-500 mt-0.5 flex-shrink-0"
class="h-4 w-4 text-purple-500 mt-0.5 shrink-0"
/>
<span class="text-xs text-gray-600 dark:text-gray-300">
保持自然表情使用恰当手势

View File

@@ -18,12 +18,12 @@ const props = defineProps({
<template>
<div
:class="{
'w-full h-[1px]': !vertical,
'w-[1px] h-full': vertical,
'w-full h-px': !vertical,
'w-px h-full': vertical,
[`from-${lineGradientFrom}-500/50`]: true,
[`to-${lineGradientTo}-300/50`]: true,
}"
class="bg-gradient-to-r rounded-full my-4"
class="bg-linear-to-r rounded-full my-4"
></div>
</template>

View File

@@ -36,6 +36,6 @@ const size = computed(() => {
<style scoped>
.gradient-background {
@apply rounded-lg;
@apply bg-gradient-to-r from-indigo-800 to-purple-600;
@apply bg-linear-to-r from-indigo-800 to-purple-600;
}
</style>

View File

@@ -585,7 +585,7 @@ const onForgetPasswordSubmit = (
.pin-input {
@apply w-full md:w-16 aspect-square rounded text-center shadow caret-transparent;
@apply outline-0 ring-indigo-500 focus:ring font-bold;
@apply outline-0 ring-indigo-500 focus:ring-3 font-bold;
}
.pin-label {

View File

@@ -68,7 +68,7 @@ const getShapeSize = (r: { w: number; h: number }, size: number) => {
:class="[ratio.value === selected && 'bg-sky-200/50 dark:bg-sky-700/50']"
>
<div
class="bg-neutral-300/50 dark:bg-neutral-600/50 text-neutral-600 dark:text-neutral-300 rounded flex justify-center items-center"
class="bg-neutral-300/50 dark:bg-neutral-600/50 text-neutral-600 dark:text-neutral-300 rounded-sm flex justify-center items-center"
:class="[
ratio.value === selected && 'bg-sky-300/50 dark:bg-sky-600/50',
]"

View File

@@ -58,7 +58,7 @@ const handleFileInput = (event: { target: any }) => {
<template>
<div
class="w-full bg-neutral-200/50 dark:bg-neutral-700/50 rounded-md flex justify-between items-center p-1.5 gap-2 relative hover:bg-neutral-200/80 hover:dark:bg-neutral-700/80 transition border dark:border-neutral-700 cursor-pointer"
class="w-full bg-neutral-200/50 dark:bg-neutral-700/50 rounded-md flex justify-between items-center p-1.5 gap-2 relative hover:bg-neutral-200/80 dark:hover:bg-neutral-700/80 transition border dark:border-neutral-700 cursor-pointer"
:class="{ 'cursor-pointer': !loading, 'cursor-not-allowed': loading }"
@click="() => !loading && fileInput?.click()"
>

View File

@@ -25,7 +25,7 @@ const message_avatar = computed(() => {
})
const message_background = computed(() => {
if (props.message?.interrupted) {
return 'bg-red-200/50 dark:bg-red-800/20 border-red-300 dark:!border-red-500/50'
return 'bg-red-200/50 dark:bg-red-800/20 border-red-300 dark:border-red-500/50!'
}
switch (props.message?.role) {
case 'user':

View File

@@ -40,7 +40,7 @@ const { data: assistantTemplates, pending: assistantTemplatesPending } =
<Transition name="loading-screen">
<div
v-if="assistantTemplatesPending"
class="absolute inset-0 bg-white dark:bg-neutral-900 flex justify-center items-center z-[1] text-primary"
class="absolute inset-0 bg-white dark:bg-neutral-900 flex justify-center items-center z-1 text-primary"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -151,7 +151,7 @@ const { data: assistantTemplates, pending: assistantTemplatesPending } =
class="group ring-primary hover:ring-2 transition duration-300"
variant="soft"
size="lg"
:ui="{ rounded: 'rounded-full' }"
:ui="{ rounded-sm: 'rounded-full' }"
@click="emit('select', null)"
>
<span class="-mt-0.5">直接开始</span>
@@ -202,7 +202,7 @@ const { data: assistantTemplates, pending: assistantTemplatesPending } =
}
.assistant-item {
@apply w-full bg-white dark:bg-neutral-800 rounded-lg shadow-sm ring-primary ring-offset-2 dark:ring-offset-0 hover:ring-2 transition;
@apply w-full bg-white dark:bg-neutral-800 rounded-lg shadow-xs ring-primary ring-offset-2 dark:ring-offset-0 hover:ring-2 transition;
@apply flex items-center gap-4 px-4 py-2 cursor-pointer border dark:border-neutral-700 hover:border-transparent;
}
</style>

View File

@@ -17,7 +17,7 @@ const props = defineProps({
<template>
<div
class="bg-neutral-50 dark:bg-neutral-900 px-1.5 py-1 rounded flex flex-col gap-1 shadow"
class="bg-neutral-50 dark:bg-neutral-900 px-1.5 py-1 rounded-sm flex flex-col gap-1 shadow-sm"
>
<div class="flex items-center gap-1 text-sm">
<UIcon

View File

@@ -155,7 +155,7 @@ const copyToClipboard = (text: string) => {
:key="`${fid}-${i}`"
>
<div
class="absolute inset-0 bg-gradient-to-t from-neutral-800/40 to-transparent w-full h-full flex items-end scale-105 opacity-0 group-hover:scale-100 group-hover:opacity-100 transition"
class="absolute inset-0 bg-linear-to-t from-neutral-800/40 to-transparent w-full h-full flex items-end scale-105 opacity-0 group-hover:scale-100 group-hover:opacity-100 transition"
>
<div class="w-full flex justify-end gap-1 p-1">
<UTooltip text="以此图为参考创作">
@@ -189,7 +189,7 @@ const copyToClipboard = (text: string) => {
</div>
<div
v-else
class="h-64 aspect-[3/4] mb-4 rounded-lg placeholder-gradient flex justify-center items-center"
class="h-64 aspect-3/4 mb-4 rounded-lg placeholder-gradient flex justify-center items-center"
>
<UIcon
name="i-svg-spinners-tadpole"
@@ -298,6 +298,6 @@ const copyToClipboard = (text: string) => {
}
.placeholder-gradient {
@apply animate-pulse bg-gradient-to-br from-neutral-200 to-neutral-300 dark:from-neutral-700 dark:to-neutral-800;
@apply animate-pulse bg-linear-to-br from-neutral-200 to-neutral-300 dark:from-neutral-700 dark:to-neutral-800;
}
</style>

View File

@@ -236,7 +236,7 @@ const onRetryClick = (course: resp.gen.CourseGenItem) => {
<template>
<div
class="w-full rounded-xl border border-neutral-200 dark:border-neutral-700 hover:shadow transition overflow-hidden"
class="w-full rounded-xl border border-neutral-200 dark:border-neutral-700 hover:shadow-sm transition overflow-hidden"
>
<div class="relative w-full aspect-video group">
<NuxtImg
@@ -248,7 +248,7 @@ const onRetryClick = (course: resp.gen.CourseGenItem) => {
/>
<div
v-else
class="absolute inset-0 bg-gradient-to-br from-purple-400 to-primary-400 flex justify-center items-center pattern"
class="absolute inset-0 bg-linear-to-br from-purple-400 to-primary-400 flex justify-center items-center pattern"
>
<Icon
v-if="isFailed"
@@ -269,7 +269,7 @@ const onRetryClick = (course: resp.gen.CourseGenItem) => {
<UBadge
:color="stateDisplay.color"
:variant="isFailed ? 'solid' : 'subtle'"
class="shadow"
class="shadow-sm"
size="sm"
>
<Icon
@@ -462,7 +462,7 @@ const onRetryClick = (course: resp.gen.CourseGenItem) => {
</template>
<video
class="w-full rounded shadow"
class="w-full rounded-sm shadow-sm"
controls
autoplay
:src="course.video_url"

View File

@@ -197,10 +197,10 @@ const startDownload = (url: string, filename: string) => {
<template>
<div
class="w-full flex gap-2 rounded-xl border border-neutral-200 dark:border-neutral-700 hover:shadow transition overflow-hidden p-3"
class="w-full flex gap-2 rounded-xl border border-neutral-200 dark:border-neutral-700 hover:shadow-sm transition overflow-hidden p-3"
>
<div
class="flex-0 h-48 aspect-[10/16] flex flex-col items-center justify-center rounded-lg shadow overflow-hidden relative group"
class="flex-0 h-48 aspect-10/16 flex flex-col items-center justify-center rounded-lg shadow-sm overflow-hidden relative group"
>
<div
v-if="!video.video_cover"
@@ -451,7 +451,7 @@ const startDownload = (url: string, filename: string) => {
</template>
<video
class="w-full rounded shadow"
class="w-full rounded-sm shadow-sm"
controls
autoplay
:src="video.video_url"
@@ -570,7 +570,7 @@ const startDownload = (url: string, filename: string) => {
视频预览
</div>
<video
class="w-full rounded-lg shadow bg-black"
class="w-full rounded-lg shadow-sm bg-black"
controls
autoplay
muted

View File

@@ -41,7 +41,7 @@ type subtitleStyleSchema = InferType<typeof subtitleStyleSchema>
const subtitleStyleState = reactive<subtitleStyleSchema>({
color: '#fff',
effect: 'shadow',
effect: 'shadow-sm',
fontSize: 24,
bottomOffset: 12,
})
@@ -213,7 +213,7 @@ const exportVideo = async () => {
color: subtitleStyleState.color,
fontSize: subtitleStyleState.fontSize,
textShadow:
subtitleStyleState.effect === 'shadow'
subtitleStyleState.effect === 'shadow-sm'
? {
offsetX: 2,
offsetY: 2,
@@ -381,7 +381,7 @@ defineExpose({
fontSize: subtitleStyleState.fontSize / 1.5 + 'px',
bottom: subtitleStyleState.bottomOffset / 1.5 + 'px',
textShadow:
subtitleStyleState.effect === 'shadow'
subtitleStyleState.effect === 'shadow-sm'
? '2px 2px 4px rgba(0, 0, 0, 0.25)'
: undefined,
}"
@@ -391,7 +391,7 @@ defineExpose({
<video
controls
ref="videoElement"
class="rounded"
class="rounded-sm"
style="-webkit-user-drag: none"
:src="course.video_url"
@timeupdate="syncSubtitles"
@@ -425,7 +425,7 @@ defineExpose({
fontSize: subtitleStyleState.fontSize / 1.5 + 'px',
bottom: subtitleStyleState.bottomOffset / 1.5 + 'px',
textShadow:
subtitleStyleState.effect === 'shadow'
subtitleStyleState.effect === 'shadow-sm'
? '2px 2px 4px rgba(0, 0, 0, 0.25)'
: undefined,
}"
@@ -475,7 +475,7 @@ defineExpose({
:options="[
{
label: '阴影',
value: 'shadow',
value: 'shadow-sm',
},
{
label: '描边',
@@ -606,7 +606,7 @@ defineExpose({
content: '';
inset: 80% 0 0;
position: absolute;
@apply bg-gradient-to-b from-transparent to-white dark:to-neutral-950 pointer-events-none;
@apply bg-linear-to-b from-transparent to-white dark:to-neutral-950 pointer-events-none;
}
.subtitle.stroke {

View File

@@ -38,12 +38,12 @@ const closePreview = () => {
<template>
<div
class="relative w-full flex flex-col rounded-lg border border-neutral-200 dark:border-neutral-700 overflow-hidden shadow-none hover:shadow transition-shadow"
class="relative w-full flex flex-col rounded-lg border border-neutral-200 dark:border-neutral-700 overflow-hidden shadow-none hover:shadow-sm transition-shadow"
>
<div class="relative w-full aspect-[16/9] group">
<div class="relative w-full aspect-16/9 group">
<NuxtImg
placeholder
placeholder-class="w-full aspect-[16/9] object-cover bg-neutral-200 dark:bg-neutral-800"
placeholder-class="w-full aspect-16/9 object-cover bg-neutral-200 dark:bg-neutral-800"
class="object-cover relative"
:src="data.opening_url"
/>
@@ -183,7 +183,7 @@ const closePreview = () => {
<video
v-if="previewVideoUrl"
class="w-full rounded shadow"
class="w-full rounded-sm shadow-sm"
controls
autoplay
:src="previewVideoUrl"

View File

@@ -55,7 +55,7 @@ const handleClick = (e: any) => {
<template>
<button
class="w-fit flex justify-center items-center rounded-md font-bold border shadow-sm transition focus:ring-4"
class="w-fit flex justify-center items-center rounded-md font-bold border shadow-xs transition focus:ring-4"
:class="{
'w-full': block,
'uni-button--disabled': disabled || loading,

View File

@@ -98,9 +98,9 @@ const handleInput = (e: any) => {
</p>
<div class="relative">
<input
class="relative w-full flex items-center gap-2.5 p-2 pr-2 rounded-md overflow-hidden border transition bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-800 focus:border-neutral-400 dark:focus:border-neutral-700 focus:ring-4 focus:ring-opacity-50 focus:ring-neutral-200 dark:focus:ring-neutral-800 outline-none placeholder-neutral-400 dark:placeholder-neutral-500 shadow-sm"
class="relative w-full flex items-center gap-2.5 p-2 pr-2 rounded-md overflow-hidden border transition bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-800 focus:border-neutral-400 dark:focus:border-neutral-700 focus:ring-4 focus:ring-opacity-50 focus:ring-neutral-200 dark:focus:ring-neutral-800 outline-hidden placeholder-neutral-400 dark:placeholder-neutral-500 shadow-xs"
:class="{
'!border-red-500': isError,
'border-red-500!': isError,
'bg-neutral-100 dark:bg-neutral-900 text-neutral-400 dark:text-neutral-600':
disabled,
}"

View File

@@ -83,7 +83,7 @@ nuxtApp.vueApp.provide('uni-message', api)
<style scoped>
#message-provider .message-wrapper {
@apply z-[50000] fixed inset-0 flex flex-col items-center pointer-events-none;
@apply z-50000 fixed inset-0 flex flex-col items-center pointer-events-none;
}
.message-move,

View File

@@ -26,12 +26,12 @@ onMounted(() => {
<div
class="message"
:class="{
'!text-blue-500 !border-blue-400 !bg-blue-50': message.type === 'info',
'!text-emerald-500 !border-emerald-400 !bg-emerald-50':
'text-blue-500! border-blue-400! bg-blue-50!': message.type === 'info',
'text-emerald-500! border-emerald-400! bg-emerald-50!':
message.type === 'success',
'!text-orange-500 !border-orange-400 !bg-orange-50':
'text-orange-500! border-orange-400! bg-orange-50!':
message.type === 'warning',
'!text-rose-500 !border-rose-400 !bg-rose-50': message.type === 'error',
'text-rose-500! border-rose-400! bg-rose-50!': message.type === 'error',
[message.type]: message.type,
}"
>

View File

@@ -97,7 +97,7 @@ onMounted(() => {
ref="selectWrapperRef"
>
<button
class="relative w-full flex items-center gap-2.5 p-2 pr-6 rounded-md overflow-hidden border transition bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-800 focus:border-neutral-400 dark:focus:border-neutral-700 focus:ring-4 focus:ring-opacity-50 focus:ring-neutral-200 dark:focus:ring-neutral-800 shadow-sm"
class="relative w-full flex items-center gap-2.5 p-2 pr-6 rounded-md overflow-hidden border transition bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-800 focus:border-neutral-400 dark:focus:border-neutral-700 focus:ring-4 focus:ring-opacity-50 focus:ring-neutral-200 dark:focus:ring-neutral-800 shadow-xs"
:class="{
'cursor-not-allowed bg-neutral-100 dark:bg-neutral-900 text-neutral-400 dark:text-neutral-600':
disabled,
@@ -148,9 +148,9 @@ onMounted(() => {
v-for="(option, index) in items"
:key="index"
:class="{
'!bg-neutral-200 dark:!bg-neutral-700 hover:!bg-neutral-200 dark:hover:!bg-neutral-700':
'bg-neutral-200! dark:bg-neutral-700! hover:bg-neutral-200! dark:hover:bg-neutral-700!':
option.value === selectedItem?.value,
'!cursor-not-allowed text-neutral-300 dark:text-neutral-500 hover:bg-white dark:hover:!bg-neutral-800':
'cursor-not-allowed! text-neutral-300 dark:text-neutral-500 hover:bg-white dark:hover:bg-neutral-800!':
option.disabled,
}"
@click="!option.disabled ? handleOptionSelect(option) : void 0"

View File

@@ -116,11 +116,11 @@ onMounted(() => {
</p>
<div class="relative">
<textarea
class="relative w-full flex items-center gap-2.5 p-2 pr-6 rounded-md overflow-hidden overflow-y-auto border transition bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-800 focus:border-neutral-400 dark:focus:border-neutral-700 focus:ring-4 focus:ring-opacity-50 focus:ring-neutral-200 dark:focus:ring-neutral-800 outline-none placeholder-neutral-400 dark:placeholder-neutral-500 shadow-sm"
class="relative w-full flex items-center gap-2.5 p-2 pr-6 rounded-md overflow-hidden overflow-y-auto border transition bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-800 focus:border-neutral-400 dark:focus:border-neutral-700 focus:ring-4 focus:ring-opacity-50 focus:ring-neutral-200 dark:focus:ring-neutral-800 outline-hidden placeholder-neutral-400 dark:placeholder-neutral-500 shadow-xs"
:rows="minRows || rows"
ref="textAreaRef"
:class="{
'!border-red-500': isError,
'border-red-500!': isError,
'bg-neutral-100 dark:bg-neutral-900 text-neutral-400 dark:text-neutral-600':
disabled,
}"

View File

@@ -98,18 +98,18 @@ watch(
<template>
<button
class="relative flex items-center rounded-lg bg-neutral-100 dark:bg-neutral-800 shadow-inner transition ease-in-out group outline-none"
class="relative flex items-center rounded-lg bg-neutral-100 dark:bg-neutral-800 shadow-inner transition ease-in-out group outline-hidden"
:class="{
'!bg-green-400 dark:!bg-green-400/50': checked,
'bg-green-400! dark:bg-green-400/50!': checked,
[buttonSizeClass]: buttonSizeClass,
[buttonPaddingClass]: buttonPaddingClass,
}"
@click="handleCheck"
>
<span
class="aspect-[1/1] translate-x-0 transition ease-in-out bg-white dark:bg-black rounded-md shadow duration-300 group-active:scale-90"
class="aspect-1/1 translate-x-0 transition ease-in-out bg-white dark:bg-black rounded-md shadow-sm duration-300 group-active:scale-90"
:class="{
'!shadow-lg': checked,
'shadow-lg!': checked,
'group-active:translate-x-3 group-active:duration-500': !checked,
[bulletSizeClass]: bulletSizeClass,
[bulletTranslateClass]: checked,