Added "repositories" tab in ModalV2 Profile (#665)

* Added "repositories" tab in ModalV2 Profile

* Add showRepositoryTab setting toggle

* fixes

---------

Co-authored-by: Accentaro <barmstrong210194@gmail.com>
Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
This commit is contained in:
MasterPepe 2026-01-21 18:10:09 +00:00 • committed by GitHub
parent 7f1d3bda7e
commit a87e28709a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 138 additions and 38 deletions

View file

@ -15,7 +15,7 @@ import { cl, settings } from "..";
import { RepoCard } from "./RepoCard";
import { ReposModal } from "./ReposModal";
export function GitHubReposComponent({ id, theme }: { id: string, theme: string; }) {
export function GitHubReposComponent({ id, theme, variant = "popout" }: { id: string, theme: string; variant?: "popout" | "tab"; }) {
const [repos, setRepos] = useState<GitHubRepo[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
@ -64,7 +64,7 @@ export function GitHubReposComponent({ id, theme }: { id: string, theme: string;
const githubId = githubConnection.id;
if (!settings.store.showInMiniProfile) setReturnJustButton(true);
if (!settings.store.showInMiniProfile && variant !== "tab") setReturnJustButton(true);
// Try to fetch by ID first, fall back to username
const reposById = await fetchReposByUserId(githubId);
@ -87,11 +87,15 @@ export function GitHubReposComponent({ id, theme }: { id: string, theme: string;
fetchData();
}, [id]);
if (loading) return <BaseText size="xs" weight="semibold" className={cl("loading")} >
Loading repositories...</BaseText>;
if (loading) return;
<BaseText size="xs" weight="semibold" className={cl("loading")} >
Loading repositories...
</BaseText>;
if (error) return <BaseText size="xs" weight="semibold" className={cl("error")}>
Error: {error}</BaseText>;
if (error) return;
<BaseText size="xs" weight="semibold" className={cl("error")}>
Error: {error}
</BaseText>;
if (!repos.length) return null;
@ -108,15 +112,18 @@ export function GitHubReposComponent({ id, theme }: { id: string, theme: string;
);
}
const topRepos = repos.slice(0, 4);
const topRepos = variant === "tab" ? repos : repos.slice(0, 4);
return (
<div className={cl("container")}>
<div className={variant === "tab" ? `${cl("container")} ${cl("tab")}` : cl("container")}>
<BaseText size="xs" weight="semibold" className={cl("header")}>
GitHub Repositories
{userInfo && (
<span className={cl("count")}>
{` (Showing only top ${topRepos.length}/${userInfo.totalRepos})`}
{variant === "tab"
? ` (${repos.length})`
: ` (Showing only top ${topRepos.length}/${userInfo.totalRepos})`
}
</span>
)}
</BaseText>
@ -127,18 +134,21 @@ export function GitHubReposComponent({ id, theme }: { id: string, theme: string;
repo={repo}
showStars={settings.store.showStars}
showLanguage={settings.store.showLanguage}
variant={variant}
/>))
}
</div>
<div className={cl("footer")}>
<TextButton
className={cl("show-more")}
color="secondary"
onClick={openReposModal}
>
Show More
</TextButton>
</div>
{variant !== "tab" && (
<div className={cl("footer")}>
<TextButton
className={cl("show-more")}
color="secondary"
onClick={openReposModal}
>
Show More
</TextButton>
</div>
)}
</div>
);
}

View file

@ -12,7 +12,7 @@ import { React, Tooltip } from "@webpack/common";
import { cl } from "..";
import { Star } from "./Star";
export function RepoCard({ repo, showStars, showLanguage }: RepoCardProps) {
export function RepoCard({ repo, showStars, showLanguage, variant }: RepoCardProps & { variant?: "popout" | "tab"; }) {
const handleClick = () => window.open(repo.html_url, "_blank");
const renderStars = () => {
@ -20,7 +20,7 @@ export function RepoCard({ repo, showStars, showLanguage }: RepoCardProps) {
return (
<div className={cl("stars")}>
<Star className={cl("stars-icon")} />
<Star className={cl("star-icon")} />
<BaseText size="sm">{repo.stargazers_count.toLocaleString()}</BaseText>
</div>
);
@ -56,12 +56,14 @@ export function RepoCard({ repo, showStars, showLanguage }: RepoCardProps) {
className={cl("language-color")}
style={{ backgroundColor: getLanguageColor(repo.language) }}
/>
<BaseText size="sm">{repo.language}</BaseText>
<BaseText size="sm" className={cl("lang-name")}>{repo.language}</BaseText>
{renderStars()}
</div >
);
};
const cardProps = variant === "tab" ? { onClick: handleClick } : {};
return (
<>
{repo.description ? (
@ -70,6 +72,7 @@ export function RepoCard({ repo, showStars, showLanguage }: RepoCardProps) {
<div className={cl("card")}
onMouseLeave={onMouseLeave}
onMouseEnter={onMouseEnter}
{...cardProps}
>
<div className={cl("header")}>
<BaseText size="sm" weight="medium" className={cl("name")}>
@ -82,7 +85,7 @@ export function RepoCard({ repo, showStars, showLanguage }: RepoCardProps) {
)}
</Tooltip>
) : (
<div className={cl("card")}>
<div className={cl("card")} {...cardProps}>
<div className={cl("header")}>
<BaseText size="sm" weight="medium" className={cl("name")} >
{repo.name}

View file

@ -55,7 +55,7 @@ export function ReposModal({ repos, username, rootProps }: ReposModalProps) {
</td>
<td>
<div className={cl("table-stars")}>
<Star className={cl("table-star-icon")} />
<Star className={cl("star-icon")} />
<span>{repo.stargazers_count.toLocaleString()}</span>
</div>
</td>

View file

@ -36,6 +36,11 @@ export const settings = definePluginSettings({
description: "Show full ui in the mini profile instead of just a button",
default: true
},
showRepositoryTab: {
type: OptionType.BOOLEAN,
description: "Show repositories tab in profile modal (hides button in connections when enabled)",
default: true
},
});
const getProfileThemeProps = findByCodeLazy(".getPreviewThemeColors", "primaryColor:");
@ -58,10 +63,24 @@ const ProfilePopoutComponent = ErrorBoundary.wrap(
}
);
const ProfileRepositoriesTab = ErrorBoundary.wrap(
(props: { user: User; displayProfile?: any; }) => {
return (
<GitHubReposComponent
{...props}
id={props.user.id}
theme={getProfileThemeProps(props).theme}
variant="tab"
/>
);
},
{ noop: true }
);
export default definePlugin({
name: "GitHubRepos",
description: "Displays a user's public GitHub repositories in their profile",
authors: [EquicordDevs.talhakf, EquicordDevs.Panniku],
authors: [EquicordDevs.talhakf, EquicordDevs.Panniku, EquicordDevs.benjii],
settings,
patches: [
@ -86,9 +105,28 @@ export default definePlugin({
find: ".MODAL_V2,onClose:",
replacement: {
match: /displayProfile:(\i).*?profileAppConnections\}\)\}\)/,
replace: "$&,$self.ProfilePopoutComponent({ user: arguments[0].user, displayProfile: $1 }),"
replace: "$&,$self.ProfilePopoutComponent({ user: arguments[0].user, displayProfile: $1 }),",
predicate: () => !settings.store.showRepositoryTab,
}
},
// User Profile Modal v2 tab bar
{
find: "#{intl::USER_PROFILE_ACTIVITY}",
replacement: {
match: /\.MUTUAL_GUILDS\}\)\)(?=,(\i))/,
replace: '$&,$1.push({text:"GitHub",section:"GITHUB"})',
predicate: () => settings.store.showRepositoryTab,
}
},
// User Profile Modal v2 tab content
{
find: ".WIDGETS?",
replacement: {
match: /(\i)===\i\.\i\.WISHLIST/,
replace: '$1==="GITHUB"?$self.ProfileRepositoriesTab(arguments[0]):$&'
}
}
],
ProfilePopoutComponent
ProfilePopoutComponent,
ProfileRepositoriesTab
});

View file

@ -10,11 +10,13 @@
gap: 16px;
}
/* stylelint-disable-next-line selector-class-pattern */
.biteSize_c0bea0 .vc-github-repos-list {
display: flex;
flex-direction: column;
gap: 12px;
.vc-github-repos-star-icon {
color: var(--text-status-idle);
fill: var(--text-status-idle);
}
.vc-github-repos-lang-name {
font-size: 12px;
}
.vc-github-repos-footer {
@ -67,7 +69,7 @@
}
.vc-github-repos-modal {
width: 90%;
width: 100%;
max-width: 900px;
background-color: var(--background-base-lower);
}
@ -76,7 +78,6 @@
color: var(--text-strong);
font-size: 20px;
font-weight: 600;
margin: 0;
}
.vc-github-repos-modal-content {
@ -182,11 +183,6 @@
text-align: center;
}
.vc-github-repos-table-star-icon {
color: var(--text-status-idle);
fill: var(--text-status-idle);
}
.vc-github-repos-modal-footer-close {
margin-right: 5px;
}
@ -209,6 +205,7 @@
.vc-github-repos-loading {
color: var(--text-default);
margin-top: 10px;
}
.vc-github-repos-count {
@ -217,6 +214,7 @@
.vc-github-repos-error {
color: var(--text-feedback-critical);
margin-top: 10px;
}
.vc-github-repos-link {
@ -242,4 +240,55 @@
.vc-github-repos-header-stars {
width: 10%
}
/* Tab variant styles */
.vc-github-repos-container.vc-github-repos-tab {
margin-top: 10px;
padding: 8px 12px;
height: 97%;
width: 100%;
box-sizing: border-box;
display: grid;
grid-template-rows: auto 1fr;
gap: 4px;
overflow: hidden;
position: relative;
}
.vc-github-repos-container.vc-github-repos-tab .vc-github-repos-list {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 4px;
overflow: hidden scroll;
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thin-thumb) var(--scrollbar-thin-track);
align-content: start;
}
.vc-github-repos-container.vc-github-repos-tab .vc-github-repos-card {
padding: 4px 6px;
cursor: pointer;
}
.vc-github-repos-container.vc-github-repos-tab .vc-github-repos-language-color {
width: 8px;
height: 8px;
}
.vc-github-repos-container.vc-github-repos-tab .vc-github-repos-name {
font-size: 14px;
line-height: 1.1;
}
.vc-github-repos-container.vc-github-repos-tab .vc-github-repos-language,
.vc-github-repos-container.vc-github-repos-tab .vc-github-repos-stars {
font-size: 11px;
line-height: 1.1;
gap: 3px;
}
.vc-github-repos-container.vc-github-repos-tab .vc-github-repos-star-icon,
.vc-github-repos-container.vc-github-repos-tab .vc-github-repos-stars {
margin-left: 2px;
}