@@ -23,7 +23,9 @@ const mobileMenuOpen = ref<boolean>(false);
2323const activeOS = ref <string >(' arch' );
2424const setupStep = ref <number >(0 );
2525const isScrolled = ref <boolean >(false );
26- const starCount = ref <string >(' 160+' );
26+ const starCount = ref <string >(' 0' );
27+ const contributorCount = ref <number >(0 );
28+ const REPO = ' LotusInputMethod/fcitx5-lotus' ;
2729
2830// --- CATPPUCCIN THEME LOGIC ---
2931const catppuccinThemes = [' latte' , ' frappe' , ' macchiato' , ' mocha' ] as const ;
@@ -71,7 +73,6 @@ const startTyping = () => {
7173};
7274
7375const fetchGithubStars = async () => {
74- const REPO = ' LotusInputMethod/fcitx5-lotus' ;
7576 const CACHE_KEY = ' lotus_stars_cache' ;
7677 const CACHE_TIME_KEY = ' lotus_stars_timestamp' ;
7778 const TWO_HOURS = 2 * 60 * 60 * 1000 ;
@@ -102,6 +103,67 @@ const fetchGithubStars = async () => {
102103 }
103104};
104105
106+ const fetchContributors = async () => {
107+ const CACHE_KEY = ' lotus_contributors_cache' ;
108+ const CACHE_TIME_KEY = ' lotus_contributors_timestamp' ;
109+ const TWO_HOURS = 2 * 60 * 60 * 1000 ;
110+
111+ const specialRoles: Record <number , string > = {
112+ 57983253 : ' Founder' , // nhktmdzhg
113+ };
114+
115+ const blacklist = [' thanhpy2009' , ' loccun' ];
116+
117+ try {
118+ const cachedData = localStorage .getItem (CACHE_KEY );
119+ const lastFetch = localStorage .getItem (CACHE_TIME_KEY );
120+ const now = Date .now ();
121+
122+ if (cachedData && lastFetch && now - parseInt (lastFetch ) < TWO_HOURS ) {
123+ const parsed = JSON .parse (cachedData );
124+ const filtered = parsed .filter (
125+ (c : any ) => ! blacklist .includes (c .name ) && ! c .name .includes (' [bot]' ),
126+ );
127+ contributors .value = filtered ;
128+ contributorCount .value = filtered .length ;
129+ return ;
130+ }
131+
132+ const response = await fetch (
133+ ` https://api.github.com/repos/${REPO }/contributors ` ,
134+ );
135+ if (! response .ok ) throw new Error (' GitHub API error' );
136+
137+ const data = await response .json ();
138+ const fetchedContributors: Contributor [] = data
139+ .filter (
140+ (item : any ) =>
141+ ! blacklist .includes (item .login ) &&
142+ item .type !== ' Bot' &&
143+ ! item .login .includes (' [bot]' ),
144+ )
145+ .map ((item : any ) => ({
146+ id: item .id ,
147+ name: item .login ,
148+ role: specialRoles [item .id ] || ' Contributor' ,
149+ avatar: item .avatar_url ,
150+ githubUrl: item .html_url ,
151+ }));
152+
153+ contributors .value = fetchedContributors ;
154+ contributorCount .value = fetchedContributors .length ;
155+ localStorage .setItem (CACHE_KEY , JSON .stringify (fetchedContributors ));
156+ localStorage .setItem (CACHE_TIME_KEY , now .toString ());
157+ } catch (error ) {
158+ console .error (' Lỗi khi lấy contributor từ GitHub:' , error );
159+ const oldCache = localStorage .getItem (CACHE_KEY );
160+ if (oldCache ) {
161+ contributors .value = JSON .parse (oldCache );
162+ contributorCount .value = contributors .value .length ;
163+ }
164+ }
165+ };
166+
105167onMounted (() => {
106168 const savedTheme = localStorage .getItem (' catppuccin-theme' );
107169 if (savedTheme && catppuccinThemes .includes (savedTheme as CatppuccinTheme )) {
@@ -119,6 +181,7 @@ onMounted(() => {
119181 window .addEventListener (' scroll' , handleScroll );
120182 startTyping ();
121183 fetchGithubStars ();
184+ fetchContributors ();
122185});
123186
124187onUnmounted (() => {
@@ -266,37 +329,13 @@ const typingModes: TypingMode[] = [
266329];
267330
268331interface Contributor {
332+ id: number ;
269333 name: string ;
270334 role: string ;
271335 avatar: string ;
336+ githubUrl: string ;
272337}
273- const contributors: Contributor [] = [
274- {
275- name: ' Nguyen Hoang Ky' ,
276- role: ' Founder' ,
277- avatar: ' https://avatars.githubusercontent.com/u/57983253?v=4' ,
278- },
279- {
280- name: ' Huỳnh Thiện Lộc' ,
281- role: ' Contributor' ,
282- avatar: ' https://avatars.githubusercontent.com/u/148019203?v=4' ,
283- },
284- {
285- name: ' Nguyễn Hồng Hiệp' ,
286- role: ' Contributor' ,
287- avatar: ' https://avatars.githubusercontent.com/u/57614330?v=4' ,
288- },
289- {
290- name: ' Đặng Quang Hiển' ,
291- role: ' Contributor' ,
292- avatar: ' https://avatars.githubusercontent.com/u/83270073?v=4' ,
293- },
294- {
295- name: ' Zebra2711' ,
296- role: ' Contributor' ,
297- avatar: ' https://avatars.githubusercontent.com/u/89755535?v=4' ,
298- },
299- ];
338+ const contributors = ref <Contributor []>([]);
300339
301340// --- COMMANDS ---
302341const commands: Record <string , string > = {
@@ -449,7 +488,7 @@ const copyToClipboard = async (text: string | undefined): Promise<void> => {
449488 <span >Distros hỗ trợ</span >
450489 </div >
451490 <div class =" stat-item" >
452- <strong >5 </strong >
491+ <strong >{{ contributorCount }} </strong >
453492 <span >Người đóng góp</span >
454493 </div >
455494 </div >
@@ -669,7 +708,12 @@ const copyToClipboard = async (text: string | undefined): Promise<void> => {
669708 </div >
670709
671710 <div class =" contributors-flex" >
672- <div v-for =" c in contributors" :key =" c.name" class =" contributor-item" >
711+ <div
712+ v-for =" c in contributors"
713+ :key =" c.name"
714+ class =" contributor-item"
715+ @click =" openLink(c.githubUrl)"
716+ >
673717 <el-avatar :size =" 80" :src =" c.avatar" class =" contributor-avatar" />
674718 <div class =" c-name" >{{ c.name }}</div >
675719 <div class =" c-role" >{{ c.role }}</div >
0 commit comments