diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue
index e2f78fe965..0d72fce836 100644
--- a/apps/app-frontend/src/App.vue
+++ b/apps/app-frontend/src/App.vue
@@ -29,24 +29,25 @@ import {
import {
Admonition,
Avatar,
- ButtonStyled,
+ ButtonLink,
commonMessages,
ContentInstallModal,
ContentUpdaterModal,
CreationFlowModal,
defineMessages,
I18nDebugPanel,
+ IconButton,
IntlFormatted,
LoadingBar,
NewsArticleCard,
NotificationPanel,
- OverflowMenu,
PopupNotificationPanel,
provideModalBehavior,
provideModrinthClient,
provideNotificationManager,
providePageContext,
providePopupNotificationManager,
+ TeleportOverflowMenu,
TextLogo,
useDebugLogger,
useFormatBytes,
@@ -1591,22 +1592,29 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
>
-
@@ -1629,7 +1637,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
{{ formatMessage(commonMessages.signOutButton) }}
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
diff --git a/apps/app-frontend/src/components/ui/AccountsCard.vue b/apps/app-frontend/src/components/ui/AccountsCard.vue
index 9c0611ef63..ebe3e333d7 100644
--- a/apps/app-frontend/src/components/ui/AccountsCard.vue
+++ b/apps/app-frontend/src/components/ui/AccountsCard.vue
@@ -4,13 +4,11 @@
class="flex flex-col gap-3 bg-button-bg border border-solid border-surface-5 rounded-xl p-3 mt-2"
>
{{ formatMessage(messages.notSignedIn) }}
-
-
-
+
-
-
-
+
+
+
-
-
-
+
@@ -95,8 +97,9 @@ import {
import {
Accordion,
Avatar,
- ButtonStyled,
+ Button,
defineMessages,
+ IconButton,
injectNotificationManager,
useVIntl,
} from '@modrinth/ui'
diff --git a/apps/app-frontend/src/components/ui/AddContentButton.vue b/apps/app-frontend/src/components/ui/AddContentButton.vue
index cdea116e87..65f6397a9e 100644
--- a/apps/app-frontend/src/components/ui/AddContentButton.vue
+++ b/apps/app-frontend/src/components/ui/AddContentButton.vue
@@ -1,6 +1,6 @@
-
-
-
+
diff --git a/apps/frontend/src/components/ui/NotificationItem.vue b/apps/frontend/src/components/ui/NotificationItem.vue
index 1bbac8bf38..4f3cfa001b 100644
--- a/apps/frontend/src/components/ui/NotificationItem.vue
+++ b/apps/frontend/src/components/ui/NotificationItem.vue
@@ -46,18 +46,18 @@
class="flex flex-wrap items-center gap-3"
:class="{ 'gap-2': compact }"
>
-
-
-
-
-
-
+
+
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {
- acceptTeamInvite(notification.body.team_id)
- read()
- }
- "
- >
-
- Accept
-
-
-
- {
- removeSelfFromTeam(notification.body.team_id)
- read()
- }
- "
- >
-
- Decline
-
-
+ Decline
+
-
-
-
- Mark as read
-
-
+
+
+ Mark as read
+
-
-
-
- Open link
-
-
-
-
-
-
- {{ action.title }}
-
-
-
-
-
- Mark as read
-
-
+
+
+ Open link
+
+
+
+
+ {{ action.title }}
+
+
+
+ Mark as read
+
@@ -390,10 +399,12 @@ import {
} from '@modrinth/assets'
import {
Avatar,
- ButtonStyled,
+ Button,
+ ButtonLink,
Categories,
CopyCode,
DoubleIcon,
+ IconButton,
injectModrinthClient,
injectNotificationManager,
ProjectStatusBadge,
diff --git a/apps/frontend/src/components/ui/OrganizationPageHeader.vue b/apps/frontend/src/components/ui/OrganizationPageHeader.vue
index c5f74542df..6063423a50 100644
--- a/apps/frontend/src/components/ui/OrganizationPageHeader.vue
+++ b/apps/frontend/src/components/ui/OrganizationPageHeader.vue
@@ -38,21 +38,19 @@
-
-
-
- {{ formatMessage(messages.manage) }}
-
-
-
-
-
-
-
+
+
+ {{ formatMessage(messages.manage) }}
+
+
+
+
@@ -68,18 +66,17 @@ import {
SettingsIcon,
UsersIcon,
} from '@modrinth/assets'
+import { ButtonLink, TeleportOverflowMenu } from '@modrinth/ui'
import {
Avatar,
- ButtonStyled,
commonMessages,
defineMessages,
+ type OverflowMenuOption,
PageHeader,
PageHeaderActions,
PageHeaderBadgeItem,
PageHeaderMetadata,
PageHeaderMetadataNumberItem,
- TeleportOverflowMenu,
- type TeleportOverflowMenuItem,
useFormatNumber,
useVIntl,
} from '@modrinth/ui'
@@ -135,7 +132,7 @@ const emit = defineEmits<{
const { formatMessage } = useVIntl()
const formatNumber = useFormatNumber()
-const moreActions = computed
(() => [
+const moreActions = computed(() => [
{
id: 'manage-projects',
label: formatMessage(messages.manageProjects),
@@ -143,10 +140,7 @@ const moreActions = computed(() => [
action: () => emit('manageProjects'),
shown: props.canManage,
},
- {
- divider: true,
- shown: props.canManage,
- },
+ { type: 'divider', shown: props.canManage },
{
id: 'copy-id',
label: formatMessage(commonMessages.copyIdButton),
diff --git a/apps/frontend/src/components/ui/OrganizationProjectTransferModal.vue b/apps/frontend/src/components/ui/OrganizationProjectTransferModal.vue
index 6f66486fd0..46524dbff5 100644
--- a/apps/frontend/src/components/ui/OrganizationProjectTransferModal.vue
+++ b/apps/frontend/src/components/ui/OrganizationProjectTransferModal.vue
@@ -65,38 +65,37 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{
- formatMessage(messages.transferSelectedProjects, {
- count: selectedProjects.length,
- })
- }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{
+ formatMessage(messages.transferSelectedProjects, {
+ count: selectedProjects.length,
+ })
+ }}
+
-
-
-
- {{ formatMessage(messages.transferProjectsTitle) }}
-
-
+
+
+ {{ formatMessage(messages.transferProjectsTitle) }}
+
-
-
- {
- if (disabled) {
- event.preventDefault()
- return
- }
- if (action) {
- action(event)
- }
- }
- "
- >
-
-
-
-
- {
- if (disabled) {
- event.preventDefault()
- return
- }
- if (action) {
- action(event)
- }
- }
- "
- >
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/ui/src/components/base/ButtonStyled.vue b/packages/ui/src/components/base/ButtonStyled.vue
deleted file mode 100644
index f546054c16..0000000000
--- a/packages/ui/src/components/base/ButtonStyled.vue
+++ /dev/null
@@ -1,397 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/packages/ui/src/components/base/Card.vue b/packages/ui/src/components/base/Card.vue
index f52f4533b0..c481f17eb0 100644
--- a/packages/ui/src/components/base/Card.vue
+++ b/packages/ui/src/components/base/Card.vue
@@ -2,7 +2,7 @@
import { DropdownIcon } from '@modrinth/assets'
import { reactive } from 'vue'
-import ButtonStyled from './ButtonStyled.vue'
+import { IconButton } from '#ui/components/base/buttons'
const props = defineProps({
collapsible: {
@@ -33,11 +33,9 @@ function toggleCollapsed() {
diff --git a/packages/ui/src/components/base/Chips.vue b/packages/ui/src/components/base/Chips.vue
index e1359c469e..e7daddc930 100644
--- a/packages/ui/src/components/base/Chips.vue
+++ b/packages/ui/src/components/base/Chips.vue
@@ -15,7 +15,11 @@
}"
@click="toggleItem(item)"
>
-
+
{{ formatLabel(item) }}
@@ -24,7 +28,7 @@
-
-
-
-
- {{ primaryAction.label }}
-
-
-
-
-
-
-
- {{ action.label }}
-
-
-
-
-
-
-
-
-
diff --git a/packages/ui/src/components/base/ManySelect.vue b/packages/ui/src/components/base/ManySelect.vue
index ed495af309..b3c927d039 100644
--- a/packages/ui/src/components/base/ManySelect.vue
+++ b/packages/ui/src/components/base/ManySelect.vue
@@ -1,23 +1,19 @@
-
- {
- searchQuery = ''
- }
- "
- >
+
+
-
+
+
+
{{ getOptionLabel(option) }}
{{ getOptionLabel(option) }}
-
-
-
+
+
+
-
-
diff --git a/packages/ui/src/components/base/Pagination.vue b/packages/ui/src/components/base/Pagination.vue
index ba1eae2cda..f7a6e08cb5 100644
--- a/packages/ui/src/components/base/Pagination.vue
+++ b/packages/ui/src/components/base/Pagination.vue
@@ -1,18 +1,20 @@
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/TimeFramePicker.vue b/packages/ui/src/components/base/TimeFramePicker.vue
index 0db65f9e14..2be4e72e73 100644
--- a/packages/ui/src/components/base/TimeFramePicker.vue
+++ b/packages/ui/src/components/base/TimeFramePicker.vue
@@ -5,6 +5,9 @@
:display-value="selectedTimeframeLabel"
:max-height="maxHeight"
:trigger-class="triggerClass"
+ :trigger-type="triggerType"
+ :trigger-size="triggerSize"
+ :trigger-interaction="triggerInteraction"
:dropdown-min-width="timeframeDropdownMinWidth"
:outside-click-ignore="timeframeDropdownOutsideClickIgnore"
:dropdown-class="
@@ -103,16 +106,18 @@
-
-
- {{ formatMessage(messages.cancel) }}
-
-
-
-
- {{ formatMessage(messages.apply) }}
-
-
+
+ {{ formatMessage(messages.cancel) }}
+
+
+ {{ formatMessage(messages.apply) }}
+
@@ -196,8 +201,14 @@
import { MinusIcon, PlusIcon } from '@modrinth/assets'
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
+import {
+ Button,
+ type ButtonInteraction,
+ type ButtonSize,
+ type ButtonType,
+} from '#ui/components/base/buttons'
+
import { defineMessages, useVIntl } from '../../composables/i18n'
-import ButtonStyled from './ButtonStyled.vue'
import Combobox, { type ComboboxOption } from './Combobox.vue'
import DatePicker from './DatePicker.vue'
@@ -391,11 +402,17 @@ const props = withDefaults(
nowTimestamp?: number
maxHeight?: number
triggerClass?: string
+ triggerType?: ButtonType
+ triggerSize?: ButtonSize
+ triggerInteraction?: ButtonInteraction
dropdownMinWidth?: string | number
customRangeDropdownMinWidth?: string | number
}>(),
{
maxHeight: TIMEFRAME_DROPDOWN_MAX_HEIGHT,
+ triggerType: 'base',
+ triggerSize: 'md',
+ triggerInteraction: 'surface',
dropdownMinWidth: TIMEFRAME_DROPDOWN_MIN_WIDTH,
customRangeDropdownMinWidth: CUSTOM_RANGE_DROPDOWN_MIN_WIDTH,
},
diff --git a/packages/ui/src/components/base/UnsavedChangesPopup.vue b/packages/ui/src/components/base/UnsavedChangesPopup.vue
index 4606042c86..c997b965a5 100644
--- a/packages/ui/src/components/base/UnsavedChangesPopup.vue
+++ b/packages/ui/src/components/base/UnsavedChangesPopup.vue
@@ -3,9 +3,10 @@ import { HistoryIcon, SaveIcon, SpinnerIcon } from '@modrinth/assets'
import { isEqual } from 'es-toolkit'
import { type Component, computed, ref } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { defineMessage, type MessageDescriptor, useVIntl } from '../../composables/i18n'
import { commonMessages } from '../../utils'
-import ButtonStyled from './ButtonStyled.vue'
import FloatingActionBar from './FloatingActionBar.vue'
const { formatMessage } = useVIntl()
@@ -62,18 +63,14 @@ defineExpose({ nudge })
{{ localizeIfPossible(text) }}
-
- emit('reset', e)">
- {{ formatMessage(commonMessages.resetButton) }}
-
-
-
- emit('save', e)">
-
-
- {{ localizeIfPossible(saving ? savingLabel : saveLabel) }}
-
-
+ emit('reset', e)">
+ {{ formatMessage(commonMessages.resetButton) }}
+
+ emit('save', e)">
+
+
+ {{ localizeIfPossible(saving ? savingLabel : saveLabel) }}
+
diff --git a/packages/ui/src/components/base/buttons/Button.vue b/packages/ui/src/components/base/buttons/Button.vue
new file mode 100644
index 0000000000..6d9f4e2b44
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/Button.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/ButtonFrame.vue b/packages/ui/src/components/base/buttons/ButtonFrame.vue
new file mode 100644
index 0000000000..3c495fe320
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/ButtonFrame.vue
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/ButtonGroup.vue b/packages/ui/src/components/base/buttons/ButtonGroup.vue
new file mode 100644
index 0000000000..1e56d09668
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/ButtonGroup.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/ButtonLink.vue b/packages/ui/src/components/base/buttons/ButtonLink.vue
new file mode 100644
index 0000000000..cb11c7c6c6
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/ButtonLink.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/FileButton.vue b/packages/ui/src/components/base/buttons/FileButton.vue
new file mode 100644
index 0000000000..0c6c09b2ee
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/FileButton.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+ {{ props.prompt }}
+
+
+
diff --git a/packages/ui/src/components/base/buttons/IconButton.vue b/packages/ui/src/components/base/buttons/IconButton.vue
new file mode 100644
index 0000000000..6fe601fb2b
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/IconButton.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/SplitButton.vue b/packages/ui/src/components/base/buttons/SplitButton.vue
new file mode 100644
index 0000000000..40badebad8
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/SplitButton.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/TeleportOverflowMenu.vue b/packages/ui/src/components/base/buttons/TeleportOverflowMenu.vue
new file mode 100644
index 0000000000..ed094170dd
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/TeleportOverflowMenu.vue
@@ -0,0 +1,440 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/TeleportPopoutMenu.vue b/packages/ui/src/components/base/buttons/TeleportPopoutMenu.vue
new file mode 100644
index 0000000000..16574bfec9
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/TeleportPopoutMenu.vue
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/index.ts b/packages/ui/src/components/base/buttons/index.ts
new file mode 100644
index 0000000000..cbfc192984
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/index.ts
@@ -0,0 +1,23 @@
+export { default as Button } from './Button.vue'
+export { default as ButtonGroup } from './ButtonGroup.vue'
+export { default as ButtonLink } from './ButtonLink.vue'
+export { default as FileButton } from './FileButton.vue'
+export { default as IconButton } from './IconButton.vue'
+export { default as SplitButton } from './SplitButton.vue'
+export { default as TeleportOverflowMenu } from './TeleportOverflowMenu.vue'
+export { default as TeleportPopoutMenu } from './TeleportPopoutMenu.vue'
+export type {
+ ButtonColor,
+ ButtonElementHandle,
+ ButtonInteraction,
+ ButtonLinkDestination,
+ ButtonNativeType,
+ ButtonSize,
+ ButtonType,
+ ButtonVisualProps,
+ OverflowMenuAction,
+ OverflowMenuDivider,
+ OverflowMenuLink,
+ OverflowMenuOption,
+ TeleportPlacement,
+} from './types'
diff --git a/packages/ui/src/components/base/buttons/types.ts b/packages/ui/src/components/base/buttons/types.ts
new file mode 100644
index 0000000000..d37c9ad236
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/types.ts
@@ -0,0 +1,105 @@
+import type { Component } from 'vue'
+import type { RouteLocationRaw } from 'vue-router'
+
+import type { AnchoredTeleportPlacement } from '../../../utils/use-anchored-teleport'
+
+export type ButtonType = 'base' | 'colored' | 'outlined' | 'quiet'
+
+export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
+
+export type ButtonInteraction = 'surface' | 'filled' | 'none'
+
+// TODO: Standardized color string enum props across @modrinth/ui
+export type ButtonColor =
+ | 'brand'
+ | 'red'
+ | 'orange'
+ | 'green'
+ | 'blue'
+ | 'purple'
+ | 'medal_promotion'
+
+export type ButtonVisualProps = {
+ size?: ButtonSize
+ interaction?: ButtonInteraction
+} & (
+ | {
+ type?: 'base'
+ color?: never
+ }
+ | {
+ type: 'outlined'
+ color?: never
+ }
+ | {
+ type: 'colored'
+ color?: ButtonColor
+ }
+ | {
+ type: 'quiet'
+ color?: ButtonColor
+ }
+)
+
+export type ButtonNativeType = 'button' | 'submit' | 'reset'
+
+export interface ButtonProps {
+ type?: ButtonType
+ color?: ButtonColor
+ size?: ButtonSize
+ interaction?: ButtonInteraction
+ nativeType?: ButtonNativeType
+ disabled?: boolean
+ loading?: boolean
+}
+
+export type ButtonLinkDestination =
+ | {
+ to: RouteLocationRaw
+ href?: never
+ }
+ | {
+ href: string
+ to?: never
+ }
+
+export type TeleportPlacement = AnchoredTeleportPlacement
+
+export interface OverflowMenuItemBase {
+ id: string
+ label: string
+ icon?: Component
+ shown?: boolean
+ disabled?: boolean
+ tooltip?: string
+ remainOpen?: boolean
+ tone?: 'default' | ButtonColor
+ hoverFilled?: boolean
+ hoverFilledOnly?: boolean
+}
+
+export interface OverflowMenuAction extends OverflowMenuItemBase {
+ type?: 'action'
+ action: (event: MouseEvent) => void
+}
+
+export interface OverflowMenuLink extends OverflowMenuItemBase {
+ type: 'link'
+ to?: RouteLocationRaw
+ href?: string
+ target?: string
+ rel?: string
+ download?: string | boolean
+}
+
+export interface OverflowMenuDivider {
+ type: 'divider'
+ id?: string
+ shown?: boolean
+}
+
+export type OverflowMenuOption = OverflowMenuAction | OverflowMenuLink | OverflowMenuDivider
+
+export interface ButtonElementHandle {
+ element: HTMLElement | null
+}
diff --git a/packages/ui/src/components/base/index.ts b/packages/ui/src/components/base/index.ts
index 1373522c33..08b54ef241 100644
--- a/packages/ui/src/components/base/index.ts
+++ b/packages/ui/src/components/base/index.ts
@@ -9,8 +9,27 @@ export { default as Badge } from './Badge.vue'
export { default as BaseTerminal } from './BaseTerminal.vue'
export { default as BigOptionButton } from './BigOptionButton.vue'
export { default as BulletDivider } from './BulletDivider.vue'
-export { default as Button } from './Button.vue'
-export { default as ButtonStyled } from './ButtonStyled.vue'
+export { default as Button } from './buttons/Button.vue'
+export { default as ButtonGroup } from './buttons/ButtonGroup.vue'
+export { default as ButtonLink } from './buttons/ButtonLink.vue'
+export { default as FileButton } from './buttons/FileButton.vue'
+export { default as IconButton } from './buttons/IconButton.vue'
+export { default as SplitButton } from './buttons/SplitButton.vue'
+export { default as TeleportOverflowMenu } from './buttons/TeleportOverflowMenu.vue'
+export { default as TeleportPopoutMenu } from './buttons/TeleportPopoutMenu.vue'
+export type {
+ ButtonColor,
+ ButtonInteraction,
+ ButtonNativeType,
+ ButtonSize,
+ ButtonType,
+ ButtonVisualProps,
+ OverflowMenuAction,
+ OverflowMenuDivider,
+ OverflowMenuLink,
+ OverflowMenuOption,
+ TeleportPlacement,
+} from './buttons/types'
export { default as Card } from './Card.vue'
export { default as Checkbox } from './Checkbox.vue'
export { default as Chips } from './Chips.vue'
@@ -46,8 +65,6 @@ export { default as HorizontalRule } from './HorizontalRule.vue'
export { default as I18nDebugPanel } from './I18nDebugPanel.vue'
export { default as IconSelect } from './IconSelect.vue'
export { default as IntlFormatted } from './IntlFormatted.vue'
-export type { JoinedButtonAction } from './JoinedButtons.vue'
-export { default as JoinedButtons } from './JoinedButtons.vue'
export { default as LoadingBar } from './LoadingBar.vue'
export { default as LoadingIndicator } from './LoadingIndicator.vue'
export { default as ManySelect } from './ManySelect.vue'
@@ -62,8 +79,6 @@ export type { MaybeCtxFn, StageButtonConfig, StageConfigInput } from './MultiSta
export { default as MultiStageModal, resolveCtxFn } from './MultiStageModal.vue'
export { default as NavTabs } from './NavTabs.vue'
export { default as OptionGroup } from './OptionGroup.vue'
-export type { Option as OverflowMenuOption } from './OverflowMenu.vue'
-export { default as OverflowMenu } from './OverflowMenu.vue'
export { default as Page } from './Page.vue'
export { default as PageHeader } from './page-header/index.vue'
export { default as PageHeaderMetadata } from './page-header/metadata/index.vue'
@@ -106,11 +121,6 @@ export type { TabsTab, TabsValue } from './Tabs.vue'
export { default as Tabs } from './Tabs.vue'
export { default as TagItem } from './TagItem.vue'
export { default as TagTagItem } from './TagTagItem.vue'
-export type {
- Item as TeleportOverflowMenuItem,
- Option as TeleportOverflowMenuOption,
-} from './TeleportOverflowMenu.vue'
-export { default as TeleportOverflowMenu } from './TeleportOverflowMenu.vue'
export type {
TimeFrameLastUnit,
TimeFrameLastUnitOption,
diff --git a/packages/ui/src/components/billing/AddPaymentMethodModal.vue b/packages/ui/src/components/billing/AddPaymentMethodModal.vue
index 8e1361adb6..a05eaf4f20 100644
--- a/packages/ui/src/components/billing/AddPaymentMethodModal.vue
+++ b/packages/ui/src/components/billing/AddPaymentMethodModal.vue
@@ -3,9 +3,11 @@ import { PlusIcon, XIcon } from '@modrinth/assets'
import type Stripe from 'stripe'
import { nextTick, ref, useTemplateRef } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { defineMessages, useVIntl } from '../../composables/i18n'
import { commonMessages } from '../../utils'
-import { ButtonStyled, NewModal } from '../index'
+import { NewModal } from '../index'
import type { AddPaymentMethodProps } from './AddPaymentMethod.vue'
import AddPaymentMethod from './AddPaymentMethod.vue'
@@ -57,18 +59,14 @@ defineExpose({
@stop-loading="loading = false"
/>
diff --git a/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue b/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue
index bdae9d75ed..14c1eacd8a 100644
--- a/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue
+++ b/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue
@@ -12,12 +12,12 @@ import { useQueryClient } from '@tanstack/vue-query'
import type Stripe from 'stripe'
import { computed, nextTick, onBeforeUnmount, ref, toRef, useTemplateRef, watch } from 'vue'
+import { Button } from '#ui/components/base/buttons'
import { injectNotificationManager } from '#ui/providers/web-notifications.ts'
import { defineMessage, type MessageDescriptor, useVIntl } from '../../composables/i18n'
import { useStripe } from '../../composables/stripe'
import { commonMessages } from '../../utils'
-import { ButtonStyled } from '../index'
import ModalLoadingIndicator from '../modal/ModalLoadingIndicator.vue'
import NewModal from '../modal/NewModal.vue'
import PlanSelector from './ServersPurchase0Plan.vue'
@@ -555,51 +555,50 @@ function goToBreadcrumbStep(id: string) {
-
-
- {{ formatMessage(commonMessages.backButton) }}
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
- {
- if (props.onFinalizeNoPaymentChange) {
- try {
- await props.onFinalizeNoPaymentChange()
- } catch (e) {
- return
- }
+
+ {{ formatMessage(commonMessages.backButton) }}
+
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+ {
+ if (props.onFinalizeNoPaymentChange) {
+ try {
+ await props.onFinalizeNoPaymentChange()
+ } catch (e) {
+ return
}
- modal?.hide()
- })()
- : setStep(nextStep)
- "
- >
-
- Confirm Change
-
-
-
- Subscribe
-
-
+ }
+ modal?.hide()
+ })()
+ : setStep(nextStep)
+ "
+ >
+
+ Confirm Change
- {{ formatMessage(commonMessages.nextButton) }}
+
+
+ Subscribe
-
-
+
+
+ {{ formatMessage(commonMessages.nextButton) }}
+
+
diff --git a/packages/ui/src/components/billing/ResubscribeModal.vue b/packages/ui/src/components/billing/ResubscribeModal.vue
index 298416af3b..084f3a0a35 100644
--- a/packages/ui/src/components/billing/ResubscribeModal.vue
+++ b/packages/ui/src/components/billing/ResubscribeModal.vue
@@ -78,18 +78,14 @@
-
-
-
- {{ formatMessage(messages.cancelButton) }}
-
-
-
-
-
- {{ formatMessage(messages.resubscribeButton) }}
-
-
+
+
+ {{ formatMessage(messages.cancelButton) }}
+
+
+
+ {{ formatMessage(messages.resubscribeButton) }}
+
@@ -100,12 +96,13 @@ import type { Labrinth } from '@modrinth/api-client'
import { RotateCounterClockwiseIcon, XIcon } from '@modrinth/assets'
import { computed, ref, useTemplateRef } from 'vue'
+import { Button } from '#ui/components/base/buttons'
import { injectNotificationManager } from '#ui/providers/web-notifications.ts'
import { useFormatDateTime, useFormatPrice } from '../../composables'
import { defineMessages, useVIntl } from '../../composables/i18n'
import IntlFormatted from '../base/IntlFormatted.vue'
-import { ButtonStyled, NewModal } from '../index'
+import { NewModal } from '../index'
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
diff --git a/packages/ui/src/components/billing/ServersGuestPlanModal.vue b/packages/ui/src/components/billing/ServersGuestPlanModal.vue
index f99f2ecc52..f1322c88ac 100644
--- a/packages/ui/src/components/billing/ServersGuestPlanModal.vue
+++ b/packages/ui/src/components/billing/ServersGuestPlanModal.vue
@@ -3,7 +3,8 @@ import type { Labrinth } from '@modrinth/api-client'
import { ChevronRightIcon, ExternalIcon, XIcon } from '@modrinth/assets'
import { computed, ref, useTemplateRef } from 'vue'
-import ButtonStyled from '../base/ButtonStyled.vue'
+import { Button, IconButton } from '#ui/components/base/buttons'
+
import NewModal from '../modal/NewModal.vue'
import type { ServerBillingInterval } from './ModrinthServersPurchaseModal.vue'
import PlanSelector from './ServersPurchase0Plan.vue'
@@ -143,11 +144,9 @@ defineExpose({
class="absolute inset-x-0 bottom-0 -m-px z-30 rounded-2xl border border-solid border-surface-5 bg-bg-raised p-6 shadow-2xl"
>
-
-
-
-
-
+
+
+
@@ -155,12 +154,10 @@ defineExpose({
Sign in to continue your purchase
You need a Modrinth account to add your billing details.
-
-
- Sign in or create an account
-
-
-
+
+ Sign in or create an account
+
+
diff --git a/packages/ui/src/components/billing/ServersPurchase0Plan.vue b/packages/ui/src/components/billing/ServersPurchase0Plan.vue
index 456b324aea..03ae8aaf7b 100644
--- a/packages/ui/src/components/billing/ServersPurchase0Plan.vue
+++ b/packages/ui/src/components/billing/ServersPurchase0Plan.vue
@@ -3,10 +3,11 @@ import type { Labrinth } from '@modrinth/api-client'
import { RightArrowIcon } from '@modrinth/assets'
import { computed } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { useFormatPrice } from '../../composables'
import { defineMessages, useVIntl } from '../../composables/i18n'
import { getPriceForInterval, monthsInInterval } from '../../utils/product-utils'
-import ButtonStyled from '../base/ButtonStyled.vue'
import OptionGroup from '../base/OptionGroup.vue'
import type { ServerBillingInterval } from './ModrinthServersPurchaseModal.vue'
import ServersSpecs from './ServersSpecs.vue'
@@ -218,19 +219,19 @@ function selectCustom() {
-
-
- {{
- existingPlan?.id === plansByRam.small.id
- ? formatMessage(messages.yourCurrentPlan)
- : formatMessage(messages.selectPlan)
- }}
-
-
+
+ {{
+ existingPlan?.id === plansByRam.small.id
+ ? formatMessage(messages.yourCurrentPlan)
+ : formatMessage(messages.selectPlan)
+ }}
+
-
-
- {{
- existingPlan?.id === plansByRam.medium.id
- ? formatMessage(messages.yourCurrentPlan)
- : formatMessage(messages.selectPlan)
- }}
-
-
+
+ {{
+ existingPlan?.id === plansByRam.medium.id
+ ? formatMessage(messages.yourCurrentPlan)
+ : formatMessage(messages.selectPlan)
+ }}
+
-
-
- {{
- existingPlan?.id === plansByRam.large.id
- ? formatMessage(messages.yourCurrentPlan)
- : formatMessage(messages.selectPlan)
- }}
-
-
+
+ {{
+ existingPlan?.id === plansByRam.large.id
+ ? formatMessage(messages.yourCurrentPlan)
+ : formatMessage(messages.selectPlan)
+ }}
+
-
-
- {{ formatMessage(messages.getStarted) }}
-
-
+
+ {{ formatMessage(messages.getStarted) }}
+
Starting at {{ formatPrice(customStartingPrice, currency, true) }}/mo
diff --git a/packages/ui/src/components/billing/ServersPurchase3Review.vue b/packages/ui/src/components/billing/ServersPurchase3Review.vue
index bfe6096c8d..ce76cbc1af 100644
--- a/packages/ui/src/components/billing/ServersPurchase3Review.vue
+++ b/packages/ui/src/components/billing/ServersPurchase3Review.vue
@@ -15,11 +15,12 @@ import dayjs from 'dayjs'
import type Stripe from 'stripe'
import { computed } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { useFormatPrice } from '../../composables'
import { useVIntl } from '../../composables/i18n'
import { getPriceForInterval, monthsInInterval } from '../../utils/product-utils'
import { regionOverrides } from '../../utils/regions'
-import ButtonStyled from '../base/ButtonStyled.vue'
import Checkbox from '../base/Checkbox.vue'
import TagItem from '../base/TagItem.vue'
import ModrinthServersIcon from '../servers/ModrinthServersIcon.vue'
@@ -323,12 +324,10 @@ function setInterval(newInterval: ServerBillingInterval) {
No payment method selected
-
-
- Change
- Select payment method
-
-
+
+ Change
+ Select payment method
+
diff --git a/packages/ui/src/components/chart/Chart.vue b/packages/ui/src/components/chart/Chart.vue
index 43c11e1fb5..72d42bc67a 100644
--- a/packages/ui/src/components/chart/Chart.vue
+++ b/packages/ui/src/components/chart/Chart.vue
@@ -4,7 +4,7 @@ import dayjs from 'dayjs'
import { defineAsyncComponent, onMounted, ref } from 'vue'
import { useFormatNumber } from '../../composables/index.ts'
-import Button from '../base/Button.vue'
+import { IconButton } from '../base/buttons'
import Checkbox from '../base/Checkbox.vue'
const VueApexCharts = defineAsyncComponent(() => import('vue3-apexcharts'))
@@ -231,12 +231,16 @@ defineExpose({
diff --git a/packages/ui/src/components/external_files/AddFilesToAttributionGroupModal.vue b/packages/ui/src/components/external_files/AddFilesToAttributionGroupModal.vue
index fc94cf5af1..effcec44fa 100644
--- a/packages/ui/src/components/external_files/AddFilesToAttributionGroupModal.vue
+++ b/packages/ui/src/components/external_files/AddFilesToAttributionGroupModal.vue
@@ -3,7 +3,8 @@ import type { Labrinth } from '@modrinth/api-client'
import { CheckIcon, PlusIcon, SearchIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
import { computed, nextTick, ref } from 'vue'
-import { ButtonStyled, NewModal, StyledInput } from '#ui/components'
+import { NewModal, StyledInput } from '#ui/components'
+import { Button } from '#ui/components/base/buttons'
import { commonMessages } from '#ui/utils'
import { defineMessages, useVIntl } from '../../composables/i18n'
@@ -263,23 +264,21 @@ defineExpose({ show, hide })
{{ formatMessage(messages.addFilesModalSelectedCount, { count: selectedFileCount }) }}
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
-
- {{ formatMessage(messages.addFilesModalConfirm, { count: selectedFileCount }) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+
+ {{ formatMessage(messages.addFilesModalConfirm, { count: selectedFileCount }) }}
+
diff --git a/packages/ui/src/components/external_files/AddToExistingExternalProjectModal.vue b/packages/ui/src/components/external_files/AddToExistingExternalProjectModal.vue
index 9ad61e3b1a..85ccadcae4 100644
--- a/packages/ui/src/components/external_files/AddToExistingExternalProjectModal.vue
+++ b/packages/ui/src/components/external_files/AddToExistingExternalProjectModal.vue
@@ -4,7 +4,8 @@ import { PlusIcon, SearchIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
import { useMutation } from '@tanstack/vue-query'
import { computed, ref, useTemplateRef } from 'vue'
-import { Accordion, ButtonStyled, NewModal, StyledInput } from '#ui/components'
+import { Accordion, NewModal, StyledInput } from '#ui/components'
+import { Button } from '#ui/components/base/buttons'
import { injectModrinthClient, injectNotificationManager } from '../../providers'
import AttributionGroupFilePicker from './AttributionGroupFilePicker.vue'
@@ -228,12 +229,15 @@ defineExpose({ show, hide })
wrapper-class="flex-1 min-w-[12rem]"
:disabled="addFilesMutation.isPending.value"
/>
-
-
-
- Search
-
-
+
+
+ Search
+
-
-
- {{ selectedProjectId === project.id ? 'Selected' : 'Select' }}
-
-
+
+ {{ selectedProjectId === project.id ? 'Selected' : 'Select' }}
+
@@ -306,22 +308,29 @@ defineExpose({ show, hide })
/>
-
-
-
- Cancel
-
-
-
-
-
-
- Add files to entry
-
-
+
+
+ Cancel
+
+
+
+
+ Add files to entry
+
diff --git a/packages/ui/src/components/external_files/AddToGlobalPermissionsDatabaseModal.vue b/packages/ui/src/components/external_files/AddToGlobalPermissionsDatabaseModal.vue
index c3a55d80d0..e36d1785d9 100644
--- a/packages/ui/src/components/external_files/AddToGlobalPermissionsDatabaseModal.vue
+++ b/packages/ui/src/components/external_files/AddToGlobalPermissionsDatabaseModal.vue
@@ -4,14 +4,8 @@ import { PlusIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
import { useMutation } from '@tanstack/vue-query'
import { computed, ref, useTemplateRef } from 'vue'
-import {
- Accordion,
- ButtonStyled,
- Combobox,
- type ComboboxOption,
- NewModal,
- StyledInput,
-} from '#ui/components'
+import { Accordion, Combobox, type ComboboxOption, NewModal, StyledInput } from '#ui/components'
+import { Button } from '#ui/components/base/buttons'
import { injectModrinthClient, injectNotificationManager } from '../../providers'
import AttributionGroupFilePicker from './AttributionGroupFilePicker.vue'
@@ -223,22 +217,26 @@ defineExpose({ show, hide })
-
-
-
- Cancel
-
-
-
-
-
-
- Add to global database
-
-
+
+
+ Cancel
+
+
+
+
+ Add to global database
+
diff --git a/packages/ui/src/components/external_files/AttributionEditor.vue b/packages/ui/src/components/external_files/AttributionEditor.vue
index 3694793a02..82e99ad7cb 100644
--- a/packages/ui/src/components/external_files/AttributionEditor.vue
+++ b/packages/ui/src/components/external_files/AttributionEditor.vue
@@ -14,8 +14,9 @@ import { builtinLicenses } from '@modrinth/utils'
import { useMutation, useQueryClient } from '@tanstack/vue-query'
import { computed, ref, watch } from 'vue'
-import { ButtonStyled, Chips, Combobox, type ComboboxOption, StyledInput } from '#ui/components'
+import { Chips, Combobox, type ComboboxOption, StyledInput } from '#ui/components'
import { FileInput } from '#ui/components/base'
+import { Button, IconButton } from '#ui/components/base/buttons'
import { commonMessages } from '#ui/utils'
import { defineMessage, defineMessages, useVIntl } from '../../composables/i18n'
@@ -577,15 +578,14 @@ function cancelEditing() {
class="flex w-full object-contain bg-surface-3"
/>
-
-
-
-
-
+
+
+
@@ -633,29 +633,29 @@ function cancelEditing() {
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
-
- {{ formatMessage(commonMessages.savingButton) }}
-
-
- {{ formatMessage(messages.saveAttribution) }}
-
- {{ formatMessage(messages.addAttribution) }}
-
-
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+
+ {{ formatMessage(commonMessages.savingButton) }}
+
+
+ {{ formatMessage(messages.saveAttribution) }}
+
+ {{ formatMessage(messages.addAttribution) }}
+
diff --git a/packages/ui/src/components/external_files/ExternalProjectLookupCard.vue b/packages/ui/src/components/external_files/ExternalProjectLookupCard.vue
index 4bf6a34a92..2467b5d3cf 100644
--- a/packages/ui/src/components/external_files/ExternalProjectLookupCard.vue
+++ b/packages/ui/src/components/external_files/ExternalProjectLookupCard.vue
@@ -9,7 +9,8 @@ import {
import { Menu } from 'floating-vue'
import { computed } from 'vue'
-import { ButtonStyled, CopyCode } from '#ui/components'
+import { CopyCode } from '#ui/components'
+import { IconButton } from '#ui/components/base/buttons'
import ExternalProjectLicenseStateTag from './ExternalProjectLicenseStateTag.vue'
import type { ExternalLicenseStatus } from './types.ts'
@@ -58,11 +59,16 @@ async function copyProjectLink() {
Project link
-
-
-
-
-
+
+
+
diff --git a/packages/ui/src/components/external_files/ExternalProjectPermissionsCard.vue b/packages/ui/src/components/external_files/ExternalProjectPermissionsCard.vue
index bb26531235..9dc39af921 100644
--- a/packages/ui/src/components/external_files/ExternalProjectPermissionsCard.vue
+++ b/packages/ui/src/components/external_files/ExternalProjectPermissionsCard.vue
@@ -18,8 +18,9 @@ import { renderString } from '@modrinth/utils'
import { useMutation, useQueryClient } from '@tanstack/vue-query'
import { computed, ref, useTemplateRef, watch } from 'vue'
-import { ButtonStyled, Collapsible, ConfirmModal, OverflowMenu } from '#ui/components'
+import { Collapsible, ConfirmModal } from '#ui/components'
import type { OverflowMenuOption } from '#ui/components/base'
+import { Button, IconButton, TeleportOverflowMenu } from '#ui/components/base/buttons'
import { commonMessages } from '#ui/utils'
import { defineMessage, defineMessages, useVIntl } from '../../composables/i18n'
@@ -498,6 +499,7 @@ const visibleQuickReplies = computed(() => {
(reply) =>
({
id: reply.label,
+ label: reply.label,
action: () => handleQuickReply(reply),
}) as OverflowMenuOption,
)
@@ -577,28 +579,27 @@ const visibleQuickReplies = computed(() => {
-
-
-
-
-
-
+
+
+
+
-
-
- {{ formatMessage(messages.addFilesToGroup) }}
-
-
+
+ {{ formatMessage(messages.addFilesToGroup) }}
+
@@ -644,11 +645,9 @@ const visibleQuickReplies = computed(() => {
"
#actions
>
-
-
- {{ formatMessage(commonMessages.editButton) }}
-
-
+
+ {{ formatMessage(commonMessages.editButton) }}
+
-
-
- Reply presets
-
-
-
-
-
-
-
- Approve
-
-
-
-
-
-
- Reject: Insufficient proof
-
-
-
-
-
-
- Reject: Not allowed
-
-
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
+
+ Reply presets
+
+
+
+
+
+ Approve
+
+
+
+
+ Reject: Insufficient proof
+
+
+
+
+ Reject: Not allowed
+
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
-
-
- Add files to database...
-
-
-
-
- Add to existing entry...
-
-
+
+ Add files to database...
+
+
+ Add to existing entry...
+
@@ -808,12 +809,10 @@ const visibleQuickReplies = computed(() => {
"
class="ml-auto"
>
-
-
-
- {{ formatMessage(commonMessages.editButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.editButton) }}
+
@@ -835,16 +834,19 @@ const visibleQuickReplies = computed(() => {
/>
-
-
-
-
- {{ formatMessage(messages.removeGroup) }}
-
-
+
+
+
+ {{ formatMessage(messages.removeGroup) }}
+
diff --git a/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue b/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue
index 2d20d1a1a0..9899a8d370 100644
--- a/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue
+++ b/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue
@@ -4,18 +4,14 @@
-
-
-
- {{ formatMessage(messages.selectIcon) }}
-
-
-
-
-
- {{ formatMessage(messages.removeIcon) }}
-
-
+
+
+ {{ formatMessage(messages.selectIcon) }}
+
+
+
+ {{ formatMessage(messages.removeIcon) }}
+
@@ -153,11 +149,11 @@ import { EyeIcon, EyeOffIcon, UploadIcon, XIcon } from '@modrinth/assets'
import { commonMessages, defineMessages, useVIntl } from '@modrinth/ui'
import { computed, onMounted, ref, watch } from 'vue'
+import { Button } from '#ui/components/base/buttons'
import { useDebugLogger } from '#ui/composables/debug-logger'
import { injectFilePicker, injectModrinthClient, injectTags } from '../../../../providers'
import Avatar from '../../../base/Avatar.vue'
-import ButtonStyled from '../../../base/ButtonStyled.vue'
import Chips from '../../../base/Chips.vue'
import Collapsible from '../../../base/Collapsible.vue'
import Combobox, { type ComboboxOption } from '../../../base/Combobox.vue'
diff --git a/packages/ui/src/components/flows/creation-flow-modal/components/ImportInstanceStage.vue b/packages/ui/src/components/flows/creation-flow-modal/components/ImportInstanceStage.vue
index 6351399bd3..3102c9bf78 100644
--- a/packages/ui/src/components/flows/creation-flow-modal/components/ImportInstanceStage.vue
+++ b/packages/ui/src/components/flows/creation-flow-modal/components/ImportInstanceStage.vue
@@ -5,13 +5,14 @@
{{
formatMessage(messages.launcherInstancesTitle)
}}
- {{ formatMessage(messages.clearAll) }}
- {{ formatMessage(messages.clearAll) }}
-
@@ -76,28 +77,22 @@
-
-
- {{ formatMessage(messages.addLauncherPath) }}
-
-
+
+ {{ formatMessage(messages.addLauncherPath) }}
+
-
-
-
-
-
+
+
+
-
-
- {{ formatMessage(messages.add) }}
-
-
+
+ {{ formatMessage(messages.add) }}
+
@@ -108,9 +103,10 @@ import { ChevronRightIcon, FolderSearchIcon, SearchIcon } from '@modrinth/assets
import { defineMessages, useVIntl } from '@modrinth/ui'
import { computed, onMounted, ref, watch } from 'vue'
+import { Button, IconButton } from '#ui/components/base/buttons'
+
import { injectInstanceImport, injectNotificationManager } from '../../../../providers'
import type { ImportableLauncher } from '../../../../providers/instance-import'
-import ButtonStyled from '../../../base/ButtonStyled.vue'
import Checkbox from '../../../base/Checkbox.vue'
import Collapsible from '../../../base/Collapsible.vue'
import StyledInput from '../../../base/StyledInput.vue'
diff --git a/packages/ui/src/components/flows/creation-flow-modal/components/ModpackStage.vue b/packages/ui/src/components/flows/creation-flow-modal/components/ModpackStage.vue
index e0860dd303..8fc5605aa3 100644
--- a/packages/ui/src/components/flows/creation-flow-modal/components/ModpackStage.vue
+++ b/packages/ui/src/components/flows/creation-flow-modal/components/ModpackStage.vue
@@ -30,28 +30,27 @@
-
-
-
- {{ formatMessage(messages.importModpack) }}
-
-
-
-
-
- {{ formatMessage(messages.browseModpacks) }}
-
-
+
+
+ {{ formatMessage(messages.importModpack) }}
+
+
+
+ {{ formatMessage(messages.browseModpacks) }}
+
@@ -61,10 +60,10 @@ import { CompassIcon, ImportIcon, RightArrowIcon } from '@modrinth/assets'
import { commonMessages, defineMessages, useVIntl } from '@modrinth/ui'
import { defineAsyncComponent, h, onMounted, ref, watch } from 'vue'
+import { Button } from '#ui/components/base/buttons'
import { useDebugLogger } from '#ui/composables/debug-logger'
import { injectFilePicker } from '../../../../providers'
-import ButtonStyled from '../../../base/ButtonStyled.vue'
import Combobox from '../../../base/Combobox.vue'
import { injectCreationFlowContext } from '../creation-flow-context'
diff --git a/packages/ui/src/components/modal/ConfirmLeaveModal.vue b/packages/ui/src/components/modal/ConfirmLeaveModal.vue
index cba7b8468c..b49b7c0665 100644
--- a/packages/ui/src/components/modal/ConfirmLeaveModal.vue
+++ b/packages/ui/src/components/modal/ConfirmLeaveModal.vue
@@ -8,18 +8,14 @@
-
-
-
- {{ localizeIfPossible(stayLabel) }}
-
-
-
-
-
- {{ localizeIfPossible(leaveLabel) }}
-
-
+
+
+ {{ localizeIfPossible(stayLabel) }}
+
+
+
+ {{ localizeIfPossible(leaveLabel) }}
+
@@ -30,7 +26,7 @@ import { RightArrowIcon, XIcon } from '@modrinth/assets'
import { ref } from 'vue'
import Admonition from '#ui/components/base/Admonition.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import { defineMessage, type MessageDescriptor, useVIntl } from '#ui/composables/i18n'
import NewModal from './NewModal.vue'
diff --git a/packages/ui/src/components/modal/ConfirmModal.vue b/packages/ui/src/components/modal/ConfirmModal.vue
index 87a091324e..157b909d20 100644
--- a/packages/ui/src/components/modal/ConfirmModal.vue
+++ b/packages/ui/src/components/modal/ConfirmModal.vue
@@ -31,18 +31,19 @@
wrapper-class="max-w-[20rem]"
/>
-
-
-
- Cancel
-
-
-
-
-
- {{ proceedLabel }}
-
-
+
+
+ Cancel
+
+
+
+ {{ proceedLabel }}
+
@@ -53,7 +54,8 @@ import { TrashIcon, XIcon } from '@modrinth/assets'
import { renderString } from '@modrinth/utils'
import { computed, ref } from 'vue'
-import ButtonStyled from '../base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
+
import StyledInput from '../base/StyledInput.vue'
import NewModal from './NewModal.vue'
diff --git a/packages/ui/src/components/modal/NewModal.vue b/packages/ui/src/components/modal/NewModal.vue
index 803b831078..c5cb846bcd 100644
--- a/packages/ui/src/components/modal/NewModal.vue
+++ b/packages/ui/src/components/modal/NewModal.vue
@@ -43,33 +43,28 @@
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
@@ -116,8 +114,10 @@ import { CheckIcon, DownloadIcon, XIcon } from '@modrinth/assets'
import { commonMessages } from '@modrinth/ui'
import { computed, nextTick, onUnmounted, ref } from 'vue'
+import { Button, ButtonLink } from '#ui/components/base/buttons'
+
import { defineMessages, useVIntl } from '../../composables/i18n'
-import { Avatar, ButtonStyled } from '../base'
+import { Avatar } from '../base'
import ServerOnlinePlayers from '../project/server/ServerOnlinePlayers.vue'
import ServerRegion from '../project/server/ServerRegion.vue'
diff --git a/packages/ui/src/components/modal/ShareModal.vue b/packages/ui/src/components/modal/ShareModal.vue
index db9c485c1b..70cf15203c 100644
--- a/packages/ui/src/components/modal/ShareModal.vue
+++ b/packages/ui/src/components/modal/ShareModal.vue
@@ -12,9 +12,10 @@ import {
import QrcodeVue from 'qrcode.vue'
import { computed, nextTick, ref } from 'vue'
+import { ButtonLink, IconButton } from '#ui/components/base/buttons'
import { injectNotificationManager } from '#ui/providers'
-import { ButtonStyled, NewModal, StyledInput } from '../index'
+import { NewModal, StyledInput } from '../index'
const props = defineProps({
header: {
@@ -156,16 +157,15 @@ defineExpose({
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
+
-
-
+ Open in new tab
+
+
+
+
+
+
+
+
+
+
- Open in new tab
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/modal/UnknownFileWarningModal.vue b/packages/ui/src/components/modal/UnknownFileWarningModal.vue
index 247ff96c04..cd4d6055b4 100644
--- a/packages/ui/src/components/modal/UnknownFileWarningModal.vue
+++ b/packages/ui/src/components/modal/UnknownFileWarningModal.vue
@@ -86,17 +86,13 @@
/>
-
-
- {{ formatMessage(messages.installAnyway) }}
-
-
-
-
-
- {{ formatMessage(messages.dontInstall) }}
-
-
+
+ {{ formatMessage(messages.installAnyway) }}
+
+
+
+ {{ formatMessage(messages.dontInstall) }}
+
@@ -106,10 +102,11 @@
import { BanIcon } from '@modrinth/assets'
import { computed, nextTick, ref, useTemplateRef } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { defineMessages, useVIntl } from '../../composables/i18n'
import { useScrollIndicator } from '../../composables/scroll-indicator'
import Admonition from '../base/Admonition.vue'
-import ButtonStyled from '../base/ButtonStyled.vue'
import Checkbox from '../base/Checkbox.vue'
import Table, { type TableColumn } from '../base/Table.vue'
import NewModal from './NewModal.vue'
diff --git a/packages/ui/src/components/nav/NotificationPanel.vue b/packages/ui/src/components/nav/NotificationPanel.vue
index 95626d907e..0f0a592d53 100644
--- a/packages/ui/src/components/nav/NotificationPanel.vue
+++ b/packages/ui/src/components/nav/NotificationPanel.vue
@@ -59,22 +59,27 @@
x{{ item.count }}
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
- {{ button.label }}
-
-
+
+ {{ button.label }}
+
@@ -121,6 +132,7 @@ import {
} from '@modrinth/assets'
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
+import { Button, IconButton } from '#ui/components/base/buttons'
import { useModalStack } from '#ui/composables/modal-stack.ts'
import {
@@ -128,7 +140,6 @@ import {
type WebNotification,
type WebNotificationButton,
} from '../../providers'
-import ButtonStyled from '../base/ButtonStyled.vue'
const notificationManager = injectNotificationManager()
const notifications = computed(() => notificationManager.getNotifications())
diff --git a/packages/ui/src/components/nav/PopupNotificationPanel.vue b/packages/ui/src/components/nav/PopupNotificationPanel.vue
index 49c55ccd58..da57f93c20 100644
--- a/packages/ui/src/components/nav/PopupNotificationPanel.vue
+++ b/packages/ui/src/components/nav/PopupNotificationPanel.vue
@@ -95,11 +95,15 @@
-
-
-
-
-
+
+
+
{{ item.text }}
@@ -142,16 +146,28 @@
full-width
/>
-
-
-
- {{ btn.label }}
-
-
+
+ {{ btn.label }}
+
@@ -171,6 +187,8 @@ import {
} from '@modrinth/assets'
import { computed, ref } from 'vue'
+import { Button, IconButton } from '#ui/components/base/buttons'
+
import { useModalStack } from '../../composables/modal-stack'
import {
injectPopupNotificationManager,
@@ -178,7 +196,6 @@ import {
type PopupNotificationButton,
type PopupNotificationProgressItem,
} from '../../providers'
-import ButtonStyled from '../base/ButtonStyled.vue'
import ProgressBar from '../base/ProgressBar.vue'
import NotificationToast from '../notifications/NotificationToast.vue'
diff --git a/packages/ui/src/components/notifications/NotificationToast.vue b/packages/ui/src/components/notifications/NotificationToast.vue
index 185fee06d7..82169e0044 100644
--- a/packages/ui/src/components/notifications/NotificationToast.vue
+++ b/packages/ui/src/components/notifications/NotificationToast.vue
@@ -49,31 +49,33 @@
-
-
-
-
-
+
+
+
-
-
-
-
- Accept
-
-
-
-
-
- Decline
-
-
+
+
+
+ Accept
+
+
+
+ Decline
+
@@ -96,16 +98,17 @@
{{ entityLabel }}
-
-
-
-
-
+
+
+
-
- Launch game
-
-
- Instance
-
+ Launch game
+ Instance
{{ progressLabel }}
@@ -145,16 +144,28 @@
v-if="type === 'instance-download' && actions?.length"
class="col-start-1 col-end-3 row-start-3 mt-2 flex min-w-0 flex-wrap items-center gap-2"
>
-
-
-
- {{ action.label }}
-
-
+
+ {{ action.label }}
+
@@ -182,11 +193,12 @@
import { CheckIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
import { computed, ref } from 'vue'
+import { Button, IconButton } from '#ui/components/base/buttons'
+
import { useFormatBytes, useFormatNumber } from '../../composables'
import type { PopupNotificationButton, PopupNotificationProgressType } from '../../providers'
import { truncatedTooltip } from '../../utils/truncate'
import Avatar from '../base/Avatar.vue'
-import ButtonStyled from '../base/ButtonStyled.vue'
type NotificationToastType =
| 'friend-request'
diff --git a/packages/ui/src/components/page/NormalPage.vue b/packages/ui/src/components/page/NormalPage.vue
index ce3f0e1689..3acc18993e 100644
--- a/packages/ui/src/components/page/NormalPage.vue
+++ b/packages/ui/src/components/page/NormalPage.vue
@@ -3,6 +3,7 @@ import { injectPageContext } from '@modrinth/ui'
defineProps<{
sidebar?: 'right' | 'left'
+ fullWidth?: boolean
}>()
const { hierarchicalSidebarAvailable } = injectPageContext()
@@ -12,6 +13,7 @@ const { hierarchicalSidebarAvailable } = injectPageContext()
:class="{
'ui-normal-page--sidebar-left': sidebar === 'left' && !hierarchicalSidebarAvailable,
'ui-normal-page--sidebar-right': sidebar === 'right' && !hierarchicalSidebarAvailable,
+ 'ui-normal-page--full-width': fullWidth,
}"
>
-
-
-
-
-
+
+
+
-
-
diff --git a/packages/ui/src/layouts/shared/server-settings/pages/installation.vue b/packages/ui/src/layouts/shared/server-settings/pages/installation.vue
index 3d943bd823..21275870a7 100644
--- a/packages/ui/src/layouts/shared/server-settings/pages/installation.vue
+++ b/packages/ui/src/layouts/shared/server-settings/pages/installation.vue
@@ -22,17 +22,16 @@
formatMessage(messages.resetServerTitle)
}}
-
-
-
- {{ formatMessage(commonMessages.resetServerButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.resetServerButton) }}
+
{{ formatMessage(messages.resetServerDescription) }}
@@ -59,17 +58,16 @@
{{ formatMessage(messages.supportOptionsTitle) }}
-
-
-
- {{ formatMessage(messages.resetToOnboardingButton) }}
-
-
+
+
+ {{ formatMessage(messages.resetToOnboardingButton) }}
+
@@ -79,7 +77,6 @@
import type { Archon } from '@modrinth/api-client'
import { RotateCounterClockwiseIcon } from '@modrinth/assets'
import {
- ButtonStyled,
commonMessages,
ConfirmModal,
defineMessages,
@@ -103,6 +100,7 @@ import {
import { useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed, ref, useTemplateRef, watch } from 'vue'
+import { Button } from '#ui/components/base/buttons'
import { injectFilePicker } from '#ui/providers/file-picker'
const debug = useDebugLogger('LoaderPage')
diff --git a/packages/ui/src/layouts/shared/server-settings/pages/network.vue b/packages/ui/src/layouts/shared/server-settings/pages/network.vue
index dd8091b289..9a91d08000 100644
--- a/packages/ui/src/layouts/shared/server-settings/pages/network.vue
+++ b/packages/ui/src/layouts/shared/server-settings/pages/network.vue
@@ -16,18 +16,16 @@
placeholder="e.g. Secondary allocation"
/>
-
- Cancel
-
-
-
- Update allocation
-
-
+ Cancel
+
+ Update allocation
+
@@ -61,9 +59,14 @@
allocationsError?.message ?? 'Unknown error'
}}
- refetchAllocations()">
- Retry
-
+ refetchAllocations()"
+ >Retry
@@ -83,16 +86,16 @@
placeholder="e.g. Secondary allocation"
/>
-
-
-
- Create allocation
-
-
+
+
+ Create allocation
+
@@ -105,30 +108,33 @@
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
@@ -153,16 +159,14 @@
:placeholder="exampleDomain"
/>
-
-
-
- Export
-
-
+
+
+ Export
+
@@ -223,8 +227,9 @@ import {
import { useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed, nextTick, ref } from 'vue'
-import { ButtonStyled, ConfirmModal, NewModal, StyledInput, Table, TagItem } from '#ui/components'
+import { ConfirmModal, NewModal, StyledInput, Table, TagItem } from '#ui/components'
import type { TableColumn } from '#ui/components/base'
+import { Button, IconButton } from '#ui/components/base/buttons'
import { useServerPermissions } from '#ui/composables/server-permissions'
import {
injectModrinthClient,
diff --git a/packages/ui/src/layouts/shared/user-profile/layout.vue b/packages/ui/src/layouts/shared/user-profile/layout.vue
index be4f1644b9..214a54e876 100644
--- a/packages/ui/src/layouts/shared/user-profile/layout.vue
+++ b/packages/ui/src/layouts/shared/user-profile/layout.vue
@@ -13,19 +13,26 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
-
- {{ formatMessage(messages.blockButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+
+ {{ formatMessage(messages.blockButton) }}
+
@@ -42,28 +49,26 @@
:placeholder="formatMessage(messages.selectRolePlaceholder)"
/>
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
-
- {{ formatMessage(messages.savingLabel) }}
-
-
-
- {{ formatMessage(commonMessages.saveChangesButton) }}
-
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+
+ {{ formatMessage(messages.savingLabel) }}
+
+
+
+ {{ formatMessage(commonMessages.saveChangesButton) }}
+
+
@@ -166,7 +171,7 @@
-
+
+ >
+
+
+
+
-
-
- {{ formatMessage(messages.createProjectButton) }}
-
-
+
+ {{ formatMessage(messages.createProjectButton) }}
+
@@ -354,11 +361,9 @@
"
>
-
-
- {{ formatMessage(messages.createCollectionButton) }}
-
-
+
+ {{ formatMessage(messages.createCollectionButton) }}
+
@@ -411,11 +416,9 @@
:description="formatMessage(messages.userLoadErrorDescription)"
>
-
-
- {{ formatMessage(commonMessages.retryButton) }}
-
-
+
+ {{ formatMessage(commonMessages.retryButton) }}
+
@@ -447,7 +450,7 @@ import { useRoute, useRouter } from 'vue-router'
import Admonition from '#ui/components/base/Admonition.vue'
import AutoLink from '#ui/components/base/AutoLink.vue'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import Combobox from '#ui/components/base/Combobox.vue'
import EmptyState from '#ui/components/base/EmptyState.vue'
import IntlFormatted from '#ui/components/base/IntlFormatted.vue'
diff --git a/packages/ui/src/layouts/wrapped/AccountProfileSettings.vue b/packages/ui/src/layouts/wrapped/AccountProfileSettings.vue
index 1cd295cdcc..f38537a444 100644
--- a/packages/ui/src/layouts/wrapped/AccountProfileSettings.vue
+++ b/packages/ui/src/layouts/wrapped/AccountProfileSettings.vue
@@ -15,12 +15,10 @@
-
-
-
- {{ formatMessage(commonMessages.signInButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.signInButton) }}
+
@@ -56,30 +54,33 @@
-
-
-
-
-
-
-
-
- {{ formatMessage(commonMessages.removeImageButton) }}
-
-
-
-
-
- {{ formatMessage(commonMessages.resetButton) }}
-
-
+
+
+
+
+
+ {{ formatMessage(commonMessages.removeImageButton) }}
+
+
+
+ {{ formatMessage(commonMessages.resetButton) }}
+
@@ -135,9 +136,8 @@ import { computed, onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import { RouterLink } from 'vue-router'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button, FileButton } from '#ui/components/base/buttons'
import EmptyState from '#ui/components/base/EmptyState.vue'
-import FileInput from '#ui/components/base/FileInput.vue'
import IntlFormatted from '#ui/components/base/IntlFormatted.vue'
import StyledInput from '#ui/components/base/StyledInput.vue'
import { defineMessages, useVIntl } from '#ui/composables'
diff --git a/packages/ui/src/layouts/wrapped/AccountSocialSettings.vue b/packages/ui/src/layouts/wrapped/AccountSocialSettings.vue
index 6d2f4f5d8c..240744fa31 100644
--- a/packages/ui/src/layouts/wrapped/AccountSocialSettings.vue
+++ b/packages/ui/src/layouts/wrapped/AccountSocialSettings.vue
@@ -15,12 +15,10 @@
-
-
-
- {{ formatMessage(commonMessages.signInButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.signInButton) }}
+
@@ -112,11 +110,9 @@
{{ formatMessage(messages.loadError) }}
-
-
- {{ formatMessage(commonMessages.retryButton) }}
-
-
+
+ {{ formatMessage(commonMessages.retryButton) }}
+
{{ formatMessage(messages.noBlockedUsers) }}
@@ -145,25 +141,24 @@
-
-
-
- {{ formatMessage(messages.unblockButton) }}
-
-
+
+
+ {{ formatMessage(messages.unblockButton) }}
+
@@ -195,7 +190,7 @@ import { useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed, ref } from 'vue'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import Chips from '#ui/components/base/Chips.vue'
import EmptyState from '#ui/components/base/EmptyState.vue'
import Table, { type TableColumn } from '#ui/components/base/Table.vue'
diff --git a/packages/ui/src/layouts/wrapped/hosting/manage/[id]/access/access.vue b/packages/ui/src/layouts/wrapped/hosting/manage/[id]/access/access.vue
index 96cc63944a..b85f8d8fe3 100644
--- a/packages/ui/src/layouts/wrapped/hosting/manage/[id]/access/access.vue
+++ b/packages/ui/src/layouts/wrapped/hosting/manage/[id]/access/access.vue
@@ -14,23 +14,25 @@
v-model="roleFilter"
:options="roleFilterOptions"
:display-value="selectedRoleFilterLabel"
- trigger-class="min-w-[225px] !h-10 !min-h-10 !py-0"
+ trigger-size="lg"
+ trigger-class="min-w-[225px]"
>
-
-
-
- {{ formatMessage(messages.inviteFriends) }}
-
-
+
+
+ {{ formatMessage(messages.inviteFriends) }}
+
@@ -113,7 +115,7 @@ import { FilterIcon, SearchIcon, UserPlusIcon } from '@modrinth/assets'
import { useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed, ref, watch } from 'vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import Combobox, { type ComboboxOption } from '#ui/components/base/Combobox.vue'
import DropdownFilterBar from '#ui/components/base/DropdownFilterBar.vue'
import StyledInput from '#ui/components/base/StyledInput.vue'
diff --git a/packages/ui/src/layouts/wrapped/hosting/manage/[id]/onboarding.vue b/packages/ui/src/layouts/wrapped/hosting/manage/[id]/onboarding.vue
index bcdebf6392..f231ba7956 100644
--- a/packages/ui/src/layouts/wrapped/hosting/manage/[id]/onboarding.vue
+++ b/packages/ui/src/layouts/wrapped/hosting/manage/[id]/onboarding.vue
@@ -42,22 +42,22 @@
-
-
-
- {{ formatMessage(messages.uploadingProgress, { percent: uploadPercent }) }}
-
-
-
-
- {{ formatMessage(messages.setupServerButton) }}
-
-
+
+
+ {{ formatMessage(messages.uploadingProgress, { percent: uploadPercent }) }}
+
+
+ {{ formatMessage(messages.setupServerButton) }}
+
{{ error.message }}
-
- Retry
-
+ Retry
@@ -71,16 +71,16 @@
{{ formatMessage(commonMessages.allProjectType) }}
-
-
-
- {{ formatMessage(messages.createBackup) }}
-
-
+
+
+ {{ formatMessage(messages.createBackup) }}
+
@@ -95,17 +95,17 @@
:description="formatMessage(messages.emptyDescription)"
>
-
-
-
- {{ formatMessage(messages.createBackup) }}
-
-
+
+
+ {{ formatMessage(messages.createBackup) }}
+
-
-
- {{ formatMessage(messages.clearFilters) }}
-
-
+
+ {{ formatMessage(messages.clearFilters) }}
+
@@ -198,30 +196,30 @@
}}
-
-
- {{ formatMessage(commonMessages.clearButton) }}
-
-
+
+ {{ formatMessage(commonMessages.clearButton) }}
+
-
-
-
- {{ formatMessage(commonMessages.deleteLabel) }}
-
-
+
+
+ {{ formatMessage(commonMessages.deleteLabel) }}
+
@@ -273,7 +271,7 @@ import type { Component } from 'vue'
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import Checkbox from '#ui/components/base/Checkbox.vue'
import EmptyState from '#ui/components/base/EmptyState.vue'
import FilterPills, { type FilterPillOption } from '#ui/components/base/FilterPills.vue'
diff --git a/packages/ui/src/layouts/wrapped/hosting/manage/index.vue b/packages/ui/src/layouts/wrapped/hosting/manage/index.vue
index d22ac2dac4..f85d23337c 100644
--- a/packages/ui/src/layouts/wrapped/hosting/manage/index.vue
+++ b/packages/ui/src/layouts/wrapped/hosting/manage/index.vue
@@ -75,14 +75,17 @@
-
- {{
- formatMessage(messages.contactSupportButton)
- }}
-
- router.go(0)">
- {{ formatMessage(messages.reloadButton) }}
-
+ {{ formatMessage(messages.contactSupportButton) }}
+ router.go(0)">{{
+ formatMessage(messages.reloadButton)
+ }}
@@ -106,12 +109,10 @@
:placeholder="formatMessage(messages.searchPlaceholder, { count: filteredData.length })"
wrapper-class="w-full md:w-72"
/>
-
-
-
- {{ formatMessage(messages.newServerButton) }}
-
-
+
+
+ {{ formatMessage(messages.newServerButton) }}
+
@@ -231,8 +232,6 @@
import type { Archon, Labrinth } from '@modrinth/api-client'
import { HammerIcon, LoaderCircleIcon, PlusIcon, SearchIcon } from '@modrinth/assets'
import {
- AutoLink,
- ButtonStyled,
CopyCode,
defineMessages,
injectAuth,
@@ -255,6 +254,7 @@ import type Stripe from 'stripe'
import { type ComponentPublicInstance, computed, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
+import { Button, ButtonLink } from '#ui/components/base/buttons'
import ServersUpgradeModalWrapper from '#ui/components/billing/ServersUpgradeModalWrapper.vue'
import type { ServerListingOwner } from '#ui/components/servers/access'
import MedalServerListing from '#ui/components/servers/marketing/MedalServerListing.vue'
diff --git a/packages/ui/src/layouts/wrapped/hosting/manage/root.vue b/packages/ui/src/layouts/wrapped/hosting/manage/root.vue
index c781570242..dbf56d1b69 100644
--- a/packages/ui/src/layouts/wrapped/hosting/manage/root.vue
+++ b/packages/ui/src/layouts/wrapped/hosting/manage/root.vue
@@ -181,31 +181,30 @@
:auto-hide="false"
placement="bottom-end"
>
-
-
-
-
-
+
+
+
{{ formatMessage(settingsHintMessages.title) }}
-
-
-
-
-
+
+
+
{{ formatMessage(settingsHintMessages.description) }}
@@ -213,15 +212,15 @@
-
-
-
-
-
+
+
+
@@ -284,13 +283,11 @@
If you're stuck, please contact Modrinth Support with the information below:
-
-
-
-
- Copy Debug Info
-
-
+
+
+
+ Copy Debug Info
+
An internal error occurred while installing your server. Don't fret — try
@@ -310,25 +307,23 @@
v-if="errorTitle === 'Installation error'"
class="mt-2 flex flex-col gap-4 sm:flex-row"
>
-
- Open Installation Log
-
-
-
-
-
- Copy Debug Info
-
-
-
-
-
- Change Loader
-
-
+ Open Installation Log
+
+
+
+ Copy Debug Info
+
+
+
+ Change Loader
+
@@ -430,7 +425,7 @@ import { computed, nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, watch
import { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button, IconButton, TeleportOverflowMenu } from '#ui/components/base/buttons'
import ErrorInformationCard from '#ui/components/base/ErrorInformationCard.vue'
import NavTabs from '#ui/components/base/NavTabs.vue'
import PageHeader from '#ui/components/base/page-header/index.vue'
@@ -438,7 +433,6 @@ import PageHeaderMetadata from '#ui/components/base/page-header/metadata/index.v
import PageHeaderMetadataItem from '#ui/components/base/page-header/metadata/page-header-metadata-item.vue'
import PageHeaderActions from '#ui/components/base/page-header/page-header-actions.vue'
import ServerNotice from '#ui/components/base/ServerNotice.vue'
-import TeleportOverflowMenu from '#ui/components/base/TeleportOverflowMenu.vue'
import ConfirmLeaveModal from '#ui/components/modal/ConfirmLeaveModal.vue'
import ServerPanelAdmonitions from '#ui/components/servers/admonitions/ServerPanelAdmonitions.vue'
import LoaderIcon from '#ui/components/servers/icons/LoaderIcon.vue'
diff --git a/packages/ui/src/stories/add-stories.md b/packages/ui/src/stories/add-stories.md
index 19f83c3ba9..2132d4f14c 100644
--- a/packages/ui/src/stories/add-stories.md
+++ b/packages/ui/src/stories/add-stories.md
@@ -153,16 +153,14 @@ For components that need user interaction to show:
```typescript
export const Default: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { Button, NewModal },
setup() {
const modalRef = ref | null>(null)
return { modalRef }
},
template: /* html */ `
-
- Open Modal
-
+
Open Modal
Modal content
@@ -199,10 +197,10 @@ Components should use relative imports, not the package alias:
```typescript
// ❌ BAD - Causes circular dependency in Storybook
-import { ButtonStyled } from '@modrinth/ui'
+import { Button } from '@modrinth/ui'
// ✅ GOOD - Use relative imports
-import ButtonStyled from '../base/ButtonStyled.vue'
+import Button from '../components/base/buttons/Button.vue'
```
### 2. Object/Array Prop Defaults Must Be Factory Functions
diff --git a/packages/ui/src/stories/base/Admonition.stories.ts b/packages/ui/src/stories/base/Admonition.stories.ts
index 413e2a1b6d..bcd6894084 100644
--- a/packages/ui/src/stories/base/Admonition.stories.ts
+++ b/packages/ui/src/stories/base/Admonition.stories.ts
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { ref } from 'vue'
import Admonition from '../../components/base/Admonition.vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
const meta = {
title: 'Base/Admonition',
@@ -78,7 +78,7 @@ export const HeaderWithTimestamp: Story = {
export const WithTopRightActions: Story = {
render: () => ({
- components: { Admonition, ButtonStyled },
+ components: { Admonition, Button },
template: /*html*/ `
Uploading server files...
-
- Cancel
-
+ Cancel
Something went wrong while extracting the archive.
-
- Retry
-
+ Retry
@@ -115,7 +111,7 @@ export const WithTopRightActions: Story = {
export const WithProgressBar: Story = {
render: () => ({
- components: { Admonition, ButtonStyled },
+ components: { Admonition, Button },
template: /*html*/ `
128 KB / 1.2 MB (45%)
-
- Cancel
-
+ Cancel
24 MB extracted — config/settings.yml
-
- Cancel
-
+ Cancel
({
- components: { Button },
- setup() {
- return { args }
- },
- template: /*html*/ `
- Click me
- `,
- }),
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Default: Story = {}
-
-export const Primary: Story = {
- args: {
- color: 'primary',
- },
-}
-
-export const Danger: Story = {
- args: {
- color: 'danger',
- },
-}
-
-export const AllColors: Story = {
- render: () => ({
- components: { Button },
- template: /*html*/ `
-
- Default
- Primary
- Danger
- Red
- Orange
- Green
- Blue
- Purple
-
- `,
- }),
-}
-
-export const Large: Story = {
- args: {
- large: true,
- },
-}
-
-export const Outline: Story = {
- args: {
- outline: true,
- },
-}
-
-export const Transparent: Story = {
- args: {
- transparent: true,
- },
-}
-
-export const Disabled: Story = {
- args: {
- disabled: true,
- },
-}
-
-export const AsLink: Story = {
- args: {
- link: 'https://modrinth.com',
- external: true,
- },
-}
diff --git a/packages/ui/src/stories/base/ButtonStyled.stories.ts b/packages/ui/src/stories/base/ButtonStyled.stories.ts
deleted file mode 100644
index 852ceab118..0000000000
--- a/packages/ui/src/stories/base/ButtonStyled.stories.ts
+++ /dev/null
@@ -1,226 +0,0 @@
-import { DownloadIcon, HeartIcon, SettingsIcon } from '@modrinth/assets'
-import type { Meta, StoryObj } from '@storybook/vue3-vite'
-
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
-
-const colors = ['standard', 'brand', 'red', 'orange', 'green', 'blue', 'purple'] as const
-const types = [
- 'standard',
- 'outlined',
- 'transparent',
- 'highlight',
- 'highlight-colored-text',
- 'chip',
-] as const
-const sizes = ['small', 'standard', 'large'] as const
-
-const meta = {
- title: 'Base/ButtonStyled',
- component: ButtonStyled,
- argTypes: {
- color: {
- control: 'select',
- options: [...colors, 'medal-promo'],
- },
- size: {
- control: 'select',
- options: [...sizes],
- },
- type: {
- control: 'select',
- options: [...types],
- },
- circular: { control: 'boolean' },
- colorFill: {
- control: 'select',
- options: ['auto', 'background', 'text', 'none'],
- },
- hoverColorFill: {
- control: 'select',
- options: ['auto', 'background', 'text', 'none'],
- },
- highlighted: { control: 'boolean' },
- highlightedStyle: {
- control: 'select',
- options: ['main-nav-primary', 'main-nav-secondary'],
- },
- },
- args: {
- color: 'standard',
- size: 'standard',
- type: 'standard',
- circular: false,
- colorFill: 'auto',
- hoverColorFill: 'auto',
- highlighted: false,
- highlightedStyle: 'main-nav-primary',
- },
- render: (args) => ({
- components: { ButtonStyled, DownloadIcon },
- setup() {
- return { args }
- },
- template: /*html*/ `
-
- Button
-
- `,
- }),
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Default: Story = {
- args: {
- type: 'standard',
- },
-}
-
-export const AllVariants: Story = {
- render: () => ({
- components: { ButtonStyled },
- setup() {
- return { colors, types }
- },
- template: /*html*/ `
-
-
-
-
- | Color / Type |
- {{ type }} |
-
-
-
-
- | {{ color }} |
-
-
- Button
-
- |
-
-
-
-
- `,
- }),
-}
-
-export const AllVariantsHighlighted: Story = {
- render: () => ({
- components: { ButtonStyled },
- setup() {
- return { colors, types }
- },
- template: /*html*/ `
-
-
-
-
- | Color / Type |
- {{ type }} |
-
-
-
-
- | {{ color }} |
-
-
- Button
-
- |
-
-
-
-
- `,
- }),
-}
-
-export const Sizes: Story = {
- render: () => ({
- components: { ButtonStyled },
- setup() {
- return { sizes, types }
- },
- template: /*html*/ `
-
-
-
-
- | Size / Type |
- {{ type }} |
-
-
-
-
- | {{ size }} |
-
-
- Button
-
- |
-
-
-
-
- `,
- }),
-}
-
-export const WithIcons: Story = {
- render: () => ({
- components: { ButtonStyled, DownloadIcon, HeartIcon, SettingsIcon },
- setup() {
- return { types }
- },
- template: /*html*/ `
-
-
-
-
- | Variant |
- {{ type }} |
-
-
-
-
- | Icon + text |
-
-
- Download
-
- |
-
-
- | Icon only |
-
-
-
-
- |
-
-
-
-
- `,
- }),
-}
-
-export const Disabled: Story = {
- render: () => ({
- components: { ButtonStyled },
- setup() {
- return { types }
- },
- template: /*html*/ `
-
-
- {{ type }}
-
-
- `,
- }),
-}
diff --git a/packages/ui/src/stories/base/EmptyState.stories.ts b/packages/ui/src/stories/base/EmptyState.stories.ts
index f698148b9b..8fa5be7f23 100644
--- a/packages/ui/src/stories/base/EmptyState.stories.ts
+++ b/packages/ui/src/stories/base/EmptyState.stories.ts
@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/vue3-vite'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
import EmptyState from '../../components/base/EmptyState.vue'
const meta = {
@@ -42,7 +42,7 @@ export const Default: Story = {
export const WithActions: StoryObj = {
render: () => ({
- components: { EmptyState, ButtonStyled },
+ components: { EmptyState, Button },
template: /*html*/ `
-
- Create backup
-
+ Create backup
`,
diff --git a/packages/ui/src/stories/base/JoinedButtons.stories.ts b/packages/ui/src/stories/base/JoinedButtons.stories.ts
deleted file mode 100644
index c007e3631d..0000000000
--- a/packages/ui/src/stories/base/JoinedButtons.stories.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-import { PlayIcon, SlashIcon, StopCircleIcon, UpdatedIcon } from '@modrinth/assets'
-import type { Meta, StoryObj } from '@storybook/vue3-vite'
-
-import JoinedButtons from '../../components/base/JoinedButtons.vue'
-
-const meta = {
- title: 'Base/JoinedButtons',
- component: JoinedButtons,
- argTypes: {
- color: {
- control: 'select',
- options: ['standard', 'brand', 'red', 'orange', 'green', 'blue', 'purple'],
- },
- size: {
- control: 'select',
- options: ['small', 'standard', 'large'],
- },
- disabled: { control: 'boolean' },
- primaryDisabled: { control: 'boolean' },
- dropdownDisabled: { control: 'boolean' },
- primaryMuted: { control: 'boolean' },
- },
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Start: Story = {
- args: {
- color: 'brand',
- size: 'large',
- actions: [
- {
- id: 'start',
- label: 'Start',
- icon: PlayIcon,
- action: () => console.log('Start'),
- },
- ],
- },
-}
-
-export const StopWithKill: Story = {
- args: {
- color: 'red',
- size: 'large',
- actions: [
- {
- id: 'stop',
- label: 'Stop',
- icon: StopCircleIcon,
- action: () => console.log('Stop'),
- },
- {
- id: 'kill_server',
- label: 'Kill server',
- icon: SlashIcon,
- action: () => console.log('Kill'),
- },
- ],
- },
-}
-
-export const Stopping: Story = {
- args: {
- color: 'red',
- size: 'large',
- primaryDisabled: true,
- primaryMuted: true,
- actions: [
- {
- id: 'stop',
- label: 'Stopping',
- icon: StopCircleIcon,
- action: () => console.log('Stop'),
- },
- {
- id: 'kill_server',
- label: 'Kill server',
- icon: SlashIcon,
- action: () => console.log('Kill'),
- },
- ],
- },
-}
-
-export const Restart: Story = {
- args: {
- color: 'orange',
- size: 'large',
- actions: [
- {
- id: 'restart',
- label: 'Restart',
- icon: UpdatedIcon,
- action: () => console.log('Restart'),
- },
- ],
- },
-}
-
-export const Disabled: Story = {
- args: {
- color: 'red',
- size: 'large',
- disabled: true,
- actions: [
- {
- id: 'stop',
- label: 'Stop',
- icon: StopCircleIcon,
- action: () => console.log('Stop'),
- },
- {
- id: 'kill_server',
- label: 'Kill server',
- icon: SlashIcon,
- action: () => console.log('Kill'),
- },
- ],
- },
-}
diff --git a/packages/ui/src/stories/base/OverflowMenu.stories.ts b/packages/ui/src/stories/base/OverflowMenu.stories.ts
deleted file mode 100644
index 0adec75cf2..0000000000
--- a/packages/ui/src/stories/base/OverflowMenu.stories.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { MoreHorizontalIcon } from '@modrinth/assets'
-import type { Meta, StoryObj } from '@storybook/vue3-vite'
-
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
-import OverflowMenu from '../../components/base/OverflowMenu.vue'
-
-const meta = {
- title: 'Base/OverflowMenu',
- component: OverflowMenu,
- render: (args) => ({
- components: { OverflowMenu, MoreHorizontalIcon, ButtonStyled },
- setup() {
- return { args }
- },
- template: /*html*/ `
-
-
-
- Edit
- Delete
- Share
-
-
- `,
- }),
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Default: Story = {
- args: {
- options: [
- { id: 'edit', action: () => console.log('Edit clicked') },
- { id: 'share', action: () => console.log('Share clicked') },
- { divider: true },
- { id: 'delete', action: () => console.log('Delete clicked'), color: 'danger' },
- ],
- },
-}
-
-export const WithDifferentPlacements: StoryObj = {
- render: () => ({
- components: { OverflowMenu, MoreHorizontalIcon, ButtonStyled },
- template: /*html*/ `
-
-
- bottom-end (default)
-
-
-
- Edit
- Delete
-
-
-
-
- bottom-start
-
-
-
- Edit
- Delete
-
-
-
-
- `,
- }),
-}
diff --git a/packages/ui/src/stories/base/PageHeader.stories.ts b/packages/ui/src/stories/base/PageHeader.stories.ts
index 73ad628820..d2e569ae6b 100644
--- a/packages/ui/src/stories/base/PageHeader.stories.ts
+++ b/packages/ui/src/stories/base/PageHeader.stories.ts
@@ -20,9 +20,13 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite'
import AutoLink from '../../components/base/AutoLink.vue'
import Avatar from '../../components/base/Avatar.vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import {
+ Button,
+ IconButton,
+ SplitButton,
+ TeleportOverflowMenu,
+} from '../../components/base/buttons'
import FormattedTag from '../../components/base/FormattedTag.vue'
-import JoinedButtons from '../../components/base/JoinedButtons.vue'
import PageHeader from '../../components/base/page-header/index.vue'
import PageHeaderMetadata from '../../components/base/page-header/metadata/index.vue'
import PageHeaderMetadataItem from '../../components/base/page-header/metadata/page-header-metadata-item.vue'
@@ -32,7 +36,6 @@ import PageHeaderMetadataTimeItem from '../../components/base/page-header/metada
import PageHeaderActions from '../../components/base/page-header/page-header-actions.vue'
import PageHeaderBadgeItem from '../../components/base/page-header/page-header-badge-item.vue'
import TagItem from '../../components/base/TagItem.vue'
-import TeleportOverflowMenu from '../../components/base/TeleportOverflowMenu.vue'
import LoaderIcon from '../../components/servers/icons/LoaderIcon.vue'
import ServerIcon from '../../components/servers/icons/ServerIcon.vue'
@@ -87,9 +90,10 @@ const pageHeaderIcons = {
const pageHeaderComponents = {
AutoLink,
Avatar,
- ButtonStyled,
+ Button,
FormattedTag,
- JoinedButtons,
+ IconButton,
+ SplitButton,
PageHeader,
PageHeaderActions,
PageHeaderBadgeItem,
@@ -111,7 +115,7 @@ const meta = {
},
decorators: [
(story) => ({
- components: { story },
+ components: { story, TeleportOverflowMenu },
template: '
',
}),
],
@@ -157,17 +161,13 @@ export const ProjectHeader: Story = {
-
-
-
- Download
-
-
-
-
-
-
-
+
+
+ Download
+
+
+
+
@@ -207,12 +207,10 @@ export const CreatorHeader: Story = {
-
-
-
- Follow
-
-
+
+
+ Follow
+
@@ -222,10 +220,7 @@ export const CreatorHeader: Story = {
export const AppInstanceHeader: Story = {
render: () => ({
- components: {
- ...pageHeaderComponents,
- LoaderIcon,
- },
+ components: { ...pageHeaderComponents, LoaderIcon, TeleportOverflowMenu },
setup() {
return {
...pageHeaderIcons,
@@ -252,22 +247,16 @@ export const AppInstanceHeader: Story = {
-
-
-
- Play
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ Play
+
+
+
+
+
+
+
@@ -277,10 +266,7 @@ export const AppInstanceHeader: Story = {
export const BrowseHeader: Story = {
render: () => ({
- components: {
- ...pageHeaderComponents,
- LoaderIcon,
- },
+ components: { ...pageHeaderComponents, LoaderIcon, TeleportOverflowMenu },
setup() {
return {
...pageHeaderIcons,
@@ -291,11 +277,9 @@ export const BrowseHeader: Story = {
template: `
-
-
-
-
-
+
+
+
@@ -317,10 +301,7 @@ export const BrowseHeader: Story = {
export const ServerPanelRootHeader: Story = {
render: () => ({
- components: {
- ...pageHeaderComponents,
- ServerIcon,
- },
+ components: { ...pageHeaderComponents, ServerIcon, TeleportOverflowMenu },
setup() {
return {
...pageHeaderIcons,
@@ -346,17 +327,13 @@ export const ServerPanelRootHeader: Story = {
-
-
-
- Start server
-
-
-
-
-
-
-
+
+
+ Start server
+
+
+
+
@@ -366,10 +343,7 @@ export const ServerPanelRootHeader: Story = {
export const ServerPanelInstanceHeader: Story = {
render: () => ({
- components: {
- ...pageHeaderComponents,
- LoaderIcon,
- },
+ components: { ...pageHeaderComponents, LoaderIcon, TeleportOverflowMenu },
setup() {
return {
...pageHeaderIcons,
@@ -381,11 +355,9 @@ export const ServerPanelInstanceHeader: Story = {
template: `
-
-
-
-
-
+
+
+
@@ -400,18 +372,24 @@ export const ServerPanelInstanceHeader: Story = {
-
-
-
- Start instance
-
-
-
-
-
-
-
-
+
+
+ Start instance
+
+
+
+ Stop
+
+
+
+
diff --git a/packages/ui/src/stories/base/PopoutMenu.stories.ts b/packages/ui/src/stories/base/PopoutMenu.stories.ts
deleted file mode 100644
index 7e3d02a512..0000000000
--- a/packages/ui/src/stories/base/PopoutMenu.stories.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import { SettingsIcon } from '@modrinth/assets'
-import type { Meta, StoryObj } from '@storybook/vue3-vite'
-
-import Button from '../../components/base/Button.vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
-import PopoutMenu from '../../components/base/PopoutMenu.vue'
-
-const meta = {
- title: 'Base/PopoutMenu',
- component: PopoutMenu,
- render: (args) => ({
- components: { PopoutMenu, Button, ButtonStyled, SettingsIcon },
- setup() {
- return { args }
- },
- template: /*html*/ `
-
-
-
-
-
- Option 1
- Option 2
- Option 3
-
-
-
-
- `,
- }),
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Default: Story = {}
-
-export const WithTooltip: Story = {
- args: {
- tooltip: 'Click for more options',
- },
-}
-
-export const DifferentPlacements: StoryObj = {
- render: () => ({
- components: { PopoutMenu, Button, ButtonStyled, SettingsIcon },
- template: /*html*/ `
-
-
-
bottom-end (default)
-
-
-
-
-
- Option 1
- Option 2
-
-
-
-
-
-
-
bottom-start
-
-
-
-
-
- Option 1
- Option 2
-
-
-
-
-
-
-
top-end
-
-
-
-
-
- Option 1
- Option 2
-
-
-
-
-
-
- `,
- }),
-}
diff --git a/packages/ui/src/stories/base/StackedAdmonitions.stories.ts b/packages/ui/src/stories/base/StackedAdmonitions.stories.ts
index c0683ad7df..fbef68fb42 100644
--- a/packages/ui/src/stories/base/StackedAdmonitions.stories.ts
+++ b/packages/ui/src/stories/base/StackedAdmonitions.stories.ts
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { ref } from 'vue'
import Admonition from '../../components/base/Admonition.vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
import StackedAdmonitionsRaw, {
type StackedAdmonitionItem,
} from '../../components/base/StackedAdmonitions.vue'
@@ -383,7 +383,7 @@ interface RichItem extends StackedAdmonitionItem {
export const RichContent: Story = {
render: () => ({
- components: { StackedAdmonitions, Admonition, ButtonStyled },
+ components: { StackedAdmonitions, Admonition, Button },
setup() {
const items = ref([
{
@@ -429,12 +429,8 @@ export const RichContent: Story = {
>
{{ item.body }}
-
- Cancel
-
-
- Retry
-
+ Cancel
+ Retry
diff --git a/packages/ui/src/stories/base/Table.stories.ts b/packages/ui/src/stories/base/Table.stories.ts
index 157c1ffbcb..6448cbe7bd 100644
--- a/packages/ui/src/stories/base/Table.stories.ts
+++ b/packages/ui/src/stories/base/Table.stories.ts
@@ -3,8 +3,7 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { computed, ref } from 'vue'
import Badge from '../../components/base/Badge.vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
-import OverflowMenu from '../../components/base/OverflowMenu.vue'
+import { Button, TeleportOverflowMenu } from '../../components/base/buttons'
import Table from '../../components/base/Table.vue'
interface User {
@@ -54,7 +53,7 @@ export default meta
export const Default: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -74,7 +73,7 @@ export const Default: StoryObj = {
export const HorizontalOverflow: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -103,7 +102,7 @@ export const HorizontalOverflow: StoryObj = {
export const CustomClasses: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name', cellClass: '!overflow-visible py-3' },
@@ -129,7 +128,7 @@ export const CustomClasses: StoryObj = {
export const WithSelection: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -160,7 +159,7 @@ export const WithSelection: StoryObj = {
export const WithSelectionData: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -193,7 +192,7 @@ export const WithSelectionData: StoryObj = {
export const WithSelectionIds: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -233,7 +232,7 @@ export const WithSorting: StoryObj = {
},
},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name', enableSorting: true },
@@ -269,7 +268,7 @@ export const WithSorting: StoryObj = {
export const WithColumnAlignment: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name', align: 'left' as const },
@@ -289,7 +288,7 @@ export const WithColumnAlignment: StoryObj = {
export const WithCustomCellSlots: StoryObj = {
args: {},
render: () => ({
- components: { Table, Badge },
+ components: { Table, Badge, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -335,7 +334,7 @@ export const WithCustomCellSlots: StoryObj = {
export const WithCustomHeaderSlots: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -365,7 +364,7 @@ export const WithCustomHeaderSlots: StoryObj = {
export const WithHeaderSlot: StoryObj = {
args: {},
render: () => ({
- components: { Table, ButtonStyled },
+ components: { Table, Button, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -383,9 +382,7 @@ export const WithHeaderSlot: StoryObj = {
Team Members
-
- Invite member
-
+ Invite member
@@ -397,7 +394,7 @@ export const WithHeaderSlot: StoryObj = {
export const WithActionsColumn: StoryObj = {
args: {},
render: () => ({
- components: { Table, ButtonStyled, EditIcon, TrashIcon },
+ components: { Table, EditIcon, TrashIcon, Button, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -421,18 +418,14 @@ export const WithActionsColumn: StoryObj = {
-
-
-
- Edit
-
-
-
-
-
- Delete
-
-
+
+
+ Edit
+
+
+
+ Delete
+
@@ -443,7 +436,7 @@ export const WithActionsColumn: StoryObj = {
export const WithLocalizedActionsColumn: StoryObj = {
args: {},
render: () => ({
- components: { Table, ButtonStyled, EditIcon, TrashIcon },
+ components: { Table, EditIcon, TrashIcon, Button, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Nombre' },
@@ -467,18 +460,14 @@ export const WithLocalizedActionsColumn: StoryObj = {
-
-
-
- Editar
-
-
-
-
-
- Eliminar
-
-
+
+
+ Editar
+
+
+
+ Eliminar
+
@@ -489,7 +478,7 @@ export const WithLocalizedActionsColumn: StoryObj = {
export const FullFeatured: StoryObj = {
args: {},
render: () => ({
- components: { Table, Badge, ButtonStyled, EditIcon, TrashIcon },
+ components: { Table, Badge, EditIcon, TrashIcon, Button, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name', enableSorting: true },
@@ -565,18 +554,14 @@ export const FullFeatured: StoryObj = {
-
-
-
- Edit
-
-
-
-
-
- Delete
-
-
+
+
+ Edit
+
+
+
+ Delete
+
@@ -592,7 +577,7 @@ export const FullFeatured: StoryObj = {
export const VirtualizedLargeData: StoryObj = {
args: {},
render: () => ({
- components: { Table, Badge },
+ components: { Table, Badge, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name', enableSorting: true },
@@ -710,7 +695,15 @@ export const VirtualizedLargeData: StoryObj = {
export const WithOverflowMenu: StoryObj = {
args: {},
render: () => ({
- components: { Table, Badge, ButtonStyled, OverflowMenu, MoreVerticalIcon, EditIcon, TrashIcon },
+ components: {
+ Table,
+ Badge,
+ MoreVerticalIcon,
+ EditIcon,
+ TrashIcon,
+ Button,
+ TeleportOverflowMenu,
+ },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -737,17 +730,19 @@ export const WithOverflowMenu: StoryObj = {
const getMenuOptions = (row: User) => [
{
id: 'edit',
+ label: 'Edit',
action: () => alert(`Edit user: ${row.name}`),
},
{
id: 'duplicate',
+ label: 'Duplicate',
action: () => alert(`Duplicate user: ${row.name}`),
},
- { divider: true },
+ { type: 'divider' },
{
id: 'delete',
- color: 'red' as const,
- hoverFilled: true,
+ label: 'Delete',
+ tone: 'red',
action: () => alert(`Delete user: ${row.name}`),
},
]
@@ -766,26 +761,23 @@ export const WithOverflowMenu: StoryObj = {
-
-
-
-
-
- Edit
-
-
-
- Duplicate
-
-
-
- Delete
-
-
-
+
+
+
+ Edit
+
+
+
+ Duplicate
+
+
+
+ Delete
+
+
@@ -796,7 +788,7 @@ export const WithOverflowMenu: StoryObj = {
export const EmptyState: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
diff --git a/packages/ui/src/stories/buttons/Button.stories.ts b/packages/ui/src/stories/buttons/Button.stories.ts
new file mode 100644
index 0000000000..b5e36499a0
--- /dev/null
+++ b/packages/ui/src/stories/buttons/Button.stories.ts
@@ -0,0 +1,208 @@
+import { DownloadIcon, ExternalIcon, HeartIcon, SettingsIcon } from '@modrinth/assets'
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+
+import Button from '../../components/base/buttons/Button.vue'
+import ButtonLink from '../../components/base/buttons/ButtonLink.vue'
+import IconButton from '../../components/base/buttons/IconButton.vue'
+
+const types = ['base', 'colored', 'outlined', 'quiet'] as const
+const sizes = ['sm', 'md', 'lg', 'xl'] as const
+const colors = ['brand', 'red', 'orange', 'green', 'blue', 'purple', 'medal_promotion'] as const
+const sizeColumns = [
+ { value: 'sm', label: 'Small' },
+ { value: 'md', label: 'Medium' },
+ { value: 'lg', label: 'Large' },
+ { value: 'xl', label: 'Extra large' },
+] as const
+const typeRows = [
+ { label: 'Base', type: 'base' },
+ { label: 'Outlined', type: 'outlined' },
+ { label: 'Quiet', type: 'quiet' },
+ ...colors.map((color) => ({
+ label: `Colored / ${color.charAt(0).toUpperCase()}${color.slice(1)}`,
+ type: 'colored' as const,
+ color,
+ })),
+ ...colors.map((color) => ({
+ label: `Quiet / ${color.charAt(0).toUpperCase()}${color.slice(1)}`,
+ type: 'quiet' as const,
+ color,
+ })),
+]
+
+const meta = {
+ title: 'Buttons/Button',
+ component: Button,
+ argTypes: {
+ type: {
+ control: 'select',
+ options: types,
+ },
+ size: {
+ control: 'select',
+ options: sizes,
+ },
+ color: {
+ control: 'select',
+ options: colors,
+ },
+ nativeType: {
+ control: 'select',
+ options: ['button', 'submit', 'reset'],
+ },
+ disabled: { control: 'boolean' },
+ loading: { control: 'boolean' },
+ },
+ args: {
+ type: 'base',
+ size: 'md',
+ color: 'brand',
+ nativeType: 'button',
+ disabled: false,
+ loading: false,
+ },
+ render: (args) => ({
+ components: { Button, DownloadIcon },
+ setup() {
+ return { args }
+ },
+ template: /*html*/ `
+
+
+ Download
+
+ `,
+ }),
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Playground: Story = {}
+
+export const AllTypes: Story = {
+ render: () => ({
+ components: { Button, DownloadIcon },
+ setup() {
+ return { sizeColumns, typeRows }
+ },
+ template: /*html*/ `
+
+
+
+ {{ size.label }}
+
+
+
+ {{ row.label }}
+
+ Button
+
+
+
+ `,
+ }),
+}
+
+export const Quiet: Story = {
+ render: () => ({
+ components: { Button, DownloadIcon, IconButton, SettingsIcon },
+ template: /*html*/ `
+
+ Quiet
+ Quiet destructive
+
+
+ `,
+ }),
+}
+
+export const Sizes: Story = {
+ render: () => ({
+ components: { Button, DownloadIcon, IconButton },
+ setup() {
+ return { sizes }
+ },
+ template: /*html*/ `
+
+
+ {{ size }}
+
+
+
+ `,
+ }),
+}
+
+export const Colors: Story = {
+ render: () => ({
+ components: { Button },
+ setup() {
+ return { colors }
+ },
+ template: /*html*/ `
+
+
+ {{ color }}
+
+
+ `,
+ }),
+}
+
+export const Content: Story = {
+ render: () => ({
+ components: { Button, DownloadIcon, SettingsIcon },
+ template: /*html*/ `
+
+ Text only
+ Leading icon
+ Trailing icon
+ Full width
+ Continue with a deliberately long translated action label
+
+ `,
+ }),
+}
+
+export const InteractionStates: Story = {
+ render: () => ({
+ components: { Button },
+ template: /*html*/ `
+
+ Enabled
+ Disabled
+ Loading
+ Colored
+ Colored disabled
+ Outlined
+ Quiet
+
+ `,
+ }),
+}
+
+export const LinksAndIconButton: Story = {
+ render: () => ({
+ components: { ButtonLink, ExternalIcon, HeartIcon, IconButton },
+ template: /*html*/ `
+
+ Internal link
+
+ Modrinth
+
+ Disabled link
+
+
+
+
+
+ `,
+ }),
+}
diff --git a/packages/ui/src/stories/buttons/ButtonGroup.stories.ts b/packages/ui/src/stories/buttons/ButtonGroup.stories.ts
new file mode 100644
index 0000000000..3f234148c4
--- /dev/null
+++ b/packages/ui/src/stories/buttons/ButtonGroup.stories.ts
@@ -0,0 +1,82 @@
+import { PlayIcon, SettingsIcon, StopCircleIcon, TrashIcon } from '@modrinth/assets'
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+
+import Button from '../../components/base/buttons/Button.vue'
+import ButtonGroup from '../../components/base/buttons/ButtonGroup.vue'
+import SplitButton from '../../components/base/buttons/SplitButton.vue'
+import type { OverflowMenuOption } from '../../components/base/buttons/types'
+
+const splitOptions: OverflowMenuOption[] = [
+ {
+ id: 'settings',
+ label: 'Server settings',
+ icon: SettingsIcon,
+ action: () => undefined,
+ },
+ { type: 'divider' },
+ {
+ id: 'delete',
+ label: 'Delete server',
+ icon: TrashIcon,
+ tone: 'red',
+ action: () => undefined,
+ },
+]
+
+const meta = {
+ title: 'Buttons/Button Group',
+ component: ButtonGroup,
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Joined: Story = {
+ render: () => ({
+ components: { Button, ButtonGroup },
+ template: /*html*/ `
+
+ Previous
+ Next
+
+ `,
+ }),
+}
+
+export const Split: Story = {
+ render: () => ({
+ components: { PlayIcon, SplitButton },
+ setup() {
+ return { splitOptions }
+ },
+ template: /*html*/ `
+
+ Start server
+
+ `,
+ }),
+}
+
+export const IndependentDisabledStates: Story = {
+ render: () => ({
+ components: { SplitButton, StopCircleIcon },
+ setup() {
+ return { splitOptions }
+ },
+ template: /*html*/ `
+
+
+ Primary disabled
+
+
+ Menu disabled
+
+
+ `,
+ }),
+}
diff --git a/packages/ui/src/stories/buttons/FileButton.stories.ts b/packages/ui/src/stories/buttons/FileButton.stories.ts
new file mode 100644
index 0000000000..2f07b27acc
--- /dev/null
+++ b/packages/ui/src/stories/buttons/FileButton.stories.ts
@@ -0,0 +1,61 @@
+import { UploadIcon } from '@modrinth/assets'
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+
+import FileButton from '../../components/base/buttons/FileButton.vue'
+
+const meta = {
+ title: 'Buttons/File Button',
+ component: FileButton,
+ argTypes: {
+ type: {
+ control: 'select',
+ options: ['base', 'colored', 'outlined', 'quiet'],
+ },
+ size: {
+ control: 'select',
+ options: ['sm', 'md', 'lg', 'xl'],
+ },
+ color: {
+ control: 'select',
+ options: ['brand', 'red', 'orange', 'green', 'blue', 'purple', 'medal_promotion'],
+ },
+ },
+ args: {
+ prompt: 'Select file',
+ type: 'base',
+ size: 'md',
+ multiple: false,
+ disabled: false,
+ },
+ render: (args) => ({
+ components: { FileButton, UploadIcon },
+ setup() {
+ return { args }
+ },
+ template: /*html*/ `
+
+
+
+ `,
+ }),
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Default: Story = {}
+
+export const MultipleImages: Story = {
+ args: {
+ prompt: 'Select images',
+ accept: 'image/*',
+ multiple: true,
+ type: 'colored',
+ },
+}
+
+export const Disabled: Story = {
+ args: {
+ disabled: true,
+ },
+}
diff --git a/packages/ui/src/stories/buttons/TeleportOverflowMenu.stories.ts b/packages/ui/src/stories/buttons/TeleportOverflowMenu.stories.ts
new file mode 100644
index 0000000000..22de68e1ea
--- /dev/null
+++ b/packages/ui/src/stories/buttons/TeleportOverflowMenu.stories.ts
@@ -0,0 +1,97 @@
+import {
+ DownloadIcon,
+ ExternalIcon,
+ MoreVerticalIcon,
+ SettingsIcon,
+ TrashIcon,
+} from '@modrinth/assets'
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+
+import TeleportOverflowMenu from '../../components/base/buttons/TeleportOverflowMenu.vue'
+import type { OverflowMenuOption } from '../../components/base/buttons/types'
+
+const options: OverflowMenuOption[] = [
+ {
+ id: 'download',
+ label: 'Download',
+ icon: DownloadIcon,
+ action: () => undefined,
+ },
+ {
+ id: 'settings',
+ label: 'Project settings',
+ icon: SettingsIcon,
+ type: 'link',
+ to: '/settings',
+ },
+ {
+ id: 'website',
+ label: 'Open website',
+ icon: ExternalIcon,
+ type: 'link',
+ href: 'https://modrinth.com',
+ target: '_blank',
+ },
+ {
+ id: 'unavailable',
+ label: 'Unavailable action',
+ disabled: true,
+ tooltip: 'This action is currently unavailable',
+ action: () => undefined,
+ },
+ { type: 'divider' },
+ {
+ id: 'delete',
+ label: 'Delete project',
+ icon: TrashIcon,
+ tone: 'red',
+ action: () => undefined,
+ },
+]
+
+const meta = {
+ title: 'Buttons/Teleport Overflow Menu',
+ component: TeleportOverflowMenu,
+ args: {
+ label: 'More actions',
+ options,
+ type: 'base',
+ size: 'md',
+ placement: 'bottom-end',
+ disabled: false,
+ },
+ render: (args) => ({
+ components: { MoreVerticalIcon, TeleportOverflowMenu },
+ setup() {
+ return { args }
+ },
+ template: /*html*/ `
+
+
+
+ `,
+ }),
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Default: Story = {}
+
+export const ColoredTrigger: Story = {
+ args: {
+ type: 'colored',
+ },
+}
+
+export const OutlinedTrigger: Story = {
+ args: {
+ type: 'outlined',
+ },
+}
+
+export const QuietTrigger: Story = {
+ args: {
+ type: 'quiet',
+ },
+}
diff --git a/packages/ui/src/stories/buttons/TeleportPopoutMenu.stories.ts b/packages/ui/src/stories/buttons/TeleportPopoutMenu.stories.ts
new file mode 100644
index 0000000000..d6b183197c
--- /dev/null
+++ b/packages/ui/src/stories/buttons/TeleportPopoutMenu.stories.ts
@@ -0,0 +1,50 @@
+import { SettingsIcon } from '@modrinth/assets'
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+
+import Button from '../../components/base/buttons/Button.vue'
+import TeleportPopoutMenu from '../../components/base/buttons/TeleportPopoutMenu.vue'
+
+const meta = {
+ title: 'Buttons/Teleport Popout Menu',
+ component: TeleportPopoutMenu,
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const ArbitraryContent: Story = {
+ render: () => ({
+ components: { Button, SettingsIcon, TeleportPopoutMenu },
+ template: /*html*/ `
+
+
+ Configure
+
+
+
+
+
+ Apply
+
+
+
+ `,
+ }),
+}
+
+export const IconTrigger: Story = {
+ render: () => ({
+ components: { SettingsIcon, TeleportPopoutMenu },
+ template: /*html*/ `
+
+
+
+ Arbitrary teleported content can live here.
+
+
+ `,
+ }),
+}
diff --git a/packages/ui/src/stories/instances/ContentCardTable.stories.ts b/packages/ui/src/stories/instances/ContentCardTable.stories.ts
index 486a4c909e..e7a90ebbea 100644
--- a/packages/ui/src/stories/instances/ContentCardTable.stories.ts
+++ b/packages/ui/src/stories/instances/ContentCardTable.stories.ts
@@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { fn } from 'storybook/test'
import { onMounted, onUnmounted, ref } from 'vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button, IconButton } from '../../components/base/buttons'
import ContentCardTable from '../../layouts/shared/content-tab/components/ContentCardTable.vue'
import type { ContentCardTableItem } from '../../layouts/shared/content-tab/types'
@@ -539,7 +539,7 @@ export const InteractiveActions: Story = {
export const WithCustomItemButtons: Story = {
render: () => ({
- components: { ContentCardTable, ButtonStyled, EyeIcon, FolderOpenIcon, DownloadIcon },
+ components: { ContentCardTable, EyeIcon, FolderOpenIcon, DownloadIcon, Button, IconButton },
setup() {
return { items: sampleItems }
},
@@ -551,23 +551,17 @@ export const WithCustomItemButtons: Story = {
@delete="(id) => console.log('Delete', id)"
>
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
`,
@@ -582,15 +576,13 @@ export const WithEmptyState: Story = {
export const WithCustomEmptyState: Story = {
render: () => ({
- components: { ContentCardTable, ButtonStyled },
+ components: { ContentCardTable, Button, IconButton },
template: /*html*/ `
No mods installed
-
- Browse mods
-
+ Browse mods
@@ -781,7 +773,7 @@ export const WithOverflowMenu: Story = {
export const BulkActionsDemo: Story = {
render: () => ({
- components: { ContentCardTable, ButtonStyled },
+ components: { ContentCardTable, Button, IconButton },
setup() {
const items = ref([
{ ...sodiumItem, enabled: true },
@@ -825,15 +817,9 @@ export const BulkActionsDemo: Story = {
{{ selectedIds.length }} selected
-
- Enable
-
-
- Disable
-
-
- Delete
-
+ Enable
+ Disable
+ Delete
export const InstanceDependency: Story = {
render: () => ({
- components: { ButtonStyled, ContentDependencyWarningModal },
+ components: { ContentDependencyWarningModal, Button },
setup() {
const modalRef = ref | null>(null)
const deleted = ref(false)
@@ -186,9 +186,7 @@ export const InstanceDependency: Story = {
},
template: /* html */ `
-
- Delete dependency
-
+
Delete dependency
Dependency deletion confirmed
({
- components: { ButtonStyled, ContentDependencyWarningModal },
+ components: { ContentDependencyWarningModal, Button },
setup() {
const modalRef = ref | null>(null)
const deleted = ref(false)
@@ -227,9 +225,7 @@ export const ServerDependency: Story = {
},
template: /* html */ `
-
- Delete server dependency
-
+
Delete server dependency
Server dependency deletion confirmed
({
- components: { ButtonStyled, ContentDependencyWarningModal },
+ components: { ContentDependencyWarningModal, Button },
setup() {
const modalRef = ref | null>(null)
const deleted = ref(false)
@@ -267,9 +263,7 @@ export const BulkDependencies: Story = {
},
template: /* html */ `
-
- Delete selected dependencies
-
+
Delete selected dependencies
Bulk dependency deletion confirmed
export const ModExample: Story = {
render: (args) => ({
- components: { ContentUpdaterModal, ButtonStyled },
+ components: { ContentUpdaterModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -277,9 +277,7 @@ export const ModExample: Story = {
},
template: /*html*/ `
-
- Update Sodium
-
+
Update Sodium
({
- components: { ContentUpdaterModal, ButtonStyled },
+ components: { ContentUpdaterModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -318,9 +316,7 @@ export const ModpackExample: Story = {
},
template: /*html*/ `
-
- Update Cobblemon Modpack
-
+
Update Cobblemon Modpack
({
- components: { ContentUpdaterModal, ButtonStyled },
+ components: { ContentUpdaterModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -355,9 +351,7 @@ export const WithIncompatibleVersions: Story = {
},
template: /*html*/ `
-
- Update (Shows Incompatible)
-
+
Update (Shows Incompatible)
({
- components: { ContentUpdaterModal, ButtonStyled },
+ components: { ContentUpdaterModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -389,9 +383,7 @@ export const AllVersionTypes: Story = {
},
template: /*html*/ `
-
- View All Version Types
-
+
View All Version Types
export const Default: Story = {
render: () => ({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show(mixedModpackContent)
@@ -417,9 +417,7 @@ export const Default: Story = {
},
template: /*html*/ `
-
- View Modpack Content (Mixed)
-
+
View Modpack Content (Mixed)
({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show(modsOnlyContent)
@@ -440,9 +438,7 @@ export const ModsOnly: Story = {
},
template: /*html*/ `
-
- View Modpack Content (Mods Only)
-
+ View Modpack Content (Mods Only)
`,
@@ -455,7 +451,7 @@ export const ModsOnly: Story = {
export const LoadingState: Story = {
render: () => ({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => {
@@ -469,9 +465,7 @@ export const LoadingState: Story = {
},
template: /*html*/ `
-
- View Content (With Loading)
-
+
View Content (With Loading)
({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show([])
@@ -496,9 +490,7 @@ export const EmptyContent: Story = {
},
template: /*html*/ `
-
- View Empty Modpack
-
+ View Empty Modpack
`,
@@ -511,7 +503,7 @@ export const EmptyContent: Story = {
export const LargeModpack: Story = {
render: () => ({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show(largeModpackContent)
@@ -519,9 +511,7 @@ export const LargeModpack: Story = {
},
template: /*html*/ `
-
- View Large Modpack (47 items)
-
+
View Large Modpack (47 items)
({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show(mixedModpackContent)
@@ -549,9 +539,7 @@ export const SearchDemo: Story = {
Click the button and try searching for "sodium", "shader", or "faithful" to test the search functionality.
-
- Test Search
-
+ Test Search
`,
@@ -564,7 +552,7 @@ export const SearchDemo: Story = {
export const FilterDemo: Story = {
render: () => ({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show(mixedModpackContent)
@@ -575,9 +563,7 @@ export const FilterDemo: Story = {
Click the button and try the filter chips (Mods, Shaders, Resource Packs) to filter content by type.
-
- Test Filters
-
+ Test Filters
`,
@@ -590,7 +576,7 @@ export const FilterDemo: Story = {
export const MixedOwnerTypes: Story = {
render: () => ({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
// Mix of user and organization owners
@@ -608,9 +594,7 @@ export const MixedOwnerTypes: Story = {
Shows content with different owner types: users (circular avatar) and organizations (rounded + icon).
-
- View Mixed Owners
-
+ View Mixed Owners
`,
diff --git a/packages/ui/src/stories/modal/ConfirmLeaveModal.stories.ts b/packages/ui/src/stories/modal/ConfirmLeaveModal.stories.ts
index 9509d27ac1..ac33eb8886 100644
--- a/packages/ui/src/stories/modal/ConfirmLeaveModal.stories.ts
+++ b/packages/ui/src/stories/modal/ConfirmLeaveModal.stories.ts
@@ -1,7 +1,7 @@
import type { StoryObj } from '@storybook/vue3-vite'
import { ref } from 'vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
import ConfirmLeaveModal from '../../components/modal/ConfirmLeaveModal.vue'
const meta = {
@@ -14,7 +14,7 @@ type Story = StoryObj
export const Default: Story = {
render: () => ({
- components: { ConfirmLeaveModal, ButtonStyled },
+ components: { ConfirmLeaveModal, Button },
setup() {
const modalRef = ref | null>(null)
const result = ref('')
@@ -27,9 +27,7 @@ export const Default: Story = {
},
template: /* html */ `
-
- Trigger Leave Confirmation
-
+
Trigger Leave Confirmation
{{ result }}
@@ -39,7 +37,7 @@ export const Default: Story = {
export const CustomMessages: Story = {
render: () => ({
- components: { ConfirmLeaveModal, ButtonStyled },
+ components: { ConfirmLeaveModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.prompt()
@@ -47,9 +45,7 @@ export const CustomMessages: Story = {
},
template: /* html */ `
-
- Discard Draft?
-
+
Discard Draft?
({
- components: { ConfirmLeaveModal, ButtonStyled },
+ components: { ConfirmLeaveModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.prompt()
@@ -73,9 +69,7 @@ export const WarningAdmonition: Story = {
},
template: /* html */ `
-
- Open Warning Variant
-
+
Open Warning Variant
export const Default: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -22,9 +22,7 @@ export const Default: Story = {
},
template: `
-
- Open Modal
-
+
Open Modal
This is the modal content.
You can put any content here.
@@ -36,7 +34,7 @@ export const Default: Story = {
export const WithActions: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -44,19 +42,13 @@ export const WithActions: Story = {
},
template: `
-
- Open Modal with Actions
-
+
Open Modal with Actions
Are you sure you want to proceed with this action?
-
- Cancel
-
-
- Confirm
-
+ Cancel
+ Confirm
@@ -67,7 +59,7 @@ export const WithActions: Story = {
export const DangerFade: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -75,19 +67,13 @@ export const DangerFade: Story = {
},
template: `
-
- Open Danger Modal
-
+
Open Danger Modal
Are you sure you want to delete this item? This action cannot be undone.
-
- Cancel
-
-
- Delete
-
+ Cancel
+ Delete
@@ -98,7 +84,7 @@ export const DangerFade: Story = {
export const WarningFade: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -106,19 +92,13 @@ export const WarningFade: Story = {
},
template: `
-
- Open Warning Modal
-
+
Open Warning Modal
This action may have unintended consequences. Please review before proceeding.
-
- Cancel
-
-
- Proceed
-
+ Cancel
+ Proceed
@@ -129,7 +109,7 @@ export const WarningFade: Story = {
export const Scrollable: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -137,9 +117,7 @@ export const Scrollable: Story = {
},
template: `
-
- Open Scrollable Modal
-
+
Open Scrollable Modal
@@ -148,9 +126,7 @@ export const Scrollable: Story = {
-
- Close
-
+ Close
@@ -161,7 +137,7 @@ export const Scrollable: Story = {
export const MergedHeader: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -169,9 +145,7 @@ export const MergedHeader: Story = {
},
template: `
-
- Open Modal (Merged Header)
-
+
Open Modal (Merged Header)
Custom Header Area
@@ -185,7 +159,7 @@ export const MergedHeader: Story = {
export const NotClosable: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -193,17 +167,13 @@ export const NotClosable: Story = {
},
template: `
-
- Open Non-Closable Modal
-
+
Open Non-Closable Modal
This modal cannot be closed by clicking outside or pressing escape.
Only the action button can close it.
-
- I understand, close
-
+ I understand, close
@@ -214,7 +184,7 @@ export const NotClosable: Story = {
export const NoPadding: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -222,16 +192,12 @@ export const NoPadding: Story = {
},
template: `
-
- Open Modal (No Padding)
-
+
Open Modal (No Padding)
This modal has no default padding on the content area.
-
- Close
-
+ Close
diff --git a/packages/ui/src/stories/modal/ShareModal.stories.ts b/packages/ui/src/stories/modal/ShareModal.stories.ts
index 10b07701f4..28c81af2ae 100644
--- a/packages/ui/src/stories/modal/ShareModal.stories.ts
+++ b/packages/ui/src/stories/modal/ShareModal.stories.ts
@@ -1,7 +1,7 @@
import type { StoryObj } from '@storybook/vue3-vite'
import { ref } from 'vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
import ShareModal from '../../components/modal/ShareModal.vue'
const meta = {
@@ -20,7 +20,7 @@ export const LinkShare: Story = {
link: true,
},
render: (args) => ({
- components: { ShareModal, ButtonStyled },
+ components: { ShareModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => {
@@ -30,9 +30,7 @@ export const LinkShare: Story = {
},
template: `
-
- Open Link Share Modal
-
+ Open Link Share Modal
`,
@@ -47,7 +45,7 @@ export const TextShare: Story = {
link: false,
},
render: (args) => ({
- components: { ShareModal, ButtonStyled },
+ components: { ShareModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => {
@@ -57,9 +55,7 @@ export const TextShare: Story = {
},
template: `
-
- Open Text Share Modal
-
+ Open Text Share Modal
`,
diff --git a/packages/ui/src/stories/modal/TabbedModal.stories.ts b/packages/ui/src/stories/modal/TabbedModal.stories.ts
index aee894f212..5d85e192ef 100644
--- a/packages/ui/src/stories/modal/TabbedModal.stories.ts
+++ b/packages/ui/src/stories/modal/TabbedModal.stories.ts
@@ -14,7 +14,7 @@ import {
import type { StoryObj } from '@storybook/vue3-vite'
import { defineComponent, h, ref } from 'vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
import UnsavedChangesPopup from '../../components/base/UnsavedChangesPopup.vue'
import TabbedModal from '../../components/modal/TabbedModal.vue'
@@ -42,7 +42,7 @@ export default meta
export const Default: StoryObj = {
render: () => ({
- components: { TabbedModal, ButtonStyled },
+ components: { TabbedModal, Button },
setup() {
const modalRef = ref | null>(null)
const tabs = [
@@ -66,9 +66,7 @@ export const Default: StoryObj = {
},
template: /* html */ `
-
- Open Tabbed Modal
-
+ Open Tabbed Modal
`,
@@ -77,7 +75,7 @@ export const Default: StoryObj = {
export const WithTitleSlot: StoryObj = {
render: () => ({
- components: { TabbedModal, ButtonStyled, SettingsIcon },
+ components: { TabbedModal, SettingsIcon, Button },
setup() {
const modalRef = ref | null>(null)
const tabs = [
@@ -96,9 +94,7 @@ export const WithTitleSlot: StoryObj = {
},
template: /* html */ `
-
- Open with Title Slot
-
+ Open with Title Slot