Add TailwindCSS (#1252)

* Setup TailwindCSS

* Fully setup configuration

* Refactor some tailwind variables
This commit is contained in:
Evan Song
2024-07-06 20:57:32 -07:00
committed by GitHub
parent 0f2ddb452c
commit abec2e48d4
176 changed files with 7905 additions and 7433 deletions

View File

@@ -1,129 +1,132 @@
/* eslint-disable no-undef */
export const useAuth = async (oldToken = null) => {
const auth = useState('auth', () => ({
const auth = useState("auth", () => ({
user: null,
token: '',
token: "",
headers: {},
}))
}));
if (!auth.value.user || oldToken) {
auth.value = await initAuth(oldToken)
auth.value = await initAuth(oldToken);
}
return auth
}
return auth;
};
export const initAuth = async (oldToken = null) => {
const auth = {
user: null,
token: '',
token: "",
};
if (oldToken === "none") {
return auth;
}
if (oldToken === 'none') {
return auth
}
const route = useRoute()
const authCookie = useCookie('auth-token', {
const route = useRoute();
const authCookie = useCookie("auth-token", {
maxAge: 60 * 60 * 24 * 365 * 10,
sameSite: 'lax',
sameSite: "lax",
secure: true,
httpOnly: false,
path: '/',
})
path: "/",
});
if (oldToken) {
authCookie.value = oldToken
authCookie.value = oldToken;
}
if (route.query.code && !route.fullPath.includes('new_account=true')) {
authCookie.value = route.query.code
if (route.query.code && !route.fullPath.includes("new_account=true")) {
authCookie.value = route.query.code;
}
if (authCookie.value) {
auth.token = authCookie.value
auth.token = authCookie.value;
if (!auth.token || !auth.token.startsWith('mra_')) {
return auth
if (!auth.token || !auth.token.startsWith("mra_")) {
return auth;
}
try {
auth.user = await useBaseFetch(
'user',
"user",
{
headers: {
Authorization: auth.token,
},
},
true
)
} catch {}
true,
);
} catch {
/* empty */
}
}
if (!auth.user && auth.token) {
try {
const session = await useBaseFetch(
'session/refresh',
"session/refresh",
{
method: 'POST',
method: "POST",
headers: {
Authorization: auth.token,
},
},
true
)
true,
);
auth.token = session.session
authCookie.value = auth.token
auth.token = session.session;
authCookie.value = auth.token;
auth.user = await useBaseFetch(
'user',
"user",
{
headers: {
Authorization: auth.token,
},
},
true
)
true,
);
} catch {
authCookie.value = null
authCookie.value = null;
}
}
return auth
}
return auth;
};
export const getAuthUrl = (provider, redirect = '') => {
const config = useRuntimeConfig()
const route = useNativeRoute()
export const getAuthUrl = (provider, redirect = "") => {
const config = useRuntimeConfig();
const route = useNativeRoute();
if (redirect === '') {
redirect = route.path
if (redirect === "") {
redirect = route.path;
}
const fullURL = `${config.public.siteUrl}${redirect}`
const fullURL = `${config.public.siteUrl}${redirect}`;
return `${config.public.apiBaseUrl}auth/init?url=${fullURL}&provider=${provider}`
}
return `${config.public.apiBaseUrl}auth/init?url=${fullURL}&provider=${provider}`;
};
export const removeAuthProvider = async (provider) => {
startLoading()
startLoading();
try {
const auth = await useAuth()
const auth = await useAuth();
await useBaseFetch('auth/provider', {
method: 'DELETE',
await useBaseFetch("auth/provider", {
method: "DELETE",
body: {
provider,
},
})
await useAuth(auth.value.token)
});
await useAuth(auth.value.token);
} catch (err) {
const data = useNuxtApp()
const data = useNuxtApp();
data.$notify({
group: 'main',
title: 'An error occurred',
group: "main",
title: "An error occurred",
text: err.data.description,
type: 'error',
})
type: "error",
});
}
stopLoading()
}
stopLoading();
};

View File

