mirror of
https://github.com/modrinth/code.git
synced 2026-08-28 10:34:53 +00:00
feat: project page header when visiting from browse (#6630)
* feat: project page header when visiting from browse * fix: lint
This commit is contained in:
@@ -455,9 +455,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "العودة إلى الاستكشاف"
|
"message": "العودة إلى الاستكشاف"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "تثبيت المحتويات الى النموذج"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "جميع الإصدارات"
|
"message": "جميع الإصدارات"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -392,9 +392,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Zpět k Objevování"
|
"message": "Zpět k Objevování"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Nainstalovat obsah do instance"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Všechny verze"
|
"message": "Všechny verze"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -296,9 +296,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Tilbage til udforsk"
|
"message": "Tilbage til udforsk"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Installer indhold til instance"
|
|
||||||
},
|
|
||||||
"app.project.versions.already-installed": {
|
"app.project.versions.already-installed": {
|
||||||
"message": "Allerede installeret"
|
"message": "Allerede installeret"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,9 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Zurück zu Entdecken"
|
"message": "Zurück zu Entdecken"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Inhalt in Instanz installieren"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Alle Versionen"
|
"message": "Alle Versionen"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,9 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Zurück zum Entdecken"
|
"message": "Zurück zum Entdecken"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Inhalt in Instanz installieren"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Alle Versionen"
|
"message": "Alle Versionen"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -494,9 +494,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Back to discover"
|
"message": "Back to discover"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Install content to instance"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "All versions"
|
"message": "All versions"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,9 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Volver al explorador"
|
"message": "Volver al explorador"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Instalar contenido a la instancia"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Todas las versiones"
|
"message": "Todas las versiones"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -296,9 +296,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Volver a descubrir"
|
"message": "Volver a descubrir"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Instalar contenido"
|
|
||||||
},
|
|
||||||
"app.settings.developer-mode-enabled": {
|
"app.settings.developer-mode-enabled": {
|
||||||
"message": "Modo desarrollador activado."
|
"message": "Modo desarrollador activado."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -377,9 +377,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Takaisin sisällön löytöön"
|
"message": "Takaisin sisällön löytöön"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Asenna sisältöä instanssiin"
|
|
||||||
},
|
|
||||||
"app.settings.developer-mode-enabled": {
|
"app.settings.developer-mode-enabled": {
|
||||||
"message": "Kehittäjätila käytössä."
|
"message": "Kehittäjätila käytössä."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,9 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Retour vers la page découvrir"
|
"message": "Retour vers la page découvrir"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Installer du contenu à l'instance"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Toutes les versions"
|
"message": "Toutes les versions"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,9 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Vissza a böngészéshez"
|
"message": "Vissza a böngészéshez"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Tartalom telepítése a profilba"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Összes verzió"
|
"message": "Összes verzió"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -272,9 +272,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Kembali ke halaman pencarian"
|
"message": "Kembali ke halaman pencarian"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Pasang konten ke instans"
|
|
||||||
},
|
|
||||||
"app.settings.developer-mode-enabled": {
|
"app.settings.developer-mode-enabled": {
|
||||||
"message": "Mode pengembang dihidupkan."
|
"message": "Mode pengembang dihidupkan."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -476,9 +476,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Torna a Esplora"
|
"message": "Torna a Esplora"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Installa il contenuto nell'istanza"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Tutte le versioni"
|
"message": "Tutte le versioni"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,21 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "탐색으로 돌아가기"
|
"message": "탐색으로 돌아가기"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "인스턴스에 콘텐츠 설치"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
|
||||||
"message": "모든 버전"
|
|
||||||
},
|
|
||||||
"app.project.version.download-in-browser": {
|
|
||||||
"message": "브라우저에서 다운로드"
|
|
||||||
},
|
|
||||||
"app.project.version.installing": {
|
|
||||||
"message": "설치 중"
|
|
||||||
},
|
|
||||||
"app.project.versions.already-installed": {
|
|
||||||
"message": "이미 설치됨"
|
|
||||||
},
|
|
||||||
"app.settings.developer-mode-enabled": {
|
"app.settings.developer-mode-enabled": {
|
||||||
"message": "개발자 모드가 활성화되었습니다."
|
"message": "개발자 모드가 활성화되었습니다."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -287,9 +287,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Kembali menemukan"
|
"message": "Kembali menemukan"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Pasang kandungan ke dalam pemasangan"
|
|
||||||
},
|
|
||||||
"app.settings.developer-mode-enabled": {
|
"app.settings.developer-mode-enabled": {
|
||||||
"message": "Mod pembangun didayakan."
|
"message": "Mod pembangun didayakan."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,21 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Terug naar Ontdekken"
|
"message": "Terug naar Ontdekken"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Inhoud op instantie installeren"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
|
||||||
"message": "Alle versies"
|
|
||||||
},
|
|
||||||
"app.project.version.download-in-browser": {
|
|
||||||
"message": "Downloaden in de browser"
|
|
||||||
},
|
|
||||||
"app.project.version.installing": {
|
|
||||||
"message": "Wordt geïnstalleerd"
|
|
||||||
},
|
|
||||||
"app.project.versions.already-installed": {
|
|
||||||
"message": "Al geïnstalleerd"
|
|
||||||
},
|
|
||||||
"app.settings.developer-mode-enabled": {
|
"app.settings.developer-mode-enabled": {
|
||||||
"message": "Ontwikkelaarsmodus ingeschakeld."
|
"message": "Ontwikkelaarsmodus ingeschakeld."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -476,9 +476,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Powróć do odkrywania"
|
"message": "Powróć do odkrywania"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Zainstaluj zasoby do instancji"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Wszystkie wersje"
|
"message": "Wszystkie wersje"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,9 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Voltar a descobrir"
|
"message": "Voltar a descobrir"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Instalar conteúdo para a instância"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Todas as versões"
|
"message": "Todas as versões"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -473,9 +473,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Вернуться к поиску"
|
"message": "Вернуться к поиску"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Установка контента в сборку"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Все версии"
|
"message": "Все версии"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,9 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Nazad da otkrivanje"
|
"message": "Nazad da otkrivanje"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Instaliraj sadržaj na instancu"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Sve verzije"
|
"message": "Sve verzije"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -446,9 +446,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Tillbaka till upptäck"
|
"message": "Tillbaka till upptäck"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Installera innehåll till instans"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Alla versioner"
|
"message": "Alla versioner"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -272,9 +272,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "กลับไปที่หน้าค้นหา"
|
"message": "กลับไปที่หน้าค้นหา"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "ติดตั้งเนื้อหาลงสู่อินสแตนซ์"
|
|
||||||
},
|
|
||||||
"app.settings.developer-mode-enabled": {
|
"app.settings.developer-mode-enabled": {
|
||||||
"message": "โหมดนักพัฒนาเปิดอยู่"
|
"message": "โหมดนักพัฒนาเปิดอยู่"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,9 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Keşfete geri dön"
|
"message": "Keşfete geri dön"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "İçeriği kuruluma yükle"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "Tüm sürümler"
|
"message": "Tüm sürümler"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,21 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Повернутися до дослідження"
|
"message": "Повернутися до дослідження"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Установити вміст до профілю"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
|
||||||
"message": "Усі версії"
|
|
||||||
},
|
|
||||||
"app.project.version.download-in-browser": {
|
|
||||||
"message": "Завантажити в браузері"
|
|
||||||
},
|
|
||||||
"app.project.version.installing": {
|
|
||||||
"message": "Установлення"
|
|
||||||
},
|
|
||||||
"app.project.versions.already-installed": {
|
|
||||||
"message": "Уже встановлено"
|
|
||||||
},
|
|
||||||
"app.settings.developer-mode-enabled": {
|
"app.settings.developer-mode-enabled": {
|
||||||
"message": "Увімкнено режим розробника."
|
"message": "Увімкнено режим розробника."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -329,21 +329,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "Quay lại trang Khám Phá"
|
"message": "Quay lại trang Khám Phá"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "Cài đặt nội dung vào phiên bản"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
|
||||||
"message": "Tất cả phiên bản"
|
|
||||||
},
|
|
||||||
"app.project.version.download-in-browser": {
|
|
||||||
"message": "Tải trong trình duyệt"
|
|
||||||
},
|
|
||||||
"app.project.version.installing": {
|
|
||||||
"message": "Đang tải"
|
|
||||||
},
|
|
||||||
"app.project.versions.already-installed": {
|
|
||||||
"message": "Đã có sẵn"
|
|
||||||
},
|
|
||||||
"app.settings.developer-mode-enabled": {
|
"app.settings.developer-mode-enabled": {
|
||||||
"message": "Chế độ nhà phát triển đã được bật."
|
"message": "Chế độ nhà phát triển đã được bật."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,9 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "返回发现页"
|
"message": "返回发现页"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "将内容安装到实例中"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "所有版本"
|
"message": "所有版本"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -479,9 +479,6 @@
|
|||||||
"app.project.install-context.back-to-browse": {
|
"app.project.install-context.back-to-browse": {
|
||||||
"message": "返回瀏覽"
|
"message": "返回瀏覽"
|
||||||
},
|
},
|
||||||
"app.project.install-context.install-content-to-instance": {
|
|
||||||
"message": "將內容安裝至實例"
|
|
||||||
},
|
|
||||||
"app.project.version.all-versions": {
|
"app.project.version.all-versions": {
|
||||||
"message": "所有版本"
|
"message": "所有版本"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ const debugLog = useDebugLogger('Browse')
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const themeStore = useTheming()
|
const themeStore = useTheming()
|
||||||
|
const browseRouteActive = computed(() => route.path.startsWith('/browse/'))
|
||||||
const serverSetupModalRef = ref<InstanceType<typeof CreationFlowModal> | null>(null)
|
const serverSetupModalRef = ref<InstanceType<typeof CreationFlowModal> | null>(null)
|
||||||
const serverInstallContent = createServerInstallContent({ serverSetupModalRef })
|
const serverInstallContent = createServerInstallContent({ serverSetupModalRef })
|
||||||
provideServerInstallContent(serverInstallContent)
|
provideServerInstallContent(serverInstallContent)
|
||||||
@@ -490,6 +491,9 @@ function resetInstanceContext() {
|
|||||||
watch(
|
watch(
|
||||||
() => route.params.projectType as ProjectType,
|
() => route.params.projectType as ProjectType,
|
||||||
async (newType) => {
|
async (newType) => {
|
||||||
|
if (!browseRouteActive.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (isSetupServerContext.value) {
|
if (isSetupServerContext.value) {
|
||||||
enforceSetupModpackRoute(newType)
|
enforceSetupModpackRoute(newType)
|
||||||
if (newType !== 'modpack') return
|
if (newType !== 'modpack') return
|
||||||
@@ -960,6 +964,7 @@ const lockedFilterMessages = computed(() => ({
|
|||||||
const searchState = useBrowseSearch({
|
const searchState = useBrowseSearch({
|
||||||
projectType,
|
projectType,
|
||||||
tags,
|
tags,
|
||||||
|
active: browseRouteActive,
|
||||||
providedFilters: combinedProvidedFilters,
|
providedFilters: combinedProvidedFilters,
|
||||||
search,
|
search,
|
||||||
persistentQueryParams: ['i', 'ai', 'shi', 'sid', 'wid', 'from'],
|
persistentQueryParams: ['i', 'ai', 'shi', 'sid', 'wid', 'from'],
|
||||||
@@ -1035,6 +1040,9 @@ onUnmounted(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
function getProjectBrowseQuery() {
|
function getProjectBrowseQuery() {
|
||||||
|
if (!browseRouteActive.value) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
if (!installContext.value) return undefined
|
if (!installContext.value) return undefined
|
||||||
return {
|
return {
|
||||||
...route.query,
|
...route.query,
|
||||||
@@ -1139,7 +1147,7 @@ provideBrowseManager({
|
|||||||
@browse-modpacks="() => {}"
|
@browse-modpacks="() => {}"
|
||||||
@create="handleServerModpackFlowCreate"
|
@create="handleServerModpackFlowCreate"
|
||||||
/>
|
/>
|
||||||
<Teleport to="#sidebar-teleport-target">
|
<Teleport v-if="browseRouteActive" to="#sidebar-teleport-target">
|
||||||
<BrowseSidebar />
|
<BrowseSidebar />
|
||||||
</Teleport>
|
</Teleport>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -320,10 +320,6 @@ const messages = defineMessages({
|
|||||||
id: 'app.project.install-button.already-installed',
|
id: 'app.project.install-button.already-installed',
|
||||||
defaultMessage: 'This project is already installed',
|
defaultMessage: 'This project is already installed',
|
||||||
},
|
},
|
||||||
installContentToInstance: {
|
|
||||||
id: 'app.project.install-context.install-content-to-instance',
|
|
||||||
defaultMessage: 'Install content to instance',
|
|
||||||
},
|
|
||||||
switchVersion: {
|
switchVersion: {
|
||||||
id: 'app.project.install-button.switch-version',
|
id: 'app.project.install-button.switch-version',
|
||||||
defaultMessage: 'Switch version',
|
defaultMessage: 'Switch version',
|
||||||
@@ -450,7 +446,7 @@ const projectInstallContext = computed(() => {
|
|||||||
iconSrc: instance.value.icon_path ? convertFileSrc(instance.value.icon_path) : null,
|
iconSrc: instance.value.icon_path ? convertFileSrc(instance.value.icon_path) : null,
|
||||||
backUrl: projectBrowseBackUrl.value,
|
backUrl: projectBrowseBackUrl.value,
|
||||||
backLabel: formatMessage(messages.backToBrowse),
|
backLabel: formatMessage(messages.backToBrowse),
|
||||||
heading: formatMessage(messages.installContentToInstance),
|
heading: formatMessage(commonMessages.installingContentLabel),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3476,6 +3476,9 @@
|
|||||||
"project.gallery.title": {
|
"project.gallery.title": {
|
||||||
"message": "Gallery"
|
"message": "Gallery"
|
||||||
},
|
},
|
||||||
|
"project.install-context.back-to-discover": {
|
||||||
|
"message": "Back to discover"
|
||||||
|
},
|
||||||
"project.license.error": {
|
"project.license.error": {
|
||||||
"message": "License text could not be retrieved."
|
"message": "License text could not be retrieved."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -97,6 +97,22 @@
|
|||||||
<CollectionCreateModal ref="modal_collection" :project-ids="[project.id]" />
|
<CollectionCreateModal ref="modal_collection" :project-ids="[project.id]" />
|
||||||
<ModpackScanModal ref="scanModal" :project_id="project.id" />
|
<ModpackScanModal ref="scanModal" :project_id="project.id" />
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="projectInstallContext && !isSettings"
|
||||||
|
ref="stickyInstallHeaderRef"
|
||||||
|
class="sticky top-0 z-20 mx-auto max-w-[80rem] border-0 border-solid border-divider bg-surface-1 px-6 pt-4"
|
||||||
|
:class="[isInstallHeaderStuck ? 'border-t' : '']"
|
||||||
|
>
|
||||||
|
<BrowseInstallHeader
|
||||||
|
:install-context="projectHeaderInstallContext"
|
||||||
|
divider
|
||||||
|
bottom-padding
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<SelectedProjectsFloatingBar
|
||||||
|
v-if="projectInstallContext && !isSettings"
|
||||||
|
:install-context="projectInstallContext"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
class="new-page sidebar"
|
class="new-page sidebar"
|
||||||
:class="{
|
:class="{
|
||||||
@@ -111,7 +127,10 @@
|
|||||||
!flags.alwaysShowChecklistAsPopup,
|
!flags.alwaysShowChecklistAsPopup,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div class="normal-page__header relative my-4">
|
<div
|
||||||
|
class="normal-page__header relative mb-4"
|
||||||
|
:class="projectInstallContext && !isSettings ? 'mt-0' : 'mt-4'"
|
||||||
|
>
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<ModerationProjectNags
|
<ModerationProjectNags
|
||||||
v-if="
|
v-if="
|
||||||
@@ -616,6 +635,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
Admonition,
|
Admonition,
|
||||||
Avatar,
|
Avatar,
|
||||||
|
BrowseInstallHeader,
|
||||||
ButtonStyled,
|
ButtonStyled,
|
||||||
commonMessages,
|
commonMessages,
|
||||||
defineMessages,
|
defineMessages,
|
||||||
@@ -636,11 +656,13 @@ import {
|
|||||||
ProjectSidebarServerInfo,
|
ProjectSidebarServerInfo,
|
||||||
ProjectSidebarTags,
|
ProjectSidebarTags,
|
||||||
provideProjectPageContext,
|
provideProjectPageContext,
|
||||||
|
SelectedProjectsFloatingBar,
|
||||||
TeleportOverflowMenu,
|
TeleportOverflowMenu,
|
||||||
useDebugLogger,
|
useDebugLogger,
|
||||||
useFormatDateTime,
|
useFormatDateTime,
|
||||||
useFormatPrice,
|
useFormatPrice,
|
||||||
useRelativeTime,
|
useRelativeTime,
|
||||||
|
useStickyObserver,
|
||||||
useVIntl,
|
useVIntl,
|
||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
import { capitalizeString, formatProjectType, renderString } from '@modrinth/utils'
|
import { capitalizeString, formatProjectType, renderString } from '@modrinth/utils'
|
||||||
@@ -663,6 +685,7 @@ import { getSignInRouteObj } from '~/composables/auth.ts'
|
|||||||
import { saveFeatureFlags } from '~/composables/featureFlags.ts'
|
import { saveFeatureFlags } from '~/composables/featureFlags.ts'
|
||||||
import { STALE_TIME, STALE_TIME_LONG } from '~/composables/queries/project'
|
import { STALE_TIME, STALE_TIME_LONG } from '~/composables/queries/project'
|
||||||
import { versionQueryOptions } from '~/composables/queries/version'
|
import { versionQueryOptions } from '~/composables/queries/version'
|
||||||
|
import { useServerInstallContent } from '~/composables/use-server-install-content'
|
||||||
import { userCollectProject, userFollowProject } from '~/composables/user.js'
|
import { userCollectProject, userFollowProject } from '~/composables/user.js'
|
||||||
import { injectCurrentProjectId } from '~/providers/current-project.ts'
|
import { injectCurrentProjectId } from '~/providers/current-project.ts'
|
||||||
import { loadChecklistState } from '~/services/moderation-checklist-storage.ts'
|
import { loadChecklistState } from '~/services/moderation-checklist-storage.ts'
|
||||||
@@ -725,6 +748,11 @@ const scanModal = ref()
|
|||||||
|
|
||||||
const projectV3Loaded = computed(() => !projectV3Pending.value || projectV3.value != null)
|
const projectV3Loaded = computed(() => !projectV3Pending.value || projectV3.value != null)
|
||||||
const isServerProject = computed(() => projectV3.value?.minecraft_server != null)
|
const isServerProject = computed(() => projectV3.value?.minecraft_server != null)
|
||||||
|
const stickyInstallHeaderRef = ref(null)
|
||||||
|
const { isStuck: isInstallHeaderStuck } = useStickyObserver(
|
||||||
|
stickyInstallHeaderRef,
|
||||||
|
'ProjectInstallHeader',
|
||||||
|
)
|
||||||
|
|
||||||
const projectEnvironmentModal = useTemplateRef('projectEnvironmentModal')
|
const projectEnvironmentModal = useTemplateRef('projectEnvironmentModal')
|
||||||
|
|
||||||
@@ -780,6 +808,10 @@ const messages = defineMessages({
|
|||||||
defaultMessage:
|
defaultMessage:
|
||||||
'{title} has been archived. {title} will not receive any further updates unless the author decides to unarchive the project.',
|
'{title} has been archived. {title} will not receive any further updates unless the author decides to unarchive the project.',
|
||||||
},
|
},
|
||||||
|
backToDiscover: {
|
||||||
|
id: 'project.install-context.back-to-discover',
|
||||||
|
defaultMessage: 'Back to discover',
|
||||||
|
},
|
||||||
changelogTab: {
|
changelogTab: {
|
||||||
id: 'project.navigation.changelog',
|
id: 'project.navigation.changelog',
|
||||||
defaultMessage: 'Changelog',
|
defaultMessage: 'Changelog',
|
||||||
@@ -1029,6 +1061,51 @@ const project = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const routeProjectType = computed(() =>
|
||||||
|
Array.isArray(route.params.type) ? route.params.type[0] : route.params.type,
|
||||||
|
)
|
||||||
|
const projectInstallType = computed(() => ({
|
||||||
|
id: project.value?.actualProjectType ?? routeProjectType.value,
|
||||||
|
}))
|
||||||
|
const serverInstallModalRef = ref(null)
|
||||||
|
const serverInstallDebug = useDebugLogger('ProjectServerInstall')
|
||||||
|
const { installContext: serverBrowseInstallContext } = useServerInstallContent({
|
||||||
|
projectType: projectInstallType,
|
||||||
|
onboardingModalRef: serverInstallModalRef,
|
||||||
|
debug: serverInstallDebug,
|
||||||
|
})
|
||||||
|
const projectDiscoverBackUrl = computed(() => {
|
||||||
|
const discoverType =
|
||||||
|
routeProjectType.value === 'project'
|
||||||
|
? (project.value?.actualProjectType ?? project.value?.project_type ?? 'mod')
|
||||||
|
: (routeProjectType.value ?? project.value?.actualProjectType ?? 'mod')
|
||||||
|
|
||||||
|
return `/discover/${discoverType}s${getInstallContextQueryString(['sid', 'wid', 'from', 'shi'])}`
|
||||||
|
})
|
||||||
|
const projectInstallContext = computed(() => {
|
||||||
|
const context = serverBrowseInstallContext.value
|
||||||
|
if (!context) return null
|
||||||
|
return {
|
||||||
|
...context,
|
||||||
|
backUrl: projectDiscoverBackUrl.value,
|
||||||
|
backLabel: formatMessage(messages.backToDiscover),
|
||||||
|
discardSelectedAndBack: async () => {
|
||||||
|
await (context.clearSelected ?? context.clearQueued)?.()
|
||||||
|
await navigateTo(projectDiscoverBackUrl.value)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const projectHeaderInstallContext = computed(() => {
|
||||||
|
const context = projectInstallContext.value
|
||||||
|
if (!context) return null
|
||||||
|
return {
|
||||||
|
...context,
|
||||||
|
onBack: undefined,
|
||||||
|
selectedProjects: [],
|
||||||
|
isInstallingSelected: false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Use actual project ID for dependent queries (ensures cache consistency)
|
// Use actual project ID for dependent queries (ensures cache consistency)
|
||||||
const projectId = computed(() => projectRaw.value?.id)
|
const projectId = computed(() => projectRaw.value?.id)
|
||||||
|
|
||||||
@@ -2067,6 +2144,32 @@ function triggerDownloadAnimation() {
|
|||||||
setTimeout(() => (overTheTopDownloadAnimation.value = false), 500)
|
setTimeout(() => (overTheTopDownloadAnimation.value = false), 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const INSTALL_CONTEXT_QUERY_KEYS = ['sid', 'wid', 'from', 'shi']
|
||||||
|
|
||||||
|
function getInstallContextQueryString(keys = INSTALL_CONTEXT_QUERY_KEYS) {
|
||||||
|
const params = new URLSearchParams()
|
||||||
|
|
||||||
|
for (const key of keys) {
|
||||||
|
const value = route.query[key]
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
for (const item of value) {
|
||||||
|
if (item != null) {
|
||||||
|
params.append(key, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (value != null) {
|
||||||
|
params.append(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryString = params.toString()
|
||||||
|
return queryString ? `?${queryString}` : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function withInstallContextQuery(path) {
|
||||||
|
return `${path}${getInstallContextQueryString()}`
|
||||||
|
}
|
||||||
|
|
||||||
async function deleteVersion(id) {
|
async function deleteVersion(id) {
|
||||||
if (!id) return
|
if (!id) return
|
||||||
|
|
||||||
@@ -2091,16 +2194,16 @@ const navLinks = computed(() => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: formatMessage(messages.descriptionTab),
|
label: formatMessage(messages.descriptionTab),
|
||||||
href: projectUrl,
|
href: withInstallContextQuery(projectUrl),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: formatMessage(messages.galleryTab),
|
label: formatMessage(messages.galleryTab),
|
||||||
href: `${projectUrl}/gallery`,
|
href: withInstallContextQuery(`${projectUrl}/gallery`),
|
||||||
shown: galleryCount > 0 || !!currentMember.value,
|
shown: galleryCount > 0 || !!currentMember.value,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: formatMessage(messages.changelogTab),
|
label: formatMessage(messages.changelogTab),
|
||||||
href: `${projectUrl}/changelog`,
|
href: withInstallContextQuery(`${projectUrl}/changelog`),
|
||||||
shown:
|
shown:
|
||||||
hasVersions.value &&
|
hasVersions.value &&
|
||||||
projectV3Loaded.value &&
|
projectV3Loaded.value &&
|
||||||
@@ -2109,7 +2212,7 @@ const navLinks = computed(() => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: formatMessage(messages.versionsTab),
|
label: formatMessage(messages.versionsTab),
|
||||||
href: `${projectUrl}/versions`,
|
href: withInstallContextQuery(`${projectUrl}/versions`),
|
||||||
shown:
|
shown:
|
||||||
(hasVersions.value || !!currentMember.value) &&
|
(hasVersions.value || !!currentMember.value) &&
|
||||||
projectV3Loaded.value &&
|
projectV3Loaded.value &&
|
||||||
@@ -2119,7 +2222,7 @@ const navLinks = computed(() => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: formatMessage(messages.moderationTab),
|
label: formatMessage(messages.moderationTab),
|
||||||
href: `${projectUrl}/moderation`,
|
href: withInstallContextQuery(`${projectUrl}/moderation`),
|
||||||
shown: !!currentMember.value,
|
shown: !!currentMember.value,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { commonProjectTypeCategoryMessages, NavTabs, useVIntl } from '@modrinth/
|
|||||||
const { formatMessage } = useVIntl()
|
const { formatMessage } = useVIntl()
|
||||||
|
|
||||||
const flags = useFeatureFlags()
|
const flags = useFeatureFlags()
|
||||||
const cosmetics = useCosmetics()
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const allowTabChanging = computed(() => !route.query.sid)
|
const allowTabChanging = computed(() => !route.query.sid)
|
||||||
@@ -48,15 +47,13 @@ const selectableProjectTypes = [
|
|||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="new-page sidebar" :class="{ 'alt-layout': !cosmetics.rightSearchLayout }">
|
<div class="mx-auto box-border flex w-full max-w-[1280px] flex-col gap-4 px-6 pb-6">
|
||||||
<section class="normal-page__header mb-4 flex flex-col gap-4">
|
<NavTabs
|
||||||
<NavTabs
|
v-if="!flags.projectTypesPrimaryNav && allowTabChanging"
|
||||||
v-if="!flags.projectTypesPrimaryNav && allowTabChanging"
|
:links="selectableProjectTypes"
|
||||||
:links="selectableProjectTypes"
|
replace
|
||||||
replace
|
class="hidden md:flex"
|
||||||
class="hidden md:flex"
|
/>
|
||||||
/>
|
|
||||||
</section>
|
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import { cycleValue } from '@modrinth/utils'
|
|||||||
import { useQueryClient } from '@tanstack/vue-query'
|
import { useQueryClient } from '@tanstack/vue-query'
|
||||||
import { useTimeoutFn } from '@vueuse/core'
|
import { useTimeoutFn } from '@vueuse/core'
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
|
import type { LocationQueryRaw } from 'vue-router'
|
||||||
|
|
||||||
import LogoAnimated from '~/components/brand/LogoAnimated.vue'
|
import LogoAnimated from '~/components/brand/LogoAnimated.vue'
|
||||||
import AdPlaceholder from '~/components/ui/AdPlaceholder.vue'
|
import AdPlaceholder from '~/components/ui/AdPlaceholder.vue'
|
||||||
@@ -55,10 +56,6 @@ const client = injectModrinthClient()
|
|||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
const filtersMenuOpen = ref(false)
|
const filtersMenuOpen = ref(false)
|
||||||
const stickyInstallHeaderRef = ref<HTMLElement | null>(null)
|
|
||||||
|
|
||||||
useStickyObserver(stickyInstallHeaderRef, 'DiscoverInstallHeader')
|
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const cosmetics = useCosmetics()
|
const cosmetics = useCosmetics()
|
||||||
@@ -202,49 +199,83 @@ function getServerModpackContent(project: Labrinth.Search.v3.ResultSearchProject
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
async function search(requestParams: string) {
|
type DiscoverProjectSearchHit = Labrinth.Search.v2.ResultSearchProject & {
|
||||||
|
version_id?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapV3ProjectHit(hit: Labrinth.Search.v3.ResultSearchProject): DiscoverProjectSearchHit {
|
||||||
|
return {
|
||||||
|
...hit,
|
||||||
|
project_type: hit.project_types[0] ?? projectTypeId.value,
|
||||||
|
title: hit.name,
|
||||||
|
description: hit.summary,
|
||||||
|
versions: hit.version_id ? [hit.version_id] : [],
|
||||||
|
latest_version: hit.version_id,
|
||||||
|
icon_url: hit.icon_url ?? '',
|
||||||
|
client_side: 'unknown',
|
||||||
|
server_side: 'unknown',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hostingContextQuery = computed(() => {
|
||||||
|
const query: LocationQueryRaw = {}
|
||||||
|
|
||||||
|
for (const key of ['sid', 'wid', 'from', 'shi']) {
|
||||||
|
const value = route.query[key]
|
||||||
|
if (value != null) {
|
||||||
|
query[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.keys(query).length > 0 ? query : undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
function withHostingContext(path: string) {
|
||||||
|
return hostingContextQuery.value ? { path, query: hostingContextQuery.value } : path
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchSearch(requestParams: string) {
|
||||||
debug('search() called', {
|
debug('search() called', {
|
||||||
requestParams: requestParams.substring(0, 100),
|
requestParams: requestParams.substring(0, 100),
|
||||||
isServer: isServerType.value,
|
isServer: isServerType.value,
|
||||||
projectTypeId: projectTypeId.value,
|
projectTypeId: projectTypeId.value,
|
||||||
})
|
})
|
||||||
const config = useRuntimeConfig()
|
|
||||||
let base = import.meta.server ? config.apiBaseUrl : config.public.apiBaseUrl
|
|
||||||
|
|
||||||
if (isServerType.value) {
|
const raw = await client.request<Labrinth.Search.v3.SearchResults>('/search', {
|
||||||
base = base.replace(/\/v\d\//, '/v3/').replace(/\/v\d$/, '/v3')
|
api: 'labrinth',
|
||||||
}
|
version: 3,
|
||||||
|
method: 'GET',
|
||||||
const url = `${base}search${requestParams}`
|
params: Object.fromEntries(new URLSearchParams(requestParams.replace(/^\?/, ''))),
|
||||||
debug('search() fetching:', url.substring(0, 120))
|
headers: withLabrinthCanaryHeader(),
|
||||||
|
})
|
||||||
const raw = await $fetch<Labrinth.Search.v2.SearchResults | Labrinth.Search.v3.SearchResults>(
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
headers: withLabrinthCanaryHeader(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
debug('search() response', { total_hits: raw.total_hits, hitCount: raw.hits?.length })
|
debug('search() response', { total_hits: raw.total_hits, hitCount: raw.hits?.length })
|
||||||
|
|
||||||
if ('hits_per_page' in raw) {
|
if (isServerType.value) {
|
||||||
// v3 response (servers)
|
|
||||||
return {
|
return {
|
||||||
projectHits: [],
|
projectHits: [],
|
||||||
serverHits: raw.hits as Labrinth.Search.v3.ResultSearchProject[],
|
serverHits: raw.hits,
|
||||||
total_hits: raw.total_hits,
|
total_hits: raw.total_hits,
|
||||||
per_page: raw.hits_per_page,
|
per_page: raw.hits_per_page,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
projectHits: raw.hits as Labrinth.Search.v2.ResultSearchProject[],
|
projectHits: raw.hits.map(mapV3ProjectHit),
|
||||||
serverHits: [],
|
serverHits: [],
|
||||||
total_hits: raw.total_hits,
|
total_hits: raw.total_hits,
|
||||||
per_page: raw.limit,
|
per_page: raw.hits_per_page,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function search(requestParams: string) {
|
||||||
|
return await queryClient.ensureQueryData({
|
||||||
|
queryKey: ['discover', 'search', 'v3', requestParams],
|
||||||
|
queryFn: () => fetchSearch(requestParams),
|
||||||
|
staleTime: 30_000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function getCardActions(
|
function getCardActions(
|
||||||
result: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject,
|
result: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject,
|
||||||
currentProjectType: string,
|
currentProjectType: string,
|
||||||
@@ -424,7 +455,7 @@ watch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
debug('calling initial refreshSearch')
|
debug('calling initial refreshSearch')
|
||||||
searchState.refreshSearch()
|
await searchState.refreshSearch()
|
||||||
|
|
||||||
const ogTitle = computed(() =>
|
const ogTitle = computed(() =>
|
||||||
searchState.query.value
|
searchState.query.value
|
||||||
@@ -462,9 +493,11 @@ provideBrowseManager({
|
|||||||
projectType: projectTypeId,
|
projectType: projectTypeId,
|
||||||
...searchState,
|
...searchState,
|
||||||
getProjectLink: (result: Labrinth.Search.v2.ResultSearchProject) =>
|
getProjectLink: (result: Labrinth.Search.v2.ResultSearchProject) =>
|
||||||
`/${projectType.value?.id ?? 'project'}/${result.slug ? result.slug : result.project_id}`,
|
withHostingContext(
|
||||||
|
`/${projectType.value?.id ?? 'project'}/${result.slug ? result.slug : result.project_id}`,
|
||||||
|
),
|
||||||
getServerProjectLink: (result: Labrinth.Search.v3.ResultSearchProject) =>
|
getServerProjectLink: (result: Labrinth.Search.v3.ResultSearchProject) =>
|
||||||
`/server/${result.slug ?? result.project_id}`,
|
withHostingContext(`/server/${result.slug ?? result.project_id}`),
|
||||||
selectableProjectTypes: computed(() => []),
|
selectableProjectTypes: computed(() => []),
|
||||||
showProjectTypeTabs: computed(() => false),
|
showProjectTypeTabs: computed(() => false),
|
||||||
variant: 'web',
|
variant: 'web',
|
||||||
@@ -504,25 +537,41 @@ provideBrowseManager({
|
|||||||
},
|
},
|
||||||
loadingComponent: LogoAnimated,
|
loadingComponent: LogoAnimated,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const stickyInstallHeaderRef = ref<HTMLElement | null>(null)
|
||||||
|
const { isStuck: isInstallHeaderStuck } = useStickyObserver(
|
||||||
|
stickyInstallHeaderRef,
|
||||||
|
'DiscoverInstallHeader',
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Teleport v-if="flags.searchBackground" to="#absolute-background-teleport">
|
<Teleport v-if="flags.searchBackground" to="#absolute-background-teleport">
|
||||||
<div class="search-background"></div>
|
<div class="search-background"></div>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="installContext"
|
v-if="installContext"
|
||||||
ref="stickyInstallHeaderRef"
|
ref="stickyInstallHeaderRef"
|
||||||
class="normal-page__header browse-install-header-bleed sticky top-0 z-20 mb-4 flex flex-col gap-2 border-0 bg-surface-1 py-3"
|
class="sticky top-0 z-20 -mx-6 border-0 border-solid border-divider bg-surface-1 px-6 pt-4"
|
||||||
|
:class="[isInstallHeaderStuck ? 'border-t' : '']"
|
||||||
>
|
>
|
||||||
<BrowseInstallHeader />
|
<BrowseInstallHeader divider bottom-padding />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SelectedProjectsFloatingBar v-if="installContext" :install-context="installContext" />
|
<SelectedProjectsFloatingBar v-if="installContext" :install-context="installContext" />
|
||||||
<aside class="normal-page__sidebar" :aria-label="formatMessage(commonMessages.filtersLabel)">
|
|
||||||
<AdPlaceholder v-if="!auth.user && !serverData" />
|
<div
|
||||||
<BrowseSidebar />
|
class="grid min-w-0 gap-3"
|
||||||
</aside>
|
:class="
|
||||||
<section class="normal-page__content">
|
cosmetics.rightSearchLayout
|
||||||
<div class="flex flex-col gap-3">
|
? 'lg:grid-cols-[minmax(0,1fr)_18.75rem]'
|
||||||
|
: 'lg:grid-cols-[18.75rem_minmax(0,1fr)]'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<section
|
||||||
|
class="flex min-w-0 flex-col gap-3"
|
||||||
|
:class="cosmetics.rightSearchLayout ? 'lg:order-1' : 'lg:order-2'"
|
||||||
|
>
|
||||||
<BrowsePageLayout>
|
<BrowsePageLayout>
|
||||||
<template #display-mode-icon>
|
<template #display-mode-icon>
|
||||||
<GridIcon v-if="resultsDisplayMode === 'grid'" />
|
<GridIcon v-if="resultsDisplayMode === 'grid'" />
|
||||||
@@ -530,78 +579,34 @@ provideBrowseManager({
|
|||||||
<ListIcon v-else />
|
<ListIcon v-else />
|
||||||
</template>
|
</template>
|
||||||
</BrowsePageLayout>
|
</BrowsePageLayout>
|
||||||
<CreationFlowModal
|
</section>
|
||||||
v-if="currentServerId && projectType?.id === 'modpack'"
|
|
||||||
ref="onboardingModalRef"
|
<aside
|
||||||
:type="fromContext === 'reset-server' ? 'reset-server' : 'server-onboarding'"
|
class="min-w-0"
|
||||||
:available-loaders="['vanilla', 'fabric', 'neoforge', 'forge', 'quilt', 'paper', 'purpur']"
|
:class="cosmetics.rightSearchLayout ? 'lg:order-2' : 'lg:order-1'"
|
||||||
:show-snapshot-toggle="true"
|
:aria-label="formatMessage(commonMessages.filtersLabel)"
|
||||||
:on-back="onOnboardingBack"
|
>
|
||||||
@hide="onOnboardingHide"
|
<BrowseSidebar>
|
||||||
@browse-modpacks="() => {}"
|
<template #prepend>
|
||||||
@create="onModpackFlowCreate"
|
<AdPlaceholder v-if="!auth.user && !serverData" />
|
||||||
/>
|
</template>
|
||||||
</div>
|
</BrowseSidebar>
|
||||||
</section>
|
</aside>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CreationFlowModal
|
||||||
|
v-if="currentServerId && projectType?.id === 'modpack'"
|
||||||
|
ref="onboardingModalRef"
|
||||||
|
:type="fromContext === 'reset-server' ? 'reset-server' : 'server-onboarding'"
|
||||||
|
:available-loaders="['vanilla', 'fabric', 'neoforge', 'forge', 'quilt', 'paper', 'purpur']"
|
||||||
|
:show-snapshot-toggle="true"
|
||||||
|
:on-back="onOnboardingBack"
|
||||||
|
@hide="onOnboardingHide"
|
||||||
|
@browse-modpacks="() => {}"
|
||||||
|
@create="onModpackFlowCreate"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.browse-install-header-bleed {
|
|
||||||
grid-column: 1 / -1;
|
|
||||||
margin-inline: -1.5rem;
|
|
||||||
padding-inline: 0.75rem !important;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
right: 50%;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100vw;
|
|
||||||
border-bottom: 1px solid var(--surface-5);
|
|
||||||
transform: translateX(50%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.normal-page__content {
|
|
||||||
display: contents;
|
|
||||||
|
|
||||||
@media screen and (min-width: 1024px) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.normal-page__sidebar {
|
|
||||||
grid-row: 3;
|
|
||||||
|
|
||||||
@media screen and (min-width: 1024px) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.filters-card {
|
|
||||||
padding: var(--spacing-card-md);
|
|
||||||
|
|
||||||
@media screen and (min-width: 1024px) {
|
|
||||||
padding: var(--spacing-card-lg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-wrapper {
|
|
||||||
grid-row: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination-after {
|
|
||||||
grid-row: 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-results {
|
|
||||||
text-align: center;
|
|
||||||
display: flow-root;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-logo {
|
|
||||||
margin: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-background {
|
.search-background {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 20rem;
|
height: 20rem;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export interface UseBrowseSearchOptions {
|
|||||||
}>
|
}>
|
||||||
providedFilters?: ComputedRef<FilterValue[]>
|
providedFilters?: ComputedRef<FilterValue[]>
|
||||||
environmentOverride?: ComputedRef<EnvironmentSearchOverride | undefined>
|
environmentOverride?: ComputedRef<EnvironmentSearchOverride | undefined>
|
||||||
|
active?: ComputedRef<boolean>
|
||||||
search: (params: string) => Promise<BrowseSearchResponse>
|
search: (params: string) => Promise<BrowseSearchResponse>
|
||||||
persistentQueryParams: string[]
|
persistentQueryParams: string[]
|
||||||
getExtraQueryParams?: () => Record<string, string | undefined>
|
getExtraQueryParams?: () => Record<string, string | undefined>
|
||||||
@@ -74,6 +75,7 @@ export function useBrowseSearch(options: UseBrowseSearchOptions): BrowseSearchSt
|
|||||||
|
|
||||||
debug('init, projectType:', options.projectType.value)
|
debug('init, projectType:', options.projectType.value)
|
||||||
|
|
||||||
|
const active = computed(() => options.active?.value ?? true)
|
||||||
const projectTypes = computed(() => [options.projectType.value] as ProjectType[])
|
const projectTypes = computed(() => [options.projectType.value] as ProjectType[])
|
||||||
const isServerType = computed(() => options.projectType.value === 'server')
|
const isServerType = computed(() => options.projectType.value === 'server')
|
||||||
|
|
||||||
@@ -184,6 +186,13 @@ export function useBrowseSearch(options: UseBrowseSearchOptions): BrowseSearchSt
|
|||||||
let searchVersion = 0
|
let searchVersion = 0
|
||||||
let searchDebounceTimer: ReturnType<typeof setTimeout> | null = null
|
let searchDebounceTimer: ReturnType<typeof setTimeout> | null = null
|
||||||
|
|
||||||
|
function clearSearchDebounce() {
|
||||||
|
if (searchDebounceTimer) {
|
||||||
|
clearTimeout(searchDebounceTimer)
|
||||||
|
searchDebounceTimer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const providedFiltersOrEmpty = computed(() => options.providedFilters?.value ?? [])
|
const providedFiltersOrEmpty = computed(() => options.providedFilters?.value ?? [])
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@@ -209,13 +218,27 @@ export function useBrowseSearch(options: UseBrowseSearchOptions): BrowseSearchSt
|
|||||||
from: oldVal?.substring(0, 80),
|
from: oldVal?.substring(0, 80),
|
||||||
to: newVal?.substring(0, 80),
|
to: newVal?.substring(0, 80),
|
||||||
})
|
})
|
||||||
if (searchDebounceTimer) clearTimeout(searchDebounceTimer)
|
clearSearchDebounce()
|
||||||
|
if (!active.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
searchDebounceTimer = setTimeout(() => {
|
searchDebounceTimer = setTimeout(() => {
|
||||||
refreshSearch()
|
refreshSearch()
|
||||||
}, 200)
|
}, 200)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(active, (isActive, wasActive) => {
|
||||||
|
clearSearchDebounce()
|
||||||
|
if (isActive && wasActive === false) {
|
||||||
|
void refreshSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
async function refreshSearch() {
|
async function refreshSearch() {
|
||||||
|
if (!active.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const version = ++searchVersion
|
const version = ++searchVersion
|
||||||
debug('refreshSearch start', {
|
debug('refreshSearch start', {
|
||||||
version,
|
version,
|
||||||
@@ -233,6 +256,10 @@ export function useBrowseSearch(options: UseBrowseSearchOptions): BrowseSearchSt
|
|||||||
try {
|
try {
|
||||||
const response = await options.search(effectiveRequestParams.value)
|
const response = await options.search(effectiveRequestParams.value)
|
||||||
|
|
||||||
|
if (!active.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (version !== searchVersion) {
|
if (version !== searchVersion) {
|
||||||
debug('refreshSearch stale, discarding', { version, current: searchVersion })
|
debug('refreshSearch stale, discarding', { version, current: searchVersion })
|
||||||
return
|
return
|
||||||
@@ -263,6 +290,10 @@ export function useBrowseSearch(options: UseBrowseSearchOptions): BrowseSearchSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateUrlParams() {
|
function updateUrlParams() {
|
||||||
|
if (!active.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
debug('updateUrlParams', { path: route.path })
|
debug('updateUrlParams', { path: route.path })
|
||||||
const persistentParams: Record<string, string | (string | null)[] | null | undefined> = {}
|
const persistentParams: Record<string, string | (string | null)[] | null | undefined> = {}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user