Skip to content

Commit df6480b

Browse files
committed
Merge upstream/main and resolve conflicts
Combines mobile hamburger menu feature with upstream statistics section.
2 parents 66f4cce + 4f63d89 commit df6480b

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

src/Main.svelte

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script lang="ts">
2+
import { onMount } from "svelte";
23
import App from "./App.svelte";
34
import Providers from "./Providers.svelte";
45
@@ -20,6 +21,54 @@
2021
activeTab = tab;
2122
closeMobileMenu();
2223
}
24+
const PROVIDERS_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/provider_endpoints_support.json";
25+
const MODELS_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
26+
27+
let providerCount = 0;
28+
let endpointCount = 0;
29+
let providerEndpointCount = 0;
30+
let modelCount = 0;
31+
let statsLoading = true;
32+
33+
onMount(async () => {
34+
try {
35+
// Fetch provider data
36+
const providersResponse = await fetch(PROVIDERS_URL);
37+
const providersData = await providersResponse.json();
38+
39+
if (providersData.providers) {
40+
const providers = Object.entries(providersData.providers).map(([provider, info]: [string, any]) => ({
41+
provider,
42+
endpoints: info.endpoints || {}
43+
}));
44+
45+
providerCount = providers.length;
46+
47+
// Count unique endpoints
48+
const allEndpoints = new Set<string>();
49+
providers.forEach(p => {
50+
Object.keys(p.endpoints).forEach(e => allEndpoints.add(e));
51+
});
52+
endpointCount = allEndpoints.size;
53+
54+
// Count provider + endpoint combinations
55+
providerEndpointCount = providers.reduce((total, provider) => {
56+
return total + Object.values(provider.endpoints).filter(supported => supported === true).length;
57+
}, 0);
58+
}
59+
60+
// Fetch model data
61+
const modelsResponse = await fetch(MODELS_URL);
62+
const modelsText = await modelsResponse.text();
63+
const modelsData = JSON.parse(modelsText);
64+
modelCount = Object.keys(modelsData).length;
65+
66+
statsLoading = false;
67+
} catch (error) {
68+
console.error("Failed to load statistics:", error);
69+
statsLoading = false;
70+
}
71+
});
2372
</script>
2473

2574
<div class="app-container">
@@ -93,6 +142,30 @@
93142
{/if}
94143
</header>
95144

145+
<!-- Statistics Section -->
146+
{#if !statsLoading}
147+
<div class="stats-section">
148+
<div class="stats-container">
149+
<div class="stat-card">
150+
<div class="stat-value">{modelCount}</div>
151+
<div class="stat-label">Models Supported</div>
152+
</div>
153+
<div class="stat-card">
154+
<div class="stat-value">{providerCount}</div>
155+
<div class="stat-label">Providers</div>
156+
</div>
157+
<div class="stat-card">
158+
<div class="stat-value">{endpointCount}</div>
159+
<div class="stat-label">Unique Endpoints</div>
160+
</div>
161+
<div class="stat-card">
162+
<div class="stat-value">{providerEndpointCount}</div>
163+
<div class="stat-label">Provider + Endpoint Combinations</div>
164+
</div>
165+
</div>
166+
</div>
167+
{/if}
168+
96169
<!-- Content -->
97170
{#if activeTab === "models"}
98171
<App />
@@ -345,5 +418,84 @@
345418
display: block;
346419
}
347420
}
421+
422+
/* Statistics Section */
423+
.stats-section {
424+
max-width: 1400px;
425+
margin: 1.5rem auto;
426+
padding: 0 2rem;
427+
}
428+
429+
.stats-container {
430+
display: grid;
431+
grid-template-columns: repeat(4, 1fr);
432+
gap: 0.75rem;
433+
}
434+
435+
.stat-card {
436+
background: #fcfcfc;
437+
border: 1px solid #f5f5f5;
438+
border-radius: 6px;
439+
padding: 0.875rem 0.75rem;
440+
text-align: center;
441+
transition: background-color 0.2s ease, border-color 0.2s ease;
442+
}
443+
444+
.stat-card:hover {
445+
background-color: #fafafa;
446+
border-color: #f0f0f0;
447+
}
448+
449+
.stat-value {
450+
font-size: 1.375rem;
451+
font-weight: 600;
452+
color: #1a1a1a;
453+
line-height: 1;
454+
margin-bottom: 0.25rem;
455+
}
456+
457+
.stat-label {
458+
font-size: 0.6875rem;
459+
font-weight: 500;
460+
color: #9ca3af;
461+
text-transform: uppercase;
462+
letter-spacing: 0.04em;
463+
}
464+
465+
/* Responsive Design */
466+
@media (max-width: 1024px) {
467+
.stats-container {
468+
grid-template-columns: repeat(2, 1fr);
469+
}
470+
}
471+
472+
@media (max-width: 640px) {
473+
.stats-container {
474+
grid-template-columns: 1fr;
475+
gap: 0.75rem;
476+
}
477+
478+
.stat-card {
479+
padding: 1rem;
480+
}
481+
482+
.stat-value {
483+
font-size: 1.5rem;
484+
}
485+
486+
.stat-label {
487+
font-size: 0.6875rem;
488+
}
489+
490+
.tabs {
491+
width: 100%;
492+
flex-wrap: wrap;
493+
}
494+
495+
.tab {
496+
font-size: 0.875rem;
497+
padding: 0.5rem 0.75rem;
498+
}
499+
}
348500
</style>
349501

src/Providers.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
...sorted.filter(e => !priorityOrder.includes(e))
130130
];
131131
}
132+
132133
</script>
133134

134135
<main>

0 commit comments

Comments
 (0)