@@ -1,573 +1,577 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
export const scopeMessages = defineMessages({
userReadEmailLabel: {
id: 'scopes.userReadEmail.label',
defaultMessage: 'Read user email',
id: "scopes.userReadEmail.label",
defaultMessage: "Read user email",
},
userReadEmailDescription: {
id: 'scopes.userReadEmail.description',
defaultMessage: 'Read your email',
id: "scopes.userReadEmail.description",
defaultMessage: "Read your email",
},
userReadLabel: {
id: 'scopes.userRead.label',
defaultMessage: 'Read user data',
id: "scopes.userRead.label",
defaultMessage: "Read user data",
},
userReadDescription: {
id: 'scopes.userRead.description',
defaultMessage: 'Access your public profile information',
id: "scopes.userRead.description",
defaultMessage: "Access your public profile information",
},
userWriteLabel: {
id: 'scopes.userWrite.label',
defaultMessage: 'Write user data',
id: "scopes.userWrite.label",
defaultMessage: "Write user data",
},
userWriteDescription: {
id: 'scopes.userWrite.description',
defaultMessage: 'Write to your profile',
id: "scopes.userWrite.description",
defaultMessage: "Write to your profile",
},
userDeleteLabel: {
id: 'scopes.userDelete.label',
defaultMessage: 'Delete your account',
id: "scopes.userDelete.label",
defaultMessage: "Delete your account",
},
userDeleteDescription: {
id: 'scopes.userDelete.description',
defaultMessage: 'Delete your account',
id: "scopes.userDelete.description",
defaultMessage: "Delete your account",
},
userAuthWriteLabel: {
id: 'scopes.userAuthWrite.label',
defaultMessage: 'Write auth data',
id: "scopes.userAuthWrite.label",
defaultMessage: "Write auth data",
},
userAuthWriteDescription: {
id: 'scopes.userAuthWrite.description',
defaultMessage: 'Modify your authentication data',
id: "scopes.userAuthWrite.description",
defaultMessage: "Modify your authentication data",
},
notificationReadLabel: {
id: 'scopes.notificationRead.label',
defaultMessage: 'Read notifications',
id: "scopes.notificationRead.label",
defaultMessage: "Read notifications",
},
notificationReadDescription: {
id: 'scopes.notificationRead.description',
defaultMessage: 'Read your notifications',
id: "scopes.notificationRead.description",
defaultMessage: "Read your notifications",
},
notificationWriteLabel: {
id: 'scopes.notificationWrite.label',
defaultMessage: 'Write notifications',
id: "scopes.notificationWrite.label",
defaultMessage: "Write notifications",
},
notificationWriteDescription: {
id: 'scopes.notificationWrite.description',
defaultMessage: 'Delete/View your notifications',
id: "scopes.notificationWrite.description",
defaultMessage: "Delete/View your notifications",
},
payoutsReadLabel: {
id: 'scopes.payoutsRead.label',
defaultMessage: 'Read payouts',
id: "scopes.payoutsRead.label",
defaultMessage: "Read payouts",
},
payoutsReadDescription: {
id: 'scopes.payoutsRead.description',
defaultMessage: 'Read your payouts data',
id: "scopes.payoutsRead.description",
defaultMessage: "Read your payouts data",
},
payoutsWriteLabel: {
id: 'scopes.payoutsWrite.label',
defaultMessage: 'Write payouts',
id: "scopes.payoutsWrite.label",
defaultMessage: "Write payouts",
},
payoutsWriteDescription: {
id: 'scopes.payoutsWrite.description',
defaultMessage: 'Withdraw money',
id: "scopes.payoutsWrite.description",
defaultMessage: "Withdraw money",
},
analyticsLabel: {
id: 'scopes.analytics.label',
defaultMessage: 'Read analytics',
id: "scopes.analytics.label",
defaultMessage: "Read analytics",
},
analyticsDescription: {
id: 'scopes.analytics.description',
defaultMessage: 'Access your analytics data',
id: "scopes.analytics.description",
defaultMessage: "Access your analytics data",
},
projectCreateLabel: {
id: 'scopes.projectCreate.label',
defaultMessage: 'Create projects',
id: "scopes.projectCreate.label",
defaultMessage: "Create projects",
},
projectCreateDescription: {
id: 'scopes.projectCreate.description',
defaultMessage: 'Create new projects',
id: "scopes.projectCreate.description",
defaultMessage: "Create new projects",
},
projectReadLabel: {
id: 'scopes.projectRead.label',
defaultMessage: 'Read projects',
id: "scopes.projectRead.label",
defaultMessage: "Read projects",
},
projectReadDescription: {
id: 'scopes.projectRead.description',
defaultMessage: 'Read all your projects',
id: "scopes.projectRead.description",
defaultMessage: "Read all your projects",
},
projectWriteLabel: {
id: 'scopes.projectWrite.label',
defaultMessage: 'Write projects',
id: "scopes.projectWrite.label",
defaultMessage: "Write projects",
},
projectWriteDescription: {
id: 'scopes.projectWrite.description',
defaultMessage: 'Write to project data',
id: "scopes.projectWrite.description",
defaultMessage: "Write to project data",
},
projectDeleteLabel: {
id: 'scopes.projectDelete.label',
defaultMessage: 'Delete projects',
id: "scopes.projectDelete.label",
defaultMessage: "Delete projects",
},
projectDeleteDescription: {
id: 'scopes.projectDelete.description',
defaultMessage: 'Delete your projects',
id: "scopes.projectDelete.description",
defaultMessage: "Delete your projects",
},
versionCreateLabel: {
id: 'scopes.versionCreate.label',
defaultMessage: 'Create versions',
id: "scopes.versionCreate.label",
defaultMessage: "Create versions",
},
versionCreateDescription: {
id: 'scopes.versionCreate.description',
defaultMessage: 'Create new versions',
id: "scopes.versionCreate.description",
defaultMessage: "Create new versions",
},
versionReadLabel: {
id: 'scopes.versionRead.label',
defaultMessage: 'Read versions',
id: "scopes.versionRead.label",
defaultMessage: "Read versions",
},
versionReadDescription: {
id: 'scopes.versionRead.description',
defaultMessage: 'Read all versions',
id: "scopes.versionRead.description",
defaultMessage: "Read all versions",
},
versionWriteLabel: {
id: 'scopes.versionWrite.label',
defaultMessage: 'Write versions',
id: "scopes.versionWrite.label",
defaultMessage: "Write versions",
},
versionWriteDescription: {
id: 'scopes.versionWrite.description',
defaultMessage: 'Write to version data',
id: "scopes.versionWrite.description",
defaultMessage: "Write to version data",
},
versionDeleteLabel: {
id: 'scopes.versionDelete.label',
defaultMessage: 'Delete versions',
id: "scopes.versionDelete.label",
defaultMessage: "Delete versions",
},
versionDeleteDescription: {
id: 'scopes.versionDelete.description',
defaultMessage: 'Delete a version',
id: "scopes.versionDelete.description",
defaultMessage: "Delete a version",
},
reportCreateLabel: {
id: 'scopes.reportCreate.label',
defaultMessage: 'Create reports',
id: "scopes.reportCreate.label",
defaultMessage: "Create reports",
},
reportCreateDescription: {
id: 'scopes.reportCreate.description',
defaultMessage: 'Create reports',
id: "scopes.reportCreate.description",
defaultMessage: "Create reports",
},
reportReadLabel: {
id: 'scopes.reportRead.label',
defaultMessage: 'Read reports',
id: "scopes.reportRead.label",
defaultMessage: "Read reports",
},
reportReadDescription: {
id: 'scopes.reportRead.description',
defaultMessage: 'Read reports',
id: "scopes.reportRead.description",
defaultMessage: "Read reports",
},
reportWriteLabel: {
id: 'scopes.reportWrite.label',
defaultMessage: 'Write reports',
id: "scopes.reportWrite.label",
defaultMessage: "Write reports",
},
reportWriteDescription: {
id: 'scopes.reportWrite.description',
defaultMessage: 'Edit reports',
id: "scopes.reportWrite.description",
defaultMessage: "Edit reports",
},
reportDeleteLabel: {
id: 'scopes.reportDelete.label',
defaultMessage: 'Delete reports',
id: "scopes.reportDelete.label",
defaultMessage: "Delete reports",
},
reportDeleteDescription: {
id: 'scopes.reportDelete.description',
defaultMessage: 'Delete reports',
id: "scopes.reportDelete.description",
defaultMessage: "Delete reports",
},
threadReadLabel: {
id: 'scopes.threadRead.label',
defaultMessage: 'Read threads',
id: "scopes.threadRead.label",
defaultMessage: "Read threads",
},
threadReadDescription: {
id: 'scopes.threadRead.description',
defaultMessage: 'Read threads',
id: "scopes.threadRead.description",
defaultMessage: "Read threads",
},
threadWriteLabel: {
id: 'scopes.threadWrite.label',
defaultMessage: 'Write threads',
id: "scopes.threadWrite.label",
defaultMessage: "Write threads",
},
threadWriteDescription: {
id: 'scopes.threadWrite.description',
defaultMessage: 'Write to threads',
id: "scopes.threadWrite.description",
defaultMessage: "Write to threads",
},
patCreateLabel: {
id: 'scopes.patCreate.label',
defaultMessage: 'Create PATs',
id: "scopes.patCreate.label",
defaultMessage: "Create PATs",
},
patCreateDescription: {
id: 'scopes.patCreate.description',
defaultMessage: 'Create personal API tokens',
id: "scopes.patCreate.description",
defaultMessage: "Create personal API tokens",
},
patReadLabel: {
id: 'scopes.patRead.label',
defaultMessage: 'Read PATs',
id: "scopes.patRead.label",
defaultMessage: "Read PATs",
},
patReadDescription: {
id: 'scopes.patRead.description',
defaultMessage: 'View created API tokens',
id: "scopes.patRead.description",
defaultMessage: "View created API tokens",
},
patWriteLabel: {
id: 'scopes.patWrite.label',
defaultMessage: 'Write PATs',
id: "scopes.patWrite.label",
defaultMessage: "Write PATs",
},
patWriteDescription: {
id: 'scopes.patWrite.description',
defaultMessage: 'Edit personal API tokens',
id: "scopes.patWrite.description",
defaultMessage: "Edit personal API tokens",
},
patDeleteLabel: {
id: 'scopes.patDelete.label',
defaultMessage: 'Delete PATs',
id: "scopes.patDelete.label",
defaultMessage: "Delete PATs",
},
patDeleteDescription: {
id: 'scopes.patDelete.description',
defaultMessage: 'Delete your personal API tokens',
id: "scopes.patDelete.description",
defaultMessage: "Delete your personal API tokens",
},
sessionReadLabel: {
id: 'scopes.sessionRead.label',
defaultMessage: 'Read sessions',
id: "scopes.sessionRead.label",
defaultMessage: "Read sessions",
},
sessionReadDescription: {
id: 'scopes.sessionRead.description',
defaultMessage: 'Read active sessions',
id: "scopes.sessionRead.description",
defaultMessage: "Read active sessions",
},
sessionDeleteLabel: {
id: 'scopes.sessionDelete.label',
defaultMessage: 'Delete sessions',
id: "scopes.sessionDelete.label",
defaultMessage: "Delete sessions",
},
sessionDeleteDescription: {
id: 'scopes.sessionDelete.description',
defaultMessage: 'Delete sessions',
id: "scopes.sessionDelete.description",
defaultMessage: "Delete sessions",
},
performAnalyticsLabel: {
id: 'scopes.performAnalytics.label',
defaultMessage: 'Perform analytics',
id: "scopes.performAnalytics.label",
defaultMessage: "Perform analytics",
},
performAnalyticsDescription: {
id: 'scopes.performAnalytics.description',
defaultMessage: 'Perform analytics actions',
id: "scopes.performAnalytics.description",
defaultMessage: "Perform analytics actions",
},
collectionCreateLabel: {
id: 'scopes.collectionCreate.label',
defaultMessage: 'Create collections',
id: "scopes.collectionCreate.label",
defaultMessage: "Create collections",
},
collectionCreateDescription: {
id: 'scopes.collectionCreate.description',
defaultMessage: 'Create collections',
id: "scopes.collectionCreate.description",
defaultMessage: "Create collections",
},
collectionReadLabel: {
id: 'scopes.collectionRead.label',
defaultMessage: 'Read collections',
id: "scopes.collectionRead.label",
defaultMessage: "Read collections",
},
collectionReadDescription: {
id: 'scopes.collectionRead.description',
defaultMessage: 'Read collections',
id: "scopes.collectionRead.description",
defaultMessage: "Read collections",
},
collectionWriteLabel: {
id: 'scopes.collectionWrite.label',
defaultMessage: 'Write collections',
id: "scopes.collectionWrite.label",
defaultMessage: "Write collections",
},
collectionWriteDescription: {
id: 'scopes.collectionWrite.description',
defaultMessage: 'Write to collections',
id: "scopes.collectionWrite.description",
defaultMessage: "Write to collections",
},
collectionDeleteLabel: {
id: 'scopes.collectionDelete.label',
defaultMessage: 'Delete collections',
id: "scopes.collectionDelete.label",
defaultMessage: "Delete collections",
},
collectionDeleteDescription: {
id: 'scopes.collectionDelete.description',
defaultMessage: 'Delete collections',
id: "scopes.collectionDelete.description",
defaultMessage: "Delete collections",
},
organizationCreateLabel: {
id: 'scopes.organizationCreate.label',
defaultMessage: 'Create organizations',
id: "scopes.organizationCreate.label",
defaultMessage: "Create organizations",
},
organizationCreateDescription: {
id: 'scopes.organizationCreate.description',
defaultMessage: 'Create organizations',
id: "scopes.organizationCreate.description",
defaultMessage: "Create organizations",
},
organizationReadLabel: {
id: 'scopes.organizationRead.label',
defaultMessage: 'Read organizations',
id: "scopes.organizationRead.label",
defaultMessage: "Read organizations",
},
organizationReadDescription: {
id: 'scopes.organizationRead.description',
defaultMessage: 'Read organizations',
id: "scopes.organizationRead.description",
defaultMessage: "Read organizations",
},
organizationWriteLabel: {
id: 'scopes.organizationWrite.label',
defaultMessage: 'Write organizations',
id: "scopes.organizationWrite.label",
defaultMessage: "Write organizations",
},
organizationWriteDescription: {
id: 'scopes.organizationWrite.description',
defaultMessage: 'Write to organizations',
id: "scopes.organizationWrite.description",
defaultMessage: "Write to organizations",
},
organizationDeleteLabel: {
id: 'scopes.organizationDelete.label',
defaultMessage: 'Delete organizations',
id: "scopes.organizationDelete.label",
defaultMessage: "Delete organizations",
},
organizationDeleteDescription: {
id: 'scopes.organizationDelete.description',
defaultMessage: 'Delete organizations',
id: "scopes.organizationDelete.description",
defaultMessage: "Delete organizations",
},
sessionAccessLabel: {
id: 'scopes.sessionAccess.label',
defaultMessage: 'Access sessions',
id: "scopes.sessionAccess.label",
defaultMessage: "Access sessions",
},
sessionAccessDescription: {
id: 'scopes.sessionAccess.description',
defaultMessage: 'Access modrinth-issued sessions',
id: "scopes.sessionAccess.description",
defaultMessage: "Access modrinth-issued sessions",
},
})
});
const scopeDefinitions = [
{
id: 'USER_READ_EMAIL',
id: "USER_READ_EMAIL",
value: BigInt(1) << BigInt(0),
label: scopeMessages.userReadEmailLabel,
desc: scopeMessages.userReadEmailDescription,
},
{
id: 'USER_READ',
id: "USER_READ",
value: BigInt(1) << BigInt(1),
label: scopeMessages.userReadLabel,
desc: scopeMessages.userReadDescription,
},
{
id: 'USER_WRITE',
id: "USER_WRITE",
value: BigInt(1) << BigInt(2),
label: scopeMessages.userWriteLabel,
desc: scopeMessages.userWriteDescription,
},
{
id: 'USER_DELETE',
id: "USER_DELETE",
value: BigInt(1) << BigInt(3),
label: scopeMessages.userDeleteLabel,
desc: scopeMessages.userDeleteDescription,
},
{
id: 'USER_AUTH_WRITE',
id: "USER_AUTH_WRITE",
value: BigInt(1) << BigInt(4),
label: scopeMessages.userAuthWriteLabel,
desc: scopeMessages.userAuthWriteDescription,
},
{
id: 'NOTIFICATION_READ',
id: "NOTIFICATION_READ",
value: BigInt(1) << BigInt(5),
label: scopeMessages.notificationReadLabel,
desc: scopeMessages.notificationReadDescription,
},
{
id: 'NOTIFICATION_WRITE',
id: "NOTIFICATION_WRITE",
value: BigInt(1) << BigInt(6),
label: scopeMessages.notificationWriteLabel,
desc: scopeMessages.notificationWriteDescription,
},
{
id: 'PAYOUTS_READ',
id: "PAYOUTS_READ",
value: BigInt(1) << BigInt(7),
label: scopeMessages.payoutsReadLabel,
desc: scopeMessages.payoutsReadDescription,
},
{
id: 'PAYOUTS_WRITE',
id: "PAYOUTS_WRITE",
value: BigInt(1) << BigInt(8),
label: scopeMessages.payoutsWriteLabel,
desc: scopeMessages.payoutsWriteDescription,
},
{
id: 'ANALYTICS',
id: "ANALYTICS",
value: BigInt(1) << BigInt(9),
label: scopeMessages.analyticsLabel,
desc: scopeMessages.analyticsDescription,
},
{
id: 'PROJECT_CREATE',
id: "PROJECT_CREATE",
value: BigInt(1) << BigInt(10),
label: scopeMessages.projectCreateLabel,
desc: scopeMessages.projectCreateDescription,
},
{
id: 'PROJECT_READ',
id: "PROJECT_READ",
value: BigInt(1) << BigInt(11),
label: scopeMessages.projectReadLabel,
desc: scopeMessages.projectReadDescription,
},
{
id: 'PROJECT_WRITE',
id: "PROJECT_WRITE",
value: BigInt(1) << BigInt(12),
label: scopeMessages.projectWriteLabel,
desc: scopeMessages.projectWriteDescription,
},
{
id: 'PROJECT_DELETE',
id: "PROJECT_DELETE",
value: BigInt(1) << BigInt(13),
label: scopeMessages.projectDeleteLabel,
desc: scopeMessages.projectDeleteDescription,
},
{
id: 'VERSION_CREATE',
id: "VERSION_CREATE",
value: BigInt(1) << BigInt(14),
label: scopeMessages.versionCreateLabel,
desc: scopeMessages.versionCreateDescription,
},
{
id: 'VERSION_READ',
id: "VERSION_READ",
value: BigInt(1) << BigInt(15),
label: scopeMessages.versionReadLabel,
desc: scopeMessages.versionReadDescription,
},
{
id: 'VERSION_WRITE',
id: "VERSION_WRITE",
value: BigInt(1) << BigInt(16),
label: scopeMessages.versionWriteLabel,
desc: scopeMessages.versionWriteDescription,
},
{
id: 'VERSION_DELETE',
id: "VERSION_DELETE",
value: BigInt(1) << BigInt(17),
label: scopeMessages.versionDeleteLabel,
desc: scopeMessages.versionDeleteDescription,
},
{
id: 'REPORT_CREATE',
id: "REPORT_CREATE",
value: BigInt(1) << BigInt(18),
label: scopeMessages.reportCreateLabel,
desc: scopeMessages.reportCreateDescription,
},
{
id: 'REPORT_READ',
id: "REPORT_READ",
value: BigInt(1) << BigInt(19),
label: scopeMessages.reportReadLabel,
desc: scopeMessages.reportReadDescription,
},
{
id: 'REPORT_WRITE',
id: "REPORT_WRITE",
value: BigInt(1) << BigInt(20),
label: scopeMessages.reportWriteLabel,
desc: scopeMessages.reportWriteDescription,
},
{
id: 'REPORT_DELETE',
id: "REPORT_DELETE",
value: BigInt(1) << BigInt(21),
label: scopeMessages.reportDeleteLabel,
desc: scopeMessages.reportDeleteDescription,
},
{
id: 'THREAD_READ',
id: "THREAD_READ",
value: BigInt(1) << BigInt(22),
label: scopeMessages.threadReadLabel,
desc: scopeMessages.threadReadDescription,
},
{
id: 'THREAD_WRITE',
id: "THREAD_WRITE",
value: BigInt(1) << BigInt(23),
label: scopeMessages.threadWriteLabel,
desc: scopeMessages.threadWriteDescription,
},
{
id: 'PAT_CREATE',
id: "PAT_CREATE",
value: BigInt(1) << BigInt(24),
label: scopeMessages.patCreateLabel,
desc: scopeMessages.patCreateDescription,
},
{
id: 'PAT_READ',
id: "PAT_READ",
value: BigInt(1) << BigInt(25),
label: scopeMessages.patReadLabel,
desc: scopeMessages.patReadDescription,
},
{
id: 'PAT_WRITE',
id: "PAT_WRITE",
value: BigInt(1) << BigInt(26),
label: scopeMessages.patWriteLabel,
desc: scopeMessages.patWriteDescription,
},
{
id: 'PAT_DELETE',
id: "PAT_DELETE",
value: BigInt(1) << BigInt(27),
label: scopeMessages.patDeleteLabel,
desc: scopeMessages.patDeleteDescription,
},
{
id: 'SESSION_READ',
id: "SESSION_READ",
value: BigInt(1) << BigInt(28),
label: scopeMessages.sessionReadLabel,
desc: scopeMessages.sessionReadDescription,
},
{
id: 'SESSION_DELETE',
id: "SESSION_DELETE",
value: BigInt(1) << BigInt(29),
label: scopeMessages.sessionDeleteLabel,
desc: scopeMessages.sessionDeleteDescription,
},
{
id: 'PERFORM_ANALYTICS',
id: "PERFORM_ANALYTICS",
value: BigInt(1) << BigInt(30),
label: scopeMessages.performAnalyticsLabel,
desc: scopeMessages.performAnalyticsDescription,
},
{
id: 'COLLECTION_CREATE',
id: "COLLECTION_CREATE",
value: BigInt(1) << BigInt(31),
label: scopeMessages.collectionCreateLabel,
desc: scopeMessages.collectionCreateDescription,
},
{
id: 'COLLECTION_READ',
id: "COLLECTION_READ",
value: BigInt(1) << BigInt(32),
label: scopeMessages.collectionReadLabel,
desc: scopeMessages.collectionReadDescription,
},
{
id: 'COLLECTION_WRITE',
id: "COLLECTION_WRITE",
value: BigInt(1) << BigInt(33),
label: scopeMessages.collectionWriteLabel,
desc: scopeMessages.collectionWriteDescription,
},
{
id: 'COLLECTION_DELETE',
id: "COLLECTION_DELETE",
value: BigInt(1) << BigInt(34),
label: scopeMessages.collectionDeleteLabel,
desc: scopeMessages.collectionDeleteDescription,
},
{
id: 'ORGANIZATION_CREATE',
id: "ORGANIZATION_CREATE",
value: BigInt(1) << BigInt(35),
label: scopeMessages.organizationCreateLabel,
desc: scopeMessages.organizationCreateDescription,
},
{
id: 'ORGANIZATION_READ',
id: "ORGANIZATION_READ",
value: BigInt(1) << BigInt(36),
label: scopeMessages.organizationReadLabel,
desc: scopeMessages.organizationReadDescription,
},
{
id: 'ORGANIZATION_WRITE',
id: "ORGANIZATION_WRITE",
value: BigInt(1) << BigInt(37),
label: scopeMessages.organizationWriteLabel,
desc: scopeMessages.organizationWriteDescription,
},
{
id: 'ORGANIZATION_DELETE',
id: "ORGANIZATION_DELETE",
value: BigInt(1) << BigInt(38),
label: scopeMessages.organizationDeleteLabel,
desc: scopeMessages.organizationDeleteDescription,
},
{
id: 'SESSION_ACCESS',
id: "SESSION_ACCESS",
value: BigInt(1) << BigInt(39),
label: scopeMessages.sessionAccessLabel,
desc: scopeMessages.sessionAccessDescription,
},
]
];
const Scopes = scopeDefinitions.reduce((acc, scope) => {
acc[scope.id] = scope.value
return acc
}, {} as Record<string, bigint>)
const Scopes = scopeDefinitions.reduce(
(acc, scope) => {
acc[scope.id] = scope.value;
return acc;
},
{} as Record<string, bigint>,
);
export const restrictedScopes = [
Scopes.PAT_READ,
@@ -580,18 +584,18 @@ export const restrictedScopes = [
Scopes.USER_AUTH_WRITE,
Scopes.USER_DELETE,
Scopes.PERFORM_ANALYTICS,
]
];
export const scopeList = Object.entries(Scopes)
.filter(([_, value]) => !restrictedScopes.includes(value))
.map(([key, _]) => key)
.map(([key, _]) => key);
export const getScopeValue = (scope: string) => {
return Scopes[scope]
}
return Scopes[scope];
};
export const encodeScopes = (scopes: string[]) => {
let scopeFlag = BigInt(0)
let scopeFlag = BigInt(0);
// We iterate over the provided scopes
for (const scope of scopes) {
@@ -599,77 +603,77 @@ export const encodeScopes = (scopes: string[]) => {
for (const [scopeName, scopeFlagValue] of Object.entries(Scopes)) {
// If the scope name is the same as the provided scope, add the scope flag to the scopeFlag variable
if (scopeName === scope) {
scopeFlag = scopeFlag | scopeFlagValue
scopeFlag = scopeFlag | scopeFlagValue;
}
}
}
return scopeFlag
}
return scopeFlag;
};
export const decodeScopes = (scopes: bigint | number) => {
if (typeof scopes === 'number') {
scopes = BigInt(scopes)
if (typeof scopes === "number") {
scopes = BigInt(scopes);
}
const authorizedScopes = []
const authorizedScopes = [];
// We iterate over the entries of the Scopes object
for (const [scopeName, scopeFlag] of Object.entries(Scopes)) {
// If the scope flag is present in the provided number, add the scope name to the list
if ((scopes & scopeFlag) === scopeFlag) {
authorizedScopes.push(scopeName)
authorizedScopes.push(scopeName);
}
}
return authorizedScopes
}
return authorizedScopes;
};
export const hasScope = (scopes: bigint, scope: string) => {
const authorizedScopes = decodeScopes(scopes)
return authorizedScopes.includes(scope)
}
const authorizedScopes = decodeScopes(scopes);
return authorizedScopes.includes(scope);
};
export const toggleScope = (scopes: bigint, scope: string) => {
const authorizedScopes = decodeScopes(scopes)
const authorizedScopes = decodeScopes(scopes);
if (authorizedScopes.includes(scope)) {
return encodeScopes(authorizedScopes.filter((authorizedScope) => authorizedScope !== scope))
return encodeScopes(authorizedScopes.filter((authorizedScope) => authorizedScope !== scope));
} else {
return encodeScopes([...authorizedScopes, scope])
return encodeScopes([...authorizedScopes, scope]);
}
}
};
export const useScopes = () => {
const { formatMessage } = useVIntl()
const { formatMessage } = useVIntl();
const scopesToDefinitions = (scopes: bigint) => {
const authorizedScopes = decodeScopes(scopes)
const authorizedScopes = decodeScopes(scopes);
return authorizedScopes.map((scope) => {
const scopeDefinition = scopeDefinitions.find(
(scopeDefinition) => scopeDefinition.id === scope
)
(scopeDefinition) => scopeDefinition.id === scope,
);
if (!scopeDefinition) {
throw new Error(`Scope ${scope} not found`)
throw new Error(`Scope ${scope} not found`);
}
return formatMessage(scopeDefinition.desc)
})
}
return formatMessage(scopeDefinition.desc);
});
};
const scopesToLabels = (scopes: bigint) => {
const authorizedScopes = decodeScopes(scopes)
const authorizedScopes = decodeScopes(scopes);
return authorizedScopes.map((scope) => {
const scopeDefinition = scopeDefinitions.find(
(scopeDefinition) => scopeDefinition.id === scope
)
(scopeDefinition) => scopeDefinition.id === scope,
);
if (!scopeDefinition) {
throw new Error(`Scope ${scope} not found`)
throw new Error(`Scope ${scope} not found`);
}
return formatMessage(scopeDefinition.label)
})
}
return formatMessage(scopeDefinition.label);
});
};
return {
scopesToDefinitions,
scopesToLabels,
}
}
};
};

