From 6a70acef25bc5ccad72e2abe4abab101c75e952f Mon Sep 17 00:00:00 2001 From: Prospector <6166773+Prospector@users.noreply.github.com> Date: Sun, 19 Oct 2025 16:26:17 -0700 Subject: [PATCH] Updated ad placeholder graphics, update Modrinth App sidebar to mockup designs (#4584) * Update ad placeholders to new green graphic * Remove rounded corners from app ad frame * Improve web ad placeholder styling * Revamp app sidebar to match mockups more closely, greatly improve friends UX, fix up context menus and typify shit * only show overflow on hover * lint * intl:extract * clean up the inline code in FriendsSection --- apps/app-frontend/src/App.vue | 70 +-- .../src/components/ui/ContextMenu.vue | 37 +- .../src/components/ui/PromotionWrapper.vue | 4 +- .../src/components/ui/friends/FriendsList.vue | 475 +++++++++--------- .../components/ui/friends/FriendsSection.vue | 185 +++++++ apps/app-frontend/src/helpers/friends.js | 17 - apps/app-frontend/src/helpers/friends.ts | 79 +++ .../src/helpers/{mr_auth.js => mr_auth.ts} | 15 +- .../app-frontend/src/locales/en-US/index.json | 57 +++ .../src/components/ui/AdPlaceholder.vue | 48 +- apps/frontend/src/public/promo-frame.html | 1 - packages/assets/generated-icons.ts | 2 + packages/assets/icons/user-cog.svg | 1 + packages/blog/compiled/index.ts | 60 +-- packages/ui/src/components/base/Accordion.vue | 16 +- .../ui/src/components/base/OverflowMenu.vue | 4 + .../ui/src/components/base/PopoutMenu.vue | 7 +- packages/ui/src/locales/en-US/index.json | 3 + packages/ui/src/utils/common-messages.ts | 4 + 19 files changed, 745 insertions(+), 340 deletions(-) create mode 100644 apps/app-frontend/src/components/ui/friends/FriendsSection.vue delete mode 100644 apps/app-frontend/src/helpers/friends.js create mode 100644 apps/app-frontend/src/helpers/friends.ts rename apps/app-frontend/src/helpers/{mr_auth.js => mr_auth.ts} (60%) create mode 100644 packages/assets/icons/user-cog.svg diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue index 4f959793..0fa6893f 100644 --- a/apps/app-frontend/src/App.vue +++ b/apps/app-frontend/src/App.vue @@ -4,6 +4,7 @@ import { ChangeSkinIcon, CompassIcon, DownloadIcon, + ExternalIcon, HomeIcon, LeftArrowIcon, LibraryIcon, @@ -18,6 +19,7 @@ import { RestoreIcon, RightArrowIcon, SettingsIcon, + UserIcon, WorldIcon, XIcon, } from '@modrinth/assets' @@ -69,7 +71,7 @@ import { debugAnalytics, initAnalytics, optOutAnalytics, trackEvent } from '@/he import { get_user } from '@/helpers/cache.js' import { command_listener, warning_listener } from '@/helpers/events.js' import { useFetch } from '@/helpers/fetch.js' -import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.js' +import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.ts' import { list } from '@/helpers/profile.js' import { get as getSettings, set as setSettings } from '@/helpers/settings.ts' import { get_opening_command, initialize_state } from '@/helpers/state' @@ -817,29 +819,39 @@ provideAppUpdateDownloadProgress(appUpdateDownload) > - - - - Sign out - - - - - Sign in + + + + + + Signed in as + + + {{ credentials.user.username }} + + + + + Sign out + + + @@ -979,19 +991,19 @@ provideAppUpdateDownloadProgress(appUpdateDownload) - Playing as + Playing as - + - - News - + + News + - - Add friends to share what you're playing! - - - - - - - - {{ friend.username }} - - - - - Remove - - - - - - - You have no pending friend requests :C - - + You have no pending friend requests :C + + - + - {{ friend.username }} sent you a friend request + {{ friend.username }} sent you a friend request You sent {{ friend.username }} a friend request @@ -246,77 +250,81 @@ onUnmounted(() => { - - - Username - You can add friends with their Modrinth username. - + + + + {{ formatMessage(messages.usernameTitle) }} + + + {{ formatMessage(messages.usernameDescription) }} + + + + + + + + + + {{ formatMessage(messages.sendFriendRequest) }} + + + - - + + + + - Add friend - - - Friends - - + + - - - - Add friend - - - - Manage friends - - {{ acceptedFriends.length }} - - - - - View friend requests - - {{ pendingFriends.length }} - - - + + + + + + + + {{ incomingRequests.length }} + + - + + {{ formatMessage(messages.friends) }} @@ -325,10 +333,13 @@ onUnmounted(() => { - - + + - Sign in to add friends! + Sign in to a Modrinth account + to add friends and see what they're playing! Add friends @@ -337,38 +348,54 @@ onUnmounted(() => { - - Remove friend - - - friendOptions.showMenu(event, friend, [ - { - name: 'remove-friend', - color: 'danger', - }, - ]) - " - > - - - - - - - {{ friend.username }} - - {{ friend.status }} - - + + + + + + {{ formatMessage(messages.noFriendsMatch, { query: search }) }} + + diff --git a/apps/app-frontend/src/components/ui/friends/FriendsSection.vue b/apps/app-frontend/src/components/ui/friends/FriendsSection.vue new file mode 100644 index 00000000..8b5822bb --- /dev/null +++ b/apps/app-frontend/src/components/ui/friends/FriendsSection.vue @@ -0,0 +1,185 @@ + + + + + + + {{ formatMessage(messages.viewProfile) }} + + {{ formatMessage(messages.removeFriend) }} + {{ formatMessage(messages.cancelRequest) }} + + + + + {{ formatMessage(messages.heading, { title: heading, count: friends.length }) }} + + + + + friendOptions?.showMenu(event, friend, createContextMenuOptions(friend)) + " + > + + + + + + + {{ friend.username }} + + + {{ formatMessage(messages.friendRequestSent) }} + + {{ friend.status }} + + + + + + + {{ formatMessage(messages.viewProfile) }} + + + + {{ formatMessage(messages.removeFriend) }} + + + + + + + + + + + + + diff --git a/apps/app-frontend/src/helpers/friends.js b/apps/app-frontend/src/helpers/friends.js deleted file mode 100644 index 16d64f11..00000000 --- a/apps/app-frontend/src/helpers/friends.js +++ /dev/null @@ -1,17 +0,0 @@ -import { invoke } from '@tauri-apps/api/core' - -export async function friends() { - return await invoke('plugin:friends|friends') -} - -export async function friend_statuses() { - return await invoke('plugin:friends|friend_statuses') -} - -export async function add_friend(userId) { - return await invoke('plugin:friends|add_friend', { userId }) -} - -export async function remove_friend(userId) { - return await invoke('plugin:friends|remove_friend', { userId }) -} diff --git a/apps/app-frontend/src/helpers/friends.ts b/apps/app-frontend/src/helpers/friends.ts new file mode 100644 index 00000000..61ad8688 --- /dev/null +++ b/apps/app-frontend/src/helpers/friends.ts @@ -0,0 +1,79 @@ +import type { User } from '@modrinth/utils' +import { invoke } from '@tauri-apps/api/core' +import type { Dayjs } from 'dayjs' +import dayjs from 'dayjs' + +import { get_user_many } from '@/helpers/cache' +import type { ModrinthCredentials } from '@/helpers/mr_auth' + +export type UserStatus = { + user_id: string + profile_name: string | null + last_update: string +} + +export type UserFriend = { + id: string + friend_id: string + accepted: boolean + created: string +} + +export async function friends(): Promise { + return await invoke('plugin:friends|friends') +} + +export async function friend_statuses(): Promise { + return await invoke('plugin:friends|friend_statuses') +} + +export async function add_friend(userId: string): Promise { + return await invoke('plugin:friends|add_friend', { userId }) +} + +export async function remove_friend(userId: string): Promise { + return await invoke('plugin:friends|remove_friend', { userId }) +} + +export type FriendWithUserData = { + id: string + friend_id: string | null + status: string | null + last_updated: Dayjs | null + created: Dayjs + username: string + accepted: boolean + online: boolean + avatar: string +} +export async function transformFriends( + friends: UserFriend[], + credentials: ModrinthCredentials | null, +): Promise { + if (friends.length === 0) { + return [] + } + + const friendStatuses = await friend_statuses() + const users = await get_user_many( + friends.map((x) => (x.id === credentials?.user_id ? x.friend_id : x.id)), + ) + + return friends.map((friend) => { + const user = users.find((x: User) => x.id === friend.id || x.id === friend.friend_id) + const status = friendStatuses.find( + (x) => x.user_id === friend.id || x.user_id === friend.friend_id, + ) + return { + id: friend.id, + friend_id: friend.friend_id, + status: status?.profile_name ?? null, + last_updated: status && status.last_update ? dayjs(status.last_update) : null, + created: dayjs(friend.created), + avatar: user?.avatar_url ?? '', + username: user?.username ?? '', + online: !!status, + accepted: friend.accepted, + } + }) +} diff --git a/apps/app-frontend/src/helpers/mr_auth.js b/apps/app-frontend/src/helpers/mr_auth.ts similarity index 60% rename from apps/app-frontend/src/helpers/mr_auth.js rename to apps/app-frontend/src/helpers/mr_auth.ts index 2690957e..dfb476d2 100644 --- a/apps/app-frontend/src/helpers/mr_auth.js +++ b/apps/app-frontend/src/helpers/mr_auth.ts @@ -5,18 +5,25 @@ */ import { invoke } from '@tauri-apps/api/core' -export async function login() { +export type ModrinthCredentials = { + session: string + expires: string + user_id: string + active: boolean +} + +export async function login(): Promise { return await invoke('plugin:mr-auth|modrinth_login') } -export async function logout() { +export async function logout(): Promise { return await invoke('plugin:mr-auth|logout') } -export async function get() { +export async function get(): Promise { return await invoke('plugin:mr-auth|get') } -export async function cancelLogin() { +export async function cancelLogin(): Promise { return await invoke('plugin:mr-auth|cancel_modrinth_login') } diff --git a/apps/app-frontend/src/locales/en-US/index.json b/apps/app-frontend/src/locales/en-US/index.json index 9ec019ff..ef869d32 100644 --- a/apps/app-frontend/src/locales/en-US/index.json +++ b/apps/app-frontend/src/locales/en-US/index.json @@ -65,6 +65,63 @@ "app.update.reload-to-update": { "message": "Reload to install update" }, + "friends.action.add-friend": { + "message": "Add a friend" + }, + "friends.action.view-friend-requests": { + "message": "{count} friend requests" + }, + "friends.add-friend.submit": { + "message": "Send friend request" + }, + "friends.add-friend.title": { + "message": "Adding a friend" + }, + "friends.add-friend.username.description": { + "message": "It may be different from their Minecraft username!" + }, + "friends.add-friend.username.placeholder": { + "message": "Enter Modrinth username..." + }, + "friends.add-friend.username.title": { + "message": "What's your friend's Modrinth username?" + }, + "friends.friend.cancel-request": { + "message": "Cancel request" + }, + "friends.friend.remove-friend": { + "message": "Remove friend" + }, + "friends.friend.request-sent": { + "message": "Friend request sent" + }, + "friends.friend.view-profile": { + "message": "View profile" + }, + "friends.heading": { + "message": "Friends" + }, + "friends.heading.active": { + "message": "Active" + }, + "friends.heading.offline": { + "message": "Offline" + }, + "friends.heading.online": { + "message": "Online" + }, + "friends.heading.pending": { + "message": "Pending" + }, + "friends.no-friends-match": { + "message": "No friends matching ''{query}''" + }, + "friends.search-friends-placeholder": { + "message": "Search friends..." + }, + "friends.section.heading": { + "message": "{title} - {count}" + }, "instance.add-server.add-and-play": { "message": "Add and play" }, diff --git a/apps/frontend/src/components/ui/AdPlaceholder.vue b/apps/frontend/src/components/ui/AdPlaceholder.vue index 937aeefd..eeaf861d 100644 --- a/apps/frontend/src/components/ui/AdPlaceholder.vue +++ b/apps/frontend/src/components/ui/AdPlaceholder.vue @@ -1,20 +1,23 @@ - - + - + @@ -23,6 +26,8 @@
Add friends to share what you're playing!
You have no pending friend requests :C
- {{ friend.username }} sent you a friend request + {{ friend.username }} sent you a friend request You sent {{ friend.username }} a friend request @@ -246,77 +250,81 @@ onUnmounted(() => {
You can add friends with their Modrinth username.
+ {{ formatMessage(messages.usernameDescription) }} +
+ {{ formatMessage(messages.noFriendsMatch, { query: search }) }} +