Skip to content

Commit

Permalink
Content page nearly done
Browse files Browse the repository at this point in the history
  • Loading branch information
Prospector committed Nov 10, 2024
1 parent cd21547 commit 797ff36
Show file tree
Hide file tree
Showing 15 changed files with 294 additions and 80 deletions.
14 changes: 7 additions & 7 deletions apps/app-frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ async function fetchCredentials() {
}
const MIDAS_BITFLAG = 1 << 0
const hasPlus = computed(() => credentials.value && credentials.value.user && (credentials.value.user.badges & MIDAS_BITFLAG) === MIDAS_BITFLAG)
const hasPlus = computed(() => true || credentials.value && credentials.value.user && (credentials.value.user.badges & MIDAS_BITFLAG) === MIDAS_BITFLAG)
onMounted(() => {
invoke('show_window')
Expand Down Expand Up @@ -321,6 +321,9 @@ async function checkUpdates() {
<template>
<SplashScreen v-if="!stateFailed" ref="splashScreen" data-tauri-drag-region />
<AppSettingsModal ref="settingsTest" />
<Suspense>
<InstanceCreationModal ref="installationModal" />
</Suspense>
<div v-if="stateInitialized" class="app-grid-layout relative">
<div class="app-grid-navbar bg-bg-raised flex flex-col p-[1rem] pt-0 gap-[0.5rem] z-10">
<NavButton to="/">
Expand All @@ -338,7 +341,7 @@ async function checkUpdates() {
<template #label>Library</template>
</NavButton>
<div class="h-px w-6 mx-auto my-2 bg-button-bg"></div>
<NavButton to="/settings">
<NavButton :to="() => $refs.installationModal.show()" :disabled="offline">
<PlusIcon />
<template #label>Create new instance</template>
</NavButton>
Expand Down Expand Up @@ -401,14 +404,14 @@ async function checkUpdates() {
</RouterView>
</div>
<div class="app-sidebar mt-px shrink-0 flex flex-col border-0 border-l-[1px] border-[--brand-gradient-border] border-solid overflow-auto" :class="{ 'has-plus': hasPlus }">
<div class="app-sidebar-scrollable flex-grow shrink overflow-y-auto relative" :class="{ 'pb-4': !hasPlus }">
<div class="app-sidebar-scrollable flex-grow shrink overflow-y-auto relative" :class="{ 'pb-12': !hasPlus }">
<div class="p-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid">
<h3 class="text-base m-0">Playing as</h3>
<suspense>
<AccountsCard ref="accounts" mode="small" />
</suspense>
</div>
<div v-if="false" class="p-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid">
<div class="p-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid">
<h3 class="text-base m-0">Friends</h3>
<p class="m-0">you have no friends :c</p>
<p class="m-0">what's up with that?</p>
Expand Down Expand Up @@ -458,9 +461,6 @@ async function checkUpdates() {
<RouterLink v-tooltip="'Library'" to="/library" class="btn icon-only collapsed-button">
<LibraryIcon />
</RouterLink>
<Suspense>
<InstanceCreationModal ref="installationModal" />
</Suspense>
</div>
</div>
<div class="settings pages-list">
Expand Down
7 changes: 5 additions & 2 deletions apps/app-frontend/src/components/ui/AccountsCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
: 'https://launcher-files.modrinth.com/assets/steve_head.png'
"
/>
<span class="w-full">{{ selectedAccount ? selectedAccount.username : 'Select account' }}</span>
<DropdownIcon class="unlocked-size w-5 h-5" />
<div class="flex flex-col w-full">
<span >{{ selectedAccount ? selectedAccount.username : 'Select account' }}</span>
<span class="text-secondary text-xs">Minecraft account</span>
</div>
<DropdownIcon class="unlocked-size w-5 h-5 shrink-0" />
</div>
<transition name="fade">
<Card
Expand Down
15 changes: 10 additions & 5 deletions apps/app-frontend/src/components/ui/NavButton.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<template>
<div class="tooltip-parent flex items-center justify-center">
<RouterLink :to="to" class="w-12 h-12 rounded-full flex items-center justify-center text-2xl transition-all bg-transparent hover:bg-button-bg hover:text-contrast">
<RouterLink v-if="typeof to === 'string'" :to="to" v-bind="$attrs" class="w-12 h-12 rounded-full flex items-center justify-center text-2xl transition-all bg-transparent hover:bg-button-bg hover:text-contrast">
<slot />
</RouterLink>
<button v-else v-bind="$attrs" class="button-animation border-none cursor-pointer w-12 h-12 rounded-full flex items-center justify-center text-2xl transition-all bg-transparent hover:bg-button-bg hover:text-contrast" @click="to">
<slot />
</button>
<div class="tooltip-label">
<slot name="label" />
</div>
Expand All @@ -12,10 +15,12 @@
<script setup lang="ts">
import { RouterLink } from 'vue-router'
withDefaults(defineProps<{
to: string
}>(), {
to: '/'
defineProps<{
to: (() => void) | string
}>()
defineOptions({
inheritAttrs: false,
})
</script>
Expand Down
2 changes: 1 addition & 1 deletion apps/app-frontend/src/components/ui/modal/ModalWrapper.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref } from 'vue'
import { Modal } from '@modrinth/ui'
import { NewModal as Modal } from '@modrinth/ui'
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js'
import { useTheming } from '@/store/theme.js'
Expand Down
176 changes: 157 additions & 19 deletions apps/app-frontend/src/pages/instance/Mods.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,12 @@
<XIcon />
</Button>
</div>
<ButtonStyled v-if="!isPackLocked" type="transparent" color="green" @click="updateAll">
<button>
<DownloadIcon /> Update all
</button>
</ButtonStyled>
<AddContentButton v-if="!isPackLocked" :instance="instance" />
</div>
<div class="flex flex-wrap gap-1 items-center pb-4">
<div v-if="filterOptions.length > 1" class="flex flex-wrap gap-1 items-center pb-4">
<FilterIcon class="unlocked-size text-secondary h-5 w-5 mr-1" />
<button v-for="filter in ['Mods', 'Resource Packs', 'Shaders', 'Updates available'].filter((x) => isPackLocked ? x !== 'Updates available' : true)" :key="filter" class="px-2 py-1 rounded-full bg-bg-raised text-secondary font-semibold leading-none border-none">
{{ filter }}
<button v-for="filter in filterOptions" :key="filter" :class="`px-2 py-1 rounded-full font-semibold leading-none border-none cursor-pointer active:scale-[0.97] duration-100 transition-all ${selectedFilters.includes(filter.id) ? 'bg-brand-highlight text-brand' : 'bg-bg-raised text-secondary'}`" @click="toggleArray(selectedFilters, filter.id)">
{{ filter.formattedName }}
</button>
</div>
<Card v-if="false && projects.length > 0" class="mod-card">
Expand Down Expand Up @@ -89,6 +84,8 @@
</Card>
<ContentListPanel
v-if="projects.length > 0"
ref="contentList"
:locked="isPackLocked"
:items="search.map((x) => ({
disabled: x.disabled,
filename: x.file_name,
Expand All @@ -111,15 +108,79 @@
data: x,
}))"
>
<template v-if="selectedProjects.length > 0" #headers>
<div class="flex gap-2">
<ButtonStyled v-if="selectedProjects.some((m) => m.outdated)" color="brand" color-fill="text" hover-color-fill="text">
<button><DownloadIcon /> Update</button>
</ButtonStyled>
<ButtonStyled>
<OverflowMenu
:options="[
{
id: 'share-names',
action: () => shareNames(),
},
{
id: 'share-file-names',
action: () => shareFileNames(),
},
{
id: 'share-urls',
action: () => shareUrls(),
},
{
id: 'share-markdown',
action: () => shareMarkdown(),
}
]">
<ShareIcon /> Share <DropdownIcon />
<template #share-names>
<TextInputIcon /> Project names
</template>
<template #share-file-names>
<FileIcon /> File names
</template>
<template #share-urls>
<LinkIcon /> Project links
</template>
<template #share-markdown>
<CodeIcon /> Markdown links
</template>
</OverflowMenu>
</ButtonStyled>
<ButtonStyled v-if="selectedProjects.some((m) => m.disabled)">
<button><CheckCircleIcon /> Enable</button>
</ButtonStyled>
<ButtonStyled v-if="selectedProjects.some((m) => !m.disabled)">
<button><SlashIcon /> Disable</button>
</ButtonStyled>
<ButtonStyled color="red">
<button><TrashIcon /> Remove</button>
</ButtonStyled>
</div>
</template>
<template #header-actions>
<ButtonStyled v-if="!isPackLocked && projects.some((m) => (m as any).outdated)" type="transparent" color="brand" color-fill="text" hover-color-fill="text">
<button>
<DownloadIcon /> Update all
</button>
</ButtonStyled>
</template>
<template #actions="{ item }">
<ButtonStyled v-if="!isPackLocked && (item.data as any).outdated" type="transparent" color="brand" circular>
<button v-tooltip="`Update`" @click="updateProject(item.data)">
<DownloadIcon />
</button>
</ButtonStyled>
<div v-else class="w-[36px]"></div>
<ButtonStyled v-if="!isPackLocked" type="transparent" circular>
<button v-tooltip="item.disabled ? `Enable` : `Disable`" @click="toggleDisableMod(item.data)">
<CheckCircleIcon v-if="item.disabled" />
<SlashIcon v-else />
</button>
</ButtonStyled>
<ButtonStyled v-if="!isPackLocked" type="transparent" circular>
<button v-tooltip="'Delete'" @click="removeMod(item)">
<button v-tooltip="'Remove'" @click="removeMod(item)">
<TrashIcon />
</button>
</ButtonStyled>
Expand All @@ -130,20 +191,25 @@
id: 'show-file',
action: () => {},
},
{
divider: true,
},
{
id: 'copy-link',
shown: item.project,
shown: item.project !== undefined,
action: () => toggleDisableMod(item.data),
},
{
divider: true,
},
{
id: 'remove',
color: 'red',
action: () => removeMod(item),
}
]"
direction="left"
>
<MoreVerticalIcon />
<template #show-file>
<ClipboardCopyIcon /> Show file
<ExternalIcon /> Show file
</template>
<template #copy-link>
<ClipboardCopyIcon /> Copy link
Expand All @@ -154,6 +220,9 @@
<template v-else #toggle>
<SlashIcon /> Disable
</template>
<template #remove>
<TrashIcon /> Remove
</template>
</OverflowMenu>
</ButtonStyled>
</template>
Expand Down Expand Up @@ -428,11 +497,12 @@
:versions="props.versions"
/>
</template>
<script setup>
<script setup lang="ts">
import {
ExternalIcon,
LinkIcon,
LockIcon,
ClipboardCopyIcon,
CompassIcon,
TrashIcon,
CheckIcon,
SearchIcon,
Expand Down Expand Up @@ -461,7 +531,9 @@ import {
Card, ButtonStyled, ContentListPanel, OverflowMenu
} from '@modrinth/ui'
import { formatProjectType } from '@modrinth/utils'
import type { ComputedRef } from 'vue';
import { computed, onUnmounted, ref, watch } from 'vue'
import { useVIntl, defineMessages } from '@vintl/vintl'
import {
add_project_from_path,
get_projects,
Expand All @@ -473,7 +545,7 @@ import {
import { handleError } from '@/store/notifications.js'
import { trackEvent } from '@/helpers/analytics'
import { listen } from '@tauri-apps/api/event'
import { highlightModInProfile, showProfileInFolder } from '@/helpers/utils.js'
import { highlightModInProfile } from '@/helpers/utils.js'
import { MenuIcon, ToggleIcon, TextInputIcon, AddProjectImage, PackageIcon } from '@/assets/icons'
import ExportModal from '@/components/ui/ExportModal.vue'
import ModpackVersionModal from '@/components/ui/ModpackVersionModal.vue'
Expand All @@ -487,6 +559,9 @@ import {
import { profile_listener } from '@/helpers/events.js'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import ShareModalWrapper from '@/components/ui/modal/ShareModalWrapper.vue'
import { getCurrentWebview } from '@tauri-apps/api/webview'
const contentList = ref<InstanceType<typeof ContentListPanel> | null>(null)
const props = defineProps({
instance: {
Expand Down Expand Up @@ -538,6 +613,8 @@ const canUpdatePack = computed(() => {
const exportModal = ref(null)
const projects = ref([])
const selectedProjects = computed(() => projects.value.filter((x) => contentList.value ? contentList.value.selected.includes(x.file_name) : []))
const selectionMap = ref(new Map())
const initProjects = async (cacheBehaviour) => {
Expand Down Expand Up @@ -639,6 +716,67 @@ await initProjects()
const modpackVersionModal = ref(null)
const installing = computed(() => props.instance.install_stage !== 'installed')
const vintl = useVIntl();
const { formatMessage } = vintl;
type FilterOption = {
id: string;
formattedName: string;
}
const messages = defineMessages({
updatesAvailableFilter: {
id: "instance.filter.updates-available",
defaultMessage: "Updates available",
},
})
const filterOptions: ComputedRef<FilterOption[]> = computed(() => {
const options: FilterOption[] = [];
const frequency = projects.value.reduce((map, item) => {
map[item.project_type] = (map[item.project_type] || 0) + 1;
return map;
}, {});
const types = Object.keys(frequency).sort((a, b) => frequency[b] - frequency[a])
types.forEach(type => {
options.push({
id: type,
formattedName: formatProjectType(type) + "s"
});
});
if (!isPackLocked.value && projects.value.some((m) => m.outdated)) {
options.push({
id: 'updates',
formattedName: formatMessage(messages.updatesAvailableFilter)
});
}
return options;
})
const selectedFilters = ref([]);
const filteredProjects = computed(() => {
const updatesFilter = selectedFilters.value.includes('updates');
const typeFilters = selectedFilters.value.filter(filter => filter !== 'updates');
return projects.value.filter(project => {
return (typeFilters.length === 0 || typeFilters.includes(project.project_type)) && (!updatesFilter || project.outdated);
});
});
function toggleArray(array, value) {
if (array.includes(value)) {
array.splice(array.indexOf(value), 1);
} else {
array.push(value);
}
}
const searchFilter = ref('')
const selectAll = ref(false)
const selectedProjectType = ref('All')
Expand All @@ -661,7 +799,7 @@ const selected = computed(() =>
)
const functionValues = computed(() =>
selected.value.length > 0 ? selected.value : Array.from(projects.value.values()),
selectedProjects.value.length > 0 ? selectedProjects.value : Array.from(projects.value.values()),
)
const selectableProjectTypes = computed(() => {
Expand All @@ -677,7 +815,7 @@ const selectableProjectTypes = computed(() => {
const search = computed(() => {
const projectType = selectableProjectTypes.value[selectedProjectType.value]
const filtered = projects.value
const filtered = filteredProjects.value
.filter((mod) => {
return (
mod.name.toLowerCase().includes(searchFilter.value.toLowerCase()) &&
Expand Down
Loading

0 comments on commit 797ff36

Please sign in to comment.