View File

@@ -1,6 +1,6 @@
export type AutoRef<T> = [T] extends [(...args: any[]) => any]
? Ref<T> | (() => T)
: T | Ref<T> | (() => T)
: T | Ref<T> | (() => T);
/**
* Accepts a value directly, a ref with the value or a getter function and returns a Vue ref.
@@ -8,6 +8,6 @@ export type AutoRef<T> = [T] extends [(...args: any[]) => any]
* @returns Either the original or newly created ref.
*/
export function useAutoRef<T>(value: AutoRef<T>): Ref<T> {
if (typeof value === 'function') return computed(() => value())
return isRef(value) ? value : ref(value as any)
if (typeof value === "function") return computed(() => value());
return isRef(value) ? value : ref(value as any);
}

View File

@@ -1,18 +1,18 @@
import { createFormatter, type Formatter } from '@vintl/compact-number'
import type { IntlController } from '@vintl/vintl/controller'
import { createFormatter, type Formatter } from "@vintl/compact-number";
import type { IntlController } from "@vintl/vintl/controller";
const formatters = new WeakMap<IntlController<any>, Formatter>()
const formatters = new WeakMap<IntlController<any>, Formatter>();
export function useCompactNumber(): Formatter {
const vintl = useVIntl()
const vintl = useVIntl();
let formatter = formatters.get(vintl)
let formatter = formatters.get(vintl);
if (formatter == null) {
const formatterRef = computed(() => createFormatter(vintl.intl))
formatter = (value, options) => formatterRef.value(value, options)
formatters.set(vintl, formatter)
const formatterRef = computed(() => createFormatter(vintl.intl));
formatter = (value, options) => formatterRef.value(value, options);
formatters.set(vintl, formatter);
}
return formatter
return formatter;
}

