Skip to content

Commit 110c5a5

Browse files
authored
Merge pull request #25 from mc-cloud-town/feat/opensource-redesign-and-perf
Feat/opensource redesign and perf
2 parents 08c052a + 43d772e commit 110c5a5

10 files changed

Lines changed: 735 additions & 85 deletions

File tree

src/components/common/StatusShowingGroup.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,21 @@ const StatusContainer = styled.div`
88
display: flex;
99
justify-content: center;
1010
align-items: center;
11+
gap: 10px;
12+
padding: 48px 0;
13+
color: var(--text-secondary);
1114
12-
i {
13-
background-color: #feffe6 !important;
15+
.anticon {
16+
color: var(--color-primary);
1417
}
1518
16-
span {
17-
margin-left: 10px;
18-
color: #feffe6;
19+
.ant-spin-dot-item {
20+
background-color: var(--color-primary);
21+
}
22+
23+
.ant-typography {
24+
color: inherit;
25+
margin-bottom: 0;
1926
}
2027
`;
2128

@@ -34,7 +41,7 @@ export const StatusShowingGroup: React.FC<StatusShowingGroupProps> = ({
3441
<>
3542
{error && (
3643
<StatusContainer>
37-
<WarningOutlined style={{ fontSize: '24px', color: '#feffe6' }} />
44+
<WarningOutlined style={{ fontSize: '24px' }} />
3845
<Typography.Text>{t('error')}</Typography.Text>
3946
</StatusContainer>
4047
)}
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import styled from 'styled-components';
2+
import { useTranslation } from 'react-i18next';
3+
import { DatabaseOutlined, FireOutlined, StarOutlined } from '@ant-design/icons';
4+
5+
const HeroCard = styled.div`
6+
display: flex;
7+
justify-content: center;
8+
margin-bottom: 64px;
9+
padding: 48px;
10+
border-radius: var(--radius-xl);
11+
border: 1px solid var(--border-color);
12+
background: linear-gradient(145deg, var(--bg-elevated), var(--bg-primary));
13+
box-shadow: var(--shadow-sm);
14+
position: relative;
15+
overflow: hidden;
16+
17+
&::before {
18+
content: '';
19+
position: absolute;
20+
top: 0;
21+
left: 0;
22+
right: 0;
23+
height: 6px;
24+
background: var(--gradient-accent);
25+
opacity: 0.8;
26+
}
27+
28+
@media (min-width: 900px) {
29+
align-items: center;
30+
}
31+
32+
@media (max-width: 768px) {
33+
padding: 32px 24px;
34+
}
35+
`;
36+
37+
const MetaGrid = styled.div`
38+
display: flex;
39+
justify-content: center;
40+
gap: 48px;
41+
flex-wrap: wrap;
42+
43+
@media (max-width: 640px) {
44+
width: 100%;
45+
flex-direction: column;
46+
justify-content: center;
47+
gap: 24px;
48+
}
49+
`;
50+
51+
const MetaCard = styled.div`
52+
display: flex;
53+
flex-direction: column;
54+
align-items: center;
55+
gap: 12px;
56+
padding: 24px 40px;
57+
border-radius: var(--radius-lg);
58+
background: var(--bg-secondary);
59+
border: 1px solid transparent;
60+
transition: all 0.3s ease;
61+
62+
&:hover {
63+
transform: translateY(-4px);
64+
box-shadow: var(--shadow-md);
65+
border-color: var(--border-color);
66+
background: var(--bg-elevated);
67+
68+
.anticon {
69+
color: var(--color-accent);
70+
transform: scale(1.1);
71+
}
72+
}
73+
74+
@media (max-width: 640px) {
75+
width: 100%;
76+
padding: 24px;
77+
}
78+
`;
79+
80+
const MetaLabel = styled.div`
81+
display: flex;
82+
align-items: center;
83+
gap: 8px;
84+
color: var(--text-tertiary);
85+
font-size: 0.95rem;
86+
font-weight: 600;
87+
text-transform: uppercase;
88+
letter-spacing: 0.1em;
89+
90+
.anticon {
91+
font-size: 1.1rem;
92+
transition: all 0.3s ease;
93+
}
94+
`;
95+
96+
const MetaValue = styled.div`
97+
font-family: var(--font-heading);
98+
font-size: 3.2rem;
99+
font-weight: 800;
100+
color: var(--text-primary);
101+
line-height: 1;
102+
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
103+
`;
104+
105+
interface HeroSectionProps {
106+
loading: boolean;
107+
stats: {
108+
totalCount: number;
109+
activeCount: number;
110+
totalStars: number;
111+
};
112+
}
113+
114+
const getNumberLocale = (language: string) => {
115+
const normalizedLocale = language.replace('_', '-');
116+
117+
return Intl.NumberFormat.supportedLocalesOf([normalizedLocale])[0] ?? 'en-US';
118+
};
119+
120+
const HeroSection = ({ loading, stats }: HeroSectionProps) => {
121+
const { t, i18n } = useTranslation();
122+
const numberLocale = getNumberLocale(i18n.resolvedLanguage ?? i18n.language);
123+
124+
const formatValue = (value: number) => {
125+
if (loading) {
126+
return '--';
127+
}
128+
129+
return value.toLocaleString(numberLocale);
130+
};
131+
132+
return (
133+
<HeroCard>
134+
<MetaGrid>
135+
<MetaCard>
136+
<MetaLabel>
137+
<DatabaseOutlined /> {t('opensource.stats.total')}
138+
</MetaLabel>
139+
<MetaValue>{formatValue(stats.totalCount)}</MetaValue>
140+
</MetaCard>
141+
<MetaCard>
142+
<MetaLabel>
143+
<FireOutlined /> {t('opensource.stats.active')}
144+
</MetaLabel>
145+
<MetaValue>{formatValue(stats.activeCount)}</MetaValue>
146+
</MetaCard>
147+
<MetaCard>
148+
<MetaLabel>
149+
<StarOutlined /> {t('opensource.stats.stars')}
150+
</MetaLabel>
151+
<MetaValue>{formatValue(stats.totalStars)}</MetaValue>
152+
</MetaCard>
153+
</MetaGrid>
154+
</HeroCard>
155+
);
156+
};
157+
158+
export default HeroSection;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import styled from 'styled-components';
2+
3+
export const RepoSection = styled.section`
4+
background: var(--bg-primary);
5+
background-image: radial-gradient(circle at top right, rgba(0, 0, 0, 0.02) 0%, transparent 60%),
6+
radial-gradient(circle at bottom left, rgba(0, 0, 0, 0.02) 0%, transparent 60%);
7+
padding: 80px 24px 100px;
8+
position: relative;
9+
10+
[data-theme='dark'] & {
11+
background-image: radial-gradient(circle at top right, rgba(255, 255, 255, 0.03) 0%, transparent 60%),
12+
radial-gradient(circle at bottom left, rgba(255, 255, 255, 0.03) 0%, transparent 60%);
13+
}
14+
15+
@media (max-width: 768px) {
16+
padding: 56px 16px 80px;
17+
}
18+
`;
19+
20+
export const Content = styled.div`
21+
max-width: 1280px;
22+
margin: 0 auto;
23+
`;
24+
25+
export const Grid = styled.div`
26+
display: grid;
27+
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
28+
gap: 32px;
29+
30+
@media (max-width: 640px) {
31+
grid-template-columns: 1fr;
32+
gap: 24px;
33+
}
34+
`;
35+
36+
export const EmptyState = styled.div`
37+
display: flex;
38+
flex-direction: column;
39+
justify-content: center;
40+
align-items: center;
41+
padding: 80px 24px;
42+
color: var(--text-secondary);
43+
font-size: 1.1rem;
44+
text-align: center;
45+
background: var(--bg-elevated);
46+
border-radius: var(--radius-xl);
47+
border: 1px dashed var(--border-color);
48+
margin-top: 32px;
49+
backdrop-filter: blur(8px);
50+
`;
51+
52+
const languageColors: Record<string, string> = {
53+
TypeScript: '#3178c6',
54+
JavaScript: '#f7df1e',
55+
Vue: '#42b883',
56+
React: '#61dafb',
57+
Python: '#3776ab',
58+
Java: '#f89820',
59+
Kotlin: '#7f52ff',
60+
Go: '#00add8',
61+
Rust: '#dea584',
62+
Shell: '#89e051',
63+
HTML: '#e34f26',
64+
CSS: '#1572b6',
65+
SCSS: '#cc6699',
66+
};
67+
68+
export const getLanguageColor = (language: string | null): string => {
69+
if (!language) return 'var(--color-accent)';
70+
return languageColors[language] ?? 'var(--color-primary)';
71+
};

0 commit comments

Comments
 (0)