refactor: Button components (#6929)

* feat: refactor button components

* fix: qa

* fix: storybook

* a11y: pass

* fix: build

* fix: rename default ->md

* fix: lint

* docs: buttons.md

* refactor part 1

* refactor part 2

* fix: undo refactor for fresh restart

* refactor

* Revert "refactor"

This reverts commit 96d65902d7.

* refactor: part 1

* fix: qa

* fix: qa

* fix: qa

* fix: qa

* fix: qa

* fix: qa

* fix: qa

* fix: qa

* fix: remove text-contrast

* fix: qa

* fix: v-tooltip

* fix: lint

* fix: split broken

* fix: passkey qa

* fix: qa

* fix: qa

* fix: prepr

* fix: splitbutton

* improve button group seam

---------

Signed-off-by: Calum H. <calum@modrinth.com>
Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
This commit is contained in:
Calum H.
2026-08-04 13:54:04 -07:00
committed by GitHub
co-authored by Prospector
parent 6cfe999cb3
commit bb2193b6f5
398 changed files with 13688 additions and 13133 deletions
+35 -35
View File
@@ -39,40 +39,40 @@
</div>
<div class="controls">
<div class="buttons">
<ButtonStyled circular>
<button class="close" @click="hideImage">
<XIcon aria-hidden="true" />
</button>
</ButtonStyled>
<ButtonStyled circular>
<a
class="open btn icon-only"
target="_blank"
:href="
expandedGalleryItem.raw_url
? expandedGalleryItem.raw_url
: 'https://cdn.modrinth.com/placeholder-banner.svg'
"
>
<ExternalIcon aria-hidden="true" />
</a>
</ButtonStyled>
<ButtonStyled circular>
<button @click="zoomedIn = !zoomedIn">
<ExpandIcon v-if="!zoomedIn" aria-hidden="true" />
<ContractIcon v-else aria-hidden="true" />
</button>
</ButtonStyled>
<ButtonStyled v-if="filteredGallery.length > 1" circular>
<button class="previous" @click="previousImage()">
<LeftArrowIcon aria-hidden="true" />
</button>
</ButtonStyled>
<ButtonStyled v-if="filteredGallery.length > 1" circular>
<button class="next" @click="nextImage()">
<RightArrowIcon aria-hidden="true" />
</button>
</ButtonStyled>
<IconButton label="Close" class="close" @click="hideImage">
<XIcon aria-hidden="true" />
</IconButton>
<ButtonLink
class="open btn icon-only !w-9 !px-0 !rounded-full"
target="_blank"
:href="
expandedGalleryItem.raw_url
? expandedGalleryItem.raw_url
: 'https://cdn.modrinth.com/placeholder-banner.svg'
"
>
<ExternalIcon aria-hidden="true" />
</ButtonLink>
<IconButton label="Toggle zoom" @click="zoomedIn = !zoomedIn">
<ExpandIcon v-if="!zoomedIn" aria-hidden="true" />
<ContractIcon v-else aria-hidden="true" />
</IconButton>
<IconButton
v-if="filteredGallery.length > 1"
label="Previous image"
class="previous"
@click="previousImage()"
>
<LeftArrowIcon aria-hidden="true" />
</IconButton>
<IconButton
v-if="filteredGallery.length > 1"
label="Next image"
class="next"
@click="nextImage()"
>
<RightArrowIcon aria-hidden="true" />
</IconButton>
</div>
</div>
</div>
@@ -90,7 +90,7 @@ import {
RightArrowIcon,
XIcon,
} from '@modrinth/assets'
import { ButtonStyled, Card, useFormatDateTime } from '@modrinth/ui'
import { ButtonLink, Card, IconButton, useFormatDateTime } from '@modrinth/ui'
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
+102 -84
View File
@@ -70,87 +70,104 @@
>
<template #actions>
<template v-if="isServerProject">
<ButtonStyled v-if="serverPlaying" color="red" size="large">
<button type="button" @click="handleStopServer">
<StopCircleIcon />
{{ formatMessage(commonMessages.stopButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-else color="brand" size="large">
<button type="button" :disabled="serverInstallLoading" @click="handleClickPlay">
<PlayIcon />
{{
serverInstallLoading
? formatMessage(commonMessages.installingLabel)
: formatMessage(commonMessages.playButton)
}}
</button>
</ButtonStyled>
<ButtonStyled circular size="large">
<button
v-tooltip="formatMessage(commonMessages.addServerToInstanceButton)"
type="button"
:aria-label="formatMessage(commonMessages.addServerToInstanceButton)"
@click="handleAddServerToInstance"
>
<PlusIcon />
</button>
</ButtonStyled>
<ButtonStyled circular size="large" type="transparent">
<TeleportOverflowMenu
:options="serverProjectHeaderMoreActions"
tooltip="More options"
aria-label="More options"
>
<MoreVerticalIcon />
</TeleportOverflowMenu>
</ButtonStyled>
<Button
v-if="serverPlaying"
type="colored"
color="red"
size="xl"
native-type="button"
@click="handleStopServer"
>
<StopCircleIcon />
{{ formatMessage(commonMessages.stopButton) }}
</Button>
<Button
v-else
type="colored"
color="brand"
size="xl"
native-type="button"
:disabled="serverInstallLoading"
@click="handleClickPlay"
>
<PlayIcon />
{{
serverInstallLoading
? formatMessage(commonMessages.installingLabel)
: formatMessage(commonMessages.playButton)
}}
</Button>
<IconButton
v-tooltip="formatMessage(commonMessages.addServerToInstanceButton)"
size="xl"
:label="formatMessage(commonMessages.addServerToInstanceButton)"
native-type="button"
@click="handleAddServerToInstance"
>
<PlusIcon />
</IconButton>
<TeleportOverflowMenu
type="quiet"
size="xl"
label="More options"
:options="serverProjectHeaderMoreActions"
>
<MoreVerticalIcon />
</TeleportOverflowMenu>
</template>
<template v-else>
<ButtonStyled v-if="showSwitchVersion && onVersionsPage" size="large">
<button v-tooltip="formatMessage(messages.alreadyInstalled)" type="button" disabled>
<CheckIcon />
{{ formatMessage(commonMessages.installedLabel) }}
</button>
</ButtonStyled>
<ButtonStyled v-else-if="showSwitchVersion" size="large">
<button type="button" @click="goToVersions">
<SwapIcon />
{{ formatMessage(messages.switchVersion) }}
</button>
</ButtonStyled>
<ButtonStyled v-else color="brand" size="large">
<button
v-tooltip="
installButtonInstalled ? formatMessage(messages.alreadyInstalled) : undefined
"
type="button"
:disabled="installButtonDisabled"
@click="install(null)"
>
<component :is="installButtonIcon" :class="installButtonIconClass" />
{{
installButtonInstalled
? formatMessage(commonMessages.installedLabel)
: installButtonValidating
? formatMessage(commonMessages.validatingLabel)
: installButtonLoading
? formatMessage(commonMessages.installingLabel)
: serverProjectSelected
? formatMessage(commonMessages.selectedLabel)
: formatMessage(commonMessages.installButton)
}}
</button>
</ButtonStyled>
<ButtonStyled circular size="large" type="transparent">
<TeleportOverflowMenu
:options="projectHeaderMoreActions"
tooltip="More options"
aria-label="More options"
>
<MoreVerticalIcon />
</TeleportOverflowMenu>
</ButtonStyled>
<Button
v-if="showSwitchVersion && onVersionsPage"
v-tooltip="formatMessage(messages.alreadyInstalled)"
size="xl"
native-type="button"
disabled
>
<CheckIcon />
{{ formatMessage(commonMessages.installedLabel) }}
</Button>
<Button
v-else-if="showSwitchVersion"
size="xl"
native-type="button"
@click="goToVersions"
>
<SwapIcon />
{{ formatMessage(messages.switchVersion) }}
</Button>
<Button
v-else
v-tooltip="
installButtonInstalled ? formatMessage(messages.alreadyInstalled) : undefined
"
type="colored"
color="brand"
size="xl"
native-type="button"
:disabled="installButtonDisabled"
@click="install(null)"
>
<component :is="installButtonIcon" :class="installButtonIconClass" />
{{
installButtonInstalled
? formatMessage(commonMessages.installedLabel)
: installButtonValidating
? formatMessage(commonMessages.validatingLabel)
: installButtonLoading
? formatMessage(commonMessages.installingLabel)
: serverProjectSelected
? formatMessage(commonMessages.selectedLabel)
: formatMessage(commonMessages.installButton)
}}
</Button>
<TeleportOverflowMenu
type="quiet"
size="xl"
label="More options"
:options="projectHeaderMoreActions"
>
<MoreVerticalIcon />
</TeleportOverflowMenu>
</template>
</template>
</ProjectPageHeader>
@@ -241,11 +258,12 @@ import {
} from '@modrinth/assets'
import {
BrowseInstallHeader,
ButtonStyled,
Button,
commonMessages,
CreationFlowModal,
defineMessages,
getTargetInstallPreferences,
IconButton,
injectNotificationManager,
NavTabs,
ProjectBackgroundGradient,
@@ -571,13 +589,13 @@ const serverProjectHeaderMoreActions = computed(() => [
action: openProjectInBrowser,
},
{
divider: true,
type: 'divider',
},
{
id: 'report',
label: formatMessage(commonMessages.reportButton),
icon: ReportIcon,
color: 'red',
tone: 'red',
action: reportProject,
},
])
@@ -605,13 +623,13 @@ const projectHeaderMoreActions = computed(() => [
action: openProjectInBrowser,
},
{
divider: true,
type: 'divider',
},
{
id: 'report',
label: formatMessage(commonMessages.reportButton),
icon: ReportIcon,
color: 'red',
tone: 'red',
action: reportProject,
},
])
+55 -56
View File
@@ -15,62 +15,62 @@
:dependency-link-creator="createDependencyLink"
>
<template #headerActions>
<ButtonStyled color="brand">
<button
:disabled="installing || (installed && installedVersion === version.id)"
@click="() => version && install(version.id)"
>
<DownloadIcon v-if="!installed" />
<SwapIcon v-else-if="installedVersion !== version.id" />
<CheckIcon v-else />
{{
installing
? formatMessage(messages.installing)
: installed && installedVersion === version.id
? formatMessage(commonMessages.installedLabel)
: installed
? formatMessage(commonMessages.switchToVersionButton)
: formatMessage(commonMessages.installButton)
}}
</button>
</ButtonStyled>
<ButtonStyled type="outlined" circular>
<OverflowMenu
v-tooltip="formatMessage(commonMessages.moreOptionsButton)"
:options="[
{
id: 'open-in-browser',
link: `https://modrinth.com/${project.project_type}/${project.slug}/version/${version.id}`,
external: true,
},
{
id: 'report',
color: 'red',
hoverFilled: true,
link: `https://modrinth.com/report?item=version&itemID=${version.id}`,
external: true,
},
]"
aria-label="More options"
>
<MoreVerticalIcon aria-hidden="true" />
<template #open-in-browser>
<ExternalIcon aria-hidden="true" />
{{ formatMessage(commonMessages.openInBrowserButton) }}
</template>
<template #report>
<ReportIcon aria-hidden="true" /> {{ formatMessage(commonMessages.reportButton) }}
</template>
</OverflowMenu>
</ButtonStyled>
<Button
type="colored"
color="brand"
:disabled="installing || (installed && installedVersion === version.id)"
@click="() => version && install(version.id)"
>
<DownloadIcon v-if="!installed" />
<SwapIcon v-else-if="installedVersion !== version.id" />
<CheckIcon v-else />
{{
installing
? formatMessage(messages.installing)
: installed && installedVersion === version.id
? formatMessage(commonMessages.installedLabel)
: installed
? formatMessage(commonMessages.switchToVersionButton)
: formatMessage(commonMessages.installButton)
}}
</Button>
<TeleportOverflowMenu
type="outlined"
label="More options"
:tooltip="formatMessage(commonMessages.moreOptionsButton)"
:options="[
{
id: 'open-in-browser',
label: formatMessage(commonMessages.openInBrowserButton),
type: 'link',
href: `https://modrinth.com/${project.project_type}/${project.slug}/version/${version.id}`,
target: '_blank',
},
{
id: 'report',
label: formatMessage(commonMessages.reportButton),
type: 'link',
tone: 'red',
href: `https://modrinth.com/report?item=version&itemID=${version.id}`,
target: '_blank',
},
]"
>
<MoreVerticalIcon aria-hidden="true" />
<template #open-in-browser>
<ExternalIcon aria-hidden="true" />
{{ formatMessage(commonMessages.openInBrowserButton) }}
</template>
<template #report>
<ReportIcon aria-hidden="true" /> {{ formatMessage(commonMessages.reportButton) }}
</template>
</TeleportOverflowMenu>
</template>
<template #supplementaryResourceActions="{ file }">
<ButtonStyled>
<a :href="file.url" :download="file.filename" target="_blank">
<DownloadIcon aria-hidden="true" />
{{ formatMessage(messages.downloadInBrowser) }}
</a>
</ButtonStyled>
<ButtonLink :href="file.url" :download="file.filename" target="_blank">
<DownloadIcon aria-hidden="true" />
{{ formatMessage(messages.downloadInBrowser) }}
</ButtonLink>
</template>
</VersionPage>
</div>
@@ -87,12 +87,11 @@ import {
ReportIcon,
VersionIcon,
} from '@modrinth/assets'
import { Button, ButtonLink, TeleportOverflowMenu } from '@modrinth/ui'
import {
ButtonStyled,
commonMessages,
defineMessages,
type DependencyContext,
OverflowMenu,
useVIntl,
VersionPage,
} from '@modrinth/ui'
@@ -9,76 +9,53 @@
:version-link="(version) => buildProjectHref(`/project/${project.id}/version/${version.id}`)"
>
<template #actions="{ version }">
<ButtonStyled
circular
type="transparent"
:color="installed && version.id === installedVersion ? 'standard' : 'green'"
<IconButton
v-tooltip="
!installed
? formatMessage(commonMessages.installButton)
: version.id !== installedVersion
? formatMessage(commonMessages.switchToVersionButton)
: formatMessage(messages.alreadyInstalled)
"
type="quiet"
:color="installed && version.id === installedVersion ? undefined : 'green'"
:label="
!installed
? formatMessage(commonMessages.installButton)
: version.id !== installedVersion
? formatMessage(commonMessages.switchToVersionButton)
: formatMessage(messages.alreadyInstalled)
"
:disabled="installing || (installed && version.id === installedVersion)"
@click.stop="() => install(version.id)"
>
<button
v-tooltip="
!installed
? formatMessage(commonMessages.installButton)
: version.id !== installedVersion
? formatMessage(commonMessages.switchToVersionButton)
: formatMessage(messages.alreadyInstalled)
"
:disabled="installing || (installed && version.id === installedVersion)"
@click.stop="() => install(version.id)"
>
<DownloadIcon v-if="!installed" />
<SwapIcon v-else-if="installed && version.id !== installedVersion" />
<CheckIcon v-else />
</button>
</ButtonStyled>
<ButtonStyled circular type="transparent">
<OverflowMenu
v-if="false"
:options="[
{
id: 'install-elsewhere',
action: () => {},
shown: false && !!instance,
color: 'primary',
hoverFilled: true,
},
{
id: 'open-in-browser',
link: `https://modrinth.com/${project.project_type}/${project.slug}/version/${version.id}`,
},
]"
aria-label="More options"
>
<MoreVerticalIcon aria-hidden="true" />
<template #install-elsewhere>
<DownloadIcon aria-hidden="true" />
Add to another instance
</template>
<template #open-in-browser>
<ExternalIcon /> {{ formatMessage(commonMessages.openInBrowserButton) }}
</template>
</OverflowMenu>
<a
v-else
v-tooltip="formatMessage(commonMessages.openInBrowserButton)"
:href="`https://modrinth.com/${project.project_type}/${project.slug}/version/${version.id}`"
target="_blank"
>
<ExternalIcon />
</a>
</ButtonStyled>
<DownloadIcon v-if="!installed" />
<SwapIcon v-else-if="installed && version.id !== installedVersion" />
<CheckIcon v-else />
</IconButton>
<ButtonLink
v-tooltip="formatMessage(commonMessages.openInBrowserButton)"
type="quiet"
:href="`https://modrinth.com/${project.project_type}/${project.slug}/version/${version.id}`"
target="_blank"
:aria-label="formatMessage(commonMessages.openInBrowserButton)"
class="!w-9 !px-0 !rounded-full"
>
<ExternalIcon />
</ButtonLink>
</template>
</ProjectPageVersions>
</div>
</template>
<script setup>
import { CheckIcon, DownloadIcon, ExternalIcon, MoreVerticalIcon } from '@modrinth/assets'
import { CheckIcon, DownloadIcon, ExternalIcon } from '@modrinth/assets'
import {
ButtonStyled,
ButtonLink,
commonMessages,
defineMessages,
IconButton,
injectNotificationManager,
OverflowMenu,
ProjectPageVersions,
useVIntl,
} from '@modrinth/ui'