View File

@@ -1,12 +1,13 @@
/* eslint-disable no-undef */
export const useCosmetics = () =>
useState('cosmetics', () => {
const cosmetics = useCookie('cosmetics', {
useState("cosmetics", () => {
const cosmetics = useCookie("cosmetics", {
maxAge: 60 * 60 * 24 * 365 * 10,
sameSite: 'lax',
sameSite: "lax",
secure: true,
httpOnly: false,
path: '/',
})
path: "/",
});
if (!cosmetics.value) {
cosmetics.value = {
@@ -16,37 +17,37 @@ export const useCosmetics = () =>
externalLinksNewTab: true,
notUsingBlockers: false,
hideModrinthAppPromos: false,
preferredDarkTheme: 'dark',
preferredDarkTheme: "dark",
searchDisplayMode: {
mod: 'list',
plugin: 'list',
resourcepack: 'gallery',
modpack: 'list',
shader: 'gallery',
datapack: 'list',
user: 'list',
collection: 'list',
mod: "list",
plugin: "list",
resourcepack: "gallery",
modpack: "list",
shader: "gallery",
datapack: "list",
user: "list",
collection: "list",
},
hideStagingBanner: false,
}
};
}
return cosmetics.value
})
return cosmetics.value;
});
export const saveCosmetics = () => {
const cosmetics = useCosmetics()
const cosmetics = useCosmetics();
console.log('SAVING COSMETICS:')
console.log(cosmetics)
console.log("SAVING COSMETICS:");
console.log(cosmetics);
const cosmeticsCookie = useCookie('cosmetics', {
const cosmeticsCookie = useCookie("cosmetics", {
maxAge: 60 * 60 * 24 * 365 * 10,
sameSite: 'lax',
sameSite: "lax",
secure: true,
httpOnly: false,
path: '/',
})
path: "/",
});
cosmeticsCookie.value = cosmetics.value
}
cosmeticsCookie.value = cosmetics.value;
};

