Fix lint checks

This commit is contained in:
Alejandro González 2025-04-26 23:27:15 +02:00
parent d37c634216
commit 61c2ce2107
No known key found for this signature in database
15 changed files with 223 additions and 136 deletions

View File

@ -1,7 +1,14 @@
<script setup>
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { SpinnerIcon, GameIcon, TimerIcon, StopCircleIcon, PlayIcon, DownloadIcon } from '@modrinth/assets'
import {
SpinnerIcon,
GameIcon,
TimerIcon,
StopCircleIcon,
PlayIcon,
DownloadIcon,
} from '@modrinth/assets'
import { ButtonStyled, Avatar, SmartClickable } from '@modrinth/ui'
import { convertFileSrc } from '@tauri-apps/api/core'
import { finish_install, kill, run } from '@/helpers/profile'
@ -129,19 +136,21 @@ onUnmounted(() => unlisten())
<template>
<SmartClickable class="card-shadow bg-bg-raised rounded-xl" @mouseenter="checkProcess">
<template #clickable>
<router-link class="no-click-animation" :to="`/instance/${encodeURIComponent(instance.path)}/`" />
<router-link
class="no-click-animation"
:to="`/instance/${encodeURIComponent(instance.path)}/`"
/>
</template>
<div
v-if="compact"
class="grid grid-cols-[auto_1fr_auto] p-3 pl-4 gap-2"
>
<div v-if="compact" class="grid grid-cols-[auto_1fr_auto] p-3 pl-4 gap-2">
<Avatar
size="48px"
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : null"
:tint-by="instance.path"
alt="Mod card"
/>
<div class="h-full flex items-center font-bold text-contrast leading-normal smart-clickable:underline-on-hover">
<div
class="h-full flex items-center font-bold text-contrast leading-normal smart-clickable:underline-on-hover"
>
<span class="line-clamp-2">{{ instance.name }}</span>
</div>
<div class="flex items-center smart-clickable:allow-pointer-events">
@ -171,11 +180,7 @@ onUnmounted(() => unlisten())
<span class="text-sm"> Played {{ dayjs(instance.last_played).fromNow() }} </span>
</div>
</div>
<div
v-else
class="p-4 rounded-xl flex gap-3 group"
@mouseenter="checkProcess"
>
<div v-else class="p-4 rounded-xl flex gap-3 group" @mouseenter="checkProcess">
<div class="relative flex items-center justify-center">
<Avatar
size="48px"
@ -224,7 +229,9 @@ onUnmounted(() => unlisten())
</div>
</div>
<div class="flex flex-col gap-1">
<p class="m-0 text-md font-bold text-contrast leading-tight line-clamp-1 smart-clickable:underline-on-hover">
<p
class="m-0 text-md font-bold text-contrast leading-tight line-clamp-1 smart-clickable:underline-on-hover"
>
{{ instance.name }}
</p>
<div class="flex items-center col-span-3 gap-1 text-secondary font-semibold mt-auto">

View File

