Add plus theme, settings appearance redesign

This commit is contained in:
Prospector 2024-08-27 21:08:28 -07:00
parent 396f737612
commit e7d096e768
14 changed files with 224 additions and 192 deletions

View File

@ -625,17 +625,17 @@ tr.button-transparent {
.danger-button { .danger-button {
--background-color: var(--color-red); --background-color: var(--color-red);
--text-color: var(--color-brand-inverted); --text-color: var(--color-accent-contrast);
} }
.moderation-button { .moderation-button {
--background-color: var(--color-orange); --background-color: var(--color-orange);
--text-color: var(--color-brand-inverted); --text-color: var(--color-accent-contrast);
} }
.brand-button { .brand-button {
--background-color: var(--color-brand); --background-color: var(--color-brand);
--text-color: var(--color-brand-inverted); --text-color: var(--color-accent-contrast);
} }
.alt-brand-button { .alt-brand-button {
@ -715,7 +715,7 @@ tr.button-transparent {
&:after { &:after {
transform: translatex(20px); transform: translatex(20px);
background: var(--color-brand-inverted); background: var(--color-accent-contrast);
} }
} }

View File

@ -51,9 +51,6 @@ html {
--color-text-inverted: initial !important; --color-text-inverted: initial !important;
--color-bg-inverted: initial !important; --color-bg-inverted: initial !important;
--color-brand: var(--color-green) !important;
--color-brand-inverted: initial !important;
--tab-underline-hovered: initial !important; --tab-underline-hovered: initial !important;
--color-button-text: initial !important; --color-button-text: initial !important;
@ -184,6 +181,8 @@ html {
--color-green-bg: rgba(0, 175, 92, 0.1); --color-green-bg: rgba(0, 175, 92, 0.1);
--color-blue-bg: rgba(31, 104, 192, 0.1); --color-blue-bg: rgba(31, 104, 192, 0.1);
--color-purple-bg: rgba(142, 50, 243, 0.1); --color-purple-bg: rgba(142, 50, 243, 0.1);
--color-purple-highlight: rgba(142, 50, 243, 0.25);
--color-purple-shadow: rgba(142, 50, 243, 0.7);
--color-warning-bg: hsl(355, 70%, 88%); --color-warning-bg: hsl(355, 70%, 88%);
--color-warning-text: hsl(342, 70%, 35%); --color-warning-text: hsl(342, 70%, 35%);
@ -280,6 +279,8 @@ html {
--color-green-bg: rgba(27, 217, 106, 0.2); --color-green-bg: rgba(27, 217, 106, 0.2);
--color-blue-bg: rgba(79, 156, 255, 0.2); --color-blue-bg: rgba(79, 156, 255, 0.2);
--color-purple-bg: rgba(199, 138, 255, 0.2); --color-purple-bg: rgba(199, 138, 255, 0.2);
--color-purple-highlight: rgba(177, 101, 255, 0.25);
--color-purple-shadow: rgba(191, 114, 255, 0.7);
--color-brand: var(--color-green); --color-brand: var(--color-green);
--color-brand-highlight: rgba(27, 217, 106, 0.25); --color-brand-highlight: rgba(27, 217, 106, 0.25);
@ -391,6 +392,11 @@ html {
} }
.oled-mode { .oled-mode {
.experimental-styles-within,
&.experimental-styles-within {
--color-button-bg: #222329;
}
--color-bg: #000000; --color-bg: #000000;
--color-raised-bg: #101013; --color-raised-bg: #101013;
@ -405,6 +411,11 @@ html {
} }
.retro-mode { .retro-mode {
.experimental-styles-within,
&.experimental-styles-within {
--color-button-bg: #3a3b38;
}
--color-bg: #191917; --color-bg: #191917;
--color-raised-bg: #1d1e1b; --color-raised-bg: #1d1e1b;
--color-button-bg: #3a3b38; --color-button-bg: #3a3b38;
@ -426,12 +437,25 @@ html {
--color-purple: rgb(139, 129, 230); --color-purple: rgb(139, 129, 230);
--color-gray: #718096; --color-gray: #718096;
--color-red-highlight: rgba(232, 32, 13, 0.25); --color-red-bg: rgba(232, 32, 13, 0.1);
--color-orange-highlight: rgba(232, 141, 13, 0.25); --color-orange-bg: rgba(232, 141, 13, 0.1);
--color-green-highlight: rgba(60, 219, 54, 0.25); --color-green-bg: rgba(60, 219, 54, 0.1);
--color-blue-highlight: rgba(9, 159, 239, 0.25); --color-blue-bg: rgba(9, 159, 239, 0.1);
--color-purple-bg: rgba(139, 129, 230, 0.1);
--color-purple-highlight: rgba(139, 129, 230, 0.25); --color-purple-highlight: rgba(139, 129, 230, 0.25);
--color-gray-highlight: rgba(113, 128, 150, 0.25); --color-purple-shadow: rgba(139, 129, 230, 0.7);
}
.green-mode {
--color-brand: var(--color-green);
--color-brand-highlight: var(--color-green-highlight);
--color-brand-shadow: var(--color-green-shadow);
}
.purple-mode {
--color-brand: var(--color-purple);
--color-brand-highlight: var(--color-purple-highlight);
--color-brand-shadow: var(--color-purple-shadow);
} }
body { body {

View File

@ -74,20 +74,20 @@
.normal-page { .normal-page {
margin: 0 auto; margin: 0 auto;
max-width: 80rem; max-width: 80rem;
column-gap: 0.75rem; column-gap: 1rem;
grid-template: grid-template:
"sidebar content" auto "sidebar content" auto
"info content" auto "info content" auto
"dummy content" 1fr "dummy content" 1fr
/ 18.75rem 1fr; / 300px 1fr;
&.alt-layout { &.alt-layout {
grid-template: grid-template:
"content sidebar" auto "content sidebar" auto
"content info" auto "content info" auto
"content dummy" 1fr "content dummy" 1fr
/ 1fr 18.75rem; / 1fr 300px;
} }
&.no-sidebar { &.no-sidebar {
@ -106,12 +106,12 @@
} }
.normal-page__sidebar { .normal-page__sidebar {
min-width: 18.75rem; min-width: 300px;
width: 18.75rem; width: 300px;
} }
.normal-page__content { .normal-page__content {
max-width: calc(80rem - 18.75rem - 0.75rem); max-width: calc(80rem - 300px - 1rem);
//overflow-x: hidden; //overflow-x: hidden;
} }
} }
@ -120,8 +120,8 @@
display: grid; display: grid;
margin: 0 auto; margin: 0 auto;
max-width: 80rem; max-width: 80rem;
column-gap: 0.75rem; column-gap: 1rem;
padding: 0 0.75rem; padding: 0 1rem;
grid-template: grid-template:
"header" "header"
@ -135,14 +135,14 @@
"header header" auto "header header" auto
"content sidebar" auto "content sidebar" auto
"content dummy" 1fr "content dummy" 1fr
/ 1fr 18.75rem; / 1fr 300px;
&.alt-layout { &.alt-layout {
grid-template: grid-template:
"header header" auto "header header" auto
"sidebar content" auto "sidebar content" auto
"dummy content" 1fr "dummy content" 1fr
/ 18.75rem 1fr; / 300px 1fr;
} }
} }
@ -158,7 +158,7 @@
.normal-page__content { .normal-page__content {
grid-area: content; grid-area: content;
max-width: calc(80rem - 18.75rem - 0.75rem); max-width: calc(80rem - 300px - 1rem);
//overflow-x: hidden; //overflow-x: hidden;
} }
} }

View File

@ -119,7 +119,7 @@ export default {
} }
svg { svg {
color: var(--color-brand-inverted); color: var(--color-accent-contrast);
stroke-width: 0.2rem; stroke-width: 0.2rem;
height: 0.8rem; height: 0.8rem;
width: 0.8rem; width: 0.8rem;

View File

@ -99,8 +99,8 @@ export default {
border-radius: 0.25rem; border-radius: 0.25rem;
.nav-content { .nav-content {
color: var(--color-button-text-active); color: var(--color-contrast);
background-color: var(--color-button-bg); background-color: var(--color-brand-highlight);
box-shadow: none; box-shadow: none;
} }
} }

View File

@ -28,7 +28,7 @@ function stopTimer(notif) {
.vue-notification { .vue-notification {
background: var(--color-blue) !important; background: var(--color-blue) !important;
border-left: 5px solid var(--color-blue) !important; border-left: 5px solid var(--color-blue) !important;
color: var(--color-brand-inverted) !important; color: var(--color-accent-contrast) !important;
box-sizing: border-box; box-sizing: border-box;
text-align: left; text-align: left;

View File

@ -135,7 +135,7 @@ a {
&.page-number.current { &.page-number.current {
background: var(--color-brand); background: var(--color-brand);
color: var(--color-brand-inverted); color: var(--color-accent-contrast);
cursor: default; cursor: default;
outline: 2px solid transparent; outline: 2px solid transparent;
} }

View File

@ -496,7 +496,7 @@ const submitForReview = async () => {
&.done { &.done {
--background-color: var(--color-green); --background-color: var(--color-green);
--content-color: var(--color-brand-inverted); --content-color: var(--color-accent-contrast);
} }
} }
} }

View File

@ -1,5 +1,13 @@
<template> <template>
<div ref="main_page" class="layout" :class="{ 'expanded-mobile-nav': isBrowseMenuOpen }"> <div
ref="main_page"
class="layout"
:class="{
'expanded-mobile-nav': isBrowseMenuOpen,
'purple-mode':
cosmetics.accentColor === 'purple' && auth.user && isPermission(auth.user.badges, 1 << 0),
}"
>
<div <div
v-if="auth.user && !auth.user.email_verified && route.path !== '/auth/verify-email'" v-if="auth.user && !auth.user.email_verified && route.path !== '/auth/verify-email'"
class="email-nag" class="email-nag"

View File

@ -646,7 +646,7 @@ export default defineNuxtComponent({
.label-button[data-active="true"] { .label-button[data-active="true"] {
--background-color: var(--color-red); --background-color: var(--color-red);
--text-color: var(--color-brand-inverted); --text-color: var(--color-accent-contrast);
} }
.links-modal { .links-modal {

View File

@ -654,7 +654,7 @@ const onBulkEditLinks = useClientTry(async () => {
.label-button[data-active="true"] { .label-button[data-active="true"] {
--background-color: var(--color-red); --background-color: var(--color-red);
--text-color: var(--color-brand-inverted); --text-color: var(--color-accent-contrast);
} }
.links-modal { .links-modal {

View File

@ -1,5 +1,5 @@
<template> <template>
<div> <div class="experimental-styles-within flex flex-col gap-6">
<MessageBanner v-if="flags.developerMode" message-type="warning" class="developer-message"> <MessageBanner v-if="flags.developerMode" message-type="warning" class="developer-message">
<CodeIcon class="inline-flex" /> <CodeIcon class="inline-flex" />
<IntlFormatted :message-id="developerModeBanner.description"> <IntlFormatted :message-id="developerModeBanner.description">
@ -13,14 +13,18 @@
{{ formatMessage(developerModeBanner.deactivate) }} {{ formatMessage(developerModeBanner.deactivate) }}
</Button> </Button>
</MessageBanner> </MessageBanner>
<section class="universal-card"> <div class="flex flex-col gap-4">
<h2 class="text-2xl">{{ formatMessage(colorTheme.title) }}</h2> <div class="flex flex-col gap-1">
<p>{{ formatMessage(colorTheme.description) }}</p> <h2 class="m-0 text-2xl font-extrabold text-contrast">
<div class="theme-options mt-4"> {{ formatMessage(colorTheme.title) }}
</h2>
<p class="m-0">{{ formatMessage(colorTheme.description) }}</p>
</div>
<section class="theme-options">
<button <button
v-for="option in themeOptions" v-for="option in themeOptions"
:key="option" :key="option"
class="preview-radio button-base" class="preview-radio transition-transform hover:brightness-110 active:scale-[0.99] active:brightness-125"
:class="{ selected: theme.preferred === option }" :class="{ selected: theme.preferred === option }"
@click="() => updateColorTheme(option)" @click="() => updateColorTheme(option)"
> >
@ -47,187 +51,153 @@
/> />
</div> </div>
</button> </button>
</section>
</div>
<div v-if="auth.user && isPermission(auth.user.badges, 1 << 0)" class="flex flex-col gap-4">
<div class="flex flex-col gap-1">
<h2 class="m-0 flex items-center gap-2 text-2xl font-extrabold text-contrast">
{{ formatMessage(accentColor.title) }}
<span
class="flex items-center justify-center gap-1 rounded-full bg-bg-purple px-2 py-0.5 text-sm font-bold text-purple"
>
<ModrinthIcon class="h-4 w-auto" />
Modrinth+
</span>
</h2>
<p class="m-0">{{ formatMessage(accentColor.description) }}</p>
</div> </div>
</section> <section class="theme-options">
<section class="universal-card"> <button
<h2 class="text-2xl">{{ formatMessage(projectListLayouts.title) }}</h2> v-for="option in accentOptions"
<p class="mb-4">{{ formatMessage(projectListLayouts.description) }}</p> :key="option"
<div class="project-lists"> class="preview-radio transition-transform hover:brightness-110 active:scale-[0.99] active:brightness-125"
<div v-for="projectType in listTypes" :key="projectType.id + '-project-list-layouts'"> :class="{
selected:
cosmetics.accentColor === option || (!cosmetics.accentColor && option === 'green'),
}"
@click="() => (cosmetics.accentColor = option)"
>
<div class="preview" :class="`${option}-mode`">
<TextLogo class="h-8 w-auto text-contrast" />
</div>
<div class="label"> <div class="label">
<div class="label__title"> <RadioButtonChecked
{{ v-if="
projectListLayouts[projectType.id] cosmetics.accentColor === option || (!cosmetics.accentColor && option === 'green')
? formatMessage(projectListLayouts[projectType.id]) "
: projectType.id class="radio"
}} />
</div> <RadioButtonIcon v-else class="radio" />
{{ accentColor[option] ? formatMessage(accentColor[option]) : option }}
</div> </div>
<div class="project-list-layouts"> </button>
<button </section>
class="preview-radio button-base" </div>
:class="{ selected: cosmetics.searchDisplayMode[projectType.id] === 'list' }" <div class="flex flex-col gap-4">
@click="() => (cosmetics.searchDisplayMode[projectType.id] = 'list')" <div class="flex flex-col gap-1">
> <h2 class="m-0 text-2xl font-extrabold text-contrast">
<div class="preview"> {{ formatMessage(toggleFeatures.title) }}
<div class="layout-list-mode"> </h2>
<div class="example-card card"></div> <p class="m-0">{{ formatMessage(toggleFeatures.description) }}</p>
<div class="example-card card"></div>
<div class="example-card card"></div>
<div class="example-card card"></div>
</div>
</div>
<div class="label">
<RadioButtonChecked
v-if="cosmetics.searchDisplayMode[projectType.id] === 'list'"
class="radio"
/>
<RadioButtonIcon v-else class="radio" />
Rows
</div>
</button>
<button
class="preview-radio button-base"
:class="{ selected: cosmetics.searchDisplayMode[projectType.id] === 'grid' }"
@click="() => (cosmetics.searchDisplayMode[projectType.id] = 'grid')"
>
<div class="preview">
<div class="layout-grid-mode">
<div class="example-card card"></div>
<div class="example-card card"></div>
<div class="example-card card"></div>
<div class="example-card card"></div>
<div class="example-card card"></div>
<div class="example-card card"></div>
</div>
</div>
<div class="label">
<RadioButtonChecked
v-if="cosmetics.searchDisplayMode[projectType.id] === 'grid'"
class="radio"
/>
<RadioButtonIcon v-else class="radio" />
Grid
</div>
</button>
<button
class="preview-radio button-base"
:class="{ selected: cosmetics.searchDisplayMode[projectType.id] === 'gallery' }"
@click="() => (cosmetics.searchDisplayMode[projectType.id] = 'gallery')"
>
<div class="preview">
<div class="layout-gallery-mode">
<div class="example-card card"></div>
<div class="example-card card"></div>
<div class="example-card card"></div>
<div class="example-card card"></div>
</div>
</div>
<div class="label">
<RadioButtonChecked
v-if="cosmetics.searchDisplayMode[projectType.id] === 'gallery'"
class="radio"
/>
<RadioButtonIcon v-else class="radio" />
Gallery
</div>
</button>
</div>
</div>
</div> </div>
</section> <label
<section class="universal-card"> class="!m-0 grid cursor-pointer grid-cols-[1fr_auto] items-center gap-1 rounded-2xl border-2 border-solid border-bg-raised px-6 py-4 transition-transform hover:brightness-110 active:scale-[0.99] active:brightness-125"
<h2 class="text-2xl">{{ formatMessage(toggleFeatures.title) }}</h2> :class="{ 'bg-bg-raised': cosmetics.advancedRendering }"
<p class="mb-4">{{ formatMessage(toggleFeatures.description) }}</p> >
<div class="adjacent-input small"> <span class="col-start-1 font-extrabold text-contrast">
<label for="advanced-rendering"> {{ formatMessage(toggleFeatures.advancedRenderingTitle) }}
<span class="label__title"> </span>
{{ formatMessage(toggleFeatures.advancedRenderingTitle) }} <span class="col-start-1">{{
</span> formatMessage(toggleFeatures.advancedRenderingDescription)
<span class="label__description"> }}</span>
{{ formatMessage(toggleFeatures.advancedRenderingDescription) }}
</span>
</label>
<input <input
id="advanced-rendering" id="advanced-rendering"
v-model="cosmetics.advancedRendering" v-model="cosmetics.advancedRendering"
class="switch stylized-toggle" class="switch stylized-toggle col-start-2 row-span-2 row-start-1"
type="checkbox" type="checkbox"
/> />
</div> </label>
<div class="adjacent-input small"> <label
<label for="external-links-new-tab"> class="!m-0 grid cursor-pointer grid-cols-[1fr_auto] items-center gap-1 rounded-2xl border-2 border-solid border-bg-raised px-6 py-4 transition-transform hover:brightness-110 active:scale-[0.99] active:brightness-125"
<span class="label__title"> :class="{ 'bg-bg-raised': cosmetics.externalLinksNewTab }"
{{ formatMessage(toggleFeatures.externalLinksNewTabTitle) }} >
</span> <span class="col-start-1 font-extrabold text-contrast">
<span class="label__description"> {{ formatMessage(toggleFeatures.externalLinksNewTabTitle) }}
{{ formatMessage(toggleFeatures.externalLinksNewTabDescription) }} </span>
</span> <span class="col-start-1">{{
</label> formatMessage(toggleFeatures.externalLinksNewTabDescription)
}}</span>
<input <input
id="external-links-new-tab"
v-model="cosmetics.externalLinksNewTab" v-model="cosmetics.externalLinksNewTab"
class="switch stylized-toggle" class="switch stylized-toggle col-start-2 row-span-2 row-start-1"
type="checkbox" type="checkbox"
/> />
</div> </label>
<div v-if="false" class="adjacent-input small"> <label
<label for="modrinth-app-promos"> v-if="false"
<span class="label__title"> class="!m-0 grid cursor-pointer grid-cols-[1fr_auto] items-center gap-1 rounded-2xl border-2 border-solid border-bg-raised px-6 py-4 transition-transform hover:brightness-110 active:scale-[0.99] active:brightness-125"
{{ formatMessage(toggleFeatures.hideModrinthAppPromosTitle) }} :class="{ 'bg-bg-raised': cosmetics.hideModrinthAppPromos }"
</span> >
<span class="label__description"> <span class="col-start-1 font-extrabold text-contrast">
{{ formatMessage(toggleFeatures.hideModrinthAppPromosDescription) }} {{ formatMessage(toggleFeatures.hideModrinthAppPromosTitle) }}
</span> </span>
</label> <span class="col-start-1">{{
formatMessage(toggleFeatures.hideModrinthAppPromosDescription)
}}</span>
<input <input
id="modrinth-app-promos"
v-model="cosmetics.hideModrinthAppPromos" v-model="cosmetics.hideModrinthAppPromos"
class="switch stylized-toggle" class="switch stylized-toggle col-start-2 row-span-2 row-start-1"
type="checkbox" type="checkbox"
/> />
</div> </label>
<div class="adjacent-input small"> <label
<label for="search-layout-toggle"> class="!m-0 grid cursor-pointer grid-cols-[1fr_auto] items-center gap-1 rounded-2xl border-2 border-solid border-bg-raised px-6 py-4 transition-transform hover:brightness-110 active:scale-[0.99] active:brightness-125"
<span class="label__title"> :class="{ 'bg-bg-raised': cosmetics.rightSearchLayout }"
{{ formatMessage(toggleFeatures.rightAlignedFiltersSidebarTitle) }} >
</span> <span class="col-start-1 font-extrabold text-contrast">
<span class="label__description"> {{ formatMessage(toggleFeatures.rightAlignedFiltersSidebarTitle) }}
{{ formatMessage(toggleFeatures.rightAlignedFiltersSidebarDescription) }} </span>
</span> <span class="col-start-1">{{
</label> formatMessage(toggleFeatures.rightAlignedFiltersSidebarDescription)
}}</span>
<input <input
id="search-layout-toggle"
v-model="cosmetics.rightSearchLayout" v-model="cosmetics.rightSearchLayout"
class="switch stylized-toggle" class="switch stylized-toggle col-start-2 row-span-2 row-start-1"
type="checkbox" type="checkbox"
/> />
</div> </label>
<div class="adjacent-input small"> <label
<label for="project-layout-toggle"> class="!m-0 grid cursor-pointer grid-cols-[1fr_auto] items-center gap-1 rounded-2xl border-2 border-solid border-bg-raised px-6 py-4 transition-transform hover:brightness-110 active:scale-[0.99] active:brightness-125"
<span class="label__title"> :class="{ 'bg-bg-raised': cosmetics.leftContentLayout }"
{{ formatMessage(toggleFeatures.leftAlignedContentSidebarTitle) }} >
</span> <span class="col-start-1 font-extrabold text-contrast">
<span class="label__description"> {{ formatMessage(toggleFeatures.leftAlignedContentSidebarTitle) }}
{{ formatMessage(toggleFeatures.leftAlignedContentSidebarDescription) }} </span>
</span> <span class="col-start-1">{{
</label> formatMessage(toggleFeatures.leftAlignedContentSidebarDescription)
}}</span>
<input <input
id="project-layout-toggle"
v-model="cosmetics.leftContentLayout" v-model="cosmetics.leftContentLayout"
class="switch stylized-toggle" class="switch stylized-toggle col-start-2 row-span-2 row-start-1"
type="checkbox" type="checkbox"
/> />
</div> </label>
</section> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { CodeIcon, MoonIcon, RadioButtonChecked, RadioButtonIcon, SunIcon } from "@modrinth/assets"; import {
import { Button } from "@modrinth/ui"; ModrinthIcon,
CodeIcon,
MoonIcon,
RadioButtonChecked,
RadioButtonIcon,
SunIcon,
} from "@modrinth/assets";
import { TextLogo, Button } from "@modrinth/ui";
import MessageBanner from "~/components/ui/MessageBanner.vue"; import MessageBanner from "~/components/ui/MessageBanner.vue";
import type { DisplayLocation } from "~/plugins/cosmetics"; import type { AccentColor, DisplayLocation } from "~/plugins/cosmetics";
import { formatProjectType } from "~/plugins/shorthands.js"; import { formatProjectType } from "~/plugins/shorthands.js";
import { isDarkTheme, type Theme } from "~/plugins/theme/index.ts"; import { isDarkTheme, type Theme } from "~/plugins/theme/index.ts";
@ -236,6 +206,7 @@ useHead({
}); });
const { formatMessage } = useVIntl(); const { formatMessage } = useVIntl();
const auth = await useAuth();
const developerModeBanner = defineMessages({ const developerModeBanner = defineMessages({
description: { description: {
@ -288,6 +259,26 @@ const colorTheme = defineMessages({
}, },
}); });
const accentColor = defineMessages({
title: {
id: "settings.display.accent.title",
defaultMessage: "Accent color",
},
description: {
id: "settings.display.accent.description",
defaultMessage:
"Thank you for supporting Modrinth! You can choose to make the Modrinth accent color purple if you'd like.",
},
green: {
id: "settings.display.accent.green",
defaultMessage: "Modrinth Green",
},
purple: {
id: "settings.display.accent.purple",
defaultMessage: "Plus Purple",
},
});
const projectListLayouts = defineMessages({ const projectListLayouts = defineMessages({
title: { title: {
id: "settings.display.project-list-layouts.title", id: "settings.display.project-list-layouts.title",
@ -415,6 +406,10 @@ const themeOptions = computed(() => {
return options; return options;
}); });
const accentOptions = computed(() => {
return ["green", "purple"] as AccentColor[];
});
function updateColorTheme(value: Theme | "system") { function updateColorTheme(value: Theme | "system") {
if (value !== "system") { if (value !== "system") {
if (isDarkTheme(value)) { if (isDarkTheme(value)) {
@ -462,7 +457,7 @@ const listTypes = computed(() => {
border-radius: var(--radius-md); border-radius: var(--radius-md);
padding: 0; padding: 0;
overflow: hidden; overflow: hidden;
border: 1px solid var(--color-divider); border: 1px solid var(--color-button-bg);
background-color: var(--color-button-bg); background-color: var(--color-button-bg);
color: var(--color-base); color: var(--color-base);
display: flex; display: flex;
@ -471,6 +466,8 @@ const listTypes = computed(() => {
&.selected { &.selected {
color: var(--color-contrast); color: var(--color-contrast);
background-color: var(--color-brand-highlight);
border-color: var(--color-brand-highlight);
.label { .label {
.radio { .radio {

View File

@ -1,6 +1,7 @@
import type { DarkTheme } from "./theme/index.ts"; import type { DarkTheme } from "./theme/index.ts";
export type DisplayMode = "list" | "gallery" | "grid"; export type DisplayMode = "list" | "gallery" | "grid";
export type AccentColor = "green" | "purple";
export type DisplayLocation = export type DisplayLocation =
| "mod" | "mod"
@ -22,6 +23,7 @@ export interface Cosmetics {
preferredDarkTheme: DarkTheme; preferredDarkTheme: DarkTheme;
searchDisplayMode: Record<DisplayLocation, DisplayMode>; searchDisplayMode: Record<DisplayLocation, DisplayMode>;
hideStagingBanner: boolean; hideStagingBanner: boolean;
accentColor: AccentColor;
} }
export default defineNuxtPlugin({ export default defineNuxtPlugin({
@ -40,6 +42,7 @@ export default defineNuxtPlugin({
externalLinksNewTab: true, externalLinksNewTab: true,
notUsingBlockers: false, notUsingBlockers: false,
hideModrinthAppPromos: false, hideModrinthAppPromos: false,
accentColor: "green",
preferredDarkTheme: "dark", preferredDarkTheme: "dark",
searchDisplayMode: { searchDisplayMode: {
mod: "list", mod: "list",

View File

@ -1,4 +1,4 @@
<svg width="512" height="514" viewBox="0 0 512 514" xmlns="http://www.w3.org/2000/svg"> <svg width="512" height="514" viewBox="0 0 512 514" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M503.16 323.56C514.55 281.47 515.32 235.91 503.2 190.76C466.57 54.2299 326.04 -26.8001 189.33 9.77991C83.8101 38.0199 11.3899 128.07 0.689941 230.47H43.99C54.29 147.33 113.74 74.7298 199.75 51.7098C306.05 23.2598 415.13 80.6699 453.17 181.38L411.03 192.65C391.64 145.8 352.57 111.45 306.3 96.8198L298.56 140.66C335.09 154.13 364.72 184.5 375.56 224.91C391.36 283.8 361.94 344.14 308.56 369.17L320.09 412.16C390.25 383.21 432.4 310.3 422.43 235.14L464.41 223.91C468.91 252.62 467.35 281.16 460.55 308.07L503.16 323.56Z" fill="var(--color-brand)"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M503.16 323.56C514.55 281.47 515.32 235.91 503.2 190.76C466.57 54.2299 326.04 -26.8001 189.33 9.77991C83.8101 38.0199 11.3899 128.07 0.689941 230.47H43.99C54.29 147.33 113.74 74.7298 199.75 51.7098C306.05 23.2598 415.13 80.6699 453.17 181.38L411.03 192.65C391.64 145.8 352.57 111.45 306.3 96.8198L298.56 140.66C335.09 154.13 364.72 184.5 375.56 224.91C391.36 283.8 361.94 344.14 308.56 369.17L320.09 412.16C390.25 383.21 432.4 310.3 422.43 235.14L464.41 223.91C468.91 252.62 467.35 281.16 460.55 308.07L503.16 323.56Z" fill="currentColor"/>
<path d="M321.99 504.22C185.27 540.8 44.7501 459.77 8.11011 323.24C3.84011 307.31 1.17 291.33 0 275.46H43.27C44.36 287.37 46.4699 299.35 49.6799 311.29C53.0399 323.8 57.45 335.75 62.79 347.07L101.38 323.92C98.1299 316.42 95.39 308.6 93.21 300.47C69.17 210.87 122.41 118.77 212.13 94.7601C229.13 90.2101 246.23 88.4401 262.93 89.1501L255.19 133C244.73 133.05 234.11 134.42 223.53 137.25C157.31 154.98 118.01 222.95 135.75 289.09C136.85 293.16 138.13 297.13 139.59 300.99L188.94 271.38L174.07 231.95L220.67 184.08L279.57 171.39L296.62 192.38L269.47 219.88L245.79 227.33L228.87 244.72L237.16 267.79C237.16 267.79 253.95 285.63 253.98 285.64L277.7 279.33L294.58 260.79L331.44 249.12L342.42 273.82L304.39 320.45L240.66 340.63L212.08 308.81L162.26 338.7C187.8 367.78 226.2 383.93 266.01 380.56L277.54 423.55C218.13 431.41 160.1 406.82 124.05 361.64L85.6399 384.68C136.25 451.17 223.84 484.11 309.61 461.16C371.35 444.64 419.4 402.56 445.42 349.38L488.06 364.88C457.17 431.16 398.22 483.82 321.99 504.22Z" fill="var(--color-brand)"/> <path d="M321.99 504.22C185.27 540.8 44.7501 459.77 8.11011 323.24C3.84011 307.31 1.17 291.33 0 275.46H43.27C44.36 287.37 46.4699 299.35 49.6799 311.29C53.0399 323.8 57.45 335.75 62.79 347.07L101.38 323.92C98.1299 316.42 95.39 308.6 93.21 300.47C69.17 210.87 122.41 118.77 212.13 94.7601C229.13 90.2101 246.23 88.4401 262.93 89.1501L255.19 133C244.73 133.05 234.11 134.42 223.53 137.25C157.31 154.98 118.01 222.95 135.75 289.09C136.85 293.16 138.13 297.13 139.59 300.99L188.94 271.38L174.07 231.95L220.67 184.08L279.57 171.39L296.62 192.38L269.47 219.88L245.79 227.33L228.87 244.72L237.16 267.79C237.16 267.79 253.95 285.63 253.98 285.64L277.7 279.33L294.58 260.79L331.44 249.12L342.42 273.82L304.39 320.45L240.66 340.63L212.08 308.81L162.26 338.7C187.8 367.78 226.2 383.93 266.01 380.56L277.54 423.55C218.13 431.41 160.1 406.82 124.05 361.64L85.6399 384.68C136.25 451.17 223.84 484.11 309.61 461.16C371.35 444.64 419.4 402.56 445.42 349.38L488.06 364.88C457.17 431.16 398.22 483.82 321.99 504.22Z" fill="currentColor"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB