* Update Nuxt dependencies * Fix ref access in ChartDisplay * Fix feature flags cookie options type error * Specify type-only imports * Fix shorthands access to tags outside of reactive scope * Replace most useRoute calls with useRoute from vue-router Nuxt's version of this composable is horrendously broken (nuxt/nuxt#21340) * Import all svgs with ?component parameter Fixes weird hydration issues + gives correct type
106 lines
2.9 KiB
TypeScript
106 lines
2.9 KiB
TypeScript
import type { CookieOptions } from '#app'
|
|
|
|
export type ProjectDisplayMode = 'list' | 'grid' | 'gallery'
|
|
export type DarkColorTheme = 'dark' | 'oled' | 'retro'
|
|
|
|
export interface NumberFlag {
|
|
min: number
|
|
max: number
|
|
}
|
|
|
|
export type BooleanFlag = boolean
|
|
|
|
export type RadioFlag = ProjectDisplayMode | DarkColorTheme
|
|
|
|
export type FlagValue = BooleanFlag /* | NumberFlag | RadioFlag */
|
|
|
|
const validateValues = <K extends PropertyKey>(flags: Record<K, FlagValue>) => flags
|
|
|
|
export const DEFAULT_FEATURE_FLAGS = validateValues({
|
|
// Developer flags
|
|
developerMode: false,
|
|
|
|
// In-development features, flags will be removed over time
|
|
newProjectLinks: true,
|
|
newProjectMembers: false,
|
|
newProjectDetails: true,
|
|
projectCompatibility: false,
|
|
removeFeaturedVersions: false,
|
|
|
|
// Alt layouts
|
|
// searchSidebarRight: false,
|
|
// projectSidebarRight: false,
|
|
|
|
// Feature toggles
|
|
// advancedRendering: true,
|
|
// externalLinksNewTab: true,
|
|
// notUsingBlockers: false,
|
|
// hideModrinthAppPromos: false,
|
|
// preferredDarkTheme: 'dark',
|
|
// hideStagingBanner: false,
|
|
|
|
// Project display modes
|
|
// modSearchDisplayMode: 'list',
|
|
// pluginSearchDisplayMode: 'list',
|
|
// resourcePackSearchDisplayMode: 'gallery',
|
|
// modpackSearchDisplayMode: 'list',
|
|
// shaderSearchDisplayMode: 'gallery',
|
|
// dataPackSearchDisplayMode: 'list',
|
|
// userProjectDisplayMode: 'list',
|
|
// collectionProjectDisplayMode: 'list',
|
|
} as const)
|
|
|
|
export type FeatureFlag = keyof typeof DEFAULT_FEATURE_FLAGS
|
|
|
|
export type AllFeatureFlags = {
|
|
[key in FeatureFlag]: (typeof DEFAULT_FEATURE_FLAGS)[key]
|
|
}
|
|
|
|
export type PartialFeatureFlags = Partial<AllFeatureFlags>
|
|
|
|
const COOKIE_OPTIONS = {
|
|
maxAge: 60 * 60 * 24 * 365 * 10,
|
|
sameSite: 'lax',
|
|
secure: true,
|
|
httpOnly: false,
|
|
path: '/',
|
|
} satisfies CookieOptions<PartialFeatureFlags>
|
|
|
|
export const useFeatureFlags = () =>
|
|
useState<AllFeatureFlags>('featureFlags', () => {
|
|
const config = useRuntimeConfig()
|
|
|
|
const savedFlags = useCookie<PartialFeatureFlags>('featureFlags', COOKIE_OPTIONS)
|
|
|
|
if (!savedFlags.value) {
|
|
savedFlags.value = {}
|
|
}
|
|
|
|
const flags: AllFeatureFlags = JSON.parse(JSON.stringify(DEFAULT_FEATURE_FLAGS))
|
|
|
|
const overrides = config.public.featureFlagOverrides as PartialFeatureFlags
|
|
for (const key in overrides) {
|
|
if (key in flags) {
|
|
const flag = key as FeatureFlag
|
|
const value = overrides[flag] as (typeof flags)[FeatureFlag]
|
|
flags[flag] = value
|
|
}
|
|
}
|
|
|
|
for (const key in savedFlags.value) {
|
|
if (key in flags) {
|
|
const flag = key as FeatureFlag
|
|
const value = savedFlags.value[flag] as (typeof flags)[FeatureFlag]
|
|
flags[flag] = value
|
|
}
|
|
}
|
|
|
|
return flags
|
|
})
|
|
|
|
export const saveFeatureFlags = () => {
|
|
const flags = useFeatureFlags()
|
|
const cookie = useCookie<PartialFeatureFlags>('featureFlags', COOKIE_OPTIONS)
|
|
cookie.value = flags.value
|
|
}
|