@@ -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 e3ac35edb..6432220b3 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 e7e323906..95b0aab5b 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 a926a64c9..f417104f6 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 88fb10400..bbd9ec21e 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 24aae857d..3feb83679 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 37b4307c4..f775cf3ea 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 619197cf7..87637c7c2 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 dfc6acc0e..eac074cb7 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 4f0df3a8a..21774cc54 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 245907524..0f2a8fba9 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 477f28855..9af125970 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 5024b141a..f7e671b65 100644
--- a/pages/settings.vue
+++ b/pages/settings.vue
@@ -1,65 +1,116 @@
-
-