Fix a number of light mode issues and get rid of scrollbar jumping on menus (#4760)

* Fix DEV-466, Fixes #4692 as well as a bunch of other poor contrast and inconsistency issues in light mode. Adds shadows to buttons and makes scrollbar gutter stable.

* lintttt & only do scrollbar gutter on website

* try to fix following hydration issue

* try another clientonly approach

* fix home page link animation

* lint

* remove dropdown style from checkbox & improve shadow consistency

* liiiint
This commit is contained in:
Prospector
2025-11-13 15:21:43 -08:00
committed by GitHub
parent c27f787c91
commit 94c0003c19
40 changed files with 384 additions and 693 deletions

View File

@@ -1,151 +0,0 @@
<template>
<div
class="checkbox-outer button-within"
:class="{ disabled, checked: modelValue }"
role="presentation"
@click="toggle"
>
<button
class="checkbox"
role="checkbox"
:disabled="disabled"
:class="{ checked: modelValue, collapsing: collapsingToggleStyle }"
:aria-label="description ?? label"
:aria-checked="modelValue"
>
<CheckIcon v-if="modelValue && !collapsingToggleStyle" aria-hidden="true" />
<DropdownIcon v-else-if="collapsingToggleStyle" aria-hidden="true" />
</button>
<!-- aria-hidden is set so screenreaders only use the <button>'s aria-label -->
<p v-if="label" aria-hidden="true">
{{ label }}
</p>
<slot v-else />
</div>
</template>
<script>
import { CheckIcon, DropdownIcon } from '@modrinth/assets'
export default {
components: {
CheckIcon,
DropdownIcon,
},
props: {
label: {
type: String,
required: false,
default: '',
},
disabled: {
type: Boolean,
required: false,
default: false,
},
description: {
type: String,
required: false,
default: null,
},
modelValue: Boolean,
clickEvent: {
type: Function,
required: false,
default: () => {},
},
collapsingToggleStyle: {
type: Boolean,
required: false,
default: false,
},
},
emits: ['update:modelValue'],
methods: {
toggle() {
if (!this.disabled) {
this.$emit('update:modelValue', !this.modelValue)
}
},
},
}
</script>
<style lang="scss" scoped>
.checkbox-outer {
display: flex;
align-items: center;
cursor: pointer;
p {
user-select: none;
padding: 0.2rem 0;
margin: 0;
}
&.disabled {
cursor: not-allowed;
}
&.checked {
outline: 2px solid transparent;
outline-offset: 4px;
border-radius: 0.25rem;
}
}
.checkbox {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
min-width: 1rem;
min-height: 1rem;
padding: 0;
margin: 0 0.5rem 0 0;
color: var(--color-button-text);
background-color: var(--color-button-bg);
border-radius: var(--size-rounded-control);
box-shadow:
var(--shadow-inset-sm),
0 0 0 0 transparent;
&.checked {
background-color: var(--color-brand);
}
svg {
color: var(--color-accent-contrast, var(--color-brand-inverted));
stroke-width: 0.2rem;
height: 0.8rem;
width: 0.8rem;
flex-shrink: 0;
}
&.collapsing {
background-color: transparent !important;
box-shadow: none;
svg {
color: inherit;
height: 1rem;
width: 1rem;
transition: transform 0.25s ease-in-out;
}
&.checked {
svg {
transform: rotate(180deg);
}
}
}
&:disabled {
box-shadow: none;
cursor: not-allowed;
}
}
</style>

View File

@@ -1,6 +1,8 @@
<template>
<nav :aria-label="ariaLabel" class="w-full">
<ul class="m-0 flex list-none flex-col items-start gap-1.5 rounded-2xl bg-bg-raised p-4">
<ul
class="card-shadow m-0 flex list-none flex-col items-start gap-1.5 rounded-2xl bg-bg-raised p-4"
>
<slot v-if="hasSlotContent" />
<template v-else>

View File

@@ -152,7 +152,7 @@ const onSubmitHandler = () => {
border-radius: var(--radius-md);
overflow: hidden;
margin-top: var(--gap-md);
border: 1px solid var(--color-button-bg);
border: 1px solid var(--color-divider);
background-color: var(--color-raised-bg);
.table-row {

View File

@@ -356,7 +356,7 @@ svg {
:deep(.apexcharts-yaxistooltip) {
background: var(--color-raised-bg) !important;
border-radius: var(--radius-sm) !important;
border: 1px solid var(--color-button-bg) !important;
border: 1px solid var(--color-divider) !important;
box-shadow: var(--shadow-floating) !important;
font-size: var(--font-size-nm) !important;
}
@@ -371,7 +371,7 @@ svg {
:deep(.apexcharts-xaxistooltip) {
background: var(--color-raised-bg) !important;
border-radius: var(--radius-sm) !important;
border: 1px solid var(--color-button-bg) !important;
border: 1px solid var(--color-divider) !important;
font-size: var(--font-size-nm) !important;
color: var(--color-base) !important;

View File

@@ -891,7 +891,7 @@ const defaultRanges: RangeObject[] = [
flex-direction: column;
background-color: var(--color-bg);
border-radius: var(--radius-sm);
border: 1px solid var(--color-button-bg);
border: 1px solid var(--color-divider);
gap: var(--gap-md);
padding: var(--gap-md);
margin-top: var(--gap-md);
@@ -920,7 +920,7 @@ const defaultRanges: RangeObject[] = [
width: 100%;
height: 1rem;
background-color: var(--color-raised-bg);
border: 1px solid var(--color-button-bg);
border: 1px solid var(--color-divider);
border-radius: var(--radius-sm);
overflow: hidden;

View File

@@ -159,10 +159,10 @@ defineExpose({
flex-direction: column;
gap: var(--gap-xs);
border: 1px solid var(--color-button-bg);
border: 1px solid var(--color-divider);
border-radius: var(--radius-md);
background-color: var(--color-raised-bg);
box-shadow: var(--shadow-floating);
box-shadow: var(--shadow-card);
color: var(--color-base);
font-size: var(--font-size-nm);
@@ -192,7 +192,7 @@ svg {
:deep(.apexcharts-yaxistooltip) {
background: var(--color-raised-bg) !important;
border-radius: var(--radius-sm) !important;
border: 1px solid var(--color-button-bg) !important;
border: 1px solid var(--color-divider) !important;
box-shadow: var(--shadow-floating) !important;
font-size: var(--font-size-nm) !important;
}

View File

@@ -1,77 +0,0 @@
<template>
<Checkbox
class="filter"
:model-value="activeFilters.includes(facetName)"
:description="displayName"
@update:model-value="toggle()"
>
<div class="filter-text">
<div v-if="icon" aria-hidden="true" class="icon" v-html="icon" />
<div v-else class="icon">
<slot />
</div>
<span aria-hidden="true"> {{ displayName }}</span>
</div>
</Checkbox>
</template>
<script>
import Checkbox from '~/components/ui/Checkbox.vue'
export default {
components: {
Checkbox,
},
props: {
facetName: {
type: String,
default: '',
},
displayName: {
type: String,
default: '',
},
icon: {
type: String,
default: '',
},
activeFilters: {
type: Array,
default() {
return []
},
},
},
emits: ['toggle'],
methods: {
toggle() {
this.$emit('toggle', this.facetName)
},
},
}
</script>
<style lang="scss" scoped>
.filter {
margin-bottom: 0.5rem;
:deep(.filter-text) {
display: flex;
align-items: center;
.icon {
height: 1rem;
svg {
margin-right: 0.25rem;
width: 1rem;
height: 1rem;
}
}
}
span {
user-select: none;
}
}
</style>

View File

@@ -245,13 +245,20 @@ import {
LockOpenIcon,
XIcon,
} from '@modrinth/assets'
import { Admonition, Avatar, ButtonStyled, Combobox, CopyCode, NewModal } from '@modrinth/ui'
import {
Admonition,
Avatar,
ButtonStyled,
Checkbox,
Combobox,
CopyCode,
NewModal,
} from '@modrinth/ui'
import TagItem from '@modrinth/ui/src/components/base/TagItem.vue'
import { formatCategory, formatVersionsForDisplay, type Mod, type Version } from '@modrinth/utils'
import { computed, ref } from 'vue'
import Accordion from '~/components/ui/Accordion.vue'
import Checkbox from '~/components/ui/Checkbox.vue'
import ContentVersionFilter, {
type ListedGameVersion,
type ListedPlatform,

View File

@@ -36,7 +36,7 @@
v-for="(option, index) in filteredOptions"
:key="isDivider(option) ? `divider-${index}` : option.id"
>
<div v-if="isDivider(option)" class="h-px w-full bg-button-bg"></div>
<div v-if="isDivider(option)" class="h-px w-full bg-surface-5"></div>
<ButtonStyled v-else type="transparent" role="menuitem" :color="option.color">
<button
v-if="typeof option.action === 'function'"
@@ -288,19 +288,10 @@ const handleMouseOver = (index: number) => {
// Scrolling is disabled for keyboard navigation
const disableBodyScroll = () => {
// Make opening not shift page when there's a vertical scrollbar
const scrollBarWidth = window.innerWidth - document.documentElement.clientWidth
if (scrollBarWidth > 0) {
document.body.style.paddingRight = `${scrollBarWidth}px`
} else {
document.body.style.paddingRight = ''
}
document.body.style.overflow = 'hidden'
}
const enableBodyScroll = () => {
document.body.style.paddingRight = ''
document.body.style.overflow = ''
}

View File

@@ -261,9 +261,14 @@ import {
SendIcon,
XIcon,
} from '@modrinth/assets'
import { CopyCode, injectNotificationManager, MarkdownEditor, OverflowMenu } from '@modrinth/ui'
import {
Checkbox,
CopyCode,
injectNotificationManager,
MarkdownEditor,
OverflowMenu,
} from '@modrinth/ui'
import Checkbox from '~/components/ui/Checkbox.vue'
import Modal from '~/components/ui/Modal.vue'
import ThreadMessage from '~/components/ui/thread/ThreadMessage.vue'
import { useImageUpload } from '~/composables/image-upload.ts'