parent
cae6f12ea0
commit
9952c3a0c1
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -8956,7 +8956,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "theseus"
|
||||
version = "0.9.0-2"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"async-tungstenite",
|
||||
@ -9007,7 +9007,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "theseus_gui"
|
||||
version = "0.9.0-2"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"cocoa 0.25.0",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@modrinth/app-frontend",
|
||||
"private": true,
|
||||
"version": "0.9.0-2",
|
||||
"version": "0.9.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@ -264,13 +264,15 @@ router.afterEach((to) => {
|
||||
forceSidebar.value = to.path.startsWith('/browse') || to.path.startsWith('/project')
|
||||
})
|
||||
|
||||
const currentTimeout = ref(null)
|
||||
watch(
|
||||
showAd,
|
||||
() => {
|
||||
if (!showAd.value) {
|
||||
if (currentTimeout.value) clearTimeout(currentTimeout.value)
|
||||
hide_ads_window(true)
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
currentTimeout.value = setTimeout(() => {
|
||||
init_ads_window(true)
|
||||
}, 400)
|
||||
}
|
||||
@ -441,7 +443,7 @@ function handleAuxClick(e) {
|
||||
<div data-tauri-drag-region class="app-grid-statusbar bg-bg-raised h-[--top-bar-height] flex">
|
||||
<div data-tauri-drag-region class="flex p-3">
|
||||
<ModrinthAppLogo class="h-full w-auto text-contrast pointer-events-none" />
|
||||
<Breadcrumbs />
|
||||
<Breadcrumbs class="pt-[2px]" />
|
||||
</div>
|
||||
<section class="flex ml-auto items-center">
|
||||
<ButtonStyled
|
||||
|
||||
@ -25,6 +25,7 @@ import { showProfileInFolder } from '@/helpers/utils.js'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { handleSevereError } from '@/store/error.js'
|
||||
import { install as installVersion } from '@/store/install.js'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@ -165,13 +166,7 @@ const handleOptionsClick = async (args) => {
|
||||
break
|
||||
}
|
||||
case 'open_link':
|
||||
window.__TAURI_INVOKE__('tauri', {
|
||||
__tauriModule: 'Shell',
|
||||
message: {
|
||||
cmd: 'open',
|
||||
path: `https://modrinth.com/${args.item.project_type}/${args.item.slug}`,
|
||||
},
|
||||
})
|
||||
openUrl(`https://modrinth.com/${args.item.project_type}/${args.item.slug}`)
|
||||
break
|
||||
case 'copy_link':
|
||||
await navigator.clipboard.writeText(
|
||||
|
||||
@ -189,11 +189,12 @@ onUnmounted(() => unlisten())
|
||||
v-else-if="modLoading || installing"
|
||||
v-tooltip="modLoading ? 'Instance is loading...' : 'Installing...'"
|
||||
class="animate-spin w-8 h-8"
|
||||
tabindex="-1"
|
||||
/>
|
||||
<ButtonStyled v-else size="large" color="brand" circular>
|
||||
<button
|
||||
v-tooltip="'Play'"
|
||||
class="transition-all scale-75 group-hover:scale-100 origin-bottom opacity-0 group-hover:opacity-100 card-shadow"
|
||||
class="transition-all scale-75 group-hover:scale-100 group-focus-within:scale-100 origin-bottom opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 card-shadow"
|
||||
@click="(e) => play(e, 'InstanceCard')"
|
||||
@mousehover="checkProcess"
|
||||
>
|
||||
|
||||
@ -16,10 +16,10 @@ const getInstances = async () => {
|
||||
recentInstances.value = profiles
|
||||
.sort((a, b) => {
|
||||
const dateACreated = dayjs(a.created)
|
||||
const dateAPlayed = dayjs(a.last_played)
|
||||
const dateAPlayed = a.last_played ? dayjs(a.last_played) : dayjs(0)
|
||||
|
||||
const dateBCreated = dayjs(b.created)
|
||||
const dateBPlayed = dayjs(b.last_played)
|
||||
const dateBPlayed = b.last_played ? dayjs(b.last_played) : dayjs(0)
|
||||
|
||||
const dateA = dateACreated.isAfter(dateAPlayed) ? dateACreated : dateAPlayed
|
||||
const dateB = dateBCreated.isAfter(dateBPlayed) ? dateBCreated : dateBPlayed
|
||||
@ -35,8 +35,10 @@ const getInstances = async () => {
|
||||
|
||||
await getInstances()
|
||||
|
||||
const unlistenProfile = await profile_listener(async () => {
|
||||
await getInstances()
|
||||
const unlistenProfile = await profile_listener(async (event) => {
|
||||
if (event.event !== 'synced') {
|
||||
await getInstances()
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@ -50,6 +52,7 @@ onUnmounted(() => {
|
||||
:key="instance.id"
|
||||
v-tooltip.right="instance.name"
|
||||
:to="`/instance/${encodeURIComponent(instance.path)}`"
|
||||
class="relative"
|
||||
>
|
||||
<Avatar
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : null"
|
||||
@ -59,7 +62,7 @@ onUnmounted(() => {
|
||||
/>
|
||||
<div
|
||||
v-if="instance.install_stage !== 'installed'"
|
||||
class="absolute inset-0 flex items-center justify-center"
|
||||
class="absolute inset-0 flex items-center justify-center z-10"
|
||||
>
|
||||
<SpinnerIcon class="animate-spin w-4 h-4" />
|
||||
</div>
|
||||
|
||||
@ -1,14 +1,10 @@
|
||||
<template>
|
||||
<div class="action-groups">
|
||||
<Button
|
||||
v-if="currentLoadingBars.length > 0"
|
||||
ref="infoButton"
|
||||
icon-only
|
||||
class="icon-button show-card-icon"
|
||||
@click="toggleCard()"
|
||||
>
|
||||
<DownloadIcon />
|
||||
</Button>
|
||||
<ButtonStyled v-if="currentLoadingBars.length > 0" color="brand" type="transparent" circular>
|
||||
<button ref="infoButton" @click="toggleCard()">
|
||||
<DownloadIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<div v-if="offline" class="status">
|
||||
<UnplugIcon />
|
||||
<div class="running-text">
|
||||
@ -41,15 +37,6 @@
|
||||
<Button v-tooltip="'View logs'" icon-only class="icon-button" @click="goToTerminal()">
|
||||
<TerminalSquareIcon />
|
||||
</Button>
|
||||
<Button
|
||||
v-if="currentLoadingBars.length > 0"
|
||||
ref="infoButton"
|
||||
icon-only
|
||||
class="icon-button show-card-icon"
|
||||
@click="toggleCard()"
|
||||
>
|
||||
<DownloadIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<div v-else class="status">
|
||||
<span class="circle stopped" />
|
||||
@ -111,7 +98,7 @@ import {
|
||||
DropdownIcon,
|
||||
UnplugIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Button, Card } from '@modrinth/ui'
|
||||
import { Button, ButtonStyled, Card } from '@modrinth/ui'
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { get_all as getRunningProcesses, kill as killProcess } from '@/helpers/process'
|
||||
import { loading_listener, process_listener } from '@/helpers/events'
|
||||
@ -409,10 +396,6 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.show-card-icon {
|
||||
color: var(--color-brand);
|
||||
}
|
||||
|
||||
.download-enter-active,
|
||||
.download-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
|
||||
@ -157,13 +157,13 @@ const installing = ref(false)
|
||||
async function install() {
|
||||
installing.value = true
|
||||
await installVersion(
|
||||
props.project.project_id,
|
||||
props.project.project_id ?? props.project.id,
|
||||
null,
|
||||
props.instance ? props.instance.path : null,
|
||||
'SearchCard',
|
||||
() => {
|
||||
installing.value = false
|
||||
emit('install', props.project.project_id)
|
||||
emit('install', props.project.project_id ?? props.project.id)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, ref, shallowRef, watch } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import { SearchIcon, XIcon } from '@modrinth/assets'
|
||||
import { SearchIcon, XIcon, ClipboardCopyIcon, GlobeIcon, ExternalIcon } from '@modrinth/assets'
|
||||
import type { Category, GameVersion, Platform, ProjectType, SortType, Tags } from '@modrinth/ui'
|
||||
import {
|
||||
SearchFilterControl,
|
||||
@ -25,6 +25,8 @@ import NavTabs from '@/components/ui/NavTabs.vue'
|
||||
import type Instance from '@/components/ui/Instance.vue'
|
||||
import InstanceIndicator from '@/components/ui/InstanceIndicator.vue'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
@ -351,6 +353,36 @@ const messages = defineMessages({
|
||||
},
|
||||
})
|
||||
|
||||
const options = ref(null)
|
||||
const handleRightClick = (event, result) => {
|
||||
options.value.showMenu(event, result, [
|
||||
{
|
||||
name: 'install',
|
||||
},
|
||||
{
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
name: 'open_link',
|
||||
},
|
||||
{
|
||||
name: 'copy_link',
|
||||
},
|
||||
])
|
||||
}
|
||||
const handleOptionsClick = (args) => {
|
||||
switch (args.option) {
|
||||
case 'open_link':
|
||||
openUrl(`https://modrinth.com/${args.item.project_type}/${args.item.slug}`)
|
||||
break
|
||||
case 'copy_link':
|
||||
navigator.clipboard.writeText(
|
||||
`https://modrinth.com/${args.item.project_type}/${args.item.slug}`,
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
await refreshSearch()
|
||||
</script>
|
||||
|
||||
@ -477,7 +509,12 @@ await refreshSearch()
|
||||
newlyInstalled.push(id)
|
||||
}
|
||||
"
|
||||
@contextmenu.prevent.stop="(event) => handleRightClick(event, result)"
|
||||
/>
|
||||
<ContextMenu ref="options" @option-clicked="handleOptionsClick">
|
||||
<template #open_link> <GlobeIcon /> Open in Modrinth <ExternalIcon /> </template>
|
||||
<template #copy_link> <ClipboardCopyIcon /> Copy link </template>
|
||||
</ContextMenu>
|
||||
</section>
|
||||
<div class="flex justify-end">
|
||||
<pagination
|
||||
|
||||
@ -218,6 +218,15 @@
|
||||
</ButtonStyled>
|
||||
</template>
|
||||
</ContentListPanel>
|
||||
<div class="flex justify-end mt-4">
|
||||
<Pagination
|
||||
v-if="search.length > 0"
|
||||
:page="currentPage"
|
||||
:count="Math.ceil(search.length / 20)"
|
||||
:link-function="(page) => `?page=${page}`"
|
||||
@switch-page="(page) => (currentPage = page)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="w-full flex flex-col items-center justify-center mt-6 max-w-[48rem] mx-auto">
|
||||
<div class="top-box w-full">
|
||||
@ -416,6 +425,7 @@ const initProjects = async (cacheBehaviour?) => {
|
||||
icon: null,
|
||||
disabled: file.file_name.endsWith('.disabled'),
|
||||
outdated: false,
|
||||
updated: dayjs(0),
|
||||
project_type: file.project_type === 'shaderpack' ? 'shader' : file.project_type,
|
||||
})
|
||||
}
|
||||
@ -541,20 +551,19 @@ const search = computed(() => {
|
||||
switch (sortColumn.value) {
|
||||
case 'Updated':
|
||||
return filtered.slice().sort((a, b) => {
|
||||
if (a.updated < b.updated) {
|
||||
return ascending.value ? 1 : -1
|
||||
}
|
||||
if (a.updated > b.updated) {
|
||||
return ascending.value ? -1 : 1
|
||||
}
|
||||
return 0
|
||||
const updated = a.updated.isAfter(b.updated) ? 1 : -1
|
||||
return ascending.value ? -updated : updated
|
||||
})
|
||||
default:
|
||||
return filtered.slice().sort((a, b) => a.name.localeCompare(b.name))
|
||||
return filtered
|
||||
.slice()
|
||||
.sort((a, b) =>
|
||||
ascending.value ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
watch(search, () => (currentPage.value = 1))
|
||||
watch([sortColumn, ascending, selectedFilters.value, searchFilter], () => (currentPage.value = 1))
|
||||
|
||||
const sortProjects = (filter) => {
|
||||
if (sortColumn.value === filter) {
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
>
|
||||
<ProjectBackgroundGradient :project="data" />
|
||||
</Teleport>
|
||||
<ProjectHeader :project="data">
|
||||
<ProjectHeader :project="data" @contextmenu.prevent.stop="handleRightClick">
|
||||
<template #actions>
|
||||
<ButtonStyled size="large" color="brand">
|
||||
<button
|
||||
@ -118,7 +118,7 @@
|
||||
:installed-version="installedVersion"
|
||||
/>
|
||||
</template>
|
||||
<template v-else> Project data coult not be loaded. </template>
|
||||
<template v-else> Project data couldn't not be loaded. </template>
|
||||
</div>
|
||||
<ContextMenu ref="options" @option-clicked="handleOptionsClick">
|
||||
<template #install> <DownloadIcon /> Install </template>
|
||||
@ -165,6 +165,7 @@ import { get_project, get_team, get_version_many } from '@/helpers/cache.js'
|
||||
import NavTabs from '@/components/ui/NavTabs.vue'
|
||||
import { useTheming } from '@/store/state.js'
|
||||
import InstanceIndicator from '@/components/ui/InstanceIndicator.vue'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
@ -172,7 +173,6 @@ const route = useRoute()
|
||||
const breadcrumbs = useBreadcrumbs()
|
||||
const themeStore = useTheming()
|
||||
|
||||
const options = ref(null)
|
||||
const installing = ref(false)
|
||||
const data = shallowRef(null)
|
||||
const versions = shallowRef([])
|
||||
@ -245,19 +245,30 @@ async function install(version) {
|
||||
)
|
||||
}
|
||||
|
||||
const options = ref(null)
|
||||
const handleRightClick = (event) => {
|
||||
options.value.showMenu(event, data.value, [
|
||||
{
|
||||
name: 'install',
|
||||
},
|
||||
{
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
name: 'open_link',
|
||||
},
|
||||
{
|
||||
name: 'copy_link',
|
||||
},
|
||||
])
|
||||
}
|
||||
const handleOptionsClick = (args) => {
|
||||
switch (args.option) {
|
||||
case 'install':
|
||||
install(null)
|
||||
break
|
||||
case 'open_link':
|
||||
window.__TAURI_INVOKE__('tauri', {
|
||||
__tauriModule: 'Shell',
|
||||
message: {
|
||||
cmd: 'open',
|
||||
path: `https://modrinth.com/${args.item.project_type}/${args.item.slug}`,
|
||||
},
|
||||
})
|
||||
openUrl(`https://modrinth.com/${args.item.project_type}/${args.item.slug}`)
|
||||
break
|
||||
case 'copy_link':
|
||||
navigator.clipboard.writeText(
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "theseus_gui"
|
||||
version = "0.9.0-2"
|
||||
version = "0.9.0"
|
||||
description = "The Modrinth App is a desktop application for managing your Minecraft mods"
|
||||
license = "GPL-3.0-only"
|
||||
repository = "https://github.com/modrinth/code/apps/app/"
|
||||
|
||||
@ -61,7 +61,7 @@ fn get_webview_position<R: Runtime>(
|
||||
let width = 300.0 * dpr;
|
||||
let height = 250.0 * dpr;
|
||||
|
||||
let main_window_size = main_window.inner_size()?;
|
||||
let main_window_size = main_window.outer_size()?;
|
||||
let x = (main_window_size.width as f32) - width;
|
||||
let y = (main_window_size.height as f32) - height;
|
||||
|
||||
|
||||
@ -237,7 +237,7 @@ fn main() {
|
||||
|
||||
if let Some(window) = app.get_window("main") {
|
||||
// Hide window to prevent white flash on startup
|
||||
let _ = window.hide();
|
||||
// let _ = window.hide();
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
]
|
||||
},
|
||||
"productName": "Modrinth App",
|
||||
"version": "0.9.0-2",
|
||||
"version": "0.9.0",
|
||||
"mainBinaryName": "Modrinth App",
|
||||
"identifier": "ModrinthApp",
|
||||
"plugins": {
|
||||
@ -69,7 +69,7 @@
|
||||
"width": 1280,
|
||||
"minHeight": 700,
|
||||
"minWidth": 1100,
|
||||
"visible": false,
|
||||
"visible": true,
|
||||
"zoomHotkeysEnabled": false,
|
||||
"decorations": false
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "theseus"
|
||||
version = "0.9.0-2"
|
||||
version = "0.9.0"
|
||||
authors = ["Jai A <jaiagr+gpg@pm.me>"]
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ defineExpose({ selectedTab, setTab })
|
||||
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
<div class="w-[600px] h-[500px] overflow-y-auto pl-4">
|
||||
<div class="w-[600px] h-[500px] overflow-y-auto px-4">
|
||||
<component :is="tabs[selectedTab].content" v-bind="tabs[selectedTab].props ?? {}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user