diff --git a/apps/frontend/src/assets/styles/global.scss b/apps/frontend/src/assets/styles/global.scss
index b0dcdc0c..b52b738e 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 2b5aa7ff..e33542af 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 4e366276..5e1ecbe6 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 6efbe1fb..9c9a5167 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 901b482c..899a8932 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 00000000..caafdf1f
--- /dev/null
+++ b/packages/ui/src/components/nav/PagewideBanner.vue
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+