Skip to content

Commit 171b6d9

Browse files
authored
Update index.html
1 parent 6c69973 commit 171b6d9

1 file changed

Lines changed: 60 additions & 34 deletions

File tree

index.html

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,10 @@
505505
<div>
506506
<div style="font-size:12px;color:var(--text)" id="settings-username"></div>
507507
<div style="font-size:11px;color:var(--text-muted);margin-top:2px">GitHub OAuth session — 30 day token</div>
508+
<div style="margin-top:8px;font-size:11px;color:var(--text-muted)">
509+
public profile: <a id="settings-public-url" href="#" target="_blank" style="color:var(--blue);text-decoration:none"></a>
510+
<button onclick="copyPublicURL()" style="background:transparent;border:1px solid var(--border);color:var(--text-muted);font-family:var(--font-mono);font-size:10px;padding:2px 8px;cursor:pointer;margin-left:8px;letter-spacing:.5px" id="copy-pub-btn">copy</button>
511+
</div>
508512
</div>
509513
<button class="btn-outline danger" onclick="logout()">[ logout ]</button>
510514
</div>
@@ -680,6 +684,15 @@
680684
window.location.href=`${API_BASE}/auth/github/login`;
681685
}
682686

687+
function copyPublicURL(){
688+
const url=window._publicURL||document.getElementById('settings-public-url')?.href;
689+
if(!url||url==='#')return;
690+
navigator.clipboard.writeText(url).then(()=>{
691+
const btn=document.getElementById('copy-pub-btn');
692+
if(btn){btn.textContent='copied!';setTimeout(()=>btn.textContent='copy',2000);}
693+
});
694+
}
695+
683696
function logout(){
684697
confirm('Log out?') && (AUTH_TOKEN='',ghToken='',userData={},repoData=[],eventData=[],langMap={},todos=[],plans=[],savedKeys=[],
685698
localStorage.removeItem('dd_token'),showScreen('login'));
@@ -785,6 +798,13 @@
785798
document.getElementById('meta-repos').textContent=userData.public_repos||0;
786799
document.getElementById('meta-followers').textContent=fmtNum(userData.followers||0);
787800
document.getElementById('sb-user').textContent=userData.login;
801+
// wire public profile URL
802+
if(userData.public_slug){
803+
const cleanPub=new URL('profile.html', window.location.href).href + '?u=' + userData.public_slug;
804+
const el=document.getElementById('settings-public-url');
805+
if(el){el.href=cleanPub;el.textContent=cleanPub;}
806+
window._publicURL=cleanPub;
807+
}
788808
document.getElementById('settings-username').textContent=`@${userData.login}`;
789809

790810
const stars=repoData.reduce((a,r)=>a+(r.stargazers_count||0),0);
@@ -1009,7 +1029,18 @@
10091029
const langs=Object.entries(langMap).sort((a,b)=>b[1]-a[1]).slice(0,6).map(([l])=>l);
10101030
const topRepos=[...repoData].sort((a,b)=>b.stargazers_count-a.stargazers_count).slice(0,5).map(r=>`${r.name}(★${r.stargazers_count},${r.language||'?'})`);
10111031
const stats={stars:repoData.reduce((a,r)=>a+(r.stargazers_count||0),0),forks:repoData.reduce((a,r)=>a+(r.forks_count||0),0),repos:userData.public_repos,followers:userData.followers};
1012-
const data=await api('POST','/api/insights',{languages:langs,top_repos:topRepos,stats,username:userData.login});
1032+
const controller=new AbortController();
1033+
const insightTimeout=setTimeout(()=>controller.abort(),15000);
1034+
let data;
1035+
try{
1036+
const r=await fetch(API_BASE+'/api/insights',{method:'POST',headers:{'Content-Type':'application/json','Authorization':`Bearer ${AUTH_TOKEN}`},body:JSON.stringify({languages:langs,top_repos:topRepos,stats,username:userData.login}),signal:controller.signal});
1037+
data=await r.json();
1038+
}catch(e){
1039+
clearTimeout(insightTimeout);
1040+
document.getElementById('insights-output').innerHTML=`<div style="color:var(--red);font-size:12px">// ${e.name==='AbortError'?'request timed out after 15s':e.message}</div>`;
1041+
return;
1042+
}
1043+
clearTimeout(insightTimeout);
10131044
if(data.error){document.getElementById('insights-output').innerHTML=`<div style="color:var(--red);font-size:12px">// ${data.message||data.error}</div>`;return}
10141045
document.getElementById('insights-output').innerHTML=(data.insights||[]).map(i=>`<div class="ai-line"><span class="ai-arrow">→</span><span>${i.insight}</span></div>`).join('');
10151046
}
@@ -1020,54 +1051,49 @@
10201051
const langs=Object.entries(langMap).sort((a,b)=>b[1]-a[1]).slice(0,4).map(([l])=>l);
10211052
const userRepoNames=new Set(repoData.map(r=>r.full_name||r.name));
10221053

