@@ -6,6 +6,16 @@ const CONFIG = JSON.parse(fs.readFileSync('config.json', 'utf8'));;
66// Couleurs officielles GitHub (NE PAS MODIFIER)
77const LANGUAGE_COLORS = JSON . parse ( fs . readFileSync ( 'github_colors.json' , 'utf8' ) ) ;
88
9+ // Icônes SVG pour les stats
10+ const ICONS = {
11+ star : `<path fill-rule="evenodd" d="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25z"/>` ,
12+ commit : `<path fill-rule="evenodd" d="M11.93 8.5a4.002 4.002 0 01-7.86 0H.75a.75.75 0 010-1.5h3.32a4.002 4.002 0 017.86 0h3.32a.75.75 0 010 1.5h-3.32zm-1.43-.75a2.5 2.5 0 10-5 0 2.5 2.5 0 005 0z"/>` ,
13+ pullRequest : `<path fill-rule="evenodd" d="M7.177 3.073L9.573.677A.25.25 0 0110 .854v4.792a.25.25 0 01-.427.177L7.177 3.427a.25.25 0 010-.354zM3.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122v5.256a2.251 2.251 0 11-1.5 0V5.372A2.25 2.25 0 011.5 3.25zM11 2.5h-1V4h1a1 1 0 011 1v5.628a2.251 2.251 0 101.5 0V5A2.5 2.5 0 0011 2.5zm1 10.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.75 12a.75.75 0 100 1.5.75.75 0 000-1.5z"/>` ,
14+ issue : `<path d="M8 9.5a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"/><path fill-rule="evenodd" d="M8 0a8 8 0 100 16A8 8 0 008 0zM1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0z"/>` ,
15+ contrib : `<path fill-rule="evenodd" d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"/>` ,
16+ github : `<path fill-rule="evenodd" 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"/>`
17+ } ;
18+
919async function fetchGitHubStats ( username , token ) {
1020 console . log ( `📊 Récupération des stats pour ${ username } ...` ) ;
1121
@@ -53,6 +63,143 @@ function getLanguageColor(language) {
5363 return LANGUAGE_COLORS [ language ] || '#858585' ;
5464}
5565
66+ async function fetchGitHubUserStats ( username , token ) {
67+ console . log ( `📊 Récupération des stats utilisateur pour ${ username } ...` ) ;
68+
69+ const query = `
70+ query($username: String!) {
71+ user(login: $username) {
72+ repositories(first: 100, ownerAffiliations: OWNER, isFork: false) {
73+ totalCount
74+ nodes {
75+ stargazerCount
76+ }
77+ }
78+ pullRequests(first: 1) {
79+ totalCount
80+ }
81+ issues(first: 1) {
82+ totalCount
83+ }
84+ repositoriesContributedTo(first: 1, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) {
85+ totalCount
86+ }
87+ contributionsCollection {
88+ totalCommitContributions
89+ restrictedContributionsCount
90+ }
91+ }
92+ }` ;
93+
94+ try {
95+ const response = await fetch ( 'https://api.github.com/graphql' , {
96+ method : 'POST' ,
97+ headers : {
98+ 'Authorization' : `bearer ${ token } ` ,
99+ 'Content-Type' : 'application/json' ,
100+ } ,
101+ body : JSON . stringify ( { query, variables : { username } } )
102+ } ) ;
103+
104+ if ( ! response . ok ) {
105+ throw new Error ( `GitHub GraphQL API error: ${ response . status } ` ) ;
106+ }
107+
108+ const data = await response . json ( ) ;
109+
110+ if ( data . errors ) {
111+ throw new Error ( data . errors [ 0 ] . message ) ;
112+ }
113+
114+ const user = data . data . user ;
115+ const totalStars = user . repositories . nodes . reduce ( ( sum , repo ) => sum + repo . stargazerCount , 0 ) ;
116+ const totalCommits = user . contributionsCollection . totalCommitContributions + user . contributionsCollection . restrictedContributionsCount ;
117+
118+ const stats = {
119+ stars : totalStars ,
120+ commits : totalCommits ,
121+ pullRequests : user . pullRequests . totalCount ,
122+ issues : user . issues . totalCount ,
123+ contributedTo : user . repositoriesContributedTo . totalCount
124+ } ;
125+
126+ console . log ( `✅ Stats utilisateur récupérées:` , stats ) ;
127+ return stats ;
128+ } catch ( error ) {
129+ console . error ( '❌ Erreur lors de la récupération des stats utilisateur:' , error . message ) ;
130+ throw error ;
131+ }
132+ }
133+
134+ function formatNumber ( num ) {
135+ if ( num >= 1000000 ) {
136+ return ( num / 1000000 ) . toFixed ( 1 ) + 'M' ;
137+ } else if ( num >= 1000 ) {
138+ return ( num / 1000 ) . toFixed ( 1 ) + 'k' ;
139+ }
140+ return num . toString ( ) ;
141+ }
142+
143+ function generateUserStatsSVG ( stats , username ) {
144+ const statItems = [
145+ { label : 'Total Stars' , value : stats . stars , icon : ICONS . star } ,
146+ { label : 'Total Commits' , value : stats . commits , icon : ICONS . commit } ,
147+ { label : 'Total PRs' , value : stats . pullRequests , icon : ICONS . pullRequest } ,
148+ { label : 'Total Issues' , value : stats . issues , icon : ICONS . issue } ,
149+ { label : 'Contributed to' , value : stats . contributedTo , icon : ICONS . contrib }
150+ ] ;
151+
152+ const statsTitle = CONFIG . STATS_TITLE || `${ username } 's GitHub Stats` ;
153+ const iconColor = CONFIG . ICON_COLOR || '#6e7681' ;
154+ const valueColor = CONFIG . VALUE_COLOR || CONFIG . TEXT_COLOR ;
155+
156+ let itemsY = 55 ;
157+ const statsItems = statItems . map ( item => {
158+ const formattedValue = formatNumber ( item . value ) ;
159+ const itemSVG = `
160+ <g transform="translate(25, ${ itemsY } )">
161+ <svg width="16" height="16" viewBox="0 0 16 16" fill="${ iconColor } ">
162+ ${ item . icon }
163+ </svg>
164+ <text x="28" y="12" font-size="14" fill="${ CONFIG . TEXT_COLOR } ">${ item . label } :</text>
165+ <text x="145" y="12" font-size="14" font-weight="600" fill="${ valueColor } ">${ formattedValue } </text>
166+ </g>` ;
167+ itemsY += 30 ;
168+ return itemSVG ;
169+ } ) . join ( '' ) ;
170+
171+ const height = 230 ;
172+ const width = 420 ;
173+
174+ return `<?xml version="1.0" encoding="UTF-8"?>
175+ <svg width="${ width } " height="${ height } " xmlns="http://www.w3.org/2000/svg">
176+ <defs>
177+ <style>
178+ @import url('https://fonts.googleapis.com/css2?family=Segoe+UI:wght@400;500;600&display=swap');
179+ * { font-family: 'Segoe UI', Ubuntu, sans-serif; }
180+ </style>
181+ </defs>
182+
183+ <!-- Background -->
184+ <rect width="${ width } " height="${ height } " fill="${ CONFIG . BG_COLOR } " rx="10" stroke="${ CONFIG . BORDER_COLOR } " stroke-width="1"/>
185+
186+ <!-- Title -->
187+ <text x="25" y="35" font-size="18" fill="${ CONFIG . TITLE_COLOR } " font-weight="600">
188+ ${ statsTitle }
189+ </text>
190+
191+ <!-- Stats Items -->
192+ ${ statsItems }
193+
194+ <!-- GitHub Logo -->
195+ <g transform="translate(${ width - 100 } , ${ height / 2 - 40 } )">
196+ <svg width="80" height="80" viewBox="0 0 16 16" fill="${ iconColor } " opacity="0.3">
197+ ${ ICONS . github }
198+ </svg>
199+ </g>
200+ </svg>` ;
201+ }
202+
56203function generateSVG ( languageStats , topN = 5 ) {
57204 // Trier et limiter
58205 const sortedLangs = Object . entries ( languageStats )
@@ -165,6 +312,12 @@ async function main() {
165312 console . log ( ` ✅ ${ filename } ` ) ;
166313 } ) ;
167314
315+ // Générer les stats utilisateur
316+ const userStats = await fetchGitHubUserStats ( CONFIG . USERNAME , token ) ;
317+ const userStatsSVG = generateUserStatsSVG ( userStats , CONFIG . USERNAME ) ;
318+ fs . writeFileSync ( 'github-stats.svg' , userStatsSVG ) ;
319+ console . log ( ` ✅ github-stats.svg` ) ;
320+
168321 console . log ( '\n🎉 Toutes les images ont été générées avec succès !' ) ;
169322 } catch ( error ) {
170323 console . error ( '❌ Erreur lors de la génération:' , error ) ;
0 commit comments