feat: redesign icon, hide servers in sidebar, collapse news

This commit is contained in:
Felitendo committed 2026-09-14 13:14:21 +02:00
1 parent f67b017c5f
commit e1ec2068e6
5 files changed
+12430 -13997

No files matched your search

@@ -4,22 +4,23 @@ Date: Mon, 14 Sep 2026 09:56:18 +0200
Subject: [PATCH] Rename the app to Modrinth Enhanced
Changes the product name, the binary name, the window title and the
version label shown in settings. A small "Enhanced" pill is added next
to the wordmark in the title bar so the fork is recognisable at a
glance.
version label shown in settings.
The title bar keeps the plain Modrinth wordmark: a badge next to it
pushes the width of that bar up, and the name is already visible in the
window title and in settings.
The bundle identifier is deliberately left as `ModrinthApp` so that
Modrinth Enhanced keeps using the same data directory as the official
app and stays a drop-in replacement for it.
---
apps/app-frontend/index.html | 2 +-
apps/app-frontend/src/App.vue | 5 +++++
.../src/components/ui/modal/AppSettingsModal.vue | 2 +-
apps/app-frontend/src/locales/en-US/index.json | 2 +-
apps/app/tauri.conf.json | 6 +++---
apps/app/tauri.linux.conf.json | 2 +-
apps/app/tauri.macos.conf.json | 2 +-
7 files changed, 13 insertions(+), 8 deletions(-)
6 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/apps/app-frontend/index.html b/apps/app-frontend/index.html
index 50867a4..6367788 100644
@@ -34,22 +35,6 @@ index 50867a4..6367788 100644
<link rel="stylesheet" href="/src/assets/stylesheets/global.scss" />
</head>
diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue
index a2ae0e6..1d1a9ce 100644
--- a/apps/app-frontend/src/App.vue
+++ b/apps/app-frontend/src/App.vue
@@ -2374,6 +2374,11 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
<div data-tauri-drag-region class="app-grid-statusbar bg-bg-raised h-[--top-bar-height] flex">
<div data-tauri-drag-region class="flex min-w-0 flex-1 items-center overflow-hidden p-2">
<TextLogo class="h-7 w-auto shrink-0 text-contrast pointer-events-none" />
+ <span
+ data-tauri-drag-region
+ class="ml-1.5 shrink-0 rounded-full bg-brand-highlight px-1.5 py-0.5 text-[0.625rem] font-bold uppercase leading-none tracking-wide text-brand pointer-events-none"
+ >Enhanced</span
+ >
<div data-tauri-drag-region class="ml-2 flex shrink-0 items-center gap-2">
<IconButton
type="outlined"
diff --git a/apps/app-frontend/src/components/ui/modal/AppSettingsModal.vue b/apps/app-frontend/src/components/ui/modal/AppSettingsModal.vue
index dd55fe5..0f33d0e 100644
--- a/apps/app-frontend/src/components/ui/modal/AppSettingsModal.vue
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -16,7 +16,7 @@ webview, no matter which call site reaches for it.
2 files changed, 25 insertions(+), 48 deletions(-)
diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue
index 1d1a9ce..4df835f 100644
index a2ae0e6..33c29ce 100644
--- a/apps/app-frontend/src/App.vue
+++ b/apps/app-frontend/src/App.vue
@@ -366,10 +366,10 @@ const hasPlus = computed(
@@ -0,0 +1,189 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Modrinth Enhanced <patches@modrinth-enhanced.invalid>
Date: Mon, 14 Sep 2026 13:06:38 +0200
Subject: [PATCH] Hide Modrinth Servers in the sidebar and fold away the news
Two sidebar preferences, both stored as feature flags so they survive a
restart without needing a settings migration:
* The Modrinth Servers button in the left sidebar is off by default and
can be turned back on under Settings > Features > Sidebar.
* The news section in the right sidebar collapses by clicking its
heading, remembering the state the way the friends list does.
---
apps/app-frontend/src/App.vue | 31 +++++++++++++++++--
.../ui/settings/display/FeaturesSettings.vue | 27 ++++++++++++++++
.../src/composables/use-app-settings.ts | 2 ++
packages/app-lib/src/state/settings.rs | 2 ++
4 files changed, 59 insertions(+), 3 deletions(-)
diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue
index 33c29ce..4c3663f 100644
--- a/apps/app-frontend/src/App.vue
+++ b/apps/app-frontend/src/App.vue
@@ -11,6 +11,7 @@ import {
import {
ArrowBigUpDashIcon,
ArrowLeftRightIcon,
+ ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
CompassIcon,
@@ -370,6 +371,21 @@ const hasPlus = computed(
// ad cookie consent flow that only exists to serve it are both switched off.
const showAd = computed(() => false)
const adConsentAvailable = computed(() => false)
+
+// Whether the news section in the right sidebar is folded away. Kept in the
+// feature flags so it survives a restart, the same way the friends list
+// remembers its collapsed sections.
+const newsCollapsed = computed(() => appSettings.getFeatureFlag('news_collapsed'))
+
+function setNewsCollapsed(collapsed: boolean) {
+ appSettings.featureFlags.news_collapsed = collapsed
+ getSettings()
+ .then((settings) => {
+ settings.feature_flags.news_collapsed = collapsed
+ return setSettings(settings)
+ })
+ .catch(handleError)
+}
providePageContext({
hierarchicalSidebarAvailable: ref(true),
showAds: showAd,
@@ -2278,6 +2294,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
<ImageIcon />
</NavButton>
<NavButton
+ v-if="appSettings.getFeatureFlag('show_hosting_in_sidebar')"
v-tooltip.right="formatMessage(messages.modrinthHosting)"
to="/hosting/manage"
:is-primary="(r) => r.path === '/hosting/manage' || r.path === '/hosting/manage/'"
@@ -2528,10 +2545,18 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
class="p-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid"
/>
<div v-if="news && news.length > 0" class="p-4 flex flex-col items-center">
- <h3 class="text-base mb-4 text-primary font-medium m-0 text-left w-full">
+ <button
+ class="button-base m-0 mb-4 flex w-full cursor-pointer items-center justify-between gap-2 border-0 bg-transparent p-0 text-left text-base font-medium text-primary"
+ :aria-expanded="!newsCollapsed"
+ @click="setNewsCollapsed(!newsCollapsed)"
+ >
{{ formatMessage(messages.news) }}
- </h3>
- <div class="space-y-4 flex flex-col items-center w-full">
+ <ChevronDownIcon
+ class="h-5 w-5 shrink-0 transition-transform"
+ :class="{ '-rotate-90': newsCollapsed }"
+ />
+ </button>
+ <div v-if="!newsCollapsed" class="space-y-4 flex flex-col items-center w-full">
<NewsArticleCard
v-for="(item, index) in news"
:key="`news-${index}`"
diff --git a/apps/app-frontend/src/components/ui/settings/display/FeaturesSettings.vue b/apps/app-frontend/src/components/ui/settings/display/FeaturesSettings.vue
index 1d3e379..54f1c51 100644
--- a/apps/app-frontend/src/components/ui/settings/display/FeaturesSettings.vue
+++ b/apps/app-frontend/src/components/ui/settings/display/FeaturesSettings.vue
@@ -43,6 +43,7 @@ const quickInstances = useQuickInstanceLimit()
const queryClient = useQueryClient()
const showJumpInFlag: FeatureFlag = 'worlds_in_home'
+const showHostingFlag: FeatureFlag = 'show_hosting_in_sidebar'
const messages = defineMessages({
syncAcrossDevicesTitle: {
@@ -95,6 +96,14 @@ const messages = defineMessages({
id: 'app.features-settings.show-skin-selector.description',
defaultMessage: 'Show a button in the left sidebar to open the skin selector.',
},
+ showHostingTitle: {
+ id: 'app.features-settings.show-hosting.title',
+ defaultMessage: 'Show Modrinth Servers in sidebar',
+ },
+ showHostingDescription: {
+ id: 'app.features-settings.show-hosting.description',
+ defaultMessage: 'Show a button in the left sidebar to manage Modrinth Servers.',
+ },
quickInstancesTitle: {
id: 'app.features-settings.quick-instances.title',
defaultMessage: 'Quick instances in sidebar',
@@ -125,6 +134,7 @@ type FeaturesSettingsState = {
showScreenshotsTab: boolean
showAllScreenshots: boolean
showSkinSelector: boolean
+ showHosting: boolean
quickInstanceCount: number
showJumpIn: boolean
}
@@ -144,6 +154,7 @@ function getFeaturesSettingsState(
showScreenshotsTab: settings.show_screenshots_tab_in_instances,
showAllScreenshots: globalSyncedOptions.screenshots,
showSkinSelector: settings.show_skin_selector_in_sidebar,
+ showHosting: settings.feature_flags[showHostingFlag] ?? DEFAULT_FEATURE_FLAGS[showHostingFlag],
quickInstanceCount: quickInstances.limit.value ?? QUICK_INSTANCE_LIMIT_MAX,
showJumpIn: settings.feature_flags[showJumpInFlag] ?? DEFAULT_FEATURE_FLAGS[showJumpInFlag],
}
@@ -184,6 +195,7 @@ const settingsMutation = useMutation({
feature_flags: {
...latestSettings.feature_flags,
[showJumpInFlag]: value.showJumpIn,
+ [showHostingFlag]: value.showHosting,
},
}
@@ -206,6 +218,7 @@ const settingsMutation = useMutation({
appSettings.showScreenshotsTabInInstances = value.showScreenshotsTab
appSettings.showSkinSelectorInSidebar = value.showSkinSelector
appSettings.featureFlags[showJumpInFlag] = value.showJumpIn
+ appSettings.featureFlags[showHostingFlag] = value.showHosting
if (updateQuickInstanceCount) {
quickInstances.setLimit(value.quickInstanceCount)
@@ -366,6 +379,20 @@ onBeforeUnmount(() => {
/>
</div>
+ <div class="flex items-center justify-between gap-4">
+ <div>
+ <h3 class="m-0 text-lg font-semibold text-contrast">
+ {{ formatMessage(messages.showHostingTitle) }}
+ </h3>
+ <p class="m-0 mt-1">{{ formatMessage(messages.showHostingDescription) }}</p>
+ </div>
+ <Toggle
+ id="show-hosting-in-sidebar"
+ v-model="current.showHosting"
+ :aria-label="formatMessage(messages.showHostingTitle)"
+ />
+ </div>
+
<div class="flex flex-col gap-2.5">
<h3 class="m-0 text-lg font-semibold text-contrast">
{{ formatMessage(messages.quickInstancesTitle) }}
diff --git a/apps/app-frontend/src/composables/use-app-settings.ts b/apps/app-frontend/src/composables/use-app-settings.ts
index 0d58903..4f0b2aa 100644
--- a/apps/app-frontend/src/composables/use-app-settings.ts
+++ b/apps/app-frontend/src/composables/use-app-settings.ts
@@ -24,6 +24,8 @@ export const DEFAULT_FEATURE_FLAGS = {
friends_pending_collapsed: true,
dismissed_photosensitivity_filter_warning: false,
localhost_sign_in: false,
+ show_hosting_in_sidebar: false,
+ news_collapsed: false,
}
export type FeatureFlag = keyof typeof DEFAULT_FEATURE_FLAGS
diff --git a/packages/app-lib/src/state/settings.rs b/packages/app-lib/src/state/settings.rs
index 20601b8..b02bbe0 100644
--- a/packages/app-lib/src/state/settings.rs
+++ b/packages/app-lib/src/state/settings.rs
@@ -88,6 +88,8 @@ pub enum FeatureFlag {
FriendsPendingCollapsed,
DismissedPhotosensitivityFilterWarning,
LocalhostSignIn,
+ ShowHostingInSidebar,
+ NewsCollapsed,
}
impl Settings {
+19 -10
View File
@@ -1,10 +1,12 @@
#!/usr/bin/env python3
"""Render the Modrinth Enhanced icon set from its vector source.
"""Render the Modrinth Enhanced icon set from its vector sources.
The source lives in the patched checkout as
`apps/app/icons/modrinth-enhanced.svg`; this rewrites every generated icon
next to it. Run it after editing that SVG, then commit the result in
build/upstream and re-export the patches.
Two sources live in the patched checkout next to the generated files:
`apps/app/icons/modrinth-enhanced.svg` for 64px and up, and
`modrinth-enhanced-small.svg` for everything below that, where the full maze
no longer resolves. This rewrites every generated icon from them. Run it after
editing either SVG, then commit the result in build/upstream and re-export the
patches.
Needs `rsvg-convert` (librsvg). ImageMagick is not used: the ICNS and ICO
writers below are a few lines each and work the same everywhere, whereas
@@ -26,6 +28,11 @@ ICONS = os.path.join(
"icons",
)
SVG = os.path.join(ICONS, "modrinth-enhanced.svg")
SVG_SMALL = os.path.join(ICONS, "modrinth-enhanced-small.svg")
# Below this the full mark's rings are thinner than a pixel and smear into each
# other, so the cropped source is used instead.
SMALL_MAX = 48
# Every PNG the Tauri bundles reference, and the size it has to be.
PNGS = {
@@ -64,10 +71,11 @@ ICNS_TYPES = [
def render(size, path):
"""Rasterise the source at exactly `size`, rather than downscaling one
large render, so the small sizes stay crisp."""
"""Rasterise the source for `size` at exactly that size, rather than
downscaling one large render, so the small sizes stay crisp."""
source = SVG_SMALL if size <= SMALL_MAX else SVG
subprocess.run(
["rsvg-convert", "-w", str(size), "-h", str(size), SVG, "-o", path],
["rsvg-convert", "-w", str(size), "-h", str(size), source, "-o", path],
check=True,
)
@@ -114,8 +122,9 @@ def build_icns(cache, path):
def main():
if not shutil.which("rsvg-convert"):
sys.exit("rsvg-convert is required (install librsvg)")
if not os.path.isfile(SVG):
sys.exit(f"No icon source at {SVG}. Run scripts/prepare.sh first.")
for source in (SVG, SVG_SMALL):
if not os.path.isfile(source):
sys.exit(f"No icon source at {source}. Run scripts/prepare.sh first.")
with tempfile.TemporaryDirectory() as tmp:
cache = {}