Skip to content

Commit 7a1d4a2

Browse files
committed
Add missing Contributors
1 parent 82674bf commit 7a1d4a2

File tree

1 file changed

+219
-0
lines changed

1 file changed

+219
-0
lines changed
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
<template>
2+
<div class="contributors-container">
3+
<div class="contributors-header">
4+
<h2>Contributors</h2>
5+
<p class="contributors-description">
6+
Thanks to all the amazing people who have contributed to this project!
7+
</p>
8+
</div>
9+
10+
<div v-if="loading" class="loading-state">
11+
<div class="spinner"></div>
12+
<p>Loading contributors...</p>
13+
</div>
14+
15+
<div v-else-if="error" class="error-state">
16+
<p>{{ error }}</p>
17+
</div>
18+
19+
<div v-else class="contributors-grid">
20+
<a
21+
v-for="contributor in contributors"
22+
:key="contributor.id"
23+
:href="contributor.html_url"
24+
target="_blank"
25+
rel="noopener noreferrer"
26+
class="contributor-card"
27+
:title="contributor.login"
28+
>
29+
<img
30+
:src="contributor.avatar_url"
31+
:alt="contributor.login"
32+
class="contributor-avatar"
33+
loading="lazy"
34+
/>
35+
<div class="contributor-name">{{ contributor.login }}</div>
36+
</a>
37+
</div>
38+
</div>
39+
</template>
40+
41+
<script setup lang="ts">
42+
import { ref, onMounted } from 'vue';
43+
44+
interface Contributor {
45+
id: number;
46+
login: string;
47+
avatar_url: string;
48+
html_url: string;
49+
contributions: number;
50+
}
51+
52+
const contributors = ref<Contributor[]>([]);
53+
const loading = ref(true);
54+
const error = ref('');
55+
56+
const fetchContributors = async () => {
57+
try {
58+
loading.value = true;
59+
error.value = '';
60+
61+
const response = await fetch(
62+
'https://api.github.com/repos/crazywhalecc/static-php-cli/contributors?per_page=24'
63+
);
64+
65+
if (!response.ok) {
66+
throw new Error('Failed to fetch contributors');
67+
}
68+
69+
const data = await response.json();
70+
contributors.value = data;
71+
} catch (err) {
72+
error.value = 'Failed to load contributors. Please try again later.';
73+
console.error('Error fetching contributors:', err);
74+
} finally {
75+
loading.value = false;
76+
}
77+
};
78+
79+
onMounted(() => {
80+
fetchContributors();
81+
});
82+
</script>
83+
84+
<style scoped>
85+
.contributors-container {
86+
margin: 48px auto;
87+
padding: 32px 24px;
88+
max-width: 1152px;
89+
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-bg) 100%);
90+
border-radius: 16px;
91+
border: 1px solid var(--vp-c-divider);
92+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
93+
}
94+
95+
.contributors-header {
96+
text-align: center;
97+
margin-bottom: 24px;
98+
}
99+
100+
.contributors-header h2 {
101+
font-size: 1.5rem;
102+
font-weight: 700;
103+
margin: 0 0 8px 0;
104+
background: linear-gradient(120deg, var(--vp-c-brand-1), var(--vp-c-brand-2));
105+
-webkit-background-clip: text;
106+
-webkit-text-fill-color: transparent;
107+
background-clip: text;
108+
}
109+
110+
.contributors-description {
111+
font-size: 0.95rem;
112+
color: var(--vp-c-text-2);
113+
margin: 0;
114+
line-height: 1.5;
115+
}
116+
117+
.loading-state,
118+
.error-state {
119+
text-align: center;
120+
padding: 40px 20px;
121+
color: var(--vp-c-text-2);
122+
}
123+
124+
.spinner {
125+
width: 40px;
126+
height: 40px;
127+
margin: 0 auto 16px;
128+
border: 4px solid var(--vp-c-divider);
129+
border-top-color: var(--vp-c-brand-1);
130+
border-radius: 50%;
131+
animation: spin 1s linear infinite;
132+
}
133+
134+
@keyframes spin {
135+
to {
136+
transform: rotate(360deg);
137+
}
138+
}
139+
140+
.contributors-grid {
141+
display: grid;
142+
grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
143+
gap: 16px;
144+
}
145+
146+
.contributor-card {
147+
display: flex;
148+
flex-direction: column;
149+
align-items: center;
150+
padding: 12px;
151+
background: var(--vp-c-bg);
152+
border-radius: 12px;
153+
border: 1px solid var(--vp-c-divider);
154+
transition: all 0.3s ease;
155+
text-decoration: none;
156+
color: var(--vp-c-text-1);
157+
}
158+
159+
.contributor-card:hover {
160+
transform: translateY(-4px);
161+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
162+
border-color: var(--vp-c-brand-1);
163+
}
164+
165+
.contributor-avatar {
166+
width: 60px;
167+
height: 60px;
168+
border-radius: 50%;
169+
border: 2px solid var(--vp-c-divider);
170+
transition: all 0.3s ease;
171+
margin-bottom: 8px;
172+
}
173+
174+
.contributor-card:hover .contributor-avatar {
175+
border-color: var(--vp-c-brand-1);
176+
transform: scale(1.05);
177+
}
178+
179+
.contributor-name {
180+
font-size: 12px;
181+
font-weight: 500;
182+
text-align: center;
183+
word-break: break-word;
184+
max-width: 100%;
185+
}
186+
187+
@media (max-width: 768px) {
188+
.contributors-container {
189+
margin: 32px 16px;
190+
padding: 24px 16px;
191+
}
192+
193+
.contributors-header h2 {
194+
font-size: 1.25rem;
195+
}
196+
197+
.contributors-description {
198+
font-size: 0.9rem;
199+
}
200+
201+
.contributors-grid {
202+
grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
203+
gap: 12px;
204+
}
205+
206+
.contributor-card {
207+
padding: 8px;
208+
}
209+
210+
.contributor-avatar {
211+
width: 48px;
212+
height: 48px;
213+
}
214+
215+
.contributor-name {
216+
font-size: 11px;
217+
}
218+
}
219+
</style>

0 commit comments

Comments
 (0)