Adding things from button or file (#136)

* Initial commit

* Update Mods.vue

* instances

* Run lint

* Update pnpm-lock.yaml

* Update pnpm-lock.yaml

* Buttons colorized

* Update pnpm-lock.yaml

* Switch to chips

* Close modal when file is selected

* fix icons

---------

Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
Co-authored-by: Jai A <jaiagr+gpg@pm.me>
This commit is contained in:
Adrian O.V
2023-06-14 20:56:32 -04:00
committed by GitHub
parent 6198cc961a
commit 84d731b670
2 changed files with 156 additions and 62 deletions

View File

@@ -1,6 +1,9 @@
<template> <template>
<Modal ref="modal" header="Create instance"> <Modal ref="modal" header="Create instance">
<div class="modal-body"> <div class="modal-header">
<Chips v-model="creationType" :items="['custom', 'from file']" />
</div>
<div v-if="creationType === 'custom'" class="modal-body">
<div class="image-upload"> <div class="image-upload">
<Avatar :src="display_icon" size="md" :rounded="true" /> <Avatar :src="display_icon" size="md" :rounded="true" />
<div class="image-input"> <div class="image-input">
@@ -79,6 +82,10 @@
</Button> </Button>
</div> </div>
</div> </div>
<div v-else class="modal-body">
<Button @click="openFile"> <FolderOpenIcon /> Import from file </Button>
<div class="info"><InfoIcon /> Or drag and drop your .mrpack file</div>
</div>
</Modal> </Modal>
</template> </template>
@@ -93,6 +100,8 @@ import {
XIcon, XIcon,
CodeIcon, CodeIcon,
Checkbox, Checkbox,
FolderOpenIcon,
InfoIcon,
} from 'omorphia' } from 'omorphia'
import { computed, ref, shallowRef } from 'vue' import { computed, ref, shallowRef } from 'vue'
import { get_loaders } from '@/helpers/tags' import { get_loaders } from '@/helpers/tags'
@@ -107,6 +116,8 @@ import {
} from '@/helpers/metadata' } from '@/helpers/metadata'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import Multiselect from 'vue-multiselect' import Multiselect from 'vue-multiselect'
import { listen } from '@tauri-apps/api/event'
import { install_from_file } from '@/helpers/pack.js'
const profile_name = ref('') const profile_name = ref('')
const game_version = ref('') const game_version = ref('')
@@ -118,6 +129,7 @@ const display_icon = ref(null)
const showAdvanced = ref(false) const showAdvanced = ref(false)
const creating = ref(false) const creating = ref(false)
const showSnapshots = ref(false) const showSnapshots = ref(false)
const creationType = ref('from file')
defineExpose({ defineExpose({
show: () => { show: () => {
@@ -184,16 +196,16 @@ const create_instance = async () => {
const loader_version_value = const loader_version_value =
loader_version.value === 'other' ? specified_loader_version.value : loader_version.value loader_version.value === 'other' ? specified_loader_version.value : loader_version.value
create( modal.value.hide()
creating.value = false
await create(
profile_name.value, profile_name.value,
game_version.value, game_version.value,
loader.value, loader.value,
loader.value === 'vanilla' ? null : loader_version_value ?? 'stable', loader.value === 'vanilla' ? null : loader_version_value ?? 'stable',
icon.value icon.value
).catch(handleError) ).catch(handleError)
modal.value.hide()
creating.value = false
} }
const upload_icon = async () => { const upload_icon = async () => {
@@ -234,14 +246,27 @@ const selectable_versions = computed(() => {
const toggle_advanced = () => { const toggle_advanced = () => {
showAdvanced.value = !showAdvanced.value showAdvanced.value = !showAdvanced.value
} }
const openFile = async () => {
const newProject = await open({ multiple: false })
if (!newProject) return
modal.value.hide()
await install_from_file(newProject).catch(handleError)
}
listen('tauri://file-drop', async (event) => {
modal.value.hide()
await install_from_file(event.payload[0]).catch(handleError)
})
</script> </script>
<style scoped> <style lang="scss" scoped>
.modal-body { .modal-body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 1rem; padding: var(--gap-lg);
gap: 1rem; gap: var(--gap-md);
} }
.input-label { .input-label {
@@ -284,4 +309,33 @@ const toggle_advanced = () => {
.selector { .selector {
max-width: 20rem; max-width: 20rem;
} }
.labeled-divider {
text-align: center;
}
.labeled-divider:after {
background-color: var(--color-raised-bg);
content: 'Or';
color: var(--color-base);
padding: var(--gap-sm);
position: relative;
top: -0.5rem;
}
.info {
display: flex;
flex-direction: row;
gap: 0.5rem;
align-items: center;
}
.modal-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: var(--gap-lg);
padding-bottom: 0;
}
</style> </style>

View File

@@ -28,18 +28,22 @@
class="dropdown" class="dropdown"
/> />
</span> </span>
<Button <DropdownButton
:options="['search', 'from_file']"
default-value="search"
name="add-content-dropdown"
color="primary" color="primary"
@click=" @option-click="handleContentOptionClick"
router.push({
path: `/browse/${props.instance.metadata.loader === 'vanilla' ? 'datapack' : 'mod'}`,
query: { i: $route.params.id },
})
"
> >
<PlusIcon /> <template #search>
<span class="no-wrap"> Add content </span> <SearchIcon />
</Button> <span class="no-wrap"> Search addons </span>
</template>
<template #from_file>
<FolderOpenIcon />
<span class="no-wrap"> Add from file </span>
</template>
</DropdownButton>
</span> </span>
</div> </div>
<div class="second-row"> <div class="second-row">
@@ -63,15 +67,15 @@
@option-click="toggleSelected" @option-click="toggleSelected"
> >
<template #toggle> <template #toggle>
<GlobeIcon /> <EditIcon />
Toggle selected Toggle selected
</template> </template>
<template #disable> <template #disable>
<EditIcon /> <XIcon />
Disable selected Disable selected
</template> </template>
<template #enable> <template #enable>
<HashIcon /> <CheckCircleIcon />
Enable selected Enable selected
</template> </template>
</DropdownButton> </DropdownButton>
@@ -182,7 +186,6 @@ import {
Avatar, Avatar,
Button, Button,
TrashIcon, TrashIcon,
PlusIcon,
Card, Card,
CheckIcon, CheckIcon,
SearchIcon, SearchIcon,
@@ -190,6 +193,7 @@ import {
DropdownSelect, DropdownSelect,
AnimatedLogo, AnimatedLogo,
Chips, Chips,
FolderOpenIcon,
Checkbox, Checkbox,
formatProjectType, formatProjectType,
DropdownButton, DropdownButton,
@@ -198,17 +202,22 @@ import {
HashIcon, HashIcon,
Modal, Modal,
XIcon, XIcon,
CheckCircleIcon,
} from 'omorphia' } from 'omorphia'
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
import { convertFileSrc } from '@tauri-apps/api/tauri' import { convertFileSrc } from '@tauri-apps/api/tauri'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { import {
add_project_from_path,
get,
remove_project, remove_project,
toggle_disable_project, toggle_disable_project,
update_all, update_all,
update_project, update_project,
} from '@/helpers/profile.js' } from '@/helpers/profile.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { open } from '@tauri-apps/api/dialog'
import { listen } from '@tauri-apps/api/event'
const router = useRouter() const router = useRouter()
@@ -228,49 +237,55 @@ const props = defineProps({
}) })
const projects = ref([]) const projects = ref([])
for (const [path, project] of Object.entries(props.instance.projects)) {
if (project.metadata.type === 'modrinth') { const initProjects = (initInstance) => {
let owner = project.metadata.members.find((x) => x.role === 'Owner') projects.value = []
projects.value.push({ for (const [path, project] of Object.entries(initInstance.projects)) {
path, if (project.metadata.type === 'modrinth') {
name: project.metadata.project.title, let owner = project.metadata.members.find((x) => x.role === 'Owner')
slug: project.metadata.project.slug, projects.value.push({
author: owner ? owner.user.username : null, path,
version: project.metadata.version.version_number, name: project.metadata.project.title,
file_name: project.file_name, slug: project.metadata.project.slug,
icon: project.metadata.project.icon_url, author: owner ? owner.user.username : null,
disabled: project.disabled, version: project.metadata.version.version_number,
updateVersion: project.metadata.update_version, file_name: project.file_name,
outdated: !!project.metadata.update_version, icon: project.metadata.project.icon_url,
project_type: project.metadata.project.project_type, disabled: project.disabled,
}) updateVersion: project.metadata.update_version,
} else if (project.metadata.type === 'inferred') { outdated: !!project.metadata.update_version,
projects.value.push({ project_type: project.metadata.project.project_type,
path, })
name: project.metadata.title ?? project.file_name, } else if (project.metadata.type === 'inferred') {
author: project.metadata.authors[0], projects.value.push({
version: project.metadata.version, path,
file_name: project.file_name, name: project.metadata.title ?? project.file_name,
icon: project.metadata.icon ? convertFileSrc(project.metadata.icon) : null, author: project.metadata.authors[0],
disabled: project.disabled, version: project.metadata.version,
outdated: false, file_name: project.file_name,
project_type: project.metadata.project_type, icon: project.metadata.icon ? convertFileSrc(project.metadata.icon) : null,
}) disabled: project.disabled,
} else { outdated: false,
projects.value.push({ project_type: project.metadata.project_type,
path, })
name: project.file_name, } else {
author: '', projects.value.push({
version: null, path,
file_name: project.file_name, name: project.file_name,
icon: null, author: '',
disabled: project.disabled, version: null,
outdated: false, file_name: project.file_name,
project_type: null, icon: null,
}) disabled: project.disabled,
outdated: false,
project_type: null,
})
}
} }
} }
initProjects(props.instance)
const searchFilter = ref('') const searchFilter = ref('')
const selectAll = ref(false) const selectAll = ref(false)
const sortFilter = ref('') const sortFilter = ref('')
@@ -392,6 +407,31 @@ async function removeMod(mod) {
projects.value = projects.value.filter((x) => mod.path !== x.path) projects.value = projects.value.filter((x) => mod.path !== x.path)
} }
const handleContentOptionClick = async (args) => {
if (args.option === 'search') {
await router.push({
path: `/browse/${props.instance.metadata.loader === 'vanilla' ? 'datapack' : 'mod'}`,
})
} else if (args.option === 'from_file') {
const newProject = await open({ multiple: true })
console.log(newProject)
if (!newProject) return
for (const project of newProject) {
console.log(project)
await add_project_from_path(props.instance.path, project, 'mod').catch(handleError)
initProjects(await get(props.instance.path).catch(handleError))
}
}
}
listen('tauri://file-drop', async (event) => {
for (const file of event.payload) {
await add_project_from_path(props.instance.path, file, 'mod').catch(handleError)
initProjects(await get(props.instance.path).catch(handleError))
}
})
async function deleteSelected() { async function deleteSelected() {
for (const project of selected.value) { for (const project of selected.value) {
await remove_project(props.instance.path, project.path).catch(handleError) await remove_project(props.instance.path, project.path).catch(handleError)