diff --git a/src/assets/base.css b/src/assets/base.css index 8816868..4a88b95 100644 --- a/src/assets/base.css +++ b/src/assets/base.css @@ -58,6 +58,12 @@ font-weight: normal; } +input, +textarea, +select { + font-size: 16px; +} + body { min-height: 100vh; color: var(--color-text); diff --git a/src/assets/main.css b/src/assets/main.css index 411d12c..9fb5f4c 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -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; diff --git a/src/views/CharacterDetailView.vue b/src/views/CharacterDetailView.vue index 1abce55..9b6d04d 100644 --- a/src/views/CharacterDetailView.vue +++ b/src/views/CharacterDetailView.vue @@ -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 () => {
+ class="w-full !text-[16px] !py-1" @blur="saveTelegramId" />
{
-
-
@@ -1632,12 +1677,12 @@ const handleGenerate = async () => {
-
+ :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'"> -
diff --git a/src/views/FlexibleGenerationView.vue b/src/views/FlexibleGenerationView.vue index 5bb8577..c9785a4 100644 --- a/src/views/FlexibleGenerationView.vue +++ b/src/views/FlexibleGenerationView.vue @@ -865,27 +865,27 @@ const confirmAddToAlbum = async () => {
@@ -1365,7 +1365,7 @@ const confirmAddToAlbum = async () => {
+ class="w-full !text-[16px] !bg-slate-900 !border-white/10 !text-white !py-1.5" />
diff --git a/src/views/IdeaDetailView.vue b/src/views/IdeaDetailView.vue index c6f1864..7808bfc 100644 --- a/src/views/IdeaDetailView.vue +++ b/src/views/IdeaDetailView.vue @@ -918,7 +918,7 @@ watch(viewMode, (v) => {
@@ -1176,7 +1176,7 @@ watch(viewMode, (v) => {