diff --git a/apps/frontend/src/assets/styles/global.scss b/apps/frontend/src/assets/styles/global.scss
index b0dcdc0ce..b52b738ed 100644
--- a/apps/frontend/src/assets/styles/global.scss
+++ b/apps/frontend/src/assets/styles/global.scss
@@ -162,6 +162,18 @@ html {
--landing-green-label-bg: rgba(0, 216, 69, 0.15);
--landing-raw-bg: #fff;
+
+ --banner-error-bg: #fee2e2;
+ --banner-error-text: #991b1b;
+ --banner-error-border: #ef4444;
+
+ --banner-warning-bg: #ffedd5;
+ --banner-warning-text: #713f12;
+ --banner-warning-border: #f97316;
+
+ --banner-info-bg: #dbeafe;
+ --banner-info-text: #1e3a8a;
+ --banner-info-border: #3b82f6;
}
.dark,
@@ -286,6 +298,18 @@ html {
--hover-filter: brightness(120%);
--active-filter: brightness(140%);
+
+ --banner-error-bg: #4c1515;
+ --banner-error-text: #fee2e2;
+ --banner-error-border: #7f1d1d;
+
+ --banner-warning-bg: #4a2a0a;
+ --banner-warning-text: #ffe6c0;
+ --banner-warning-border: #b54708;
+
+ --banner-info-bg: #1e2a44;
+ --banner-info-text: #dbeafe;
+ --banner-info-border: #2563eb;
}
.oled-mode {
diff --git a/apps/frontend/src/layouts/default.vue b/apps/frontend/src/layouts/default.vue
index 2b5aa7ff3..e33542af0 100644
--- a/apps/frontend/src/layouts/default.vue
+++ b/apps/frontend/src/layouts/default.vue
@@ -27,76 +27,90 @@
-
-
- {{ formatMessage(verifyEmailBannerMessages.title) }}
-
-
+
- {{ formatMessage(subscriptionPaymentFailedBannerMessages.title) }}
-
-
- {{ formatMessage(subscriptionPaymentFailedBannerMessages.action) }}
-
-
-
+
{{ formatMessage(subscriptionPaymentFailedBannerMessages.title) }}
+
+
+ {{ formatMessage(subscriptionPaymentFailedBannerMessages.description) }}
+
+
+
+
+ {{ formatMessage(subscriptionPaymentFailedBannerMessages.action) }}
+
+
+
+
-
-
+
{{ formatMessage(stagingBannerMessages.title) }}
-
-
+
+
{{ formatMessage(stagingBannerMessages.description) }}
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
{{ formatMessage(failedToBuildBannerMessages.title) }}
-
-
+
+
{{
formatMessage(failedToBuildBannerMessages.description, {
errors: generatedStateErrors,
url: config.public.apiBaseUrl,
})
}}
-
-
+
+
@@ -692,7 +706,14 @@ import {
GitHubIcon,
ScaleIcon,
} from "@modrinth/assets";
-import { Button, ButtonStyled, OverflowMenu, Avatar, commonMessages } from "@modrinth/ui";
+import {
+ Button,
+ ButtonStyled,
+ OverflowMenu,
+ PagewideBanner,
+ Avatar,
+ commonMessages,
+} from "@modrinth/ui";
import { isAdmin, isStaff } from "@modrinth/utils";
import { errors as generatedStateErrors } from "~/generated/state.json";
@@ -720,8 +741,13 @@ const basePopoutId = useId();
const verifyEmailBannerMessages = defineMessages({
title: {
- id: "layout.banner.verify-email.title",
- defaultMessage: "For security purposes, please verify your email address on Modrinth.",
+ id: "layout.banner.account-action",
+ defaultMessage: "Account action required",
+ },
+ description: {
+ id: "layout.banner.verify-email.description",
+ defaultMessage:
+ "For security reasons, Modrinth needs you to verify the email address associated with your account.",
},
action: {
id: "layout.banner.verify-email.action",
@@ -731,8 +757,13 @@ const verifyEmailBannerMessages = defineMessages({
const addEmailBannerMessages = defineMessages({
title: {
- id: "layout.banner.add-email.title",
- defaultMessage: "For security purposes, please enter your email on Modrinth.",
+ id: "layout.banner.account-action",
+ defaultMessage: "Account action required",
+ },
+ description: {
+ id: "layout.banner.add-email.description",
+ defaultMessage:
+ "For security reasons, Modrinth needs you to register an email address to your account.",
},
action: {
id: "layout.banner.add-email.button",
@@ -743,8 +774,12 @@ const addEmailBannerMessages = defineMessages({
const subscriptionPaymentFailedBannerMessages = defineMessages({
title: {
id: "layout.banner.subscription-payment-failed.title",
+ defaultMessage: "Billing action required.",
+ },
+ description: {
+ id: "layout.banner.subscription-payment-failed.description",
defaultMessage:
- "Your subscription failed to renew. Please update your payment method to prevent losing access.",
+ "One or more subscriptions failed to renew. Please update your payment method to prevent losing access!",
},
action: {
id: "layout.banner.subscription-payment-failed.button",
@@ -755,7 +790,7 @@ const subscriptionPaymentFailedBannerMessages = defineMessages({
const stagingBannerMessages = defineMessages({
title: {
id: "layout.banner.staging.title",
- defaultMessage: "You’re viewing Modrinth’s staging environment.",
+ defaultMessage: "You’re viewing Modrinth’s staging environment",
},
description: {
id: "layout.banner.staging.description",
@@ -1347,72 +1382,6 @@ const footerLinks = [
}
}
-.email-nag {
- z-index: 6;
- position: relative;
- background-color: var(--color-raised-bg);
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 1rem;
- padding: 0.5rem 1rem;
-}
-
-.site-banner--warning {
- // On some pages, there's gradient backgrounds that seep underneath
- // the banner, so we need to add a solid color underlay.
- background-color: black;
- border-bottom: 2px solid var(--color-red);
- display: grid;
- gap: 0.5rem;
- grid-template: "title actions" "description actions";
- padding-block: var(--gap-xl);
- padding-inline: max(calc((100% - 80rem) / 2 + var(--gap-md)), var(--gap-xl));
- z-index: 4;
- position: relative;
-
- &::before {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: var(--color-red-bg);
- z-index: 5;
- }
-
- .site-banner__title {
- grid-area: title;
- display: flex;
- gap: 0.5rem;
- align-items: center;
- font-weight: bold;
- font-size: var(--font-size-md);
- color: var(--color-contrast);
-
- svg {
- color: var(--color-red);
- width: 1.5rem;
- height: 1.5rem;
- flex-shrink: 0;
- }
- }
-
- .site-banner__description {
- grid-area: description;
- }
-
- .site-banner__actions {
- grid-area: actions;
- }
-
- a {
- color: var(--color-red);
- }
-}
-
@media (max-width: 1200px) {
.app-btn {
display: none;
diff --git a/apps/frontend/src/locales/en-US/index.json b/apps/frontend/src/locales/en-US/index.json
index 4e3662765..5e1ecbe68 100644
--- a/apps/frontend/src/locales/en-US/index.json
+++ b/apps/frontend/src/locales/en-US/index.json
@@ -344,35 +344,38 @@
"layout.avatar.alt": {
"message": "Your avatar"
},
+ "layout.banner.account-action": {
+ "message": "Account action required"
+ },
"layout.banner.add-email.button": {
"message": "Visit account settings"
},
- "layout.banner.add-email.title": {
- "message": "For security purposes, please enter your email on Modrinth."
- },
"layout.banner.build-fail.description": {
"message": "This deploy of Modrinth's frontend failed to generate state from the API. This may be due to an outage or an error in configuration. Rebuild when the API is available. Error codes: {errors}; Current API URL is: {url}"
},
"layout.banner.build-fail.title": {
- "message": "Error generating state from API when building."
+ "message": "Error generating state from API when building"
},
"layout.banner.staging.description": {
"message": "The staging environment is completely separate from the production Modrinth database. This is used for testing and debugging purposes, and may be running in-development versions of the Modrinth backend or frontend newer than the production instance."
},
"layout.banner.staging.title": {
- "message": "You’re viewing Modrinth’s staging environment."
+ "message": "You’re viewing Modrinth’s staging environment"
},
"layout.banner.subscription-payment-failed.button": {
"message": "Update billing info"
},
"layout.banner.subscription-payment-failed.title": {
- "message": "Your subscription failed to renew. Please update your payment method to prevent losing access."
+ "message": "Billing action required"
+ },
+ "layout.banner.subscription-payment-failed.description": {
+ "message": "One or more subscriptions failed to renew. Please update your payment method to prevent losing access!"
},
"layout.banner.verify-email.action": {
"message": "Re-send verification email"
},
- "layout.banner.verify-email.title": {
- "message": "For security purposes, please verify your email address on Modrinth."
+ "layout.banner.verify-email.description": {
+ "message": "For security reasons, Modrinth needs you to verify the email address associated with your account."
},
"layout.footer.about": {
"message": "About"
diff --git a/apps/frontend/tailwind.config.js b/apps/frontend/tailwind.config.ts
similarity index 89%
rename from apps/frontend/tailwind.config.js
rename to apps/frontend/tailwind.config.ts
index 6efbe1fb0..9c9a51676 100644
--- a/apps/frontend/tailwind.config.js
+++ b/apps/frontend/tailwind.config.ts
@@ -1,5 +1,6 @@
-/** @type {import('tailwindcss').Config} */
-const config = {
+import type { Config } from "tailwindcss";
+
+const config: Config = {
content: [
"./src/components/**/*.{js,vue,ts}",
"./src/layouts/**/*.vue",
@@ -36,6 +37,23 @@ const config = {
purple: "var(--color-purple-bg)",
raised: "var(--color-raised-bg)",
},
+ banners: {
+ error: {
+ bg: "var(--banner-error-bg)",
+ text: "var(--banner-error-text)",
+ border: "var(--banner-error-border)",
+ },
+ warning: {
+ bg: "var(--banner-warning-bg)",
+ text: "var(--banner-warning-text)",
+ border: "var(--banner-warning-border)",
+ },
+ info: {
+ bg: "var(--banner-info-bg)",
+ text: "var(--banner-info-text)",
+ border: "var(--banner-info-border)",
+ },
+ },
highlight: {
DEFAULT: "var(--color-brand-highlight)",
red: "var(--color-red-highlight)",
@@ -126,6 +144,7 @@ const config = {
backgroundImage: {
mazeBg: "var(--landing-maze-bg)",
mazeGradientBg: "var(--landing-maze-gradient-bg)",
+ // @ts-ignore
landing: {
mazeOuterBg: "var(--landing-maze-outer-bg)",
colorHeading: "var(--landing-color-heading)",
diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts
index 901b482c6..899a89320 100644
--- a/packages/ui/src/components/index.ts
+++ b/packages/ui/src/components/index.ts
@@ -71,6 +71,7 @@ export { default as Breadcrumbs } from './nav/Breadcrumbs.vue'
export { default as NavItem } from './nav/NavItem.vue'
export { default as NavRow } from './nav/NavRow.vue'
export { default as NavStack } from './nav/NavStack.vue'
+export { default as PagewideBanner } from './nav/PagewideBanner.vue'
// Project
export { default as NewProjectCard } from './project/NewProjectCard.vue'
diff --git a/packages/ui/src/components/nav/PagewideBanner.vue b/packages/ui/src/components/nav/PagewideBanner.vue
new file mode 100644
index 000000000..caafdf1fa
--- /dev/null
+++ b/packages/ui/src/components/nav/PagewideBanner.vue
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+