1023-
// Large topic pool — pick 3 random ones each refresh
1024-
const ALL_TOPICS = [
1025-
'topic:cli','topic:tool','topic:bot','topic:security','topic:hacking',
1026-
'topic:iot','topic:monitoring','topic:dashboard','topic:terminal',
1027-
'topic:automation','topic:devops','topic:api','topic:game','topic:productivity',
1028-
'topic:reverse-engineering','topic:penetration-testing','topic:fuzzing',
1029-
'topic:network','topic:linux','topic:raspberry-pi','topic:arduino',
1030-
'topic:machine-learning','topic:data-science','topic:visualization',
1031-
'topic:compiler','topic:interpreter','topic:editor','topic:shell',
1054+
// Topic buckets — each bucket has related topics, pick 1 topic per query (OR logic)
1055+
const TOPIC_BUCKETS = [
1056+
['topic:security','topic:hacking','topic:penetration-testing','topic:ctf','topic:exploit'],
1057+
['topic:cli','topic:terminal','topic:shell','topic:command-line'],
1058+
['topic:tool','topic:developer-tools','topic:productivity','topic:automation'],
1059+
['topic:iot','topic:arduino','topic:raspberry-pi','topic:embedded'],
1060+
['topic:monitoring','topic:dashboard','topic:devops','topic:sysadmin'],
1061+
['topic:bot','topic:chatbot','topic:telegram-bot','topic:discord-bot'],
1062+
['topic:game','topic:gamedev','topic:puzzle'],
1063+
['topic:network','topic:networking','topic:proxy','topic:vpn'],
1064+
['topic:reverse-engineering','topic:malware','topic:forensics'],
1065+
['topic:api','topic:rest-api','topic:graphql'],
10321066
];
10331067

1034-
// Shuffle helper
10351068
function shuffle(arr) {
10361069
const a = [...arr];
1037-
for (let i = a.length-1; i > 0; i--) {
1038-
const j = Math.floor(Math.random() * (i+1));
1039-
[a[i],a[j]] = [a[j],a[i]];
1040-
}
1070+
for (let i=a.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[a[i],a[j]]=[a[j],a[i]];}
10411071
return a;
10421072
}
10431073

1044-
// Random star threshold: 100–1000
1045-
function randStars() { return [100,200,300,500,1000][Math.floor(Math.random()*5)]; }
1046-
// Random sort
1047-
function randSort() { return ['updated','stars'][Math.floor(Math.random()*2)]; }
1048-
// Random page (1-3) so same query returns different results
1049-
function randPage() { return Math.floor(Math.random()*3)+1; }
1074+
function randPage() { return Math.floor(Math.random()*4)+1; }
1075+
function randSort() { return ['updated','stars','help-wanted-issues'][Math.floor(Math.random()*3)]; }
10501076

1051-
// Pick 3 random topics per query
1052-
const pickedTopics = shuffle(ALL_TOPICS).slice(0,3).join('+');
1053-
const pickedTopics2 = shuffle(ALL_TOPICS).slice(0,3).join('+');
1054-
const pickedTopics3 = shuffle(ALL_TOPICS).slice(0,3).join('+');
1077+
// Pick a single topic from a random bucket
1078+
function pickTopic() {
1079+
const bucket = TOPIC_BUCKETS[Math.floor(Math.random()*TOPIC_BUCKETS.length)];
1080+
return bucket[Math.floor(Math.random()*bucket.length)];
1081+
}
10551082

1056-
// Shuffle langs and pick randomly
10571083
const shuffledLangs = shuffle(langs);
1084+
const t1=pickTopic(), t2=pickTopic(), t3=pickTopic();
10581085

10591086
try {
10601087
const headers={'Authorization':`token ${ghToken}`,'Accept':'application/vnd.github.v3+json'};
10611088

1089+
// Each query uses ONE topic (not ANDed) — much more results
10621090
const queries = [
1063-
// User's top language + random topics
1064-
`https://api.github.com/search/repositories?q=language:${encodeURIComponent(shuffledLangs[0]||'Python')}+${pickedTopics}+stars:>${randStars()}+is:public&sort=${randSort()}&order=desc&per_page=15&page=${randPage()}`,
1065-
// Second language if exists
1066-
shuffledLangs[1]
1067-
? `https://api.github.com/search/repositories?q=language:${encodeURIComponent(shuffledLangs[1])}+${pickedTopics2}+stars:>${randStars()}+is:public&sort=${randSort()}&order=desc&per_page=15&page=${randPage()}`
1068-
: `https://api.github.com/search/repositories?q=${pickedTopics2}+stars:>500+is:public&sort=updated&order=desc&per_page=15&page=${randPage()}`,
1069-
// Pure random topic set — no language filter
1070-
`https://api.github.com/search/repositories?q=${pickedTopics3}+stars:>${randStars()}+is:public&sort=${randSort()}&order=desc&per_page=15&page=${randPage()}`,
1091+
// Language + single topic — broad
1092+
`https://api.github.com/search/repositories?q=language:${encodeURIComponent(shuffledLangs[0]||'Python')}+${t1}+stars:>50+is:public+fork:false&sort=${randSort()}&order=desc&per_page=20&page=${randPage()}`,
1093+
// Second lang + different topic
1094+
`https://api.github.com/search/repositories?q=language:${encodeURIComponent(shuffledLangs[1]||shuffledLangs[0]||'JavaScript')}+${t2}+stars:>50+is:public+fork:false&sort=${randSort()}&order=desc&per_page=20&page=${randPage()}`,
1095+
// No language filter — just a topic, broader catch
1096+
`https://api.github.com/search/repositories?q=${t3}+stars:>100+is:public+fork:false&sort=${randSort()}&order=desc&per_page=20&page=${randPage()}`,
10711097
];
10721098

10731099
const results = await Promise.all(queries.map(url=>fetch(url,{headers}).then(r=>r.json()).catch(()=>({items:[]}))));

0 commit comments

Comments
 (0)