feat: Moderation Dashboard Overhaul (#4059)

* feat: Moderation Dashboard Overhaul

* fix: lint issues

* fix: issues

* fix: report layout

* fix: lint

* fix: impl quick replies

* fix: remove test qr

* feat: individual report page + use new backend

* feat: memoize filtering

* feat: apply optimizations to moderation queue

* fix: lint issues

* feat: impl quick reply functionality

* fix: top level await

* fix: dep issue

* fix: dep issue x2

* fix: dep issue

* feat: intl extract

* fix: dev-187

* fix: dev-186 & review project btn

* fix: dev-176

* remove redundant moderation button from user dropdown

* correct a msg and add admin to read filter

---------

Co-authored-by: coolbot100s <76798835+coolbot100s@users.noreply.github.com>
This commit is contained in:
IMB11
2025-07-29 22:19:25 +01:00
committed by GitHub
parent c7d0839bfb
commit 6387fb21c6
43 changed files with 3114 additions and 1903 deletions

View File

@@ -0,0 +1,97 @@
<template>
<div
class="relative overflow-hidden rounded-xl border-[2px] border-solid border-divider shadow-lg"
:class="{ 'max-h-32': isCollapsed }"
>
<div
class="px-4 pt-4"
:class="{
'content-disabled pb-16': isCollapsed,
'pb-4': !isCollapsed,
}"
>
<slot />
</div>
<div
v-if="isCollapsed"
class="pointer-events-none absolute inset-0 bg-gradient-to-b from-transparent to-button-bg"
></div>
<div class="absolute bottom-4 left-1/2 z-20 -translate-x-1/2">
<ButtonStyled circular type="transparent">
<button class="flex items-center gap-1 text-xs" @click="toggleCollapsed">
<ExpandIcon v-if="isCollapsed" />
<CollapseIcon v-else />
{{ isCollapsed ? expandText : collapseText }}
</button>
</ButtonStyled>
</div>
</div>
</template>
<script setup lang="ts">
import ButtonStyled from './ButtonStyled.vue'
import { ExpandIcon, CollapseIcon } from '@modrinth/assets'
import { ref } from 'vue'
const props = withDefaults(
defineProps<{
initiallyCollapsed?: boolean
expandText?: string
collapseText?: string
}>(),
{
initiallyCollapsed: true,
expandText: 'Expand',
collapseText: 'Collapse',
},
)
const isCollapsed = ref(props.initiallyCollapsed)
function toggleCollapsed() {
isCollapsed.value = !isCollapsed.value
}
function setCollapsed(value: boolean) {
isCollapsed.value = value
}
defineExpose({
isCollapsed,
setCollapsed,
toggleCollapsed,
})
</script>
<style lang="scss" scoped>
.content-disabled {
pointer-events: none;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
:deep(*) {
pointer-events: none !important;
user-select: none !important;
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
}
:deep(button),
:deep(input),
:deep(textarea),
:deep(select),
:deep(a),
:deep([tabindex]) {
tabindex: -1 !important;
}
:deep(*:focus) {
outline: none !important;
}
}
</style>

View File

@@ -163,7 +163,6 @@ const onFocus = () => {
}
const onBlur = (event) => {
console.log(event)
if (!isChildOfDropdown(event.relatedTarget)) {
dropdownVisible.value = false
}

View File

@@ -10,6 +10,7 @@ export { default as Card } from './base/Card.vue'
export { default as Checkbox } from './base/Checkbox.vue'
export { default as Chips } from './base/Chips.vue'
export { default as Collapsible } from './base/Collapsible.vue'
export { default as CollapsibleRegion } from './base/CollapsibleRegion.vue'
export { default as ContentPageHeader } from './base/ContentPageHeader.vue'
export { default as CopyCode } from './base/CopyCode.vue'
export { default as DoubleIcon } from './base/DoubleIcon.vue'