@ -11,7 +11,10 @@ defineProps<{
</script>
<template>
<div v-if="instance" class="flex justify-between items-center border-0 border-b border-solid border-divider pb-4">
<div
v-if="instance"
class="flex justify-between items-center border-0 border-b border-solid border-divider pb-4"
>
<router-link
:to="`/instance/${encodeURIComponent(instance.path)}`"
tabindex="-1"

View File

@ -5,7 +5,6 @@ import { formatNumber, formatCategory } from '@modrinth/utils'
import { computed } from 'vue'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import { useRouter } from 'vue-router'
dayjs.extend(relativeTime)
@ -45,10 +44,7 @@ const toColor = computed(() => {
class="card-shadow bg-bg-raised rounded-xl overflow-clip cursor-pointer hover:brightness-90 transition-all"
>
<template #clickable>
<router-link
class="no-click-animation"
:to="`/project/${project.slug}`"
/>
<router-link class="no-click-animation" :to="`/project/${project.slug}`" />
</template>
<div
class="w-full aspect-[2/1] bg-cover bg-center bg-no-repeat"
@ -60,12 +56,13 @@ const toColor = computed(() => {
'https://launcher-files.modrinth.com/assets/maze-bg.png'
})`,
}"
>
</div>
></div>
<div class="flex flex-col justify-center gap-2 px-4 py-3">
<div class="flex gap-2 items-center">
<Avatar size="48px" :src="project.icon_url" />
<div class="h-full flex items-center font-bold text-contrast leading-normal smart-clickable:underline-on-hover">
<div
class="h-full flex items-center font-bold text-contrast leading-normal smart-clickable:underline-on-hover"
>
<span class="line-clamp-2">{{ project.title }}</span>
</div>
</div>

View File

@ -34,8 +34,9 @@ const installed: Ref<boolean> = ref(false)
function checkInstallStatus() {
if (props.instanceContent) {
installed.value = Object.values(props.instanceContent)
.some((content) => content.metadata?.project_id === projectId.value)
installed.value = Object.values(props.instanceContent).some(
(content) => content.metadata?.project_id === projectId.value,
)
}
}

View File

@ -11,14 +11,16 @@
)
"
:experimental-colors="themeStore.featureFlags.project_card_background"
:creator-link=" creator ?
asLink(
{
path: `/user/${creator}`,
query: { i: props.instance ? props.instance.path : undefined },
},
() => emit('open'),
) : undefined
:creator-link="
creator
? asLink(
{
path: `/user/${creator}`,
query: { i: props.instance ? props.instance.path : undefined },
},
() => emit('open'),
)
: undefined
"
>
<template #actions>
@ -42,12 +44,8 @@
<script setup lang="ts">
import { DownloadIcon, CheckIcon } from '@modrinth/assets'
import { ButtonStyled, NewProjectCard, asLink } from '@modrinth/ui'
import type {
Project,
SearchResult} from '@modrinth/utils';
import {
isSearchResult
} from '@modrinth/utils'
import type { Project, SearchResult } from '@modrinth/utils'
import { isSearchResult } from '@modrinth/utils'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import { ref, computed } from 'vue'
@ -58,14 +56,17 @@ dayjs.extend(relativeTime)
const themeStore = useTheming()
const props = withDefaults(defineProps<{
project: Project | SearchResult
instance?: GameInstance
installed?: boolean
}>(), {
instance: undefined,
installed: false,
})
const props = withDefaults(
defineProps<{
project: Project | SearchResult
instance?: GameInstance
installed?: boolean
}>(),
{
instance: undefined,
installed: false,
},
)
const emit = defineEmits(['open', 'install'])
@ -85,6 +86,8 @@ async function install() {
)
}
const projectId = computed(() => isSearchResult(props.project) ? props.project.project_id : props.project.id)
const creator = computed(() => isSearchResult(props.project) ? props.project.author : undefined)
const projectId = computed(() =>
isSearchResult(props.project) ? props.project.project_id : props.project.id,
)
const creator = computed(() => (isSearchResult(props.project) ? props.project.author : undefined))
</script>

View File

@ -30,31 +30,37 @@ watch(
)
</script>
<template>
<h2 class="m-0 text-lg font-extrabold text-contrast">
Feature flags
</h2>
<h2 class="m-0 text-lg font-extrabold text-contrast">Feature flags</h2>
<p class="mt-1 mb-0 leading-tight text-secondary">
These are developer tools that are not intended to be used by end users except for debugging purposes.
These are developer tools that are not intended to be used by end users except for debugging
purposes.
</p>
<p class="my-3 font-bold">Do not report bugs or issues if you have any feature flags enabled.</p>
<div v-for="option in options" :key="option" class="mt-2 px-4 py-3 flex items-center justify-between bg-bg rounded-2xl">
<div
v-for="option in options"
:key="option"
class="mt-2 px-4 py-3 flex items-center justify-between bg-bg rounded-2xl"
>
<div>
<h2 class="m-0 text-base font-bold text-primary capitalize">
{{ option.replace(new RegExp('_', "g"), ' ') }}
{{ option.replace(new RegExp('_', 'g'), ' ') }}
</h2>
<p class="m-0 text-sm text-secondary">Default: {{ DEFAULT_FEATURE_FLAGS[option] }}</p>
</div>
<div class="flex items-center gap-1">
<ButtonStyled type="transparent">
<button class="text-sm" :disabled="getStoreValue(option) === DEFAULT_FEATURE_FLAGS[option]" @click="() => setStoreValue(option, !themeStore.featureFlags[option])">
<button
class="text-sm"
:disabled="getStoreValue(option) === DEFAULT_FEATURE_FLAGS[option]"
@click="() => setStoreValue(option, !themeStore.featureFlags[option])"
>
Reset to default
</button>
</ButtonStyled>
<Toggle
id="advanced-rendering"
:model-value="getStoreValue(option)"
@update:model-value="() => setStoreValue(option, !themeStore.featureFlags[option])"
/>
</div>

View File

@ -12,18 +12,17 @@ export async function useInstanceContext() {
const instance: Ref<GameInstance | undefined> = ref()
const instanceContent: Ref<InstanceContentMap | undefined> = ref()
await loadInstance();
await loadInstance()
watch(route, () => {
loadInstance()
})
async function loadInstance() {
[instance.value, instanceContent.value] =
await Promise.all([
route.query.i ? getInstance(route.query.i).catch(handleError) : Promise.resolve(),
route.query.i ? getInstanceProjects(route.query.i).catch(handleError) : Promise.resolve(),
])
;[instance.value, instanceContent.value] = await Promise.all([
route.query.i ? getInstance(route.query.i).catch(handleError) : Promise.resolve(),
route.query.i ? getInstanceProjects(route.query.i).catch(handleError) : Promise.resolve(),
])
}
const instanceQueryAppendage = computed(() => {

View File

@ -37,7 +37,7 @@ type InstanceContent = {
file_name: string
size: number
metadata?: {
project_id: ModrinthId,
project_id: ModrinthId
version_id: ModrinthId
}
update_version_id: string

View File

@ -26,15 +26,13 @@ import { get_categories, get_game_versions, get_loaders } from '@/helpers/tags'
import type { LocationQuery } from 'vue-router'
import { useRoute, useRouter } from 'vue-router'
import SearchCard from '@/components/ui/SearchCard.vue'
import { get as getInstance, get_projects as getInstanceProjects } from '@/helpers/profile.js'
import { get_search_results } from '@/helpers/cache.js'
import NavTabs from '@/components/ui/NavTabs.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'
import type { GameInstance } from '@/helpers/types'
import { InstanceContentMap, useInstanceContext } from '@/composables/instance-context.ts'
import { useInstanceContext } from '@/composables/instance-context.ts'
import type { SearchResult } from '@modrinth/utils'
const { formatMessage } = useVIntl()

View File

@ -1,8 +1,21 @@
<template>
<Teleport to="#sidebar-teleport-target">
<CollectionSidebarDescription v-if="collection" :collection="collection" class="project-sidebar-section" />
<CollectionSidebarCurator v-if="curator" :user="curator" :link="`/user/${curator.id}`" class="project-sidebar-section" />
<CollectionSidebarDetails v-if="collection" :collection="collection" class="project-sidebar-section" />
<CollectionSidebarDescription
v-if="collection"
:collection="collection"
class="project-sidebar-section"
/>
<CollectionSidebarCurator
v-if="curator"
:user="curator"
:link="`/user/${curator.id}`"
class="project-sidebar-section"
/>
<CollectionSidebarDetails
v-if="collection"
:collection="collection"
class="project-sidebar-section"
/>
</Teleport>
<div v-if="collection" class="p-6 flex flex-col gap-4">
<InstanceIndicator :instance="instance" />
@ -10,9 +23,7 @@
<template #actions>
<ButtonStyled v-if="themeStore.devMode" circular type="transparent" size="large">
<OverflowMenu
:options="[
{ id: 'copy-id', action: () => copyId(), shown: themeStore.devMode },
]"
:options="[{ id: 'copy-id', action: () => copyId(), shown: themeStore.devMode }]"
aria-label="More options"
>
<MoreVerticalIcon aria-hidden="true" />
@ -25,9 +36,17 @@
</template>
</CollectionHeader>
<div v-if="projects">
<ProjectsList :projects="projects" :project-link="(project) => `/project/${project.id}${instanceQueryAppendage}`" :experimental-colors="themeStore.featureFlags.project_card_background">
<ProjectsList
:projects="projects"
:project-link="(project) => `/project/${project.id}${instanceQueryAppendage}`"
:experimental-colors="themeStore.featureFlags.project_card_background"
>
<template #project-actions="{ project }">
<ProjectCardActions :instance="instance" :instance-content="instanceContent" :project="project" />
<ProjectCardActions
:instance="instance"
:instance-content="instanceContent"
:project="project"
/>
</template>
</ProjectsList>
</div>
@ -43,7 +62,10 @@ import {
ButtonStyled,
commonMessages,
OverflowMenu,
CollectionHeader, CollectionSidebarCurator, CollectionSidebarDescription, CollectionSidebarDetails
CollectionHeader,
CollectionSidebarCurator,
CollectionSidebarDescription,
CollectionSidebarDetails,
} from '@modrinth/ui'
import { ClipboardCopyIcon, MoreVerticalIcon } from '@modrinth/assets'
import { useVIntl } from '@vintl/vintl'
@ -64,14 +86,18 @@ const curator: Ref<User | null> = ref(null)
const projects: Ref<Project[]> = ref([])
async function fetchCollection() {
collection.value = await useFetch(`https://api.modrinth.com/v3/collection/${route.params.id}`).catch(handleError)
collection.value = await useFetch(
`https://api.modrinth.com/v3/collection/${route.params.id}`,
).catch(handleError)
if (!collection.value) {
return;
return
}
[ projects.value, curator.value ] = await Promise.all([
useFetch(`https://api.modrinth.com/v2/projects?ids=${encodeURIComponent(JSON.stringify(collection.value.projects))}`),
;[projects.value, curator.value] = await Promise.all([
useFetch(
`https://api.modrinth.com/v2/projects?ids=${encodeURIComponent(JSON.stringify(collection.value.projects))}`,
),
useFetch(`https://api.modrinth.com/v2/user/${collection.value.user}`).catch(handleError),
])
@ -94,10 +120,9 @@ watch(
const themeStore = useTheming()
async function copyId() {
if (collection.value) {
await navigator.clipboard.writeText(String(collection.value.id));
await navigator.clipboard.writeText(String(collection.value.id))
}
}
</script>

View File

@ -69,7 +69,10 @@
name: x.author.name,
type: x.author.type,
id: x.author.slug,
link: { path: `/${x.author.type}/${x.author.slug}`, query: { i: props.instance.path } },
link: {
path: `/${x.author.type}/${x.author.slug}`,
query: { i: props.instance.path },
},
linkProps: { target: '_blank' },
}
}

View File

@ -1,16 +1,23 @@
<template>
<Teleport to="#sidebar-teleport-target">
<OrganizationSidebarMembers v-if="organization" :members="organization.members" :user-link="(user) => `/user/${user.id}`" class="project-sidebar-section" />
<OrganizationSidebarMembers
v-if="organization"
:members="organization.members"
:user-link="(user) => `/user/${user.id}`"
class="project-sidebar-section"
/>
</Teleport>
<div v-if="organization" class="flex flex-col gap-4 p-6">
<InstanceIndicator :instance="instance" />
<OrganizationHeader :organization="organization" :download-count="sumDownloads" :project-count="projects.length">
<OrganizationHeader
:organization="organization"
:download-count="sumDownloads"
:project-count="projects.length"
>
<template #actions>
<ButtonStyled v-if="themeStore.devMode" circular type="transparent" size="large">
<OverflowMenu
:options="[
{ id: 'copy-id', action: () => copyId(), shown: themeStore.devMode },
]"
:options="[{ id: 'copy-id', action: () => copyId(), shown: themeStore.devMode }]"
aria-label="More options"
>
<MoreVerticalIcon aria-hidden="true" />
@ -23,9 +30,17 @@
</template>
</OrganizationHeader>
<div v-if="projects">
<ProjectsList :projects="projects" :project-link="(project) => `/project/${project.id}${instanceQueryAppendage}`" :experimental-colors="themeStore.featureFlags.project_card_background">
<ProjectsList
:projects="projects"
:project-link="(project) => `/project/${project.id}${instanceQueryAppendage}`"
:experimental-colors="themeStore.featureFlags.project_card_background"
>
<template #project-actions="{ project }">
<ProjectCardActions :project="project" :instance="instance" :instance-content="instanceContent" />
<ProjectCardActions
:project="project"
:instance="instance"
:instance-content="instanceContent"
/>
</template>
</ProjectsList>
</div>
@ -41,9 +56,10 @@ import {
ButtonStyled,
commonMessages,
OverflowMenu,
OrganizationHeader, OrganizationSidebarMembers
OrganizationHeader,
OrganizationSidebarMembers,
} from '@modrinth/ui'
import { ClipboardCopyIcon, MoreVerticalIcon, DownloadIcon, HeartIcon, BookmarkIcon } from '@modrinth/assets'
import { ClipboardCopyIcon, MoreVerticalIcon } from '@modrinth/assets'
import { useVIntl } from '@vintl/vintl'
import { useFetch } from '@/helpers/fetch'
import type { Project, Organization, ProjectV3, Environment } from '@modrinth/utils'
@ -63,35 +79,41 @@ const projects: Ref<Project[]> = ref([])
const { instance, instanceContent, instanceQueryAppendage } = await useInstanceContext()
async function fetchOrganization() {
organization.value = await useFetch(`https://api.modrinth.com/v3/organization/${route.params.id}`).catch(handleError)
projects.value = (await useFetch(`https://api.modrinth.com/v3/organization/${route.params.id}/projects`).catch(handleError)).map((projectV3: ProjectV3) => {
organization.value = await useFetch(
`https://api.modrinth.com/v3/organization/${route.params.id}`,
).catch(handleError)
projects.value = (
await useFetch(`https://api.modrinth.com/v3/organization/${route.params.id}/projects`).catch(
handleError,
)
).map((projectV3: ProjectV3) => {
let type = projectV3.project_types[0]
if (type === 'plugin' || type === 'datapack') {
type = 'mod'
}
let clientSide: Environment = 'unknown';
let serverSide: Environment = 'unknown';
let clientSide: Environment = 'unknown'
let serverSide: Environment = 'unknown'
const singleplayer = projectV3.singleplayer && projectV3.singleplayer[0];
const clientAndServer = projectV3.client_and_server && projectV3.client_and_server[0];
const clientOnly = projectV3.client_only && projectV3.client_only[0];
const serverOnly = projectV3.server_only && projectV3.server_only[0];
const singleplayer = projectV3.singleplayer && projectV3.singleplayer[0]
const clientAndServer = projectV3.client_and_server && projectV3.client_and_server[0]
const clientOnly = projectV3.client_only && projectV3.client_only[0]
const serverOnly = projectV3.server_only && projectV3.server_only[0]
// quick and dirty hack to show envs as legacy
if (singleplayer && clientAndServer && !clientOnly && !serverOnly) {
clientSide = "required";
serverSide = "required";
clientSide = 'required'
serverSide = 'required'
} else if (singleplayer && clientAndServer && clientOnly && !serverOnly) {
clientSide = "required";
serverSide = "unsupported";
clientSide = 'required'
serverSide = 'unsupported'
} else if (singleplayer && clientAndServer && !clientOnly && serverOnly) {
clientSide = "unsupported";
serverSide = "required";
clientSide = 'unsupported'
serverSide = 'required'
} else if (singleplayer && clientAndServer && clientOnly && serverOnly) {
clientSide = "optional";
serverSide = "optional";
clientSide = 'optional'
serverSide = 'optional'
}
const projectV2: Project = {
@ -109,7 +131,7 @@ async function fetchOrganization() {
})
if (!organization.value) {
return;
return
}
breadcrumbs.setName('Organization', organization.value.name)
@ -130,20 +152,19 @@ const themeStore = useTheming()
async function copyId() {
if (organization.value) {
await navigator.clipboard.writeText(String(organization.value.id));
await navigator.clipboard.writeText(String(organization.value.id))
}
}
const sumDownloads = computed(() => {
let sum = 0;
let sum = 0
for (const project of projects.value) {
sum += project.downloads;
sum += project.downloads
}
return sum;
});
return sum
})
</script>
<style scoped lang="scss">
.project-sidebar-section {

View File

@ -204,7 +204,9 @@ async function fetchProjectData() {
])
if (project.organization) {
organization.value = await useFetch(`https://api.modrinth.com/v3/organization/${project.organization}`).catch(handleError)
organization.value = await useFetch(
`https://api.modrinth.com/v3/organization/${project.organization}`,
).catch(handleError)
}
versions.value = versions.value.sort((a, b) => dayjs(b.date_published) - dayjs(a.date_published))

View File

@ -1,13 +1,21 @@
<template>
<Teleport to="#sidebar-teleport-target">
<UserSidebarOrganizations :organizations="organizations" :link="(org: Organization) => `/organization/${org.id}${instanceQueryAppendage}`" class="project-sidebar-section" />
<UserSidebarOrganizations
:organizations="organizations"
:link="(org: Organization) => `/organization/${org.id}${instanceQueryAppendage}`"
class="project-sidebar-section"
/>
<UserSidebarBadges
v-if="user"
:user="user"
:download-count="sumDownloads"
class="project-sidebar-section"
/>
<UserSidebarCollections :collections="collections" :link="(collection: Collection) => `/collection/${collection.id}${instanceQueryAppendage}`" class="project-sidebar-section" />
<UserSidebarCollections
:collections="collections"
:link="(collection: Collection) => `/collection/${collection.id}${instanceQueryAppendage}`"
class="project-sidebar-section"
/>
</Teleport>
<div v-if="user" class="p-6 flex flex-col gap-4">
<InstanceIndicator :instance="instance" />
@ -16,9 +24,13 @@
<ButtonStyled circular type="transparent" size="large">
<OverflowMenu
:options="[
{ id: 'report', link: `https://modrinth.com/report?item=user&itemID=${user.id}`, color: 'red' },
{ id: 'copy-id', action: () => copyId(), shown: themeStore.devMode },
]"
{
id: 'report',
link: `https://modrinth.com/report?item=user&itemID=${user.id}`,
color: 'red',
},
{ id: 'copy-id', action: () => copyId(), shown: themeStore.devMode },
]"
aria-label="More options"
>
<MoreVerticalIcon aria-hidden="true" />
@ -35,9 +47,17 @@
</template>
</UserHeader>
<div v-if="projects">
<ProjectsList :projects="projects" :project-link="(project) => `/project/${project.id}${instanceQueryAppendage}`" :experimental-colors="themeStore.featureFlags.project_card_background">
<ProjectsList
:projects="projects"
:project-link="(project) => `/project/${project.id}${instanceQueryAppendage}`"
:experimental-colors="themeStore.featureFlags.project_card_background"
>
<template #project-actions="{ project }">
<ProjectCardActions :instance="instance" :instance-content="instanceContent" :project="project" />
<ProjectCardActions
:instance="instance"
:instance-content="instanceContent"
:project="project"
/>
</template>
</ProjectsList>
</div>
@ -55,7 +75,8 @@ import {
commonMessages,
OverflowMenu,
UserHeader,
UserSidebarBadges, UserSidebarCollections
UserSidebarBadges,
UserSidebarCollections,
} from '@modrinth/ui'
import { ReportIcon, ClipboardCopyIcon, MoreVerticalIcon } from '@modrinth/assets'
import { useVIntl } from '@vintl/vintl'
@ -77,15 +98,17 @@ const organizations: Ref<Organization[]> = ref([])
const collections: Ref<Collection[]> = ref([])
async function fetchUser() {
[ user.value, projects.value, organizations.value, collections.value ] = await Promise.all([
;[user.value, projects.value, organizations.value, collections.value] = await Promise.all([
useFetch(`https://api.modrinth.com/v2/user/${route.params.id}`).catch(handleError),
useFetch(`https://api.modrinth.com/v2/user/${route.params.id}/projects`).catch(handleError),
useFetch(`https://api.modrinth.com/v3/user/${route.params.id}/organizations`).catch(handleError),
useFetch(`https://api.modrinth.com/v3/user/${route.params.id}/collections`).catch(handleError)
useFetch(`https://api.modrinth.com/v3/user/${route.params.id}/organizations`).catch(
handleError,
),
useFetch(`https://api.modrinth.com/v3/user/${route.params.id}/collections`).catch(handleError),
])
if (!user.value) {
return;
return
}
breadcrumbs.setContext({ name: 'User', link: `/user/${user.value.username}` })
@ -107,22 +130,21 @@ watch(
const themeStore = useTheming()
async function copyId() {
if (user.value) {
await navigator.clipboard.writeText(String(user.value.id));
await navigator.clipboard.writeText(String(user.value.id))
}
}
const sumDownloads = computed(() => {
let sum = 0;
let sum = 0
for (const project of projects.value) {
sum += project.downloads;
sum += project.downloads
}
return sum;
});
return sum
})
</script>
<style scoped lang="scss">
.project-sidebar-section {

View File

@ -1,9 +1,9 @@
import { defineStore } from 'pinia'
export const DEFAULT_FEATURE_FLAGS = {
'project_background': false,
'page_path': false,
'project_card_background': false,
project_background: false,
page_path: false,
project_card_background: false,
}
export const useTheming = defineStore('themeStore', {