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
@@ -12,23 +12,19 @@
<template #actions>
<div class="flex justify-end gap-2">
<ButtonStyled type="transparent">
<button @click="modal?.hide()">
{{ formatMessage(analyticsChartMessages.cancelButton) }}
</button>
</ButtonStyled>
<ButtonStyled color="orange">
<button class="!shadow-none" @click="confirm">
{{ formatMessage(analyticsChartMessages.showAll) }}
</button>
</ButtonStyled>
<Button type="quiet" @click="modal?.hide()">
{{ formatMessage(analyticsChartMessages.cancelButton) }}
</Button>
<Button type="colored" color="orange" @click="confirm">
{{ formatMessage(analyticsChartMessages.showAll) }}
</Button>
</div>
</template>
</NewModal>
</template>
<script setup lang="ts">
import { ButtonStyled, NewModal, useVIntl } from '@modrinth/ui'
import { Button, NewModal, useVIntl } from '@modrinth/ui'
import { analyticsChartMessages } from '../../analytics-messages'
@@ -31,23 +31,22 @@
wrapper-class="w-full sm:w-64"
@focusin="selectSearchInputText"
/>
<ButtonStyled>
<OverflowMenu
class="!shadow-none"
:options="csvExportOptions"
:disabled="isDataLoading || filteredRows.length === 0"
>
<DownloadIcon />
{{ formatMessage(analyticsTableMessages.exportCsvButton) }}
<DropdownIcon />
<template #cumulative-csv>
{{ formatMessage(analyticsTableMessages.cumulativeCsv) }}
</template>
<template #grouped-csv>
{{ formatMessage(analyticsTableMessages.groupedCsv, { groupBy: groupByLabel }) }}
</template>
</OverflowMenu>
</ButtonStyled>
<TeleportOverflowMenu
label="More options"
class="!w-auto !rounded-xl !px-2.5"
:options="csvExportOptions"
:disabled="isDataLoading || filteredRows.length === 0"
>
<DownloadIcon />
{{ formatMessage(analyticsTableMessages.exportCsvButton) }}
<DropdownIcon />
<template #cumulative-csv>
{{ formatMessage(analyticsTableMessages.cumulativeCsv) }}
</template>
<template #grouped-csv>
{{ formatMessage(analyticsTableMessages.groupedCsv, { groupBy: groupByLabel }) }}
</template>
</TeleportOverflowMenu>
</div>
</div>
</template>
@@ -191,9 +190,8 @@
<script setup lang="ts">
import { DownloadIcon, DropdownIcon, SearchIcon, UserIcon } from '@modrinth/assets'
import { TeleportOverflowMenu } from '@modrinth/ui'
import {
ButtonStyled,
OverflowMenu,
type OverflowMenuOption,
Pagination,
StyledInput,
@@ -370,10 +368,12 @@ const csvExportOptions = computed<OverflowMenuOption[]>(() => {
return [
{
id: 'cumulative-csv',
label: formatMessage(analyticsTableMessages.cumulativeCsv),
action: () => downloadCsv('breakdown_only'),
},
{
id: 'grouped-csv',
label: formatMessage(analyticsTableMessages.groupedCsv, { groupBy: groupByLabel.value }),
action: () => downloadCsv('date_breakdown'),
},
]
@@ -384,6 +384,10 @@ const csvExportOptions = computed<OverflowMenuOption[]>(() => {
return [
{
id: mode === 'date_breakdown' ? 'grouped-csv' : 'cumulative-csv',
label:
mode === 'date_breakdown'
? formatMessage(analyticsTableMessages.groupedCsv, { groupBy: groupByLabel.value })
: formatMessage(analyticsTableMessages.cumulativeCsv),
action: () => downloadCsv(mode),
},
]
@@ -6,25 +6,23 @@
{{ formatMessage(analyticsMessages.title) }}
</span>
<div class="flex flex-wrap items-center justify-end gap-2">
<ButtonStyled type="transparent">
<button
type="button"
:disabled="isAnalyticsQueryBuilderDefault"
@click="resetAnalyticsQueryBuilder"
>
{{ formatMessage(analyticsMessages.resetButton) }}
</button>
</ButtonStyled>
<ButtonStyled type="outlined">
<button
type="button"
:disabled="projects.length === 0 || !fetchRequest || isRefetching"
@click="refreshAnalyticsQuery"
>
<RefreshCwIcon :class="isRefetching ? 'animate-spin' : ''" />
{{ formatMessage(analyticsMessages.refreshButton) }}
</button>
</ButtonStyled>
<Button
type="quiet"
native-type="button"
:disabled="isAnalyticsQueryBuilderDefault"
@click="resetAnalyticsQueryBuilder"
>
{{ formatMessage(analyticsMessages.resetButton) }}
</Button>
<Button
type="outlined"
native-type="button"
:disabled="projects.length === 0 || !fetchRequest || isRefetching"
@click="refreshAnalyticsQuery"
>
<RefreshCwIcon :class="isRefetching ? 'animate-spin' : ''" />
{{ formatMessage(analyticsMessages.refreshButton) }}
</Button>
</div>
</div>
<QueryBuilder />
@@ -37,7 +35,7 @@
<script setup lang="ts">
import { RefreshCwIcon } from '@modrinth/assets'
import { ButtonStyled, injectProjectPageContext, useVIntl } from '@modrinth/ui'
import { Button, injectProjectPageContext, useVIntl } from '@modrinth/ui'
import {
createAnalyticsDashboardContext,
@@ -7,6 +7,7 @@
:show-preview-filter-icon="showPreviewFilterIcon"
:preview-trigger-class="previewTriggerClass"
:add-button-class="addButtonClass"
:add-button-size="addButtonSize"
:clear-label="formatMessage(analyticsMessages.resetButton)"
:add-label="resolvedAddLabel"
checkbox-position="right"
@@ -199,6 +200,7 @@
import { BoxIcon, UserIcon } from '@modrinth/assets'
import {
buildDependentsSearchFilters,
type ButtonSize,
DropdownFilterBar,
type DropdownFilterBarCategory,
type DropdownFilterBarOption,
@@ -273,6 +275,7 @@ const props = withDefaults(
showPreviewFilterIcon?: boolean
previewTriggerClass?: string
addButtonClass?: string
addButtonSize?: ButtonSize
showClearAction?: boolean
}>(),
{
@@ -9,6 +9,9 @@
:min-date="ANALYTICS_START_DATE_INPUT_VALUE"
:now-timestamp="queryRefreshTimestamp"
:trigger-class="triggerClass"
:trigger-type="triggerType"
:trigger-size="triggerSize"
:trigger-interaction="triggerInteraction"
@open="handleTimeframeOpen"
@commit="handleTimeframeCommit"
@apply="handleTimeframeApply"
@@ -23,6 +26,9 @@
<script setup lang="ts">
import {
type ButtonInteraction,
type ButtonSize,
type ButtonType,
type ComboboxOption,
TimeFramePicker as BaseTimeFramePicker,
type TimeFramePickerSelection,
@@ -58,6 +64,9 @@ const {
defineProps<{
triggerClass?: string
triggerType?: ButtonType
triggerSize?: ButtonSize
triggerInteraction?: ButtonInteraction
}>()
const draftSelectedGroupBy = ref(selectedGroupBy.value)
@@ -16,6 +16,7 @@
:max-tag-rows="1"
:trigger-class="analyticsQueryChipTriggerClass"
fit-content
trigger-type="base"
checkbox-position="right"
show-selection-actions
@open="handleProjectSelectOpen"
@@ -32,7 +33,7 @@
decoding="async"
/>
<LayersIcon v-else class="size-5 shrink-0 text-primary" />
<span class="min-w-0 flex-1 truncate px-0.5 font-semibold text-primary">
<span class="min-w-0 flex-1 truncate px-0.5 font-semibold text-inherit">
{{ selectedProjectLabel }}
</span>
<ChevronLeftIcon
@@ -145,6 +146,7 @@
:dropdown-min-width="QUERY_BUILDER_DROPDOWN_MIN_WIDTH"
:display-value="selectedGroupByLabel"
:trigger-class="analyticsQueryChipTriggerClass"
trigger-type="base"
>
<template #prefix>
<ClockIcon class="size-5 shrink-0 text-primary" />
@@ -160,6 +162,7 @@
:dropdown-min-width="QUERY_BUILDER_DROPDOWN_MIN_WIDTH"
:trigger-class="analyticsQueryChipTriggerClass"
fit-content
trigger-type="base"
checkbox-position="right"
:placeholder="formatMessage(analyticsMessages.none)"
show-selection-actions
@@ -170,7 +173,7 @@
<div class="flex min-h-7 min-w-0 max-w-full flex-1 items-center gap-1.5 pr-1">
<BlocksIcon class="size-5 shrink-0 text-primary" />
<span
class="min-w-0 flex-1 truncate px-0.5 font-semibold text-primary"
class="min-w-0 flex-1 truncate px-0.5 font-semibold text-inherit"
:title="mobileSelectedBreakdownLabel"
>
{{ mobileSelectedBreakdownLabel }}
@@ -191,6 +194,7 @@
show-preview-filter-icon
:show-clear-action="false"
:add-button-class="analyticsQueryAddFilterButtonClass"
add-button-size="lg"
/>
</div>
@@ -214,6 +218,7 @@
:searchable="projectOptions.length > 6"
fuzzy-search
:max-tag-rows="1"
trigger-type="base"
checkbox-position="right"
show-selection-actions
@open="handleProjectSelectOpen"
@@ -243,7 +248,7 @@
class="size-5 shrink-0 text-primary"
/>
<BoxIcon v-else class="size-5 shrink-0 text-primary" />
<span class="min-w-0 flex-1 truncate px-1.5 font-semibold text-primary">
<span class="min-w-0 flex-1 truncate px-1.5 font-semibold text-inherit">
{{ selectedProjectLabel }}
</span>
</div>
@@ -372,18 +377,19 @@
:options="groupByOptions"
:max-height="QUERY_BUILDER_DROPDOWN_MAX_HEIGHT"
:dropdown-min-width="QUERY_BUILDER_DROPDOWN_MIN_WIDTH"
trigger-type="base"
/>
</div>
</div>
<ButtonStyled v-if="!isTimeframeAndGroupByDefault" type="transparent">
<button
type="button"
:disabled="isTimeframeAndGroupByDefault"
@click="resetTimeframeAndGroupBy"
>
{{ formatMessage(analyticsMessages.resetButton) }}
</button>
</ButtonStyled>
<Button
v-if="!isTimeframeAndGroupByDefault"
type="quiet"
native-type="button"
:disabled="isTimeframeAndGroupByDefault"
@click="resetTimeframeAndGroupBy"
>
{{ formatMessage(analyticsMessages.resetButton) }}
</Button>
</div>
<div class="flex flex-wrap items-start gap-2">
@@ -403,6 +409,7 @@
:max-height="QUERY_BUILDER_DROPDOWN_MAX_HEIGHT"
:dropdown-width="QUERY_BUILDER_DROPDOWN_MIN_WIDTH"
:dropdown-min-width="QUERY_BUILDER_DROPDOWN_MIN_WIDTH"
trigger-type="base"
checkbox-position="right"
:placeholder="formatMessage(analyticsMessages.none)"
show-selection-actions
@@ -412,7 +419,7 @@
<template #input-content="{ isOpen, openDirection }">
<div class="flex min-h-7 min-w-0 flex-1 items-center gap-1.5 pr-1">
<span
class="min-w-0 flex-1 truncate font-semibold text-primary"
class="min-w-0 flex-1 truncate font-semibold text-inherit"
:title="selectedBreakdownLabel"
>
{{ selectedBreakdownLabel }}
@@ -453,8 +460,8 @@ import {
LayersIcon,
UserIcon,
} from '@modrinth/assets'
import { Button } from '@modrinth/ui'
import {
ButtonStyled,
Combobox,
type ComboboxOption,
MultiSelect,
@@ -504,7 +511,7 @@ import TimeFramePicker from './TimeframePicker.vue'
const QUERY_BUILDER_DROPDOWN_MAX_HEIGHT = 500
const QUERY_BUILDER_DROPDOWN_MIN_WIDTH = '14rem'
const analyticsQueryChipTriggerClass = 'h-10 '
const analyticsQueryAddFilterButtonClass = '!h-10 max-w-full !w-max !px-3.5 flex !gap-2'
const analyticsQueryAddFilterButtonClass = 'max-w-full !w-max !px-3.5 flex !gap-2'
const projectOptionCollator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' })
type ProjectSelectionPreset = 'user' | 'all'
@@ -12,12 +12,16 @@
{{ formatMessage(analyticsStatCardMessages.monetizationBannerBody) }}
</div>
<template #actions>
<ButtonStyled color="blue">
<a href="https://modrinth.com/legal/cmp-info" target="_blank" class="w-fit !px-4">
{{ formatMessage(analyticsStatCardMessages.monetizationBannerLearnMore) }}
<RightArrowIcon aria-hidden="true" />
</a>
</ButtonStyled>
<ButtonLink
type="colored"
color="blue"
href="https://modrinth.com/legal/cmp-info"
target="_blank"
class="w-fit !px-4"
>
{{ formatMessage(analyticsStatCardMessages.monetizationBannerLearnMore) }}
<RightArrowIcon aria-hidden="true" />
</ButtonLink>
</template>
</Admonition>
<div class="grid grid-cols-2 gap-3 lg:grid-cols-4">
@@ -39,7 +43,7 @@
<script setup lang="ts">
import { RightArrowIcon } from '@modrinth/assets'
import { Admonition, ButtonStyled, useFormatNumber, useVIntl } from '@modrinth/ui'
import { Admonition, ButtonLink, useFormatNumber, useVIntl } from '@modrinth/ui'
import { useLocalStorage } from '@vueuse/core'
import {