feat: add ClientCard and ClientsList components to MDXComponents

This commit is contained in:
kastov
2025-10-10 18:09:37 +03:00
parent 917092db54
commit d349be4f3b
9 changed files with 1329 additions and 0 deletions

View File

@@ -0,0 +1,210 @@
import GitHubStars from '@site/src/components/GitHubStars'
import Link from '@docusaurus/Link'
import React from 'react'
import clsx from 'clsx'
import styles from './styles.module.css'
type CoreType = 'mihomo' | 'other' | 'singbox' | 'xray'
interface ClientCardProps {
author?: string
authorLink?: string
core: CoreType
coreIcon?: string // SVG icon URL
description: string
featured?: boolean
githubRepo?: string
hwidSupported?: boolean
id?: string
links?: {
docs?: string
download?: string
github?: string
telegram?: string
website?: string
}
platform?: string
title: string
}
const CORE_CONFIG: Record<
CoreType,
{ color: string; darkColor: string; iconSvg?: string; label: string }
> = {
mihomo: {
label: 'Mihomo',
iconSvg: '/clients/mihomo_black.svg',
color: '#3a4f66',
darkColor: '#2a3847'
},
xray: {
label: 'X-Ray',
iconSvg: '/clients/xray_black.svg',
color: '#4a3d5a',
darkColor: '#3a2d4a'
},
singbox: {
label: 'Sing-Box',
iconSvg: '/clients/sb_black.svg',
color: '#2d4a3d',
darkColor: '#1d3a2d'
},
other: {
label: 'Other',
color: '#3d4349',
darkColor: '#2d3339'
}
}
export default function ClientCard({
title,
description,
author,
authorLink,
links,
core,
coreIcon,
featured = false,
hwidSupported = false,
githubRepo,
id,
platform
}: ClientCardProps) {
const clientId =
id ||
title
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
const coreConfig = CORE_CONFIG[core] || CORE_CONFIG.other
return (
<div
className={clsx(styles.clientCard, featured && styles.featured)}
data-core={core}
id={clientId}
>
{/* Content */}
<div className={styles.cardContent}>
{/* Badges Row - Always render to maintain consistent spacing */}
<div className={styles.badgesRow}>
{featured && <span className={styles.featuredBadge}></span>}
{hwidSupported && (
<div
className={styles.hwidBadge}
data-tooltip="This client supports sending HWID"
>
<svg fill="currentColor" height="14" viewBox="0 0 16 16" width="14">
<path d="M13.485 1.431a1.473 1.473 0 0 1 2.104 2.062l-7.84 9.801a1.473 1.473 0 0 1-2.12.04L.431 8.138a1.473 1.473 0 0 1 2.084-2.083l4.111 4.112 6.82-8.69a.486.486 0 0 1 .04-.045z" />
</svg>
<span>HWID</span>
</div>
)}
{githubRepo && links?.github && (
<Link className={styles.starsBadge} to={links.github}>
<GitHubStars repo={githubRepo} />
</Link>
)}
</div>
<div className={styles.cardHeader}>
<div className={styles.titleWrapper}>
<h3 className={styles.clientTitle}>
<a className={styles.clientAnchor} href={`#${clientId}`}>
{title}
</a>
</h3>
{author && (
<div className={styles.authorInfo}>
<span className={styles.byText}>by</span>
{authorLink ? (
<Link className={styles.authorLink} to={authorLink}>
{author}
</Link>
) : (
<span className={styles.authorName}>{author}</span>
)}
</div>
)}
{platform && <div className={styles.platformBadge}>{platform}</div>}
</div>
</div>
<p className={styles.description}>{description}</p>
{links && (
<div className={styles.links}>
{links?.download && (
<Link
className={clsx(styles.link, styles.downloadLink)}
to={links.download}
>
<svg fill="currentColor" height="14" viewBox="0 0 16 16" width="14">
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z" />
<path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z" />
</svg>
Download
</Link>
)}
{links?.github && (
<Link
className={clsx(styles.link, styles.githubLink)}
to={links.github}
>
<svg fill="currentColor" height="14" viewBox="0 0 16 16" width="14">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" />
</svg>
GitHub
</Link>
)}
{links?.docs && (
<Link className={clsx(styles.link, styles.docsLink)} to={links.docs}>
<svg fill="currentColor" height="14" viewBox="0 0 16 16" width="14">
<path d="M2 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v13.5a.5.5 0 0 1-.777.416L8 13.101l-5.223 2.815A.5.5 0 0 1 2 15.5V2zm2-1a1 1 0 0 0-1 1v12.566l4.723-2.482a.5.5 0 0 1 .554 0L13 14.566V2a1 1 0 0 0-1-1H4z" />
</svg>
Docs
</Link>
)}
{links?.telegram && (
<Link
className={clsx(styles.link, styles.telegramLink)}
to={links.telegram}
>
<svg fill="currentColor" height="14" viewBox="0 0 16 16" width="14">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8.287 5.906c-.778.324-2.334.994-4.666 2.01-.378.15-.577.298-.595.442-.03.243.275.339.69.47l.175.055c.408.133.958.288 1.243.294.26.006.549-.1.868-.32 2.179-1.471 3.304-2.214 3.374-2.23.05-.012.12-.026.166.016.047.041.042.12.037.141-.03.129-1.227 1.241-1.846 1.817-.193.18-.33.307-.358.336a8.154 8.154 0 0 1-.188.186c-.38.366-.664.64.015 1.088.327.216.589.393.85.571.284.194.568.387.936.629.093.06.183.125.27.187.331.236.63.448.997.414.214-.02.435-.22.547-.82.265-1.417.786-4.486.906-5.751a1.426 1.426 0 0 0-.013-.315.337.337 0 0 0-.114-.217.526.526 0 0 0-.31-.093c-.3.005-.763.166-2.984 1.09z" />
</svg>
Telegram
</Link>
)}
{links?.website && (
<Link
className={clsx(styles.link, styles.websiteLink)}
to={links.website}
>
<svg fill="currentColor" height="14" viewBox="0 0 16 16" width="14">
<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855A7.97 7.97 0 0 0 5.145 4H7.5V1.077zM4.09 4a9.267 9.267 0 0 1 .64-1.539 6.7 6.7 0 0 1 .597-.933A7.025 7.025 0 0 0 2.255 4H4.09zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a6.958 6.958 0 0 0-.656 2.5h2.49zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5H4.847zM8.5 5v2.5h2.99a12.495 12.495 0 0 0-.337-2.5H8.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5H4.51zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5H8.5zM5.145 12c.138.386.295.744.468 1.068.552 1.035 1.218 1.65 1.887 1.855V12H5.145zm.182 2.472a6.696 6.696 0 0 1-.597-.933A9.268 9.268 0 0 1 4.09 12H2.255a7.024 7.024 0 0 0 3.072 2.472zM3.82 11a13.652 13.652 0 0 1-.312-2.5h-2.49c.062.89.291 1.733.656 2.5H3.82zm6.853 3.472A7.024 7.024 0 0 0 13.745 12H11.91a9.27 9.27 0 0 1-.64 1.539 6.688 6.688 0 0 1-.597.933zM8.5 12v2.923c.67-.204 1.335-.82 1.887-1.855.173-.324.33-.682.468-1.068H8.5zm3.68-1h2.146c.365-.767.594-1.61.656-2.5h-2.49a13.65 13.65 0 0 1-.312 2.5zm2.802-3.5a6.959 6.959 0 0 0-.656-2.5H12.18c.174.782.282 1.623.312 2.5h2.49zM11.27 2.461c.247.464.462.98.64 1.539h1.835a7.024 7.024 0 0 0-3.072-2.472c.218.284.418.598.597.933zM10.855 4a7.966 7.966 0 0 0-.468-1.068C9.835 1.897 9.17 1.282 8.5 1.077V4h2.355z" />
</svg>
Website
</Link>
)}
</div>
)}
{/* Core Badge - Bottom */}
<div className={styles.coreBadge} data-core={core}>
{(coreIcon || coreConfig.iconSvg) && (
<img
alt={coreConfig.label}
className={styles.coreIconSvg}
src={coreIcon || coreConfig.iconSvg}
/>
)}
<span className={styles.coreLabel}>{coreConfig.label}</span>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,557 @@
.clientCard {
background: var(--ifm-card-background-color);
border: 1px solid var(--ifm-color-emphasis-200);
border-radius: 12px;
overflow: visible;
transition: all 0.3s ease;
height: 100%;
display: flex;
flex-direction: column;
position: relative;
scroll-margin-top: 100px;
}
.clientCard:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
}
[data-theme='dark'] .clientCard:hover {
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.4);
}
/* Core-specific border colors on hover */
.clientCard[data-core='mihomo']:hover {
border-color: #3a4f66;
}
.clientCard[data-core='xray']:hover {
border-color: #4a3d5a;
}
.clientCard[data-core='singbox']:hover {
border-color: #2d4a3d;
}
.clientCard[data-core='other']:hover {
border-color: #3d4349;
}
[data-theme='dark'] .clientCard[data-core='mihomo']:hover {
border-color: #2a3847;
}
[data-theme='dark'] .clientCard[data-core='xray']:hover {
border-color: #3a2d4a;
}
[data-theme='dark'] .clientCard[data-core='singbox']:hover {
border-color: #1d3a2d;
}
[data-theme='dark'] .clientCard[data-core='other']:hover {
border-color: #2d3339;
}
.featured {
border: 2px solid var(--ifm-color-primary);
background: linear-gradient(
135deg,
var(--ifm-card-background-color) 0%,
rgba(var(--ifm-color-primary-rgb), 0.03) 100%
);
}
/* Core Badge - Bottom of Card */
.coreBadge {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.6rem 1rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.6px;
margin-top: auto;
border-radius: 0 0 12px 12px;
}
.coreBadge[data-core='mihomo'] {
background: #3a4f66;
color: #d4e3f0;
}
.coreBadge[data-core='xray'] {
background: #4a3d5a;
color: #e5dff0;
}
.coreBadge[data-core='singbox'] {
background: #2d4a3d;
color: #d4f0e0;
}
.coreBadge[data-core='other'] {
background: #3d4349;
color: #e0e3e6;
}
[data-theme='dark'] .coreBadge[data-core='mihomo'] {
background: #2a3847;
color: #b8d0e5;
}
[data-theme='dark'] .coreBadge[data-core='xray'] {
background: #3a2d4a;
color: #d5c8e5;
}
[data-theme='dark'] .coreBadge[data-core='singbox'] {
background: #1d3a2d;
color: #b8e5d0;
}
[data-theme='dark'] .coreBadge[data-core='other'] {
background: #2d3339;
color: #c8ced3;
}
.coreIcon {
font-size: 1.1rem;
line-height: 1;
}
.coreIconSvg {
width: 18px;
height: 18px;
object-fit: contain;
flex-shrink: 0;
}
.coreLabel {
font-size: 0.75rem;
}
/* Badges Row */
.badgesRow {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 0.5rem;
flex-wrap: wrap;
min-height: 28px;
margin-bottom: 0.5rem;
}
.hwidBadge {
display: flex;
align-items: center;
gap: 0.3rem;
padding: 0.35rem 0.65rem;
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
border-radius: 6px;
font-size: 0.65rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
cursor: help;
transition: all 0.2s ease;
position: relative;
z-index: 1;
}
.hwidBadge::before {
content: attr(data-tooltip);
position: absolute;
bottom: calc(100% + 10px);
right: 0;
padding: 0.5rem 0.75rem;
background: var(--ifm-color-emphasis-900);
color: white;
border-radius: 6px;
font-size: 0.75rem;
font-weight: 500;
text-transform: none;
letter-spacing: normal;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition:
opacity 0.2s ease,
transform 0.2s ease;
transform: translateY(5px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
z-index: 10000;
}
.hwidBadge::after {
content: '';
position: absolute;
bottom: calc(100% + 2px);
right: 15px;
border: 5px solid transparent;
border-top-color: var(--ifm-color-emphasis-900);
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease;
z-index: 10000;
}
.hwidBadge:hover::before,
.hwidBadge:hover::after {
opacity: 1;
transform: translateY(0);
}
.hwidBadge:hover {
background: #c3e6cb;
border-color: #b1dfbb;
transform: translateY(-1px);
z-index: 10001;
}
[data-theme='dark'] .hwidBadge {
background: #1e4620;
color: #a3d9a5;
border-color: #2d5a2f;
}
[data-theme='dark'] .hwidBadge:hover {
background: #2d5a2f;
border-color: #3d6a3f;
}
[data-theme='dark'] .hwidBadge::before {
background: var(--ifm-color-emphasis-100);
color: var(--ifm-color-emphasis-900);
}
[data-theme='dark'] .hwidBadge::after {
border-top-color: var(--ifm-color-emphasis-100);
}
.starsBadge {
display: flex;
align-items: center;
padding: 0.4rem 0.75rem;
background: #24292e;
color: white;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 6px;
font-size: 0.75rem;
font-weight: 600;
transition: all 0.2s ease;
text-decoration: none;
cursor: pointer;
}
.starsBadge:hover {
background: #1a1e22;
border-color: rgba(255, 255, 255, 0.2);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
color: white;
text-decoration: none;
}
[data-theme='dark'] .starsBadge {
background: #2d333b;
border-color: rgba(255, 255, 255, 0.15);
}
[data-theme='dark'] .starsBadge:hover {
background: #373e47;
border-color: rgba(255, 255, 255, 0.25);
color: white;
}
/* Card Content */
.cardContent {
padding: 1.25rem;
flex: 1;
display: flex;
flex-direction: column;
gap: 0.85rem;
border-radius: 12px 12px 0 0;
}
.featured .cardContent {
background: linear-gradient(
135deg,
var(--ifm-card-background-color) 0%,
rgba(var(--ifm-color-primary-rgb), 0.03) 100%
);
}
.cardHeader {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 0.5rem;
}
.titleWrapper {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.clientTitle {
margin: 0;
font-size: 1.15rem;
font-weight: 700;
color: var(--ifm-heading-color);
line-height: 1.3;
}
.clientAnchor {
color: inherit;
text-decoration: none;
}
.clientAnchor:hover {
color: var(--ifm-color-primary);
text-decoration: none;
}
.featuredBadge {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.3rem;
padding: 0.35rem 0.65rem;
background: var(--ifm-color-primary);
color: white;
border-radius: 6px;
font-size: 0.7rem;
font-weight: 600;
flex-shrink: 0;
box-shadow: 0 2px 8px rgba(var(--ifm-color-primary-rgb), 0.3);
}
.authorInfo {
display: flex;
align-items: center;
gap: 0.35rem;
font-size: 0.85rem;
}
.byText {
color: var(--ifm-color-emphasis-600);
font-weight: 400;
}
.authorLink {
color: var(--ifm-color-primary);
text-decoration: none;
font-weight: 600;
transition: all 0.2s ease;
}
.authorLink:hover {
text-decoration: underline;
color: var(--ifm-color-primary-dark);
}
.authorName {
color: var(--ifm-color-emphasis-800);
font-weight: 600;
}
[data-theme='dark'] .byText {
color: var(--ifm-color-emphasis-500);
}
[data-theme='dark'] .authorName {
color: var(--ifm-color-emphasis-700);
}
.platformBadge {
display: inline-block;
padding: 0.2rem 0.5rem;
background: var(--ifm-color-emphasis-100);
color: var(--ifm-color-emphasis-700);
border-radius: 4px;
font-size: 0.7rem;
font-weight: 600;
}
.description {
flex: 1;
margin: 0;
color: var(--ifm-color-emphasis-800);
line-height: 1.5;
font-size: 0.9rem;
}
.links {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
margin-top: auto;
padding-top: 0.75rem;
border-top: 1px solid var(--ifm-color-emphasis-200);
}
.link {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.35rem;
padding: 0.5rem 0.9rem;
min-height: 36px;
border-radius: 6px;
font-size: 0.8rem;
font-weight: 500;
text-decoration: none;
transition: all 0.2s ease;
white-space: nowrap;
}
.githubLink {
background: #24292e;
color: white;
}
.githubLink:hover {
background: #1a1e22;
color: white;
text-decoration: none;
box-shadow: 0 2px 8px rgba(36, 41, 46, 0.3);
}
[data-theme='dark'] .githubLink {
background: #2d333b;
color: white;
}
[data-theme='dark'] .githubLink:hover {
background: #404852;
color: white;
}
.docsLink {
background: var(--ifm-color-primary-lightest);
color: var(--ifm-color-primary-darker);
}
.docsLink:hover {
background: var(--ifm-color-primary);
color: white;
text-decoration: none;
}
.telegramLink {
background: #0088cc;
color: white;
}
.telegramLink:hover {
background: #006699;
color: white;
text-decoration: none;
}
[data-theme='dark'] .telegramLink:hover {
background: #33adff;
color: white;
}
.websiteLink {
background: #0097a7;
color: white;
}
.websiteLink:hover {
background: #00838f;
color: white;
text-decoration: none;
}
[data-theme='dark'] .websiteLink {
background: #00acc1;
color: white;
}
[data-theme='dark'] .websiteLink:hover {
background: #00bcd4;
color: white;
}
.downloadLink {
background: #475569;
color: white;
}
.downloadLink:hover {
background: #334155;
color: white;
text-decoration: none;
box-shadow: 0 2px 8px rgba(71, 85, 105, 0.3);
}
[data-theme='dark'] .downloadLink {
background: #64748b;
color: white;
}
[data-theme='dark'] .downloadLink:hover {
background: #475569;
color: white;
}
/* Mobile Responsive */
@media (max-width: 768px) {
.coreBadge {
padding: 0.5rem 0.75rem;
font-size: 0.7rem;
gap: 0.4rem;
}
.coreIcon {
font-size: 0.95rem;
}
.coreIconSvg {
width: 16px;
height: 16px;
}
.coreLabel {
font-size: 0.7rem;
}
.badgesRow {
gap: 0.4rem;
}
.hwidBadge,
.starsBadge,
.featuredBadge {
padding: 0.3rem 0.5rem;
font-size: 0.6rem;
}
.cardContent {
padding: 1rem;
gap: 0.75rem;
}
.clientTitle {
font-size: 1rem;
}
.description {
font-size: 0.85rem;
}
.link {
padding: 0.45rem 0.75rem;
min-height: 32px;
font-size: 0.75rem;
}
}

View File

@@ -0,0 +1,43 @@
import React from 'react'
import ClientCard from '@site/src/components/ClientCard'
import type { Client, Platform } from '@site/src/data/clients'
import { getClientsByPlatform } from '@site/src/data/clients'
interface ClientsListProps {
platform: Platform
}
export default function ClientsList({ platform }: ClientsListProps) {
const clients = getClientsByPlatform(platform)
return (
<>
{clients.map((client: Client) => {
// Merge platform-specific download link with general links
const platformDownloadLink = client.downloadLinks?.[platform]
const links = {
...client.links,
...(platformDownloadLink && { download: platformDownloadLink })
}
return (
<ClientCard
key={`${client.id}-${platform}`}
id={`${client.id}-${platform}`}
title={client.name}
description={client.description}
core={client.core}
coreIcon={client.coreIcon}
author={client.author}
authorLink={client.authorLink}
githubRepo={client.githubRepo}
featured={client.badges?.featured}
hwidSupported={client.badges?.hwid}
links={links}
/>
)
})}
</>
)
}

406
src/data/clients.ts Normal file
View File

@@ -0,0 +1,406 @@
/**
* Clients Data Source
*
* This file contains all proxy clients information.
* Each client can support multiple platforms with platform-specific download links.
*
* @example
* {
* id: 'my-client',
* name: 'My Client',
* core: 'mihomo',
* platforms: ['android', 'windows'],
* description: 'Amazing proxy client',
* badges: {
* featured: true, // Shows first on all platforms
* hwid: true // Shows HWID badge
* },
* githubRepo: 'user/repo', // Shows GitHub stars badge
* downloadLinks: {
* android: 'https://play.google.com/...', // Android-specific download
* windows: 'https://github.com/.../releases' // Windows-specific download
* },
* links: {
* github: 'https://github.com/...',
* telegram: 'https://t.me/...',
* website: 'https://...',
* docs: 'https://...'
* }
* }
*/
export type CoreType = 'mihomo' | 'other' | 'singbox' | 'xray'
export type Platform = 'android' | 'ios' | 'linux' | 'macos' | 'windows'
export interface Client {
author?: string
authorLink?: string
badges?: {
featured?: boolean
hwid?: boolean
}
core: CoreType
coreIcon?: string
description: string
downloadLinks?: {
android?: string
ios?: string
linux?: string
macos?: string
windows?: string
}
githubRepo?: string
id: string
links?: {
docs?: string
github?: string
telegram?: string
website?: string
}
name: string
platforms: Platform[]
}
export const CLIENTS: Client[] = [
{
id: 'happ',
name: 'Happ',
core: 'xray',
platforms: ['android', 'ios', 'macos', 'windows'],
description: 'Modern and feature-rich proxy client for Android, iOS, macOS, and Windows.',
badges: {
featured: true,
hwid: true
},
downloadLinks: {
android: 'https://play.google.com/store/apps/details?id=com.happproxy',
ios: 'https://apps.apple.com/us/app/happ-proxy-utility/id6504287215',
macos: 'https://apps.apple.com/us/app/happ-proxy-utility/id6504287215',
windows:
'https://github.com/Happ-proxy/happ-desktop/releases/latest/download/setup-Happ.x86.exe',
linux: 'https://github.com/Happ-proxy/happ-desktop/releases/'
},
links: {
website: 'https://happ.su/main',
telegram: 'https://t.me/happ_chat'
}
},
{
id: 'flclashx',
name: 'FlClashX',
core: 'mihomo',
platforms: ['android', 'windows', 'macos', 'linux'],
description: 'Fork of FlClash with improvements and additional features.',
badges: {
featured: true,
hwid: true
},
githubRepo: 'pluralplay/flclashx',
downloadLinks: {
android: 'https://github.com/pluralplay/FlClashX/releases',
windows: 'https://github.com/pluralplay/FlClashX/releases',
macos: 'https://github.com/pluralplay/FlClashX/releases',
linux: 'https://github.com/pluralplay/FlClashX/releases'
},
links: {
github: 'https://github.com/pluralplay/FlClashX',
telegram: 'https://t.me/flclashx'
}
},
{
id: 'clash-meta-android',
name: 'Clash Meta for Android',
core: 'mihomo',
platforms: ['android'],
description: 'A powerful Mihomo-based proxy client for Android',
githubRepo: 'MetaCubeX/ClashMetaForAndroid',
downloadLinks: {
android: 'https://github.com/MetaCubeX/ClashMetaForAndroid/releases'
},
links: {
github: 'https://github.com/MetaCubeX/ClashMetaForAndroid'
}
},
{
id: 'flclash',
name: 'FlClash',
core: 'mihomo',
platforms: ['android', 'windows', 'macos', 'linux'],
description: 'Multi-platform proxy client based on ClashMeta, simple and easy to use',
githubRepo: 'chen08209/FlClash',
downloadLinks: {
android: 'https://github.com/chen08209/FlClash/releases',
windows: 'https://github.com/chen08209/FlClash/releases',
macos: 'https://github.com/chen08209/FlClash/releases',
linux: 'https://github.com/chen08209/FlClash/releases'
},
links: {
github: 'https://github.com/chen08209/FlClash'
}
},
{
id: 'clash-mi',
name: 'Clash Mi',
core: 'mihomo',
platforms: ['android', 'ios'],
description: 'Mihomo client for Android and iOS (Alpha version)',
links: {
github: 'https://github.com/placeholder/clash-mi'
}
},
{
id: 'onexray',
name: 'OneXray',
core: 'xray',
platforms: ['android', 'ios', 'windows', 'macos', 'linux'],
description: 'Lightweight X-Ray proxy client',
githubRepo: 'OneXray/OneXray',
downloadLinks: {
android: 'https://play.google.com/store/apps/details?id=net.yuandev.onexray',
ios: 'https://apps.apple.com/app/onexray/id6503296188',
windows: 'https://github.com/OneXray/OneXray/releases',
macos: 'https://apps.apple.com/app/onexray/id6503296188',
linux: 'https://github.com/OneXray/OneXray/releases'
},
links: {
github: 'https://github.com/OneXray/OneXray'
}
},
{
id: 'v2rayng',
name: 'V2rayNG',
core: 'xray',
platforms: ['android'],
description: 'Popular and widely-used V2Ray client for Android',
githubRepo: '2dust/v2rayNG',
downloadLinks: {
android: 'https://github.com/2dust/v2rayNG/releases'
},
links: {
github: 'https://github.com/2dust/v2rayNG'
}
},
{
id: 'v2box',
name: 'V2Box',
core: 'xray',
platforms: ['android', 'ios', 'macos'],
description: 'Simple V2Ray client with clean interface',
downloadLinks: {
android: 'https://play.google.com/store/apps/details?id=dev.hexasoftware.v2box',
ios: 'https://apps.apple.com/app/v2box-v2ray-client/id6446814690',
macos: 'https://apps.apple.com/app/v2box-v2ray-client/id6446814690'
}
},
{
id: 'simple-gui-client',
name: 'Simple GUI Client',
core: 'xray',
platforms: ['android'],
description: 'Minimalistic V2Ray GUI client for Android',
author: 'SaeedDev94',
authorLink: 'https://github.com/SaeedDev94',
githubRepo: 'SaeedDev94/Xray',
downloadLinks: {
android: 'https://github.com/SaeedDev94/Xray/releases'
},
links: {
github: 'https://github.com/SaeedDev94/Xray'
}
},
{
id: 'simplexray',
name: 'SimpleXray',
core: 'xray',
platforms: ['android'],
description: 'Straightforward Xray client for Android',
githubRepo: 'lhear/SimpleXray',
downloadLinks: {
android: 'https://github.com/lhear/SimpleXray/releases'
},
links: {
github: 'https://github.com/lhear/SimpleXray'
}
},
{
id: 'singbox',
name: 'sing-box',
core: 'singbox',
platforms: ['android', 'ios', 'macos'],
description: 'Universal proxy platform with multiple protocol support',
links: {
github: 'https://github.com/placeholder/sing-box',
website: 'https://play.google.com/store/apps/placeholder'
}
},
{
id: 'husi',
name: 'Husi',
core: 'singbox',
platforms: ['android'],
description: 'Feature-rich Sing-box based proxy client',
links: {
github: 'https://github.com/placeholder/husi'
}
},
{
id: 'nekobox',
name: 'NekoBox',
core: 'singbox',
platforms: ['android'],
description: 'Sing-box based proxy client with modern UI',
links: {
github: 'https://github.com/placeholder/nekobox'
}
},
{
id: 'karing',
name: 'Karing',
core: 'singbox',
platforms: ['android', 'ios', 'macos', 'windows'],
description: 'Multi-platform proxy client based on Sing-box core',
links: {
github: 'https://github.com/placeholder/karing'
}
},
{
id: 'hiddify',
name: 'Hiddify',
core: 'singbox',
platforms: ['android', 'ios', 'macos', 'windows', 'linux'],
description: 'Sing-box client (⚠️ No updates since October 2024)',
links: {
github: 'https://github.com/placeholder/hiddify'
}
},
{
id: 'prizrakbox',
name: 'Prizrak-Box',
core: 'mihomo',
platforms: ['windows', 'macos', 'linux'],
description:
'Desktop client with custom routing templates (includes built-in templates for Russia)',
githubRepo: 'legiz-ru/Prizrak-Box',
badges: {
hwid: true
},
links: {
github: 'https://github.com/legiz-ru/Prizrak-Box'
}
},
{
id: 'clash-verge',
name: 'Clash Verge',
core: 'mihomo',
platforms: ['windows', 'macos', 'linux'],
description: 'Modern Clash Meta GUI based on Tauri framework',
links: {
github: 'https://github.com/placeholder/clash-verge'
}
},
{
id: 'koalaclash',
name: 'Koala Clash',
core: 'mihomo',
platforms: ['windows', 'macos', 'linux'],
description: 'Fork of Clash Verge Rev with improvements and optimizations.',
githubRepo: 'coolcoala/clash-verge-rev-lite',
badges: {
hwid: true
},
links: {
github: 'https://github.com/coolcoala/clash-verge-rev-lite',
telegram: 'https://t.me/+WCL__GOFzZJkYjZi'
}
},
{
id: 'v2rayn',
name: 'V2rayN',
core: 'xray',
platforms: ['windows', 'macos', 'linux'],
description: 'Popular V2Ray client.',
links: {
github: 'https://github.com/placeholder/v2rayn'
}
},
{
id: 'nekoray',
name: 'NekoRay',
core: 'singbox',
platforms: ['windows', 'macos', 'linux'],
description: 'Feature-rich Sing-box based client.',
links: {
github: 'https://github.com/placeholder/nekoray'
}
},
{
id: 'streisand',
name: 'Streisand',
core: 'xray',
platforms: ['ios', 'macos'],
description: 'X-Ray client (⚠️ sometimes has connection issues)',
links: {
website: 'https://apps.apple.com/placeholder'
}
},
{
id: 'v2raytun',
name: 'V2rayTun',
core: 'xray',
platforms: ['ios', 'macos'],
description: 'V2Ray client with tunnel support',
links: {
website: 'https://apps.apple.com/placeholder'
}
},
{
id: 'stash',
name: 'Stash',
core: 'other',
platforms: ['ios', 'macos'],
description: 'Advanced proxy client ($7)',
links: {
website: 'https://apps.apple.com/placeholder',
docs: 'https://placeholder.wiki'
}
},
{
id: 'shadowrocket',
name: 'ShadowRocket',
core: 'other',
platforms: ['ios', 'macos'],
description: 'Popular proxy client ($3)',
links: {
website: 'https://apps.apple.com/placeholder'
}
},
{
id: 'loon',
name: 'Loon',
core: 'other',
platforms: ['ios', 'macos'],
description: 'Advanced proxy client with scripting support ($8)',
links: {
website: 'https://apps.apple.com/placeholder'
}
}
]
export function getClientsByPlatform(platform: Platform): Client[] {
return CLIENTS.filter((client) => client.platforms.includes(platform)).sort((a, b) => {
const aFeatured = a.badges?.featured ? 1 : 0
const bFeatured = b.badges?.featured ? 1 : 0
return bFeatured - aFeatured
})
}
export function getPlatformClients() {
return {
android: getClientsByPlatform('android'),
ios: getClientsByPlatform('ios'),
windows: getClientsByPlatform('windows'),
macos: getClientsByPlatform('macos'),
linux: getClientsByPlatform('linux')
}
}

View File

@@ -5,7 +5,9 @@ import HeroSection from '@site/src/components/HeroSection'
import CategoryNav from '@site/src/components/CategoryNav'
import GitHubStars from '@site/src/components/GitHubStars'
import ProjectCard from '@site/src/components/ProjectCard'
import ClientsList from '@site/src/components/ClientsList'
import MDXComponents from '@theme-original/MDXComponents'
import ClientCard from '@site/src/components/ClientCard'
import StatsBar from '@site/src/components/StatsBar'
import Button from '@site/src/components/Button'
@@ -15,6 +17,8 @@ export default {
CategoryNav,
GitHubStars,
ProjectCard,
ClientCard,
ClientsList,
ProjectsGrid,
CategorySection,
HeroSection,