fixes
This commit is contained in:
@@ -58,6 +58,12 @@
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
select {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
color: var(--color-text);
|
||||
|
||||
@@ -218,19 +218,27 @@ h1, h2, h3, h4, h5, h6 {
|
||||
|
||||
/* --- Textarea / Inputs --- */
|
||||
.p-textarea,
|
||||
.p-inputtext {
|
||||
.p-inputtext,
|
||||
.p-dropdown,
|
||||
.p-multiselect,
|
||||
.p-autocomplete,
|
||||
.p-inputnumber input {
|
||||
width: 100%;
|
||||
background: rgba(15, 23, 42, 0.6) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
||||
border-radius: 8px !important;
|
||||
padding: 0.5rem !important;
|
||||
color: white !important;
|
||||
font-size: 0.8125rem !important;
|
||||
font-size: 1rem !important;
|
||||
transition: all 0.3s ease !important;
|
||||
}
|
||||
|
||||
.p-textarea:focus,
|
||||
.p-inputtext:focus {
|
||||
.p-inputtext:focus,
|
||||
.p-dropdown:focus,
|
||||
.p-multiselect:focus,
|
||||
.p-autocomplete:focus,
|
||||
.p-inputnumber input:focus {
|
||||
outline: none !important;
|
||||
border-color: #8b5cf6 !important;
|
||||
box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.1) !important;
|
||||
|
||||
@@ -41,7 +41,8 @@ const isEnvAssetPickerVisible = ref(false)
|
||||
const isDeletingEnv = ref(false)
|
||||
const envForm = ref({
|
||||
name: '',
|
||||
asset_ids: []
|
||||
asset_ids: [],
|
||||
assets_list: []
|
||||
})
|
||||
const editingEnvId = ref(null)
|
||||
|
||||
@@ -53,28 +54,36 @@ const envModalRows = ref(20)
|
||||
const envModalTotal = ref(0)
|
||||
const isEnvModalLoading = ref(false)
|
||||
const envAssetScrollContainer = ref(null)
|
||||
const envAssetScrollSentinel = ref(null)
|
||||
const envAssetPickerFileInput = ref(null)
|
||||
const envUploadProgress = ref(0)
|
||||
const isEnvUploading = ref(false)
|
||||
const envCurrentEnvAssets = ref([])
|
||||
let envAssetObserver = null
|
||||
|
||||
const envSelectedAssets = computed(() => {
|
||||
// We check against all known assets or just the ones in picker
|
||||
// Since picker is for the character, we can look into characterAssets too
|
||||
return [...characterAssets.value, ...envModalAssets.value]
|
||||
.filter((a, index, self) => self.findIndex(t => t.id === a.id) === index) // Unique
|
||||
.filter(a => envForm.value.asset_ids.includes(a.id))
|
||||
// We check against all known assets, picker assets and current environment assets
|
||||
return [...characterAssets.value, ...envModalAssets.value, ...envCurrentEnvAssets.value]
|
||||
.filter((a, index, self) => self.findIndex(t => (t.id || t._id) === (a.id || a._id)) === index) // Unique
|
||||
.filter(a => envForm.value.asset_ids.includes(a.id) || (a._id && envForm.value.asset_ids.includes(a._id)))
|
||||
})
|
||||
|
||||
const loadEnvModalAssets = async (isNewTab = false) => {
|
||||
if (isEnvModalLoading.value) return
|
||||
isEnvModalLoading.value = true
|
||||
|
||||
if (isNewTab) {
|
||||
envModalFirst.value = 0
|
||||
envModalAssets.value = []
|
||||
} else {
|
||||
// Increment offset for pagination
|
||||
envModalFirst.value += envModalRows.value
|
||||
}
|
||||
|
||||
if (envModalTotal.value > 0 && envModalFirst.value >= envModalTotal.value && !isNewTab) {
|
||||
return
|
||||
}
|
||||
|
||||
isEnvModalLoading.value = true
|
||||
try {
|
||||
const response = await dataService.getAssetsByCharacterId(
|
||||
route.params.id,
|
||||
@@ -89,14 +98,15 @@ const loadEnvModalAssets = async (isNewTab = false) => {
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load env modal assets', e)
|
||||
// Rollback offset on failure if not first page
|
||||
if (!isNewTab) envModalFirst.value -= envModalRows.value
|
||||
} finally {
|
||||
isEnvModalLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleEnvAssetInfiniteScroll = (entries) => {
|
||||
if (entries[0].isIntersecting && !isEnvModalLoading.value && envModalAssets.value.length < envModalTotal.value) {
|
||||
envModalFirst.value += envModalRows.value
|
||||
if (entries[0].isIntersecting && !isEnvModalLoading.value && (envModalTotal.value === 0 || envModalAssets.value.length < envModalTotal.value)) {
|
||||
loadEnvModalAssets()
|
||||
}
|
||||
}
|
||||
@@ -128,8 +138,14 @@ watch(envAssetPickerTab, () => {
|
||||
|
||||
const toggleEnvAssetSelection = (id) => {
|
||||
const idx = envForm.value.asset_ids.indexOf(id)
|
||||
if (idx > -1) envForm.value.asset_ids.splice(idx, 1)
|
||||
else envForm.value.asset_ids.push(id)
|
||||
if (idx > -1) {
|
||||
envForm.value.asset_ids.splice(idx, 1)
|
||||
const listIdx = envForm.value.assets_list.indexOf(id)
|
||||
if (listIdx > -1) envForm.value.assets_list.splice(listIdx, 1)
|
||||
} else {
|
||||
envForm.value.asset_ids.push(id)
|
||||
envForm.value.assets_list.push(id)
|
||||
}
|
||||
}
|
||||
|
||||
const triggerEnvAssetUpload = () => {
|
||||
@@ -154,6 +170,7 @@ const handleEnvAssetUpload = async (event) => {
|
||||
if (response && response.id) {
|
||||
if (!envForm.value.asset_ids.includes(response.id)) {
|
||||
envForm.value.asset_ids.push(response.id)
|
||||
envForm.value.assets_list.push(response.id)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -167,7 +184,11 @@ const handleEnvAssetUpload = async (event) => {
|
||||
|
||||
const removeEnvAsset = (id) => {
|
||||
const idx = envForm.value.asset_ids.indexOf(id)
|
||||
if (idx > -1) envForm.value.asset_ids.splice(idx, 1)
|
||||
if (idx > -1) {
|
||||
envForm.value.asset_ids.splice(idx, 1)
|
||||
const listIdx = envForm.value.assets_list.indexOf(id)
|
||||
if (listIdx > -1) envForm.value.assets_list.splice(listIdx, 1)
|
||||
}
|
||||
}
|
||||
|
||||
const loadEnvironments = async () => {
|
||||
@@ -179,18 +200,41 @@ const loadEnvironments = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const openEnvModal = (env = null) => {
|
||||
const openEnvModal = async (env = null) => {
|
||||
envCurrentEnvAssets.value = []
|
||||
if (env) {
|
||||
editingEnvId.value = env.id || env._id
|
||||
const initialAssets = [...(env.asset_ids || [])]
|
||||
envForm.value = {
|
||||
name: env.name,
|
||||
asset_ids: env.asset_ids || []
|
||||
asset_ids: initialAssets,
|
||||
assets_list: [...initialAssets]
|
||||
}
|
||||
|
||||
// Fetch current environment assets if not already in memory
|
||||
if (initialAssets.length > 0) {
|
||||
const missingIds = initialAssets.filter(id =>
|
||||
!characterAssets.value.find(a => (a.id || a._id) === id) &&
|
||||
!envModalAssets.value.find(a => (a.id || a._id) === id)
|
||||
)
|
||||
|
||||
if (missingIds.length > 0) {
|
||||
try {
|
||||
const fetchedAssets = await Promise.all(
|
||||
missingIds.map(id => dataService.getAsset(id))
|
||||
)
|
||||
envCurrentEnvAssets.value = fetchedAssets.filter(a => !!a)
|
||||
} catch (e) {
|
||||
console.error('Failed to fetch missing env assets', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
editingEnvId.value = null
|
||||
envForm.value = {
|
||||
name: '',
|
||||
asset_ids: []
|
||||
asset_ids: [],
|
||||
assets_list: []
|
||||
}
|
||||
}
|
||||
isEnvModalVisible.value = true
|
||||
@@ -202,6 +246,7 @@ const saveEnvironment = async () => {
|
||||
...envForm.value,
|
||||
character_id: route.params.id
|
||||
}
|
||||
console.log('Saving environment with payload:', payload)
|
||||
if (editingEnvId.value) {
|
||||
await dataService.updateEnvironment(editingEnvId.value, payload)
|
||||
} else {
|
||||
@@ -1048,7 +1093,7 @@ const handleGenerate = async () => {
|
||||
<div v-if="sendToTelegram && !isTelegramIdSaved"
|
||||
class="animate-in fade-in slide-in-from-top-1 duration-200">
|
||||
<InputText v-model="telegramId" placeholder="Enter Telegram ID"
|
||||
class="w-full !text-[10px] !py-1" @blur="saveTelegramId" />
|
||||
class="w-full !text-[16px] !py-1" @blur="saveTelegramId" />
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mt-1">
|
||||
<Checkbox v-model="useProfileImage" :binary="true"
|
||||
@@ -1572,11 +1617,11 @@ const handleGenerate = async () => {
|
||||
</div>
|
||||
|
||||
<div v-if="envSelectedAssets.length > 0" class="flex flex-wrap gap-2 p-3 bg-slate-900/50 rounded-xl border border-white/5">
|
||||
<div v-for="asset in envSelectedAssets" :key="asset.id"
|
||||
<div v-for="asset in envSelectedAssets" :key="asset.id || asset._id"
|
||||
class="relative w-12 h-12 rounded overflow-hidden border border-violet-500/50 group">
|
||||
<img :src="API_URL + asset.url + '?thumbnail=true'"
|
||||
class="w-full h-full object-cover" />
|
||||
<div @click="removeEnvAsset(asset.id)"
|
||||
<div @click="removeEnvAsset(asset.id || asset._id)"
|
||||
class="absolute inset-0 bg-black/60 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity cursor-pointer">
|
||||
<i class="pi pi-times text-white text-[10px]"></i>
|
||||
</div>
|
||||
@@ -1632,12 +1677,12 @@ const handleGenerate = async () => {
|
||||
|
||||
<div ref="envAssetScrollContainer" class="flex-1 overflow-y-auto p-1 text-slate-100 custom-scrollbar">
|
||||
<div v-if="envModalAssets.length > 0" class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-4">
|
||||
<div v-for="asset in envModalAssets" :key="asset.id" @click="toggleEnvAssetSelection(asset.id)"
|
||||
<div v-for="asset in envModalAssets" :key="asset.id || asset._id" @click="toggleEnvAssetSelection(asset.id || asset._id)"
|
||||
class="aspect-square rounded-xl overflow-hidden cursor-pointer relative border transition-all"
|
||||
:class="envForm.asset_ids.includes(asset.id) ? 'border-violet-500 ring-2 ring-violet-500/20' : 'border-white/10 hover:border-white/30'">
|
||||
:class="(envForm.asset_ids.includes(asset.id) || (asset._id && envForm.asset_ids.includes(asset._id))) ? 'border-violet-500 ring-2 ring-violet-500/20' : 'border-white/10 hover:border-white/30'">
|
||||
<img :src="API_URL + asset.url + '?thumbnail=true'"
|
||||
class="w-full h-full object-cover" />
|
||||
<div v-if="envForm.asset_ids.includes(asset.id)"
|
||||
<div v-if="envForm.asset_ids.includes(asset.id) || (asset._id && envForm.asset_ids.includes(asset._id))"
|
||||
class="absolute inset-0 bg-violet-600/30 flex items-center justify-center">
|
||||
<div class="bg-violet-600 rounded-full p-1 shadow-lg">
|
||||
<i class="pi pi-check text-white text-xs font-bold"></i>
|
||||
|
||||
@@ -865,27 +865,27 @@ const confirmAddToAlbum = async () => {
|
||||
<div class="flex items-center gap-1.5">
|
||||
<Dropdown v-model="filterCharacter" :options="characters" optionLabel="name"
|
||||
placeholder="All Characters" showClear
|
||||
class="!w-40 !bg-slate-800/60 !border-white/10 !text-white !rounded-lg !text-[10px]" :pt="{
|
||||
class="!w-40 !bg-slate-800/60 !border-white/10 !text-white !rounded-lg !text-[16px]" :pt="{
|
||||
root: { class: '!bg-slate-800/60 !h-7' },
|
||||
input: { class: '!text-white !text-[10px] !py-0.5 !px-2' },
|
||||
input: { class: '!text-white !text-[16px] !py-0.5 !px-2' },
|
||||
trigger: { class: '!text-slate-400 !w-5' },
|
||||
panel: { class: '!bg-slate-800 !border-white/10' },
|
||||
item: { class: '!text-slate-300 hover:!bg-white/10 hover:!text-white !text-[10px] !py-1' },
|
||||
item: { class: '!text-slate-300 hover:!bg-white/10 hover:!text-white !text-[16px] !py-1' },
|
||||
clearIcon: { class: '!text-slate-400 hover:!text-white !text-[8px]' }
|
||||
}">
|
||||
<template #value="slotProps">
|
||||
<div v-if="slotProps.value" class="flex items-center gap-1">
|
||||
<img v-if="slotProps.value.avatar_image" :src="API_URL + slotProps.value.avatar_image"
|
||||
class="w-4 h-4 rounded-full object-cover" />
|
||||
<span class="text-[10px]">{{ slotProps.value.name }}</span>
|
||||
<span class="text-[16px]">{{ slotProps.value.name }}</span>
|
||||
</div>
|
||||
<span v-else class="text-[10px] text-slate-400">{{ slotProps.placeholder }}</span>
|
||||
<span v-else class="text-[16px] text-slate-400">{{ slotProps.placeholder }}</span>
|
||||
</template>
|
||||
<template #option="slotProps">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<img v-if="slotProps.option.avatar_image" :src="API_URL + slotProps.option.avatar_image"
|
||||
class="w-5 h-5 rounded-full object-cover" />
|
||||
<span class="text-[10px]">{{ slotProps.option.name }}</span>
|
||||
<span class="text-[16px]">{{ slotProps.option.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</Dropdown>
|
||||
@@ -1365,7 +1365,7 @@ const confirmAddToAlbum = async () => {
|
||||
</div>
|
||||
<div v-if="sendToTelegram" class="animate-in fade-in slide-in-from-top-1">
|
||||
<InputText v-model="telegramId" placeholder="Telegram ID"
|
||||
class="w-full !text-xs !bg-slate-900 !border-white/10 !text-white !py-1.5" />
|
||||
class="w-full !text-[16px] !bg-slate-900 !border-white/10 !text-white !py-1.5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -918,7 +918,7 @@ watch(viewMode, (v) => {
|
||||
<div class="flex items-center gap-2">
|
||||
<div v-if="isEditingName" class="flex items-center gap-2">
|
||||
<InputText v-model="editableName"
|
||||
class="idea-name-input !bg-slate-800 !border-violet-500/50 !text-white !py-0.5 !h-7 !text-sm !font-bold"
|
||||
class="idea-name-input !bg-slate-800 !border-violet-500/50 !text-white !py-0.5 !h-7 !text-[16px] !font-bold"
|
||||
@keyup.enter="saveName"
|
||||
@blur="saveName"
|
||||
/>
|
||||
@@ -1176,7 +1176,7 @@ watch(viewMode, (v) => {
|
||||
</div>
|
||||
</div>
|
||||
<Textarea v-model="prompt" rows="2" placeholder="Describe what you want to create..."
|
||||
class="w-full !h-28 bg-slate-800 !text-sm border-white/10 text-white rounded-lg p-2 focus:border-violet-500 focus:ring-1 focus:ring-violet-500/50 transition-all resize-none shadow-inner" />
|
||||
class="w-full !h-28 bg-slate-800 !text-[16px] border-white/10 text-white rounded-lg p-2 focus:border-violet-500 focus:ring-1 focus:ring-violet-500/50 transition-all resize-none shadow-inner" />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col md:flex-row gap-2">
|
||||
@@ -1340,7 +1340,7 @@ watch(viewMode, (v) => {
|
||||
</div>
|
||||
<div v-if="sendToTelegram" class="animate-in fade-in slide-in-from-top-1">
|
||||
<InputText v-model="telegramId" placeholder="Telegram ID"
|
||||
class="w-full !text-xs !bg-slate-900 !border-white/10 !text-white !py-1.5" />
|
||||
class="w-full !text-[16px] !bg-slate-900 !border-white/10 !text-white !py-1.5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -437,7 +437,7 @@ const handleAssetPickerUpload = async (event) => {
|
||||
</div>
|
||||
<Textarea v-model="prompt" rows="2"
|
||||
placeholder="Describe what you want to create... (Auto-starts new session)"
|
||||
class="w-full !h-28 bg-slate-800 !text-sm border-white/10 text-white rounded-lg p-2 focus:border-violet-500 focus:ring-1 focus:ring-violet-500/50 transition-all resize-none shadow-inner" />
|
||||
class="w-full !h-28 bg-slate-800 !text-[16px] border-white/10 text-white rounded-lg p-2 focus:border-violet-500 focus:ring-1 focus:ring-violet-500/50 transition-all resize-none shadow-inner" />
|
||||
</div>
|
||||
|
||||
<!-- Character & Assets Row -->
|
||||
@@ -598,7 +598,7 @@ const handleAssetPickerUpload = async (event) => {
|
||||
</div>
|
||||
<div v-if="sendToTelegram" class="animate-in fade-in slide-in-from-top-1">
|
||||
<InputText v-model="telegramId" placeholder="Telegram ID"
|
||||
class="w-full !text-xs !bg-slate-900 !border-white/10 !text-white !py-1.5" />
|
||||
class="w-full !text-[16px] !bg-slate-900 !border-white/10 !text-white !py-1.5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -546,7 +546,7 @@ onMounted(() => {
|
||||
<div v-if="sendToTelegram && !isTelegramIdSaved"
|
||||
class="animate-in fade-in slide-in-from-top-1 duration-200">
|
||||
<InputText v-model="telegramId" placeholder="Enter Telegram ID"
|
||||
class="w-full !text-xs !py-1.5" @blur="saveTelegramId" />
|
||||
class="w-full !text-[16px] !py-1.5" @blur="saveTelegramId" />
|
||||
<small class="text-[10px] text-slate-500 block mt-0.5">ID will be saved for future
|
||||
use</small>
|
||||
</div>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<div v-if="isOwner" class="mb-6">
|
||||
<div class="flex gap-2">
|
||||
<InputText v-model="inviteUsername" placeholder="Username to add"
|
||||
class="w-full p-inputtext-sm" @keyup.enter="addMember" />
|
||||
class="w-full" @keyup.enter="addMember" />
|
||||
<Button label="Add" icon="pi pi-user-plus" size="small" @click="addMember"
|
||||
:loading="inviting" :disabled="!inviteUsername.trim()" />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user