fix: remove legacy button classes (#7011)

* fix: remove legacy button-group class for tailwind (conflicts)

* fix: delete legacy button classes from scss

* fix: fmt
This commit is contained in:
Calum H.
2026-08-05 16:34:00 +02:00
committed by GitHub
parent c0e6f094d9
commit 0038ea8b15
23 changed files with 162 additions and 564 deletions
-103
View File
@@ -1,103 +0,0 @@
<template>
<div class="chips">
<button
v-for="item in items"
:key="item"
class="iconified-button"
:class="{ selected: selected === item, capitalize: capitalize }"
@click="toggleItem(item)"
>
<CheckIcon v-if="selected === item" />
<span>{{ formatLabel(item) }}</span>
</button>
</div>
</template>
<script>
import { CheckIcon } from '@modrinth/assets'
export default {
components: {
CheckIcon,
},
props: {
modelValue: {
required: true,
type: String,
},
items: {
required: true,
type: Array,
},
neverEmpty: {
default: true,
type: Boolean,
},
formatLabel: {
default: (x) => x,
type: Function,
},
capitalize: {
type: Boolean,
default: true,
},
},
emits: ['update:modelValue'],
computed: {
selected: {
get() {
return this.modelValue
},
set(value) {
this.$emit('update:modelValue', value)
},
},
},
created() {
if (this.items.length > 0 && this.neverEmpty) {
this.selected = this.items[0]
}
},
methods: {
toggleItem(item) {
if (this.selected === item && !this.neverEmpty) {
this.selected = null
} else {
this.selected = item
}
},
},
}
</script>
<style lang="scss" scoped>
.chips {
display: flex;
grid-gap: 0.5rem;
flex-wrap: wrap;
.iconified-button {
&.capitalize {
text-transform: capitalize;
}
svg {
width: 1em;
height: 1em;
}
&:focus-visible {
outline: 0.25rem solid var(--color-focus-ring);
border-radius: 0.25rem;
}
}
.selected {
color: var(--color-button-text-active);
background-color: var(--color-brand-highlight);
box-shadow:
inset 0 0 0 transparent,
0 0 0 2px var(--color-brand);
}
}
</style>
@@ -7,7 +7,7 @@ import {
ToggleRightIcon,
TwitterIcon,
} from '@modrinth/assets'
import { ButtonLink } from '@modrinth/ui'
import { Button, ButtonLink } from '@modrinth/ui'
import {
AutoLink,
defineMessage,
@@ -266,11 +266,17 @@ function developerModeIncrement() {
:aria-label="formatMessage(messages.modrinthInformation)"
>
<div class="flex items-center gap-2">
<TextLogo
aria-hidden="true"
class="text-logo button-base h-6 w-auto text-contrast lg:h-8"
<Button
type="quiet"
interaction="none"
aria-label="Modrinth"
class="!h-auto !p-0"
@click="developerModeIncrement()"
/>
>
<span class="inline-flex">
<TextLogo aria-hidden="true" class="text-logo h-6 w-auto text-contrast lg:h-8" />
</span>
</Button>
<ButtonLink
v-if="flags.developerMode"
v-tooltip="formatMessage(commonSettingsMessages.featureFlags)"
+12 -7
View File
@@ -17,10 +17,12 @@
{{ item.label }}
</div>
<NuxtLink
<ButtonLink
v-else-if="item.link ?? item.to"
type="quiet"
interaction="surface"
:to="(item.link ?? item.to) as string"
class="nav-item inline-flex w-full cursor-pointer items-center gap-2 rounded-xl border-none bg-transparent px-4 py-2.5 text-left text-base font-semibold leading-tight text-button-text transition-all hover:bg-button-bg hover:text-contrast active:scale-[0.97]"
class="nav-item !h-auto !w-full !justify-start !rounded-xl !px-4 !py-2.5 text-left leading-tight"
:class="{ 'is-active': isActive(item as NavStackLinkItem) }"
>
<component
@@ -37,12 +39,14 @@
{{ String(item.badge) }}
</span>
<span v-if="item.chevron" class="ml-auto"><ChevronRightIcon /></span>
</NuxtLink>
</ButtonLink>
<button
<Button
v-else-if="item.action"
class="nav-item inline-flex w-full cursor-pointer items-center gap-2 text-nowrap rounded-xl border-none bg-transparent px-4 py-2.5 text-left text-base font-semibold leading-tight text-button-text transition-all hover:bg-button-bg hover:text-contrast active:scale-[0.97]"
:class="{ 'danger-button': item.danger }"
type="quiet"
interaction="surface"
:color="item.danger ? 'red' : undefined"
class="nav-item !h-auto !w-full !justify-start !rounded-xl !px-4 !py-2.5 text-left leading-tight"
@click="item.action"
>
<component
@@ -58,7 +62,7 @@
>
{{ String(item.badge) }}
</span>
</button>
</Button>
<span v-else>You frog. 🐸</span>
</li>
@@ -69,6 +73,7 @@
<script setup lang="ts">
import { ChevronRightIcon } from '@modrinth/assets'
import { Button, ButtonLink } from '@modrinth/ui'
import { type Component, computed, useSlots } from 'vue'
type NavStackBaseItem = {
@@ -1,128 +0,0 @@
<template>
<nav
ref="scrollContainer"
class="card-shadow relative flex w-fit overflow-x-auto rounded-full bg-bg-raised p-1 text-sm font-bold"
>
<button
v-for="(option, index) in options"
:key="`option-group-${index}`"
ref="optionButtons"
class="button-animation z-[1] flex flex-row items-center gap-2 rounded-full bg-transparent px-4 py-2 font-semibold"
:class="{
'text-button-textSelected': modelValue === option,
'text-primary': modelValue !== option,
}"
@click="setOption(option)"
>
<slot :option="option" :selected="modelValue === option" />
</button>
<div
class="navtabs-transition pointer-events-none absolute h-[calc(100%-0.5rem)] overflow-hidden rounded-full bg-button-bgSelected p-1"
:style="{
left: sliderLeftPx,
top: sliderTopPx,
right: sliderRightPx,
bottom: sliderBottomPx,
opacity: initialized ? 1 : 0,
}"
aria-hidden="true"
></div>
</nav>
</template>
<script setup lang="ts" generic="T">
import { computed, onMounted, ref } from 'vue'
const modelValue = defineModel<T>({ required: true })
const props = defineProps<{
options: T[]
}>()
const scrollContainer = ref<HTMLElement | null>(null)
const sliderLeft = ref(4)
const sliderTop = ref(4)
const sliderRight = ref(4)
const sliderBottom = ref(4)
const sliderLeftPx = computed(() => `${sliderLeft.value}px`)
const sliderTopPx = computed(() => `${sliderTop.value}px`)
const sliderRightPx = computed(() => `${sliderRight.value}px`)
const sliderBottomPx = computed(() => `${sliderBottom.value}px`)
const optionButtons = ref()
const initialized = ref(false)
function setOption(option: T) {
modelValue.value = option
}
watch(modelValue, () => {
startAnimation(props.options.indexOf(modelValue.value))
})
function startAnimation(index: number) {
const el = optionButtons.value[index]
if (!el || !el.offsetParent) return
const newValues = {
left: el.offsetLeft,
top: el.offsetTop,
right: el.offsetParent.offsetWidth - el.offsetLeft - el.offsetWidth,
bottom: el.offsetParent.offsetHeight - el.offsetTop - el.offsetHeight,
}
if (sliderLeft.value === 4 && sliderRight.value === 4) {
sliderLeft.value = newValues.left
sliderRight.value = newValues.right
sliderTop.value = newValues.top
sliderBottom.value = newValues.bottom
} else {
const delay = 200
if (newValues.left < sliderLeft.value) {
sliderLeft.value = newValues.left
setTimeout(() => {
sliderRight.value = newValues.right
}, delay)
} else {
sliderRight.value = newValues.right
setTimeout(() => {
sliderLeft.value = newValues.left
}, delay)
}
if (newValues.top < sliderTop.value) {
sliderTop.value = newValues.top
setTimeout(() => {
sliderBottom.value = newValues.bottom
}, delay)
} else {
sliderBottom.value = newValues.bottom
setTimeout(() => {
sliderTop.value = newValues.top
}, delay)
}
}
initialized.value = true
}
onMounted(() => {
startAnimation(props.options.indexOf(modelValue.value))
})
</script>
<style scoped>
.navtabs-transition {
transition:
all 150ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 250ms cubic-bezier(0.5, 0, 0.2, 1) 50ms;
}
.card-shadow {
box-shadow: var(--shadow-card);
}
</style>
@@ -6,7 +6,7 @@
</p>
<p v-else>{{ getFormattedMessage(messages.invitationNoRole) }}</p>
<div class="input-group">
<Button type="colored" color="brand" class="brand-button" @click="acceptInvite()">
<Button type="colored" color="brand" @click="acceptInvite()">
<CheckIcon />
{{ getFormattedMessage(commonMessages.acceptButton) }}
</Button>
@@ -275,7 +275,6 @@
{{ formatMessage(messages.actionApprove) }}
</Button>
<SplitButton
class="!m-0 !inline-flex !flex-nowrap !justify-start !gap-0"
type="colored"
color="red"
:menu-label="formatMessage(commonMessages.moreOptionsButton)"