diff --git a/.vscode/settings.json b/.vscode/settings.json
index d4d338f6dc..7522198819 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -29,5 +29,7 @@
},
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer"
- }
+ },
+ "css.lint.unknownAtRules": "ignore",
+ "scss.lint.unknownAtRules": "ignore"
}
diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue
index a4bc69aafc..06e392bf3d 100644
--- a/apps/app-frontend/src/App.vue
+++ b/apps/app-frontend/src/App.vue
@@ -970,13 +970,6 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
@@ -919,6 +920,13 @@ const getPyroCharge = (subscription) => { ) } +const getCancellationDate = (subscription) => { + const charge = getPyroCharge(subscription) + if (!charge) return null + if (charge.status === 'cancelled') return charge.due + return null +} + const getProductSize = (product) => { if (!product || !product.metadata) return 'Unknown' const ramSize = product.metadata.ram diff --git a/packages/ui/.storybook/preview.ts b/packages/ui/.storybook/preview.ts index d775c85df0..9b340008eb 100644 --- a/packages/ui/.storybook/preview.ts +++ b/packages/ui/.storybook/preview.ts @@ -1,15 +1,22 @@ -import '@modrinth/assets/omorphia.scss' import 'floating-vue/dist/style.css' -import '../src/styles/tailwind.css' +import '../../assets/styles/defaults.scss' +// frontend css imports +// import '../../../apps/frontend/src/assets/styles/global.scss' +// import '../../../apps/frontend/src/assets/styles/tailwind.css' +// --- +// app-frontend css imports +import '../../../apps/app-frontend/src/assets/stylesheets/global.scss' import type { Labrinth } from '@modrinth/api-client' import { GenericModrinthClient } from '@modrinth/api-client' import { withThemeByClassName } from '@storybook/addon-themes' import type { Preview } from '@storybook/vue3-vite' import { setup } from '@storybook/vue3-vite' +import { QueryClient, VueQueryPlugin } from '@tanstack/vue-query' import FloatingVue from 'floating-vue' -import { defineComponent, ref } from 'vue' +import { computed, defineComponent, h, ref } from 'vue' import { createI18n } from 'vue-i18n' +import { createMemoryHistory, createRouter } from 'vue-router' import NotificationPanel from '../src/components/nav/NotificationPanel.vue' import PopupNotificationPanel from '../src/components/nav/PopupNotificationPanel.vue' @@ -109,9 +116,68 @@ class StorybookPopupNotificationManager extends AbstractPopupNotificationManager } } +const StorybookLink = defineComponent({ + name: 'StorybookLink', + inheritAttrs: false, + props: { + to: { + type: [String, Object], + default: '', + }, + }, + setup(props, { attrs, slots }) { + const href = computed(() => { + if (typeof props.to === 'string') return props.to || '#' + if (props.to && typeof props.to === 'object' && 'path' in props.to) { + const path = props.to.path + return typeof path === 'string' ? path : '#' + } + return '#' + }) + + return () => + h( + 'a', + { + ...attrs, + href: href.value, + }, + slots.default?.(), + ) + }, +}) + +const StorybookClientOnly = defineComponent({ + name: 'StorybookClientOnly', + setup(_, { slots }) { + return () => slots.default?.() + }, +}) + setup((app) => { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + mutations: { + retry: false, + }, + }, + }) + app.use(VueQueryPlugin, { queryClient }) app.use(i18n) + const router = createRouter({ + history: createMemoryHistory(), + routes: [{ path: '/:pathMatch(.*)*', component: { render: () => null } }], + }) + app.use(router) + + app.component('NuxtLink', StorybookLink) + app.component('RouterLink', StorybookLink) + app.component('ClientOnly', StorybookClientOnly) + // Provide the custom I18nContext for components using injectI18n() const i18nContext: I18nContext = { locale: i18n.global.locale, diff --git a/packages/ui/src/components/base/CopyCode.vue b/packages/ui/src/components/base/CopyCode.vue index f046b5f12c..7e3edb33f6 100644 --- a/packages/ui/src/components/base/CopyCode.vue +++ b/packages/ui/src/components/base/CopyCode.vue @@ -1,5 +1,9 @@ -