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

@@ -164,23 +164,31 @@ function setColorFill(
}
const colorVariables = computed(() => {
const defaultShadow =
props.type === 'standard' || props.type === 'highlight' || props.highlighted
? 'var(--shadow-button)'
: 'none'
if (props.highlighted) {
const colors = {
bg:
props.highlightedStyle === 'main-nav-primary'
? 'var(--color-brand-highlight)'
? 'var(--color-button-bg-selected)'
: 'var(--color-button-bg)',
text: 'var(--color-contrast)',
text:
props.highlightedStyle === 'main-nav-primary'
? 'var(--color-button-text-selected)'
: 'var(--color-contrast)',
icon:
props.type === 'chip'
? 'var(--color-contrast)'
: props.highlightedStyle === 'main-nav-primary'
? 'var(--color-brand)'
? 'var(--color-button-text-selected)'
: 'var(--color-contrast)',
}
const hoverColors = JSON.parse(JSON.stringify(colors))
const boxShadow =
props.type === 'chip' && colorVar.value ? `0 0 0 2px ${colorVar.value}` : 'none'
props.type === 'chip' && colorVar.value ? `0 0 0 2px ${colorVar.value}` : defaultShadow
return `--_bg: ${colors.bg}; --_text: ${colors.text}; --_icon: ${colors.icon}; --_hover-bg: ${hoverColors.bg}; --_hover-text: ${hoverColors.text}; --_hover-icon: ${hoverColors.icon}; --_box-shadow: ${boxShadow};`
}
@@ -217,7 +225,8 @@ const colorVariables = computed(() => {
)
}
const boxShadow = props.type === 'chip' && colorVar.value ? `0 0 0 2px ${colorVar.value}` : 'none'
const boxShadow =
props.type === 'chip' && colorVar.value ? `0 0 0 2px ${colorVar.value}` : defaultShadow
return `--_bg: ${colors.bg}; --_text: ${colors.text}; --_hover-bg: ${hoverColors.bg}; --_hover-text: ${hoverColors.text}; --_box-shadow: ${boxShadow};`
})

View File

@@ -1,31 +1,38 @@
<template>
<div
class="checkbox-outer button-within"
:class="{ disabled }"
role="presentation"
<button
class="group bg-transparent border-none p-0 m-0 flex items-center gap-3 checkbox-outer outline-offset-4 text-contrast"
:disabled="disabled"
:class="
disabled
? 'cursor-not-allowed opacity-50'
: 'cursor-pointer hover:brightness-[--hover-brightness] focus-visible:brightness-[--hover-brightness]'
"
:aria-label="description"
:aria-checked="modelValue"
role="checkbox"
@click="toggle"
>
<button
class="checkbox border-none"
role="checkbox"
:disabled="disabled"
:class="{ checked: modelValue, collapsing: collapsingToggleStyle }"
:aria-label="description"
:aria-checked="modelValue"
<span
class="w-5 h-5 rounded-md flex items-center justify-center border-[1px] border-solid"
:class="
(modelValue
? 'bg-brand border-button-border text-brand-inverted'
: 'bg-surface-2 border-surface-5') +
(disabled ? '' : ' checkbox-shadow group-active:scale-95')
"
>
<MinusIcon v-if="indeterminate" aria-hidden="true" />
<CheckIcon v-else-if="modelValue && !collapsingToggleStyle" aria-hidden="true" />
<DropdownIcon v-else-if="collapsingToggleStyle" aria-hidden="true" />
</button>
<MinusIcon v-if="indeterminate" aria-hidden="true" stroke-width="3" />
<CheckIcon v-else-if="modelValue" aria-hidden="true" stroke-width="3" />
</span>
<!-- aria-hidden is set so screenreaders only use the <button>'s aria-label -->
<p v-if="label" aria-hidden="true" class="checkbox-label">
<span v-if="label" aria-hidden="true">
{{ label }}
</p>
</span>
<slot v-else />
</div>
</button>
</template>
<script setup lang="ts">
import { CheckIcon, DropdownIcon, MinusIcon } from '@modrinth/assets'
import { CheckIcon, MinusIcon } from '@modrinth/assets'
const emit = defineEmits<{
'update:modelValue': [boolean]
@@ -38,7 +45,6 @@ const props = withDefaults(
description?: string
modelValue: boolean
clickEvent?: () => void
collapsingToggleStyle?: boolean
indeterminate?: boolean
}>(),
{
@@ -47,7 +53,6 @@ const props = withDefaults(
description: '',
modelValue: false,
clickEvent: () => {},
collapsingToggleStyle: false,
indeterminate: false,
},
)
@@ -60,86 +65,7 @@ function toggle() {
</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;
}
}
.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-contrast);
background-color: var(--color-button-bg);
border-radius: var(--radius-xs);
box-shadow:
var(--shadow-inset-sm),
0 0 0 0 transparent;
&.checked {
background-color: var(--color-brand);
svg {
color: var(--color-accent-contrast);
}
}
svg {
color: var(--color-secondary);
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;
@media (prefers-reduced-motion) {
transition: none !important;
}
}
&.checked {
svg {
transform: rotate(180deg);
}
}
}
&:disabled {
box-shadow: none;
cursor: not-allowed;
}
}
.checkbox-label {
color: var(--color-base);
.checkbox-shadow {
box-shadow: 1px 1px 2px 0 rgba(0, 0, 0, 0.08);
}
</style>

View File

@@ -891,7 +891,7 @@ function openVideoModal() {
}
.markdown-body-wrapper {
border: 1px solid var(--color-button-bg);
border: 1px solid var(--color-divider);
border-radius: var(--radius-md);
width: 100%;
padding: var(--radius-md);

View File

@@ -14,7 +14,7 @@
<div
v-if="isDivider(option)"
:key="`divider-${index}`"
class="h-px mx-3 my-2 bg-button-bg"
class="h-px mx-3 my-2 bg-surface-5"
></div>
<Button
v-else

View File

@@ -286,7 +286,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;
}
@@ -301,7 +301,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

@@ -161,10 +161,10 @@ const chartOptions = ref({
display: flex;
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);
width: 100%;
@@ -190,7 +190,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

@@ -151,21 +151,10 @@ const visible = ref(false)
const scrollContainer = ref<HTMLElement | null>(null)
const { showTopFade, showBottomFade, checkScrollState } = useScrollIndicator(scrollContainer)
// make modal opening not shift page when there's a vertical scrollbar
function addBodyPadding() {
const scrollBarWidth = window.innerWidth - document.documentElement.clientWidth
if (scrollBarWidth > 0) {
document.body.style.paddingRight = `${scrollBarWidth}px`
} else {
document.body.style.paddingRight = ''
}
}
function show(event?: MouseEvent) {
props.onShow?.()
open.value = true
addBodyPadding()
document.body.style.overflow = 'hidden'
window.addEventListener('mousedown', updateMousePosition)
window.addEventListener('keydown', handleKeyDown)
@@ -184,7 +173,6 @@ function hide() {
props.onHide?.()
visible.value = false
document.body.style.overflow = ''
document.body.style.paddingRight = ''
window.removeEventListener('mousedown', updateMousePosition)
window.removeEventListener('keydown', handleKeyDown)
setTimeout(() => {

View File

@@ -50,7 +50,7 @@
<template v-for="(version, index) in currentVersions" :key="index">
<!-- Row divider -->
<div
class="versions-grid-row h-px w-full bg-button-bg"
class="versions-grid-row h-px w-full bg-surface-5"
:class="{
'max-sm:!hidden': index === 0,
}"