mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-20 15:19:41 +08:00
refactor: migrate page-specific action buttons to dynamic FABs for PWA mode compatibility
This commit is contained in:
@@ -1031,7 +1031,7 @@ export default {
|
||||
doubanGlobalTVRankings: 'Douban Global TV Rankings',
|
||||
noCategoryContent: 'No content to display in current category',
|
||||
configureContent: 'Configure Display Content',
|
||||
customizeContent: 'Customize Content',
|
||||
customizeContent: 'Customize Recommendations',
|
||||
selectContentToDisplay: 'Select content you want to display on the page',
|
||||
selectAll: 'Select All',
|
||||
selectNone: 'Select None',
|
||||
@@ -2959,7 +2959,7 @@ export default {
|
||||
},
|
||||
transferHistory: {
|
||||
title: 'Transfer History',
|
||||
searchPlaceholder: 'Search transfer records',
|
||||
searchPlaceholder: 'Search (supports * ? wildcards)',
|
||||
titleColumn: 'Title',
|
||||
pathColumn: 'Path',
|
||||
modeColumn: 'Mode',
|
||||
|
||||
@@ -1025,7 +1025,7 @@ export default {
|
||||
doubanGlobalTVRankings: '豆瓣全球剧集榜',
|
||||
noCategoryContent: '当前分类下没有可显示的内容',
|
||||
configureContent: '设置显示内容',
|
||||
customizeContent: '自定义内容',
|
||||
customizeContent: '自定义推荐',
|
||||
selectContentToDisplay: '选择您想在页面显示的内容',
|
||||
selectAll: '全选',
|
||||
selectNone: '全不选',
|
||||
@@ -2904,7 +2904,7 @@ export default {
|
||||
},
|
||||
transferHistory: {
|
||||
title: '转移历史',
|
||||
searchPlaceholder: '搜索转移记录',
|
||||
searchPlaceholder: '搜索(支持 * ? 通配符)',
|
||||
titleColumn: '标题',
|
||||
pathColumn: '路径',
|
||||
modeColumn: '转移方式',
|
||||
|
||||
@@ -1026,7 +1026,7 @@ export default {
|
||||
doubanGlobalTVRankings: '豆瓣全球劇集榜',
|
||||
noCategoryContent: '當前分類下沒有可顯示的內容',
|
||||
configureContent: '設置顯示內容',
|
||||
customizeContent: '自定義內容',
|
||||
customizeContent: '自定義推薦',
|
||||
selectContentToDisplay: '選擇您想在頁面顯示的內容',
|
||||
selectAll: '全選',
|
||||
selectNone: '全不選',
|
||||
@@ -2906,7 +2906,7 @@ export default {
|
||||
},
|
||||
transferHistory: {
|
||||
title: '轉移歷史',
|
||||
searchPlaceholder: '搜索轉移記錄',
|
||||
searchPlaceholder: '搜索(支援 * ? 萬用字元)',
|
||||
titleColumn: '標題',
|
||||
pathColumn: '路徑',
|
||||
modeColumn: '轉移方式',
|
||||
|
||||
@@ -5,9 +5,12 @@ import MediaCardSlideView from '@/views/discover/MediaCardSlideView.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import { useDynamicHeaderTab } from '@/composables/useDynamicHeaderTab'
|
||||
import { useDynamicButton } from '@/composables/useDynamicButton'
|
||||
import { usePWA } from '@/composables/usePWA'
|
||||
import { getItemColor, initializeItemColors } from '@/utils/colorUtils'
|
||||
|
||||
const display = useDisplay()
|
||||
const { appMode } = usePWA()
|
||||
|
||||
// 国际化
|
||||
const { t } = useI18n()
|
||||
@@ -21,6 +24,10 @@ const currentCategory = ref(t('recommend.all'))
|
||||
// 使用动态标签页
|
||||
const { registerHeaderTab } = useDynamicHeaderTab()
|
||||
|
||||
function openRecommendSettings() {
|
||||
dialog.value = true
|
||||
}
|
||||
|
||||
const viewList = reactive<{ apipath: string; linkurl: string; title: string; type: string }[]>([
|
||||
{
|
||||
apipath: 'recommend/tmdb_trending',
|
||||
@@ -218,17 +225,12 @@ const categoryItems = computed(() => [
|
||||
registerHeaderTab({
|
||||
items: categoryItems,
|
||||
modelValue: currentCategory,
|
||||
appendButtons: [
|
||||
{
|
||||
icon: 'mdi-tune',
|
||||
variant: 'text',
|
||||
color: 'grey',
|
||||
class: 'settings-icon-button',
|
||||
action: () => {
|
||||
dialog.value = true
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
useDynamicButton({
|
||||
icon: 'mdi-tune',
|
||||
onClick: openRecommendSettings,
|
||||
show: computed(() => appMode.value),
|
||||
})
|
||||
|
||||
// 页面是否准备就绪
|
||||
@@ -346,7 +348,19 @@ onActivated(async () => {
|
||||
|
||||
<!-- 快速滚动到顶部按钮 -->
|
||||
<Teleport to="body" v-if="route.path === '/recommend'">
|
||||
<VScrollToTopBtn />
|
||||
<div v-if="!appMode" class="compact-fab-stack">
|
||||
<VFab
|
||||
icon="mdi-tune"
|
||||
color="primary"
|
||||
appear
|
||||
class="compact-fab compact-fab--primary"
|
||||
@click="openRecommendSettings"
|
||||
/>
|
||||
</div>
|
||||
</Teleport>
|
||||
|
||||
<Teleport to="body" v-if="route.path === '/recommend'">
|
||||
<VScrollToTopBtn :offset-fab="!appMode" />
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -11,11 +11,15 @@ import TorrentFilterBar from '@/components/filter/TorrentFilterBar.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useGlobalSettingsStore } from '@/stores/global'
|
||||
import { useTorrentFilter, type FilterState } from '@/composables/useTorrentFilter'
|
||||
import { useDynamicButton } from '@/composables/useDynamicButton'
|
||||
import { usePWA } from '@/composables/usePWA'
|
||||
import { useToast } from 'vue-toastification'
|
||||
|
||||
// 国际化
|
||||
const { t } = useI18n()
|
||||
|
||||
const { appMode } = usePWA()
|
||||
|
||||
// 提示框
|
||||
const toast = useToast()
|
||||
|
||||
@@ -225,6 +229,19 @@ const filteredCardDataList = ref<Array<SearchTorrent>>([])
|
||||
// 是否刷新过
|
||||
const isRefreshed = ref(false)
|
||||
|
||||
const viewToggleIcon = computed(() => (viewType.value === 'card' ? 'mdi-view-list-outline' : 'mdi-view-grid-outline'))
|
||||
|
||||
// 搜索结果视图切换收纳到页面动态按钮中,和仪表盘的设置按钮保持一致。
|
||||
function toggleViewType() {
|
||||
changeViewType(viewType.value === 'card' ? 'row' : 'card')
|
||||
}
|
||||
|
||||
useDynamicButton({
|
||||
icon: viewToggleIcon,
|
||||
onClick: toggleViewType,
|
||||
show: computed(() => appMode.value && isRefreshed.value),
|
||||
})
|
||||
|
||||
// 是否正在重新搜索
|
||||
const isRefreshing = ref(false)
|
||||
|
||||
@@ -1211,18 +1228,6 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 重新设计的视图切换按钮 -->
|
||||
<div class="view-toggle-container">
|
||||
<div class="view-toggle-buttons">
|
||||
<div class="active-indicator" :class="viewType"></div>
|
||||
<button class="view-toggle-btn" :class="{ active: viewType === 'card' }" @click="changeViewType('card')">
|
||||
<VIcon icon="mdi-view-grid-outline" :color="viewType === 'card' ? 'primary' : undefined" />
|
||||
</button>
|
||||
<button class="view-toggle-btn" :class="{ active: viewType === 'row' }" @click="changeViewType('row')">
|
||||
<VIcon icon="mdi-view-list-outline" :color="viewType === 'row' ? 'primary' : undefined" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</VCard>
|
||||
|
||||
<!-- 搜索结果 -->
|
||||
@@ -1328,9 +1333,22 @@ onUnmounted(() => {
|
||||
|
||||
<!-- 初始加载状态 -->
|
||||
<LoadingBanner v-else-if="!isRefreshed && !isSearchLoading" />
|
||||
|
||||
<Teleport to="body" v-if="route.path === '/resource'">
|
||||
<div v-if="isRefreshed && !appMode" class="compact-fab-stack">
|
||||
<VFab
|
||||
:icon="viewToggleIcon"
|
||||
color="primary"
|
||||
appear
|
||||
class="compact-fab compact-fab--primary"
|
||||
@click="toggleViewType"
|
||||
/>
|
||||
</div>
|
||||
</Teleport>
|
||||
|
||||
<!-- 滚动到顶部按钮 -->
|
||||
<Teleport to="body" v-if="route.path === '/resource'">
|
||||
<VScrollToTopBtn />
|
||||
<VScrollToTopBtn :offset-fab="isRefreshed && !appMode" />
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1465,58 +1483,6 @@ onUnmounted(() => {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
/* 重新设计的视图切换按钮 */
|
||||
.view-toggle-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.view-toggle-buttons {
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding: 4px;
|
||||
border-radius: 8px;
|
||||
background-color: rgba(var(--v-theme-surface-variant), 0.1);
|
||||
isolation: isolate; /* Create new stacking context */
|
||||
}
|
||||
|
||||
.active-indicator {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
border-radius: 6px;
|
||||
background-color: rgb(var(--v-theme-surface));
|
||||
block-size: 36px;
|
||||
box-shadow:
|
||||
0 1px 3px rgba(0, 0, 0, 12%),
|
||||
0 1px 2px rgba(0, 0, 0, 24%);
|
||||
inline-size: 40px;
|
||||
inset-block-start: 4px;
|
||||
inset-inline-start: 4px;
|
||||
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.active-indicator.row {
|
||||
transform: translateX(40px);
|
||||
}
|
||||
|
||||
.view-toggle-btn {
|
||||
position: relative;
|
||||
z-index: 2; /* Sit on top of indicator */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
background: transparent;
|
||||
block-size: 36px;
|
||||
cursor: pointer;
|
||||
inline-size: 40px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.view-toggle-btn:hover:not(.active) {
|
||||
border-radius: 6px;
|
||||
background-color: rgba(var(--v-theme-primary), 0.05);
|
||||
}
|
||||
|
||||
/* 重新搜索按钮 */
|
||||
.refresh-search-btn {
|
||||
border-radius: 8px !important;
|
||||
@@ -1690,30 +1656,6 @@ onUnmounted(() => {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.view-toggle-container {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.view-toggle-buttons {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.active-indicator {
|
||||
block-size: 32px;
|
||||
inline-size: 36px;
|
||||
inset-block-start: 2px;
|
||||
inset-inline-start: 2px;
|
||||
}
|
||||
|
||||
.active-indicator.row {
|
||||
transform: translateX(36px);
|
||||
}
|
||||
|
||||
.view-toggle-btn {
|
||||
block-size: 32px;
|
||||
inline-size: 36px;
|
||||
}
|
||||
|
||||
.refresh-search-btn {
|
||||
block-size: 36px !important;
|
||||
inline-size: 36px !important;
|
||||
|
||||
Reference in New Issue
Block a user