View File

@@ -1,17 +1,18 @@
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
/* eslint-disable no-undef */
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
dayjs.extend(relativeTime)
dayjs.extend(relativeTime);
export const useCurrentDate = () => useState('currentDate', () => Date.now())
export const useCurrentDate = () => useState("currentDate", () => Date.now());
export const updateCurrentDate = () => {
const currentDate = useCurrentDate()
const currentDate = useCurrentDate();
currentDate.value = Date.now()
}
currentDate.value = Date.now();
};
export const fromNow = (date) => {
const currentDate = useCurrentDate()
return dayjs(date).from(currentDate.value)
}
const currentDate = useCurrentDate();
return dayjs(date).from(currentDate.value);
};

View File

@@ -1,91 +1,91 @@
import { useAutoRef, type AutoRef } from './auto-ref.ts'
import { useAutoRef, type AutoRef } from "./auto-ref.ts";
const safeTags = new Map<string, string>()
const safeTags = new Map<string, string>();
function safeTagFor(locale: string) {
let safeTag = safeTags.get(locale)
let safeTag = safeTags.get(locale);
if (safeTag == null) {
safeTag = new Intl.Locale(locale).baseName
safeTags.set(locale, safeTag)
safeTag = new Intl.Locale(locale).baseName;
safeTags.set(locale, safeTag);
}
return safeTag
return safeTag;
}
type DisplayNamesWrapper = Intl.DisplayNames & {
of(tag: string): string | undefined
}
of(tag: string): string | undefined;
};
const displayNamesDicts = new Map<string, DisplayNamesWrapper>()
const displayNamesDicts = new Map<string, DisplayNamesWrapper>();
function getWrapperKey(locale: string, options: Intl.DisplayNamesOptions) {
return JSON.stringify({ ...options, locale })
return JSON.stringify({ ...options, locale });
}
export function createDisplayNames(
locale: string,
options: Intl.DisplayNamesOptions = { type: 'language' }
options: Intl.DisplayNamesOptions = { type: "language" },
) {
const wrapperKey = getWrapperKey(locale, options)
let wrapper = displayNamesDicts.get(wrapperKey)
const wrapperKey = getWrapperKey(locale, options);
let wrapper = displayNamesDicts.get(wrapperKey);
if (wrapper == null) {
const dict = new Intl.DisplayNames(locale, options)
const dict = new Intl.DisplayNames(locale, options);
const badTags: string[] = []
const badTags: string[] = [];
wrapper = {
resolvedOptions() {
return dict.resolvedOptions()
return dict.resolvedOptions();
},
of(tag: string) {
let attempt = 0
let attempt = 0;
// eslint-disable-next-line no-labels
lookupLoop: do {
let lookup: string
let lookup: string;
switch (attempt) {
case 0:
lookup = tag
break
lookup = tag;
break;
case 1:
lookup = safeTagFor(tag)
break
lookup = safeTagFor(tag);
break;
default:
// eslint-disable-next-line no-labels
break lookupLoop
break lookupLoop;
}
if (badTags.includes(lookup)) continue
if (badTags.includes(lookup)) continue;
try {
return dict.of(lookup)
return dict.of(lookup);
} catch (err) {
console.warn(
`Failed to get display name for ${lookup} using dictionary for ${
this.resolvedOptions().locale
}`
)
badTags.push(lookup)
continue
}`,
);
badTags.push(lookup);
continue;
}
} while (++attempt < 5)
} while (++attempt < 5);
return undefined
return undefined;
},
}
};
displayNamesDicts.set(wrapperKey, wrapper)
displayNamesDicts.set(wrapperKey, wrapper);
}
return wrapper
return wrapper;
}
export function useDisplayNames(
locale: AutoRef<string>,
options?: AutoRef<Intl.DisplayNamesOptions | undefined>
options?: AutoRef<Intl.DisplayNamesOptions | undefined>,
) {
const $locale = useAutoRef(locale)
const $options = useAutoRef(options)
const $locale = useAutoRef(locale);
const $options = useAutoRef(options);
return computed(() => createDisplayNames($locale.value, $options.value))
return computed(() => createDisplayNames($locale.value, $options.value));
}

View File

@@ -1,20 +1,20 @@
import type { CookieOptions } from '#app'
import type { CookieOptions } from "#app";
export type ProjectDisplayMode = 'list' | 'grid' | 'gallery'
export type DarkColorTheme = 'dark' | 'oled' | 'retro'
export type ProjectDisplayMode = "list" | "grid" | "gallery";
export type DarkColorTheme = "dark" | "oled" | "retro";
export interface NumberFlag {
min: number
max: number
min: number;
max: number;
}
export type BooleanFlag = boolean
export type BooleanFlag = boolean;
export type RadioFlag = ProjectDisplayMode | DarkColorTheme
export type RadioFlag = ProjectDisplayMode | DarkColorTheme;
export type FlagValue = BooleanFlag /* | NumberFlag | RadioFlag */
export type FlagValue = BooleanFlag; /* | NumberFlag | RadioFlag */
const validateValues = <K extends PropertyKey>(flags: Record<K, FlagValue>) => flags
const validateValues = <K extends PropertyKey>(flags: Record<K, FlagValue>) => flags;
export const DEFAULT_FEATURE_FLAGS = validateValues({
// Developer flags
@@ -48,58 +48,58 @@ export const DEFAULT_FEATURE_FLAGS = validateValues({
// dataPackSearchDisplayMode: 'list',
// userProjectDisplayMode: 'list',
// collectionProjectDisplayMode: 'list',
} as const)
} as const);
export type FeatureFlag = keyof typeof DEFAULT_FEATURE_FLAGS
export type FeatureFlag = keyof typeof DEFAULT_FEATURE_FLAGS;
export type AllFeatureFlags = {
[key in FeatureFlag]: (typeof DEFAULT_FEATURE_FLAGS)[key]
}
[key in FeatureFlag]: (typeof DEFAULT_FEATURE_FLAGS)[key];
};
export type PartialFeatureFlags = Partial<AllFeatureFlags>
export type PartialFeatureFlags = Partial<AllFeatureFlags>;
const COOKIE_OPTIONS = {
maxAge: 60 * 60 * 24 * 365 * 10,
sameSite: 'lax',
sameSite: "lax",
secure: true,
httpOnly: false,
path: '/',
} satisfies CookieOptions<PartialFeatureFlags>
path: "/",
} satisfies CookieOptions<PartialFeatureFlags>;
export const useFeatureFlags = () =>
useState<AllFeatureFlags>('featureFlags', () => {
const config = useRuntimeConfig()
useState<AllFeatureFlags>("featureFlags", () => {
const config = useRuntimeConfig();
const savedFlags = useCookie<PartialFeatureFlags>('featureFlags', COOKIE_OPTIONS)
const savedFlags = useCookie<PartialFeatureFlags>("featureFlags", COOKIE_OPTIONS);
if (!savedFlags.value) {
savedFlags.value = {}
savedFlags.value = {};
}
const flags: AllFeatureFlags = JSON.parse(JSON.stringify(DEFAULT_FEATURE_FLAGS))
const flags: AllFeatureFlags = JSON.parse(JSON.stringify(DEFAULT_FEATURE_FLAGS));
const overrides = config.public.featureFlagOverrides as PartialFeatureFlags
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
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
const flag = key as FeatureFlag;
const value = savedFlags.value[flag] as (typeof flags)[FeatureFlag];
flags[flag] = value;
}
}
return flags
})
return flags;
});
export const saveFeatureFlags = () => {
const flags = useFeatureFlags()
const cookie = useCookie<PartialFeatureFlags>('featureFlags', COOKIE_OPTIONS)
cookie.value = flags.value
}
const flags = useFeatureFlags();
const cookie = useCookie<PartialFeatureFlags>("featureFlags", COOKIE_OPTIONS);
cookie.value = flags.value;
};

View File

@@ -1,36 +1,37 @@
/* eslint-disable no-undef */
export const useBaseFetch = async (url, options = {}, skipAuth = false) => {
const config = useRuntimeConfig()
let base = process.server ? config.apiBaseUrl : config.public.apiBaseUrl
const config = useRuntimeConfig();
let base = process.server ? config.apiBaseUrl : config.public.apiBaseUrl;
if (!options.headers) {
options.headers = {}
options.headers = {};
}
if (process.server) {
options.headers['x-ratelimit-key'] = config.rateLimitKey
options.headers["x-ratelimit-key"] = config.rateLimitKey;
}
if (!skipAuth) {
const auth = await useAuth()
const auth = await useAuth();
options.headers.Authorization = auth.value.token
options.headers.Authorization = auth.value.token;
}
if (options.apiVersion || options.internal) {
// Base may end in /vD/ or /vD. We would need to replace the digit with the new version number
// and keep the trailing slash if it exists
const baseVersion = base.match(/\/v\d\//)
const baseVersion = base.match(/\/v\d\//);
const replaceStr = options.internal ? `/_internal/` : `/v${options.apiVersion}/`
const replaceStr = options.internal ? `/_internal/` : `/v${options.apiVersion}/`;
if (baseVersion) {
base = base.replace(baseVersion[0], replaceStr)
base = base.replace(baseVersion[0], replaceStr);
} else {
base = base.replace(/\/v\d$/, replaceStr)
base = base.replace(/\/v\d$/, replaceStr);
}
delete options.apiVersion
delete options.apiVersion;
}
return await $fetch(`${base}${url}`, options)
}
return await $fetch(`${base}${url}`, options);
};

View File

@@ -1,18 +1,18 @@
import { createFormatter, type Formatter } from '@vintl/how-ago'
import type { IntlController } from '@vintl/vintl/controller'
import { createFormatter, type Formatter } from "@vintl/how-ago";
import type { IntlController } from "@vintl/vintl/controller";
const formatters = new WeakMap<IntlController<any>, Formatter>()
const formatters = new WeakMap<IntlController<any>, Formatter>();
export function useRelativeTime(): Formatter {
const vintl = useVIntl()
const vintl = useVIntl();
let formatter = formatters.get(vintl)
let formatter = formatters.get(vintl);
if (formatter == null) {
const formatterRef = computed(() => createFormatter(vintl.intl))
formatter = (value, options) => formatterRef.value(value, options)
formatters.set(vintl, formatter)
const formatterRef = computed(() => createFormatter(vintl.intl));
formatter = (value, options) => formatterRef.value(value, options);
formatters.set(vintl, formatter);
}
return formatter
return formatter;
}

View File

@@ -1,46 +1,46 @@
type ImageUploadContext = {
projectID?: string
context: 'project' | 'version' | 'thread_message' | 'report'
}
projectID?: string;
context: "project" | "version" | "thread_message" | "report";
};
interface ImageUploadResponse {
id: string
url: string
id: string;
url: string;
}
export const useImageUpload = async (file: File, ctx: ImageUploadContext) => {
// Make sure file is of type image/png, image/jpeg, image/gif, or image/webp
if (
!file.type.startsWith('image/') ||
!['png', 'jpeg', 'gif', 'webp'].includes(file.type.split('/')[1])
!file.type.startsWith("image/") ||
!["png", "jpeg", "gif", "webp"].includes(file.type.split("/")[1])
) {
throw new Error('File is not an accepted image type')
throw new Error("File is not an accepted image type");
}
// Make sure file is less than 1MB
if (file.size > 1024 * 1024) {
throw new Error('File is too large')
throw new Error("File is too large");
}
const qs = new URLSearchParams()
if (ctx.projectID) qs.set('project_id', ctx.projectID)
qs.set('context', ctx.context)
qs.set('ext', file.type.split('/')[1])
const url = `image?${qs.toString()}`
const qs = new URLSearchParams();
if (ctx.projectID) qs.set("project_id", ctx.projectID);
qs.set("context", ctx.context);
qs.set("ext", file.type.split("/")[1]);
const url = `image?${qs.toString()}`;
const response = (await useBaseFetch(url, {
method: 'POST',
method: "POST",
body: file,
apiVersion: 3,
})) as ImageUploadResponse
})) as ImageUploadResponse;
// Type check to see if response has a url property and an id property
if (!response?.id || typeof response.id !== 'string') {
throw new Error('Unexpected response from server')
if (!response?.id || typeof response.id !== "string") {
throw new Error("Unexpected response from server");
}
if (!response?.url || typeof response.url !== 'string') {
throw new Error('Unexpected response from server')
if (!response?.url || typeof response.url !== "string") {
throw new Error("Unexpected response from server");
}
return response
}
return response;
};

View File

@@ -1,13 +1,14 @@
export const useLoading = () => useState('loading', () => false)
/* eslint-disable no-undef */
export const useLoading = () => useState("loading", () => false);
export const startLoading = () => {
const loading = useLoading()
const loading = useLoading();
loading.value = true
}
loading.value = true;
};
export const stopLoading = () => {
const loading = useLoading()
const loading = useLoading();
loading.value = false
}
loading.value = false;
};

View File

@@ -1,34 +1,37 @@
export const useNotifications = () => useState('notifications', () => [])
/* eslint-disable no-undef */
export const useNotifications = () => useState("notifications", () => []);
export const addNotification = (notification) => {
const notifications = useNotifications()
const notifications = useNotifications();
const existingNotif = notifications.value.find(
(x) =>
x.text === notification.text && x.title === notification.title && x.type === notification.type
)
x.text === notification.text &&
x.title === notification.title &&
x.type === notification.type,
);
if (existingNotif) {
setNotificationTimer(existingNotif)
setNotificationTimer(existingNotif);
return
return;
}
notification.id = new Date()
notification.id = new Date();
setNotificationTimer(notification)
notifications.value.push(notification)
}
setNotificationTimer(notification);
notifications.value.push(notification);
};
export const setNotificationTimer = (notification) => {
if (!notification) return
if (!notification) return;
const notifications = useNotifications()
const notifications = useNotifications();
if (notification.timer) {
clearTimeout(notification.timer)
clearTimeout(notification.timer);
}
notification.timer = setTimeout(() => {
notifications.value.splice(notifications.value.indexOf(notification), 1)
}, 30000)
}
notifications.value.splice(notifications.value.indexOf(notification), 1);
}, 30000);
};

View File

@@ -1 +1 @@
export { useRoute as useNativeRoute, useRouter as useNativeRouter } from 'vue-router'
export { useRoute as useNativeRoute, useRouter as useNativeRouter } from "vue-router";

View File

@@ -1,7 +1,7 @@
export const getArrayOrString = (x) => {
if (typeof x === 'string' || x instanceof String) {
return [x]
if (typeof x === "string" || x instanceof String) {
return [x];
} else {
return x
return x;
}
}
};

View File

@@ -1,10 +1,11 @@
/* eslint-disable no-undef */
/**
* Extracts the [id] from the route params and returns it as a ref.
*
* @param {string?} key The key of the route param to extract.
* @returns {import('vue').Ref<string | string[] | undefined>}
*/
export const useRouteId = (key = 'id') => {
const route = useNativeRoute()
return route.params?.[key] || undefined
}
export const useRouteId = (key = "id") => {
const route = useNativeRoute();
return route.params?.[key] || undefined;
};

View File

@@ -1,7 +1,8 @@
import tags from '~/generated/state.json'
/* eslint-disable no-undef */
import tags from "~/generated/state.json";
export const useTags = () =>
useState('tags', () => ({
useState("tags", () => ({
categories: tags.categories,
loaders: tags.loaders,
gameVersions: tags.gameVersions,
@@ -9,56 +10,56 @@ export const useTags = () =>
reportTypes: tags.reportTypes,
projectTypes: [
{
actual: 'mod',
id: 'mod',
display: 'mod',
actual: "mod",
id: "mod",
display: "mod",
},
{
actual: 'mod',
id: 'plugin',
display: 'plugin',
actual: "mod",
id: "plugin",
display: "plugin",
},
{
actual: 'mod',
id: 'datapack',
display: 'data pack',
actual: "mod",
id: "datapack",
display: "data pack",
},
{
actual: 'shader',
id: 'shader',
display: 'shader',
actual: "shader",
id: "shader",
display: "shader",
},
{
actual: 'resourcepack',
id: 'resourcepack',
display: 'resource pack',
actual: "resourcepack",
id: "resourcepack",
display: "resource pack",
},
{
actual: 'modpack',
id: 'modpack',
display: 'modpack',
actual: "modpack",
id: "modpack",
display: "modpack",
},
],
loaderData: {
pluginLoaders: ['bukkit', 'spigot', 'paper', 'purpur', 'sponge', 'folia'],
pluginPlatformLoaders: ['bungeecord', 'waterfall', 'velocity'],
pluginLoaders: ["bukkit", "spigot", "paper", "purpur", "sponge", "folia"],
pluginPlatformLoaders: ["bungeecord", "waterfall", "velocity"],
allPluginLoaders: [
'bukkit',
'spigot',
'paper',
'purpur',
'sponge',
'bungeecord',
'waterfall',
'velocity',
'folia',
"bukkit",
"spigot",
"paper",
"purpur",
"sponge",
"bungeecord",
"waterfall",
"velocity",
"folia",
],
dataPackLoaders: ['datapack'],
modLoaders: ['forge', 'fabric', 'quilt', 'liteloader', 'modloader', 'rift', 'neoforge'],
hiddenModLoaders: ['liteloader', 'modloader', 'rift'],
dataPackLoaders: ["datapack"],
modLoaders: ["forge", "fabric", "quilt", "liteloader", "modloader", "rift", "neoforge"],
hiddenModLoaders: ["liteloader", "modloader", "rift"],
},
projectViewModes: ['list', 'grid', 'gallery'],
approvedStatuses: ['approved', 'archived', 'unlisted', 'private'],
rejectedStatuses: ['rejected', 'withheld'],
staffRoles: ['moderator', 'admin'],
}))
projectViewModes: ["list", "grid", "gallery"],
approvedStatuses: ["approved", "archived", "unlisted", "private"],
rejectedStatuses: ["rejected", "withheld"],
staffRoles: ["moderator", "admin"],
}));

View File

@@ -1,58 +1,59 @@
/* eslint-disable no-undef */
export const useTheme = () =>
useState('theme', () => {
const colorMode = useCookie('color-mode', {
useState("theme", () => {
const colorMode = useCookie("color-mode", {
maxAge: 60 * 60 * 24 * 365 * 10,
sameSite: 'lax',
sameSite: "lax",
secure: true,
httpOnly: false,
path: '/',
})
path: "/",
});
if (!colorMode.value) {
colorMode.value = {
value: 'dark',
preference: 'system',
}
value: "dark",
preference: "system",
};
}
if (colorMode.value.preference !== 'system') {
colorMode.value.value = colorMode.value.preference
if (colorMode.value.preference !== "system") {
colorMode.value.value = colorMode.value.preference;
}
return colorMode.value
})
return colorMode.value;
});
export const updateTheme = (value, updatePreference = false) => {
const theme = useTheme()
const cosmetics = useCosmetics()
const theme = useTheme();
const cosmetics = useCosmetics();
const themeCookie = useCookie('color-mode', {
const themeCookie = useCookie("color-mode", {
maxAge: 60 * 60 * 24 * 365 * 10,
sameSite: 'lax',
sameSite: "lax",
secure: true,
httpOnly: false,
path: '/',
})
path: "/",
});
if (value === 'system') {
theme.value.preference = 'system'
if (value === "system") {
theme.value.preference = "system";
const colorSchemeQueryList = window.matchMedia('(prefers-color-scheme: light)')
const colorSchemeQueryList = window.matchMedia("(prefers-color-scheme: light)");
if (colorSchemeQueryList.matches) {
theme.value.value = 'light'
theme.value.value = "light";
} else {
theme.value.value = cosmetics.value.preferredDarkTheme
theme.value.value = cosmetics.value.preferredDarkTheme;
}
} else {
theme.value.value = value
if (updatePreference) theme.value.preference = value
theme.value.value = value;
if (updatePreference) theme.value.preference = value;
}
if (process.client) {
document.documentElement.className = `${theme.value.value}-mode`
document.documentElement.className = `${theme.value.value}-mode`;
}
themeCookie.value = theme.value
}
themeCookie.value = theme.value;
};
export const DARK_THEMES = ['dark', 'oled', 'retro']
export const DARK_THEMES = ["dark", "oled", "retro"];

View File

@@ -1,36 +1,36 @@
type AsyncFunction<TArgs extends any[], TResult> = (...args: TArgs) => Promise<TResult>
type ErrorFunction = (err: any) => void | Promise<void>
type VoidFunction = () => void | Promise<void>
type AsyncFunction<TArgs extends any[], TResult> = (...args: TArgs) => Promise<TResult>;
type ErrorFunction = (err: any) => void | Promise<void>;
type VoidFunction = () => void | Promise<void>;
type useClientTry = <TArgs extends any[], TResult>(
fn: AsyncFunction<TArgs, TResult>,
onFail?: ErrorFunction,
onFinish?: VoidFunction
) => (...args: TArgs) => Promise<TResult | undefined>
onFinish?: VoidFunction,
) => (...args: TArgs) => Promise<TResult | undefined>;
const defaultOnError: ErrorFunction = (error) => {
addNotification({
group: 'main',
title: 'An error occurred',
text: error?.data?.description || error.message || error || 'Unknown error',
type: 'error',
})
}
group: "main",
title: "An error occurred",
text: error?.data?.description || error.message || error || "Unknown error",
type: "error",
});
};
export const useClientTry: useClientTry =
(fn, onFail = defaultOnError, onFinish) =>
async (...args) => {
startLoading()
startLoading();
try {
return await fn(...args)
return await fn(...args);
} catch (err) {
if (onFail) {
await onFail(err)
await onFail(err);
} else {
console.error('[CLIENT TRY ERROR]', err)
console.error("[CLIENT TRY ERROR]", err);
}
} finally {
if (onFinish) await onFinish()
stopLoading()
if (onFinish) await onFinish();
stopLoading();
}
}
};

View File

@@ -1,173 +1,176 @@
/* eslint-disable no-undef */
export const useUser = async (force = false) => {
const user = useState('user', () => {})
const user = useState("user", () => {});
if (!user.value || force || (user.value && Date.now() - user.value.lastUpdated > 300000)) {
user.value = await initUser()
user.value = await initUser();
}
return user
}
return user;
};
export const initUser = async () => {
const auth = (await useAuth()).value
const auth = (await useAuth()).value;
const user = {
notifications: [],
follows: [],
lastUpdated: 0,
}
};
if (auth.user && auth.user.id) {
try {
const [follows, collections] = await Promise.all([
useBaseFetch(`user/${auth.user.id}/follows`),
useBaseFetch(`user/${auth.user.id}/collections`, { apiVersion: 3 }),
])
]);
user.collections = collections
user.follows = follows
user.lastUpdated = Date.now()
user.collections = collections;
user.follows = follows;
user.lastUpdated = Date.now();
} catch (err) {
console.error(err)
console.error(err);
}
}
return user
}
return user;
};
export const initUserCollections = async () => {
const auth = (await useAuth()).value
const user = (await useUser()).value
const auth = (await useAuth()).value;
const user = (await useUser()).value;
if (auth.user && auth.user.id) {
try {
user.collections = await useBaseFetch(`user/${auth.user.id}/collections`, { apiVersion: 3 })
user.collections = await useBaseFetch(`user/${auth.user.id}/collections`, { apiVersion: 3 });
} catch (err) {
console.error(err)
console.error(err);
}
}
}
};
export const initUserFollows = async () => {
const auth = (await useAuth()).value
const user = (await useUser()).value
const auth = (await useAuth()).value;
const user = (await useUser()).value;
if (auth.user && auth.user.id) {
try {
user.follows = await useBaseFetch(`user/${auth.user.id}/follows`)
user.follows = await useBaseFetch(`user/${auth.user.id}/follows`);
} catch (err) {
console.error(err)
console.error(err);
}
}
}
};
export const initUserProjects = async () => {
const auth = (await useAuth()).value
const user = (await useUser()).value
const auth = (await useAuth()).value;
const user = (await useUser()).value;
if (auth.user && auth.user.id) {
try {
user.projects = await useBaseFetch(`user/${auth.user.id}/projects`)
user.projects = await useBaseFetch(`user/${auth.user.id}/projects`);
} catch (err) {
console.error(err)
console.error(err);
}
}
}
};
export const userCollectProject = async (collection, projectId) => {
const user = (await useUser()).value
await initUserCollections()
const user = (await useUser()).value;
await initUserCollections();
const collectionId = collection.id
const collectionId = collection.id;
const latestCollection = user.collections.find((x) => x.id === collectionId)
const latestCollection = user.collections.find((x) => x.id === collectionId);
if (!latestCollection) {
throw new Error('This collection was not found. Has it been deleted?')
throw new Error("This collection was not found. Has it been deleted?");
}
const add = !latestCollection.projects.includes(projectId)
const add = !latestCollection.projects.includes(projectId);
const projects = add
? [...latestCollection.projects, projectId]
: [...latestCollection.projects].filter((x) => x !== projectId)
: [...latestCollection.projects].filter((x) => x !== projectId);
const idx = user.collections.findIndex((x) => x.id === latestCollection.id)
const idx = user.collections.findIndex((x) => x.id === latestCollection.id);
if (idx >= 0) {
user.collections[idx].projects = projects
user.collections[idx].projects = projects;
}
await useBaseFetch(`collection/${collection.id}`, {
method: 'PATCH',
method: "PATCH",
body: {
new_projects: projects,
},
apiVersion: 3,
})
}
});
};
export const userFollowProject = async (project) => {
const user = (await useUser()).value
const user = (await useUser()).value;
user.follows = user.follows.concat(project)
project.followers++
user.follows = user.follows.concat(project);
project.followers++;
setTimeout(() => {
useBaseFetch(`project/${project.id}/follow`, {
method: 'POST',
})
})
}
method: "POST",
});
});
};
export const userUnfollowProject = async (project) => {
const user = (await useUser()).value
const user = (await useUser()).value;
user.follows = user.follows.filter((x) => x.id !== project.id)
project.followers--
user.follows = user.follows.filter((x) => x.id !== project.id);
project.followers--;
setTimeout(() => {
useBaseFetch(`project/${project.id}/follow`, {
method: 'DELETE',
})
})
}
method: "DELETE",
});
});
};
export const resendVerifyEmail = async () => {
const app = useNuxtApp()
const app = useNuxtApp();
startLoading()
startLoading();
try {
await useBaseFetch('auth/email/resend_verify', {
method: 'POST',
})
await useBaseFetch("auth/email/resend_verify", {
method: "POST",
});
const auth = await useAuth()
const auth = await useAuth();
app.$notify({
group: 'main',
title: 'Email sent',
group: "main",
title: "Email sent",
text: `An email with a link to verify your account has been sent to ${auth.value.user.email}.`,
type: 'success',
})
type: "success",
});
} catch (err) {
app.$notify({
group: 'main',
title: 'An error occurred',
group: "main",
title: "An error occurred",
text: err.data.description,
type: 'error',
})
type: "error",
});
}
stopLoading()
}
stopLoading();
};
export const logout = async () => {
startLoading()
const auth = await useAuth()
startLoading();
const auth = await useAuth();
try {
await useBaseFetch(`session/${auth.value.token}`, {
method: 'DELETE',
})
} catch {}
method: "DELETE",
});
} catch {
/* empty */
}
await useAuth('none')
useCookie('auth-token').value = null
await navigateTo('/')
stopLoading()
}
await useAuth("none");
useCookie("auth-token").value = null;
await navigateTo("/");
stopLoading();
};