@@ -82,6 +82,12 @@ export default {
&.disabled {
cursor: not-allowed;
}
+
+ &.checked {
+ outline: 2px solid transparent;
+ outline-offset: 4px;
+ border-radius: 0.25rem;
+ }
}
.checkbox {
diff --git a/components/ui/MessageBanner.vue b/components/ui/MessageBanner.vue
index e3ac35edbd..6432220b32 100644
--- a/components/ui/MessageBanner.vue
+++ b/components/ui/MessageBanner.vue
@@ -24,6 +24,7 @@ const ariaLabelByType = computed(() => `Banner with ${props.messageType} message
border-radius: var(--size-rounded-card);
overflow: hidden;
outline: 2px solid transparent;
+ outline-offset: -2px;
margin-bottom: var(--spacing-card-md);
diff --git a/components/ui/Modal.vue b/components/ui/Modal.vue
index e7e3239066..95b0aab5b8 100644
--- a/components/ui/Modal.vue
+++ b/components/ui/Modal.vue
@@ -119,6 +119,7 @@ export default {
overflow-y: auto;
width: 600px;
pointer-events: auto;
+ outline: 3px solid transparent;
.header {
display: flex;
diff --git a/components/ui/NavRow.vue b/components/ui/NavRow.vue
index a926a64c9e..f417104f60 100644
--- a/components/ui/NavRow.vue
+++ b/components/ui/NavRow.vue
@@ -134,6 +134,12 @@ export default {
&.router-link-exact-active {
color: var(--color-text);
+ &:not(:focus-visible) {
+ outline: 2px solid transparent;
+ outline-offset: 6px;
+ border-radius: 0.25rem;
+ }
+
&::after {
opacity: 1;
}
@@ -157,6 +163,8 @@ export default {
transition: all ease-in-out 0.2s;
border-radius: var(--size-rounded-max);
background-color: var(--color-brand);
+ outline: 2px solid transparent;
+ outline-offset: -2px;
@media (prefers-reduced-motion) {
transition: none !important;
diff --git a/components/ui/NavStack.vue b/components/ui/NavStack.vue
index 88fb10400e..bbd9ec21e8 100644
--- a/components/ui/NavStack.vue
+++ b/components/ui/NavStack.vue
@@ -19,6 +19,10 @@ ul {
list-style-type: none;
margin: 0;
padding: 0;
+
+ > :first-child {
+ margin-top: 0;
+ }
}
li {
diff --git a/components/ui/NavStackItem.vue b/components/ui/NavStackItem.vue
index 24aae857d1..3feb836796 100644
--- a/components/ui/NavStackItem.vue
+++ b/components/ui/NavStackItem.vue
@@ -70,6 +70,7 @@ export default {
box-shadow: none;
padding: 0;
width: 100%;
+ outline: none;
:where(.nav-link) {
--text-color: var(--color-text);
@@ -94,6 +95,9 @@ export default {
}
&.router-link-exact-active {
+ outline: 2px solid transparent;
+ border-radius: 0.25rem;
+
.nav-content {
color: var(--color-button-text-active);
background-color: var(--color-button-bg);
diff --git a/components/ui/Pagination.vue b/components/ui/Pagination.vue
index 37b4307c49..f775cf3ea4 100644
--- a/components/ui/Pagination.vue
+++ b/components/ui/Pagination.vue
@@ -133,6 +133,7 @@ a {
background: var(--color-brand);
color: var(--color-brand-inverted);
cursor: default;
+ outline: 2px solid transparent;
}
&.paginate.disabled {
diff --git a/composables/cosmetics.js b/composables/cosmetics.js
index 619197cf74..87637c7c28 100644
--- a/composables/cosmetics.js
+++ b/composables/cosmetics.js
@@ -17,6 +17,7 @@ export const useCosmetics = () =>
developerMode: false,
notUsingBlockers: false,
hideModrinthAppPromos: false,
+ preferredDarkTheme: 'dark',
searchDisplayMode: {
mod: 'list',
plugin: 'list',
diff --git a/composables/theme.js b/composables/theme.js
index dfc6acc0ef..eac074cb7b 100644
--- a/composables/theme.js
+++ b/composables/theme.js
@@ -24,6 +24,7 @@ export const useTheme = () =>
export const updateTheme = (value, updatePreference = false) => {
const theme = useTheme()
+ const cosmetics = useCosmetics()
const themeCookie = useCookie('color-mode', {
maxAge: 60 * 60 * 24 * 365 * 10,
@@ -40,7 +41,7 @@ export const updateTheme = (value, updatePreference = false) => {
if (colorSchemeQueryList.matches) {
theme.value.value = 'light'
} else {
- theme.value.value = 'dark'
+ theme.value.value = cosmetics.value.preferredDarkTheme
}
} else {
theme.value.value = value
@@ -53,3 +54,5 @@ export const updateTheme = (value, updatePreference = false) => {
themeCookie.value = theme.value
}
+
+export const DARK_THEMES = ['dark', 'oled', 'retro']
diff --git a/layouts/default.vue b/layouts/default.vue
index 4f0df3a8aa..21774cc544 100644
--- a/layouts/default.vue
+++ b/layouts/default.vue
@@ -433,6 +433,7 @@ import ModalCreation from '~/components/ui/ModalCreation.vue'
import Avatar from '~/components/ui/Avatar.vue'
import { getProjectTypeMessage } from '~/utils/i18n-project-type.ts'
import { commonMessages } from '~/utils/common-messages.ts'
+import { DARK_THEMES } from '~/composables/theme.js'
const { formatMessage } = useVIntl()
@@ -724,7 +725,10 @@ function toggleBrowseMenu() {
}
}
function changeTheme() {
- updateTheme(app.$colorMode.value === 'dark' ? 'light' : 'dark', true)
+ updateTheme(
+ DARK_THEMES.includes(app.$colorMode.value) ? 'light' : cosmetics.value.preferredDarkTheme,
+ true
+ )
}
function hideStagingBanner() {
@@ -781,6 +785,15 @@ function hideStagingBanner() {
a {
align-items: center;
display: flex;
+
+ &:not(:focus-visible) {
+ outline: none;
+
+ &.router-link-exact-active {
+ outline: 2px solid transparent;
+ border-radius: 0.25rem;
+ }
+ }
}
.small-logo {
@@ -909,6 +922,7 @@ function hideStagingBanner() {
display: flex;
justify-content: center;
padding: 0;
+ outline: none;
.user-icon {
height: 2rem;
@@ -959,6 +973,7 @@ function hideStagingBanner() {
display: flex;
padding: 0.5rem 0.75rem;
width: 100%;
+ outline: none;
.icon {
margin-right: 0.5rem;
@@ -969,6 +984,7 @@ function hideStagingBanner() {
&.router-link-exact-active {
color: var(--color-button-text-active);
background-color: var(--color-button-bg);
+ outline: 2px solid transparent;
&.primary-color {
color: var(--color-button-text-active);
diff --git a/locales/en-US/index.json b/locales/en-US/index.json
index 2459075245..0f2a8fba92 100644
--- a/locales/en-US/index.json
+++ b/locales/en-US/index.json
@@ -191,6 +191,9 @@
"button.sign-out": {
"message": "Sign out"
},
+ "button.upload-image": {
+ "message": "Upload image"
+ },
"collection.button.delete-icon": {
"message": "Delete icon"
},
@@ -285,7 +288,10 @@
"message": "Grid view"
},
"input.view.list": {
- "message": "List view"
+ "message": "Rows view"
+ },
+ "label.changes-saved": {
+ "message": "Changes saved"
},
"label.collections": {
"message": "Collections"
@@ -779,6 +785,114 @@
"scopes.versionWrite.label": {
"message": "Write versions"
},
+ "settings.account.title": {
+ "message": "Account and security"
+ },
+ "settings.appearance.title": {
+ "message": "Appearance"
+ },
+ "settings.applications.title": {
+ "message": "Your applications"
+ },
+ "settings.authorized-apps.title": {
+ "message": "Authorized apps"
+ },
+ "settings.display.banner.developer-mode.button": {
+ "message": "Deactivate developer mode"
+ },
+ "settings.display.banner.developer-mode.description": {
+ "message": "
Developer mode is active. This will allow you to view the internal IDs of various things throughout Modrinth that may be helpful if you're a developer using the Modrinth API. Click on the Modrinth logo at the bottom of the page 5 times to toggle developer mode."
+ },
+ "settings.display.flags.description": {
+ "message": "Enable or disable certain features on this device."
+ },
+ "settings.display.flags.title": {
+ "message": "Feature flags"
+ },
+ "settings.display.project-list-layouts.datapack": {
+ "message": "Data Packs page"
+ },
+ "settings.display.project-list-layouts.description": {
+ "message": "Select your preferred layout for each page that displays project lists on this device."
+ },
+ "settings.display.project-list-layouts.mod": {
+ "message": "Mods page"
+ },
+ "settings.display.project-list-layouts.modpack": {
+ "message": "Modpacks page"
+ },
+ "settings.display.project-list-layouts.plugin": {
+ "message": "Plugins page"
+ },
+ "settings.display.project-list-layouts.resourcepack": {
+ "message": "Resource Packs page"
+ },
+ "settings.display.project-list-layouts.shader": {
+ "message": "Shaders page"
+ },
+ "settings.display.project-list-layouts.title": {
+ "message": "Project list layouts"
+ },
+ "settings.display.project-list-layouts.user": {
+ "message": "User profile pages"
+ },
+ "settings.display.sidebar.advanced-rendering.description": {
+ "message": "Enables advanced rendering such as blur effects that may cause performance issues without hardware-accelerated rendering."
+ },
+ "settings.display.sidebar.advanced-rendering.title": {
+ "message": "Advanced rendering"
+ },
+ "settings.display.sidebar.external-links-new-tab.description": {
+ "message": "Make links which go outside of Modrinth open in a new tab. No matter this setting, links on the same domain and in Markdown descriptions will open in the same tab, and links on ads and edit pages will open in a new tab."
+ },
+ "settings.display.sidebar.external-links-new-tab.title": {
+ "message": "Open external links in new tab"
+ },
+ "settings.display.sidebar.hide-app-promos.description": {
+ "message": "Hides the \"Get Modrinth App\" buttons from primary navigation. The Modrinth App page can still be found on the landing page or in the footer."
+ },
+ "settings.display.sidebar.hide-app-promos.title": {
+ "message": "Hide Modrinth App promotions"
+ },
+ "settings.display.sidebar.right-aligned-project-sidebar.description": {
+ "message": "Aligns the project details sidebar to the right of the page's content."
+ },
+ "settings.display.sidebar.right-aligned-project-sidebar.title": {
+ "message": "Right-aligned project sidebar"
+ },
+ "settings.display.sidebar.right-aligned-search-sidebar.description": {
+ "message": "Aligns the search filters sidebar to the right of the search results."
+ },
+ "settings.display.sidebar.right-aligned-search-sidebar.title": {
+ "message": "Right-aligned search sidebar"
+ },
+ "settings.display.theme.dark": {
+ "message": "Dark"
+ },
+ "settings.display.theme.description": {
+ "message": "Select your preferred color theme for Modrinth on this device."
+ },
+ "settings.display.theme.light": {
+ "message": "Light"
+ },
+ "settings.display.theme.oled": {
+ "message": "OLED"
+ },
+ "settings.display.theme.preferred-dark-theme": {
+ "message": "Preferred dark theme"
+ },
+ "settings.display.theme.preferred-light-theme": {
+ "message": "Preferred light theme"
+ },
+ "settings.display.theme.retro": {
+ "message": "Retro"
+ },
+ "settings.display.theme.system": {
+ "message": "Sync with system"
+ },
+ "settings.display.theme.title": {
+ "message": "Color theme"
+ },
"settings.language.categories.auto": {
"message": "Automatic"
},
@@ -858,10 +972,7 @@
"message": "Edit personal access token"
},
"settings.pats.title": {
- "message": "PATs"
- },
- "settings.pats.title.long": {
- "message": "Personal Access Tokens"
+ "message": "Personal access tokens"
},
"settings.pats.token.action.edit": {
"message": "Edit token"
@@ -881,6 +992,36 @@
"settings.pats.token.never-used": {
"message": "Never used"
},
+ "settings.profile.bio.description": {
+ "message": "A short description to tell everyone a little bit about you."
+ },
+ "settings.profile.bio.title": {
+ "message": "Bio"
+ },
+ "settings.profile.description": {
+ "message": "Your profile information is publicly viewable on Modrinth and through the
Modrinth API."
+ },
+ "settings.profile.profile-info": {
+ "message": "Profile information"
+ },
+ "settings.profile.profile-picture.reset": {
+ "message": "Reset"
+ },
+ "settings.profile.profile-picture.title": {
+ "message": "Profile picture"
+ },
+ "settings.profile.title": {
+ "message": "Public profile"
+ },
+ "settings.profile.username.description": {
+ "message": "A unique case-insensitive name to identify your profile."
+ },
+ "settings.profile.username.title": {
+ "message": "Username"
+ },
+ "settings.profile.visit-profile": {
+ "message": "Visit your profile"
+ },
"settings.sessions.action.revoke-session": {
"message": "Revoke session"
},
diff --git a/pages/dashboard/projects.vue b/pages/dashboard/projects.vue
index 477f288553..9af125970a 100644
--- a/pages/dashboard/projects.vue
+++ b/pages/dashboard/projects.vue
@@ -502,6 +502,7 @@ export default defineNuxtComponent({
border-radius: var(--size-rounded-sm);
overflow: hidden;
margin-top: var(--spacing-card-md);
+ outline: 1px solid transparent;
.grid-table__row {
display: contents;
diff --git a/pages/settings.vue b/pages/settings.vue
index 5024b141aa..f7e671b656 100644
--- a/pages/settings.vue
+++ b/pages/settings.vue
@@ -1,65 +1,116 @@
-
-